@@ -45,10 +45,14 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFLockFailedException.h" #import "OFOutOfRangeException.h" #import "OFUnlockFailedException.h" + +#ifdef HAVE_NET_IF_H +# include +#endif #ifdef OF_AMIGAOS # include #endif @@ -232,11 +236,11 @@ CloseLibrary(socketBase); } #endif int -OFSocketErrNo() +OFSocketErrNo(void) { #if defined(OF_WINDOWS) switch (WSAGetLastError()) { case WSAEACCES: return EACCES; @@ -431,11 +435,11 @@ OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port) { void *pool = objc_autoreleasePoolPush(); OFSocketAddress ret; struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6; - size_t doubleColon; + size_t doubleColon, percent; memset(&ret, '\0', sizeof(ret)); ret.family = OFSocketAddressFamilyIPv6; ret.length = sizeof(ret.sockaddr.in6); @@ -443,13 +447,30 @@ addrIn6->sin6_family = AF_INET6; #else addrIn6->sin6_family = AF_UNSPEC; #endif addrIn6->sin6_port = OFToBigEndian16(port); + + if ((percent = [IPv6 rangeOfString: @"%"].location) != OFNotFound) { + OFString *interface = [IPv6 substringFromIndex: percent + 1]; + IPv6 = [IPv6 substringToIndex: percent]; + + @try { + addrIn6->sin6_scope_id = (uint32_t)[interface + unsignedLongLongValueWithBase: 10]; + } @catch (OFInvalidFormatException *e) { +#if defined(HAVE_IF_NAMETOINDEX) && !defined(OF_WINDOWS) + addrIn6->sin6_scope_id = if_nametoindex([interface + cStringWithEncoding: [OFLocale encoding]]); +#endif + } + + if (addrIn6->sin6_scope_id == 0) + @throw [OFInvalidArgumentException exception]; + } doubleColon = [IPv6 rangeOfString: @"::"].location; - if (doubleColon != OFNotFound) { OFString *left = [IPv6 substringToIndex: doubleColon]; OFString *right = [IPv6 substringFromIndex: doubleColon + 2]; OFArray OF_GENERIC(OFString *) *leftComponents; OFArray OF_GENERIC(OFString *) *rightComponents; @@ -570,18 +591,44 @@ memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); return ret; } + +OFSocketAddress +OFSocketAddressMakeAppleTalk(uint16_t network, uint8_t node, uint8_t port) +{ + OFSocketAddress ret; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyAppleTalk; + ret.length = sizeof(ret.sockaddr.at); + +#ifdef AF_APPLETALK + ret.sockaddr.at.sat_family = AF_APPLETALK; +#else + ret.sockaddr.at.sat_family = AF_UNSPEC; +#endif +#ifdef OF_WINDOWS + ret.sockaddr.at.sat_net = network; +#else + ret.sockaddr.at.sat_net = OFToBigEndian16(network); +#endif + ret.sockaddr.at.sat_node = node; + ret.sockaddr.at.sat_port = port; + + return ret; +} bool OFSocketAddressEqual(const OFSocketAddress *address1, const OFSocketAddress *address2) { const struct sockaddr_in *addrIn1, *addrIn2; const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; const struct sockaddr_ipx *addrIPX1, *addrIPX2; + const struct sockaddr_at *addrAT1, *addrAT2; void *pool; OFString *path1, *path2; bool ret; if (address1->family != address2->family) @@ -655,10 +702,26 @@ return false; if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, IPX_NODE_LEN) != 0) return false; + return true; + case OFSocketAddressFamilyAppleTalk: + if (address1->length < (socklen_t)sizeof(struct sockaddr_at) || + address2->length < (socklen_t)sizeof(struct sockaddr_at)) + @throw [OFInvalidArgumentException exception]; + + addrAT1 = &address1->sockaddr.at; + addrAT2 = &address2->sockaddr.at; + + if (addrAT1->sat_net != addrAT2->sat_net) + return false; + if (addrAT1->sat_node != addrAT2->sat_node) + return false; + if (addrAT1->sat_port != addrAT2->sat_port) + return false; + return true; default: @throw [OFInvalidArgumentException exception]; } } @@ -667,11 +730,11 @@ OFSocketAddressHash(const OFSocketAddress *address) { unsigned long hash; OFHashInit(&hash); - OFHashAdd(&hash, address->family); + OFHashAddByte(&hash, address->family); switch (address->family) { case OFSocketAddressFamilyIPv4: #if defined(OF_WII) || defined(OF_NINTENDO_3DS) if (address->length < 8) @@ -679,28 +742,30 @@ #else if (address->length < (socklen_t)sizeof(struct sockaddr_in)) @throw [OFInvalidArgumentException exception]; #endif - OFHashAdd(&hash, address->sockaddr.in.sin_port >> 8); - OFHashAdd(&hash, address->sockaddr.in.sin_port); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 24); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 16); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr >> 8); - OFHashAdd(&hash, address->sockaddr.in.sin_addr.s_addr); + OFHashAddByte(&hash, address->sockaddr.in.sin_port >> 8); + OFHashAddByte(&hash, address->sockaddr.in.sin_port); + OFHashAddByte(&hash, + address->sockaddr.in.sin_addr.s_addr >> 24); + OFHashAddByte(&hash, + address->sockaddr.in.sin_addr.s_addr >> 16); + OFHashAddByte(&hash, address->sockaddr.in.sin_addr.s_addr >> 8); + OFHashAddByte(&hash, address->sockaddr.in.sin_addr.s_addr); break; case OFSocketAddressFamilyIPv6: if (address->length < (socklen_t)sizeof(struct sockaddr_in6)) @throw [OFInvalidArgumentException exception]; - OFHashAdd(&hash, address->sockaddr.in6.sin6_port >> 8); - OFHashAdd(&hash, address->sockaddr.in6.sin6_port); + OFHashAddByte(&hash, address->sockaddr.in6.sin6_port >> 8); + OFHashAddByte(&hash, address->sockaddr.in6.sin6_port); for (size_t i = 0; i < sizeof(address->sockaddr.in6.sin6_addr.s6_addr); i++) - OFHashAdd(&hash, + OFHashAddByte(&hash, address->sockaddr.in6.sin6_addr.s6_addr[i]); break; case OFSocketAddressFamilyUNIX:; void *pool = objc_autoreleasePoolPush(); @@ -716,21 +781,31 @@ sizeof(address->sockaddr.ipx.sipx_network)]; if (address->length < (socklen_t)sizeof(struct sockaddr_ipx)) @throw [OFInvalidArgumentException exception]; - OFHashAdd(&hash, address->sockaddr.ipx.sipx_port >> 8); - OFHashAdd(&hash, address->sockaddr.ipx.sipx_port); + OFHashAddByte(&hash, address->sockaddr.ipx.sipx_port >> 8); + OFHashAddByte(&hash, address->sockaddr.ipx.sipx_port); memcpy(network, &address->sockaddr.ipx.sipx_network, sizeof(network)); for (size_t i = 0; i < sizeof(network); i++) - OFHashAdd(&hash, network[i]); + OFHashAddByte(&hash, network[i]); for (size_t i = 0; i < IPX_NODE_LEN; i++) - OFHashAdd(&hash, address->sockaddr.ipx.sipx_node[i]); + OFHashAddByte(&hash, + address->sockaddr.ipx.sipx_node[i]); + + break; + case OFSocketAddressFamilyAppleTalk: + if (address->length < (socklen_t)sizeof(struct sockaddr_at)) + @throw [OFInvalidArgumentException exception]; + + OFHashAddByte(&hash, address->sockaddr.at.sat_net >> 8); + OFHashAddByte(&hash, address->sockaddr.at.sat_net); + OFHashAddByte(&hash, address->sockaddr.at.sat_port); break; default: @throw [OFInvalidArgumentException exception]; } @@ -813,10 +888,21 @@ (addrIn6->sin6_addr.s6_addr[i] << 8) | addrIn6->sin6_addr.s6_addr[i + 1]]; first = false; } } + + if (addrIn6->sin6_scope_id != 0) { +#if defined(HAVE_IF_INDEXTONAME) && !defined(OF_WINDOWS) + char interface[IF_NAMESIZE]; + + if (if_indextoname(addrIn6->sin6_scope_id, interface) != NULL) + [string appendFormat: @"%%%s", interface]; + else +# endif + [string appendFormat: @"%%%u", addrIn6->sin6_scope_id]; + } [string makeImmutable]; return string; } @@ -833,37 +919,32 @@ @throw [OFInvalidArgumentException exception]; } } void -OFSocketAddressSetPort(OFSocketAddress *address, uint16_t port) +OFSocketAddressSetIPPort(OFSocketAddress *address, uint16_t port) { switch (address->family) { case OFSocketAddressFamilyIPv4: address->sockaddr.in.sin_port = OFToBigEndian16(port); break; case OFSocketAddressFamilyIPv6: address->sockaddr.in6.sin6_port = OFToBigEndian16(port); break; - case OFSocketAddressFamilyIPX: - address->sockaddr.ipx.sipx_port = OFToBigEndian16(port); - break; default: @throw [OFInvalidArgumentException exception]; } } uint16_t -OFSocketAddressPort(const OFSocketAddress *address) +OFSocketAddressIPPort(const OFSocketAddress *address) { switch (address->family) { case OFSocketAddressFamilyIPv4: return OFFromBigEndian16(address->sockaddr.in.sin_port); case OFSocketAddressFamilyIPv6: return OFFromBigEndian16(address->sockaddr.in6.sin6_port); - case OFSocketAddressFamilyIPX: - return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); default: @throw [OFInvalidArgumentException exception]; } } @@ -922,13 +1003,93 @@ memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); } void -OFSocketAddressIPXNode(const OFSocketAddress *address, +OFSocketAddressGetIPXNode(const OFSocketAddress *address, unsigned char node[IPX_NODE_LEN]) { if (address->family != OFSocketAddressFamilyIPX) @throw [OFInvalidArgumentException exception]; memcpy(node, address->sockaddr.ipx.sipx_node, IPX_NODE_LEN); } + +void +OFSocketAddressSetIPXPort(OFSocketAddress *address, uint16_t port) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.ipx.sipx_port = OFToBigEndian16(port); +} + +uint16_t +OFSocketAddressIPXPort(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); +} + +void +OFSocketAddressSetAppleTalkNetwork(OFSocketAddress *address, uint16_t network) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + +#ifdef OF_WINDOWS + address->sockaddr.at.sat_net = network; +#else + address->sockaddr.at.sat_net = OFToBigEndian16(network); +#endif +} + +uint16_t +OFSocketAddressAppleTalkNetwork(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + +#ifdef OF_WINDOWS + return address->sockaddr.at.sat_net; +#else + return OFFromBigEndian16(address->sockaddr.at.sat_net); +#endif +} + +void +OFSocketAddressSetAppleTalkNode(OFSocketAddress *address, uint8_t node) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_node = node; +} + +uint8_t +OFSocketAddressAppleTalkNode(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return address->sockaddr.at.sat_node; +} + +void +OFSocketAddressSetAppleTalkPort(OFSocketAddress *address, uint8_t port) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_port = port; +} + +uint8_t +OFSocketAddressAppleTalkPort(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return address->sockaddr.at.sat_port; +}