/* extern */ Boolean _CFServerStart(_CFServerRef server, CFStringRef name, CFStringRef type, UInt32 port) { Server* s = (Server*)server; CFDataRef address = NULL; do { unsigned i; CFRunLoopRef rl = CFRunLoopGetCurrent(); CFAllocatorRef alloc = CFGetAllocator(server); struct sockaddr_in addr4; struct sockaddr_in6 addr6; // Make sure the port is valid (0 - 65535). if ((port & 0xFFFF0000U) != 0) break; // NULL means to use the machine name. if (name == NULL) name = _kCFServerEmptyString; for (i = 0; i < (sizeof(s->_sockets) / sizeof(s->_sockets[0])); i++) { // Create the run loop source for putting on the run loop. CFRunLoopSourceRef src = CFSocketCreateRunLoopSource(alloc, s->_sockets[i], 0); if (src == NULL) break; // Add the run loop source to the current run loop and default mode. CFRunLoopAddSource(rl, src, kCFRunLoopCommonModes); CFRelease(src); } memset(&addr4, 0, sizeof(addr4)); // Put the local port and address into the native address. #if !defined(__WIN32__) addr4.sin_len = sizeof(addr4); #endif addr4.sin_family = AF_INET; addr4.sin_port = htons((UInt16)port); addr4.sin_addr.s_addr = htonl(INADDR_ANY); // Wrap the native address structure for CFSocketCreate. address = CFDataCreateWithBytesNoCopy(alloc, (const UInt8*)&addr4, sizeof(addr4), kCFAllocatorNull); // If it failed to create the address data, bail. if (address == NULL) break; // Set the local binding which causes the socket to start listening. if (CFSocketSetAddress(s->_sockets[0], address) != kCFSocketSuccess) break; CFRelease(address); address = CFSocketCopyAddress(s->_sockets[0]); memcpy(&addr4, CFDataGetBytePtr(address), CFDataGetLength(address)); port = ntohs(addr4.sin_port); CFRelease(address); memset(&addr6, 0, sizeof(addr6)); // Put the local port and address into the native address. addr6.sin6_family = AF_INET6; #ifndef __WIN32__ addr6.sin6_port = htons((UInt16)port); addr6.sin6_len = sizeof(addr6); memcpy(&(addr6.sin6_addr), &in6addr_any, sizeof(addr6.sin6_addr)); #else #ifndef __MINGW32__ // real MS headers have this IN6ADDR_SETANY(addr6); addr6.sin6_port = htons((UInt16)port); #else addr6.sin6_port = htons((UInt16)port); // mingw's w32 headers have this INIT macro instead, for some odd reason struct sockaddr_in6 in6addr_any = IN6ADDR_ANY_INIT; memcpy(&(addr6.sin6_addr), &in6addr_any, sizeof(addr6.sin6_addr)); #endif #endif // Wrap the native address structure for CFSocketCreate. address = CFDataCreateWithBytesNoCopy(alloc, (const UInt8*)&addr6, sizeof(addr6), kCFAllocatorNull); // Set the local binding which causes the socket to start listening. if (CFSocketSetAddress(s->_sockets[1], address) != kCFSocketSuccess) break; // Save the name, service type and port. s->_name = CFRetain(name); s->_type = type ? CFRetain(type) : NULL; s->_port = port; #if defined(__MACH__) // Attempt to register the service on the network. if (type && !_ServerCreateAndRegisterNetService(s)) break; #endif // Release this since it's not needed any longer. CFRelease(address); return TRUE; } while (0); // Handle the error cleanup. // Release the address data if it was created. if (address) CFRelease(address); // Kill the socket if it was created. _ServerReleaseSocket(s); return FALSE; }
JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind* b) { int fd=-1, ofd=-1, rv, len; /* need to defer close until new sockets created */ int close_fd=-1, close_ofd=-1; SOCKETADDRESS oaddr; /* other address to bind */ int family = b->addr->him.sa_family; int ofamily; u_short port; /* requested port parameter */ u_short bound_port; if (family == AF_INET && (b->addr->him4.sin_addr.s_addr != INADDR_ANY)) { /* bind to v4 only */ int ret; ret = NET_Bind (b->ipv4_fd, (struct sockaddr *)b->addr, sizeof (struct sockaddr_in)); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } closesocket (b->ipv6_fd); b->ipv6_fd = -1; return 0; } if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->him6.sin6_addr))) { /* bind to v6 only */ int ret; ret = NET_Bind (b->ipv6_fd, (struct sockaddr *)b->addr, sizeof (struct SOCKADDR_IN6)); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } closesocket (b->ipv4_fd); b->ipv4_fd = -1; return 0; } /* We need to bind on both stacks, with the same port number */ memset (&oaddr, 0, sizeof(oaddr)); if (family == AF_INET) { ofamily = AF_INET6; fd = b->ipv4_fd; ofd = b->ipv6_fd; port = (u_short)GET_PORT (b->addr); IN6ADDR_SETANY (&oaddr.him6); oaddr.him6.sin6_port = port; } else { ofamily = AF_INET; ofd = b->ipv4_fd; fd = b->ipv6_fd; port = (u_short)GET_PORT (b->addr); oaddr.him4.sin_family = AF_INET; oaddr.him4.sin_port = port; oaddr.him4.sin_addr.s_addr = INADDR_ANY; } rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* get the port and set it in the other address */ len = SOCKETADDRESS_LEN(b->addr); if (getsockname(fd, (struct sockaddr *)b->addr, &len) == -1) { CLOSE_SOCKETS_AND_RETURN; } bound_port = GET_PORT (b->addr); SET_PORT (&oaddr, bound_port); if ((rv=NET_Bind (ofd, (struct sockaddr *) &oaddr, SOCKETADDRESS_LEN (&oaddr))) == SOCKET_ERROR) { int retries; int sotype, arglen=sizeof(sotype); /* no retries unless, the request was for any free port */ if (port != 0) { CLOSE_SOCKETS_AND_RETURN; } getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen); #define SOCK_RETRIES 50 /* 50 is an arbitrary limit, just to ensure that this * cannot be an endless loop. Would expect socket creation to * succeed sooner. */ for (retries = 0; retries < SOCK_RETRIES; retries ++) { int len; close_fd = fd; fd = -1; close_ofd = ofd; ofd = -1; b->ipv4_fd = SOCKET_ERROR; b->ipv6_fd = SOCKET_ERROR; /* create two new sockets */ fd = socket (family, sotype, 0); if (fd == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } ofd = socket (ofamily, sotype, 0); if (ofd == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* bind random port on first socket */ SET_PORT (&oaddr, 0); rv = NET_Bind (ofd, (struct sockaddr *)&oaddr, SOCKETADDRESS_LEN(&oaddr)); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* close the original pair of sockets before continuing */ closesocket (close_fd); closesocket (close_ofd); close_fd = close_ofd = -1; /* bind new port on second socket */ len = SOCKETADDRESS_LEN(&oaddr); if (getsockname(ofd, (struct sockaddr *)&oaddr, &len) == -1) { CLOSE_SOCKETS_AND_RETURN; } bound_port = GET_PORT (&oaddr); SET_PORT (b->addr, bound_port); rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); if (rv != SOCKET_ERROR) { if (family == AF_INET) { b->ipv4_fd = fd; b->ipv6_fd = ofd; } else { b->ipv4_fd = ofd; b->ipv6_fd = fd; } return 0; } } CLOSE_SOCKETS_AND_RETURN; } return 0; }