Artifact 2b1705fa68f22b25782a5a9dbe22f68a3ce71d32c9899eb933643bd189874a36:
- File
src/OFUDPSocket.m
— part of check-in
[13ee56edf3]
at
2014-06-21 21:43:43
on branch trunk
— Move all macros from OFObject.h to macros.h
This means that OFObject.h imports macros.h now, making it unnecessary
to manually import macros.h in almost every file. And while at it, also
import autorelease.h in OFObject.h, so that this doesn't need to be
manually imported in almost every file as well. (user: js, size: 12231) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <string.h> #include <assert.h> #import "OFUDPSocket.h" #ifdef OF_HAVE_THREADS # import "OFThread.h" #endif #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFBindFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotConnectedException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" #import "resolver.h" #import "socket_helpers.h" #ifdef __wii__ static uint16_t freePort = 65532; #endif #ifdef OF_HAVE_THREADS @interface OFUDPSocket_ResolveThread: OFThread { OFThread *_sourceThread; OFString *_host; uint16_t _port; id _target; SEL _selector; # ifdef OF_HAVE_BLOCKS of_udp_socket_async_resolve_block_t _block; # endif of_udp_socket_address_t _address; OFException *_exception; } - initWithSourceThread: (OFThread*)sourceThread host: (OFString*)host port: (uint16_t)port target: (id)target selector: (SEL)selector; # ifdef OF_HAVE_BLOCKS - initWithSourceThread: (OFThread*)sourceThread host: (OFString*)host port: (uint16_t)port block: (of_udp_socket_async_resolve_block_t)block; # endif @end @implementation OFUDPSocket_ResolveThread - initWithSourceThread: (OFThread*)sourceThread host: (OFString*)host port: (uint16_t)port target: (id)target selector: (SEL)selector { self = [super init]; @try { _sourceThread = [sourceThread retain]; _host = [host retain]; _port = port; _target = [target retain]; _selector = selector; } @catch (id e) { [self release]; @throw e; } return self; } # ifdef OF_HAVE_BLOCKS - initWithSourceThread: (OFThread*)sourceThread host: (OFString*)host port: (uint16_t)port block: (of_udp_socket_async_resolve_block_t)block { self = [super init]; @try { _sourceThread = [sourceThread retain]; _host = [host copy]; _port = port; _block = [block copy]; } @catch (id e) { [self release]; @throw e; } return self; } # endif - (void)dealloc { [_sourceThread release]; [_host release]; [_target release]; # ifdef OF_HAVE_BLOCKS [_block release]; # endif [_exception release]; [super dealloc]; } - (void)didResolve { [self join]; # ifdef OF_HAVE_BLOCKS if (_block != NULL) _block(_host, _port, _address, _exception); else { # endif void (*func)(id, SEL, OFString*, uint16_t, of_udp_socket_address_t, OFException*) = (void(*)(id, SEL, OFString*, uint16_t, of_udp_socket_address_t, OFException*))[_target methodForSelector: _selector]; func(_target, _selector, _host, _port, _address, _exception); # ifdef OF_HAVE_BLOCKS } # endif } - (id)main { void *pool = objc_autoreleasePoolPush(); @try { [OFUDPSocket resolveAddressForHost: _host port: _port address: &_address]; } @catch (OFException *e) { _exception = e; } [self performSelector: @selector(didResolve) onThread: _sourceThread waitUntilDone: false]; objc_autoreleasePoolPop(pool); return nil; } @end #endif bool of_udp_socket_address_equal(of_udp_socket_address_t *address1, of_udp_socket_address_t *address2) { struct sockaddr_in *sin_1, *sin_2; #ifdef AF_INET6 struct sockaddr_in6 *sin6_1, *sin6_2; #endif if (address1->address.ss_family != address2->address.ss_family) return false; switch (address1->address.ss_family) { case AF_INET: if (address1->length < sizeof(struct sockaddr_in) || address2->length < sizeof(struct sockaddr_in)) @throw [OFInvalidArgumentException exception]; sin_1 = (struct sockaddr_in*)&address1->address; sin_2 = (struct sockaddr_in*)&address2->address; if (sin_1->sin_port != sin_2->sin_port) return false; if (sin_1->sin_addr.s_addr != sin_2->sin_addr.s_addr) return false; break; #ifdef AF_INET6 case AF_INET6: if (address1->length < sizeof(struct sockaddr_in6) || address2->length < sizeof(struct sockaddr_in6)) @throw [OFInvalidArgumentException exception]; sin6_1 = (struct sockaddr_in6*)&address1->address; sin6_2 = (struct sockaddr_in6*)&address2->address; if (sin6_1->sin6_port != sin6_2->sin6_port) return false; if (memcmp(sin6_1->sin6_addr.s6_addr, sin6_2->sin6_addr.s6_addr, sizeof(sin6_1->sin6_addr.s6_addr)) != 0) return false; break; #endif default: @throw [OFInvalidArgumentException exception]; } return true; } uint32_t of_udp_socket_address_hash(of_udp_socket_address_t *address) { uint32_t hash = of_hash_seed; struct sockaddr_in *sin; #ifdef AF_INET6 struct sockaddr_in6 *sin6; uint32_t subhash; size_t i; #endif hash += address->address.ss_family; switch (address->address.ss_family) { case AF_INET: if (address->length < sizeof(struct sockaddr_in)) @throw [OFInvalidArgumentException exception]; sin = (struct sockaddr_in*)&address->address; hash += (sin->sin_port << 1); hash ^= sin->sin_addr.s_addr; break; #ifdef AF_INET6 case AF_INET6: if (address->length < sizeof(struct sockaddr_in6)) @throw [OFInvalidArgumentException exception]; sin6 = (struct sockaddr_in6*)&address->address; hash += (sin6->sin6_port << 1); OF_HASH_INIT(subhash); for (i = 0; i < sizeof(sin6->sin6_addr.s6_addr); i++) OF_HASH_ADD(subhash, sin6->sin6_addr.s6_addr[i]); OF_HASH_FINALIZE(subhash); hash ^= subhash; break; #endif default: @throw [OFInvalidArgumentException exception]; } return hash; } @implementation OFUDPSocket + (void)initialize { if (self != [OFUDPSocket class]) return; if (!of_init_sockets()) @throw [OFInitializationFailedException exceptionWithClass: self]; } + (instancetype)socket { return [[[self alloc] init] autorelease]; } + (void)resolveAddressForHost: (OFString*)host port: (uint16_t)port address: (of_udp_socket_address_t*)address { of_resolver_result_t **results = of_resolve_host(host, port, SOCK_DGRAM); assert(results[0]->addressLength <= sizeof(address->address)); memcpy(&address->address, results[0]->address, results[0]->addressLength); address->length = results[0]->addressLength; of_resolver_free(results); } #ifdef OF_HAVE_THREADS + (void)asyncResolveAddressForHost: (OFString*)host port: (uint16_t)port target: (id)target selector: (SEL)selector { void *pool = objc_autoreleasePoolPush(); [[[[OFUDPSocket_ResolveThread alloc] initWithSourceThread: [OFThread currentThread] host: host port: port target: target selector: selector] autorelease] start]; objc_autoreleasePoolPop(pool); } # ifdef OF_HAVE_BLOCKS + (void)asyncResolveAddressForHost: (OFString*)host port: (uint16_t)port block: (of_udp_socket_async_resolve_block_t)block { void *pool = objc_autoreleasePoolPush(); [[[[OFUDPSocket_ResolveThread alloc] initWithSourceThread: [OFThread currentThread] host: host port: port block: block] autorelease] start]; objc_autoreleasePoolPop(pool); } # endif #endif + (void)getHost: (OFString *__autoreleasing*)host andPort: (uint16_t*)port forAddress: (of_udp_socket_address_t*)address { of_address_to_string_and_port( (struct sockaddr*)&address->address, address->length, host, port); } - init { self = [super init]; _socket = INVALID_SOCKET; return self; } - (void)dealloc { if (_socket != INVALID_SOCKET) [self close]; [super dealloc]; } - (id)copy { return [self retain]; } - (uint16_t)bindToHost: (OFString*)host port: (uint16_t)port { of_resolver_result_t **results; #ifndef __wii__ union { struct sockaddr_storage storage; struct sockaddr_in in; # ifdef AF_INET6 struct sockaddr_in6 in6; # endif } addr; socklen_t addrLen; #endif #ifdef __wii__ if (port == 0) port = freePort--; #endif results = of_resolve_host(host, port, SOCK_DGRAM); @try { if ((_socket = socket(results[0]->family, results[0]->type, results[0]->protocol)) == INVALID_SOCKET) @throw [OFBindFailedException exceptionWithHost: host port: port socket: self]; if (bind(_socket, results[0]->address, results[0]->addressLength) == -1) { close(_socket); _socket = INVALID_SOCKET; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self]; } } @finally { of_resolver_free(results); } if (port > 0) return port; #ifndef __wii__ addrLen = (socklen_t)sizeof(addr.storage); if (getsockname(_socket, (struct sockaddr*)&addr.storage, &addrLen)) { close(_socket); _socket = INVALID_SOCKET; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self]; } if (addr.storage.ss_family == AF_INET) return OF_BSWAP16_IF_LE(addr.in.sin_port); # ifdef AF_INET6 if (addr.storage.ss_family == AF_INET6) return OF_BSWAP16_IF_LE(addr.in6.sin6_port); # endif #endif close(_socket); _socket = INVALID_SOCKET; @throw [OFBindFailedException exceptionWithHost: host port: port socket: self]; } - (size_t)receiveIntoBuffer: (void*)buffer length: (size_t)length sender: (of_udp_socket_address_t*)sender { ssize_t ret; if (_socket == INVALID_SOCKET) @throw [OFNotConnectedException exceptionWithSocket: self]; sender->length = (socklen_t)sizeof(sender->address); #ifndef _WIN32 if ((ret = recvfrom(_socket, buffer, length, 0, (struct sockaddr*)&sender->address, &sender->length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = recvfrom(_socket, buffer, (int)length, 0, (struct sockaddr*)&sender->address, &sender->length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length]; #endif return ret; } - (void)asyncReceiveIntoBuffer: (void*)buffer length: (size_t)length target: (id)target selector: (SEL)selector { [OFRunLoop OF_addAsyncReceiveForUDPSocket: self buffer: buffer length: length target: target selector: selector]; } #ifdef OF_HAVE_BLOCKS - (void)asyncReceiveIntoBuffer: (void*)buffer length: (size_t)length block: (of_udp_socket_async_receive_block_t)block { [OFRunLoop OF_addAsyncReceiveForUDPSocket: self buffer: buffer length: length block: block]; } #endif - (void)sendBuffer: (const void*)buffer length: (size_t)length receiver: (of_udp_socket_address_t*)receiver { if (_socket == INVALID_SOCKET) @throw [OFNotConnectedException exceptionWithSocket: self]; #ifndef _WIN32 if (sendto(_socket, buffer, length, 0, (struct sockaddr*)&receiver->address, receiver->length) < length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if (sendto(_socket, buffer, (int)length, 0, (struct sockaddr*)&receiver->address, receiver->length) < length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length]; #endif } - (void)cancelAsyncRequests { [OFRunLoop OF_cancelAsyncRequestsForObject: self]; } - (int)fileDescriptorForReading { #ifndef _WIN32 return _socket; #else if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; return (int)_socket; #endif } - (int)fileDescriptorForWriting { #ifndef _WIN32 return _socket; #else if (_socket > INT_MAX) @throw [OFOutOfRangeException exception]; return (int)_socket; #endif } - (void)close { if (_socket == INVALID_SOCKET) @throw [OFNotConnectedException exceptionWithSocket: self]; close(_socket); _socket = INVALID_SOCKET; } @end