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; }
/** * @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; }
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(); } }); }
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; }
/** * 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 }