diff --git a/lib/isc/win32/include/isc/net.h b/lib/isc/win32/include/isc/net.h index 86bb6040f8..e84d190a1d 100644 --- a/lib/isc/win32/include/isc/net.h +++ b/lib/isc/win32/include/isc/net.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.h,v 1.28 2007/06/19 23:47:20 tbox Exp $ */ +/* $Id: net.h,v 1.29 2008/07/01 03:55:10 each Exp $ */ #ifndef ISC_NET_H #define ISC_NET_H 1 @@ -306,6 +306,23 @@ isc_net_enableipv4(void); void isc_net_enableipv6(void); +isc_result_t +isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high); +/*%< + * Returns system's default range of ephemeral UDP ports, if defined. + * If the range is not available or unknown, ISC_NET_PORTRANGELOW and + * ISC_NET_PORTRANGEHIGH will be returned. + * + * Requires: + * + *\li 'low' and 'high' must be non NULL. + * + * Returns: + * + *\li *low and *high will be the ports specifying the low and high ends of + * the range. + */ + #ifdef ISC_PLATFORM_NEEDNTOP const char * isc_net_ntop(int af, const void *src, char *dst, size_t size); diff --git a/lib/isc/win32/net.c b/lib/isc/win32/net.c index 29f2656097..5647c424bc 100644 --- a/lib/isc/win32/net.c +++ b/lib/isc/win32/net.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: net.c,v 1.16 2008/04/02 23:46:57 tbox Exp $ */ +/* $Id: net.c,v 1.17 2008/07/01 03:55:10 each Exp $ */ #include @@ -30,6 +30,23 @@ #include #include +/*% + * Definitions about UDP port range specification. This is a total mess of + * portability variants: some use sysctl (but the sysctl names vary), some use + * system-specific interfaces, some have the same interface for IPv4 and IPv6, + * some separate them, etc... + */ + +/*% + * The last resort defaults: use all non well known port space + */ +#ifndef ISC_NET_PORTRANGELOW +#define ISC_NET_PORTRANGELOW 1024 +#endif /* ISC_NET_PORTRANGELOW */ +#ifndef ISC_NET_PORTRANGEHIGH +#define ISC_NET_PORTRANGEHIGH 65535 +#endif /* ISC_NET_PORTRANGEHIGH */ + #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY) const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT; #endif @@ -269,6 +286,22 @@ isc_net_probe_ipv6pktinfo(void) { return (ipv6pktinfo_result); } +isc_result_t +isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) { + int result = ISC_R_FAILURE; + + REQUIRE(low != NULL && high != NULL); + + UNUSED(af); + + if (result != ISC_R_SUCCESS) { + *low = ISC_NET_PORTRANGELOW; + *high = ISC_NET_PORTRANGEHIGH; + } + + return (ISC_R_SUCCESS); /* we currently never fail in this function */ +} + void isc_net_disableipv4(void) { initialize(); diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c index cb1a6f0a28..e8e8c7e73f 100644 --- a/lib/isc/win32/socket.c +++ b/lib/isc/win32/socket.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: socket.c,v 1.55 2008/06/25 23:13:51 jinmei Exp $ */ +/* $Id: socket.c,v 1.56 2008/07/01 03:55:10 each Exp $ */ /* This code has been rewritten to take advantage of Windows Sockets * I/O Completion Ports and Events. I/O Completion Ports is ONLY @@ -1173,7 +1173,7 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, memset(msg, 0, sizeof(*msg)); - if (sock->type == isc_sockettype_udp) { + if (!sock->connected) { msg->msg_name = (void *)&dev->address.type.sa; msg->msg_namelen = dev->address.length; } else { @@ -1869,16 +1869,8 @@ free_socket(isc_socket_t **socketp) { *socketp = NULL; } -/* - * Create a new 'type' socket managed by 'manager'. Events - * will be posted to 'task' and when dispatched 'action' will be - * called with 'arg' as the arg value. The new socket is returned - * in 'socketp'. - */ -isc_result_t -isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, - isc_socket_t **socketp) { - isc_socket_t *sock = NULL; +static isc_result_t +internal_open(isc_socketmgr_t *manager, isc_socket_t *sock) { isc_result_t result; #if defined(USE_CMSG) int on = 1; @@ -1890,17 +1882,9 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, int socket_errno; char strbuf[ISC_STRERRORSIZE]; - REQUIRE(VALID_MANAGER(manager)); - REQUIRE(socketp != NULL && *socketp == NULL); - - result = allocate_socket(manager, type, &sock); - if (result != ISC_R_SUCCESS) - return (result); - - sock->pf = pf; - switch (type) { + switch (sock->type) { case isc_sockettype_udp: - sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP); + sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP); if (sock->fd != INVALID_SOCKET) { result = connection_reset_fix(sock->fd); if (result != ISC_R_SUCCESS) { @@ -1911,13 +1895,12 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, } break; case isc_sockettype_tcp: - sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP); + sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); break; } if (sock->fd == INVALID_SOCKET) { socket_errno = WSAGetLastError(); - free_socket(&sock); switch (socket_errno) { case WSAEMFILE: @@ -1945,19 +1928,17 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, result = make_nonblock(sock->fd); if (result != ISC_R_SUCCESS) { closesocket(sock->fd); - free_socket(&sock); return (result); } - #if defined(USE_CMSG) || defined(SO_RCVBUF) - if (type == isc_sockettype_udp) { + if (sock->type == isc_sockettype_udp) { #if defined(USE_CMSG) #if defined(ISC_PLATFORM_HAVEIPV6) #ifdef IPV6_RECVPKTINFO /* 2292bis */ - if ((pf == AF_INET6) + if ((sock->pf == AF_INET6) && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *)&on, sizeof(on)) < 0)) { isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); @@ -1972,7 +1953,7 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, } #else /* 2292 */ - if ((pf == AF_INET6) + if ((sock->pf == AF_INET6) && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO, (void *)&on, sizeof(on)) < 0)) { isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); @@ -1988,7 +1969,7 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #endif /* IPV6_RECVPKTINFO */ #ifdef IPV6_USE_MIN_MTU /*2292bis, not too common yet*/ /* use minimum MTU */ - if (pf == AF_INET6) { + if (sock->pf == AF_INET6) { (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void *)&on, sizeof(on)); @@ -2011,6 +1992,36 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, } #endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */ + return (ISC_R_SUCCESS); +} + + +/* + * Create a new 'type' socket managed by 'manager'. Events + * will be posted to 'task' and when dispatched 'action' will be + * called with 'arg' as the arg value. The new socket is returned + * in 'socketp'. + */ +isc_result_t +isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp) { + isc_socket_t *sock = NULL; + isc_result_t result; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(socketp != NULL && *socketp == NULL); + + result = allocate_socket(manager, type, &sock); + if (result != ISC_R_SUCCESS) + return (result); + + sock->pf = pf; + result = internal_open(manager, sock); + if (result != ISC_R_SUCCESS) { + free_socket(&sock); + return (result); + } + sock->references = 1; *socketp = sock; @@ -2030,6 +2041,29 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, return (ISC_R_SUCCESS); } +isc_result_t +isc_socket_open(isc_socket_t *sock) { + isc_result_t result; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + REQUIRE(sock->references == 1); + UNLOCK(&sock->lock); + + /* + * We don't need to retain the lock hereafter, since no one else has + * this socket. + */ + REQUIRE(sock->fd == -1); + + result = internal_open(sock->manager, sock); + if (result != ISC_R_SUCCESS) + sock->fd = -1; + + return (result); +} + /* * Attach to a socket. Caller must explicitly detach when it is done. */ @@ -2071,6 +2105,38 @@ isc_socket_detach(isc_socket_t **socketp) { *socketp = NULL; } +void +isc_socket_close(isc_socket_t *sock) { + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + REQUIRE(sock->references == 1); + UNLOCK(&sock->lock); + /* + * We don't need to retain the lock hereafter, since no one else has + * this socket. + */ + REQUIRE(sock->fd >= 0); + + INSIST(!sock->connecting); + INSIST(!sock->pending_recv); + INSIST(!sock->pending_send); + INSIST(!sock->pending_accept); + INSIST(ISC_LIST_EMPTY(sock->recv_list)); + INSIST(ISC_LIST_EMPTY(sock->send_list)); + INSIST(ISC_LIST_EMPTY(sock->accept_list)); + INSIST(sock->connect_ev == NULL); + + sock->fd = -1; + sock->listener = 0; + sock->connected = 0; + sock->connecting = 0; + sock->bound = 0; + isc_sockaddr_any(&sock->address); + + socket_close(sock); +} + /* * Dequeue an item off the given socket's read queue, set the result code * in the done event to the one provided, and send it to the task it was