/* 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_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; }
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 resolver. */ PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf, const char *name, unsigned options, pj_timer_heap_t *timer, pj_ioqueue_t *ioqueue, pj_dns_resolver **p_resolver) { pj_pool_t *pool; pj_dns_resolver *resv; pj_ioqueue_callback socket_cb; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL); if (name == NULL) name = THIS_FILE; /* Create and initialize resolver instance */ pool = pj_pool_create(pf, name, 4000, 4000, NULL); if (!pool) return PJ_ENOMEM; /* Create pool and name */ resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver); resv->pool = pool; resv->udp_sock = PJ_INVALID_SOCKET; pj_strdup2_with_null(pool, &resv->name, name); /* Create the mutex */ status = pj_mutex_create_recursive(pool, name, &resv->mutex); if (status != PJ_SUCCESS) goto on_error; /* Timer, ioqueue, and settings */ resv->timer = timer; resv->ioqueue = ioqueue; resv->last_id = 1; pj_dns_settings_default(&resv->settings); resv->settings.options = options; /* Create the timer heap if one is not specified */ if (resv->timer == NULL) { status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer); if (status != PJ_SUCCESS) goto on_error; } /* Create the ioqueue if one is not specified */ if (resv->ioqueue == NULL) { status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue); if (status != PJ_SUCCESS) goto on_error; } /* Response cache hash table */ resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE); /* Query hash table and free list. */ resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE); resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE); pj_list_init(&resv->query_free_nodes); /* Create the UDP socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind to any address/port */ status = pj_sock_bind_in(resv->udp_sock, 0, 0); if (status != PJ_SUCCESS) goto on_error; /* Register to ioqueue */ pj_bzero(&socket_cb, sizeof(socket_cb)); socket_cb.on_read_complete = &on_read_complete; status = pj_ioqueue_register_sock(pool, resv->ioqueue, resv->udp_sock, resv, &socket_cb, &resv->udp_key); if (status != PJ_SUCCESS) goto on_error; pj_ioqueue_op_key_init(&resv->udp_op_key, sizeof(resv->udp_op_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_key, resv->udp_rx_pkt, &resv->udp_len, PJ_IOQUEUE_ALWAYS_ASYNC, &resv->udp_src_addr, &resv->udp_addr_len); if (status != PJ_EPENDING) goto on_error; /* Looks like everything is okay */ *p_resolver = resv; return PJ_SUCCESS; on_error: pj_dns_resolver_destroy(resv, PJ_FALSE); return status; }
/* 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_in 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 */ PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() && addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL); listener = (struct tcp_listener*)factory; /* Create socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) return status; /* Bind to any port */ status = pj_sock_bind_in(sock, 0, 0); if (status != PJ_SUCCESS) { pj_sock_close(sock); return status; } /* Get the local port */ addr_len = sizeof(pj_sockaddr_in); 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 */ local_addr.sin_addr.s_addr = ((pj_sockaddr_in*)&listener->factory.local_addr)->sin_addr.s_addr; /* Create the transport descriptor */ status = tcp_create(listener, NULL, sock, PJ_FALSE, &local_addr, (pj_sockaddr_in*)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, sizeof(pj_sockaddr_in)); 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(pj_sockaddr_in); if (pj_sock_getsockname(sock, &local_addr, &addr_len)==PJ_SUCCESS) { pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr; /* Some systems (like old Win32 perhaps) may not set local address * properly before socket is fully connected. */ if (tp_addr->sin_addr.s_addr != local_addr.sin_addr.s_addr && local_addr.sin_addr.s_addr != 0) { tp_addr->sin_addr.s_addr = local_addr.sin_addr.s_addr; tp_addr->sin_port = local_addr.sin_port; 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; }