Exemple #1
0
int tnet_transport_start(tnet_transport_handle_t* handle)
{
	int ret = -1;
	if(handle){
		tnet_transport_t *transport = handle;
				
		/* prepare transport */
		if((ret = tnet_transport_prepare(transport))){
			TSK_DEBUG_ERROR("Failed to prepare transport.");
			goto bail;
		}
		
		/* start transport */
		TSK_RUNNABLE(transport)->run = run;
		if((ret = tsk_runnable_start(TSK_RUNNABLE(transport), tnet_transport_event_def_t))){
			TSK_DEBUG_ERROR("Failed to start transport.");
			goto bail;
		}
	}
	else{
		TSK_DEBUG_ERROR("NULL transport object.");
	}

bail:
	return ret;
}
int tsip_api_publish_send_publish(const tsip_ssession_handle_t *ss, ...)
{
	const tsip_ssession_t* _ss;
	va_list ap;
	tsip_action_t* action;
	tsip_dialog_t* dialog;
	int ret = -1;

	if(!(_ss = ss) || !_ss->stack){
		TSK_DEBUG_ERROR("Invalid parameter.");
		return ret;
	}

	/* Checks if the stack has been started */
	if(!TSK_RUNNABLE(_ss->stack)->started){
		TSK_DEBUG_ERROR("Stack not started.");
		return -2;
	}
	
	va_start(ap, ss);
	if((action = _tsip_action_create(tsip_atype_publish, &ap))){
		if(!(dialog = tsip_dialog_layer_find_by_ss(_ss->stack->layer_dialog, ss))){
			dialog = tsip_dialog_layer_new(_ss->stack->layer_dialog, tsip_dialog_PUBLISH, ss);
		}
		ret = tsip_dialog_fsm_act(dialog, action->type, tsk_null, action);
		
		tsk_object_unref(dialog);
		TSK_OBJECT_SAFE_FREE(action);
	}
	va_end(ap);

	return ret;
}
int tsip_api_publish_send_unpublish(const tsip_ssession_handle_t *ss, ...)
{
	const tsip_ssession_t* _ss;
	va_list ap;
	tsip_action_t* action;
	int ret = -1;

	if(!(_ss = ss) || !_ss->stack){
		TSK_DEBUG_ERROR("Invalid parameter.");
		return ret;
	}

	/* Checks if the stack is running */
	if(!TSK_RUNNABLE(_ss->stack)->running){
		TSK_DEBUG_ERROR("Stack not running.");
		return -2;
	}
	
	va_start(ap, ss);
	if((action = _tsip_action_create(tsip_atype_unpublish, &ap))){
		ret = tsip_ssession_handle(ss, action);
		TSK_OBJECT_SAFE_FREE(action);
	}
	va_end(ap);

	return 0;
}
Exemple #4
0
tnet_transport_t* tnet_transport_create(const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description)
{		
	tnet_transport_t* transport;

	if((transport = tsk_object_new(tnet_transport_def_t))){
		transport->description = tsk_strdup(description);
		transport->local_host = tsk_strdup(host);
		transport->req_local_port = port;
		transport->type = type;
		transport->context = tnet_transport_context_create();
		
		if((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){
			transport->local_ip = tsk_strdup(transport->master->ip);
			transport->bind_local_port = transport->master->port;
		}
		else{
			TSK_DEBUG_ERROR("Failed to create master socket");
			TSK_OBJECT_SAFE_FREE(transport);
		}

		if(_tnet_transport_ssl_init(transport) != 0){
			TSK_DEBUG_ERROR("Failed to initialize TLS and/or DTLS caps");
			TSK_OBJECT_SAFE_FREE(transport);
		}
		// set priority
		tsk_runnable_set_priority(TSK_RUNNABLE(transport), TSK_THREAD_PRIORITY_TIME_CRITICAL);
	}

	return transport;
}
Exemple #5
0
tnet_transport_t* tnet_transport_create_2(tnet_socket_t *master, const char* description)
{
	tnet_transport_t* transport;
	if(!master){
		TSK_DEBUG_ERROR("Invalid parameter");
		return tsk_null;
	}

	if((transport = tsk_object_new(tnet_transport_def_t))){
		transport->description = tsk_strdup(description);
		transport->local_host = tsk_strdup(master->ip);
		transport->req_local_port = master->port;
		transport->type = master->type;
		
		transport->master = tsk_object_ref(master);
		transport->local_ip = tsk_strdup(transport->master->ip);
		transport->bind_local_port = transport->master->port;

		transport->context = tnet_transport_context_create();

		if(_tnet_transport_ssl_init(transport) != 0){
			TSK_DEBUG_ERROR("Failed to initialize TLS and/or DTLS caps");
			TSK_OBJECT_SAFE_FREE(transport);
		}

		// set priority
		tsk_runnable_set_priority(TSK_RUNNABLE(transport), TSK_THREAD_PRIORITY_TIME_CRITICAL);
	}

	return transport;
}
int tnet_transport_stop(tnet_transport_t *transport)
{	
	int ret;
	transport_context_t *context;
    
	if (!transport) {
		return -1;
	}
	
	context = transport->context;
	
	if ((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))) {
		return ret;
	}
	
	if(transport->mainThreadId[0]){
		if (context && context->cf_run_loop) {
			// Signal the run-loop
			CFRunLoopWakeUp(context->cf_run_loop);
		}
		return tsk_thread_join(transport->mainThreadId);
	}
	else { // already stopped
		return 0;
	}
}
int tnet_transport_stop(tnet_transport_t *transport)
{
    int ret;
    transport_context_t *context;

    if(!transport) {
        return -1;
    }

    context = transport->context;

    if((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))) {
        return ret;
    }

    if(context) {
        static char c = '\0';

        // signal
        tsk_safeobj_lock(context); // =>MUST
        if(tnet_transport_have_socket(transport, context->pipeR)) { // to avoid SIGPIPE=> check that there is at least one reader
            write(context->pipeW, &c, 1);
        }
        tsk_safeobj_unlock(context);
    }

    if(transport->mainThreadId[0]) {
        return tsk_thread_join(transport->mainThreadId);
    }
    else {
        /* already soppped */
        return 0;
    }
}
Exemple #8
0
static int _tnet_transport_dtls_cb(const void* usrdata, tnet_dtls_socket_event_type_t dtls_e, const tnet_dtls_socket_handle_t* handle, const void* data, tsk_size_t size)
{
	tnet_transport_t *transport = (tnet_transport_t*)usrdata;
	if (transport) {
		tnet_transport_event_type_t t_e;
		const struct sockaddr_storage* remote_addr;
		tnet_fd_t fd;
		tnet_transport_event_t* e;

		switch (dtls_e) {
			case tnet_dtls_socket_event_type_handshake_started: t_e = event_dtls_handshake_started; break;
			case tnet_dtls_socket_event_type_handshake_succeed: t_e = event_dtls_handshake_succeed; break;
			case tnet_dtls_socket_event_type_handshake_failed: t_e = event_dtls_handshake_failed; break;
			case tnet_dtls_socket_event_type_fingerprint_mismatch: t_e = event_dtls_fingerprint_mismatch; break;
			case tnet_dtls_socket_event_type_dtls_srtp_profile_selected: t_e = event_dtls_srtp_profile_selected; break;
			case tnet_dtls_socket_event_type_dtls_srtp_data: t_e = event_dtls_srtp_data; break;
			case tnet_dtls_socket_event_type_error: t_e = event_dtls_error; break;
			default: TSK_DEBUG_ERROR("DTLS event = %d ignored", dtls_e); return -1;
		}	
		remote_addr = tnet_dtls_socket_get_remote_addr(handle);
		fd = tnet_dtls_socket_get_fd(handle);
		if ((e = tnet_transport_event_create(t_e, transport->callback_data, fd))) {
			if (data && size && (e ->data = tsk_malloc(size))) {
				memcpy(e ->data, data, size);
				e->size = size;
			}
			if (remote_addr) {
				e->remote_addr = *remote_addr;
			}
			if (TSK_RUNNABLE(transport)->initialized && TSK_RUNNABLE(transport)->running && TSK_RUNNABLE(transport)->started) {
				TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
			}
			else {
				TSK_DEBUG_INFO("Delivering network event synchronously.");
				// network transport not started (happens when TURN is using the sockets instead of the RTP manager)
				if (transport->callback) {
					transport->callback(e);
				}
				TSK_OBJECT_SAFE_FREE(e);
			}
			return 0;
		}
	}
	return -1;
}
static tsk_object_t* tdav_runnable_video_dtor(tsk_object_t * self)
{ 
	tdav_runnable_video_t *runnable = self;
	if(runnable){
		tsk_runnable_stop(TSK_RUNNABLE(runnable));
	}

	return self;
}
int tdav_runnable_video_stop(tdav_runnable_video_t* self)
{
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	return tsk_runnable_stop(TSK_RUNNABLE(self));
}
int tsip_publish_event_signal(tsip_publish_event_type_t type, tsip_ssession_handle_t* ss, short status_code, const char *phrase, const tsip_message_t* sipmessage)
{
	tsip_publish_event_t* sipevent = TSIP_PUBLISH_EVENT_CREATE(type);
	tsip_event_init(TSIP_EVENT(sipevent), ss, status_code, phrase, sipmessage, tsip_event_publish);

	TSK_RUNNABLE_ENQUEUE_OBJECT(TSK_RUNNABLE(TSIP_SSESSION(ss)->stack), sipevent);

	return 0;
}
int tdav_runnable_video_start(tdav_runnable_video_t* self)
{
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	return tsk_runnable_start(TSK_RUNNABLE(self), tsk_buffer_def_t);
}
tdav_runnable_video_t* tdav_runnable_video_create(tsk_runnable_func_run run_f, const void* userdata)
{
	tdav_runnable_video_t* runnable;

	if((runnable = tsk_object_new(tdav_runnable_video_def_t))){
		TSK_RUNNABLE(runnable)->run = run_f;
		runnable->userdata = userdata;
	}
	return runnable;
}
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, tnet_tls_socket_handle_t* tlsHandle)
{
    tnet_transport_t *transport = (tnet_transport_t*)handle;
    transport_context_t* context;
    static char c = '\0';
    int ret = -1;

    if(!transport) {
        TSK_DEBUG_ERROR("Invalid server handle.");
        return ret;
    }

    if(!(context = (transport_context_t*)transport->context)) {
        TSK_DEBUG_ERROR("Invalid context.");
        return -2;
    }

    if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)) {
        transport->tls.enabled = 1;
    }

    if((ret = addSocket(fd, type, transport, take_ownership, isClient, tlsHandle))) {
        TSK_DEBUG_ERROR("Failed to add new Socket.");
        return ret;
    }

    // signal
    if(context->pipeW && (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started)) {
        if((ret = write(context->pipeW, &c, 1)) > 0) {
            TSK_DEBUG_INFO("Socket added (external call) %d", fd);
            return 0;
        }
        else {
            TSK_DEBUG_ERROR("Failed to add new Socket.");
            return ret;
        }
    }
    else {
        TSK_DEBUG_INFO("pipeW (write site) not initialized yet.");
        return 0; //Will be taken when mainthead start
    }
}
/*
* Add new socket to the watcher.
*/
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, tnet_tls_socket_handle_t* tlsHandle)
{
    tnet_transport_t *transport = (tnet_transport_t*)handle;
    transport_context_t* context;
    int ret = -1;

    if (!transport) {
        TSK_DEBUG_ERROR("Invalid server handle.");
        return ret;
    }

    if (!(context = (transport_context_t*)transport->context)) {
        TSK_DEBUG_ERROR("Invalid context.");
        return -2;
    }

    if (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)) {
        transport->tls.enabled = tsk_true;
    }

    addSocket(fd, type, transport, take_ownership, isClient, tlsHandle);

    if (WSAEventSelect(fd, context->events[context->count - 1], FD_ALL_EVENTS) == SOCKET_ERROR) {
        removeSocket((int)(context->count - 1), context);
        TNET_PRINT_LAST_ERROR("WSAEventSelect have failed.");
        return -1;
    }

    /* Signal if transport is running */
    if (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) {
        if (WSASetEvent(context->events[0])) {
            TSK_DEBUG_INFO("New socket added to the network transport.");
            return 0;
        }
        TSK_DEBUG_ERROR("Transport not started yet");
        return -1;
    }

    TSK_DEBUG_INFO("Adding socket delayed");
    return 0;
}
/*=== stop all threads */
int tnet_transport_stop(tnet_transport_t *transport)
{
    int ret;

    if ((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))) {
        return ret;
    }

    if (transport->mainThreadId[0]) {
        WSASetEvent(((transport_context_t*)(transport->context))->events[0]);
        return tsk_thread_join(transport->mainThreadId);
    }
    else {
        /* already stoppped */
        return 0;
    }
}
Exemple #17
0
/*
* Runnable interface implementation.
*/
static void* TSK_STDCALL run(void* self)
{
	int ret = 0;
	tsk_list_item_t *curr;
	tnet_transport_t *transport = self;
	
	TSK_DEBUG_INFO("Transport::run() - enter");

	/* create main thread */
	if((ret = tsk_thread_create(transport->mainThreadId, tnet_transport_mainthread, transport))){ /* More important than "tsk_runnable_start" ==> start it first. */
		TSK_FREE(transport->context); /* Otherwise (tsk_thread_create is ok) will be freed when mainthread exit. */
		TSK_DEBUG_FATAL("Failed to create main thread [%d]", ret);
		return tsk_null;
	}
	/* set thread priority 
     iOS and OSX: no incoming pkts (STUN, rtp, dtls...) when thread priority is changed -> to be checked
     */
#if !TNET_UNDER_APPLE
	ret = tsk_thread_set_priority(transport->mainThreadId[0], TSK_THREAD_PRIORITY_TIME_CRITICAL);
#endif
	
	TSK_RUNNABLE_RUN_BEGIN(transport);
	
	if((curr = TSK_RUNNABLE_POP_FIRST_SAFE(TSK_RUNNABLE(transport)))){
		const tnet_transport_event_t *e = (const tnet_transport_event_t*)curr->data;
		
		if (transport->callback) {
			transport->callback(e);
		}
		tsk_object_unref(curr);
	}
	
	TSK_RUNNABLE_RUN_END(transport);

	TSK_DEBUG_INFO("Transport::run(%s) - exit", transport->description);

	return tsk_null;
}
/*=== Main thread */
void* TSK_STDCALL tnet_transport_mainthread(void *param)
{
    tnet_transport_t *transport = (tnet_transport_t*)param;
    transport_context_t *context = (transport_context_t*)transport->context;
    DWORD evt;
    WSANETWORKEVENTS networkEvents;
    DWORD flags = 0;
    int ret;

    struct sockaddr_storage remote_addr = { 0 };
    WSAEVENT active_event;
    transport_socket_xt* active_socket;
    int index;

    TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type);

    while (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) {
        /* Wait for multiple events */
        if ((evt = WSAWaitForMultipleEvents((DWORD)context->count, context->events, FALSE, WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED) {
            TNET_PRINT_LAST_ERROR("WSAWaitForMultipleEvents have failed.");
            goto bail;
        }

        if (!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started) {
            goto bail;
        }

        /* lock context */
        tsk_safeobj_lock(context);

        /* Get active event and socket */
        index = (evt - WSA_WAIT_EVENT_0);
        active_event = context->events[index];
        if (!(active_socket = context->sockets[index])) {
            goto done;
        }

        /* Get the network events flags */
        if (WSAEnumNetworkEvents(active_socket->fd, active_event, &networkEvents) == SOCKET_ERROR) {
            TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
            TNET_PRINT_LAST_ERROR("WSAEnumNetworkEvents have failed.");

            tsk_safeobj_unlock(context);
            goto bail;
        }

        /*================== FD_ACCEPT ==================*/
        if (networkEvents.lNetworkEvents & FD_ACCEPT) {
            tnet_fd_t fd;

            TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT", transport->description);

            if (networkEvents.iErrorCode[FD_ACCEPT_BIT]) {
                TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
                TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
                goto done;
            }

            /* Accept the connection */
            if ((fd = (tnet_fd_t)WSAAccept(active_socket->fd, NULL, NULL, AcceptCondFunc, (DWORD_PTR)context)) != INVALID_SOCKET) {
                /* Add the new fd to the server context */
                addSocket(fd, transport->master->type, transport, tsk_true, tsk_false, tsk_null);
                if (active_socket->tlshandle) {
                    transport_socket_xt* tls_socket;
                    if ((tls_socket = getSocket(context, fd))) {
                        if (tnet_tls_socket_accept(tls_socket->tlshandle)) {
                            tnet_transport_remove_socket(transport, &fd);
                            TNET_PRINT_LAST_ERROR("SSL_accept() failed");
                            goto done;
                        }
                    }
                }
                if (WSAEventSelect(fd, context->events[context->count - 1], FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR) {
                    tnet_transport_remove_socket(transport, &fd);
                    TNET_PRINT_LAST_ERROR("WSAEventSelect() have failed.");
                    goto done;
                }
                TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
            }
            else {
                TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
                goto done;
            }




        }

        /*================== FD_CONNECT ==================*/
        if (networkEvents.lNetworkEvents & FD_CONNECT) {
            TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CONNECT", transport->description);

            if (networkEvents.iErrorCode[FD_CONNECT_BIT]) {
                tnet_fd_t fd = active_socket->fd;
                TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd);
                tnet_transport_remove_socket(transport, &fd);
                TNET_PRINT_LAST_ERROR("CONNECT FAILED.");
                goto done;
            }
            else {
                TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
                active_socket->connected = 1;
            }
        }


        /*================== FD_READ ==================*/
        if (networkEvents.lNetworkEvents & FD_READ) {
            DWORD readCount = 0;
            WSABUF wsaBuffer;

            /* TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_READ", transport->description); */

            /* check whether the socket is paused or not */
            if (active_socket->paused) {
                TSK_DEBUG_INFO("Socket is paused");
                goto FD_READ_DONE;
            }

            if (networkEvents.iErrorCode[FD_READ_BIT]) {
                TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
                TNET_PRINT_LAST_ERROR("READ FAILED.");
                goto done;
            }

            /* Retrieve the amount of pending data */
            if (tnet_ioctlt(active_socket->fd, FIONREAD, &(wsaBuffer.len)) < 0) {
                TNET_PRINT_LAST_ERROR("IOCTLT FAILED.");
                goto done;
            }

            if (!wsaBuffer.len) {
                goto done;
            }

            /* Alloc data */
            if (!(wsaBuffer.buf = tsk_calloc(wsaBuffer.len, sizeof(uint8_t)))) {
                goto done;
            }

            /* Retrieve the remote address */
            if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
                ret = tnet_getpeername(active_socket->fd, &remote_addr);
            }

            /* Receive the waiting data. */
            if (active_socket->tlshandle) {
                int isEncrypted;
                tsk_size_t len = wsaBuffer.len;
                if (!(ret = tnet_tls_socket_recv(active_socket->tlshandle, &wsaBuffer.buf, &len, &isEncrypted))) {
                    if (isEncrypted) {
                        TSK_FREE(wsaBuffer.buf);
                        goto done;
                    }
                    wsaBuffer.len = (ULONG)len;
                }
            }
            else {
                if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
                    ret = WSARecv(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, 0, 0);
                }
                else {
                    int len = sizeof(remote_addr);
                    ret = WSARecvFrom(active_socket->fd, &wsaBuffer, 1, &readCount, &flags,
                                      (struct sockaddr*)&remote_addr, &len, 0, 0);
                }
                if (readCount < wsaBuffer.len) {
                    wsaBuffer.len = readCount;
                    /* wsaBuffer.buf = tsk_realloc(wsaBuffer.buf, readCount); */
                }
            }

            if (ret) {
                ret = WSAGetLastError();
                if (ret == WSAEWOULDBLOCK) {
                    // Doesn't (always) mean congestion but... another thread is also poll()ing the FD. For example, when TURN session has a reference to the fd.
                    TSK_DEBUG_WARN("WSAEWOULDBLOCK error for READ SSESSION");
                }
                else if (ret == WSAECONNRESET && TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) {
                    /* For DGRAM ==> The sent packet gernerated "ICMP Destination/Port unreachable" result. */
                    TSK_FREE(wsaBuffer.buf);
                    goto done; // ignore and retry.
                }
                else {
                    TSK_FREE(wsaBuffer.buf);

                    removeSocket(index, context);
                    TNET_PRINT_LAST_ERROR("WSARecv have failed.");
                    goto done;
                }
            }
            else {
                tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
                transport->bytes_in += wsaBuffer.len;
                e->data = wsaBuffer.buf;
                e->size = wsaBuffer.len;
                e->remote_addr = remote_addr;

                TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
            }
FD_READ_DONE:
            ;
        }




        /*================== FD_WRITE ==================*/
        if (networkEvents.lNetworkEvents & FD_WRITE) {
            TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_WRITE", transport->description);

            if (networkEvents.iErrorCode[FD_WRITE_BIT]) {
                TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
                TNET_PRINT_LAST_ERROR("WRITE FAILED.");
                goto done;
            }
        }



        /*================== FD_CLOSE ==================*/
        if (networkEvents.lNetworkEvents & FD_CLOSE) {
            TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CLOSE", transport->description);

            TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, active_socket->fd);
            removeSocket(index, context);
        }

        /*	http://msdn.microsoft.com/en-us/library/ms741690(VS.85).aspx

        	The proper way to reset the state of an event object used with the WSAEventSelect function
        	is to pass the handle of the event object to the WSAEnumNetworkEvents function in the hEventObject parameter.
        	This will reset the event object and adjust the status of active FD events on the socket in an atomic fashion.
        	*/
        /* WSAResetEvent(active_event); <== DO NOT USE (see above) */

done:
        /* unlock context */
        tsk_safeobj_unlock(context);
    } /* while(transport->running) */


bail:

    TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type);
    return tsk_null;
}
/*=== Main thread */
void *tnet_transport_mainthread(void *param)
{
    tnet_transport_t *transport = param;
    transport_context_t *context = transport->context;
    int ret, status;
    tsk_size_t i;
    tsk_bool_t is_stream;
    tnet_fd_t fd;

    struct sockaddr_storage remote_addr = {0};
    transport_socket_xt* active_socket;

    /* check whether the transport is already prepared */
    if(!transport->prepared) {
        TSK_DEBUG_ERROR("Transport must be prepared before strating.");
        goto bail;
    }

    is_stream = TNET_SOCKET_TYPE_IS_STREAM(transport->master->type);

    TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d} using master fd {%d} with type {%d} with max_fds {%lu}...",
                   transport->description,
                   transport->master->ip,
                   transport->master->port,
                   transport->master->fd,
                   transport->master->type,
                   sizeof(context->ufds)/sizeof(context->ufds[0]));

    while(TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) {
        context->polling = tsk_true;
        ret = tnet_poll(context->ufds, context->count, -1);
        context->polling = tsk_false;
        if(ret < 0) {
            TNET_PRINT_LAST_ERROR("poll() have failed.");
            goto bail;
        }

        if(!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started) {
            TSK_DEBUG_INFO("Stopping [%s] server with IP {%s} on port {%d} with type {%d}...", transport->description, transport->master->ip, transport->master->port, transport->master->type);
            goto bail;
        }

        /* lock context */
        tsk_safeobj_lock(context);

        /* == == */
        for(i=0; i<context->count; i++) {
            if(!context->ufds[i].revents) {
                continue;
            }

            // TSK_DEBUG_INFO("REVENTS(i=%d) = %d", i, context->ufds[i].revents);

            if(context->ufds[i].fd == context->pipeR) {
                TSK_DEBUG_INFO("PipeR event = %d", context->ufds[i].revents);
                if(context->ufds[i].revents & TNET_POLLIN) {
                    static char __buffer[1024];
                    if(read(context->pipeR, __buffer, sizeof(__buffer)) < 0) {
                        TNET_PRINT_LAST_ERROR("Failed to read from the Pipe");
                    }
                }
                else if(context->ufds[i].revents & TNET_POLLHUP) {
                    TNET_PRINT_LAST_ERROR("Pipe Error");
                    goto bail;
                }
                context->ufds[i].revents = 0;
                continue;
            }

            /* Get active event and socket */
            active_socket = context->sockets[i];

            /*================== TNET_POLLHUP ==================*/
            if(context->ufds[i].revents & (TNET_POLLHUP)) {
                if(context->ufds[i].revents & TNET_POLLOUT) {
                    TSK_DEBUG_INFO("POLLOUT and POLLHUP are exclusive");
                }
                else {
                    fd = active_socket->fd;
                    TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLHUP(%d)", transport->description, fd);

                    tnet_transport_remove_socket(transport, &active_socket->fd);
                    TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd);
                    continue;
                }
            }

            /*================== TNET_POLLERR ==================*/
            if(context->ufds[i].revents & (TNET_POLLERR)) {
                fd = active_socket->fd;
                TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLERR(%d)", transport->description, fd);

                tnet_transport_remove_socket(transport, &active_socket->fd);
                TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd);
                continue;
            }

            /*================== TNET_POLLNVAL ==================*/
            if(context->ufds[i].revents & (TNET_POLLNVAL)) {
                fd = active_socket->fd;
                TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLNVAL(%d)", transport->description, fd);

                tnet_transport_remove_socket(transport, &active_socket->fd);
                TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, fd);
                continue;
            }

            /*================== POLLIN ==================*/
            if(context->ufds[i].revents & TNET_POLLIN) {
                tsk_size_t len = 0;
                void* buffer = tsk_null;
                tnet_transport_event_t* e;

                // TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLIN(%d)", transport->description, active_socket->fd);

                /* check whether the socket is paused or not */
                if(active_socket->paused) {
                    TSK_DEBUG_INFO("Socket is paused");
                    goto TNET_POLLIN_DONE;
                }

                /* Retrieve the amount of pending data.
                 * IMPORTANT: If you are using Symbian please update your SDK to the latest build (August 2009) to have 'FIONREAD'.
                 * This apply whatever you are using the 3rd or 5th edition.
                 * Download link: http://wiki.forum.nokia.com/index.php/Open_C/C%2B%2B_Release_History
                 */
                ret = tnet_ioctlt(active_socket->fd, FIONREAD, &len);
                if((ret < 0 || !len) && is_stream) {
                    /* It's probably an incoming connection --> try to accept() it */
                    int listening = 0, remove_socket = 0;
                    socklen_t socklen = sizeof(listening);

                    TSK_DEBUG_INFO("ioctlt(%d), len=%u returned zero or failed", active_socket->fd, (unsigned)len);

                    // check if socket is listening
                    if(getsockopt(active_socket->fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &socklen) != 0) {
#if defined(BSD) /* old FreeBSD versions (and OSX up to Lion) do not support SO_ACCEPTCONN */
                        listening = 1;
#else
                        TNET_PRINT_LAST_ERROR("getsockopt(SO_ACCEPTCONN, %d) failed\n", active_socket->fd);
                        /* not socket accepted -> no socket to remove */
                        goto TNET_POLLIN_DONE;
#endif
                    }
                    if (listening) {
                        if((fd = accept(active_socket->fd, tsk_null, tsk_null)) != TNET_INVALID_SOCKET) {
                            TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT(fd=%d)", transport->description, fd);
                            addSocket(fd, transport->master->type, transport, tsk_true, tsk_false, tsk_null);
                            TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
                            if(active_socket->tlshandle) {
                                transport_socket_xt* tls_socket;
                                if((tls_socket = getSocket(context, fd))) {
                                    if(tnet_tls_socket_accept(tls_socket->tlshandle) != 0) {
                                        TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd);
                                        tnet_transport_remove_socket(transport, &fd);
                                        TNET_PRINT_LAST_ERROR("SSL_accept() failed");
                                        continue;
                                    }
                                }
                            }
                        }
                        else {
                            TNET_PRINT_LAST_ERROR("accept(%d) failed", active_socket->fd);
                            remove_socket = 1;
                        }
                    }
                    else {
                        TSK_DEBUG_INFO("Closing socket with fd = %d because ioctlt() returned zero or failed", active_socket->fd);
                        remove_socket = 1;
                    }

                    if(remove_socket) {
                        fd = active_socket->fd;
                        tnet_transport_remove_socket(transport, &active_socket->fd);
                        TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, fd);
                        continue;
                    }
                    goto TNET_POLLIN_DONE;
                }

                if(len <= 0) {
#if defined(__ANDROID__) || defined(ANDROID)
                    // workaround for indoona OSX which sends bodiless UDP packets
                    // vand Android requires to call recv() even if len is equal to zero
                    if(len == 0 && ret == 0) {
                        static char __fake_buff[1];
                        ret = recv(active_socket->fd, __fake_buff, len, 0);
                    }
#endif
                    goto TNET_POLLIN_DONE;
                }

                if (!(buffer = tsk_calloc(len, sizeof(uint8_t)))) {
                    TSK_DEBUG_ERROR("TSK_CALLOC FAILED");
                    goto TNET_POLLIN_DONE;
                }

                // Retrieve the remote address
                if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) {
                    ret = tnet_getpeername(active_socket->fd, &remote_addr);
                }

                // Receive the waiting data
                if (active_socket->tlshandle) {
                    int isEncrypted;
                    tsk_size_t tlslen = len;
                    if ((ret = tnet_tls_socket_recv(active_socket->tlshandle, &buffer, &tlslen, &isEncrypted)) == 0) {
                        if (isEncrypted) {
                            TSK_FREE(buffer);
                            goto TNET_POLLIN_DONE;
                        }
                        if (ret == 0) {
                            len = ret = tlslen;
                        }
                    }
                }
                else {
                    if (is_stream) {
                        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);
                    status = tnet_geterrno();
                    // do not remove the socket for i/o pending errors
                    if (status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_INPROGRESS || status == TNET_ERROR_EAGAIN) {
                        TSK_DEBUG_WARN("recv returned error code:%d", status);
                    }
                    else {
                        TNET_PRINT_LAST_ERROR("recv/recvfrom have failed");
                        removeSocket(i, context);
                    }
                    goto TNET_POLLIN_DONE;
                }

                if((len != (tsk_size_t)ret) && len) {
                    len = (tsk_size_t)ret;
                    // buffer = tsk_realloc(buffer, len);
                }

                if(len > 0) {
                    transport->bytes_in += len;
                    e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
                    e->data = buffer, buffer = tsk_null;
                    e->size = len;
                    e->remote_addr = remote_addr;

                    TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
                }
                TSK_FREE(buffer);

TNET_POLLIN_DONE:
                /*context->ufds[i].revents &= ~TNET_POLLIN*/
                ;
            }


            /*================== TNET_POLLOUT ==================*/
            if(context->ufds[i].revents & TNET_POLLOUT) {
                TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLOUT", transport->description);
                if(!active_socket->connected) {
                    active_socket->connected = tsk_true;
                    TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
                }
                //else{
                context->ufds[i].events &= ~TNET_POLLOUT;
                //}
            }


            /*================== TNET_POLLPRI ==================*/
            if(context->ufds[i].revents & TNET_POLLPRI) {
                TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLPRI", transport->description);
            }

            context->ufds[i].revents = 0;
        }/* for */

done:
        /* unlock context */
        tsk_safeobj_unlock(context);

    } /* while */

bail:

    TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}", transport->description, transport->master->ip, transport->master->port);
    return 0;
}
void __CFReadStreamClientCallBack(CFReadStreamRef 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 = CFReadStreamCopyProperty(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("__CFReadStreamClientCallBack --> kCFStreamEventOpenCompleted");
            break;
        }
        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);
            
            break;
        }
        case kCFStreamEventEndEncountered:
        case kCFStreamEventErrorOccurred:
        {
            // Get the error code
            CFErrorRef error = CFReadStreamCopyError(stream);
            CFIndex index = CFErrorGetCode(error);
            CFRelease(error);
                        
            TSK_DEBUG_INFO("__CFReadStreamClientCallBack --> 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);
}
void __CFSocketCallBack(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) {
    // Extract the context
    tnet_transport_t *transport = (tnet_transport_t *) info;
	transport_context_t *context = transport->context;
    
    // Extract the native socket
    int fd = CFSocketGetNative(s);
    transport_socket_t *sock = (transport_socket_t *) getSocket(context, fd);

    /* lock context */
    tsk_safeobj_lock(context);
    
    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);
            
            break;
        }
        case kCFSocketAcceptCallBack:
        case kCFSocketConnectCallBack:
        case kCFSocketDataCallBack:
        case kCFSocketWriteCallBack:
        default:
        {
            // Not Implemented
            assert(42 == 0);
            break;
        }
    }
    
    /* unlock context */
    tsk_safeobj_unlock(context);
}
/*=== Main thread */
void *tnet_transport_mainthread(void *param)
{
	tnet_transport_t *transport = param;
    transport_context_t *context = transport->context;
    int i;

	/* check whether the transport is already prepared */
	if (!transport->prepared) {
		TSK_DEBUG_ERROR("Transport must be prepared before strating.");
		goto bail;
	}
	
	TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
    
    // Set the RunLoop of the context
    context->cf_run_loop = CFRunLoopGetCurrent();
    
	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);
        
		if (!TSK_RUNNABLE(transport)->running) {
            goto bail;
		}
    }
    
    // Remove all the sockets, streams and sources from the run loop
    for(i = 0; i < context->count; i++) {
        transport_context_t *context = transport->context;
        transport_socket_t *sock = context->sockets[i];
        
        if (sock) {
            continue;
        }
        if (sock->cf_run_loop_source) {
            CFRunLoopRemoveSource(context->cf_run_loop, sock->cf_run_loop_source, kCFRunLoopDefaultMode);
        }
        if (sock->cf_read_stream) {
            //CFReadStreamClose(sock->cf_read_stream);
            CFReadStreamUnscheduleFromRunLoop(sock->cf_read_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
        }
        if (sock->cf_write_stream) {
            //CFWriteStreamClose(sock->cf_write_stream);
            CFWriteStreamUnscheduleFromRunLoop(sock->cf_write_stream, context->cf_run_loop, kCFRunLoopDefaultMode);
        }
    }

    
bail:
	TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
	return 0;
}