#include "docking.h"
#include "errno.h"
extern int errno;

int chinput_net_create_socket (int *sock, const char *addr)
{
	struct sockaddr_un address;
	socklen_t addr_len;

	if ((*sock = socket (PF_UNIX, SOCK_DGRAM, 0)) < 0)
	{
		perror ("chinput_net_create_socket() >> socket()");
		return 1;
	}

	address.sun_family = PF_UNIX;
	// Please handler exception here.
	strcpy (address.sun_path, addr);
	if (unlink (addr) < 0 && errno != ENOENT)
	{
		perror ("chinput_net_create_socket() >> unlink()");
		return 1;
	}
	addr_len = sizeof (address.sun_family) + sizeof (address.sun_path);

	if (bind (*sock, (struct sockaddr *)&address, addr_len) < 0)
	{
		perror ("chinput_net_create_socket() >> bind()");
		return 1;
	}

	return 0;
}

int chinput_net_connect_peer (int *sock, const char *addr)
{
	struct sockaddr_un address;
	socklen_t addr_len;

	if ((*sock = socket (PF_UNIX, SOCK_DGRAM, 0)) < 0)
	{
		perror ("chinput_net_connect_peer() >> socket()");
		return 1;
	}

	address.sun_family = PF_UNIX;
	// Please Handler exception here
	strcpy (address.sun_path, addr);
	addr_len = sizeof (address.sun_family) + sizeof (address.sun_path);

	if (connect (*sock, (struct sockaddr *)&address, addr_len) < 0)
	{
		perror ("chinput_net_connect_peer() >> connect()");
		return 1;
	}

	return 0;
}

int chinput_net_set_sock_attr (int sock)
{
	long sock_flag;

	if ((sock_flag = fcntl (sock, F_GETFL)) < 0)
	{
		perror ("chinput_net_set_sock_attr() >> fcntl () >> F_GETFL");
		return 1;
	}
	if (fcntl (sock, F_SETFL, sock_flag | O_NONBLOCK | O_ASYNC) < 0)
	{
		perror ("chinput_net_set_sock_attr() >> fcntl () >> F_SETFL");
		return 1;
	}
	if (fcntl (sock, F_SETOWN, getpid ()) < 0)
	{
		perror ("chinput_net_set_sock_attr() >> fcntl () >> F_SETOWN");
		return 1;
	}
	if (fcntl (sock, F_SETSIG, SIGIO) < 0)
	{
		perror ("chinput_net_set_sock_attr() >> fcntl () >> F_SETSIG");
		return 1;
	}
	return 0;
}

int chinput_net_set_signal_handler (int signum, void *hdlr)
{
	struct sigaction sig_act;

	memset (&sig_act, 0, sizeof (struct sigaction));
	sig_act.sa_sigaction = hdlr;
	sig_act.sa_flags = 0 | SA_SIGINFO;

	if (sigaction (signum, &sig_act, NULL) < 0)
	{
		perror ("chinput_net_set_signal_handler() >> sigaction ()");
		return 1;
	}
	return 0;
}

// Socket clearup. Pass NULL as paramemter is OK
// message != NULL, means that, some socket or related operation is failed
// 					otherwise, it is a clear clean up like chinput exit
// Return 0 if nothing goes wrong.
int chinput_net_clear_socket (char *message, int csock, int dsock)
{
	int ret = 0;

	if (message != NULL)
		fprintf (stderr, message);

	fprintf (stderr, "Going to clear socket.\n");

	if (csock == -1)
	{
		if (close (csock) < 0)
		{
			perror ("chinput_net_clear_socket () >> close ()\n");
			ret = -1;
		}
		else
			perror ("chinput_net_clear_socket () >> close ()\n");
	}
	if (dsock == -1)
	{
		if (close (dsock) < 0)
		{
			fprintf (stderr, "... Error in closing docking socket.\n");
			ret = -1;
		}
		else
			fprintf (stderr, "... Docking socket closed.\n");
	}
	return ret;
}
