Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -22,18 +22,58 @@ * The OFTCPSocket class provides functions to create and use sockets. */ @interface OFTCPSocket: OFObject { int sock; + struct sockaddr *saddr; + socklen_t saddr_len; } +/** + * Initializes an already allocated OFTCPSocket. + * + * \return An initialized OFTCPSocket + */ +- init; + - free; +- setSocket: (int)socket; +- setSocketAddress: (struct sockaddr*)sockaddr + withLength: (socklen_t)len; /** * Connect the OFTCPSocket to the specified destination. * - * \param host The host to connect to + * \param host The host or IP to connect to * \param port The port of the host to connect to */ - connectTo: (const char*)host onPort: (uint16_t)port; + +/** + * Bind socket to the specified address and port. + * + * \param host The host or IP to bind to + * \param port The port to bind to + * \param protocol The protocol to use (AF_INET or AF_INET6) + */ +- bindOn: (const char*)host + withPort: (uint16_t)port + andFamily: (int)family; + +/** + * Listen on the socket. + * + * \param backlog Maximum length for the queue of pending connections. + */ +- listenWithBackLog: (int)backlog; + +/** + * Listen on the socket. + */ +- listen; + +/** + * Accept an incoming connection. + */ +- (OFTCPSocket*)accept; @end Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -18,33 +18,65 @@ #import "OFTCPSocket.h" #import "OFExceptions.h" @implementation OFTCPSocket +- init +{ + if ((self = [super init])) { + sock = -1; + saddr = NULL; + saddr_len = 0; + } + + return self; +} + - free { if (sock >= 0) close(sock); return [super free]; } + +- setSocket: (int)socket +{ + sock = socket; + + return self; +} + +- setSocketAddress: (struct sockaddr*)sockaddr + withLength: (socklen_t)len +{ + saddr = sockaddr; + saddr_len = len; + + return self; +} - connectTo: (const char*)host onPort: (uint16_t)port { struct addrinfo hints, *res, *res0; char portstr[6]; + + if (!port) { + /* FIXME: Throw exception */ + return nil; + } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, 6, "%d", port); if (getaddrinfo(host, portstr, &hints, &res0)) { /* FIXME: Throw exception */ - return NULL; + return nil; } for (res = res0; res != NULL; res = res->ai_next) { if ((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) @@ -66,15 +98,118 @@ return nil; } return self; } + +- bindOn: (const char*)host + withPort: (uint16_t)port + andFamily: (int)family +{ + struct addrinfo hints, *res; + char portstr[6]; + + if (!port) { + /* FIXME: Throw exception */ + return nil; + } + + if ((sock = socket(family, SOCK_STREAM, 0)) < 0) { + /* FIXME: Throw exception */ + return nil; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + + snprintf(portstr, 6, "%d", port); + + if (getaddrinfo(host, portstr, &hints, &res)) { + /* FIXME: Throw exception */ + return nil; + } + + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { + /* FIXME: Throw exception */ + freeaddrinfo(res); + return nil; + } + + freeaddrinfo(res); + + return self; +} + +- listenWithBackLog: (int)backlog +{ + if (sock < 0) { + /* FIXME: Throw exception */ + return nil; + } + + if (listen(sock, backlog) < 0 ) { + /* FIXME: Throw exception */ + return nil; + } + + return self; +} + +- listen +{ + if (sock < 0) { + /* FIXME: Throw exception */ + return nil; + } + + if (listen(sock, 5) < 0 ) { + /* FIXME: Throw exception */ + return nil; + } + + return self; +} + +- (OFTCPSocket*)accept +{ + OFTCPSocket *newsock; + struct sockaddr *addr; + socklen_t addrlen; + int s; + + newsock = [OFTCPSocket new]; + addrlen = sizeof(struct sockaddr); + + @try { + addr = [newsock getMemWithSize: sizeof(struct sockaddr)]; + } @catch(id e) { + [newsock free]; + @throw e; + } + + if ((s = accept(sock, addr, &addrlen)) < 0) { + /* FIXME: Throw exception */ + return nil; + } + + [newsock setSocket: s]; + [newsock setSocketAddress: addr + withLength: addrlen]; + + return newsock; +} - (size_t)readNBytes: (size_t)size intoBuffer: (uint8_t*)buf { ssize_t ret; + + if (sock < 0) { + /* FIXME: Throw exception */ + return 0; + } if ((ret = recv(sock, buf, size, 0)) < 0) { /* FIXME: Throw exception */ return 0; } @@ -84,10 +219,15 @@ } - (uint8_t*)readNBytes: (size_t)size { uint8_t *ret; + + if (sock < 0) { + /* FIXME: Throw exception */ + return NULL; + } ret = [self getMemWithSize: size]; @try { [self readNBytes: size @@ -102,10 +242,15 @@ - (size_t)writeNBytes: (size_t)size fromBuffer: (const uint8_t*)buf { ssize_t ret; + + if (sock < 0) { + /* FIXME: Throw exception */ + return 0; + } if ((ret = send(sock, buf, size, 0)) < 0) { /* FIXME: Throw exception */ return 0; } @@ -114,10 +259,15 @@ return ret; } - (size_t)writeCString: (const char*)str { + if (sock < 0) { + /* FIXME: Throw exception */ + return 0; + } + return [self writeNBytes: strlen(str) fromBuffer: (const uint8_t*)str]; } - close Index: tests/OFTCPSocket/OFTCPSocket.m ================================================================== --- tests/OFTCPSocket/OFTCPSocket.m +++ tests/OFTCPSocket/OFTCPSocket.m @@ -18,17 +18,73 @@ int main() { @try { - OFTCPSocket *sock = [[OFTCPSocket new] connectTo: "webkeks.org" - onPort: 80]; - [sock writeCString: "GET / HTTP/1.1\r\n" - "Host: webkeks.org\r\n\r\n"]; - puts((char*)[sock readNBytes: 1024]); - [sock free]; + OFTCPSocket *server = [OFTCPSocket new]; + OFTCPSocket *client = [OFTCPSocket new]; + OFTCPSocket *accepted; + char buf[8]; + + puts("== IPv4 =="); + + [server bindOn: "localhost" + withPort: 12345 + andFamily: AF_INET]; + [server listen]; + + [client connectTo: "localhost" + onPort: 12345]; + + accepted = [server accept]; + + [client writeCString: "Hallo!"]; + [accepted readNBytes: 7 + intoBuffer: (uint8_t*)buf]; + buf[7] = 0; + + if (!strcmp(buf, "Hallo!")) + puts("Received correct string!"); + else { + puts("Received INCORRECT string!"); + return 1; + } + + memset(buf, 0, 8); + + [accepted free]; + [client close]; + [server close]; + + puts("== IPv6 =="); + + [server bindOn: "localhost" + withPort: 12345 + andFamily: AF_INET6]; + [server listen]; + + [client connectTo: "localhost" + onPort: 12345]; + + accepted = [server accept]; + + [client writeCString: "IPv6 :)"]; + [accepted readNBytes: 7 + intoBuffer: (uint8_t*)buf]; + buf[7] = 0; + + if (!strcmp(buf, "IPv6 :)")) + puts("Received correct string!"); + else { + puts("Received INCORRECT string!"); + return 1; + } + + [accepted free]; + [client close]; + [server close]; } @catch(OFException *e) { printf("EXCEPTION: %s\n", [e cString]); } return 0; }