/** * Create UDP stream transport. */ PJ_DEF(pj_status_t) pjmedia_transport_udp_create2(pjmedia_endpt *endpt, const char *name, const pj_str_t *addr, int port, unsigned options, pjmedia_transport **p_tp) { pjmedia_sock_info si; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && port && p_tp, PJ_EINVAL); pj_bzero(&si, sizeof(pjmedia_sock_info)); si.rtp_sock = si.rtcp_sock = PJ_INVALID_SOCKET; /* Create RTP socket */ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &si.rtp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind RTP socket */ pj_sockaddr_in_init(&si.rtp_addr_name, addr, (pj_uint16_t)port); status = pj_sock_bind(si.rtp_sock, &si.rtp_addr_name, sizeof(si.rtp_addr_name)); if (status != PJ_SUCCESS) goto on_error; /* Create RTCP socket */ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &si.rtcp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind RTCP socket */ pj_sockaddr_in_init(&si.rtcp_addr_name, addr, (pj_uint16_t)(port+1)); status = pj_sock_bind(si.rtcp_sock, &si.rtcp_addr_name, sizeof(si.rtcp_addr_name)); if (status != PJ_SUCCESS) goto on_error; /* Create UDP transport by attaching socket info */ return pjmedia_transport_udp_attach( endpt, name, &si, options, p_tp); on_error: if (si.rtp_sock != PJ_INVALID_SOCKET) pj_sock_close(si.rtp_sock); if (si.rtcp_sock != PJ_INVALID_SOCKET) pj_sock_close(si.rtcp_sock); return status; }
int main() { pj_sock_t sock; pj_sockaddr_in to_addr; char *s = "Cong hoa xa hoi chu nghia VietNam"; char buffer[100]; pj_ssize_t len; struct timeval tv_begin, tv_end, tv_diff; pj_log_set_level(3); CHECK(__FILE__, pj_init()); pj_bzero(buffer, sizeof(buffer)); CHECK_R( __FILE__, pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock) ); //udp_socket(12345, &sock); setup_addr_with_host_and_port(&to_addr, "127.0.0.1", 33333); len = strlen(s); gettimeofday(&tv_begin, NULL); pj_sock_sendto(sock, s, &len, 0, &to_addr, sizeof(to_addr)); PJ_LOG(3, (__FILE__, "Sent: %s", s)); len = 100; pj_sock_recv(sock, buffer, &len, 0); gettimeofday(&tv_end, NULL); int diff = timeval_subtract(&tv_diff, &tv_end, &tv_begin); PJ_LOG(3, (__FILE__, "Received: %s %0.2f msec", buffer, diff*1.0/1000)); pj_shutdown(); return 0; }
/* Create socket */ static pj_status_t create_socket(int af, const pj_sockaddr_t *local_a, int addr_len, pj_sock_t *p_sock) { pj_sock_t sock; pj_sockaddr_in tmp_addr; pj_status_t status; status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock); if (status != PJ_SUCCESS) return status; if (local_a == NULL) { pj_sockaddr_in_init(&tmp_addr, NULL, 0); local_a = &tmp_addr; addr_len = sizeof(tmp_addr); } status = pj_sock_bind(sock, local_a, addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } *p_sock = sock; return PJ_SUCCESS; }
/* Create socket */ static pj_status_t create_socket(int af, const pj_sockaddr_t *local_a, int addr_len, pj_sock_t *p_sock) { pj_sock_t sock; pj_sockaddr_in tmp_addr; pj_sockaddr_in6 tmp_addr6; pj_status_t status; status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock); if (status != PJ_SUCCESS) return status; if (local_a == NULL) { if (af == pj_AF_INET6()) { pj_bzero(&tmp_addr6, sizeof(tmp_addr6)); tmp_addr6.sin6_family = (pj_uint16_t)af; local_a = &tmp_addr6; addr_len = sizeof(tmp_addr6); } else { pj_sockaddr_in_init(&tmp_addr, NULL, 0); local_a = &tmp_addr; addr_len = sizeof(tmp_addr); } } status = pj_sock_bind(sock, local_a, addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } *p_sock = sock; return PJ_SUCCESS; }
static void open_udp_socket($UPROTO$_server_t *userver, char *addr, int port) { pj_sockaddr_in saddr; pj_str_t s; int optval = 1; SHOW_LOG(3, __FILE__":open_udp_socket: %s:%d\n", addr, port); // create udp socket here CHECK(__FILE__, pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &userver->fd)); #ifdef __ICS_INTEL__ // Allow socket reuse //CHECK(__FILE__, pj_sock_setsockopt(userver->fd, PJ_SOL_SOCKET, 512, &optval, sizeof(optval))); CHECK(__FILE__, pj_sock_setsockopt(userver->fd, PJ_SOL_SOCKET, PJ_SO_REUSEADDR, &optval, sizeof(optval))); #endif // bind the socket pj_bzero(&saddr, sizeof(saddr)); saddr.sin_family = PJ_AF_INET; saddr.sin_port = pj_htons(port); saddr.sin_addr = pj_inet_addr(pj_cstr(&s,addr)); /*pj_status_t status = pj_sock_bind(userver->fd, &saddr, sizeof(saddr)); if( status != 0 ) { SHOW_LOG(1, __FILE__":open_udp_socket error(%d)\n", status); exit(-1); }*/ CHECK(__FILE__, pj_sock_bind(userver->fd, &saddr, sizeof(saddr))); }
static int simple_sock_test(void) { int types[2]; pj_sock_t sock; int i; pj_status_t rc = PJ_SUCCESS; types[0] = pj_SOCK_STREAM(); types[1] = pj_SOCK_DGRAM(); PJ_LOG(3,("test", "...simple_sock_test()")); for (i=0; i<(int)(sizeof(types)/sizeof(types[0])); ++i) { rc = pj_sock_socket(pj_AF_INET(), types[i], 0, &sock); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create socket", rc); break; } else { rc = pj_sock_close(sock); if (rc != 0) { app_perror("...error: close socket", rc); break; } } } return rc; }
pj_status_t app_socket(int family, int type, int proto, int port, pj_sock_t *ptr_sock) { pj_sockaddr_in addr; pj_sock_t sock; pj_status_t rc; rc = pj_sock_socket(family, type, proto, &sock); if (rc != PJ_SUCCESS) return rc; pj_bzero(&addr, sizeof(addr)); addr.sin_family = (pj_uint16_t)family; addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0); rc = pj_sock_bind(sock, &addr, sizeof(addr)); if (rc != PJ_SUCCESS) return rc; #if PJ_HAS_TCP if (type == pj_SOCK_STREAM()) { rc = pj_sock_listen(sock, 5); if (rc != PJ_SUCCESS) return rc; } #endif *ptr_sock = sock; return PJ_SUCCESS; }
/* Get the default IP interface */ PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) { pj_sock_t fd; pj_str_t cp; pj_sockaddr a; int len; pj_uint8_t zero[64]; pj_status_t status; addr->addr.sa_family = (pj_uint16_t)af; status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd); if (status != PJ_SUCCESS) { return status; } PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sock_socket.")); if (af == PJ_AF_INET) { cp = pj_str("1.1.1.1"); } else { cp = pj_str("1::1"); } status = pj_sockaddr_init(af, &a, &cp, 53); if (status != PJ_SUCCESS) { pj_sock_close(fd); return status; } PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sockaddr_init.")); status = pj_sock_connect(fd, &a, pj_sockaddr_get_len(&a)); if (status != PJ_SUCCESS) { pj_sock_close(fd); return status; } PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sock_connect.")); len = sizeof(a); status = pj_sock_getsockname(fd, &a, &len); if (status != PJ_SUCCESS) { pj_sock_close(fd); return status; } PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sock_getsockname.")); pj_sock_close(fd); /* Check that the address returned is not zero */ pj_bzero(zero, sizeof(zero)); if (pj_memcmp(pj_sockaddr_get_addr(&a), zero, pj_sockaddr_get_addr_len(&a))==0) { PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() interface not found.")); return PJ_ENOTFOUND; } pj_sockaddr_copy_addr(addr, &a); /* Success */ return PJ_SUCCESS; }
static void open_udp_socket(response_client_t *uclient, char *server, int port) { pj_sockaddr_in *saddr; pj_str_t s; // open socket CHECK(__FILE__, pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &uclient->fd)); uclient->connect_data = malloc(sizeof(pj_sockaddr_in)); saddr = (pj_sockaddr_in *)uclient->connect_data; pj_bzero((void *)saddr, sizeof(pj_sockaddr_in)); saddr->sin_family = PJ_AF_INET; saddr->sin_port = pj_htons(port); saddr->sin_addr = pj_inet_addr(pj_cstr(&s, server)); CHECK(__FILE__,pj_sock_connect(uclient->fd, (const pj_sockaddr_t *)saddr, sizeof(pj_sockaddr_in))); }
PJ_DEF(pj_status_t) pj_activesock_create_udp( pj_pool_t *pool, const pj_sockaddr *addr, const pj_activesock_cfg *opt, pj_ioqueue_t *ioqueue, const pj_activesock_cb *cb, void *user_data, pj_activesock_t **p_asock, pj_sockaddr *bound_addr) { pj_sock_t sock_fd; pj_sockaddr default_addr; pj_status_t status; if (addr == NULL) { pj_sockaddr_init(pj_AF_INET(), &default_addr, NULL, 0); addr = &default_addr; } status = pj_sock_socket(addr->addr.sa_family, pj_SOCK_DGRAM(), 0, &sock_fd); if (status != PJ_SUCCESS) { return status; } status = pj_sock_bind(sock_fd, addr, pj_sockaddr_get_len(addr)); if (status != PJ_SUCCESS) { pj_sock_close(sock_fd); return status; } status = pj_activesock_create(pool, sock_fd, pj_SOCK_DGRAM(), opt, ioqueue, cb, user_data, p_asock); if (status != PJ_SUCCESS) { pj_sock_close(sock_fd); return status; } if (bound_addr) { int addr_len = sizeof(*bound_addr); status = pj_sock_getsockname(sock_fd, bound_addr, &addr_len); if (status != PJ_SUCCESS) { pj_activesock_close(*p_asock); return status; } } return PJ_SUCCESS; }
int CPjSSLSocket::Connect(CPjSSLSocket_cb cb, void *key, const TInetAddr &local_addr, const TInetAddr &rem_addr, const TDesC8 &servername, const TDesC8 &ciphers) { pj_status_t status; PJ_ASSERT_RETURN(state_ == SSL_STATE_NULL, PJ_EINVALIDOP); status = pj_sock_socket(rem_addr.Family(), pj_SOCK_STREAM(), 0, &sock_); if (status != PJ_SUCCESS) return status; // Apply QoS status = pj_sock_apply_qos2(sock_, qos_type_, &qos_params_, 2, THIS_FILE, NULL); RSocket &rSock = ((CPjSocket*)sock_)->Socket(); local_addr_ = local_addr; if (!local_addr_.IsUnspecified()) { TInt err = rSock.Bind(local_addr_); if (err != KErrNone) return PJ_RETURN_OS_ERROR(err); } cb_ = cb; key_ = key; rem_addr_ = rem_addr; /* Note: the following members only keep the pointer, not the data */ servername_.Set(servername); ciphers_.Set(ciphers); rSock.Connect(rem_addr_, iStatus); SetActive(); state_ = SSL_STATE_CONNECTING; rSock.LocalName(local_addr_); return PJ_EPENDING; }
/* Initialize UDP socket */ static pj_status_t init_sock(pj_dns_resolver *resv) { pj_ioqueue_callback socket_cb; pj_status_t status; /* Create the UDP socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock); if (status != PJ_SUCCESS) return status; /* Bind to any address/port */ status = pj_sock_bind_in(resv->udp_sock, 0, 0); if (status != PJ_SUCCESS) return status; /* Register to ioqueue */ pj_bzero(&socket_cb, sizeof(socket_cb)); socket_cb.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(resv->pool, resv->ioqueue, resv->udp_sock, resv, &socket_cb, &resv->udp_key); if (status != PJ_SUCCESS) return status; pj_ioqueue_op_key_init(&resv->udp_op_rx_key, sizeof(resv->udp_op_rx_key)); pj_ioqueue_op_key_init(&resv->udp_op_tx_key, sizeof(resv->udp_op_tx_key)); /* Start asynchronous read to the UDP socket */ resv->udp_len = sizeof(resv->udp_rx_pkt); resv->udp_addr_len = sizeof(resv->udp_src_addr); status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_rx_key, resv->udp_rx_pkt, &resv->udp_len, PJ_IOQUEUE_ALWAYS_ASYNC, &resv->udp_src_addr, &resv->udp_addr_len); if (status != PJ_EPENDING) return status; return PJ_SUCCESS; }
static pj_status_t get_local_interface(const pj_sockaddr *server, pj_sockaddr *local_addr) { pj_sock_t sock; pj_sockaddr tmp, local; int addr_len; pj_status_t status; status = pj_sock_socket(server->addr.sa_family, pj_SOCK_DGRAM(), 0, &sock); if (status != PJ_SUCCESS) return status; addr_len = pj_sockaddr_get_len(server); pj_sockaddr_init(server->addr.sa_family, &local, NULL, 0); status = pj_sock_bind(sock, &local, addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } status = pj_sock_connect(sock, server, addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } status = pj_sock_getsockname(sock, &tmp, &addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } pj_sockaddr_cp(local_addr, &tmp); pj_sock_close(sock); return PJ_SUCCESS; }
static pj_status_t get_local_interface(const pj_sockaddr_in *server, pj_in_addr *local_addr) { pj_sock_t sock; pj_sockaddr_in tmp; int addr_len; pj_status_t status; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock); if (status != PJ_SUCCESS) return status; status = pj_sock_bind_in(sock, 0, 0); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } status = pj_sock_connect(sock, server, sizeof(pj_sockaddr_in)); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } addr_len = sizeof(pj_sockaddr_in); status = pj_sock_getsockname(sock, &tmp, &addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } local_addr->s_addr = tmp.sin_addr.s_addr; pj_sock_close(sock); return PJ_SUCCESS; }
/* * Repeated connect/accept on the same listener socket. */ static int compliance_test_2(pj_bool_t allow_concur) { #if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0 enum { MAX_PAIR = 1, TEST_LOOP = 2 }; #else enum { MAX_PAIR = 4, TEST_LOOP = 2 }; #endif struct listener { pj_sock_t sock; pj_ioqueue_key_t *key; pj_sockaddr_in addr; int addr_len; } listener; struct server { pj_sock_t sock; pj_ioqueue_key_t *key; pj_sockaddr_in local_addr; pj_sockaddr_in rem_addr; int rem_addr_len; pj_ioqueue_op_key_t accept_op; } server[MAX_PAIR]; struct client { pj_sock_t sock; pj_ioqueue_key_t *key; } client[MAX_PAIR]; pj_pool_t *pool = NULL; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; int i, bufsize = BUF_MIN_SIZE; pj_ssize_t status; int test_loop, pending_op = 0; pj_timestamp t_elapsed; pj_str_t s; pj_status_t rc; listener.sock = PJ_INVALID_SOCKET; listener.key = NULL; for (i=0; i<MAX_PAIR; ++i) { server[i].sock = PJ_INVALID_SOCKET; server[i].key = NULL; } for (i=0; i<MAX_PAIR; ++i) { client[i].sock = PJ_INVALID_SOCKET; client[i].key = NULL; } // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Create I/O Queue. rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_create()", rc); return -10; } // Concurrency rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_set_default_concurrency()", rc); return -11; } // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Create listener socket rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &listener.sock); if (rc != PJ_SUCCESS) { app_perror("...error creating socket", rc); status=-20; goto on_error; } // Bind listener socket. pj_sockaddr_in_init(&listener.addr, 0, 0); if ((rc=pj_sock_bind(listener.sock, &listener.addr, sizeof(listener.addr))) != 0 ) { app_perror("...bind error", rc); status=-30; goto on_error; } // Get listener address. listener.addr_len = sizeof(listener.addr); rc = pj_sock_getsockname(listener.sock, &listener.addr, &listener.addr_len); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_sock_getsockname()", rc); status=-40; goto on_error; } listener.addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); // Register listener socket. rc = pj_ioqueue_register_sock(pool, ioque, listener.sock, NULL, &test_cb, &listener.key); if (rc != PJ_SUCCESS) { app_perror("...ERROR", rc); status=-50; goto on_error; } // Listener socket listen(). if (pj_sock_listen(listener.sock, 5)) { app_perror("...ERROR in pj_sock_listen()", rc); status=-60; goto on_error; } for (test_loop=0; test_loop < TEST_LOOP; ++test_loop) { // Client connect and server accept. for (i=0; i<MAX_PAIR; ++i) { rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &client[i].sock); if (rc != PJ_SUCCESS) { app_perror("...error creating socket", rc); status=-70; goto on_error; } rc = pj_ioqueue_register_sock(pool, ioque, client[i].sock, NULL, &test_cb, &client[i].key); if (rc != PJ_SUCCESS) { app_perror("...error ", rc); status=-80; goto on_error; } // Server socket accept() pj_ioqueue_op_key_init(&server[i].accept_op, sizeof(server[i].accept_op)); server[i].rem_addr_len = sizeof(pj_sockaddr_in); status = pj_ioqueue_accept(listener.key, &server[i].accept_op, &server[i].sock, &server[i].local_addr, &server[i].rem_addr, &server[i].rem_addr_len); if (status!=PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR in pj_ioqueue_accept()", rc); status=-90; goto on_error; } if (status==PJ_EPENDING) { ++pending_op; } // Client socket connect() status = pj_ioqueue_connect(client[i].key, &listener.addr, sizeof(listener.addr)); if (status!=PJ_SUCCESS && status != PJ_EPENDING) { app_perror("...ERROR in pj_ioqueue_connect()", rc); status=-100; goto on_error; } if (status==PJ_EPENDING) { ++pending_op; } } // Poll until all connected while (pending_op) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status > 0) { if (status > pending_op) { PJ_LOG(3,(THIS_FILE, "...error: pj_ioqueue_poll() returned %d " "(only expecting %d)", status, pending_op)); return -110; } pending_op -= status; if (pending_op == 0) { status = 0; } } } // There's no pending operation. // When we poll the ioqueue, there must not be events. if (pending_op == 0) { pj_time_val timeout = {1, 0}; #ifdef PJ_SYMBIAN status = pj_symbianos_poll(-1, 1000); #else status = pj_ioqueue_poll(ioque, &timeout); #endif if (status != 0) { status=-120; goto on_error; } } for (i=0; i<MAX_PAIR; ++i) { // Check server socket. if (server[i].sock == PJ_INVALID_SOCKET) { status = -130; app_perror("...accept() error", pj_get_os_error()); goto on_error; } // Check addresses if (server[i].local_addr.sin_family != pj_AF_INET() || server[i].local_addr.sin_addr.s_addr == 0 || server[i].local_addr.sin_port == 0) { app_perror("...ERROR address not set", rc); status = -140; goto on_error; } if (server[i].rem_addr.sin_family != pj_AF_INET() || server[i].rem_addr.sin_addr.s_addr == 0 || server[i].rem_addr.sin_port == 0) { app_perror("...ERROR address not set", rc); status = -150; goto on_error; } // Register newly accepted socket. rc = pj_ioqueue_register_sock(pool, ioque, server[i].sock, NULL, &test_cb, &server[i].key); if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_ioqueue_register_sock", rc); status = -160; goto on_error; } // Test send and receive. t_elapsed.u32.lo = 0; status = send_recv_test(ioque, server[i].key, client[i].key, send_buf, recv_buf, bufsize, &t_elapsed); if (status != 0) { goto on_error; } } // Success status = 0; for (i=0; i<MAX_PAIR; ++i) { if (server[i].key != NULL) { pj_ioqueue_unregister(server[i].key); server[i].key = NULL; server[i].sock = PJ_INVALID_SOCKET; } else if (server[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(server[i].sock); server[i].sock = PJ_INVALID_SOCKET; } if (client[i].key != NULL) { pj_ioqueue_unregister(client[i].key); client[i].key = NULL; client[i].sock = PJ_INVALID_SOCKET; } else if (client[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(client[i].sock); client[i].sock = PJ_INVALID_SOCKET; } } } status = 0; on_error: for (i=0; i<MAX_PAIR; ++i) { if (server[i].key != NULL) { pj_ioqueue_unregister(server[i].key); server[i].key = NULL; server[i].sock = PJ_INVALID_SOCKET; } else if (server[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(server[i].sock); server[i].sock = PJ_INVALID_SOCKET; } if (client[i].key != NULL) { pj_ioqueue_unregister(client[i].key); client[i].key = NULL; server[i].sock = PJ_INVALID_SOCKET; } else if (client[i].sock != PJ_INVALID_SOCKET) { pj_sock_close(client[i].sock); client[i].sock = PJ_INVALID_SOCKET; } } if (listener.key) { pj_ioqueue_unregister(listener.key); listener.key = NULL; } else if (listener.sock != PJ_INVALID_SOCKET) { pj_sock_close(listener.sock); listener.sock = PJ_INVALID_SOCKET; } if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release(pool); return status; }
/* * Benchmarking IOQueue */ static int bench_test(pj_bool_t allow_concur, int bufsize, int inactive_sock_count) { pj_sock_t ssock=-1, csock=-1; pj_sockaddr_in addr; pj_pool_t *pool = NULL; pj_sock_t *inactive_sock=NULL; pj_ioqueue_op_key_t *inactive_read_op; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; pj_ioqueue_key_t *skey, *ckey, *keys[SOCK_INACTIVE_MAX+2]; pj_timestamp t1, t2, t_elapsed; int rc=0, i; /* i must be signed */ pj_str_t temp; char errbuf[PJ_ERR_MSG_SIZE]; TRACE__((THIS_FILE, " bench test %d", inactive_sock_count)); // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Allocate sockets for sending and receiving. rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock); if (rc == PJ_SUCCESS) { rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock); } else csock = PJ_INVALID_SOCKET; if (rc != PJ_SUCCESS) { app_perror("...error: pj_sock_socket()", rc); goto on_error; } // Bind server socket. pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); addr.sin_port = pj_htons(PORT); if (pj_sock_bind(ssock, &addr, sizeof(addr))) goto on_error; pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES); // Create I/O Queue. rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { app_perror("...error: pj_ioqueue_create()", rc); goto on_error; } // Set concurrency rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...error: pj_ioqueue_set_default_concurrency()", rc); goto on_error; } // Allocate inactive sockets, and bind them to some arbitrary address. // Then register them to the I/O queue, and start a read operation. inactive_sock = (pj_sock_t*)pj_pool_alloc(pool, inactive_sock_count*sizeof(pj_sock_t)); inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool, inactive_sock_count*sizeof(pj_ioqueue_op_key_t)); pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); for (i=0; i<inactive_sock_count; ++i) { pj_ssize_t bytes; rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &inactive_sock[i]); if (rc != PJ_SUCCESS || inactive_sock[i] < 0) { app_perror("...error: pj_sock_socket()", rc); goto on_error; } if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) { pj_sock_close(inactive_sock[i]); inactive_sock[i] = PJ_INVALID_SOCKET; app_perror("...error: pj_sock_bind()", rc); goto on_error; } rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i], NULL, &test_cb, &keys[i]); if (rc != PJ_SUCCESS) { pj_sock_close(inactive_sock[i]); inactive_sock[i] = PJ_INVALID_SOCKET; app_perror("...error(1): pj_ioqueue_register_sock()", rc); PJ_LOG(3,(THIS_FILE, "....i=%d", i)); goto on_error; } bytes = bufsize; rc = pj_ioqueue_recv(keys[i], &inactive_read_op[i], recv_buf, &bytes, 0); if (rc != PJ_EPENDING) { pj_sock_close(inactive_sock[i]); inactive_sock[i] = PJ_INVALID_SOCKET; app_perror("...error: pj_ioqueue_read()", rc); goto on_error; } } // Register server and client socket. // We put this after inactivity socket, hopefully this can represent the // worst waiting time. rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); if (rc != PJ_SUCCESS) { app_perror("...error(2): pj_ioqueue_register_sock()", rc); goto on_error; } rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL, &test_cb, &ckey); if (rc != PJ_SUCCESS) { app_perror("...error(3): pj_ioqueue_register_sock()", rc); goto on_error; } // Set destination address to send the packet. pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT); // Test loop. t_elapsed.u64 = 0; for (i=0; i<LOOP; ++i) { pj_ssize_t bytes; pj_ioqueue_op_key_t read_op, write_op; // Randomize send buffer. pj_create_random_string(send_buf, bufsize); // Start reading on the server side. bytes = bufsize; rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0); if (rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_read()", rc); break; } // Starts send on the client side. bytes = bufsize; rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr, sizeof(addr)); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_write()", rc); break; } if (rc == PJ_SUCCESS) { if (bytes < 0) { app_perror("...error: pj_ioqueue_sendto()",(pj_status_t)-bytes); break; } } // Begin time. pj_get_timestamp(&t1); // Poll the queue until we've got completion event in the server side. callback_read_key = NULL; callback_read_size = 0; TRACE__((THIS_FILE, " waiting for key = %p", skey)); do { pj_time_val timeout = { 1, 0 }; #ifdef PJ_SYMBIAN rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout)); #else rc = pj_ioqueue_poll(ioque, &timeout); #endif TRACE__((THIS_FILE, " poll rc=%d", rc)); } while (rc >= 0 && callback_read_key != skey); // End time. pj_get_timestamp(&t2); t_elapsed.u64 += (t2.u64 - t1.u64); if (rc < 0) { app_perror(" error: pj_ioqueue_poll", -rc); break; } // Compare recv buffer with send buffer. if (callback_read_size != bufsize || pj_memcmp(send_buf, recv_buf, bufsize)) { rc = -10; PJ_LOG(3,(THIS_FILE, " error: size/buffer mismatch")); break; } // Poll until all events are exhausted, before we start the next loop. do { pj_time_val timeout = { 0, 10 }; #ifdef PJ_SYMBIAN PJ_UNUSED_ARG(timeout); rc = pj_symbianos_poll(-1, 100); #else rc = pj_ioqueue_poll(ioque, &timeout); #endif } while (rc>0); rc = 0; } // Print results if (rc == 0) { pj_timestamp tzero; pj_uint32_t usec_delay; tzero.u32.hi = tzero.u32.lo = 0; usec_delay = pj_elapsed_usec( &tzero, &t_elapsed); PJ_LOG(3, (THIS_FILE, "...%10d %15d % 9d", bufsize, inactive_sock_count, usec_delay)); } else { PJ_LOG(2, (THIS_FILE, "...ERROR rc=%d (buf:%d, fds:%d)", rc, bufsize, inactive_sock_count+2)); } // Cleaning up. for (i=inactive_sock_count-1; i>=0; --i) { pj_ioqueue_unregister(keys[i]); } pj_ioqueue_unregister(skey); pj_ioqueue_unregister(ckey); pj_ioqueue_destroy(ioque); pj_pool_release( pool); return rc; on_error: PJ_LOG(1,(THIS_FILE, "...ERROR: %s", pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)))); if (ssock) pj_sock_close(ssock); if (csock) pj_sock_close(csock); for (i=0; i<inactive_sock_count && inactive_sock && inactive_sock[i]!=PJ_INVALID_SOCKET; ++i) { pj_sock_close(inactive_sock[i]); } if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release( pool); return -1; }
/* * Testing with many handles. * This will just test registering PJ_IOQUEUE_MAX_HANDLES count * of sockets to the ioqueue. */ static int many_handles_test(pj_bool_t allow_concur) { enum { MAX = PJ_IOQUEUE_MAX_HANDLES }; pj_pool_t *pool; pj_ioqueue_t *ioqueue; pj_sock_t *sock; pj_ioqueue_key_t **key; pj_status_t rc; int count, i; /* must be signed */ PJ_LOG(3,(THIS_FILE,"...testing with so many handles")); pool = pj_pool_create(mem, NULL, 4000, 4000, NULL); if (!pool) return PJ_ENOMEM; key = (pj_ioqueue_key_t**) pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*)); sock = (pj_sock_t*) pj_pool_alloc(pool, MAX*sizeof(pj_sock_t)); /* Create IOQueue */ rc = pj_ioqueue_create(pool, MAX, &ioqueue); if (rc != PJ_SUCCESS || ioqueue == NULL) { app_perror("...error in pj_ioqueue_create", rc); return -10; } // Set concurrency rc = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur); if (rc != PJ_SUCCESS) { return -11; } /* Register as many sockets. */ for (count=0; count<MAX; ++count) { sock[count] = PJ_INVALID_SOCKET; rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[count]); if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) { PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d", count, rc)); break; } key[count] = NULL; rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count], NULL, &test_cb, &key[count]); if (rc != PJ_SUCCESS || key[count] == NULL) { PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d", count, rc)); return -30; } } /* Test complete. */ /* Now deregister and close all handles. */ /* NOTE for RTEMS: * It seems that the order of close(sock) is pretty important here. * If we close the sockets with the same order as when they were created, * RTEMS doesn't seem to reuse the sockets, thus next socket created * will have descriptor higher than the last socket created. * If we close the sockets in the reverse order, then the descriptor will * get reused. * This used to cause problem with select ioqueue, since the ioqueue * always gives FD_SETSIZE for the first select() argument. This ioqueue * behavior can be changed with setting PJ_SELECT_NEEDS_NFDS macro. */ for (i=count-1; i>=0; --i) { ///for (i=0; i<count; ++i) { rc = pj_ioqueue_unregister(key[i]); if (rc != PJ_SUCCESS) { app_perror("...error in pj_ioqueue_unregister", rc); } } rc = pj_ioqueue_destroy(ioqueue); if (rc != PJ_SUCCESS) { app_perror("...error in pj_ioqueue_destroy", rc); } pj_pool_release(pool); PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok")); return 0; }
/* * compliance_test() * To test that the basic IOQueue functionality works. It will just exchange * data between two sockets. */ static int compliance_test(pj_bool_t allow_concur) { pj_sock_t ssock=-1, csock=-1; pj_sockaddr_in addr, dst_addr; int addrlen; pj_pool_t *pool = NULL; char *send_buf, *recv_buf; pj_ioqueue_t *ioque = NULL; pj_ioqueue_key_t *skey = NULL, *ckey = NULL; pj_ioqueue_op_key_t read_op, write_op; int bufsize = BUF_MIN_SIZE; pj_ssize_t bytes; int status = -1; pj_str_t temp; pj_bool_t send_pending, recv_pending; pj_status_t rc; pj_set_os_error(PJ_SUCCESS); // Create pool. pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL); // Allocate buffers for send and receive. send_buf = (char*)pj_pool_alloc(pool, bufsize); recv_buf = (char*)pj_pool_alloc(pool, bufsize); // Allocate sockets for sending and receiving. TRACE_("creating sockets..."); rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &ssock); if (rc==PJ_SUCCESS) rc = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &csock); else csock = PJ_INVALID_SOCKET; if (rc != PJ_SUCCESS) { app_perror("...ERROR in pj_sock_socket()", rc); status=-1; goto on_error; } // Bind server socket. TRACE_("bind socket..."); pj_bzero(&addr, sizeof(addr)); addr.sin_family = pj_AF_INET(); addr.sin_port = pj_htons(PORT); if (pj_sock_bind(ssock, &addr, sizeof(addr))) { status=-10; goto on_error; } // Create I/O Queue. TRACE_("create ioqueue..."); rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque); if (rc != PJ_SUCCESS) { status=-20; goto on_error; } // Set concurrency TRACE_("set concurrency..."); rc = pj_ioqueue_set_default_concurrency(ioque, allow_concur); if (rc != PJ_SUCCESS) { status=-21; goto on_error; } // Register server and client socket. // We put this after inactivity socket, hopefully this can represent the // worst waiting time. TRACE_("registering first sockets..."); rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey); if (rc != PJ_SUCCESS) { app_perror("...error(10): ioqueue_register error", rc); status=-25; goto on_error; } TRACE_("registering second sockets..."); rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, &test_cb, &ckey); if (rc != PJ_SUCCESS) { app_perror("...error(11): ioqueue_register error", rc); status=-26; goto on_error; } // Randomize send_buf. pj_create_random_string(send_buf, bufsize); // Register reading from ioqueue. TRACE_("start recvfrom..."); pj_bzero(&addr, sizeof(addr)); addrlen = sizeof(addr); bytes = bufsize; rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0, &addr, &addrlen); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_recvfrom", rc); status=-28; goto on_error; } else if (rc == PJ_EPENDING) { recv_pending = 1; PJ_LOG(3, (THIS_FILE, "......ok: recvfrom returned pending")); } else { PJ_LOG(3, (THIS_FILE, "......error: recvfrom returned immediate ok!")); status=-29; goto on_error; } // Set destination address to send the packet. TRACE_("set destination address..."); temp = pj_str("127.0.0.1"); if ((rc=pj_sockaddr_in_init(&dst_addr, &temp, PORT)) != 0) { app_perror("...error: unable to resolve 127.0.0.1", rc); status=-290; goto on_error; } // Write must return the number of bytes. TRACE_("start sendto..."); bytes = bufsize; rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &dst_addr, sizeof(dst_addr)); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_sendto", rc); status=-30; goto on_error; } else if (rc == PJ_EPENDING) { send_pending = 1; PJ_LOG(3, (THIS_FILE, "......ok: sendto returned pending")); } else { send_pending = 0; PJ_LOG(3, (THIS_FILE, "......ok: sendto returned immediate success")); } // reset callback variables. callback_read_size = callback_write_size = 0; callback_accept_status = callback_connect_status = -2; callback_read_key = callback_write_key = callback_accept_key = callback_connect_key = NULL; callback_read_op = callback_write_op = NULL; // Poll if pending. while (send_pending || recv_pending) { int rc; pj_time_val timeout = { 5, 0 }; TRACE_("poll..."); #ifdef PJ_SYMBIAN rc = pj_symbianos_poll(-1, PJ_TIME_VAL_MSEC(timeout)); #else rc = pj_ioqueue_poll(ioque, &timeout); #endif if (rc == 0) { PJ_LOG(1,(THIS_FILE, "...ERROR: timed out...")); status=-45; goto on_error; } else if (rc < 0) { app_perror("...ERROR in ioqueue_poll()", -rc); status=-50; goto on_error; } if (callback_read_key != NULL) { if (callback_read_size != bufsize) { status=-61; goto on_error; } if (callback_read_key != skey) { status=-65; goto on_error; } if (callback_read_op != &read_op) { status=-66; goto on_error; } if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) { status=-67; goto on_error; } if (addrlen != sizeof(pj_sockaddr_in)) { status=-68; goto on_error; } if (addr.sin_family != pj_AF_INET()) { status=-69; goto on_error; } recv_pending = 0; } if (callback_write_key != NULL) { if (callback_write_size != bufsize) { status=-73; goto on_error; } if (callback_write_key != ckey) { status=-75; goto on_error; } if (callback_write_op != &write_op) { status=-76; goto on_error; } send_pending = 0; } } // Success status = 0; on_error: if (skey) pj_ioqueue_unregister(skey); else if (ssock != -1) pj_sock_close(ssock); if (ckey) pj_ioqueue_unregister(ckey); else if (csock != -1) pj_sock_close(csock); if (ioque != NULL) pj_ioqueue_destroy(ioque); pj_pool_release(pool); return status; }
static int stun_destroy_test(void) { enum { LOOP = 500 }; struct stun_test_session test_sess; pj_sockaddr bind_addr; int addr_len; pj_caching_pool cp; pj_pool_t *pool; unsigned i; pj_status_t status; int rc = 0; PJ_LOG(3,(THIS_FILE, " STUN destroy concurrency test")); pj_bzero(&test_sess, sizeof(test_sess)); pj_caching_pool_init(&cp, NULL, 0); pool = pj_pool_create(&cp.factory, "testsess", 512, 512, NULL); pj_stun_config_init(&test_sess.stun_cfg, &cp.factory, 0, NULL, NULL); status = pj_timer_heap_create(pool, 1023, &test_sess.stun_cfg.timer_heap); pj_assert(status == PJ_SUCCESS); status = pj_lock_create_recursive_mutex(pool, NULL, &test_sess.lock); pj_assert(status == PJ_SUCCESS); pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, PJ_TRUE); pj_assert(status == PJ_SUCCESS); status = pj_ioqueue_create(pool, 512, &test_sess.stun_cfg.ioqueue); pj_assert(status == PJ_SUCCESS); pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &test_sess.server_sock); pj_sockaddr_init(pj_AF_INET(), &bind_addr, NULL, 0); status = pj_sock_bind(test_sess.server_sock, &bind_addr, pj_sockaddr_get_len(&bind_addr)); pj_assert(status == PJ_SUCCESS); addr_len = sizeof(bind_addr); status = pj_sock_getsockname(test_sess.server_sock, &bind_addr, &addr_len); pj_assert(status == PJ_SUCCESS); test_sess.server_port = pj_sockaddr_get_port(&bind_addr); status = pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, &test_sess.server_event); pj_assert(status == PJ_SUCCESS); for (i=0; i<SERVER_THREAD_CNT; ++i) { status = pj_thread_create(pool, NULL, &server_thread_proc, &test_sess, 0, 0, &test_sess.server_threads[i]); pj_assert(status == PJ_SUCCESS); } for (i=0; i<WORKER_THREAD_CNT; ++i) { status = pj_thread_create(pool, NULL, &worker_thread_proc, &test_sess, 0, 0, &test_sess.worker_threads[i]); pj_assert(status == PJ_SUCCESS); } /* Test 1: Main thread calls destroy while callback is processing response */ PJ_LOG(3,(THIS_FILE, " Destroy in main thread while callback is running")); for (i=0; i<LOOP; ++i) { int sleep = pj_rand() % 5; PJ_LOG(3,(THIS_FILE, " Try %-3d of %d", i+1, LOOP)); /* Test 1: destroy at the same time when receiving response */ pj_bzero(&test_sess.param, sizeof(test_sess.param)); test_sess.param.client_sleep_after_start = 20; test_sess.param.client_sleep_before_destroy = sleep; test_sess.param.server_wait_for_event = PJ_TRUE; stun_destroy_test_session(&test_sess); PJ_LOG(3,(THIS_FILE, " stun test a: sleep delay:%d: clients with response: %d", sleep, test_sess.param.client_got_response)); /* Test 2: destroy at the same time with STUN retransmit timer */ test_sess.param.server_drop_request = PJ_TRUE; test_sess.param.client_sleep_after_start = 0; test_sess.param.client_sleep_before_destroy = PJ_STUN_RTO_VALUE; test_sess.param.server_wait_for_event = PJ_FALSE; stun_destroy_test_session(&test_sess); PJ_LOG(3,(THIS_FILE, " stun test b: retransmit concurrency")); /* Test 3: destroy at the same time with receiving response * AND STUN retransmit timer */ test_sess.param.client_got_response = 0; test_sess.param.server_drop_request = PJ_FALSE; test_sess.param.client_sleep_after_start = PJ_STUN_RTO_VALUE; test_sess.param.client_sleep_before_destroy = 0; test_sess.param.server_wait_for_event = PJ_TRUE; stun_destroy_test_session(&test_sess); PJ_LOG(3,(THIS_FILE, " stun test c: clients with response: %d", test_sess.param.client_got_response)); pj_thread_sleep(10); ice_one_conc_test(&test_sess.stun_cfg, PJ_FALSE); pj_thread_sleep(10); } /* Avoid compiler warning */ goto on_return; on_return: test_sess.thread_quit_flag = PJ_TRUE; for (i=0; i<SERVER_THREAD_CNT; ++i) { pj_thread_join(test_sess.server_threads[i]); } for (i=0; i<WORKER_THREAD_CNT; ++i) { pj_thread_join(test_sess.worker_threads[i]); } pj_event_destroy(test_sess.server_event); pj_sock_close(test_sess.server_sock); pj_ioqueue_destroy(test_sess.stun_cfg.ioqueue); pj_timer_heap_destroy(test_sess.stun_cfg.timer_heap); pj_pool_release(pool); pj_caching_pool_destroy(&cp); PJ_LOG(3,(THIS_FILE, " Done. rc=%d", rc)); return rc; }
static int run_client_test(const char *title, pj_bool_t server_responding, pj_stun_auth_type server_auth_type, pj_stun_auth_type client_auth_type, const char *realm, const char *username, const char *nonce, const char *password, pj_bool_t dummy_mi, pj_bool_t expected_error, pj_status_t expected_code, const char *expected_realm, const char *expected_nonce, int (*more_check)(void)) { pj_pool_t *pool; pj_stun_session_cb sess_cb; pj_stun_auth_cred cred; pj_stun_tx_data *tdata; pj_status_t status; int rc = 0; PJ_LOG(3,(THIS_FILE, " %s test", title)); /* Create client */ pool = pj_pool_create(mem, "client", 1000, 1000, NULL); client = PJ_POOL_ZALLOC_T(pool, struct client); client->pool = pool; client->responding = PJ_TRUE; /* Create STUN session */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_request_complete = &client_on_request_complete; sess_cb.on_send_msg = &client_send_msg; status = pj_stun_session_create(&stun_cfg, "client", &sess_cb, PJ_FALSE, NULL, &client->sess); if (status != PJ_SUCCESS) { destroy_client_server(); return -200; } /* Create semaphore */ status = pj_sem_create(pool, "client", 0, 1, &client->test_complete); if (status != PJ_SUCCESS) { destroy_client_server(); return -205; } /* Create client socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &client->sock); if (status != PJ_SUCCESS) { destroy_client_server(); return -210; } /* Bind client socket */ status = pj_sock_bind_in(client->sock, 0, 0); if (status != PJ_SUCCESS) { destroy_client_server(); return -220; } /* Create client thread */ status = pj_thread_create(pool, "client", &client_thread, NULL, 0, 0, &client->thread); if (status != PJ_SUCCESS) { destroy_client_server(); return -230; } /* Initialize credential */ pj_bzero(&cred, sizeof(cred)); cred.type = PJ_STUN_AUTH_CRED_STATIC; if (realm) cred.data.static_cred.realm = pj_str((char*)realm); if (username) cred.data.static_cred.username = pj_str((char*)username); if (nonce) cred.data.static_cred.nonce = pj_str((char*)nonce); if (password) cred.data.static_cred.data = pj_str((char*)password); cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; status = pj_stun_session_set_credential(client->sess, client_auth_type, &cred); if (status != PJ_SUCCESS) { destroy_client_server(); return -240; } /* Create the server */ status = create_std_server(server_auth_type, server_responding); if (status != 0) { destroy_client_server(); return status; } /* Create request */ status = pj_stun_session_create_req(client->sess, PJ_STUN_BINDING_REQUEST, PJ_STUN_MAGIC, NULL, &tdata); if (status != PJ_SUCCESS) { destroy_client_server(); return -250; } /* Add our own attributes if client authentication is set to none */ if (client_auth_type == PJ_STUN_AUTH_NONE) { pj_str_t tmp; if (realm) pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_REALM, pj_cstr(&tmp, realm)); if (username) pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_USERNAME, pj_cstr(&tmp, username)); if (nonce) pj_stun_msg_add_string_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, nonce)); if (password) { // ignored } if (dummy_mi) { pj_stun_msgint_attr *mi; pj_stun_msgint_attr_create(tdata->pool, &mi); pj_stun_msg_add_attr(tdata->msg, &mi->hdr); } } /* Send the request */ status = pj_stun_session_send_msg(client->sess, NULL, PJ_FALSE, PJ_TRUE, &server->addr, pj_sockaddr_get_len(&server->addr), tdata); if (status != PJ_SUCCESS) { destroy_client_server(); return -270; } /* Wait until test complete */ pj_sem_wait(client->test_complete); /* Verify response */ if (expected_error) { if (expected_code != client->response_status) { char e1[PJ_ERR_MSG_SIZE], e2[PJ_ERR_MSG_SIZE]; pj_strerror(expected_code, e1, sizeof(e1)); pj_strerror(client->response_status, e2, sizeof(e2)); PJ_LOG(3,(THIS_FILE, " err: expecting %d (%s) but got %d (%s) response", expected_code, e1, client->response_status, e2)); rc = -500; } } else { int res_code = 0; pj_stun_realm_attr *arealm; pj_stun_nonce_attr *anonce; if (client->response_status != 0) { PJ_LOG(3,(THIS_FILE, " err: expecting successful operation but got error %d", client->response_status)); rc = -600; goto done; } if (PJ_STUN_IS_ERROR_RESPONSE(client->response->hdr.type)) { pj_stun_errcode_attr *aerr = NULL; aerr = (pj_stun_errcode_attr*) pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_ERROR_CODE, 0); if (aerr == NULL) { PJ_LOG(3,(THIS_FILE, " err: received error response without ERROR-CODE")); rc = -610; goto done; } res_code = aerr->err_code; } else { res_code = 0; } /* Check that code matches */ if (expected_code != res_code) { PJ_LOG(3,(THIS_FILE, " err: expecting response code %d but got %d", expected_code, res_code)); rc = -620; goto done; } /* Find REALM and NONCE attributes */ arealm = (pj_stun_realm_attr*) pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_REALM, 0); anonce = (pj_stun_nonce_attr*) pj_stun_msg_find_attr(client->response, PJ_STUN_ATTR_NONCE, 0); if (expected_realm) { if (arealm == NULL) { PJ_LOG(3,(THIS_FILE, " err: expecting REALM in esponse")); rc = -630; goto done; } if (pj_strcmp2(&arealm->value, expected_realm)!=0) { PJ_LOG(3,(THIS_FILE, " err: REALM mismatch in response")); rc = -640; goto done; } } else { if (arealm != NULL) { PJ_LOG(3,(THIS_FILE, " err: non expecting REALM in response")); rc = -650; goto done; } } if (expected_nonce) { if (anonce == NULL) { PJ_LOG(3,(THIS_FILE, " err: expecting NONCE in esponse")); rc = -660; goto done; } if (pj_strcmp2(&anonce->value, expected_nonce)!=0) { PJ_LOG(3,(THIS_FILE, " err: NONCE mismatch in response")); rc = -670; goto done; } } else { if (anonce != NULL) { PJ_LOG(3,(THIS_FILE, " err: non expecting NONCE in response")); rc = -680; goto done; } } } /* Our tests are okay so far. Let caller do some more tests if * it wants to. */ if (rc==0 && more_check) { rc = (*more_check)(); } done: destroy_client_server(); return rc; }
// // Create the socket. // pj_status_t create(int af, int type, int proto) { return pj_sock_socket(af, type, proto, &sock_); }
/* Raw TCP socket try to connect to SSL socket server, once * connection established, it will just do nothing, SSL socket * server should be able to close the connection after specified * timeout period (set ms_timeout to 0 to disable timer). */ static int client_non_ssl(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_ssl_sock_t *ssock_serv = NULL; pj_activesock_t *asock_cli = NULL; pj_activesock_cb asock_cb = { 0 }; pj_sock_t sock = PJ_INVALID_SOCKET; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr listen_addr; pj_ssl_cert_t *cert = NULL; pj_status_t status; pool = pj_pool_create(mem, "ssl_accept_raw_tcp", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* Set cert */ { pj_str_t tmp1, tmp2, tmp3, tmp4; status = pj_ssl_cert_load_from_files(pool, pj_strset2(&tmp1, (char*)CERT_CA_FILE), pj_strset2(&tmp2, (char*)CERT_FILE), pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), &cert); if (status != PJ_SUCCESS) { goto on_return; } } pj_ssl_sock_param_default(¶m); param.cb.on_accept_complete = &ssl_on_accept_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; pj_time_val_normalize(¶m.timeout); /* SERVER */ param.user_data = &state_serv; state_serv.pool = pool; state_serv.is_server = PJ_TRUE; state_serv.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert); if (status != PJ_SUCCESS) { goto on_return; } /* Init bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_ssl_sock_start_accept(ssock_serv, pool, &listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status != PJ_SUCCESS) { goto on_return; } /* Update listener address */ { pj_ssl_sock_info info; pj_ssl_sock_get_info(ssock_serv, &info); pj_sockaddr_cp(&listen_addr, &info.local_addr); } /* CLIENT */ state_cli.pool = pool; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) { goto on_return; } asock_cb.on_connect_complete = &asock_on_connect_complete; asock_cb.on_data_read = &asock_on_data_read; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, ioqueue, &asock_cb, &state_cli, &asock_cli); if (status != PJ_SUCCESS) { goto on_return; } status = pj_activesock_start_connect(asock_cli, pool, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status == PJ_SUCCESS) { asock_on_connect_complete(asock_cli, PJ_SUCCESS); } else if (status == PJ_EPENDING) { status = PJ_SUCCESS; } else { goto on_return; } /* Wait until everything has been sent/received or error */ while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.done) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state_serv.err || state_cli.err) { if (state_serv.err != PJ_SUCCESS) status = state_serv.err; else status = state_cli.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); on_return: if (ssock_serv) pj_ssl_sock_close(ssock_serv); if (asock_cli && !state_cli.err && !state_cli.done) pj_activesock_close(asock_cli); if (timer) pj_timer_heap_destroy(timer); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* SSL socket try to connect to raw TCP socket server, once * connection established, SSL socket will try to perform SSL * handshake. SSL client socket should be able to close the * connection after specified timeout period (set ms_timeout to * 0 to disable timer). */ static int server_non_ssl(unsigned ms_timeout) { pj_pool_t *pool = NULL; pj_ioqueue_t *ioqueue = NULL; pj_timer_heap_t *timer = NULL; pj_activesock_t *asock_serv = NULL; pj_ssl_sock_t *ssock_cli = NULL; pj_activesock_cb asock_cb = { 0 }; pj_sock_t sock = PJ_INVALID_SOCKET; pj_ssl_sock_param param; struct test_state state_serv = { 0 }; struct test_state state_cli = { 0 }; pj_sockaddr addr, listen_addr; pj_status_t status; pool = pj_pool_create(mem, "ssl_connect_raw_tcp", 256, 256, NULL); status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { goto on_return; } status = pj_timer_heap_create(pool, 4, &timer); if (status != PJ_SUCCESS) { goto on_return; } /* SERVER */ state_serv.pool = pool; state_serv.ioqueue = ioqueue; status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) { goto on_return; } /* Init bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_sock_bind(sock, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len((pj_sockaddr_t*)&listen_addr)); if (status != PJ_SUCCESS) { goto on_return; } status = pj_sock_listen(sock, PJ_SOMAXCONN); if (status != PJ_SUCCESS) { goto on_return; } asock_cb.on_accept_complete = &asock_on_accept_complete; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, ioqueue, &asock_cb, &state_serv, &asock_serv); if (status != PJ_SUCCESS) { goto on_return; } status = pj_activesock_start_accept(asock_serv, pool); if (status != PJ_SUCCESS) goto on_return; /* Update listener address */ { int addr_len; addr_len = sizeof(listen_addr); pj_sock_getsockname(sock, (pj_sockaddr_t*)&listen_addr, &addr_len); } /* CLIENT */ pj_ssl_sock_param_default(¶m); param.cb.on_connect_complete = &ssl_on_connect_complete; param.cb.on_data_read = &ssl_on_data_read; param.cb.on_data_sent = &ssl_on_data_sent; param.ioqueue = ioqueue; param.timer_heap = timer; param.timeout.sec = 0; param.timeout.msec = ms_timeout; pj_time_val_normalize(¶m.timeout); param.user_data = &state_cli; state_cli.pool = pool; state_cli.is_server = PJ_FALSE; state_cli.is_verbose = PJ_TRUE; status = pj_ssl_sock_create(pool, ¶m, &ssock_cli); if (status != PJ_SUCCESS) { goto on_return; } /* Init default bind address */ { pj_str_t tmp_st; pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0); } status = pj_ssl_sock_start_connect(ssock_cli, pool, (pj_sockaddr_t*)&addr, (pj_sockaddr_t*)&listen_addr, pj_sockaddr_get_len(&listen_addr)); if (status != PJ_EPENDING) { goto on_return; } /* Wait until everything has been sent/received or error */ while ((!state_serv.err && !state_serv.done) || (!state_cli.err && !state_cli.done)) { #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 1000); #else pj_time_val delay = {0, 100}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer, &delay); #endif } if (state_serv.err || state_cli.err) { if (state_cli.err != PJ_SUCCESS) status = state_cli.err; else status = state_serv.err; goto on_return; } PJ_LOG(3, ("", "...Done!")); on_return: if (asock_serv) pj_activesock_close(asock_serv); if (ssock_cli && !state_cli.err && !state_cli.done) pj_ssl_sock_close(ssock_cli); if (timer) pj_timer_heap_destroy(timer); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return status; }
/* * GET request scenario 2: using on_complete() to get the * complete data. Server does not reply with content-length. * Request timed out, application sets a longer timeout, then * then restart the request. */ int http_client_test2() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; pj_time_val timeout; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; pj_http_req_param_default(¶m); /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -41; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -42; #ifdef USE_LOCAL_SERVER pj_cstr(&url, "http://127.0.0.1:380"); param.timeout.sec = 0; param.timeout.msec = 2000; thread_quit = PJ_FALSE; g_server.action = ACTION_IGNORE; g_server.send_content_length = PJ_FALSE; g_server.data_size = 4173; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://www.google.com.sg"); param.timeout.sec = 0; param.timeout.msec = 50; #endif pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept", (char*)"image/gif, image/x-xbitmap, image/jpeg, " "image/pjpeg, application/x-ms-application," " application/vnd.ms-xpsdocument, " "application/xaml+xml, " "application/x-ms-xbap, " "application/x-shockwave-flash, " "application/vnd.ms-excel, " "application/vnd.ms-powerpoint, " "application/msword, */*"); pj_http_headers_add_elmt2(¶m.headers, (char*)"Accept-Language", (char*)"en-sg"); pj_http_headers_add_elmt2(¶m.headers, (char*)"User-Agent", (char*)"Mozilla/4.0 (compatible; MSIE 7.0; " "Windows NT 6.0; SLCC1; " ".NET CLR 2.0.50727; " ".NET CLR 3.0.04506)"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -43; if (pj_http_req_start(http_req)) return -45; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER g_server.action = ACTION_REPLY; #endif timeout.sec = 0; timeout.msec = 10000; pj_http_req_set_timeout(http_req, &timeout); if (pj_http_req_start(http_req)) return -47; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
/* * select_test() * * Test main entry. */ int select_test() { pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET; pj_sockaddr_in udp_addr; int status; int setcount[3]; pj_str_t s; const char data[] = "hello"; const int datalen = 5; pj_ssize_t sent, received; char buf[10]; pj_status_t rc; PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()")); // Create two UDP sockets. rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp1); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create socket", rc); status=-10; goto on_return; } rc = pj_sock_socket( pj_AF_INET(), pj_SOCK_DGRAM(), 0, &udp2); if (udp2 == PJ_INVALID_SOCKET) { app_perror("...error: unable to create socket", rc); status=-20; goto on_return; } // Bind one of the UDP socket. pj_bzero(&udp_addr, sizeof(udp_addr)); udp_addr.sin_family = pj_AF_INET(); udp_addr.sin_port = UDP_PORT; udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1")); if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) { status=-30; goto on_return; } // Send data. sent = datalen; rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr)); if (rc != PJ_SUCCESS || sent != datalen) { app_perror("...error: sendto() error", rc); status=-40; goto on_return; } // Sleep a bit. See http://trac.pjsip.org/repos/ticket/890 pj_thread_sleep(10); // Check that socket is marked as reable. // Note that select() may also report that sockets are writable. status = do_select(udp1, udp2, setcount); if (status < 0) { char errbuf[128]; pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf)); PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf)); status=-50; goto on_return; } if (status == 0) { status=-60; goto on_return; } if (setcount[READ_FDS] != 1) { status=-70; goto on_return; } if (setcount[WRITE_FDS] != 0) { if (setcount[WRITE_FDS] == 2) { PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets")); } else { status=-80; goto on_return; } } else { PJ_LOG(3,(THIS_FILE, "...info: system doesn't report writable sockets")); } if (setcount[EXCEPT_FDS] != 0) { status=-90; goto on_return; } // Read the socket to clear readable sockets. received = sizeof(buf); rc = pj_sock_recv(udp2, buf, &received, 0); if (rc != PJ_SUCCESS || received != 5) { status=-100; goto on_return; } status = 0; // Test timeout on the read part. // This won't necessarily return zero, as select() may report that // sockets are writable. setcount[0] = setcount[1] = setcount[2] = 0; status = do_select(udp1, udp2, setcount); if (status != 0 && status != setcount[WRITE_FDS]) { PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set", status)); PJ_LOG(3,(THIS_FILE, " rdset: %d, wrset: %d, exset: %d", setcount[0], setcount[1], setcount[2])); status = -110; goto on_return; } if (setcount[READ_FDS] != 0) { PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected")); status = -120; goto on_return; } status = 0; on_return: if (udp1 != PJ_INVALID_SOCKET) pj_sock_close(udp1); if (udp2 != PJ_INVALID_SOCKET) pj_sock_close(udp2); return status; }
int http_client_test_delete() { pj_str_t url; pj_http_req_callback hcb; pj_http_req_param param; char urlbuf[80]; pj_bzero(&hcb, sizeof(hcb)); hcb.on_complete = &on_complete; hcb.on_response = &on_response; /* Create pool, timer, and ioqueue */ pool = pj_pool_create(mem, NULL, 8192, 4096, NULL); if (pj_timer_heap_create(pool, 16, &timer_heap)) return -61; if (pj_ioqueue_create(pool, 16, &ioqueue)) return -62; #ifdef USE_LOCAL_SERVER thread_quit = PJ_FALSE; g_server.action = ACTION_REPLY; g_server.send_content_length = PJ_TRUE; g_server.data_size = 0; g_server.buf_size = 1024; sstatus = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &g_server.sock); if (sstatus != PJ_SUCCESS) return -41; pj_sockaddr_in_init(&addr, NULL, 0); sstatus = pj_sock_bind(g_server.sock, &addr, sizeof(addr)); if (sstatus != PJ_SUCCESS) return -43; { pj_sockaddr_in addr; int addr_len = sizeof(addr); sstatus = pj_sock_getsockname(g_server.sock, &addr, &addr_len); if (sstatus != PJ_SUCCESS) return -44; g_server.port = pj_sockaddr_in_get_port(&addr); pj_ansi_snprintf(urlbuf, sizeof(urlbuf), "http://127.0.0.1:%d/test/test2.txt", g_server.port); url = pj_str(urlbuf); } sstatus = pj_sock_listen(g_server.sock, 8); if (sstatus != PJ_SUCCESS) return -45; sstatus = pj_thread_create(pool, NULL, &server_thread, &g_server, 0, 0, &g_server.thread); if (sstatus != PJ_SUCCESS) return -47; #else pj_cstr(&url, "http://127.0.0.1:280/test/test2.txt"); #endif pj_http_req_param_default(¶m); pj_strset2(¶m.method, (char*)"DELETE"); if (pj_http_req_create(pool, &url, timer_heap, ioqueue, ¶m, &hcb, &http_req)) return -63; if (pj_http_req_start(http_req)) return -65; while (pj_http_req_is_running(http_req)) { pj_time_val delay = {0, 50}; pj_ioqueue_poll(ioqueue, &delay); pj_timer_heap_poll(timer_heap, NULL); } #ifdef USE_LOCAL_SERVER thread_quit = PJ_TRUE; pj_thread_join(g_server.thread); pj_sock_close(g_server.sock); #endif pj_http_req_destroy(http_req); pj_ioqueue_destroy(ioqueue); pj_timer_heap_destroy(timer_heap); pj_pool_release(pool); return PJ_SUCCESS; }
/* Instantiate standard server */ static int create_std_server(pj_stun_auth_type auth_type, pj_bool_t responding) { pj_pool_t *pool; pj_stun_session_cb sess_cb; pj_stun_auth_cred cred; pj_status_t status; /* Create server */ pool = pj_pool_create(mem, "server", 1000, 1000, NULL); server = PJ_POOL_ZALLOC_T(pool, struct server); server->pool = pool; server->auth_type = auth_type; server->responding = responding; /* Create STUN session */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_rx_request = &server_on_rx_request; sess_cb.on_send_msg = &server_send_msg; status = pj_stun_session_create(&stun_cfg, "server", &sess_cb, PJ_FALSE, NULL, &server->sess); if (status != PJ_SUCCESS) { destroy_server(); return -10; } /* Configure credential */ pj_bzero(&cred, sizeof(cred)); cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; cred.data.dyn_cred.get_auth = &server_get_auth; cred.data.dyn_cred.get_password = &server_get_password; cred.data.dyn_cred.verify_nonce = &server_verify_nonce; status = pj_stun_session_set_credential(server->sess, auth_type, &cred); if (status != PJ_SUCCESS) { destroy_server(); return -20; } /* Create socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &server->sock); if (status != PJ_SUCCESS) { destroy_server(); return -30; } /* Bind */ pj_sockaddr_in_init(&server->addr.ipv4, NULL, 0); status = pj_sock_bind(server->sock, &server->addr, pj_sockaddr_get_len(&server->addr)); if (status != PJ_SUCCESS) { destroy_server(); return -40; } else { /* Get the bound IP address */ int namelen = sizeof(server->addr); pj_sockaddr addr; status = pj_sock_getsockname(server->sock, &server->addr, &namelen); if (status != PJ_SUCCESS) { destroy_server(); return -43; } status = pj_gethostip(pj_AF_INET(), &addr); if (status != PJ_SUCCESS) { destroy_server(); return -45; } pj_sockaddr_copy_addr(&server->addr, &addr); } /* Create worker thread */ status = pj_thread_create(pool, "server", &server_thread, 0, 0, 0, &server->thread); if (status != PJ_SUCCESS) { destroy_server(); return -30; } return 0; }
/* * 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"); /* 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; }
/* * Create relay. */ static pj_status_t create_relay(pj_turn_srv *srv, pj_turn_allocation *alloc, const pj_stun_msg *msg, const alloc_request *req, pj_turn_relay_res *relay) { enum { RETRY = 40 }; pj_pool_t *pool = alloc->pool; int retry, retry_max, sock_type; pj_ioqueue_callback icb; int af, namelen; pj_stun_string_attr *sa; pj_status_t status; pj_bzero(relay, sizeof(*relay)); relay->allocation = alloc; relay->tp.sock = PJ_INVALID_SOCKET; /* TODO: get the requested address family from somewhere */ af = alloc->transport->listener->addr.addr.sa_family; /* Save realm */ sa = (pj_stun_string_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0); PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP); pj_strdup(pool, &relay->realm, &sa->value); /* Save username */ sa = (pj_stun_string_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP); pj_strdup(pool, &relay->user, &sa->value); /* Lifetime and timeout */ relay->lifetime = req->lifetime; pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay, &relay_timeout_cb); resched_timeout(alloc); /* Transport type */ relay->hkey.tp_type = req->tp_type; /* Create the socket */ if (req->tp_type == PJ_TURN_TP_UDP) { sock_type = pj_SOCK_DGRAM(); } else if (req->tp_type == PJ_TURN_TP_TCP) { sock_type = pj_SOCK_STREAM(); } else { pj_assert(!"Unknown transport"); return PJ_EINVALIDOP; } status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock); if (status != PJ_SUCCESS) { pj_bzero(relay, sizeof(*relay)); return status; } /* Find suitable port for this allocation */ if (req->rpp_port) { retry_max = 1; } else { retry_max = RETRY; } for (retry=0; retry<retry_max; ++retry) { pj_uint16_t port; pj_sockaddr bound_addr; pj_lock_acquire(srv->core.lock); if (req->rpp_port) { port = (pj_uint16_t) req->rpp_port; } else if (req->tp_type == PJ_TURN_TP_UDP) { port = (pj_uint16_t) srv->ports.next_udp++; if (srv->ports.next_udp > srv->ports.max_udp) srv->ports.next_udp = srv->ports.min_udp; } else if (req->tp_type == PJ_TURN_TP_TCP) { port = (pj_uint16_t) srv->ports.next_tcp++; if (srv->ports.next_tcp > srv->ports.max_tcp) srv->ports.next_tcp = srv->ports.min_tcp; } else { pj_assert(!"Invalid transport"); port = 0; } pj_lock_release(srv->core.lock); pj_sockaddr_init(af, &bound_addr, NULL, port); status = pj_sock_bind(relay->tp.sock, &bound_addr, pj_sockaddr_get_len(&bound_addr)); if (status == PJ_SUCCESS) break; } if (status != PJ_SUCCESS) { /* Unable to allocate port */ PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d", status)); pj_sock_close(relay->tp.sock); relay->tp.sock = PJ_INVALID_SOCKET; return status; } /* Init relay key */ namelen = sizeof(relay->hkey.addr); status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen); if (status != PJ_SUCCESS) { PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d", status)); pj_sock_close(relay->tp.sock); relay->tp.sock = PJ_INVALID_SOCKET; return status; } if (!pj_sockaddr_has_addr(&relay->hkey.addr)) { pj_sockaddr_copy_addr(&relay->hkey.addr, &alloc->transport->listener->addr); } if (!pj_sockaddr_has_addr(&relay->hkey.addr)) { pj_sockaddr tmp_addr; pj_gethostip(af, &tmp_addr); pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr); } /* Init ioqueue */ pj_bzero(&icb, sizeof(icb)); icb.on_read_complete = &on_rx_from_peer; status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock, relay, &icb, &relay->tp.key); if (status != PJ_SUCCESS) { PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d", status)); pj_sock_close(relay->tp.sock); relay->tp.sock = PJ_INVALID_SOCKET; return status; } /* Kick off pending read operation */ pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key)); on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0); /* Done */ return PJ_SUCCESS; }
/* This callback is called by transport manager for the TCP factory * to create outgoing transport to the specified destination. */ static pj_status_t lis_create_transport(pjsip_tpfactory *factory, pjsip_tpmgr *mgr, pjsip_endpoint *endpt, const pj_sockaddr *rem_addr, int addr_len, pjsip_transport **p_transport) { struct tcp_listener *listener; struct tcp_transport *tcp; pj_sock_t sock; pj_sockaddr local_addr; pj_status_t status; /* Sanity checks */ PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr && addr_len && p_transport, PJ_EINVAL); /* Check that address is a sockaddr_in or sockaddr_in6*/ PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() && addr_len == sizeof(pj_sockaddr_in)) || (rem_addr->addr.sa_family == pj_AF_INET6() && addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL); listener = (struct tcp_listener*)factory; /* Create socket */ status = pj_sock_socket(rem_addr->addr.sa_family, pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) return status; /* Apply QoS, if specified */ status = pj_sock_apply_qos2(sock, listener->qos_type, &listener->qos_params, 2, listener->factory.obj_name, "outgoing SIP TCP socket"); /* Bind to listener's address and any port */ pj_bzero(&local_addr, sizeof(local_addr)); pj_sockaddr_cp(&local_addr, &listener->bound_addr); pj_sockaddr_set_port(&local_addr, 0); status = pj_sock_bind(sock, &local_addr, pj_sockaddr_get_len(&local_addr)); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } /* Get the local port */ addr_len = sizeof(local_addr); status = pj_sock_getsockname(sock, &local_addr, &addr_len); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } /* Initially set the address from the listener's address */ if (!pj_sockaddr_has_addr(&local_addr)) { pj_sockaddr_copy_addr(&local_addr, &listener->factory.local_addr); } /* Create the transport descriptor */ status = tcp_create(listener, NULL, sock, PJ_FALSE, &local_addr, rem_addr, &tcp); if (status != PJ_SUCCESS) return status; /* Start asynchronous connect() operation */ tcp->has_pending_connect = PJ_TRUE; status = pj_activesock_start_connect(tcp->asock, tcp->base.pool, rem_addr, addr_len); if (status == PJ_SUCCESS) { on_connect_complete(tcp->asock, PJ_SUCCESS); } else if (status != PJ_EPENDING) { tcp_destroy(&tcp->base, status); return status; } if (tcp->has_pending_connect) { /* Update (again) local address, just in case local address currently * set is different now that asynchronous connect() is started. */ addr_len = sizeof(local_addr); if (pj_sock_getsockname(sock, &local_addr, &addr_len)==PJ_SUCCESS) { pj_sockaddr *tp_addr = &tcp->base.local_addr; /* Some systems (like old Win32 perhaps) may not set local address * properly before socket is fully connected. */ if (pj_sockaddr_cmp(tp_addr, &local_addr) && pj_sockaddr_get_port(&local_addr) != 0) { pj_sockaddr_cp(tp_addr, &local_addr); sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name, &local_addr); } } PJ_LOG(4,(tcp->base.obj_name, "TCP transport %.*s:%d is connecting to %.*s:%d...", (int)tcp->base.local_name.host.slen, tcp->base.local_name.host.ptr, tcp->base.local_name.port, (int)tcp->base.remote_name.host.slen, tcp->base.remote_name.host.ptr, tcp->base.remote_name.port)); } /* Done */ *p_transport = &tcp->base; return PJ_SUCCESS; }