2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #if defined(__APPLE__)
24 # include <sys/types.h>
25 # include <sys/socket.h>
28 #include <NGStreams/NGDescriptorFunctions.h>
29 #include "NGDatagramSocket.h"
30 #include "NGDatagramPacket.h"
31 #include "NGSocketExceptions.h"
32 #include "NGSocket+private.h"
35 #if !defined(POLLRDNORM)
36 # define POLLRDNORM POLLIN
39 NSString *NGSocketTimedOutNotificationName = @"NGSocketTimedOutNotification";
41 @interface NGSocket(privateMethods)
43 - (void)_createSocketInDomain:(int)_domain;
45 - (void)setOption:(int)_option level:(int)_level value:(void *)_value len:(int)_len;
46 - (void)setOption:(int)_option value:(void *)_value len:(int)_len;
47 - (void)getOption:(int)_option level:(int)_level value:(void *)_val len:(int *)_len;
48 - (void)getOption:(int)_option value:(void *)_value len:(int *)_len;
52 //static const int NGMaxTimeout = (int)-1;
53 static const NSTimeInterval NGNoTimeout = 0.0;
55 @implementation NGDatagramSocket
57 #if !defined(WIN32) || defined(__CYGWIN32__)
59 + (BOOL)socketPair:(id<NGSocket>[2])_pair inDomain:(id<NGSocketDomain>)_domain {
65 if (socketpair([_domain socketDomain], SOCK_DGRAM, [_domain protocol],
67 NGDatagramSocket *s1 = nil;
68 NGDatagramSocket *s2 = nil;
70 s1 = [[self alloc] _initWithDomain:_domain descriptor:fds[0]];
71 s2 = [[self alloc] _initWithDomain:_domain descriptor:fds[1]];
75 if ((s1 != nil) && (s2 != nil)) {
86 NSString *reason = nil;
90 reason = @"Not allowed to create socket of this type";
93 reason = @"Could not create socket: Insufficient user memory available";
96 reason = @"The protocol is not supported by the address family or "
100 reason = @"The socket type is not supported by the protocol";
103 reason = @"Could not create socket: descriptor table is full";
106 reason = @"The specified protocol does not permit creation of socket "
111 reason = [NSString stringWithFormat:@"Could not create socketpair: %s",
115 [[[NGCouldNotCreateSocketException alloc]
116 initWithReason:reason domain:_domain] raise];
123 + (id)socketBoundToAddress:(id<NGSocketAddress>)_address {
124 volatile id sock = [[self alloc] initWithDomain:[_address domain]];
127 sock = AUTORELEASE(sock);
128 [sock bindToAddress:_address];
133 - (id)initWithDomain:(id<NGSocketDomain>)_domain { // designated initializer
134 if ((self = [super initWithDomain:_domain])) {
135 [self setMaxPacketSize:2048];
136 [self setPacketFactory:(id)[NGDatagramPacket class]];
137 self->udpFlags.isConnected = NO;
144 - (void)setMaxPacketSize:(int)_maxPacketSize {
145 self->maxPacketSize = _maxPacketSize;
147 - (int)maxPacketSize {
148 return self->maxPacketSize;
151 - (void)setPacketFactory:(id<NGDatagramPacketFactory>)_factory {
152 ASSIGN(self->packetFactory, _factory);
154 - (id<NGDatagramPacketFactory>)packetFactory {
155 return self->packetFactory;
162 - (BOOL)isConnected {
163 return self->udpFlags.isConnected;
168 - (BOOL)wouldBlockInMode:(NGStreamMode)_mode {
171 if (fd == NGInvalidSocketDescriptor)
174 if (NGCanReadInStreamMode(_mode)) events |= POLLRDNORM;
175 if (NGCanWriteInStreamMode(_mode)) events |= POLLWRNORM;
177 // timeout of 0 means return immediatly
178 return (NGPollDescriptor([self fileDescriptor], events, 0) == 1 ? NO : YES);
183 - (void)primarySendPacket:(id<NGDatagramPacket>)_packet {
186 NSAssert([_packet receiver], @"packet has no destination !");
188 bytesWritten = sendto(self->fd, // socket
189 [[_packet data] bytes], [[_packet data] length],
191 [[_packet receiver] internalAddressRepresentation],
192 [[_packet receiver] addressRepresentationSize]);
194 if (!self->flags.isBound) // was not explictly bound, so get local address
195 [self kernelBoundAddress];
197 [_packet setSender:[self localAddress]];
200 - (BOOL)sendPacket:(id<NGDatagramPacket>)_packet timeout:(NSTimeInterval)_to {
201 if (_to > NGNoTimeout) {
202 int result = NGPollDescriptor([self fileDescriptor],
204 (int)(_to * 1000.0));
208 [[NSNotificationCenter defaultCenter]
209 postNotificationName:NGSocketTimedOutNotificationName
213 else if (result < 0) {
214 [[[NGSocketException alloc]
215 initWithReason:@"error during poll on UDP socket"] raise];
219 // else receive packet ..
221 [self primarySendPacket:_packet];
225 - (BOOL)sendPacket:(id<NGDatagramPacket>)_packet {
226 return [self sendPacket:_packet timeout:NGNoTimeout];
231 - (id<NGDatagramPacket>)primaryReceivePacketWithMaxSize:(int)_maxSize {
232 id<NGSocketAddress> remote = nil;
233 id<NGDatagramPacket> packet = nil;
234 char buffer[_maxSize];
236 int len = [[self domain] addressRepresentationSize];
239 size = recvfrom(self->fd, buffer, _maxSize,
242 remote = [[self domain] addressWithRepresentation:(void *)data size:len];
244 if (!self->flags.isBound) // was not explictly bound, so get local address
245 [self kernelBoundAddress];
247 packet = [[self packetFactory] packetWithBytes:buffer size:size];
248 [packet setReceiver:[self localAddress]];
249 [packet setSender:remote];
253 - (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_size
254 timeout:(NSTimeInterval)_to {
256 if (_to > NGNoTimeout) {
257 int result = NGPollDescriptor([self fileDescriptor],
259 (int)(_to * 1000.0));
263 [[NSNotificationCenter defaultCenter]
264 postNotificationName:NGSocketTimedOutNotificationName
268 else if (result < 0) {
269 [[[NGSocketException alloc]
270 initWithReason:@"error during poll on UDP socket"] raise];
273 // else receive packet ..
275 return [self primaryReceivePacketWithMaxSize:_size];
278 - (id<NGDatagramPacket>)receivePacketWithTimeout:(NSTimeInterval)_timeout {
279 return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:_timeout];
282 - (id<NGDatagramPacket>)receivePacketWithMaxSize:(int)_maxPacketSize {
283 return [self receivePacketWithMaxSize:_maxPacketSize timeout:NGNoTimeout];
285 - (id<NGDatagramPacket>)receivePacket {
286 return [self receivePacketWithMaxSize:[self maxPacketSize] timeout:NGNoTimeout];
289 // ************************* options *************************
291 static int i_yes = 1;
294 static inline void setBoolOption(id self, int _option, BOOL _flag) {
295 [self setOption:_option level:SOL_SOCKET
296 value:(_flag ? &i_yes : &i_no) len:4];
298 static inline BOOL getBoolOption(id self, int _option) {
300 [self getOption:_option level:SOL_SOCKET value:&value len:&len];
301 return (value ? YES : NO);
304 - (void)setBroadcast:(BOOL)_flag {
305 setBoolOption(self, SO_BROADCAST, _flag);
307 - (BOOL)doesBroadcast {
308 return getBoolOption(self, SO_BROADCAST);
311 // aborts, only supported for TCP
313 - (void)setDebug:(BOOL)_flag {
314 [self doesNotRecognizeSelector:_cmd];
317 [self doesNotRecognizeSelector:_cmd];