1// 2// Copyright (c) ZeroC, Inc. All rights reserved. 3// 4 5#include "Transceiver.h" 6#include "EndpointI.h" 7 8#include <IceIAP/ConnectionInfo.h> 9 10#include <Ice/LocalException.h> 11#include <Ice/ProtocolInstance.h> 12#include <Ice/Buffer.h> 13 14#import <Foundation/NSRunLoop.h> 15#import <Foundation/NSError.h> 16#import <Foundation/NSString.h> 17 18using namespace std; 19using namespace Ice; 20using namespace IceInternal; 21 22@interface iAPTransceiverCallback : NSObject<NSStreamDelegate> 23{ 24@private 25 26 SelectorReadyCallback* callback; 27} 28-(id) init:(SelectorReadyCallback*)cb; 29@end 30 31@implementation iAPTransceiverCallback 32-(id) init:(SelectorReadyCallback*)cb 33{ 34 if(![super init]) 35 { 36 return nil; 37 } 38 callback = cb; 39 return self; 40} 41 42- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode 43{ 44 switch(eventCode) 45 { 46 case NSStreamEventHasBytesAvailable: 47 callback->readyCallback(SocketOperationRead); 48 break; 49 case NSStreamEventHasSpaceAvailable: 50 callback->readyCallback(SocketOperationWrite); 51 break; 52 case NSStreamEventOpenCompleted: 53 if([[stream class] isSubclassOfClass:[NSInputStream class]]) 54 { 55 callback->readyCallback(static_cast<SocketOperation>(SocketOperationConnect | SocketOperationRead)); 56 } 57 else 58 { 59 callback->readyCallback(static_cast<SocketOperation>(SocketOperationConnect | SocketOperationWrite)); 60 } 61 break; 62 default: 63 if([[stream class] isSubclassOfClass:[NSInputStream class]]) 64 { 65 callback->readyCallback(SocketOperationRead, -1); // Error 66 } 67 else 68 { 69 callback->readyCallback(SocketOperationWrite, -1); // Error 70 } 71 } 72} 73@end 74 75void 76IceObjC::iAPTransceiver::initStreams(SelectorReadyCallback* callback) 77{ 78 _callback = [[iAPTransceiverCallback alloc] init:callback]; 79 [_writeStream setDelegate:_callback]; 80 [_readStream setDelegate:_callback]; 81} 82 83SocketOperation 84IceObjC::iAPTransceiver::registerWithRunLoop(SocketOperation op) 85{ 86 IceUtil::Mutex::Lock sync(_mutex); 87 SocketOperation readyOp = SocketOperationNone; 88 if(op & SocketOperationConnect) 89 { 90 if([_writeStream streamStatus] != NSStreamStatusNotOpen || [_readStream streamStatus] != NSStreamStatusNotOpen) 91 { 92 return SocketOperationConnect; 93 } 94 95 _opening = true; 96 97 [_writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 98 [_readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 99 100 _writeStreamRegistered = true; // Note: this must be set after the schedule call 101 _readStreamRegistered = true; // Note: this must be set after the schedule call 102 103 [_writeStream open]; 104 [_readStream open]; 105 } 106 else 107 { 108 if(op & SocketOperationWrite) 109 { 110 if([_writeStream hasSpaceAvailable]) 111 { 112 readyOp = static_cast<SocketOperation>(readyOp | SocketOperationWrite); 113 } 114 else if(!_writeStreamRegistered) 115 { 116 [_writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 117 _writeStreamRegistered = true; // Note: this must be set after the schedule call 118 if([_writeStream hasSpaceAvailable]) 119 { 120 readyOp = static_cast<SocketOperation>(readyOp | SocketOperationWrite); 121 } 122 } 123 } 124 125 if(op & SocketOperationRead) 126 { 127 if([_readStream hasBytesAvailable]) 128 { 129 readyOp = static_cast<SocketOperation>(readyOp | SocketOperationRead); 130 } 131 else if(!_readStreamRegistered) 132 { 133 [_readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 134 _readStreamRegistered = true; // Note: this must be set after the schedule call 135 if([_readStream hasBytesAvailable]) 136 { 137 readyOp = static_cast<SocketOperation>(readyOp | SocketOperationRead); 138 } 139 } 140 } 141 } 142 return readyOp; 143} 144 145SocketOperation 146IceObjC::iAPTransceiver::unregisterFromRunLoop(SocketOperation op, bool error) 147{ 148 IceUtil::Mutex::Lock sync(_mutex); 149 _error |= error; 150 151 if(_opening) 152 { 153 // Wait for the stream to be ready for write 154 if(op == SocketOperationWrite) 155 { 156 _writeStreamRegistered = false; 157 } 158 159 // 160 // We don't wait for the stream to be ready for read (even if 161 // it's a client connection) because there's no guarantees that 162 // the server might actually send data right away. If we use 163 // the WebSocket transport, the server actually waits for the 164 // client to write the HTTP upgrade request. 165 // 166 //if(op & SocketOperationRead && (_fd != INVALID_SOCKET || !(op & SocketOperationConnect))) 167 if(op == (SocketOperationRead | SocketOperationConnect)) 168 { 169 _readStreamRegistered = false; 170 } 171 172 if(error || (!_readStreamRegistered && !_writeStreamRegistered)) 173 { 174 [_writeStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 175 [_readStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 176 _opening = false; 177 return SocketOperationConnect; 178 } 179 else 180 { 181 return SocketOperationNone; 182 } 183 } 184 else 185 { 186 if(op & SocketOperationWrite && _writeStreamRegistered) 187 { 188 [_writeStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 189 _writeStreamRegistered = false; 190 } 191 192 if(op & SocketOperationRead && _readStreamRegistered) 193 { 194 [_readStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 195 _readStreamRegistered = false; 196 } 197 } 198 return op; 199} 200 201void 202IceObjC::iAPTransceiver::closeStreams() 203{ 204 [_writeStream setDelegate:nil]; 205 [_readStream setDelegate:nil]; 206 207 [_callback release]; 208 _callback = 0; 209 210 [_writeStream close]; 211 [_readStream close]; 212} 213 214IceInternal::NativeInfoPtr 215IceObjC::iAPTransceiver::getNativeInfo() 216{ 217 return this; 218} 219 220SocketOperation 221IceObjC::iAPTransceiver::initialize(Buffer& /*readBuffer*/, Buffer& /*writeBuffer*/) 222{ 223 IceUtil::Mutex::Lock sync(_mutex); 224 if(_state == StateNeedConnect) 225 { 226 _state = StateConnectPending; 227 return SocketOperationConnect; 228 } 229 230 if(_state <= StateConnectPending) 231 { 232 if(_error) 233 { 234 checkErrorStatus(_writeStream, __FILE__, __LINE__); 235 checkErrorStatus(_readStream, __FILE__, __LINE__); 236 } 237 _state = StateConnected; 238 } 239 assert(_state == StateConnected); 240 return SocketOperationNone; 241} 242 243SocketOperation 244IceObjC::iAPTransceiver::closing(bool initiator, const Ice::LocalException&) 245{ 246 // If we are initiating the connection closure, wait for the peer 247 // to close the TCP/IP connection. Otherwise, close immediately. 248 return initiator ? SocketOperationRead : SocketOperationNone; 249} 250 251void 252IceObjC::iAPTransceiver::close() 253{ 254} 255 256SocketOperation 257IceObjC::iAPTransceiver::write(Buffer& buf) 258{ 259 IceUtil::Mutex::Lock sync(_mutex); 260 if(_error) 261 { 262 checkErrorStatus(_writeStream, __FILE__, __LINE__); 263 } 264 265 size_t packetSize = buf.b.end() - buf.i; 266 while(buf.i != buf.b.end()) 267 { 268 if(![_writeStream hasSpaceAvailable]) 269 { 270 return SocketOperationWrite; 271 } 272 assert([_writeStream streamStatus] >= NSStreamStatusOpen); 273 274 NSInteger ret = [_writeStream write:reinterpret_cast<const UInt8*>(&*buf.i) maxLength:packetSize]; 275 if(ret == SOCKET_ERROR) 276 { 277 checkErrorStatus(_writeStream, __FILE__, __LINE__); 278 if(noBuffers() && packetSize > 1024) 279 { 280 packetSize /= 2; 281 } 282 continue; 283 } 284 285 buf.i += ret; 286 287 if(packetSize > static_cast<size_t>(buf.b.end() - buf.i)) 288 { 289 packetSize = buf.b.end() - buf.i; 290 } 291 } 292 293 return SocketOperationNone; 294} 295 296SocketOperation 297IceObjC::iAPTransceiver::read(Buffer& buf) 298{ 299 IceUtil::Mutex::Lock sync(_mutex); 300 if(_error) 301 { 302 checkErrorStatus(_readStream, __FILE__, __LINE__); 303 } 304 305 size_t packetSize = buf.b.end() - buf.i; 306 while(buf.i != buf.b.end()) 307 { 308 if(![_readStream hasBytesAvailable] && [_readStream streamStatus] != NSStreamStatusError) 309 { 310 return SocketOperationRead; 311 } 312 assert([_readStream streamStatus] >= NSStreamStatusOpen); 313 314 NSInteger ret = [_readStream read:reinterpret_cast<UInt8*>(&*buf.i) maxLength:packetSize]; 315 if(ret == 0) 316 { 317 throw ConnectionLostException(__FILE__, __LINE__); 318 } 319 320 if(ret == SOCKET_ERROR) 321 { 322 checkErrorStatus(_readStream, __FILE__, __LINE__); 323 if(noBuffers() && packetSize > 1024) 324 { 325 packetSize /= 2; 326 } 327 continue; 328 } 329 330 buf.i += ret; 331 332 if(packetSize > static_cast<size_t>(buf.b.end() - buf.i)) 333 { 334 packetSize = buf.b.end() - buf.i; 335 } 336 } 337 338 return SocketOperationNone; 339} 340 341string 342IceObjC::iAPTransceiver::protocol() const 343{ 344 return _instance->protocol(); 345} 346 347string 348IceObjC::iAPTransceiver::toString() const 349{ 350 return _desc; 351} 352 353string 354IceObjC::iAPTransceiver::toDetailedString() const 355{ 356 return toString(); 357} 358 359Ice::ConnectionInfoPtr 360IceObjC::iAPTransceiver::getInfo() const 361{ 362 IceIAP::ConnectionInfoPtr info = ICE_MAKE_SHARED(IceIAP::ConnectionInfo); 363 info->manufacturer = [_session.accessory.manufacturer UTF8String]; 364 info->name = [_session.accessory.name UTF8String]; 365 info->modelNumber = [_session.accessory.modelNumber UTF8String]; 366 info->firmwareRevision = [_session.accessory.firmwareRevision UTF8String]; 367 info->hardwareRevision = [_session.accessory.hardwareRevision UTF8String]; 368 info->protocol = [_session.protocolString UTF8String]; 369 return info; 370} 371 372void 373IceObjC::iAPTransceiver::checkSendSize(const Buffer& /*buf*/) 374{ 375} 376 377void 378IceObjC::iAPTransceiver::setBufferSize(int, int) 379{ 380} 381 382IceObjC::iAPTransceiver::iAPTransceiver(const ProtocolInstancePtr& instance, EASession* session) : 383 StreamNativeInfo(INVALID_SOCKET), 384 _instance(instance), 385 _session([session retain]), 386 _readStream([session inputStream]), 387 _writeStream([session outputStream]), 388 _readStreamRegistered(false), 389 _writeStreamRegistered(false), 390 _error(false), 391 _state(StateNeedConnect) 392{ 393 ostringstream os; 394 os << "name = " << [session.accessory.name UTF8String] << "\n"; 395 os << "protocol = " << [session.protocolString UTF8String]; 396 _desc = os.str(); 397} 398 399IceObjC::iAPTransceiver::~iAPTransceiver() 400{ 401 [_session release]; 402} 403 404void 405IceObjC::iAPTransceiver::checkErrorStatus(NSStream* stream, const char* file, int line) 406{ 407 NSStreamStatus status = [stream streamStatus]; 408 if(status == NSStreamStatusAtEnd) 409 { 410 throw ConnectionLostException(file, line); 411 } 412 413 assert(status == NSStreamStatusError); 414 415 NSError* err = [stream streamError]; 416 NSString* domain = [err domain]; 417 if([domain compare:NSPOSIXErrorDomain] == NSOrderedSame) 418 { 419 errno = [err code]; 420 [err release]; 421 if(interrupted() || noBuffers()) 422 { 423 return; 424 } 425 else if(connectionRefused()) 426 { 427 ConnectionRefusedException ex(file, line); 428 ex.error = getSocketErrno(); 429 throw ex; 430 } 431 else if(connectFailed()) 432 { 433 ConnectFailedException ex(file, line); 434 ex.error = getSocketErrno(); 435 throw ex; 436 } 437 else 438 { 439 SocketException ex(file, line); 440 ex.error = getSocketErrno(); 441 throw ex; 442 } 443 } 444 445 // Otherwise throw a generic exception. 446 CFNetworkException ex(file, line); 447 ex.domain = [domain UTF8String]; 448 ex.error = [err code]; 449 [err release]; 450 throw ex; 451} 452