Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -23,10 +23,11 @@ OFObject.m \ ${OFPLUGIN_M} \ OFSeekableStream.m \ OFSHA1Hash.m \ OFSocket.m \ + OFSocketObserver.m \ OFStream.m \ OFString.m \ OFString+Hashing.m \ OFString+URLEncoding.m \ OFString+XMLEscaping.m \ Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -173,13 +173,13 @@ return [[delegate retain] autorelease]; } - (void)setDelegate: (OFObject *)delegate_ { - id old = delegate; - delegate = [delegate_ retain]; - [old release]; + [delegate_ retain]; + [delegate release]; + delegate = delegate_; } - (void)run { [delegate applicationDidFinishLaunching]; Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -42,11 +42,11 @@ }; /** * \brief Provides a way to store a number in an object. */ -@interface OFNumber: OFObject +@interface OFNumber: OFObject { union { char char_; short short_; int int_; Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1002,6 +1002,11 @@ numberWithDouble: fmod(value.double_, [num doubleValue])]; default: @throw [OFInvalidFormatException newWithClass: isa]; } } + +- copy +{ + return [self retain]; +} @end Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -19,10 +19,11 @@ /** * \brief A class which provides functions to create and use sockets. */ @interface OFSocket: OFStream { +@public #ifndef _WIN32 int sock; #else SOCKET sock; #endif ADDED src/OFSocketObserver.h Index: src/OFSocketObserver.h ================================================================== --- src/OFSocketObserver.h +++ src/OFSocketObserver.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * 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 included in + * the packaging of this file. + */ + +#import "OFObject.h" + +@class OFSocket; +@class OFDataArray; +@class OFMutableDictionary; + +/** + * \brief A protocol that needs to be implemented by delegates for + * OFSocketObserver. + */ +@protocol OFSocketObserverDelegate +/** + * This callback is called when a socket did get ready for reading. + * + * This callback is also called when a listening socket got a new incoming + * connection. + * + * \param sock The socket which did get ready for reading + */ +- (void)socketDidGetReadyForReading: (OFSocket*)sock; + +/** + * This callback is called when a socket did get ready for writing. + * + * \param sock The socket which did get ready for writing + */ +- (void)socketDidGetReadyForWriting: (OFSocket*)sock; +@end + +/** + * \brief A class that can observe multiple sockets at once. + */ +@interface OFSocketObserver: OFObject +{ + OFObject *delegate; + OFDataArray *fds; + OFMutableDictionary *fdToSocket; +} + +#ifdef OF_HAVE_PROPERTIES +@property (retain) OFObject *delegate; +#endif + +/** + * \return A new, autoreleased OFSocketObserver + */ ++ socketObserver; + +/** + * \return The delegate for the OFSocketObserver + */ +- (OFObject *)delegate; + +/** + * Sets the delegate for the OFSocketObserver. + * + * \param delegate The delegate for the OFSocketObserver + */ +- (void)setDelegate: (OFObject *)delegate; + +/** + * Adds a socket to observe for reading. + * + * \param sock The socket to observe for reading + */ +- (void)addSocketToObserveForReading: (OFSocket*)sock; + +/** + * Adds a socket to observe for writing. + * + * \param sock The socket to observe for writing + */ +- (void)addSocketToObserveForWriting: (OFSocket*)sock; + +/** + * Removes a socket to observe for reading. + * + * \param sock The socket to remove from observing for reading + */ +- (void)removeSocketToObserveForReading: (OFSocket*)sock; + +/** + * Removes a socket to observe for writing. + * + * \param sock The socket to remove from observing for writing + */ +- (void)removeSocketToObserveForWriting: (OFSocket*)sock; + +/** + * Observes all sockets and blocks until an event happens on a socket. + * + * \return The number of sockets that have pending events + */ +- (int)observe; + +/** + * Observes all sockets until an event happens on a socket or the timeout is + * reached. + * + * \return The number of sockets that have pending events + */ +- (int)observeWithTimeout: (int)timeout; +@end + +@interface OFObject (OFSocketObserverDelegate) +@end ADDED src/OFSocketObserver.m Index: src/OFSocketObserver.m ================================================================== --- src/OFSocketObserver.m +++ src/OFSocketObserver.m @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * 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 included in + * the packaging of this file. + */ + +#include "config.h" + +#include + +#import "OFSocketObserver.h" +#import "OFDataArray.h" +#import "OFDictionary.h" +#import "OFSocket.h" +#import "OFNumber.h" +#import "OFAutoreleasePool.h" + +@implementation OFSocketObserver ++ socketObserver +{ + return [[[self alloc] init] autorelease]; +} + +- init +{ + self = [super init]; + + fds = [[OFDataArray alloc] initWithItemSize: sizeof(struct pollfd)]; + fdToSocket = [[OFMutableDictionary alloc] init]; + + return self; +} + +- (void)dealloc +{ + [delegate release]; + [fds release]; + [fdToSocket release]; + + [super dealloc]; +} + +- (OFObject *)delegate +{ + return [[delegate retain] autorelease]; +} + +- (void)setDelegate: (OFObject *)delegate_ +{ + [delegate_ retain]; + [delegate release]; + delegate = delegate_; +} + +- (void)addSocketToObserveForReading: (OFSocket*)sock +{ + struct pollfd *fds_c = [fds cArray]; + size_t i, count = [fds count]; + BOOL found = NO; + + for (i = 0; i < count; i++) { + if (fds_c[i].fd == sock->sock) { + fds_c[i].events |= POLLIN; + found = YES; + } + } + + if (!found) { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + struct pollfd p = { sock->sock, POLLIN, 0 }; + [fds addItem: &p]; + [fdToSocket setObject: sock + forKey: [OFNumber numberWithInt: sock->sock]]; + [pool release]; + } +} + +- (void)addSocketToObserveForWriting: (OFSocket*)sock +{ + struct pollfd *fds_c = [fds cArray]; + size_t i, nfds = [fds count]; + BOOL found = NO; + + for (i = 0; i < nfds; i++) { + if (fds_c[i].fd == sock->sock) { + fds_c[i].events |= POLLOUT; + found = YES; + } + } + + if (!found) { + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + struct pollfd p = { sock->sock, POLLOUT, 0 }; + [fds addItem: &p]; + [fdToSocket setObject: sock + forKey: [OFNumber numberWithInt: sock->sock]]; + [pool release]; + } +} + +- (void)removeSocketToObserveForReading: (OFSocket*)sock +{ + struct pollfd *fds_c = [fds cArray]; + size_t i, nfds = [fds count]; + + for (i = 0; i < nfds; i++) { + if (fds_c[i].fd == sock->sock) { + OFAutoreleasePool *pool; + + fds_c[i].events &= ~POLLIN; + + if (fds_c[i].events != 0) + return; + + pool = [[OFAutoreleasePool alloc] init]; + + [fds removeItemAtIndex: i]; + [fdToSocket removeObjectForKey: + [OFNumber numberWithInt: sock->sock]]; + + [pool release]; + } + } +} + +- (void)removeSocketToObserveForWriting: (OFSocket*)sock +{ + struct pollfd *fds_c = [fds cArray]; + size_t i, nfds = [fds count]; + + for (i = 0; i < nfds; i++) { + if (fds_c[i].fd == sock->sock) { + OFAutoreleasePool *pool; + + fds_c[i].events &= ~POLLOUT; + + if (fds_c[i].events != 0) + return; + + pool = [[OFAutoreleasePool alloc] init]; + + [fds removeItemAtIndex: i]; + [fdToSocket removeObjectForKey: + [OFNumber numberWithInt: sock->sock]]; + + [pool release]; + } + } +} + +- (int)observe +{ + return [self observeWithTimeout: -1]; +} + +- (int)observeWithTimeout: (int)timeout +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + struct pollfd *fds_c = [fds cArray]; + size_t i, nfds = [fds count]; + int ret = poll(fds_c, nfds, timeout); + + if (ret <= 0) + return ret; + + for (i = 0; i < nfds; i++) { + OFNumber *num; + OFSocket *sock; + + if (fds_c[i].revents & POLLIN) { + num = [OFNumber numberWithInt: fds_c[i].fd]; + sock = [fdToSocket objectForKey: num]; + [delegate socketDidGetReadyForReading: sock]; + } + + if (fds_c[i].revents & POLLOUT) { + num = [OFNumber numberWithInt: fds_c[i].fd]; + sock = [fdToSocket objectForKey: num]; + [delegate socketDidGetReadyForReading: sock]; + } + + fds_c[i].revents = 0; + } + + [pool release]; + + return ret; +} +@end + +@implementation OFObject (OFSocketObserverDelegate) +- (void)socketDidGetReadyForReading: (OFSocket*)sock +{ +} + +- (void)socketDidGetReadyForWriting: (OFSocket*)sock +{ +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -31,13 +31,19 @@ #import "OFFile.h" #import "OFSocket.h" #import "OFTCPSocket.h" +#import "OFSocketObserver.h" #import "OFHash.h" +#import "OFMD5Hash.h" +#import "OFSHA1Hash.h" + +#import "OFXMLAttribute.h" #import "OFXMLElement.h" +#import "OFXMLParser.h" #import "OFApplication.h" #import "macros.h"