void __CFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void *clientCallBackInfo) { // Extract the context tnet_transport_t *transport = (tnet_transport_t *) clientCallBackInfo; transport_context_t *context = transport->context; /* lock context */ tsk_safeobj_lock(context); // Extract the native socket CFDataRef data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle); CFSocketNativeHandle fd; CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd); CFRelease(data); transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd); switch(eventType) { case kCFStreamEventOpenCompleted: { TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventOpenCompleted"); if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) { #if !TARGET_OS_IPHONE SSLContextRef sslContext = NULL; data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketSSLContext); CFDataGetBytes(data, CFRangeMake(0, sizeof(SSLContextRef)), (UInt8*) &sslContext); CFRelease(data); // TODO: Set the client certificates #endif } break; } case kCFStreamEventEndEncountered: case kCFStreamEventErrorOccurred: { // Get the error code CFErrorRef error = CFWriteStreamCopyError(stream); CFIndex index = CFErrorGetCode(error); CFRelease(error); TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> Error %lu", index); TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, sock->fd); removeSocket(sock, context); break; } default: { // Not Implemented assert(42 == 0); break; } } /* unlock context */ tsk_safeobj_unlock(context); }
int tnet_transport_issecure(const tnet_transport_handle_t *handle) { if (handle) { const tnet_transport_t *transport = handle; if (transport->master) { return TNET_SOCKET_TYPE_IS_SECURE(transport->master->type); } } else { TSK_DEBUG_ERROR("NULL transport object."); } return 0; }
int tnet_transport_wrap(tnet_transport_t *transport, int index) { transport_context_t *context = transport->context; transport_socket_t *sock = context->sockets[index]; // If the socket is already wrapped in a CFSocket then return. if (sock->cf_socket || sock->cf_read_stream) { return 1; } // Put a reference to the transport context const CFSocketContext socket_context = { 0, transport, NULL, NULL, NULL }; if (TNET_SOCKET_TYPE_IS_DGRAM(sock->type)) { // Create a CFSocket from the native socket and register for Read events sock->cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault, sock->fd, kCFSocketReadCallBack, &__CFSocketCallBack, &socket_context); // Don't close the socket if the CFSocket is invalidated CFOptionFlags flags = CFSocketGetSocketFlags(sock->cf_socket); flags = flags & ~kCFSocketCloseOnInvalidate; CFSocketSetSocketFlags(sock->cf_socket, flags); // Create a new RunLoopSource and register it with the main thread RunLoop sock->cf_run_loop_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock->cf_socket, 0); CFRunLoopAddSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopDefaultMode); CFRelease(sock->cf_run_loop_source); } else if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) { // Create a pair of streams (read/write) from the socket CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock->fd, &sock->cf_read_stream, &sock->cf_write_stream); // Don't close underlying socket CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse); if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) { CFMutableDictionaryRef settings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue); CFDictionaryAddValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue); CFDictionaryAddValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse); CFDictionaryAddValue(settings, kCFStreamSSLPeerName, kCFNull); // Set the SSL settings CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL); CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertySSLSettings, settings); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySSLSettings, settings); CFRelease(settings); } #if __IPHONE_4_0 // Mark the stream for VoIP usage CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); #endif // Setup a context for the streams CFStreamClientContext streamContext = { 0, transport, NULL, NULL, NULL }; // Set the client callback for the stream CFReadStreamSetClient(sock->cf_read_stream, kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, &__CFReadStreamClientCallBack, &streamContext); CFWriteStreamSetClient(sock->cf_write_stream, kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, &__CFWriteStreamClientCallBack, &streamContext); // Enroll streams in the run-loop CFReadStreamScheduleWithRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopDefaultMode); CFWriteStreamScheduleWithRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode); // Release references CFRelease(sock->cf_read_stream); CFRelease(sock->cf_write_stream); CFReadStreamOpen(sock->cf_read_stream); CFWriteStreamOpen(sock->cf_write_stream); } return 0; }