static void socketAccept(socket_t *sp) { struct sockaddr_in addr; socket_t *nsp; size_t len; char *pString; int newSock, nid; #ifdef NW NETINET_DEFINE_CONTEXT; #endif a_assert(sp); /* * Accept the connection and prevent inheriting by children (F_SETFD) */ len = sizeof(struct sockaddr_in); if ((newSock = accept(sp->sock, (struct sockaddr *) &addr, (int *) &len)) < 0) { return; } #ifndef __NO_FCNTL fcntl(newSock, F_SETFD, FD_CLOEXEC); #endif socketHighestFd = max(socketHighestFd, newSock); /* * Create a socket structure and insert into the socket list */ nid = socketAlloc(sp->host, sp->port, sp->accept, sp->flags); nsp = socketList[nid]; a_assert(nsp); if (nsp == NULL) return; nsp->sock = newSock; nsp->flags &= ~SOCKET_LISTENING; /* * Set the blocking mode before calling the accept callback. */ socketSetBlock(nid, (nsp->flags & SOCKET_BLOCK) ? 1: 0); /* * Call the user accept callback. The user must call socketCreateHandler * to register for further events of interest. */ if (sp->accept != NULL) { pString = inet_ntoa(addr.sin_addr); if ((sp->accept)(nid, pString, ntohs(addr.sin_port), sp->sid) < 0) { socketFree(nid); } #ifdef VXWORKS free(pString); #endif } }
static ssize blockingWrite(Webs *wp, void *buf, ssize len) { ssize written, bytes; int prior; prior = socketSetBlock(wp->sid, 1); for (written = 0; len > 0; ) { if ((bytes = socketWrite(wp->sid, buf, len)) < 0) { socketSetBlock(wp->sid, prior); return bytes; } buf += bytes; len -= bytes; written += bytes; } socketSetBlock(wp->sid, prior); return written; }
void socketFree(int sid) { socket_t *sp; char_t buf[256]; int i; if ((sp = socketPtr(sid)) == NULL) { return; } /* * To close a socket, remove any registered interests, set it to * non-blocking so that the recv which follows won't block, do a * shutdown on it so peers on the other end will receive a FIN, * then read any data not yet retrieved from the receive buffer, * and finally close it. If these steps are not all performed * RESETs may be sent to the other end causing problems. */ socketRegisterInterest(sp, 0); if (sp->sock >= 0) { socketSetBlock(sid, 0); /**************************** HANHUI ***************************/ /* if (shutdown(sp->sock, 1) >= 0) { recv(sp->sock, buf, sizeof(buf), 0); } */ shutdown(sp->sock, SHUT_RDWR); /**************************** HANHUI ***************************/ #if (defined (WIN) || defined (CE)) closesocket(sp->sock); #else close(sp->sock); #endif } ringqClose(&sp->inBuf); ringqClose(&sp->outBuf); ringqClose(&sp->lineBuf); bfree(B_L, sp); socketMax = hFree((void***) &socketList, sid); /* * Calculate the new highest socket number */ socketHighestFd = -1; for (i = 0; i < socketMax; i++) { if ((sp = socketList[i]) == NULL) { continue; } socketHighestFd = max(socketHighestFd, sp->sock); } }
/* Accept a connection. Called as a callback on incoming connection. */ static void socketAccept(WebsSocket *sp) { struct sockaddr_storage addrStorage; struct sockaddr *addr; WebsSocket *nsp; Socket newSock; size_t len; char ipbuf[1024]; int port, nid; assert(sp); /* Accept the connection and prevent inheriting by children (F_SETFD) */ len = sizeof(addrStorage); addr = (struct sockaddr*) &addrStorage; if ((newSock = accept(sp->sock, addr, (Socklen*) &len)) == SOCKET_ERROR) { return; } #if ME_COMPILER_HAS_FCNTL fcntl(newSock, F_SETFD, FD_CLOEXEC); #endif socketHighestFd = max(socketHighestFd, newSock); /* Create a socket structure and insert into the socket list */ nid = socketAlloc(sp->ip, sp->port, sp->accept, sp->flags); if ((nsp = socketList[nid]) == 0) { return; } assert(nsp); nsp->sock = newSock; nsp->flags &= ~SOCKET_LISTENING; socketSetBlock(nid, (nsp->flags & SOCKET_BLOCK)); if (nsp->flags & SOCKET_NODELAY) { socketSetNoDelay(nid, 1); } /* Call the user accept callback. The user must call socketCreateHandler to register for further events of interest. */ if (sp->accept != NULL) { /* Get the remote client address */ socketAddress(addr, (int) len, ipbuf, sizeof(ipbuf), &port); if ((sp->accept)(nid, ipbuf, port, sp->sid) < 0) { socketFree(nid); } } }
/* Free a socket structure */ PUBLIC void socketFree(int sid) { WebsSocket *sp; char buf[256]; int i; if ((sp = socketPtr(sid)) == NULL) { return; } /* To close a socket, remove any registered interests, set it to non-blocking so that the recv which follows won't block, do a shutdown on it so peers on the other end will receive a FIN, then read any data not yet retrieved from the receive buffer, and finally close it. If these steps are not all performed RESETs may be sent to the other end causing problems. */ socketRegisterInterest(sid, 0); if (sp->sock >= 0) { socketSetBlock(sid, 0); while (recv(sp->sock, buf, sizeof(buf), 0) > 0) {} if (shutdown(sp->sock, SHUT_RDWR) >= 0) { while (recv(sp->sock, buf, sizeof(buf), 0) > 0) {} } closesocket(sp->sock); } wfree(sp->ip); wfree(sp); socketMax = wfreeHandle(&socketList, sid); /* Calculate the new highest socket number */ socketHighestFd = -1; for (i = 0; i < socketMax; i++) { if ((sp = socketList[i]) == NULL) { continue; } socketHighestFd = max(socketHighestFd, sp->sock); } }
PUBLIC int socketConnect(char *ip, int port, int flags) { WebsSocket *sp; struct sockaddr_storage addr; socklen_t addrlen; int family, protocol, sid, rc; if (port > SOCKET_PORT_MAX) { return -1; } if ((sid = socketAlloc(ip, port, NULL, flags)) < 0) { return -1; } sp = socketList[sid]; assert(sp); if (socketInfo(ip, port, &family, &protocol, &addr, &addrlen) < 0) { return -1; } if ((sp->sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { socketFree(sid); return -1; } socketHighestFd = max(socketHighestFd, sp->sock); #if ME_COMPILER_HAS_FCNTL fcntl(sp->sock, F_SETFD, FD_CLOEXEC); #endif /* Connect to the remote server in blocking mode, then go into non-blocking mode if desired. */ if (!(sp->flags & SOCKET_BLOCK)) { #if ME_WIN_LIKE /* Set to non-blocking for an async connect */ int flag = 1; if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) { socketFree(sid); return -1; } sp->flags |= SOCKET_ASYNC; #else socketSetBlock(sid, 1); #endif } if ((rc = connect(sp->sock, (struct sockaddr*) &addr, sizeof(addr))) < 0 && (rc = tryAlternateConnect(sp->sock, (struct sockaddr*) &addr)) < 0) { #if ME_WIN_LIKE if (socketGetError() != EWOULDBLOCK) { socketFree(sid); return -1; } #else socketFree(sid); return -1; #endif } socketSetBlock(sid, (flags & SOCKET_BLOCK)); return sid; }
PUBLIC int socketListen(char *ip, int port, SocketAccept accept, int flags) { WebsSocket *sp; struct sockaddr_storage addr; Socklen addrlen; char *sip; int family, protocol, sid, rc, only; if (port > SOCKET_PORT_MAX) { return -1; } if ((sid = socketAlloc(ip, port, accept, flags)) < 0) { return -1; } sp = socketList[sid]; assert(sp); /* Change null IP address to be an IPv6 endpoint if the system is dual-stack. That way we can listen on both IPv4 and IPv6 */ sip = ((ip == 0 || *ip == '\0') && socketHasDualNetworkStack()) ? "::" : ip; /* Bind to the socket endpoint and the call listen() to start listening */ if (socketInfo(sip, port, &family, &protocol, &addr, &addrlen) < 0) { return -1; } if ((sp->sock = socket(family, SOCK_STREAM, protocol)) == SOCKET_ERROR) { socketFree(sid); return -1; } socketHighestFd = max(socketHighestFd, sp->sock); #if ME_COMPILER_HAS_FCNTL fcntl(sp->sock, F_SETFD, FD_CLOEXEC); #endif rc = 1; #if ME_UNIX_LIKE || VXWORKS setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char*) &rc, sizeof(rc)); #elif ME_WIN_LIKE && defined(SO_EXCLUSIVEADDRUSE) setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR | SO_EXCLUSIVEADDRUSE, (char*) &rc, sizeof(rc)); #endif #if defined(IPV6_V6ONLY) /* By default, most stacks listen on both IPv6 and IPv4 if ip == 0, except windows which inverts this. So we explicitly control. */ if (hasIPv6) { if (ip == 0) { only = 0; setsockopt(sp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &only, sizeof(only)); } else if (ipv6(ip)) { only = 1; setsockopt(sp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &only, sizeof(only)); } } #endif if (bind(sp->sock, (struct sockaddr*) &addr, addrlen) == SOCKET_ERROR) { error("Can't bind to address %s:%d, errno %d", ip ? ip : "*", port, errno); socketFree(sid); return -1; } if (listen(sp->sock, SOMAXCONN) < 0) { socketFree(sid); return -1; } sp->flags |= SOCKET_LISTENING | SOCKET_NODELAY; sp->handlerMask |= SOCKET_READABLE; socketSetBlock(sid, (flags & SOCKET_BLOCK)); if (sp->flags & SOCKET_NODELAY) { socketSetNoDelay(sid, 1); } return sid; }
int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags) { #if (!defined (NO_GETHOSTBYNAME) && !defined (VXWORKS)) struct hostent *hostent; /* Host database entry */ #endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */ socket_t *sp; struct sockaddr_in sockaddr; int sid, bcast, dgram, rc; #ifdef WF_USE_IPV6 int gaierr; char portstr[10]; struct addrinfo hints; struct addrinfo *ai, *ai2, *aiv6 = NULL; struct sockaddr_in6 sockaddr6; #endif if (port > SOCKET_PORT_MAX) { return -1; } /* * Allocate a socket structure */ if ((sid = socketAlloc(host, port, accept, flags)) < 0) { return -1; } sp = socketList[sid]; a_assert(sp); /* * Create the socket address structure */ #ifdef WF_USE_IPV6 memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); if ((gaierr = getaddrinfo(host, portstr, &hints, &ai)) != 0) { fprintf(stderr, "goahead: getaddrinfo - %s\n", gai_strerror(gaierr)); socketFree(sid); return -1; } aiv6 = NULL; for (ai2 = ai; ai2 != (struct addrinfo*)0; ai2 = ai2->ai_next) { switch (ai2->ai_family) { case AF_INET6: if (aiv6 == NULL) aiv6 = ai2; break; } } if (aiv6 == NULL) { fprintf(stderr, "goahead: cannot find IPv6 addrinfo\n"); socketFree(sid); return -1; } memcpy(&sockaddr6, aiv6->ai_addr, aiv6->ai_addrlen); freeaddrinfo(ai); #else /* WF_USE_IPV6 */ memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons((short) (port & 0xFFFF)); if (host == NULL) { sockaddr.sin_addr.s_addr = INADDR_ANY; } else { sockaddr.sin_addr.s_addr = inet_addr(host); if (sockaddr.sin_addr.s_addr == INADDR_NONE) { /* * If the OS does not support gethostbyname functionality, the macro: * NO_GETHOSTBYNAME should be defined to skip the use of gethostbyname. * Unfortunatly there is no easy way to recover, the following code * simply uses the basicGetHost IP for the sockaddr. */ #ifdef NO_GETHOSTBYNAME if (strcmp(host, basicGetHost()) == 0) { sockaddr.sin_addr.s_addr = inet_addr(basicGetAddress()); } if (sockaddr.sin_addr.s_addr == INADDR_NONE) { socketFree(sid); return -1; } #elif (defined (VXWORKS)) sockaddr.sin_addr.s_addr = (unsigned long) hostGetByName(host); if (sockaddr.sin_addr.s_addr == NULL) { errno = ENXIO; socketFree(sid); return -1; } #else hostent = gethostbyname(host); if (hostent != NULL) { memcpy((char *) &sockaddr.sin_addr, (char *) hostent->h_addr_list[0], (size_t) hostent->h_length); } else { char *asciiAddress; char_t *address; address = basicGetAddress(); asciiAddress = ballocUniToAsc(address, gstrlen(address)); sockaddr.sin_addr.s_addr = inet_addr(asciiAddress); bfree(B_L, asciiAddress); if (sockaddr.sin_addr.s_addr == INADDR_NONE) { errno = ENXIO; socketFree(sid); return -1; } } #endif /* (NO_GETHOSTBYNAME || VXWORKS) */ } } #endif /* WF_USE_IPV6 */ bcast = sp->flags & SOCKET_BROADCAST; if (bcast) { sp->flags |= SOCKET_DATAGRAM; } dgram = sp->flags & SOCKET_DATAGRAM; /* * Create the socket. Support for datagram sockets. Set the close on * exec flag so children don't inherit the socket. */ #ifdef WF_USE_IPV6 sp->sock = socket(AF_INET6, SOCK_STREAM, 0); #else sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0); #endif if (sp->sock < 0) { socketFree(sid); return -1; } #ifndef __NO_FCNTL fcntl(sp->sock, F_SETFD, FD_CLOEXEC); #endif socketHighestFd = max(socketHighestFd, sp->sock); /* * If broadcast, we need to turn on broadcast capability. */ if (bcast) { int broadcastFlag = 1; if (setsockopt(sp->sock, SOL_SOCKET, SO_BROADCAST, (char *) &broadcastFlag, sizeof(broadcastFlag)) < 0) { socketFree(sid); return -1; } } /* * Host is set if we are the client */ if (host) { /* * Connect to the remote server in blocking mode, then go into * non-blocking mode if desired. */ if (!dgram) { if (! (sp->flags & SOCKET_BLOCK)) { /* * sockGen.c is only used for Windows products when blocking * connects are expected. This applies to FieldUpgrader * agents and open source webserver connectws. Therefore the * asynchronous connect code here is not compiled. */ #if (defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined (WEBS)) int flag; sp->flags |= SOCKET_ASYNC; /* * Set to non-blocking for an async connect */ flag = 1; if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) { socketFree(sid); return -1; } #else socketSetBlock(sid, 1); #endif /* #if (WIN || CE) && !(LITTLEFOOT || WEBS) */ } if ((rc = connect(sp->sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) < 0 && (rc = tryAlternateConnect(sp->sock, (struct sockaddr *) &sockaddr)) < 0) { #if (defined (WIN) || defined (CE)) if (socketGetError() != EWOULDBLOCK) { socketFree(sid); return -1; } #else socketFree(sid); return -1; #endif /* WIN || CE */ } } } else { /* * Bind to the socket endpoint and the call listen() to start listening */ rc = 1; setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc)); #ifdef WF_USE_IPV6 if (bind(sp->sock, (struct sockaddr *) &sockaddr6, sizeof(sockaddr6)) < 0) { #else if (bind(sp->sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) { #endif socketFree(sid); return -1; } if (! dgram) { if (listen(sp->sock, SOMAXCONN) < 0) { socketFree(sid); return -1; } sp->flags |= SOCKET_LISTENING; } sp->handlerMask |= SOCKET_READABLE; } /* * Set the blocking mode */ if (flags & SOCKET_BLOCK) { socketSetBlock(sid, 1); } else { socketSetBlock(sid, 0); } return sid; } /******************************************************************************/ /* * If the connection failed, swap the first two bytes in the * sockaddr structure. This is a kludge due to a change in * VxWorks between versions 5.3 and 5.4, but we want the * product to run on either. */ static int tryAlternateConnect(int sock, struct sockaddr *sockaddr) { #ifdef VXWORKS char *ptr; ptr = (char *)sockaddr; *ptr = *(ptr+1); *(ptr+1) = 0; return connect(sock, sockaddr, sizeof(struct sockaddr)); #else return -1; #endif /* VXWORKS */ }
int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags) { #if (!defined (NO_GETHOSTBYNAME) && !defined (VXWORKS)) struct hostent *hostent; /* Host database entry */ #endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */ socket_t *sp; struct sockaddr_in sockaddr; int sid, bcast, dgram, rc; if (port > SOCKET_PORT_MAX) { return -1; } /* * Allocate a socket structure */ if ((sid = socketAlloc(host, port, accept, flags)) < 0) { return -1; } sp = socketList[sid]; a_assert(sp); /* * Create the socket address structure */ memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons((short) (port & 0xFFFF)); if (host == NULL) { sockaddr.sin_addr.s_addr = INADDR_ANY; } else { sockaddr.sin_addr.s_addr = inet_addr(host); if (sockaddr.sin_addr.s_addr == INADDR_NONE) { /* * If the OS does not support gethostbyname functionality, the macro: * NO_GETHOSTBYNAME should be defined to skip the use of gethostbyname. * Unfortunatly there is no easy way to recover, the following code * simply uses the basicGetHost IP for the sockaddr. */ #ifdef NO_GETHOSTBYNAME if (strcmp(host, basicGetHost()) == 0) { sockaddr.sin_addr.s_addr = inet_addr(basicGetAddress()); } if (sockaddr.sin_addr.s_addr == INADDR_NONE) { socketFree(sid); return -1; } #elif (defined (VXWORKS)) sockaddr.sin_addr.s_addr = (unsigned long) hostGetByName(host); if (sockaddr.sin_addr.s_addr == NULL) { errno = ENXIO; socketFree(sid); return -1; } #else hostent = gethostbyname(host); if (hostent != NULL) { memcpy((char *) &sockaddr.sin_addr, (char *) hostent->h_addr_list[0], (size_t) hostent->h_length); } else { char *asciiAddress; char *address; address = basicGetAddress(); asciiAddress = ballocUniToAsc(address, gstrlen(address)); sockaddr.sin_addr.s_addr = inet_addr(asciiAddress); bfree(B_L, asciiAddress); if (sockaddr.sin_addr.s_addr == INADDR_NONE) { errno = ENXIO; socketFree(sid); return -1; } } #endif /* (NO_GETHOSTBYNAME || VXWORKS) */ } } bcast = sp->flags & SOCKET_BROADCAST; if (bcast) { sp->flags |= SOCKET_DATAGRAM; } dgram = sp->flags & SOCKET_DATAGRAM; /* * Create the socket. Support for datagram sockets. Set the close on * exec flag so children don't inherit the socket. */ sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0); if (sp->sock < 0) { socketFree(sid); return -1; } #ifndef __NO_FCNTL fcntl(sp->sock, F_SETFD, FD_CLOEXEC); #endif socketHighestFd = max(socketHighestFd, sp->sock); /* * If broadcast, we need to turn on broadcast capability. */ if (bcast) { int broadcastFlag = 1; if (setsockopt(sp->sock, SOL_SOCKET, SO_BROADCAST, (char *) &broadcastFlag, sizeof(broadcastFlag)) < 0) { socketFree(sid); return -1; } } /* * Host is set if we are the client */ if (host) { /* * Connect to the remote server in blocking mode, then go into * non-blocking mode if desired. */ if (!dgram) { if (! (sp->flags & SOCKET_BLOCK)) { /* * sockGen.c is only used for Windows products when blocking * connects are expected. This applies to FieldUpgrader * agents and open source webserver connectws. Therefore the * asynchronous connect code here is not compiled. */ #if (defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined (WEBS)) int flag; sp->flags |= SOCKET_ASYNC; /* * Set to non-blocking for an async connect */ flag = 1; if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) { socketFree(sid); return -1; } #else socketSetBlock(sid, 1); #endif /* #if (WIN || CE) && !(LITTLEFOOT || WEBS) */ } if ((rc = connect(sp->sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) < 0 && (rc = tryAlternateConnect(sp->sock, (struct sockaddr *) &sockaddr)) < 0) { #if (defined (WIN) || defined (CE)) if (socketGetError() != EWOULDBLOCK) { socketFree(sid); return -1; } #else socketFree(sid); return -1; #endif /* WIN || CE */ } } } else { /* * Bind to the socket endpoint and the call listen() to start listening */ rc = 1; setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc)); if (bind(sp->sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) { socketFree(sid); return -1; } if (! dgram) { if (listen(sp->sock, SOMAXCONN) < 0) { socketFree(sid); return -1; } #ifndef UEMF sp->fileHandle = emfCreateFileHandler(sp->sock, SOCKET_READABLE, (emfFileProc *) socketAccept, (void *) sp); #else sp->flags |= SOCKET_LISTENING; #endif } sp->handlerMask |= SOCKET_READABLE; } /* * Set the blocking mode */ if (flags & SOCKET_BLOCK) { socketSetBlock(sid, 1); } else { socketSetBlock(sid, 0); } return sid; }