Artifact 3f2fb0c9c67fc041755cc2e2ff2756cb195a70e83cba00d9b7aefc76386ecbf2:
- File
src/OFTCPSocket.m
— part of check-in
[033054ad75]
at
2009-05-29 19:21:57
on branch trunk
— A few renames.
OFExceptions:
* OFNoMemException to OFOutOfMemoryException.
* OFMemNotPartOfObjException to OFMemoryNotPartOfObjectException.OFObject:
* -[addItemToMemoryPool:] to -[addMemoryToPool:].
* -[allocWithSize:] to -[allocMemoryWithSize:].
* -[allocNItems:withSize] to -[allocMemoryForNItems:withSize:].
* -[resizeMem:toSize] to -[resizeMemory:toSize:].
* -[resizeMem:toNItems:withSize:] to
-[resizeMemoryToNItems:withSize:].
* -[freeMem] to -[freeMemory:].OFString:
* -[urlencode] to -[urlEncodedString].
* -[urldecode] to -[urlDecodedString]. (user: js, size: 6709) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008 - 2009 * Jonathan Schleifer <js@webkeks.org> * * 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. */ #include "config.h" #include <stdio.h> #include <string.h> #include <unistd.h> #ifndef HAVE_GETADDRINFO #include <stdlib.h> #include <arpa/inet.h> #endif #import "OFTCPSocket.h" #import "OFExceptions.h" #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif #ifndef HAVE_GETADDRINFO #import "OFThread.h" static OFObject *lock = nil; #endif @implementation OFTCPSocket #ifndef HAVE_GETADDRINFO + (void)initialize { if (self == [OFTCPSocket class]) lock = [[OFObject alloc] init]; } #endif - (void)dealloc { if (sock != INVALID_SOCKET) close(sock); [super dealloc]; } - connectToService: (OFString*)service onNode: (OFString*)node { if (sock != INVALID_SOCKET) @throw [OFAlreadyConnectedException newWithClass: isa]; #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res, *res0; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo([node cString], [service cString], &hints, &res0)) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; for (res = res0; res != NULL; res = res->ai_next) { if ((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == INVALID_SOCKET) continue; if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) { close(sock); sock = INVALID_SOCKET; continue; } break; } freeaddrinfo(res0); #else BOOL connected = NO; struct hostent *he; struct servent *se; struct sockaddr_in addr; uint16_t port; char **ip; @synchronized (lock) { if ((he = gethostbyname([node cString])) == NULL) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; if ((se = getservbyname([service cString], "TCP")) != NULL) port = se->s_port; else if ((port = htons(atoi([service cString]))) == 0) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = port; if (he->h_addrtype != AF_INET || (sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) @throw [OFConnectionFailedException newWithClass: isa andNode: node andService: service]; for (ip = he->h_addr_list; *ip != NULL; ip++) { memcpy(&addr.sin_addr.s_addr, *ip, he->h_length); if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) continue; connected = YES; break; } if (!connected) { close(sock); sock = INVALID_SOCKET; } } #endif if (sock == INVALID_SOCKET) @throw [OFConnectionFailedException newWithClass: isa andNode: node andService: service]; return self; } - bindService: (OFString*)service onNode: (OFString*)node withFamily: (int)family { if (sock != INVALID_SOCKET) @throw [OFAlreadyConnectedException newWithClass: isa]; if ((sock = socket(family, SOCK_STREAM, 0)) == INVALID_SOCKET) @throw [OFBindFailedException newWithClass: isa andNode: node andService: service andFamily: family]; #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo([node cString], [service cString], &hints, &res)) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) { freeaddrinfo(res); @throw [OFBindFailedException newWithClass: isa andNode: node andService: service andFamily: family]; } freeaddrinfo(res); #else struct hostent *he; struct servent *se; struct sockaddr_in addr; uint16_t port; if (family != AF_INET) @throw [OFBindFailedException newWithClass: isa andNode: node andService: service andFamily: family]; @synchronized (lock) { if ((he = gethostbyname([node cString])) == NULL) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; if ((se = getservbyname([service cString], "TCP")) != NULL) port = se->s_port; else if ((port = htons(atoi([service cString]))) == 0) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = port; if (he->h_addrtype != AF_INET || he->h_addr_list[0] == NULL) @throw [OFAddressTranslationFailedException newWithClass: isa andNode: node andService: service]; memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length); if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) @throw [OFBindFailedException newWithClass: isa andNode: node andService: service andFamily: family]; } #endif return self; } - listenWithBackLog: (int)backlog { if (sock == INVALID_SOCKET) @throw [OFNotConnectedException newWithClass: isa]; if (listen(sock, backlog) == -1) @throw [OFListenFailedException newWithClass: isa andBackLog: backlog]; return self; } - listen { if (sock == INVALID_SOCKET) @throw [OFNotConnectedException newWithClass: isa]; if (listen(sock, 5) == -1) @throw [OFListenFailedException newWithClass: isa andBackLog: 5]; return self; } - (OFTCPSocket*)accept { OFTCPSocket *newsock; struct sockaddr *addr; socklen_t addrlen; int s; newsock = [OFTCPSocket socket]; addrlen = sizeof(struct sockaddr); @try { addr = [newsock allocMemoryWithSize: sizeof(struct sockaddr)]; } @catch (OFException *e) { [newsock dealloc]; @throw e; } if ((s = accept(sock, addr, &addrlen)) == INVALID_SOCKET) { [newsock dealloc]; @throw [OFAcceptFailedException newWithClass: isa]; } newsock->sock = s; newsock->saddr = addr; newsock->saddr_len = addrlen; return newsock; } - enableKeepAlives: (BOOL)enable { int v = enable; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&v, sizeof(v))) @throw [OFSetOptionFailedException newWithClass: isa]; return self; } - close { if (sock == INVALID_SOCKET) @throw [OFNotConnectedException newWithClass: isa]; sock = INVALID_SOCKET; if (saddr != NULL) [self freeMemory: saddr]; saddr_len = 0; return self; } @end