Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -7,10 +7,11 @@ OFHashes.m \ OFFile.m \ OFList.m \ OFListObject.m \ OFObject.m \ + OFSocket.m \ OFString.m \ OFXMLFactory.m INCLUDES = ${SRCS:.m=.h} \ OFMacros.h \ Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -118,14 +118,13 @@ @try { [self readNItems: nitems ofSize: size intoBuffer: ret]; - } @catch (OFReadFailedException *e) { + } @catch (id exception) { [self freeMem: ret]; - @throw e; - return NULL; + @throw exception; } return ret; } ADDED src/OFSocket.h Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2008 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import + +#import +#import +#import + +#import "OFObject.h" +#import "OFStream.h" + +/** + * The OFSocketAddress class is a class to build socket addresses. + */ +@interface OFSocketAddress: OFObject +{ + char *hoststr, portstr[6]; + struct addrinfo hints, *res; +} + +/** + * \param host The host of the address + * \param port The port of the address + * \param family The protocol family to use + * \param type The socket type to use + * \param protocol The specific protocol to use + * \return A new OFSocketAddress + */ ++ newWithHost: (const char*)host + andPort: (uint16_t)port + andFamily: (int)family + andType: (int)type + andProtocol: (int)protocol; + +/** + * Initializes an already allocated OFSocketAddress. + * + * \param host The host of the address + * \param port The port of the address + * \param family The protocol family to use + * \param type The socket type to use + * \param protocol The specific protocol to use + * \return An initialized OFSocketAddress + */ +- initWithHost: (const char*)host + andPort: (uint16_t)port + andFamily: (int)family + andType: (int)type + andProtocol: (int)protocol; + +/* + * \return The addrinfo struct for the OFSocketAddress + */ +- (struct addrinfo*)getAddressInfo; + +- free; +@end + +/** + * The OFSocket class provides functions to create and use sockets. + */ +@interface OFSocket: OFObject +{ + int sock; +} + +- free; + +/** + * Connect the OFSocket to a destination specified in an OFSocketAddress. + * + * \param addr A OFSocketAddress to connect to. + */ +- connect: (OFSocketAddress*)addr; + +/** + * Receive data from the socket into a buffer. + * + * \param buf The buffer into which the data is read + * \param size The size of the data that should be read. + * The buffer MUST be at least size big! + * \return The number of bytes read + */ +- (size_t)readNBytes: (size_t)size + intoBuffer: (uint8_t*)buf; + +/** + * Receive data from the socket into a new buffer. + * + * \param size The size of the data that should be read + * \return A new buffer with the data read. + * It is part of the memory pool of the OFFile. + */ +- (uint8_t*)readNBytes: (size_t)size; + +/** + * Sends data from a buffer. + * + * \param buf The buffer from which the data is written to the file + * \param size The size of the data that should be written + * \return The number of bytes written + */ +- (size_t)writeNBytes: (size_t)size + fromBuffer: (uint8_t*)buf; +@end ADDED src/OFSocket.m Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2008 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "config.h" + +#import +#import +#import + +#import "OFSocket.h" + +@implementation OFSocketAddress ++ newWithHost: (const char*)host + andPort: (uint16_t)port + andFamily: (int)family + andType: (int)type + andProtocol: (int)protocol +{ + return [[OFSocketAddress alloc] initWithHost: host + andPort: port + andFamily: family + andType: type + andProtocol: protocol]; +} + +- initWithHost: (const char*)host + andPort: (uint16_t)port + andFamily: (int)family + andType: (int)type + andProtocol: (int)protocol +{ + if ((self = [super init])) { + if (port == 0) { + /* FIXME: Throw exception */ + [self free]; + return nil; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_socktype = type; + hints.ai_protocol = protocol; + + hoststr = strdup(host); + snprintf(portstr, 6, "%d", port); + + res = NULL; + } + + return self; +} + +- (struct addrinfo*)getAddressInfo +{ + if (res != NULL) + return res; + + if (getaddrinfo(hoststr, portstr, &hints, &res)) { + /* FIXME: Throw exception */ + return NULL; + } + + return res; +} + +- free +{ + free(hoststr); + + if (res != NULL) + freeaddrinfo(res); + + return [super free]; +} +@end + +@implementation OFSocket +- free +{ + if (sock >= 0) + close(sock); + + return [super free]; +} + +- connect: (OFSocketAddress*)addr +{ + struct addrinfo *ai, *iter; + + ai = [addr getAddressInfo]; + for (iter = ai; iter != NULL; iter = iter->ai_next) { + if ((sock = socket(iter->ai_family, iter->ai_socktype, + iter->ai_protocol)) < 0) + continue; + + if (connect(sock, iter->ai_addr, iter->ai_addrlen) < 0) { + close(sock); + sock = -1; + continue; + } + + break; + } + + if (sock < 0) { + /* FIXME: Throw exception */ + return nil; + } + + return self; +} + +- (size_t)readNBytes: (size_t)size + intoBuffer: (uint8_t*)buf +{ + ssize_t ret; + + if ((ret = recv(sock, buf, size, 0)) < 0) { + /* FIXME: Throw exception */ + return 0; + } + + /* This is safe, as we already checked < 0 */ + return ret; +} + +- (uint8_t*)readNBytes: (size_t)size +{ + uint8_t *ret; + + ret = [self getMemWithSize: size]; + + @try { + [self readNBytes: size + intoBuffer: ret]; + } @catch (id exception) { + [self freeMem: ret]; + @throw exception; + } + + return ret; +} + +- (size_t)writeNBytes: (size_t)size + fromBuffer: (uint8_t*)buf +{ + ssize_t ret; + + if ((ret = send(sock, buf, size, 0)) < 0) { + /* FIXME: Throw exception */ + return 0; + } + + /* This is safe, as we already checked < 0 */ + return ret; +} +@end Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,8 +1,9 @@ SUBDIRS = OFObject \ OFArray \ OFHashes \ + OFSocket \ OFString \ OFList \ OFXMLFactory include ../buildsys.mk ADDED tests/OFSocket/Makefile Index: tests/OFSocket/Makefile ================================================================== --- tests/OFSocket/Makefile +++ tests/OFSocket/Makefile @@ -0,0 +1,20 @@ +PROG_NOINST = ofsocket +SRCS = OFSocket.m + +include ../../buildsys.mk + +CPPFLAGS += -I../../src -I../.. +LIBS += -lobjc -L../../src -lobjfw + +.PHONY: run + +all: run +run: ${PROG_NOINST} + rm -f libobjfw.so.1 libobjfw.so.1.0 libobjfw.dylib + ln -s ../../src/libobjfw.so libobjfw.so.1 + ln -s ../../src/libobjfw.so libobjfw.so.1.0 + ln -s ../../src/libobjfw.dylib libobjfw.dylib + LD_LIBRARY_PATH=. \ + DYLD_LIBRARY_PATH=. \ + ./${PROG_NOINST} + rm -f libobjfw.so.1 libobjfw.so.1.0 libobjfw.dylib ADDED tests/OFSocket/OFSocket.m Index: tests/OFSocket/OFSocket.m ================================================================== --- tests/OFSocket/OFSocket.m +++ tests/OFSocket/OFSocket.m @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of libobjfw. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#import "config.h" + +#import + +#import "OFSocket.h" +#import "OFExceptions.h" + +const char *sendstr = "GET / HTTP/1.1\r\nHost: webkeks.org\r\n\r\n"; + +int +main() +{ + OFSocketAddress *addr; + OFSocket *sock; + + @try { + addr = [OFSocketAddress newWithHost: "webkeks.org" + andPort: 80 + andFamily: AF_UNSPEC + andType: SOCK_STREAM + andProtocol: 0]; + sock = [OFSocket new]; + [sock connect: addr]; + [addr free]; + + [sock writeNBytes: strlen(sendstr) + fromBuffer: (uint8_t*)sendstr]; + + puts((char*)[sock readNBytes: 1024]); + + [sock free]; + } @catch(OFException *e) { + printf("EXCEPTION: %s\n", [e cString]); + } + + return 0; +}