socket_in.c 4.55 KB
/*
 * some basic berkley socket stuff....far from beeing complete
 */
#define USE_STRUCT_SCOT_SOCKET

#include <scot/exception.h>
#include <scot/memory.h>
#include <scot_common.h>
#include <scot/socket.h>
#include <scot/scot_types.h>

#ifdef WIN32
# define hstrerror strerror
#endif

struct scot_socket * 
scot_socket_in_new (const char* proto, const char* service)
{
	struct protoent *    ppe;
	struct servent *     pse;
	struct scot_socket * sock = NULL;
	int                  port;
	SOCKET               handle;
	excenv_t *           ee;

	TRY
	{
		if (scot_strisdigit (proto))
			ppe = getprotobynumber (atoi (proto));
		else
			ppe = getprotobyname (proto);

		if (ppe == NULL)
			THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));

		handle = socket (PF_INET, SOCK_STREAM, ppe->p_proto);

		if (handle == INVALID_SOCKET)
			THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));

		if (scot_strisdigit (service))
			pse = getservbyport (atoi (service), proto);
		else
			pse = getservbyname (service, proto);

		if (pse == NULL)
			port = htons ((unsigned short) atoi (service));
		else
			port = pse->s_port;

		sock = SCOT_MEM_GET (sizeof (struct scot_socket));
		SCOT_MEM_ZERO (sock, sizeof (struct scot_socket));
		sock->sa = SCOT_MEM_GET (sizeof (struct sockaddr_in));
		SCOT_MEM_ZERO (sock->sa, sizeof (struct sockaddr_in));

		sock->socket.handle.sock = handle;
		sock->socket.s_type = SCOT_STREAM_TYPE_SOCKET;

		((struct sockaddr_in *) sock->sa)->sin_port        = port;
		((struct sockaddr_in *) sock->sa)->sin_addr.s_addr = INADDR_ANY;
		((struct sockaddr_in *) sock->sa)->sin_family      = AF_INET;

		sock->addr_len = sizeof (struct sockaddr_in);
	}
	CATCH (ee)
	{
		forward_all_exceptions (ee);

		if (sock != NULL)
		{
			if (sock->socket.handle.sock <= 0)
				SCOT_SOCK_CLOSE (sock->socket.handle.sock);

			if (sock->sa != NULL)
				SCOT_MEM_FREE (sock->sa);

			SCOT_MEM_FREE (sock);
		}

		THROW (EXC (EXC_ERROR, 
					SCOT_SOCKET_NEW_FAIL, 
					scot_socket_errmsg [SCOT_SOCKET_NEW_FAIL]));
	}

	return sock;
}

struct scot_socket *
scot_socket_in_accept (const struct scot_socket* s)
{
	SOCKET handle;
#ifndef WIN32
	SIZE_T addr_len;
#else
	int    addr_len;
#endif
	struct sockaddr sa;

	struct scot_socket * sock = NULL;
	excenv_t *           ee;

	TRY
	{
		addr_len = s->addr_len;

		handle = accept (s->socket.handle.sock, &sa, &addr_len);
		if (handle == INVALID_SOCKET)
			THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));

		/*
		 * ich reserviere erst hier den speicher für den neuen socket falls
		 * ein signal accept unterbricht und das programm evtl. abbricht.
		 * so bleibt garantiert kein reservierter speicher in diesem Fall 
		 * zurück. Solange das ganze Programm abbricht währe das kein Problem,
		 * falls der aufruf aber in einem thread erfolgt so würde diese thread
		 * abbrechen und das memory leaken....(wenn es vor dem accept reserviert
		 * worden währe.)
		 */
		sock = SCOT_MEM_GET (sizeof (struct scot_socket));
		SCOT_MEM_ZERO (sock, sizeof (struct scot_socket));
		sock->sa = SCOT_MEM_GET (sizeof (struct sockaddr_in));
		SCOT_MEM_ZERO (sock->sa, sizeof (struct sockaddr_in));

		sock->addr_len      = addr_len;
		sock->socket.handle.sock = handle;
		sock->socket.s_type = SCOT_STREAM_TYPE_SOCKET;
		SCOT_MEM_COPY (sock->sa, &sa, sizeof (struct sockaddr_in));
	}
	CATCH (ee)
	{
		forward_all_exceptions (ee);

		if (sock != NULL)
		{
			if (sock->socket.handle.sock <= 0)
				SCOT_SOCK_CLOSE (sock->socket.handle.sock);

			if (sock->sa != NULL)
				SCOT_MEM_FREE (sock->sa);

			SCOT_MEM_FREE (sock);
		}

		THROW (EXC (EXC_ERROR, 
					SCOT_SOCKET_ACCEPT_FAIL, 
					scot_socket_errmsg [SCOT_SOCKET_ACCEPT_FAIL]));
	}

	return sock;
}

const
char *
scot_socket_in_get_host (struct scot_socket * s)
{
	struct hostent * phe;

	phe = gethostbyaddr (
			(char *) &(((struct sockaddr_in *) s->sa)->sin_addr.s_addr),
			sizeof (unsigned long),
			AF_INET);

	if (!phe)
		THROW (EXC (EXC_WARNING, SCOT_H_ERRNO, hstrerror (SCOT_H_ERRNO)));

	return phe->h_name; 
}

const
char *
scot_socket_in_get_ddc (struct scot_socket * s)
{
	return inet_ntoa (((struct sockaddr_in *) s->sa)->sin_addr);
}

void
scot_socket_in_prep_con (const struct scot_socket * s, const char * adr)
{
	struct hostent * phe;

	phe = gethostbyname (adr);

	if (phe)
	{
		SCOT_MEM_COPY (
				(char*) &(((struct sockaddr_in *) s->sa)->sin_addr), 
				phe->h_addr,
				phe->h_length);
	}
#ifndef WIN32
	else
	{
		if (inet_aton (adr, &(((struct sockaddr_in *) s->sa)->sin_addr)) == 0)
			THROW (EXC (EXC_ERROR, 
						SCOT_SOCKET_NO_VALID_HOST, 
						scot_socket_errmsg [SCOT_SOCKET_NO_VALID_HOST]));
	}
#endif
}