Exemple #1
0
bool Socket::open()
{
    // Prevent double call to this func.
    if ( m_OutBuffer.get() )
        return false;

    // Store peer address.
    m_Address = obtain_remote_address();
    if( m_Address == UNKNOWN_NETWORK_ADDRESS )
        return false;

    // Hook for the manager.
    if ( !m_manager.OnSocketOpen( shared_from_this() ) )
        return false;

    m_closing = false;

    // Allocate buffers.
    m_OutBuffer.reset( new NetworkBuffer(m_OutBufferSize) );
    m_ReadBuffer.reset( new NetworkBuffer( protocol::READ_BUFFER_SIZE ) );

    // Start reading data from client
    start_async_read();

    return true;
}
Exemple #2
0
/**
 * @brief Call to process any new requests from Erlang
 *
 * @return 1 if the program should exit gracefully
 */
int erlcmd_process(struct erlcmd *handler)
{
#ifdef __WIN32__
    DWORD amount_read;
    BOOL rc = GetOverlappedResult(handler->h,
                                  &handler->overlapped,
                                  &amount_read, FALSE);

    if (!rc) {
        DWORD last_error = GetLastError();

        // Check if this was a spurious event.
        if (last_error == ERROR_IO_PENDING)
            return 0;

        // Error - most likely the Erlang port connected to us was closed.
        // Tell the caller to exit gracefully.
        return 1;
    }

    ResetEvent(handler->overlapped.hEvent);
#else
    ssize_t amount_read = read(STDIN_FILENO, handler->buffer + handler->index, sizeof(handler->buffer) - handler->index);
    if (amount_read < 0) {
        /* EINTR is ok to get, since we were interrupted by a signal. */
        if (errno == EINTR)
            return 0;

        /* Everything else is unexpected. */
        err(EXIT_FAILURE, "read");
    } else if (amount_read == 0) {
        /* EOF. Erlang process was terminated. This happens after a release or if there was an error. */
        return 1;
    }
#endif
    handler->index += amount_read;

    for (;;) {
        size_t bytes_processed = erlcmd_try_dispatch(handler);

        if (bytes_processed == 0) {
            /* Only have part of the command to process. */
            break;
        } else if (handler->index > bytes_processed) {
            /* Processed the command and there's more data. */
            memmove(handler->buffer, &handler->buffer[bytes_processed], handler->index - bytes_processed);
            handler->index -= bytes_processed;
        } else {
            /* Processed the whole buffer. */
            handler->index = 0;
            break;
        }
    }

#ifdef __WIN32__
    start_async_read(handler);
#endif

    return 0;
}
Exemple #3
0
void MClient::do_connect(tcp::resolver::iterator endpoint_iterator)
{
	boost::asio::async_connect(socket_, endpoint_iterator,
		[this](boost::system::error_code ec, tcp::resolver::iterator)
	{
		if (!ec)
		{
			start_async_read();
		}
	});
}
Exemple #4
0
void Socket::on_read_complete( const boost::system::error_code& error,
                                    size_t bytes_transferred )
{
    if( error )
    {
        OnError( error );
        return;
    }

    if( bytes_transferred > 0 )
    {
        m_ReadBuffer->wr_ptr( bytes_transferred );

        if( !process_incoming_data() )
        {
            CloseSocket();
            return;
        }
    }

    start_async_read();
}
/*
 * pjsip_udp_transport_attach()
 *
 * Attach UDP socket and start transport.
 */
static pj_status_t transport_attach( pjsip_endpoint *endpt,
				     pjsip_transport_type_e type,
				     pj_sock_t sock,
				     const pjsip_host_port *a_name,
				     unsigned async_cnt,
				     pjsip_transport **p_transport)
{
    pj_pool_t *pool;
    struct udp_transport *tp;
    const char *format, *ipv6_quoteb, *ipv6_quotee;
    unsigned i;
    pj_status_t status;

    PJ_ASSERT_RETURN(endpt && sock!=PJ_INVALID_SOCKET && a_name && async_cnt>0,
		     PJ_EINVAL);

    /* Object name. */
    if (type & PJSIP_TRANSPORT_IPV6) {
	format = "udpv6%p";
	ipv6_quoteb = "[";
	ipv6_quotee = "]";
    } else {
	format = "udp%p";
	ipv6_quoteb = ipv6_quotee = "";
    }

    /* Create pool. */
    pool = pjsip_endpt_create_pool(endpt, format, PJSIP_POOL_LEN_TRANSPORT, 
				   PJSIP_POOL_INC_TRANSPORT);
    if (!pool)
	return PJ_ENOMEM;

    /* Create the UDP transport object. */
    tp = PJ_POOL_ZALLOC_T(pool, struct udp_transport);

    /* Save pool. */
    tp->base.pool = pool;

    pj_memcpy(tp->base.obj_name, pool->obj_name, PJ_MAX_OBJ_NAME);

    /* Init reference counter. */
    status = pj_atomic_create(pool, 0, &tp->base.ref_cnt);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Init lock. */
    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, 
					    &tp->base.lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Set type. */
    tp->base.key.type = type;

    /* Remote address is left zero (except the family) */
    tp->base.key.rem_addr.addr.sa_family = (pj_uint16_t)
	((type & PJSIP_TRANSPORT_IPV6) ? pj_AF_INET6() : pj_AF_INET());

    /* Type name. */
    tp->base.type_name = "UDP";

    /* Transport flag */
    tp->base.flag = pjsip_transport_get_flag_from_type(type);


    /* Length of addressess. */
    tp->base.addr_len = sizeof(tp->base.local_addr);

    /* Init local address. */
    status = pj_sock_getsockname(sock, &tp->base.local_addr, 
				 &tp->base.addr_len);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Init remote name. */
    if (type == PJSIP_TRANSPORT_UDP)
	tp->base.remote_name.host = pj_str("0.0.0.0");
    else
	tp->base.remote_name.host = pj_str("::0");
    tp->base.remote_name.port = 0;

    /* Init direction */
    tp->base.dir = PJSIP_TP_DIR_NONE;

    /* Set endpoint. */
    tp->base.endpt = endpt;

    /* Transport manager and timer will be initialized by tpmgr */

    /* Attach socket and assign name. */
    udp_set_socket(tp, sock, a_name);

    /* Register to ioqueue */
    status = register_to_ioqueue(tp);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Set functions. */
    tp->base.send_msg = &udp_send_msg;
    tp->base.do_shutdown = &udp_shutdown;
    tp->base.destroy = &udp_destroy;

    /* This is a permanent transport, so we initialize the ref count
     * to one so that transport manager don't destroy this transport
     * when there's no user!
     */
    pj_atomic_inc(tp->base.ref_cnt);

    /* Register to transport manager. */
    tp->base.tpmgr = pjsip_endpt_get_tpmgr(endpt);
    status = pjsip_transport_register( tp->base.tpmgr, (pjsip_transport*)tp);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create rdata and put it in the array. */
    tp->rdata_cnt = 0;
    tp->rdata = (pjsip_rx_data**)
    		pj_pool_calloc(tp->base.pool, async_cnt, 
			       sizeof(pjsip_rx_data*));
    for (i=0; i<async_cnt; ++i) {
	pj_pool_t *rdata_pool = pjsip_endpt_create_pool(endpt, "rtd%p", 
							PJSIP_POOL_RDATA_LEN,
							PJSIP_POOL_RDATA_INC);
	if (!rdata_pool) {
	    pj_atomic_set(tp->base.ref_cnt, 0);
	    pjsip_transport_destroy(&tp->base);
	    return PJ_ENOMEM;
	}

	init_rdata(tp, i, rdata_pool, NULL);
	tp->rdata_cnt++;
    }

    /* Start reading the ioqueue. */
    status = start_async_read(tp);
    if (status != PJ_SUCCESS) {
	pjsip_transport_destroy(&tp->base);
	return status;
    }

    /* Done. */
    if (p_transport)
	*p_transport = &tp->base;
    
    PJ_LOG(4,(tp->base.obj_name, 
	      "SIP %s started, published address is %s%.*s%s:%d",
	      pjsip_transport_get_type_desc((pjsip_transport_type_e)tp->base.key.type),
	      ipv6_quoteb,
	      (int)tp->base.local_name.host.slen,
	      tp->base.local_name.host.ptr,
	      ipv6_quotee,
	      tp->base.local_name.port));

    return PJ_SUCCESS;

on_error:
    udp_destroy((pjsip_transport*)tp);
    return status;
}
/*
 * Restart transport.
 *
 * If option is KEEP_SOCKET, just re-activate ioqueue operation.
 *
 * If option is DESTROY_SOCKET:
 *  - if socket is specified, replace.
 *  - if socket is not specified, create and replace.
 */
PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
					        unsigned option,
						pj_sock_t sock,
						const pj_sockaddr_in *local,
						const pjsip_host_port *a_name)
{
    struct udp_transport *tp;
    pj_status_t status;

    PJ_ASSERT_RETURN(transport != NULL, PJ_EINVAL);
    /* Flag must be specified */
    PJ_ASSERT_RETURN((option & 0x03) != 0, PJ_EINVAL);

    tp = (struct udp_transport*) transport;

    if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) {
	char addr_buf[PJ_INET6_ADDRSTRLEN];
	pjsip_host_port bound_name;

	/* Request to recreate transport */

	/* Destroy existing socket, if any. */
	if (tp->key) {
	    /* This implicitly closes the socket */
	    pj_ioqueue_unregister(tp->key);
	    tp->key = NULL;
	} else {
	    /* Close socket. */
	    if (tp->sock && tp->sock != PJ_INVALID_SOCKET) {
		pj_sock_close(tp->sock);
		tp->sock = PJ_INVALID_SOCKET;
	    }
	}
	tp->sock = PJ_INVALID_SOCKET;

	/* Create the socket if it's not specified */
	if (sock == PJ_INVALID_SOCKET) {
	    status = create_socket(pj_AF_INET(), local, 
				   sizeof(pj_sockaddr_in), &sock);
	    if (status != PJ_SUCCESS)
		return status;
	}

	/* If transport published name is not specified, calculate it
	 * from the bound address.
	 */
	if (a_name == NULL) {
	    status = get_published_name(sock, addr_buf, sizeof(addr_buf),
					&bound_name);
	    if (status != PJ_SUCCESS) {
		pj_sock_close(sock);
		return status;
	    }

	    a_name = &bound_name;
	}

        /* Init local address. */
        status = pj_sock_getsockname(sock, &tp->base.local_addr, 
				     &tp->base.addr_len);
        if (status != PJ_SUCCESS) {
            pj_sock_close(sock);
            return status;
        }

	/* Assign the socket and published address to transport. */
	udp_set_socket(tp, sock, a_name);

    } else {

	/* For KEEP_SOCKET, transport must have been paused before */
	PJ_ASSERT_RETURN(tp->is_paused, PJ_EINVALIDOP);

	/* If address name is specified, update it */
	if (a_name != NULL)
	    udp_set_pub_name(tp, a_name);
    }

    /* Re-register new or existing socket to ioqueue. */
    status = register_to_ioqueue(tp);
    if (status != PJ_SUCCESS) {
	return status;
    }

    /* Restart async read operation. */
    status = start_async_read(tp);
    if (status != PJ_SUCCESS)
	return status;

    /* Everything has been set up */
    tp->is_paused = PJ_FALSE;

    PJ_LOG(4,(tp->base.obj_name, 
	      "SIP UDP transport restarted, published address is %.*s:%d",
	      (int)tp->base.local_name.host.slen,
	      tp->base.local_name.host.ptr,
	      tp->base.local_name.port));

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjsip_udp_transport_restart2(pjsip_transport *transport,
					         unsigned option,
					         pj_sock_t sock,
					         const pj_sockaddr *local,
					         const pjsip_host_port *a_name)
{
    struct udp_transport *tp;
    pj_status_t status;
    char addr[PJ_INET6_ADDRSTRLEN+10];
    int i;

    PJ_ASSERT_RETURN(transport != NULL, PJ_EINVAL);
    /* Flag must be specified */
    PJ_ASSERT_RETURN((option & 0x03) != 0, PJ_EINVAL);

    tp = (struct udp_transport*) transport;

    /* Pause the transport first, so that any active read loop spin will
     * quit as soon as possible.
     */
    tp->is_paused = PJ_TRUE;
    
    if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) {
	char addr_buf[PJ_INET6_ADDRSTRLEN];
	pjsip_host_port bound_name;

	/* Request to recreate transport */

	/* Destroy existing socket, if any. */
	if (tp->key) {
	    /* This implicitly closes the socket */
	    pj_ioqueue_unregister(tp->key);
	    tp->key = NULL;
	} else {
	    /* Close socket. */
	    if (tp->sock && tp->sock != PJ_INVALID_SOCKET) {
		pj_sock_close(tp->sock);
		tp->sock = PJ_INVALID_SOCKET;
	    }
	}
	tp->sock = PJ_INVALID_SOCKET;

	/* Create the socket if it's not specified */
	if (sock == PJ_INVALID_SOCKET) {
	    status = create_socket(local?local->addr.sa_family:pj_AF_UNSPEC(), 
				   local, local?pj_sockaddr_get_len(local):0, 
				   &sock);
	    if (status != PJ_SUCCESS)
		return status;
	}

	/* If transport published name is not specified, calculate it
	 * from the bound address.
	 */
	if (a_name == NULL) {
	    status = get_published_name(sock, addr_buf, sizeof(addr_buf),
					&bound_name);
	    if (status != PJ_SUCCESS) {
		pj_sock_close(sock);
		return status;
	    }

	    a_name = &bound_name;
	}

        /* Init local address. */
        status = pj_sock_getsockname(sock, &tp->base.local_addr, 
				     &tp->base.addr_len);
        if (status != PJ_SUCCESS) {
            pj_sock_close(sock);
            return status;
        }

	/* Assign the socket and published address to transport. */
	udp_set_socket(tp, sock, a_name);

    } else {

	/* For KEEP_SOCKET, transport must have been paused before */
	PJ_ASSERT_RETURN(tp->is_paused, PJ_EINVALIDOP);

	/* If address name is specified, update it */
	if (a_name != NULL)
	    udp_set_pub_name(tp, a_name);
    }

    /* Make sure all udp_on_read_complete() loop spin are stopped */
    do {
	pj_thread_sleep(1);
    } while (tp->read_loop_spin);

    /* Re-register new or existing socket to ioqueue. */
    status = register_to_ioqueue(tp);
    if (status != PJ_SUCCESS) {
	return status;
    }

    /* Re-init op_key. */
    for (i = 0; i < tp->rdata_cnt; ++i) {
	pj_ioqueue_op_key_init(&tp->rdata[i]->tp_info.op_key.op_key,
			       sizeof(pj_ioqueue_op_key_t));
    }

    /* Restart async read operation. */
    status = start_async_read(tp);
    if (status != PJ_SUCCESS)
	return status;

    /* Everything has been set up */
    tp->is_paused = PJ_FALSE;

    PJ_LOG(4, (tp->base.obj_name,
	       "SIP UDP transport restarted, published address is %s",
	       pj_addr_str_print(&tp->base.local_name.host,
				 tp->base.local_name.port,
				 addr, sizeof(addr), 1)));

    return PJ_SUCCESS;
}
Exemple #8
0
/**
 * Initialize an Erlang command handler.
 *
 * @param handler the structure to initialize
 * @param request_handler callback for each message received
 * @param cookie optional data to pass back to the handler
 */
void erlcmd_init(struct erlcmd *handler,
                 void (*request_handler)(const char *req, void *cookie),
                 void *cookie)
{
    memset(handler, 0, sizeof(*handler));

    handler->request_handler = request_handler;
    handler->cookie = cookie;

#ifdef __WIN32__
    handler->running = TRUE;

    char pipe_name[64];
    sprintf(pipe_name,
             "\\\\.\\Pipe\\circuits-uart.%08x",
             (unsigned int) GetCurrentProcessId());

    handler->stdin_read_pipe = CreateNamedPipeA(
                         pipe_name,
                         PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
                         PIPE_TYPE_BYTE | PIPE_WAIT,
                         1,             // Number of pipes
                         4096,          // Out buffer size
                         4096,          // In buffer size
                         120 * 1000,    // Timeout in ms
                         NULL
                         );
    if (!handler->stdin_read_pipe)
        errx(EXIT_FAILURE, "Can't create overlapped i/o stdin pipe");

    handler->stdin_write_pipe = CreateFileA(
                        pipe_name,
                        GENERIC_WRITE,
                        0,                         // No sharing
                        NULL,
                        OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL                       // Template file
                      );
    if (!handler->stdin_write_pipe)
        errx(EXIT_FAILURE, "Can't create write side of stdin pipe");

    handler->stdin_reader_thread = CreateThread(
               NULL,                   // default security attributes
               0,                      // use default stack size
               pipe_copy_thread,       // thread function name
               handler,          // argument to thread function
               0,                      // use default creation flags
               NULL);
    if (handler->stdin_reader_thread == NULL) {
        errx(EXIT_FAILURE, "CreateThread failed: %d", (int) GetLastError());
        return;
    }
    handler->h = handler->stdin_read_pipe;
    if (handler->h == INVALID_HANDLE_VALUE)
        errx(EXIT_FAILURE, "Can't open stdin %d", (int) GetLastError());

    handler->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    handler->overlapped.Offset = 0;
    handler->overlapped.OffsetHigh = 0;

    start_async_read(handler);
#endif
}