From 1c48b508171aa08a46d8796f4ec8d604e06c2d85 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C4=81nis=20R=C5=ABcis?= Date: Mon, 29 Mar 2010 17:18:44 +0300 Subject: [PATCH] LHNET: non-blocking connected sockets --- lhnet.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lhnet.h | 12 +++++ 2 files changed, 165 insertions(+) diff --git a/lhnet.c b/lhnet.c index 99b9f144..517f0815 100644 --- a/lhnet.c +++ b/lhnet.c @@ -56,6 +56,8 @@ #if defined(WIN32) #define EWOULDBLOCK WSAEWOULDBLOCK #define ECONNREFUSED WSAECONNREFUSED +#define EINPROGRESS WSAEINPROGRESS +#define EALREADY WSAEALREADY #define SOCKETERRNO WSAGetLastError() @@ -997,6 +999,146 @@ lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) return NULL; } +lhnetsocket_t *LHNET_AllocSocket(lhnetaddress_t *address) +{ + lhnetsocket_t *lhnetsocket; + if (!address) + return NULL; + lhnetsocket = (lhnetsocket_t *)Z_Malloc(sizeof (*lhnetsocket)); + if (lhnetsocket) + { + memset(lhnetsocket, 0, sizeof (*lhnetsocket)); + lhnetsocket->address = *address; + lhnetsocket->constatus = LHNETCONSTATUS_DISCONNECTED; + return lhnetsocket; + } + return NULL; +} + +void LHNET_OpenSocket_Connected(lhnetsocket_t *lhnetsocket) +{ + lhnetsocket_t *s; + lhnetaddressnative_t *remoteaddress; + SOCKLEN_T namelen; + int connectresult; + if (!lhnetsocket) + return; + if (lhnetsocket->constatus == LHNETCONSTATUS_CONNECTED) + return; + switch(lhnetsocket->address.addresstype) + { + case LHNETADDRESSTYPE_LOOP: + if (lhnetsocket->address.port == 0) + { + // allocate a port dynamically + // this search will always terminate because there is never + // an allocated socket with port 0, so if the number wraps it + // will find the port is unused, and then refuse to use port + // 0, causing an intentional failure condition + lhnetsocket->address.port = 1024; + for (;;) + { + for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) + if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port) + break; + if (s == &lhnet_socketlist) + break; + lhnetsocket->address.port++; + } + } + // check if the port is available + for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next) + if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port) + break; + if (s == &lhnet_socketlist && lhnetsocket->address.port != 0) + { + lhnetsocket->next = &lhnet_socketlist; + lhnetsocket->prev = lhnetsocket->next->prev; + lhnetsocket->next->prev = lhnetsocket; + lhnetsocket->prev->next = lhnetsocket; + lhnetsocket->constatus = LHNETCONSTATUS_CONNECTED; + return; + } + lhnetsocket->constatus = LHNETCONSTATUS_ERROR; + break; + + case LHNETADDRESSTYPE_INET4: +#ifdef SUPPORTIPV6 + case LHNETADDRESSTYPE_INET6: +#endif + +#ifdef WIN32 + if (!lhnet_didWSAStartup) + { + Con_Print("LHNET_OpenSocket_Connected: can't open a socket (WSAStartup failed during LHNET_Init)\n"); + lhnetsocket->constatus = LHNETCONSTATUS_ERROR; + return; + } +#endif + + if (lhnetsocket->constatus == LHNETCONSTATUS_DISCONNECTED) + { +#ifdef WIN32 + u_long _true = 1; +#else + char _true = 1; +#endif + +#ifdef SUPPORTIPV6 + if ((lhnetsocket->inetsocket = socket(address->addresstype == LHNETADDRESSTYPE_INET6 ? PF_INET6 : PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) +#else + if ((lhnetsocket->inetsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) +#endif + { + Con_Printf("LHNET_OpenSocket_Connected: socket returned error: %s\n", LHNETPRIVATE_StrError()); + lhnetsocket->constatus = LHNETCONSTATUS_ERROR; + break; + } + + if (ioctlsocket(lhnetsocket->inetsocket, FIONBIO, &_true) == -1) + { + Con_Printf("LHNET_OpenSocket_Connected: ioctlsocket returned error: %s\n", LHNETPRIVATE_StrError()); + closesocket(lhnetsocket->inetsocket); + lhnetsocket->constatus = LHNETCONSTATUS_ERROR; + break; + } + } + + remoteaddress = (lhnetaddressnative_t *)&lhnetsocket->address; +#ifdef SUPPORTIPV6 + namelen = sizeof(remoteaddress->addr.in6); +#else + namelen = sizeof(remoteaddress->addr.in); +#endif + connectresult = connect(lhnetsocket->inetsocket, &remoteaddress->addr.sock, namelen); + + if (connectresult != -1) + { + lhnetsocket->next = &lhnet_socketlist; + lhnetsocket->prev = lhnetsocket->next->prev; + lhnetsocket->next->prev = lhnetsocket; + lhnetsocket->prev->next = lhnetsocket; + lhnetsocket->constatus = LHNETCONSTATUS_CONNECTED; + } + else + { + if (SOCKETERRNO == EINPROGRESS || SOCKETERRNO == EALREADY) + { + lhnetsocket->constatus = LHNETCONSTATUS_INPROGRESS; + } + else + { + Con_Printf("LHNET_OpenSocket_Connected: connect returned error: %s\n", LHNETPRIVATE_StrError()); + closesocket(lhnetsocket->inetsocket); + lhnetsocket->constatus = LHNETCONSTATUS_ERROR; + } + } + break; + default: + break; + } +} + void LHNET_CloseSocket(lhnetsocket_t *lhnetsocket) { if (lhnetsocket) @@ -1098,6 +1240,12 @@ int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, } Con_Printf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); } + else if (value == 0) + { + /* Connection closed. */ + lhnetsocket->constatus = LHNETCONSTATUS_DISCONNECTED; + return 0; + } } #ifdef SUPPORTIPV6 else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) @@ -1125,6 +1273,11 @@ int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, } Con_Printf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); } + else if (value == 0) + { + lhnetsocket->constatus = LHNETCONSTATUS_DISCONNECTED; + return 0; + } } #endif return value; diff --git a/lhnet.h b/lhnet.h index 701045e3..b306b40b 100644 --- a/lhnet.h +++ b/lhnet.h @@ -30,10 +30,20 @@ int LHNETADDRESS_GetPort(const lhnetaddress_t *address); int LHNETADDRESS_SetPort(lhnetaddress_t *address, int port); int LHNETADDRESS_Compare(const lhnetaddress_t *address1, const lhnetaddress_t *address2); +typedef enum lhnetconstatus_e +{ + LHNETCONSTATUS_DISCONNECTED, + LHNETCONSTATUS_INPROGRESS, + LHNETCONSTATUS_CONNECTED, + LHNETCONSTATUS_ERROR +} +lhnetconstatus_t; + typedef struct lhnetsocket_s { lhnetaddress_t address; int inetsocket; + lhnetconstatus_t constatus; struct lhnetsocket_s *next, *prev; } lhnetsocket_t; @@ -42,6 +52,8 @@ void LHNET_Init(void); void LHNET_Shutdown(void); void LHNET_SleepUntilPacket_Microseconds(int microseconds); lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address); +lhnetsocket_t *LHNET_AllocSocket(lhnetaddress_t *address); +void LHNET_OpenSocket_Connected(lhnetsocket_t *socket); void LHNET_CloseSocket(lhnetsocket_t *lhnetsocket); lhnetaddress_t *LHNET_AddressFromSocket(lhnetsocket_t *sock); int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, lhnetaddress_t *address); -- 2.39.2