Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -50,16 +50,18 @@ onPort: (uint16_t)port; /** * Bind the socket on the specified port and host. * - * \param port The port to bind to + * \param port The port to bind to. If the port is 0, an unused port will be + * chosen, which can be obtained using the return value. * \param host The host to bind to. Use @"0.0.0.0" for IPv4 or @"::" for IPv6 * to bind to all. + * \return The port the socket was bound to */ -- (void)bindToPort: (uint16_t)port - onHost: (OFString*)host; +- (uint16_t)bindToPort: (uint16_t)port + onHost: (OFString*)host; /** * Listen on the socket. * * \param backlog Maximum length for the queue of pending connections. Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -193,13 +193,16 @@ socket: self host: host port: port]; } -- (void)bindToPort: (uint16_t)port - onHost: (OFString*)host +- (uint16_t)bindToPort: (uint16_t)port + onHost: (OFString*)host { + struct sockaddr_storage addr; + socklen_t addrLen; + if (sock != INVALID_SOCKET) @throw [OFAlreadyConnectedException newWithClass: isa socket: self]; #ifdef HAVE_THREADSAFE_GETADDRINFO @@ -233,11 +236,10 @@ } freeaddrinfo(res); #else struct hostent *he; - struct sockaddr_in addr; # ifdef OF_THREADS [mutex lock]; # endif @@ -244,43 +246,74 @@ if ((he = gethostbyname([host cString])) == NULL) { # ifdef OF_THREADS [mutex unlock]; # endif @throw [OFAddressTranslationFailedException newWithClass: isa + socket: self host: host]; } memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = of_bswap16_if_le(port); + ((struct sockaddr_in*)&addr)->sin_family = AF_INET; + ((struct sockaddr_in*)&addr)->sin_port = of_bswap16_if_le(port); if (he->h_addrtype != AF_INET || he->h_addr_list[0] == NULL) { # ifdef OF_THREADS [mutex unlock]; # endif @throw [OFAddressTranslationFailedException newWithClass: isa + socket: self host: host]; } - memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length); + memcpy(&((struct sockaddr_in*)&addr)->sin_addr.s_addr, + he->h_addr_list[0], he->h_length); # ifdef OF_THREADS [mutex unlock]; # endif if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) @throw [OFBindFailedException newWithClass: isa + socket: self host: host port: port]; if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { close(sock); sock = INVALID_SOCKET; @throw [OFBindFailedException newWithClass: isa + socket: self host: host port: port]; } #endif + + if (port > 0) + return port; + + addrLen = sizeof(addr); + if (getsockname(sock, (struct sockaddr*)&addr, &addrLen)) { + close(sock); + sock = INVALID_SOCKET; + @throw [OFBindFailedException newWithClass: isa + socket: self + host: host + port: port]; + } + + if (addr.ss_family == AF_INET) + return of_bswap16_if_le(((struct sockaddr_in*)&addr)->sin_port); + if (addr.ss_family == AF_INET6) + return of_bswap16_if_le( + ((struct sockaddr_in6*)&addr)->sin6_port); + + close(sock); + sock = INVALID_SOCKET; + @throw [OFBindFailedException newWithClass: isa + socket: self + host: host + port: port]; } - (void)listenWithBackLog: (int)backlog { if (sock == INVALID_SOCKET) Index: tests/OFHTTPRequestTests.m ================================================================== --- tests/OFHTTPRequestTests.m +++ tests/OFHTTPRequestTests.m @@ -47,12 +47,12 @@ OFTCPSocket *listener, *client; [cond lock]; listener = [OFTCPSocket socket]; - [listener bindToPort: port - onHost: @"127.0.0.1"]; + port = [listener bindToPort: 0 + onHost: @"127.0.0.1"]; [listener listen]; [cond signal]; [cond unlock]; @@ -93,27 +93,23 @@ cond = [OFCondition condition]; [cond lock]; server = [[[OFHTTPRequestTestsServer alloc] init] autorelease]; - /* srand(time(NULL)) was already called by OFTCPSocket */ - server->port = (uint16_t)rand(); - if (server->port < 1024) - server->port += 1024; [server start]; + [cond wait]; + [cond unlock]; + url = [OFURL URLWithString: [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo", server->port]]; TEST(@"+[requestWithURL]", (req = [OFHTTPRequest requestWithURL: url])) - [cond wait]; - [cond unlock]; - TEST(@"-[perform]", (res = [req perform])) [server join]; [pool drain]; } @end Index: tests/OFTCPSocketTests.m ================================================================== --- tests/OFTCPSocketTests.m +++ tests/OFTCPSocketTests.m @@ -14,13 +14,11 @@ * file. */ #include "config.h" -#include #include -#include #import "OFTCPSocket.h" #import "OFString.h" #import "OFAutoreleasePool.h" @@ -33,25 +31,18 @@ @implementation TestsAppDelegate (OFTCPSocketTests) - (void)TCPSocketTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFTCPSocket *server, *client = nil, *accepted; - OFString *msg; uint16_t port; char buf[6]; - srand((unsigned)time(NULL)); - port = (uint16_t)rand(); - if (port < 1024) - port += 1024; - TEST(@"+[socket]", (server = [OFTCPSocket socket]) && (client = [OFTCPSocket socket])) - msg = [OFString stringWithFormat: - @"-[bindToPort:onHost:] (port %" @PRIu16 @")", port]; - TEST(msg, R([server bindToPort: port + TEST(@"-[bindToPort:onHost:]", + (port = [server bindToPort: 0 onHost: @"127.0.0.1"])) TEST(@"-[listen]", R([server listen])) TEST(@"-[connectToHost:onPort:]",