/** * Add a socket to the list of socket to check with select * @param newSd the new socket to add */ int Socket_addSocket(int newSd) { int rc = 0; FUNC_ENTRY; if (ListFindItem(s.clientsds, &newSd, intcompare) == NULL) /* make sure we don't add the same socket twice */ { int* pnewSd = (int*)malloc(sizeof(newSd)); *pnewSd = newSd; ListAppend(s.clientsds, pnewSd, sizeof(newSd)); FD_SET(newSd, &(s.rset_saved)); s.maxfdp1 = max(s.maxfdp1, newSd + 1); rc = Socket_setnonblocking(newSd); } else Log(TRACE_MIN, -1, "addSocket: socket %d already in the list", newSd); FUNC_EXIT_RC(rc); return rc; }
/** * Fully initialize the socket module for in and outbound communications. * In single-listener mode. * @param anAddress IP address string * @param port number * @param ipv6 flag to indicate ipv6 should be used * @return completion code */ int Socket_initialize(char* anAddress, int aPort, int ipv6) { int flag = 1; int rc = SOCKET_ERROR; int ipv4 = 1; /* yes we can drop down to ipv4 */ FUNC_ENTRY; s.port = aPort; if (anAddress == NULL || strcmp(anAddress, "INADDR_ANY") == 0) { s.addr.sin_addr.s_addr = htonl(INADDR_ANY); s.addr6.sin6_addr = in6addr_any; } else { if (anAddress[0] == '[') { int changed = ipv6_format(anAddress); inet_pton(AF_INET6, &anAddress[1], &(s.addr6.sin6_addr)); ipv4 = 0; if (changed) (anAddress)[changed] = ']'; } else { inet_pton(AF_INET, anAddress, &(s.addr.sin_addr.s_addr)); ipv6 = 0; } } Socket_outInitialize(); s.mySocket = -1; if (ipv6) s.mySocket = socket(AF_INET6, SOCK_STREAM, 0); if (s.mySocket < 0 && ipv4) { s.mySocket = socket(AF_INET, SOCK_STREAM, 0); ipv6 = 0; } s.maxfdp1 = 0; Log(TRACE_MAX, 6, NULL, FD_SETSIZE); if (s.mySocket < 0) { Socket_error("socket", s.mySocket); Log(LOG_WARNING, 77, NULL); rc = s.mySocket; goto exit; } #if !defined(WIN32) if (setsockopt(s.mySocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&flag, sizeof(int)) != 0) Log(LOG_WARNING, 109, NULL, aPort); #endif if (ipv6) { s.addr6.sin6_family = AF_INET6; s.addr6.sin6_port = htons(s.port); rc = bind(s.mySocket, (struct sockaddr *)&(s.addr6), sizeof(s.addr6)); } else { s.addr.sin_family = AF_INET; s.addr.sin_port = htons(s.port); memset(s.addr.sin_zero, 0, sizeof(s.addr.sin_zero)); rc = bind(s.mySocket, (struct sockaddr *)&(s.addr), sizeof(s.addr)); } if (rc == SOCKET_ERROR) { Socket_error("bind", s.mySocket); Log(LOG_WARNING, 78, NULL, aPort); goto exit; } if (listen(s.mySocket, SOMAXCONN) == SOCKET_ERROR) /* second parm is max no of connections */ { Socket_error("listen", s.mySocket); Log(LOG_WARNING, 79, NULL, aPort); goto exit; } if (Socket_setnonblocking(s.mySocket) == SOCKET_ERROR) { Socket_error("setnonblocking", s.mySocket); goto exit; } FD_SET((u_int)s.mySocket, &(s.rset)); /* Add the current socket descriptor */ s.maxfdp1 = s.mySocket + 1; memcpy((void*)&(s.rset_saved), (void*)&(s.rset), sizeof(s.rset_saved)); rc = 0; exit: FUNC_EXIT_RC(rc); return rc; }
/** * Create the server socket in multi-listener mode. * @param list pointer to a listener structure * @return completion code */ int Socket_addServerSocket(Listener* list) { int flag = 1; int rc = SOCKET_ERROR; int ipv4 = 1; /* yes we can drop down to ipv4 */ FUNC_ENTRY; if (!list->address || strcmp(list->address, "INADDR_ANY") == 0) { struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; list->addr.sin_addr.s_addr = htonl(INADDR_ANY); list->addr6.sin6_addr = in6addr_any; } else { if (list->address[0] == '[') { int changed = ipv6_format(list->address); #if defined(WIN32) /*wchar_t buf[(INET6_ADDRSTRLEN+1)*2]; int buflen = sizeof(list->addr6); mbstowcs(buf, &list->address[1], sizeof(buf)); rc = WSAStringToAddress(buf, AF_INET6, NULL, (struct sockaddr*)&list->addr6, &buflen);*/ rc = win_inet_pton(AF_INET6, &list->address[1], &(list->addr6.sin6_addr)); #else rc = inet_pton(AF_INET6, &list->address[1], &(list->addr6.sin6_addr)); #endif ipv4 = 0; if (changed) (list->address)[changed] = ']'; } else { #if defined(WIN32) /*wchar_t buf[(INET6_ADDRSTRLEN+1)*2]; int buflen = sizeof(list->addr); mbstowcs(buf, list->address, sizeof(buf)); rc = WSAStringToAddress(buf, AF_INET, NULL, (struct sockaddr*)&list->addr, &buflen);*/ rc = win_inet_pton(AF_INET, list->address, &(list->addr.sin_addr.s_addr)); #else rc = inet_pton(AF_INET, list->address, &(list->addr.sin_addr.s_addr)); #endif list->ipv6 = 0; } #if defined(WIN32) if (rc != 0) #else if (rc != 1) #endif { Log(LOG_WARNING, 67, NULL, list->address); rc = -1; goto exit; } } list->socket = -1; if (list->protocol == PROTOCOL_MQTT) { if (list->ipv6) list->socket = socket(AF_INET6, SOCK_STREAM, 0); if (list->socket < 0 && ipv4) { list->socket = socket(AF_INET, SOCK_STREAM, 0); list->ipv6 = 0; } } #if defined(MQTTS) else if (list->protocol == PROTOCOL_MQTTS) { if (list->ipv6) list->socket = socket(AF_INET6, SOCK_DGRAM, 0); if (list->socket < 0 && ipv4) { list->socket = socket(AF_INET, SOCK_DGRAM, 0); list->ipv6 = 0; } } #endif Log(TRACE_MAX, 6, NULL, FD_SETSIZE); if (list->socket < 0) { Socket_error("socket", list->socket); Log(LOG_WARNING, 77, NULL); rc = list->socket; goto exit; } #if !defined(WIN32) if (setsockopt(list->socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&flag, sizeof(int)) != 0) Log(LOG_WARNING, 109, NULL, list->port); #endif if (list->ipv6) { list->addr6.sin6_family = AF_INET6; list->addr6.sin6_port = htons(list->port); rc = bind(list->socket, (struct sockaddr *)&(list->addr6), sizeof(list->addr6)); } else { list->addr.sin_family = AF_INET; list->addr.sin_port = htons(list->port); memset(list->addr.sin_zero, 0, sizeof(list->addr.sin_zero)); rc = bind(list->socket, (struct sockaddr *)&(list->addr), sizeof(list->addr)); } if (rc == SOCKET_ERROR) { Socket_error("bind", list->socket); Log(LOG_WARNING, 78, NULL, list->port); goto exit; } /* Only listen if this is mqtt/tcp */ if (list->protocol == PROTOCOL_MQTT && listen(list->socket, SOMAXCONN) == SOCKET_ERROR) /* second parm is max no of connections */ { Socket_error("listen", list->socket); Log(LOG_WARNING, 79, NULL, list->port); goto exit; } if (Socket_setnonblocking(list->socket) == SOCKET_ERROR) { Socket_error("setnonblocking", list->socket); goto exit; } #if defined(MQTTS) /* If mqtts/udp, add to the list of clientsds to test for reading */ if (list->protocol == PROTOCOL_MQTTS) { ListElement* current = NULL; int loopback = list->loopback; #if !defined(USE_POLL) int* pnewSd = (int*)malloc(sizeof(list->socket)); *pnewSd = list->socket; ListAppend(s.clientsds, pnewSd, sizeof(list->socket)); #endif Log(LOG_INFO, 300, NULL, list->port); if (setsockopt(list->socket, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback)) == SOCKET_ERROR) Socket_error("set listener IP_MULTICAST_LOOP", list->socket); /* join any multicast groups */ while (ListNextElement(list->multicast_groups, ¤t)) Socket_joinMulticastGroup(list->socket, list->ipv6, (char*)(current->content)); } else #endif Log(LOG_INFO, 14, NULL, list->port); #if defined(USE_POLL) /* add new socket to the epoll descriptor with epoll_ctl */ struct socket_info* si = malloc(sizeof(struct socket_info)); si->listener = list; si->fd = list->socket; si->connect_pending = 0; si->event.events = EPOLLIN; si->event.data.ptr = si; TreeAdd(s.fds_tree, si, sizeof(struct socket_info)); if (epoll_ctl(s.epoll_fds, EPOLL_CTL_ADD, list->socket, &si->event) != 0) Socket_error("epoll_ctl add", list->socket); #else FD_SET((u_int)list->socket, &(s.rset)); /* Add the current socket descriptor */ s.maxfdp1 = max(s.maxfdp1+1, list->socket+1); memcpy((void*)&(s.rset_saved), (void*)&(s.rset), sizeof(s.rset_saved)); #endif rc = 0; exit: FUNC_EXIT_RC(rc); return rc; }