Use CFSocket on iOS to allow TCP multitasking

This commit is contained in:
bossiel 2012-04-24 10:37:56 +00:00
parent f6367d3290
commit 4d20b1679e
3 changed files with 214 additions and 201 deletions

View File

@ -36,7 +36,7 @@
#include "tsk_buffer.h"
#include "tsk_safeobj.h"
#if TNET_USE_POLL && (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000) && 0
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
#import <CoreFoundation/CoreFoundation.h>
#import <Security/Security.h>
@ -48,7 +48,7 @@
#endif
#define TNET_MAX_FDS 64
#define TNET_BUFFER_SIZE 1024
#define TNET_BUFFER_MAX_SIZE 0x1964
const extern CFStringRef kCFStreamPropertySocketSSLContext;
@ -58,9 +58,9 @@ typedef struct transport_socket_s
tnet_fd_t fd;
tsk_bool_t owner;
tsk_bool_t connected;
tsk_bool_t paused;
tnet_socket_type_t type;
//tnet_tls_socket_handle_t* tlshandle;
CFSocketRef cf_socket;
CFReadStreamRef cf_read_stream;
@ -83,9 +83,95 @@ typedef struct transport_context_s
}
transport_context_t;
static int recvData(tnet_transport_t *transport, transport_socket_t* active_socket);
static const transport_socket_t* getSocket(transport_context_t *context, tnet_fd_t fd);
int removeSocket(transport_socket_t *value, transport_context_t *context);
static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client);
static int removeSocketAtIndex(int index, transport_context_t *context);
static int wrapSocket(tnet_transport_t *transport, transport_socket_t *sock);
int recvData(tnet_transport_t *transport, transport_socket_t* active_socket)
{
transport_context_t *context;
int ret;
if(!transport || !transport->context || !active_socket){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
/* check whether the socket is paused or not */
if(active_socket->paused){
TSK_DEBUG_INFO("Socket is paused");
goto bail;
}
tsk_size_t len = 0;
tsk_bool_t is_stream = TNET_SOCKET_TYPE_IS_STREAM(active_socket->type);
if(tnet_ioctlt(active_socket->fd, FIONREAD, &len) < 0){
TNET_PRINT_LAST_ERROR("IOCTLT failed");
goto bail;
}
if(!len){
// probably incoming connection
if(is_stream){
tnet_fd_t fd;
if((fd = accept(active_socket->fd, tsk_null, tsk_null)) > 0){
if(addSocket(fd, active_socket->type, transport, tsk_true, tsk_false) == 0){
goto bail; // read() data next time
}
}
}
TSK_DEBUG_WARN("IOCTLT returned zero for fd=%d", active_socket->fd);
recv(active_socket->fd, 0, 0, 0);
goto bail;
}
void* buffer = tsk_null;
if(!(buffer = tsk_calloc(len, sizeof(uint8_t)))){
TSK_DEBUG_ERROR("TSK_CALLOC FAILED.");
goto bail;
}
struct sockaddr_storage remote_addr = {0};
if(is_stream){
if(active_socket->cf_read_stream){
ret = CFReadStreamRead(active_socket->cf_read_stream, buffer, (CFIndex)len);
}
else {
ret = tnet_sockfd_recv(active_socket->fd, buffer, len, 0);
}
}
else {
ret = tnet_sockfd_recvfrom(active_socket->fd, buffer, len, 0, (struct sockaddr*)&remote_addr);
}
if(ret < 0){
TSK_FREE(buffer);
removeSocket(active_socket, transport->context);
TNET_PRINT_LAST_ERROR("recv/recvfrom have failed.");
goto bail;
}
if((len != (tsk_size_t)ret) && len){
len = (tsk_size_t)ret;
}
tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
e->data = buffer;
e->size = len;
e->remote_addr = remote_addr;
TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
bail:
return 0;
}
int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient)
{
@ -104,7 +190,7 @@ int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t f
}
if (TNET_SOCKET_TYPE_IS_TLS(type)) {
transport->tls.have_tls = 1;
transport->tls.have_tls = tsk_true;
}
if ((ret = addSocket(fd, type, transport, take_ownership, isClient))) {
@ -118,12 +204,31 @@ int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t f
return 0;
} else {
TSK_DEBUG_WARN("run_loop not initialized yet.");
return 0; //Will be taken when mainthead start
return 0; //Will be taken when mainthead is started
}
}
/* Remove socket
*/
int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause){
tnet_transport_t *transport = (tnet_transport_t*)handle;
transport_context_t *context;
transport_socket_t* socket;
if(!transport || !(context = (transport_context_t *)transport->context)){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if((socket = (transport_socket_t*)getSocket(context, fd))){
socket->paused = pause;
}
else {
TSK_DEBUG_WARN("Failed to find socket with fd=%d", (int)fd);
}
return 0;
}
/* Remove socket */
int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t *fd)
{
tnet_transport_t *transport = (tnet_transport_t*)handle;
@ -132,17 +237,19 @@ int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_
tsk_size_t i;
tsk_bool_t found = tsk_false;
if (!transport) {
TSK_DEBUG_ERROR("Invalid server handle.");
return ret;
if (!transport || !fd) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
TSK_DEBUG_INFO("Removing socket %d", *fd);
if (!(context = (transport_context_t*)transport->context)) {
TSK_DEBUG_ERROR("Invalid context.");
return -2;
}
for(i=0; i<context->count; i++) {
for(i=0; i<context->count; ++i) {
if (context->sockets[i]->fd == *fd) {
removeSocketAtIndex(i, context);
found = tsk_true;
@ -151,7 +258,7 @@ int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_
}
}
if (found && context && context->cf_run_loop) {
if (found && context->cf_run_loop) {
// Signal the run-loop
CFRunLoopWakeUp(context->cf_run_loop);
return 0;
@ -162,12 +269,6 @@ int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_
return -1;
}
int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause){
// FIXME
TSK_DEBUG_ERROR("Not implemented");
return 0;
}
tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size)
{
tnet_transport_t *transport = (tnet_transport_t*)handle;
@ -179,21 +280,17 @@ tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t
}
const transport_socket_t* sock = getSocket(transport->context, from);
if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
if (!sock->cf_write_stream) {
TNET_PRINT_LAST_ERROR("No stream found.");
goto bail;
}
if (TNET_SOCKET_TYPE_IS_STREAM(sock->type) && sock->cf_write_stream) {
if (CFWriteStreamGetStatus(sock->cf_write_stream) == kCFStreamStatusNotOpen) {
CFWriteStreamOpen(sock->cf_write_stream);
}
if ((numberOfBytesSent = CFWriteStreamWrite(sock->cf_write_stream, buf, (CFIndex) size)) <= 0) {
TNET_PRINT_LAST_ERROR("Send have failed.");
if ((numberOfBytesSent = CFWriteStreamWrite(sock->cf_write_stream, buf, (CFIndex) size)) < size) {
TNET_PRINT_LAST_ERROR("Send have failed");
goto bail;
}
} else {
if ((numberOfBytesSent = send(from, buf, size, 0)) <= 0) {
TNET_PRINT_LAST_ERROR("Send have failed.");
if ((numberOfBytesSent = send(from, buf, size, 0)) < size) {
TNET_PRINT_LAST_ERROR("Send have failed");
goto bail;
}
}
@ -208,17 +305,17 @@ tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_
int numberOfBytesSent = 0;
if (!transport) {
TSK_DEBUG_ERROR("Invalid server handle.");
TSK_DEBUG_ERROR("Invalid server handle");
goto bail;
}
if (!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) {
TSK_DEBUG_ERROR("In order to use sendto you must use an udp transport.");
TSK_DEBUG_ERROR("In order to use sendto you must use an udp transport");
goto bail;
}
if ((numberOfBytesSent = sendto(from, buf, size, 0, to, sizeof(*to))) <= 0) {
TNET_PRINT_LAST_ERROR("sendto have failed.");
if ((numberOfBytesSent = sendto(from, buf, size, 0, to, tnet_get_sockaddr_size(to))) < size) {
TNET_PRINT_LAST_ERROR("sendto have failed");
goto bail;
}
@ -251,14 +348,14 @@ const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transpor
if((socket = getSocket((transport_context_t*)transport->context, fd))){
// return socket->tlshandle;
}
return 0;
return tsk_null;
}
/*== Get socket ==*/
static const transport_socket_t* getSocket(transport_context_t *context, tnet_fd_t fd)
{
tsk_size_t i;
transport_socket_t* ret = 0;
transport_socket_t* ret = tsk_null;
if (context) {
tsk_safeobj_lock(context);
@ -283,14 +380,19 @@ int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport
sock->fd = fd;
sock->type = type;
sock->owner = take_ownership;
if(!sock){
TSK_DEBUG_ERROR("Failed to allocate socket");
return -1;
}
// TODO: Find out how to specify client certificate
// FIXME: TLS keys
//if (TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
// sock->tlshandle = tnet_sockfd_set_tlsfiles(sock->fd, is_client, transport->tls.ca, transport->tls.pvk, transport->tls.pbk);
//}
tsk_safeobj_lock(context);
wrapSocket(transport, sock);
context->sockets[context->count] = sock;
context->count++;
@ -354,7 +456,7 @@ int removeSocketAtIndex(int index, transport_context_t *context)
context->sockets[i] = context->sockets[i+1];
}
context->sockets[context->count-1] = 0;
context->sockets[context->count-1] = tsk_null;
context->count--;
TSK_DEBUG_INFO("Socket removed");
@ -390,6 +492,7 @@ int tnet_transport_stop(tnet_transport_t *transport)
transport_context_t *context;
if (!transport) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
@ -416,19 +519,28 @@ int tnet_transport_prepare(tnet_transport_t *transport)
int ret = -1;
transport_context_t *context;
if (!transport || !transport->context) {
if (!transport || !(context = transport->context)) {
TSK_DEBUG_ERROR("Invalid parameter.");
return -1;
}
else{
context = transport->context;
}
if (transport->prepared) {
TSK_DEBUG_ERROR("Transport already prepared.");
return -2;
}
/* Prepare master */
if(!transport->master){
if((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){
tsk_strupdate(&transport->local_ip, transport->master->ip);
transport->bind_local_port = transport->master->port;
}
else{
TSK_DEBUG_ERROR("Failed to create master socket");
return -3;
}
}
/* Start listening */
if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
if ((ret = tnet_sockfd_listen(transport->master->fd, TNET_MAX_FDS))) {
@ -438,7 +550,9 @@ int tnet_transport_prepare(tnet_transport_t *transport)
}
/* Add the master socket to the context. */
if ((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_true, tsk_false))) {
// don't take ownership: will be closed by the dtor()
// otherwise will be cosed twice: dtor() and removeSocket
if ((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false))) {
TSK_DEBUG_ERROR("Failed to add master socket");
goto bail;
}
@ -450,8 +564,26 @@ bail:
}
int tnet_transport_unprepare(tnet_transport_t *transport){
// FIXME
TSK_DEBUG_ERROR("Not implemented");
transport_context_t *context;
if(!transport || !(context = transport->context)){
TSK_DEBUG_ERROR("Invalid parameter.");
return -1;
}
if(!transport->prepared){
return 0;
}
transport->prepared = tsk_false;
while(context->count){
removeSocketAtIndex(0, context); // safe
}
// destroy master as it has been closed by removeSocket()
TSK_OBJECT_SAFE_FREE(transport->master);
return 0;
}
@ -465,10 +597,12 @@ void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType even
// Extract the native socket
CFDataRef data = CFReadStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle);
if(!data) goto bail;
CFSocketNativeHandle fd;
CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd);
CFRelease(data);
transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd);
if(!sock) goto bail;
switch(eventType) {
case kCFStreamEventOpenCompleted:
@ -478,29 +612,7 @@ void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType even
}
case kCFStreamEventHasBytesAvailable:
{
tsk_size_t len = 0;
void *buffer = 0;
tnet_transport_event_t* e;
// Allocate a standard buffer
len = TNET_BUFFER_SIZE;
if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) {
TSK_DEBUG_ERROR("TSK_CALLOC FAILED.");
break;
}
// Process to read data
CFIndex index = CFReadStreamRead(stream, buffer, TNET_BUFFER_SIZE);
len = index;
TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> %u bytes read", len);
e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd);
e->data = buffer;
e->size = len;
TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport), e);
recvData(transport, sock);
break;
}
case kCFStreamEventEndEncountered:
@ -520,12 +632,13 @@ void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType even
default:
{
// Not Implemented
assert(42 == 0);
TSK_DEBUG_WARN("Not implemented");
break;
}
}
/* unlock context */
bail:
tsk_safeobj_unlock(context);
}
@ -539,17 +652,20 @@ void __CFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType ev
// Extract the native socket
CFDataRef data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketNativeHandle);
if(!data) goto bail;
CFSocketNativeHandle fd;
CFDataGetBytes(data, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8*) &fd);
CFRelease(data);
transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd);
if(!sock) goto bail;
switch(eventType) {
case kCFStreamEventOpenCompleted:
{
TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventOpenCompleted");
if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) {
if (TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
sock->connected = tsk_true;
#if !TARGET_OS_IPHONE
SSLContextRef sslContext = NULL;
data = CFWriteStreamCopyProperty(stream, kCFStreamPropertySocketSSLContext);
@ -579,12 +695,13 @@ void __CFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType ev
default:
{
// Not Implemented
assert(42 == 0);
TSK_DEBUG_ERROR("Not implemented");
break;
}
}
/* unlock context */
bail:
tsk_safeobj_unlock(context);
}
@ -596,6 +713,7 @@ void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFData
// Extract the native socket
int fd = CFSocketGetNative(s);
transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd);
if(!sock) goto bail;
/* lock context */
tsk_safeobj_lock(context);
@ -603,47 +721,7 @@ void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFData
switch (callbackType) {
case kCFSocketReadCallBack:
{
int ret;
tsk_size_t len = 0;
void* buffer = 0;
tnet_transport_event_t* e;
if (tnet_ioctlt(sock->fd, FIONREAD, &len) < 0) {
TNET_PRINT_LAST_ERROR("IOCTLT FAILED.");
break;
}
if (!len) {
TSK_DEBUG_WARN("IOCTLT returned zero.");
TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, sock->fd);
removeSocket(sock, context);
break;
}
if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) {
TSK_DEBUG_ERROR("TSK_CALLOC FAILED.");
break;
}
if ((ret = tnet_sockfd_recv(sock->fd, buffer, len, 0)) < 0) {
TSK_FREE(buffer);
removeSocket(sock, context);
TNET_PRINT_LAST_ERROR("recv have failed.");
break;
}
else if ((len != (tsk_size_t)ret) && len) { // useless test ?
len = (tsk_size_t)ret;
// buffer = tsk_realloc(buffer, len);
}
TSK_DEBUG_INFO("__CFSocketCallBack -> %u bytes read", len);
e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd);
e->data = buffer;
e->size = len;
TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(transport), e);
recvData(transport, sock);
break;
}
case kCFSocketAcceptCallBack:
@ -653,22 +731,27 @@ void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFData
default:
{
// Not Implemented
assert(42 == 0);
TSK_DEBUG_ERROR("Not implemented");
break;
}
}
/* unlock context */
bail:
tsk_safeobj_unlock(context);
}
int tnet_transport_wrap(tnet_transport_t *transport, int index) {
transport_context_t *context = transport->context;
transport_socket_t *sock = context->sockets[index];
int wrapSocket(tnet_transport_t *transport, transport_socket_t *sock)
{
transport_context_t *context;
if(!transport || !(context = transport->context) || !sock){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
// If the socket is already wrapped in a CFSocket then return.
if (sock->cf_socket || sock->cf_read_stream) {
return 1;
// If the socket is already wrapped in a CFSocket or mainthead not started yet then return
if (!context->cf_run_loop || sock->cf_socket || sock->cf_read_stream) {
return 0;
}
// Put a reference to the transport context
@ -703,7 +786,7 @@ int tnet_transport_wrap(tnet_transport_t *transport, int index) {
CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
if (TNET_SOCKET_TYPE_IS_SECURE(sock->type)) {
if (TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
CFMutableDictionaryRef settings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
CFDictionaryAddValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue);
@ -719,11 +802,9 @@ int tnet_transport_wrap(tnet_transport_t *transport, int index) {
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 };
@ -770,19 +851,17 @@ void *tnet_transport_mainthread(void *param)
// Set the RunLoop of the context
context->cf_run_loop = CFRunLoopGetCurrent();
// Wrap sockets now that the runloop is defined
tsk_safeobj_lock(context);
for (i = 0; i < context->count; ++i) {
wrapSocket(transport, context->sockets[i]);
}
tsk_safeobj_unlock(context);
while(TSK_RUNNABLE(transport)->running)
{
// Check if new socket were added and wrap them.
// We go backward as new socket are always added at the end.
for(i = context->count - 1; i >= 0; i--) {
if (tnet_transport_wrap(transport, i)) {
break;
}
}
// Give some time to process sources
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0, false);
if (!TSK_RUNNABLE(transport)->running) {
goto bail;
@ -790,11 +869,12 @@ void *tnet_transport_mainthread(void *param)
}
// Remove all the sockets, streams and sources from the run loop
tsk_safeobj_lock(context);
for(i = 0; i < context->count; i++) {
transport_context_t *context = transport->context;
transport_socket_t *sock = context->sockets[i];
if (sock) {
if (!sock) {
continue;
}
if (sock->cf_run_loop_source) {
@ -809,6 +889,7 @@ void *tnet_transport_mainthread(void *param)
CFWriteStreamUnscheduleFromRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
}
}
tsk_safeobj_unlock(context);
bail:

View File

@ -35,14 +35,10 @@
#include "tsk_buffer.h"
#include "tsk_safeobj.h"
#if TNET_USE_POLL //&& !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
#if TNET_USE_POLL && !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
#include "tnet_poll.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
# import <CFNetwork/CFNetwork.h>
#endif
#define TNET_MAX_FDS 64
/*== Socket description ==*/
@ -55,11 +51,6 @@ typedef struct transport_socket_s
tnet_socket_type_t type;
tnet_tls_socket_handle_t* tlshandle;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
CFReadStreamRef cfReadStream;
CFWriteStreamRef cfWriteStream;
#endif
}
transport_socket_t;
@ -318,54 +309,6 @@ int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport
context->count++;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
if(context->pipeR != sock->fd){
if(TNET_SOCKET_TYPE_IS_DGRAM(sock->type)){
CFSocketRef cfSocket;
cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,
sock->fd,
kCFSocketReadCallBack,
tsk_null,
tsk_null);
// Don't close the socket if the CFSocket is invalidated
CFOptionFlags flags = CFSocketGetSocketFlags(cfSocket);
flags = flags & ~kCFSocketCloseOnInvalidate;
CFSocketSetSocketFlags(cfSocket, flags);
if (CFSocketIsValid(cfSocket)) {
CFSocketInvalidate(cfSocket);
}
CFRelease(cfSocket);
}
else if(TNET_SOCKET_TYPE_IS_STREAM(sock->type)){
CFStreamCreatePairWithSocket(kCFAllocatorDefault, (CFSocketNativeHandle)sock->fd, &sock->cfReadStream, &sock->cfWriteStream);
CFReadStreamSetProperty(sock->cfReadStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
CFWriteStreamSetProperty(sock->cfWriteStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
if(!CFReadStreamSetProperty(sock->cfReadStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP)){
TNET_PRINT_LAST_ERROR("CFReadStreamSetProperty(cfReadStream, kCFStreamNetworkServiceTypeVoIP) failed");
}
if(!CFWriteStreamSetProperty(sock->cfWriteStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP)){
TNET_PRINT_LAST_ERROR("CFReadStreamSetProperty(cfWriteStream, kCFStreamNetworkServiceTypeVoIP) failed");
}
}
if(sock->cfReadStream){
if(!CFReadStreamOpen(sock->cfReadStream)){
TNET_PRINT_LAST_ERROR("CFReadStreamOpen(cfWriteStream) failed");
}
}
if(sock->cfWriteStream){
if(!CFWriteStreamOpen(sock->cfWriteStream)){
TNET_PRINT_LAST_ERROR("CFWriteStreamOpen(cfWriteStream) failed");
}
}
}
#endif
tsk_safeobj_unlock(context);
TSK_DEBUG_INFO("Socket added %d", fd);
@ -401,18 +344,6 @@ int removeSocket(int index, transport_context_t *context)
tsk_safeobj_lock(context);
if(index < (int)context->count){
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
// Even if we are not the owner as CFSocket is only supported at low level
if(context->sockets[index]->cfReadStream){
CFReadStreamClose(context->sockets[index]->cfReadStream);
CFRelease(context->sockets[index]->cfReadStream);
}
if(context->sockets[index]->cfWriteStream){
CFWriteStreamClose(context->sockets[index]->cfWriteStream);
CFRelease(context->sockets[index]->cfWriteStream);
}
#endif
/* Close the socket if we are the owner. */
if(context->sockets[index]->owner){
tnet_sockfd_close(&(context->sockets[index]->fd));
@ -581,7 +512,7 @@ int tnet_transport_unprepare(tnet_transport_t *transport)
removeSocket(0, context); // safe
}
// destroy master as it has been close by removeSocket()
// destroy master as it has been closed by removeSocket()
TSK_OBJECT_SAFE_FREE(transport->master);
return 0;

View File

@ -117,6 +117,7 @@ int tsip_transport_msg_update_aor(tsip_transport_t* self, tsip_message_t *msg)
if(!self->stack->network.aor.ip && !self->stack->network.aor.port){
tnet_ip_t ip = {0};
tnet_port_t port = 0;
if((ret = tsip_transport_get_public_ip_n_port(self, &ip, &port))){
TSK_DEBUG_ERROR("Failed to get public IP");
return ret;