/* * Bind socket. */ PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, const pj_sockaddr_t *addr, int len) { PJ_CHECK_STACK(); PJ_ASSERT_RETURN(addr && len >= (int)sizeof(struct sockaddr_in), PJ_EINVAL); CHECK_ADDR_LEN(addr, len); pj_int32_t val = 1; int rc = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &val, sizeof(val)); if (rc != 0) return rc; if (bind(sock, (struct sockaddr*)addr, len) != 0) return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); else return PJ_SUCCESS; }
/* * This is the public API to create, initialize, register, and start the * TCP listener. */ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3( pjsip_endpoint *endpt, const pjsip_tcp_transport_cfg *cfg, pjsip_tpfactory **p_factory ) { pj_pool_t *pool; pj_sock_t sock = PJ_INVALID_SOCKET; struct tcp_listener *listener; pj_activesock_cfg asock_cfg; pj_activesock_cb listener_cb; pj_sockaddr *listener_addr; int addr_len; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL); /* Verify that address given in a_name (if any) is valid */ if (cfg->addr_name.host.slen) { pj_sockaddr tmp; status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, (pj_uint16_t)cfg->addr_name.port); if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) || (cfg->af==pj_AF_INET() && tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) { /* Invalid address */ return PJ_EINVAL; } } pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT, POOL_LIS_INC); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener); listener->factory.pool = pool; listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP : PJSIP_TRANSPORT_TCP6; listener->factory.type_name = (char*) pjsip_transport_get_type_name(listener->factory.type); listener->factory.flag = pjsip_transport_get_flag_from_type(listener->factory.type); listener->qos_type = cfg->qos_type; pj_memcpy(&listener->qos_params, &cfg->qos_params, sizeof(cfg->qos_params)); pj_ansi_strcpy(listener->factory.obj_name, "tcplis"); if (listener->factory.type==PJSIP_TRANSPORT_TCP6) pj_ansi_strcat(listener->factory.obj_name, "6"); status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name, &listener->factory.lock); if (status != PJ_SUCCESS) goto on_error; /* Create socket */ status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) goto on_error; /* Apply QoS, if specified */ status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 2, listener->factory.obj_name, "SIP TCP listener socket"); /* Apply SO_REUSEADDR */ if (cfg->reuse_addr) { int enabled = 1; status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &enabled, sizeof(enabled)); if (status != PJ_SUCCESS) { PJ_PERROR(4,(listener->factory.obj_name, status, "Warning: error applying SO_REUSEADDR")); } } /* Bind address may be different than factory.local_addr because * factory.local_addr will be resolved below. */ pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr); /* Bind socket */ listener_addr = &listener->factory.local_addr; pj_sockaddr_cp(listener_addr, &cfg->bind_addr); status = pj_sock_bind(sock, listener_addr, pj_sockaddr_get_len(listener_addr)); if (status != PJ_SUCCESS) goto on_error; /* Retrieve the bound address */ addr_len = pj_sockaddr_get_len(listener_addr); status = pj_sock_getsockname(sock, listener_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; /* If published host/IP is specified, then use that address as the * listener advertised address. */ if (cfg->addr_name.host.slen) { /* Copy the address */ listener->factory.addr_name = cfg->addr_name; pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, &cfg->addr_name.host); listener->factory.addr_name.port = cfg->addr_name.port; } else { /* No published address is given, use the bound address */ /* If the address returns 0.0.0.0, use the default * interface address as the transport's address. */ if (!pj_sockaddr_has_addr(listener_addr)) { pj_sockaddr hostip; status = pj_gethostip(listener->bound_addr.addr.sa_family, &hostip); if (status != PJ_SUCCESS) goto on_error; pj_sockaddr_copy_addr(listener_addr, &hostip); } /* Save the address name */ sockaddr_to_host_port(listener->factory.pool, &listener->factory.addr_name, listener_addr); } /* If port is zero, get the bound port */ if (listener->factory.addr_name.port == 0) { listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr); } pj_ansi_snprintf(listener->factory.obj_name, sizeof(listener->factory.obj_name), "tcplis:%d", listener->factory.addr_name.port); /* Start listening to the address */ status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG); if (status != PJ_SUCCESS) goto on_error; /* Create active socket */ pj_activesock_cfg_default(&asock_cfg); if (cfg->async_cnt > MAX_ASYNC_CNT) asock_cfg.async_cnt = MAX_ASYNC_CNT; else asock_cfg.async_cnt = cfg->async_cnt; pj_bzero(&listener_cb, sizeof(listener_cb)); listener_cb.on_accept_complete = &on_accept_complete; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg, pjsip_endpt_get_ioqueue(endpt), &listener_cb, listener, &listener->asock); /* Register to transport manager */ listener->endpt = endpt; listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); listener->factory.create_transport = lis_create_transport; listener->factory.destroy = lis_destroy; listener->is_registered = PJ_TRUE; status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, &listener->factory); if (status != PJ_SUCCESS) { listener->is_registered = PJ_FALSE; goto on_error; } /* Start pending accept() operations */ status = pj_activesock_start_accept(listener->asock, pool); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4,(listener->factory.obj_name, "SIP TCP listener ready for incoming connections at %.*s:%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port)); /* Return the pointer to user */ if (p_factory) *p_factory = &listener->factory; return PJ_SUCCESS; on_error: if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET) pj_sock_close(sock); lis_destroy(&listener->factory); return status; }
pj_status_t pj_open_tcp_serverport(pj_str_t *ip, pj_uint16_t port, pj_sock_t &sock) { pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, status ); int enabled = 1; status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &enabled, sizeof(enabled)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); pj_sockaddr_in addr; status = pj_sockaddr_in_init(&addr, ip, port); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); status = pj_sock_bind(sock, &addr, pj_sockaddr_get_len(&addr)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); status = pj_sock_listen(sock, 5); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); u_long val = 1; #if defined(PJ_WIN32) && PJ_WIN32!=0 || \ defined(PJ_WIN64) && PJ_WIN64 != 0 || \ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 if (ioctlsocket(sock, FIONBIO, &val)) { #else if (ioctl(new_sock, FIONBIO, &val)) { #endif pj_sock_close(sock); return -1; } return status; } pj_status_t pj_open_tcp_clientport(pj_str_t *ip, pj_uint16_t port, pj_sock_t &sock) { pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, status ); pj_sockaddr_in addr; status = pj_sockaddr_in_init(&addr, ip, port); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); u_long val = 1; #if defined(PJ_WIN32) && PJ_WIN32!=0 || \ defined(PJ_WIN64) && PJ_WIN64 != 0 || \ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 if (ioctlsocket(sock, FIONBIO, &val)) { #else if (ioctl(new_sock, FIONBIO, &val)) { #endif pj_sock_close(sock); return -1; } status = pj_sock_connect(sock, &addr, sizeof(addr)); pj_time_val timeout = {2, 0}; // connect³¬Ê±Ê±¼ä1Ãë pj_fd_set_t rset, wset; PJ_FD_ZERO(&rset); PJ_FD_ZERO(&wset); PJ_FD_SET(sock, &rset); PJ_FD_SET(sock, &wset); int selret = pj_sock_select(sock + 1, &rset, &wset, nullptr, &timeout); switch(selret) { case -1: return PJ_EINVAL; case 0: return PJ_ETIMEDOUT; default: { if(PJ_FD_ISSET(sock, &rset) || PJ_FD_ISSET(sock, &wset)) { return PJ_SUCCESS; } else { return PJ_EINVAL; } } } return PJ_EINVAL; } pj_status_t pj_open_udp_transport(pj_str_t *ip, pj_uint16_t port, pj_sock_t &sock) { pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, status ); int enabled = 1; status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), &enabled, sizeof(enabled)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); if ( ip != nullptr && port > 0 ) { pj_sockaddr_in addr; status = pj_sockaddr_in_init(&addr, ip, port); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); status = pj_sock_bind(sock, &addr, pj_sockaddr_get_len(&addr)); RETURN_VAL_IF_FAIL( status == PJ_SUCCESS, (pj_sock_close(sock), status) ); } u_long val = 1; #if defined(PJ_WIN32) && PJ_WIN32!=0 || \ defined(PJ_WIN64) && PJ_WIN64 != 0 || \ defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0 if (ioctlsocket(sock, FIONBIO, &val)) { #else if (ioctl(new_sock, FIONBIO, &val)) { #endif pj_sock_close(sock); return -1; } return status; } pj_uint64_t pj_ntohll(pj_uint64_t netlonglong) { return ntohll(netlonglong); } pj_uint64_t pj_htonll(pj_uint64_t hostlonglong) { return htonll(hostlonglong); } static pj_oshandle_t g_log_handle; pj_status_t log_open(pj_pool_t *pool, const pj_str_t &file_name) { pj_log_set_log_func(log_writer); return pj_file_open(pool, file_name.ptr, PJ_O_WRONLY | PJ_O_APPEND, &g_log_handle); }