Fix issues on iOS8
This commit is contained in:
parent
8d4e3a181b
commit
6264f73f51
|
@ -312,7 +312,7 @@ tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t
|
||||||
return numberOfBytesSent;
|
return numberOfBytesSent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (to_send > 0 && (sent = CFWriteStreamWrite(sock->cf_write_stream, &buff_ptr[numberOfBytesSent], (CFIndex) to_send)) > 0) {
|
while (to_send > 0 && (sent = (int)CFWriteStreamWrite(sock->cf_write_stream, &buff_ptr[numberOfBytesSent], (CFIndex) to_send)) > 0) {
|
||||||
numberOfBytesSent += sent;
|
numberOfBytesSent += sent;
|
||||||
to_send = TSK_MIN(max_size_to_send, (size - numberOfBytesSent));
|
to_send = TSK_MIN(max_size_to_send, (size - numberOfBytesSent));
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((numberOfBytesSent = send(from, buf, size, 0)) < size) {
|
if ((numberOfBytesSent = (int)send(from, buf, size, 0)) < size) {
|
||||||
TNET_PRINT_LAST_ERROR("Send have failed");
|
TNET_PRINT_LAST_ERROR("Send have failed");
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
@ -460,6 +460,12 @@ int removeSocketAtIndex(int index, transport_context_t *context)
|
||||||
|
|
||||||
if (index < (int)context->count) {
|
if (index < (int)context->count) {
|
||||||
transport_socket_xt *sock = context->sockets[index];
|
transport_socket_xt *sock = context->sockets[index];
|
||||||
|
|
||||||
|
// Remove from runloop
|
||||||
|
if (context->cf_run_loop && sock->cf_run_loop_source) {
|
||||||
|
CFRunLoopRemoveSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopCommonModes);
|
||||||
|
CFRelease(sock->cf_run_loop_source), sock->cf_run_loop_source = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Invalidate CFSocket
|
// Invalidate CFSocket
|
||||||
if (sock->cf_socket) {
|
if (sock->cf_socket) {
|
||||||
|
@ -467,6 +473,7 @@ int removeSocketAtIndex(int index, transport_context_t *context)
|
||||||
CFSocketInvalidate(sock->cf_socket);
|
CFSocketInvalidate(sock->cf_socket);
|
||||||
}
|
}
|
||||||
CFRelease(sock->cf_socket);
|
CFRelease(sock->cf_socket);
|
||||||
|
sock->cf_socket = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close and free write stream
|
// Close and free write stream
|
||||||
|
@ -657,9 +664,11 @@ void __CFReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType even
|
||||||
case kCFStreamEventOpenCompleted:
|
case kCFStreamEventOpenCompleted:
|
||||||
{
|
{
|
||||||
TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> kCFStreamEventOpenCompleted(fd=%d)", sock->fd);
|
TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> kCFStreamEventOpenCompleted(fd=%d)", sock->fd);
|
||||||
sock->readable = tsk_true;
|
if (!sock->readable) {
|
||||||
if(sock->writable){
|
sock->readable = tsk_true;
|
||||||
TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, sock->fd);
|
if (sock->writable) {
|
||||||
|
TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, sock->fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -738,9 +747,11 @@ void __CFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType ev
|
||||||
{
|
{
|
||||||
// To avoid blocking, call this function only if CFWriteStreamCanAcceptBytes returns true or after the stream’s client (set with CFWriteStreamSetClient) is notified of a kCFStreamEventCanAcceptBytes event.
|
// To avoid blocking, call this function only if CFWriteStreamCanAcceptBytes returns true or after the stream’s client (set with CFWriteStreamSetClient) is notified of a kCFStreamEventCanAcceptBytes event.
|
||||||
TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventCanAcceptBytes(fd=%d)", sock->fd);
|
TSK_DEBUG_INFO("__CFWriteStreamClientCallBack --> kCFStreamEventCanAcceptBytes(fd=%d)", sock->fd);
|
||||||
sock->writable = tsk_true;
|
if (!sock->writable) {
|
||||||
if(sock->readable){
|
sock->writable = tsk_true;
|
||||||
TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, sock->fd);
|
if (sock->readable) {
|
||||||
|
TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, sock->fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -800,8 +811,33 @@ void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFData
|
||||||
}
|
}
|
||||||
case kCFSocketAcceptCallBack:
|
case kCFSocketAcceptCallBack:
|
||||||
case kCFSocketConnectCallBack:
|
case kCFSocketConnectCallBack:
|
||||||
case kCFSocketDataCallBack:
|
|
||||||
case kCFSocketWriteCallBack:
|
case kCFSocketWriteCallBack:
|
||||||
|
{
|
||||||
|
TSK_DEBUG_INFO("__CFSocketCallBack(fd=%d), callbackType=%lu", sock->fd, callbackType);
|
||||||
|
wrapSocket(transport, sock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kCFSocketDataCallBack:
|
||||||
|
{
|
||||||
|
if (data) {
|
||||||
|
const UInt8 *ptr = CFDataGetBytePtr((CFDataRef)data);
|
||||||
|
int len = (int)CFDataGetLength((CFDataRef)data);
|
||||||
|
if (ptr && len > 0) {
|
||||||
|
tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, sock->fd);
|
||||||
|
if (e) {
|
||||||
|
e->data = tsk_malloc(len);
|
||||||
|
if (e->data) {
|
||||||
|
memcpy(e->data, ptr, len);
|
||||||
|
e->size = len;
|
||||||
|
}
|
||||||
|
memcpy(&e->remote_addr, (struct sockaddr*)address, tnet_get_sockaddr_size((struct sockaddr*)address));
|
||||||
|
TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Not Implemented
|
// Not Implemented
|
||||||
|
@ -826,41 +862,64 @@ int wrapSocket(tnet_transport_t *transport, transport_socket_xt *sock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the socket is already wrapped in a CFSocket or mainthead not started yet then return
|
// 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) {
|
if (!context->cf_run_loop) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put a reference to the transport context
|
// Put a reference to the transport context
|
||||||
const CFSocketContext socket_context = { 0, transport, NULL, NULL, NULL };
|
const CFSocketContext socket_context = { 0, transport, NULL, NULL, NULL };
|
||||||
|
|
||||||
if (TNET_SOCKET_TYPE_IS_DGRAM(sock->type)) {
|
// Wrap socket and listen to events
|
||||||
|
if (!sock->cf_socket && !sock->cf_read_stream && !sock->cf_write_stream) {
|
||||||
// Create a CFSocket from the native socket and register for Read events
|
sock->cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
|
||||||
sock->cf_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
|
|
||||||
sock->fd,
|
sock->fd,
|
||||||
kCFSocketReadCallBack,
|
kCFSocketReadCallBack | kCFSocketConnectCallBack | kCFSocketWriteCallBack | kCFSocketAcceptCallBack | kCFSocketDataCallBack,
|
||||||
&__CFSocketCallBack,
|
&__CFSocketCallBack,
|
||||||
&socket_context);
|
&socket_context);
|
||||||
|
|
||||||
// Don't close the socket if the CFSocket is invalidated
|
// Don't close the socket if the CFSocket is invalidated
|
||||||
CFOptionFlags flags = CFSocketGetSocketFlags(sock->cf_socket);
|
CFOptionFlags flags = CFSocketGetSocketFlags(sock->cf_socket);
|
||||||
flags = flags & ~kCFSocketCloseOnInvalidate;
|
flags = flags & ~kCFSocketCloseOnInvalidate;
|
||||||
CFSocketSetSocketFlags(sock->cf_socket, flags);
|
CFSocketSetSocketFlags(sock->cf_socket, flags);
|
||||||
|
|
||||||
|
|
||||||
// Create a new RunLoopSource and register it with the main thread RunLoop
|
// Create a new RunLoopSource and register it with the main thread RunLoop
|
||||||
sock->cf_run_loop_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock->cf_socket, 0);
|
sock->cf_run_loop_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock->cf_socket, 0);
|
||||||
CFRunLoopAddSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopDefaultMode);
|
CFRunLoopAddSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopCommonModes);
|
||||||
CFRelease(sock->cf_run_loop_source), sock->cf_run_loop_source = NULL;
|
}
|
||||||
|
|
||||||
|
if (TNET_SOCKET_TYPE_IS_DGRAM(sock->type)) {
|
||||||
|
// Nothing to do
|
||||||
|
|
||||||
} else if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
|
} else if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
|
||||||
|
if (!sock->cf_read_stream && !sock->cf_write_stream) {
|
||||||
// Create a pair of streams (read/write) from the socket
|
// Create a pair of streams (read/write) from the socket
|
||||||
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock->fd, &sock->cf_read_stream, &sock->cf_write_stream);
|
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock->fd, &sock->cf_read_stream, &sock->cf_write_stream);
|
||||||
|
|
||||||
// Don't close underlying socket
|
// Don't close underlying socket
|
||||||
CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
|
CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
|
||||||
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
|
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
|
||||||
|
|
||||||
|
// Mark the stream for VoIP usage
|
||||||
|
CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
|
||||||
|
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
|
||||||
|
|
||||||
|
// 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 | kCFStreamEventCanAcceptBytes |kCFStreamEventEndEncountered,
|
||||||
|
&__CFWriteStreamClientCallBack,
|
||||||
|
&streamContext);
|
||||||
|
|
||||||
|
// Enroll streams in the run-loop
|
||||||
|
CFReadStreamScheduleWithRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopCommonModes);
|
||||||
|
CFWriteStreamScheduleWithRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopCommonModes);
|
||||||
|
}
|
||||||
|
|
||||||
if (TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
|
if (TNET_SOCKET_TYPE_IS_TLS(sock->type)) {
|
||||||
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
|
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
|
||||||
|
@ -904,34 +963,28 @@ int wrapSocket(tnet_transport_t *transport, transport_socket_xt *sock)
|
||||||
CFRelease(settings);
|
CFRelease(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the stream for VoIP usage
|
// Open streams only if ready (otherwise, fails on iOS8)
|
||||||
CFReadStreamSetProperty(sock->cf_read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
|
if (tnet_sockfd_waitUntilReadable(sock->fd, 1) == 0 || tnet_sockfd_waitUntilWritable(sock->fd, 1) == 0) {
|
||||||
CFWriteStreamSetProperty(sock->cf_write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
|
// switch from cf_socket to streams
|
||||||
|
if (sock->cf_run_loop_source) {
|
||||||
// Setup a context for the streams
|
CFRunLoopRemoveSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopCommonModes);
|
||||||
CFStreamClientContext streamContext = { 0, transport, NULL, NULL, NULL };
|
CFRelease(sock->cf_run_loop_source), sock->cf_run_loop_source = NULL;
|
||||||
|
}
|
||||||
// Set the client callback for the stream
|
if (sock->cf_socket) {
|
||||||
CFReadStreamSetClient(sock->cf_read_stream,
|
CFSocketInvalidate(sock->cf_socket);
|
||||||
kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
|
CFRelease(sock->cf_socket);
|
||||||
&__CFReadStreamClientCallBack,
|
sock->cf_socket = NULL;
|
||||||
&streamContext);
|
}
|
||||||
CFWriteStreamSetClient(sock->cf_write_stream,
|
|
||||||
kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventCanAcceptBytes |kCFStreamEventEndEncountered,
|
// Open streams
|
||||||
&__CFWriteStreamClientCallBack,
|
if (!CFReadStreamOpen(sock->cf_read_stream)) {
|
||||||
&streamContext);
|
TSK_DEBUG_ERROR("CFReadStreamOpen(fd=%d) failed", sock->fd);
|
||||||
|
return -1;
|
||||||
// Enroll streams in the run-loop
|
}
|
||||||
CFReadStreamScheduleWithRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
|
if (!CFWriteStreamOpen(sock->cf_write_stream)) {
|
||||||
CFWriteStreamScheduleWithRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
|
TSK_DEBUG_ERROR("CFWriteStreamOpen(fd=%d) failed", sock->fd);
|
||||||
|
return -1;
|
||||||
if (!CFReadStreamOpen(sock->cf_read_stream)) {
|
}
|
||||||
TSK_DEBUG_ERROR("CFReadStreamOpen(fd=%d) failed", sock->fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!CFWriteStreamOpen(sock->cf_write_stream)) {
|
|
||||||
TSK_DEBUG_ERROR("CFWriteStreamOpen(fd=%d) failed", sock->fd);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,7 +1004,7 @@ void *tnet_transport_mainthread(void *param)
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
|
TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} with fd {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->fd);
|
||||||
|
|
||||||
// Set the RunLoop of the context
|
// Set the RunLoop of the context
|
||||||
context->cf_run_loop = CFRunLoopGetCurrent();
|
context->cf_run_loop = CFRunLoopGetCurrent();
|
||||||
|
|
Loading…
Reference in New Issue