SXSocketRef SXCreateClientSocket(const char * ipaddr, unsigned short port, int domain, int type, int protocol, SXError * err_ret) { SXSocketRef sockPtr = (SXSocketRef)sx_calloc(1, sizeof(sx_socket_t)); if (sockPtr == NULL) ERR_RET(SX_ERROR_MEM_ALLOC); sockPtr->protocol = protocol; sockPtr->type = type; sockPtr->domain = domain; sx_obj_init(&sockPtr->obj, &SXFreeSocket); socklen_t addrlen; memset(&sockPtr->addr, 0, sizeof(struct sockaddr_storage)); if ((sockPtr->sockfd = socket(domain, type, protocol)) == -1) { perror("socket"); ERR_RET(SX_ERROR_SYS_SOCKET); } switch (domain) { case AF_INET: sockaddr_in(sockPtr->addr).sin_port = htons(port); sockaddr_in(sockPtr->addr).sin_len = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in); inet_pton(AF_INET, ipaddr, &sockaddr_in(sockPtr->addr).sin_addr); break; case AF_INET6: sockaddr_in6(sockPtr->addr).sin6_port = htons(port); sockaddr_in6(sockPtr->addr).sin6_len = sizeof(struct sockaddr_in6); addrlen = sizeof(struct sockaddr_in6); inet_pton(AF_INET6, ipaddr, &sockaddr_in6(sockPtr->addr).sin6_addr); break; default: ERR_RET(SX_ERROR_INVALID_IPADDR); return NULL; } int yes = 1; if (setsockopt(sockPtr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &yes, sizeof(int)) == -1) { perror("setsockopt"); ERR_RET(SX_ERROR_SYS_SETSOCKOPT); } sockPtr->addr.ss_family = domain; ERR_RET(SX_SUCCESS); return sockPtr; }
/** * Sets the address to invalid, and m_addr to the default for the given type. * * @param type */ void sockAddrBase::init(Addr::Type type) { switch (type) { case Addr::IPv4: { sockaddr_in *storage = getIPv4Storage(); storage->sin_family = AF_INET; storage->sin_port = 0; storage->sin_addr.s_addr = INADDR_ANY; } break; case Addr::IPv6: { sockaddr_in6 *storage = getIPv6Storage(); *storage = sockaddr_in6(); storage->sin6_family = AF_INET6; storage->sin6_addr = in6addr_any; /** Probably not necessary. Is in6addr_any _guaranteed_ to be 0?*/ } break; default: m_addr.ss_family = AF_UNSPEC; break; } }
SXError dns_lookup(SXSocketRef socket, const char * hostname, const char * service, struct addrinfo * hint) { struct addrinfo * info, * cinfo; if (getaddrinfo(hostname, service, hint, &info) != 0) return SX_ERROR_SYS_GET_ADDR_INFO; cinfo = info; while (cinfo != NULL) { cinfo = cinfo->ai_next; short port = htons(getservbyname(service, NULL)->s_port); memset(&socket->addr, 0, sizeof(struct sockaddr_storage)); switch (cinfo->ai_family) { case AF_INET: socket->domain = AF_INET; socket->type = cinfo->ai_socktype; socket->protocol = cinfo->ai_protocol; sockaddr_in(socket->addr).sin_len = sizeof(struct sockaddr_in); sockaddr_in(socket->addr).sin_family = AF_INET; sockaddr_in(socket->addr).sin_addr = sockaddr_in(cinfo->ai_addr).sin_addr; sockaddr_in(socket->addr).sin_port = port; goto clean; case AF_INET6: sockaddr_in6(socket->addr).sin6_len = sizeof(struct sockaddr_in6); sockaddr_in6(socket->addr).sin6_family = AF_INET6; sockaddr_in6(socket->addr).sin6_port = port; sockaddr_in6(socket->addr).sin6_addr = sockaddr_in6(cinfo->ai_addr).sin6_addr; goto clean; default: goto cont; } cont: continue; } clean: freeaddrinfo(info); return SX_SUCCESS; }
SXSocketRef SXCreateServerSocket(unsigned short port, int domain, int type, int protocol, SXError * err_ret) { SXSocketRef sockPtr = (SXSocketRef)sx_calloc(1, sizeof(sx_socket_t)); if (sockPtr == NULL) ERR_RET(SX_ERROR_MEM_ALLOC); sockPtr->domain = domain; sockPtr->type = type; sockPtr->protocol = protocol; sockPtr->ref_count = 1; sockPtr->port = port; socklen_t addrlen; memset(&sockPtr->addr, 0, sizeof(struct sockaddr_storage)); if ((sockPtr->sockfd = socket(domain, type, protocol)) == -1) { perror("socket"); ERR_RET(SX_ERROR_SYS_SOCKET); } switch (domain) { case AF_INET: sockaddr_in(sockPtr->addr).sin_addr.s_addr = INADDR_ANY; sockaddr_in(sockPtr->addr).sin_port = htons(port); sockaddr_in(sockPtr->addr).sin_len = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in); break; case AF_INET6: sockaddr_in6(sockPtr->addr).sin6_addr = in6addr_any; sockaddr_in6(sockPtr->addr).sin6_port = htons(port); sockaddr_in6(sockPtr->addr).sin6_len = sizeof(struct sockaddr_in6); addrlen = sizeof(struct sockaddr_in6); break; default: ERR_RET(SX_ERROR_INVALID_IPADDR); return NULL; } sockPtr->addr.ss_family = domain; int yes=1; if (setsockopt(sockPtr->sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { perror("setsockopt"); ERR_RET(SX_ERROR_SYS_SETSOCKOPT); } if (bind(sockPtr->sockfd, (struct sockaddr *)&sockPtr->addr, addrlen) == -1) { perror("bind"); ERR_RET(SX_ERROR_SYS_BIND); } ERR_RET(SX_SUCCESS); return sockPtr; }
bool sockAddrBase::FromString(const char *str) { // This is called from the constructor, so it must work with an uninitialized // structure. init(Addr::Invalid); // First determine if it is IPv4 or IPv6 str = SkipWhite(str); const char *firstColon = strchr(str, ':'); const char *firstDot = strchr(str, '.'); const char *firstPercent = strchr(str, '%'); if (!firstDot && !firstColon) return false; if (!firstColon || (firstDot && firstDot < firstColon)) { // IPv4 uint16_t port; uint32_t addr; if (firstPercent) return false; if (!firstColon) { if (!ParseIPv4(str, &addr, &str)) return false; str = SkipWhite(str); if (*str != '\0') return false; init(Addr::IPv4); getIPv4Storage()->sin_addr.s_addr = addr; return true; } // Has dots and a colon, presumably its an IPv4 with port if (!m_allowPort) return false; if (!ParseIPv4Port(str, &addr, &port)) return false; init(Addr::IPv4); getIPv4Storage()->sin_addr.s_addr = addr; SetPort(port); return true; } // Not IPv4 if (!firstColon || (firstPercent && (firstPercent < firstColon))) return false; else { // IPv6 sockaddr_in6 tmp = sockaddr_in6(); if (firstPercent || *str == '[') { char addrStr[INET6_ADDRSTRLEN]; const char *last, *lastBrace = NULL; if (*str == '[') { ++str; last = lastBrace = strchr(str, ']'); if (!lastBrace) return false; } if (firstPercent) { if (lastBrace && lastBrace < firstPercent + 2) return false; last = firstPercent; } if (last == str || size_t(last - str) >= sizeof(addrStr)) return false; memcpy(addrStr, str, last - str); addrStr[last - str] = '\0'; if (1 != inet_pton(AF_INET6, addrStr, &tmp.sin6_addr)) return false; if (firstPercent) { // ONLY allow interface (scope) for link local addresses (for now) // Otherwise address comparison breaks for regular addresses, one of which has a // scope. if (!IN6_IS_ADDR_LINKLOCAL(&tmp.sin6_addr)) return false; if (lastBrace) { // already checked that (lastBrace-firstPercent >= 2) memcpy(addrStr, firstPercent + 1, lastBrace - (firstPercent + 1)); addrStr[lastBrace - (firstPercent + 1)] = '\0'; last = addrStr; } else last = firstPercent + 1; unsigned int index = if_nametoindex(last); if (index == 0 || index > UINT32_MAX) return false; tmp.sin6_scope_id = uint32_t(index); } if (lastBrace) { last = lastBrace + 1; if (*last != ':') { last = SkipWhite(last); if (*last != '\0') return false; } else { // We have a port uint64_t val; if (!m_allowPort) return false; ++last; if (!StringToInt(last, val)) return false; if (val > UINT16_MAX) return false; tmp.sin6_port = htons(uint16_t(val)); } } } else { // no [] and no % so the string can be parsed directly if (1 != inet_pton(AF_INET6, str, &tmp.sin6_addr)) return false; } // Set the actual value init(Addr::IPv6); sockaddr_in6 *storage = getIPv6Storage(); storage->sin6_addr = tmp.sin6_addr; storage->sin6_port = tmp.sin6_port; storage->sin6_scope_id = tmp.sin6_scope_id; return true; } }