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 } }
PUBLIC void socketCloseConnection(int sid) { WebsSocket *sp; if ((sp = socketPtr(sid)) == NULL) { return; } socketFree(sid); }
/* 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); } } }
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; }