Wired Networking  2.0
Objective-C implementation of the Wired 2.0 protocol
WISocket.m
00001 /* $Id$ */
00002 
00003 /*
00004  *  Copyright (c) 2006-2009 Axel Andersson
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *  1. Redistributions of source code must retain the above copyright
00011  *     notice, this list of conditions and the following disclaimer.
00012  *  2. Redistributions in binary form must reproduce the above copyright
00013  *     notice, this list of conditions and the following disclaimer in the
00014  *     documentation and/or other materials provided with the distribution.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00017  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
00020  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00022  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00023  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00024  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00025  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026  * POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00029 #import <WiredNetworking/NSString-WINetworking.h>
00030 #import <WiredNetworking/WIAddress.h>
00031 #import <WiredNetworking/WIError.h>
00032 #import <WiredNetworking/WISocket.h>
00033 
00034 #define _WISocketBufferMaxSize                                                  131072
00035 
00036 
00037 static void _WISocketCallback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
00038 
00039 static void _WISocketCallback(CFSocketRef socketRef, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) {
00040                 WISocket                        *socket = info;
00041                 
00042                 [[socket delegate] socket:socket handleEvent:callbackType];
00043 }
00044 
00045 
00046 
00047 @interface WISocketTLS(Private)
00048 
00049 - (id)_initForClient;
00050 
00051 @end
00052 
00053 
00054 @implementation WISocketTLS(Private)
00055 
00056 - (id)_initForClient {
00057 #ifdef WI_SSL
00058                 wi_pool_t       *pool;
00059                 
00060                 self = [super init];
00061                 
00062                 pool = wi_pool_init(wi_pool_alloc());
00063                 _tls = wi_socket_tls_init_with_type(wi_socket_tls_alloc(), WI_SOCKET_TLS_CLIENT);
00064                 wi_release(pool);
00065 
00066                 return self;
00067 #else
00068                 [self release];
00069                 
00070                 return NULL;
00071 #endif
00072 }
00073 
00074 @end
00075 
00076 
00077 
00078 @implementation WISocketTLS
00079 
00080 + (WISocketTLS *)socketTLSForClient {
00081                 return [[[self alloc] _initForClient] autorelease];
00082 }
00083 
00084 
00085 
00086 - (void)dealloc {
00087                 wi_release(_tls);
00088                 
00089                 [super dealloc];
00090 }
00091 
00092 
00093 
00094 #pragma mark -
00095 
00096 - (wi_socket_tls_t *)TLS {
00097                 return _tls;
00098 }
00099 
00100 
00101 
00102 #pragma mark -
00103 
00104 - (void)setSSLCiphers:(NSString *)ciphers {
00105 #ifdef WI_SSL
00106                 wi_pool_t       *pool;
00107                 
00108                 pool = wi_pool_init(wi_pool_alloc());
00109                 wi_socket_tls_set_ciphers(_tls, [ciphers wiredString]);
00110                 wi_release(pool);
00111 #endif
00112 }
00113 
00114 @end
00115 
00116 
00117 
00118 @interface WISocket(Private)
00119 
00120 - (id)_initWithSocket:(wi_socket_t *)socket address:(WIAddress *)address;
00121 
00122 - (WIError *)_errorWithCode:(NSInteger)code;
00123 
00124 @end
00125 
00126 
00127 @implementation WISocket(Private)
00128 
00129 - (id)_initWithSocket:(wi_socket_t *)socket address:(WIAddress *)address {
00130                 self = [self init];
00131                 
00132                 _socket                         = wi_retain(socket);
00133                 _address        = [address retain];
00134                 
00135                 return self;
00136 }
00137 
00138 
00139 
00140 #pragma mark -
00141 
00142 - (WIError *)_errorWithCode:(NSInteger)code {
00143                 return [WIError errorWithDomain:WIWiredNetworkingErrorDomain
00144                                                                                                                    code:code
00145                                                                                                    userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
00146                                                                                                                                                  [WIError errorWithDomain:WILibWiredErrorDomain],
00147                                                                                                                                                                  WILibWiredErrorKey,
00148                                                                                                                                                  [_address string],
00149                                                                                                                                                                  WIArgumentErrorKey,
00150                                                                                                                                                  NULL]];
00151 }
00152 
00153 @end
00154 
00155 
00156 
00157 @implementation WISocket
00158 
00159 + (WISocket *)socketWithAddress:(WIAddress *)address type:(WISocketType)type {
00160                 return [[[self alloc] initWithAddress:address type:type] autorelease];
00161 }
00162 
00163 
00164 
00165 + (WISocket *)socketWithFileDescriptor:(int)sd {
00166                 return [[[self alloc] initWithFileDescriptor:sd] autorelease];
00167 }
00168 
00169 
00170 
00171 - (id)initWithAddress:(WIAddress *)address type:(WISocketType)type {
00172                 wi_pool_t                       *pool;
00173                 wi_socket_t                     *socket;
00174                 
00175                 pool = wi_pool_init(wi_pool_alloc());
00176                 socket = wi_socket_init_with_address(wi_socket_alloc(), [address address], type);
00177 
00178                 self = [self _initWithSocket:socket address:address];
00179                 
00180                 wi_release(socket);
00181                 wi_release(pool);
00182                 
00183                 return self;
00184 }
00185 
00186 
00187 
00188 - (id)initWithFileDescriptor:(int)sd {
00189                 WIAddress                       *address;
00190                 wi_pool_t                       *pool;
00191                 wi_socket_t                     *socket;
00192                 
00193                 pool = wi_pool_init(wi_pool_alloc());
00194                 socket = wi_socket_init_with_descriptor(wi_socket_alloc(), sd);
00195                 address = [[WIAddress alloc] initWithAddress:wi_socket_address(socket)];
00196 
00197                 self = [self _initWithSocket:socket address:address];
00198                 
00199                 [address release];
00200                 wi_release(socket);
00201                 wi_release(pool);
00202                 
00203                 return self;
00204 }
00205 
00206 
00207 
00208 - (id)init {
00209                 self = [super init];
00210                 
00211                 _buffer = [[NSMutableString alloc] initWithCapacity:WISocketBufferSize];
00212                 
00213                 return self;
00214 }
00215 
00216 
00217 
00218 - (void)dealloc {
00219                 wi_pool_t       *pool;
00220                 
00221                 pool = wi_pool_init(wi_pool_alloc());
00222                 wi_release(_socket);
00223                 wi_release(pool);
00224                 
00225                 [_address release];
00226                 [_buffer release];
00227 
00228                 [super dealloc];
00229 }
00230 
00231 
00232 
00233 #pragma mark -
00234 
00235 - (WIAddress *)address {
00236                 return _address;
00237 }
00238 
00239 
00240 
00241 - (int)fileDescriptor {
00242                 return wi_socket_descriptor(_socket);
00243 }
00244 
00245 
00246 
00247 - (void *)SSL {
00248                 return wi_socket_ssl(_socket);
00249 }
00250 
00251 
00252 
00253 - (wi_socket_t *)socket {
00254                 return _socket;
00255 }
00256 
00257 
00258 
00259 - (NSString *)cipherVersion {
00260                 NSString                        *string;
00261                 wi_pool_t                       *pool;
00262                 
00263                 pool = wi_pool_init(wi_pool_alloc());
00264                 string = [NSString stringWithWiredString:wi_socket_cipher_version(_socket)];
00265                 wi_release(pool);
00266                 
00267                 return string;
00268 }
00269 
00270 
00271 
00272 - (NSString *)cipherName {
00273                 NSString                        *string;
00274                 wi_pool_t                       *pool;
00275                 
00276                 pool = wi_pool_init(wi_pool_alloc());
00277                 string = [NSString stringWithWiredString:wi_socket_cipher_name(_socket)];
00278                 wi_release(pool);
00279                 
00280                 return string;
00281 }
00282 
00283 
00284 
00285 - (NSUInteger)cipherBits {
00286                 return wi_socket_cipher_bits(_socket);
00287 }
00288 
00289 
00290 
00291 - (NSString *)certificateName {
00292                 NSString                        *string = NULL;
00293                 wi_pool_t                       *pool;
00294                 wi_string_t                     *wstring;
00295                 
00296                 pool = wi_pool_init(wi_pool_alloc());
00297                 wstring = wi_socket_certificate_name(_socket);
00298                 
00299                 if(wstring)
00300                                 string = [NSString stringWithWiredString:wstring];
00301                 
00302                 wi_release(pool);
00303                 
00304                 return string;
00305 }
00306 
00307 
00308 
00309 - (NSUInteger)certificateBits {
00310                 return wi_socket_certificate_bits(_socket);
00311 }
00312 
00313 
00314 
00315 - (NSString *)certificateHostname {
00316                 NSString                        *string = NULL;
00317                 wi_pool_t                       *pool;
00318                 wi_string_t                     *wstring;
00319                 
00320                 pool = wi_pool_init(wi_pool_alloc());
00321                 wstring = wi_socket_certificate_hostname(_socket);
00322                 
00323                 if(wstring)
00324                                 string = [NSString stringWithWiredString:wstring];
00325                 
00326                 wi_release(pool);
00327                 
00328                 return string;
00329 }
00330 
00331 
00332 
00333 #pragma mark -
00334 
00335 - (void)setDelegate:(id <WISocketDelegate>)newDelegate {
00336                 delegate = newDelegate;
00337 }
00338 
00339 
00340 
00341 - (id <WISocketDelegate>)delegate {
00342                 return delegate;
00343 }
00344 
00345 
00346 
00347 - (void)setPort:(NSUInteger)port {
00348                 wi_socket_set_port(_socket, port);
00349                 
00350                 [_address setPort:port];
00351 }
00352 
00353 
00354 
00355 - (NSUInteger)port {
00356                 return wi_socket_port(_socket);
00357 }
00358 
00359 
00360 
00361 - (void)setDirection:(WISocketDirection)direction {
00362                 wi_socket_set_direction(_socket, (wi_socket_direction_t) direction);
00363 }
00364 
00365 
00366 
00367 - (WISocketDirection)direction {
00368                 return (WISocketDirection) wi_socket_direction(_socket);
00369 }
00370 
00371 
00372 
00373 - (void)setBlocking:(BOOL)blocking {
00374                 wi_socket_set_blocking(_socket, blocking);
00375 }
00376 
00377 
00378 
00379 - (BOOL)blocking {
00380                 return wi_socket_blocking(_socket);
00381 }
00382 
00383 
00384 
00385 - (void)setInteractive:(BOOL)interactive {
00386                 wi_socket_set_interactive(_socket, interactive);
00387 }
00388 
00389 
00390 
00391 - (BOOL)interactive {
00392                 return wi_socket_interactive(_socket);
00393 }
00394 
00395 
00396 
00397 #pragma mark -
00398 
00399 - (BOOL)waitWithTimeout:(NSTimeInterval)timeout {
00400                 wi_pool_t                                       *pool;
00401                 wi_socket_state_t               state;
00402                 
00403                 pool = wi_pool_init(wi_pool_alloc());
00404                 state = wi_socket_wait(_socket, timeout);
00405                 wi_release(pool);
00406                 
00407                 return (state == WI_SOCKET_READY);
00408 }
00409 
00410 
00411 
00412 #pragma mark -
00413 
00414 - (BOOL)connectWithTimeout:(NSTimeInterval)timeout error:(WIError **)error {
00415                 wi_pool_t                       *pool;
00416                 BOOL                                            result = YES;
00417                 
00418                 pool = wi_pool_init(wi_pool_alloc());
00419                 
00420                 if(!wi_socket_connect(_socket, timeout)) {
00421                                 if(error)
00422                                                 *error = [self _errorWithCode:WISocketConnectFailed];
00423                                 
00424                                 result = NO;
00425                 }
00426                 
00427                 wi_release(pool);
00428                 
00429                 return result;
00430 }
00431 
00432 
00433 
00434 - (BOOL)connectWithTLS:(WISocketTLS *)tls timeout:(NSTimeInterval)timeout error:(WIError **)error {
00435 #ifdef WI_SSL
00436                 wi_pool_t                       *pool;
00437                 BOOL                                            result = YES;
00438                 
00439                 pool = wi_pool_init(wi_pool_alloc());
00440                 
00441                 if(!wi_socket_connect_tls(_socket, [tls TLS], timeout)) {
00442                                 if(error)
00443                                                 *error = [self _errorWithCode:WISocketConnectFailed];
00444                                 
00445                                 result = NO;
00446                 }
00447                 
00448                 wi_release(pool);
00449                 
00450                 return result;
00451 #else
00452                 return NO;
00453 #endif
00454 }
00455 
00456 
00457 
00458 - (BOOL)listenWithError:(WIError **)error {
00459                 wi_pool_t                       *pool;
00460                 BOOL                                            result = YES;
00461                 
00462                 pool = wi_pool_init(wi_pool_alloc());
00463                 
00464                 if(!wi_socket_listen(_socket)) {
00465                                 if(error)
00466                                                 *error = [self _errorWithCode:WISocketListenFailed];
00467                                 
00468                                 result = NO;
00469                 }
00470                 
00471                 if([_address port] == 0)
00472                                 [_address setPort:wi_socket_port(_socket)];
00473                 
00474                 wi_release(pool);
00475                 
00476                 return result;
00477 }
00478 
00479 
00480 
00481 - (WISocket *)acceptWithTimeout:(NSTimeInterval)timeout error:(WIError **)error {
00482                 WISocket                        *remoteSocket = NULL;
00483                 wi_pool_t                       *pool;
00484                 wi_socket_t                     *socket;
00485                 wi_address_t    *address;
00486                 
00487                 pool = wi_pool_init(wi_pool_alloc());
00488 
00489                 socket = wi_socket_accept(_socket, timeout, &address);
00490                 
00491                 if(socket)
00492                                 remoteSocket = [[[WISocket alloc] _initWithSocket:socket address:[[[WIAddress alloc] initWithAddress:address] autorelease]] autorelease];
00493                 else if(error)
00494                                 *error = [self _errorWithCode:WISocketListenFailed];
00495                 
00496                 wi_release(pool);
00497                 
00498                 return remoteSocket;
00499 }
00500 
00501 
00502 
00503 - (void)close {
00504                 wi_pool_t                       *pool;
00505 
00506                 pool = wi_pool_init(wi_pool_alloc());
00507                 wi_socket_close(_socket);
00508                 wi_release(pool);
00509 }
00510 
00511 
00512 
00513 #pragma mark -
00514 
00515 - (BOOL)writeString:(NSString *)string encoding:(NSStringEncoding)encoding timeout:(NSTimeInterval)timeout error:(WIError **)error {
00516                 NSData                                          *data;
00517                 wi_pool_t                       *pool;
00518                 BOOL                                            result = NO;
00519                 
00520                 pool = wi_pool_init(wi_pool_alloc());
00521                 data = [string dataUsingEncoding:encoding];
00522                 
00523                 if(wi_socket_write_buffer(_socket, timeout, [data bytes], [data length]) < 0) {
00524                                 if(error)
00525                                                 *error = [self _errorWithCode:WISocketWriteFailed];
00526                                 
00527                                 result = NO;
00528                 }
00529                 
00530                 wi_release(pool);
00531                 
00532                 return result;
00533 }
00534 
00535 
00536 
00537 #pragma mark -
00538 
00539 - (NSString *)readStringOfLength:(NSUInteger)length encoding:(NSStringEncoding)encoding timeout:(NSTimeInterval)timeout error:(WIError **)error {
00540                 NSMutableString                 *string, *substring;
00541                 wi_pool_t                                       *pool;
00542                 char                                                            buffer[WISocketBufferSize];
00543                 wi_integer_t                    bytes = -1;
00544                 
00545                 pool = wi_pool_init(wi_pool_alloc());
00546                 string = [[NSMutableString alloc] initWithCapacity:length];
00547                 
00548                 while(length > sizeof(buffer)) {
00549                                 bytes = wi_socket_read_buffer(_socket, timeout, buffer, sizeof(buffer));
00550                                 
00551                                 if(bytes <= 0)
00552                                                 goto end;
00553                                 
00554                                 substring = [[NSString alloc] initWithBytes:buffer length:bytes encoding:encoding];
00555                                 
00556                                 if(substring) {
00557                                                 [string appendString:substring];
00558                                                 [substring release];
00559                                                 
00560                                                 length -= bytes;
00561                                 }
00562                 }
00563                 
00564                 if(length > 0) {
00565                                 do {
00566                                                 bytes = wi_socket_read_buffer(_socket, timeout, buffer, length);
00567                                                 
00568                                                 if(bytes <= 0)
00569                                                                 goto end;
00570                                                 
00571                                                 substring = [[NSString alloc] initWithBytes:buffer length:bytes encoding:encoding];
00572                                                 
00573                                                 if(substring) {
00574                                                                 [string appendString:substring];
00575                                                                 [substring release];
00576                                                 }
00577                                 } while(!substring);
00578                 }
00579 
00580 end:
00581                 if([string length] == 0) {
00582                                 if(bytes < 0) {
00583                                                 if(error) {
00584                                                                 if(wi_error_domain() == WI_ERROR_DOMAIN_ERRNO && wi_error_code() == ETIMEDOUT) {
00585                                                                                 if(!_readTimeoutError)
00586                                                                                                 _readTimeoutError = [[self _errorWithCode:WISocketReadFailed] retain];
00587                                                                                 
00588                                                                                 *error = _readTimeoutError;
00589                                                                 } else {
00590                                                                                 *error = [self _errorWithCode:WISocketReadFailed];
00591                                                                 }
00592                                                 }
00593                                                 
00594                                                 [string release];
00595                                                 
00596                                                 string = NULL;
00597                                 }
00598                 }
00599                 
00600                 wi_release(pool);
00601                 
00602                 return [string autorelease];
00603 }
00604 
00605 
00606 
00607 - (NSString *)readStringUpToString:(NSString *)separator encoding:(NSStringEncoding)encoding timeout:(NSTimeInterval)timeout error:(WIError **)error {
00608                 NSString                        *string, *substring;
00609                 NSUInteger                      index;
00610                 
00611                 index = [_buffer rangeOfString:separator].location;
00612                 
00613                 if(index != NSNotFound) {
00614                                 substring = [_buffer substringToIndex:index + [separator length]];
00615                                 
00616                                 [_buffer deleteCharactersInRange:NSMakeRange(0, [substring length])];
00617                                 
00618                                 return substring;
00619                 }
00620                 
00621                 while((string = [self readStringOfLength:WISocketBufferSize encoding:encoding timeout:timeout error:error])) {
00622                                 if([string length] == 0)
00623                                                 return string;
00624                                 
00625                                 [_buffer appendString:string];
00626                                 
00627                                 index = [_buffer rangeOfString:separator].location;
00628                                 
00629                                 if(index == NSNotFound) {
00630                                                 if([_buffer length] > _WISocketBufferMaxSize) {
00631                                                                 substring = [_buffer substringToIndex:_WISocketBufferMaxSize];
00632                                                                 
00633                                                                 [_buffer deleteCharactersInRange:NSMakeRange(0, [substring length])];
00634                                                                 
00635                                                                 return substring;
00636                                                 }
00637                                 } else {
00638                                                 substring = [_buffer substringToIndex:index + [separator length]];
00639                                                 
00640                                                 [_buffer deleteCharactersInRange:NSMakeRange(0, [substring length])];
00641                                                 
00642                                                 return substring;
00643                                 }
00644                 }
00645                 
00646                 return NULL;
00647 }
00648 
00649 
00650 
00651 - (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode {
00652                 CFSocketContext                                 context;
00653                 CFSocketCallBackType            type;
00654                 
00655                 if(!_sourceRef) {
00656                                 context.version                                                 = 0;
00657                                 context.info                                                    = self;
00658                                 context.retain                                                  = NULL;
00659                                 context.release                                                 = NULL;
00660                                 context.copyDescription                         = NULL;
00661                                 
00662                                 type = kCFSocketNoCallBack;
00663                                 
00664                                 if([self direction] & WISocketRead)
00665                                                 type |= kCFSocketReadCallBack;
00666 
00667                                 if([self direction] & WISocketWrite)
00668                                                 type |= kCFSocketWriteCallBack;
00669                                 
00670                                 _socketRef = CFSocketCreateWithNative(NULL,
00671                                                                                                                                                                                   wi_socket_descriptor(_socket),
00672                                                                                                                                                                                   type,
00673                                                                                                                                                                                   _WISocketCallback,
00674                                                                                                                                                                                   &context);
00675                                 
00676                                 _sourceRef = CFSocketCreateRunLoopSource(NULL, _socketRef, 0);
00677                 }
00678 
00679                 CFRunLoopAddSource([runLoop getCFRunLoop], _sourceRef, (CFStringRef) mode);
00680 }
00681 
00682 
00683 
00684 - (void)removeFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode {
00685                 if(_sourceRef) {
00686                                 CFRunLoopRemoveSource([runLoop getCFRunLoop], _sourceRef, (CFStringRef) mode);
00687                                 
00688                                 if(_sourceRef) {
00689                                                 CFRelease(_sourceRef);
00690                                                 _sourceRef = NULL;
00691                                 }
00692                                 
00693                                 if(_socketRef) {
00694                                                 CFSocketInvalidate(_socketRef);
00695                                                 CFRelease(_socketRef);
00696                                                 _socketRef = NULL;
00697                                 }
00698                 }
00699 }
00700 
00701 @end
 All Classes