2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #if defined(__APPLE__)
23 # include <sys/types.h>
24 # include <sys/socket.h>
27 #include <NGStreams/NGDescriptorFunctions.h>
28 #include "NGDatagramSocket.h"
29 #include "NGDatagramPacket.h"
30 #include "NGSocketExceptions.h"
31 #include "NGSocket+private.h"
34 #if !defined(POLLRDNORM)
35 # define POLLRDNORM POLLIN
38 NSString *NGSocketTimedOutNotificationName = @"NGSocketTimedOutNotification";
40 @interface NGSocket(privateMethods)
42 - (void)_createSocketInDomain:(int)_domain;
44 - (void)setOption:(int)_option level:(int)_level value:(void *)_value len:(int)_len;
45 - (void)setOption:(int)_option value:(void *)_value len:(int)_len;
46 - (void)getOption:(int)_option level:(int)_level value:(void *)_val len:(int *)_len;
47 - (void)getOption:(int)_option value:(void *)_value len:(int *)_len;
51 //static const int NGMaxTimeout = (int)-1;
52 static const NSTimeInterval NGNoTimeout = 0.0;
54 @implementation NGDatagramSocket
56 #if !defined(WIN32) || defined(__CYGWIN32__)
58 + (BOOL)socketPair:(id<NGSocket>[2])_pair inDomain:(id<NGSocketDomain>)_domain {
64 if (socketpair([_domain socketDomain], SOCK_DGRAM, [_domain protocol],
66 NGDatagramSocket *s1 = nil;
67 NGDatagramSocket *s2 = nil;
69 s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]];
70 s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]];
74 if ((s1 != nil) && (s2 != nil)) {
85 NSString *reason = nil;
89 reason = @"Not allowed to create socket of this type";
92 reason = @"Could not create socket: Insufficient user memory available";
95 reason = @"The protocol is not supported by the address family or "
99 reason = @"The socket type is not supported by the protocol";
102 reason = @"Could not create socket: descriptor table is full";
105 reason = @"The specified protocol does not permit creation of socket "
110 reason = [NSString stringWithFormat:@"Could not create socketpair: %s",
114 [[[NGCouldNotCreateSocketException alloc]
115 initWithReason:reason domain:_domain] raise];
122 + (id)socketBoundToAddress:(id<NGSocketAddress>)_address {
123 volatile id sock = [[self alloc] initWithDomain:[_address domain]];
126 sock = AUTORELEASE(sock);
127 [sock bindToAddress:_address];
132 - (id)initWithDomain:(id<NGSocketDomain>)_domain { // designated initializer
133 if ((self = [super initWithDomain:_domain])) {
134 [self setMaxPacketSize:2048];
135 [self setPacketFactory:(id)[NGDatagramPacket class]];
136 self->udpFlags.isConnected = NO;
143 - (void)setMaxPacketSize:(int)_maxPacketSize {
144 self->maxPacketSize = _maxPacketSize;
146 - (int)maxPacketSize {
147 return self->maxPacketSize;
150 - (void)setPacketFactory:(id<NGDatagramPacketFactory>)_factory {
151 ASSIGN(self->packetFactory, _factory);
153 - (id<NGDatagramPacketFactory>)packetFactory {
154 return self->packetFactory;
161 - (BOOL)isConnected {
162 return self->udpFlags.isConnected;
167 - (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
170 if (fd == NGInvalidSocketDescriptor)
173 if (NGCanReadInStreamMode(_mode)) events |= POLLRDNORM;
174 if (NGCanWriteInStreamMode(_mode)) events |= POLLWRNORM;
176 // timeout of 0 means return immediatly
177 return (NGPollDescriptor([self fileDescriptor], events, 0) == 1 ? NO : YES);
182 - (void)primarySendPacket:(id<NGDatagramPacket>)_packet {
185 NSAssert([_packet receiver], @"packet has no destination !");
187 bytesWritten = sendto(self->fd, // socket
188 [[_packet data] bytes], [[_packet data] length],
190 [[_packet receiver] internalAddressRepresentation],
191 [[_packet receiver] addressRepresentationSize]);
193 if (!self->flags.isBound) // was not explictly bound, so get local address
194 [self kernelBoundAddress];
196 [_packet setSender:[self localAddress]];
199 - (BOOL)sendPacket:(id<NGDatagramPacket>)_packet timeout:(NSTimeInterval)_to {
200 if (_to > NGNoTimeout) {
201 int result = NGPollDescriptor([self fileDescriptor],
203 (int)(_to * 1000.0));
207 [[NSNotificationCenter defaultCenter]
208 postNotificationName:NGSocketTimedOutNotificationName
212 else if (result < 0) {
213 [[[NGSocketException alloc]
214 initWithReason:@"error during poll on UDP socket"] raise];
218 // else receive packet ..
220 [self primarySendPacket:_packet];
224 - (BOOL)sendPacket:(id<NGDatagramPacket>)_packet {
225 return [self sendPacket:_packet timeout:NGNoTimeout];
230 - (id<NGDatagramPacket>)primaryReceivePacketWithMaxSize:(int)_maxSize {
231 id<NGSocketAddress> remote = nil;
232 id<NGDatagramPacket> packet = nil;
233 char buffer[_maxSize];
235 unsigned int len = [[self domain] addressRepresentationSize];
238 size = recvfrom(self->fd, buffer, _maxSize,
241 remote = [[self domain] addressWithRepresentation:(void *)data size:len];
243 if (!self->flags.isBound) // was not explictly bound, so get local address
244 [self kernelBoundAddress];
246 packet = [[self packetFactory] packetWithBytes:buffer size:size];
247 [packet setReceiver:[self localAddress]];
248 [packet setSender:remote];
252 - (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_size
253 timeout:(NSTimeInterval)_to {
255 if (_to > NGNoTimeout) {
256 int result = NGPollDescriptor([self fileDescriptor],
258 (int)(_to * 1000.0));
262 [[NSNotificationCenter defaultCenter]
263 postNotificationName:NGSocketTimedOutNotificationName
267 else if (result < 0) {
268 [[[NGSocketException alloc]
269 initWithReason:@"error during poll on UDP socket"] raise];
272 // else receive packet ..
274 return [self primaryReceivePacketWithMaxSize:_size];
277 - (id<NGDatagramPacket>)receivePacketWithTimeout:(NSTimeInterval)_timeout {
278 return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:_timeout];
281 - (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_maxPacketSize {
282 return [self receivePacketWithMaxSize:_maxPacketSize timeout:NGNoTimeout];
284 - (id<NGDatagramPacket>)receivePacket {
285 return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:NGNoTimeout];
288 // ************************* options *************************
290 static int i_yes = 1;
293 static inline void setBoolOption(id self, int _option, BOOL _flag) {
294 [self setOption:_option level:SOL_SOCKET
295 value:(_flag ? &i_yes : &i_no) len:4];
297 static inline BOOL getBoolOption(id self, int _option) {
299 [self getOption:_option level:SOL_SOCKET value:&value len:&len];
300 return (value ? YES : NO);
303 - (void)setBroadcast:(BOOL)_flag {
304 setBoolOption(self, SO_BROADCAST, _flag);
306 - (BOOL)doesBroadcast {
307 return getBoolOption(self, SO_BROADCAST);
310 // aborts, only supported for TCP
312 - (void)setDebug:(BOOL)_flag {
313 [self doesNotRecognizeSelector:_cmd];
316 [self doesNotRecognizeSelector:_cmd];