From 2f268d0332d061cea83e3a3e410c4c57a1680ce4 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Sun, 4 Mar 2007 18:29:10 +0000 Subject: Fixed warnings in STUN git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1039 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/build/pjstun_srv_test.dsp | 2 +- pjlib-util/src/pjlib-util/stun_msg.c | 16 +- pjlib-util/src/pjlib-util/stun_session.c | 4 +- pjlib-util/src/pjstun-srv-test/server.c | 537 +++++++++++++++++++++++++++ pjlib-util/src/pjstun-srv-test/server_main.c | 537 --------------------------- 5 files changed, 548 insertions(+), 548 deletions(-) create mode 100644 pjlib-util/src/pjstun-srv-test/server.c delete mode 100644 pjlib-util/src/pjstun-srv-test/server_main.c diff --git a/pjlib-util/build/pjstun_srv_test.dsp b/pjlib-util/build/pjstun_srv_test.dsp index f9a8ff9d..b5926cb8 100644 --- a/pjlib-util/build/pjstun_srv_test.dsp +++ b/pjlib-util/build/pjstun_srv_test.dsp @@ -87,7 +87,7 @@ LINK32=link.exe # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File -SOURCE="..\src\pjstun-srv-test\server_main.c" +SOURCE="..\src\pjstun-srv-test\server.c" # End Source File # End Group # Begin Group "Header Files" diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c index e5accd82..19828234 100644 --- a/pjlib-util/src/pjlib-util/stun_msg.c +++ b/pjlib-util/src/pjlib-util/stun_msg.c @@ -692,7 +692,7 @@ pj_stun_msg_add_string_attr(pj_pool_t *pool, int attr_type, const pj_str_t *value) { - pj_stun_string_attr *attr; + pj_stun_string_attr *attr = NULL; pj_status_t status; status = pj_stun_string_attr_create(pool, attr_type, value, @@ -880,7 +880,7 @@ pj_stun_msg_add_uint_attr(pj_pool_t *pool, int attr_type, pj_uint32_t value) { - pj_stun_uint_attr *attr; + pj_stun_uint_attr *attr = NULL; pj_status_t status; status = pj_stun_uint_attr_create(pool, attr_type, value, &attr); @@ -979,7 +979,7 @@ pj_stun_msgint_attr_create(pj_pool_t *pool, PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool, pj_stun_msg *msg) { - pj_stun_msgint_attr *attr; + pj_stun_msgint_attr *attr = NULL; pj_status_t status; status = pj_stun_msgint_attr_create(pool, &attr); @@ -1090,7 +1090,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool, int err_code, const pj_str_t *err_reason) { - pj_stun_errcode_attr *err_attr; + pj_stun_errcode_attr *err_attr = NULL; pj_status_t status; status = pj_stun_errcode_attr_create(pool, err_code, err_reason, @@ -1214,7 +1214,7 @@ pj_stun_msg_add_unknown_attr(pj_pool_t *pool, unsigned attr_cnt, const pj_uint16_t attr_types[]) { - pj_stun_unknown_attr *attr; + pj_stun_unknown_attr *attr = NULL; pj_status_t status; status = pj_stun_unknown_attr_create(pool, attr_cnt, attr_types, &attr); @@ -1332,7 +1332,7 @@ pj_stun_msg_add_binary_attr(pj_pool_t *pool, const pj_uint8_t *data, unsigned length) { - pj_stun_binary_attr *attr; + pj_stun_binary_attr *attr = NULL; pj_status_t status; status = pj_stun_binary_attr_create(pool, attr_type, @@ -1534,7 +1534,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool, pj_stun_msg **p_response) { unsigned msg_type = req_msg->hdr.type; - pj_stun_msg *response; + pj_stun_msg *response = NULL; pj_status_t status; PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL); @@ -1881,7 +1881,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg, pj_stun_username_attr *auname = NULL; pj_stun_msgint_attr *amsgint = NULL; pj_stun_fingerprint_attr *afingerprint = NULL; - unsigned printed; + unsigned printed = 0; pj_status_t status; unsigned i; diff --git a/pjlib-util/src/pjlib-util/stun_session.c b/pjlib-util/src/pjlib-util/stun_session.c index ce30c0bb..49ae6eae 100644 --- a/pjlib-util/src/pjlib-util/stun_session.c +++ b/pjlib-util/src/pjlib-util/stun_session.c @@ -396,7 +396,7 @@ PJ_DEF(void) pj_stun_session_set_credential(pj_stun_session *sess, PJ_DEF(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess, pj_stun_tx_data **p_tdata) { - pj_stun_tx_data *tdata; + pj_stun_tx_data *tdata = NULL; pj_status_t status; PJ_ASSERT_RETURN(sess && p_tdata, PJ_EINVAL); @@ -472,7 +472,7 @@ PJ_DEF(pj_status_t) pj_stun_session_create_response( pj_stun_session *sess, pj_stun_tx_data **p_tdata) { pj_status_t status; - pj_stun_tx_data *tdata; + pj_stun_tx_data *tdata = NULL; status = create_tdata(sess, NULL, &tdata); if (status != PJ_SUCCESS) diff --git a/pjlib-util/src/pjstun-srv-test/server.c b/pjlib-util/src/pjstun-srv-test/server.c new file mode 100644 index 00000000..e4fc6d5b --- /dev/null +++ b/pjlib-util/src/pjstun-srv-test/server.c @@ -0,0 +1,537 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2005 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include +#include + + +#define THIS_FILE "server_main.c" +#define MAX_THREADS 8 +#define MAX_SERVICE 16 +#define MAX_PKT_LEN 512 + +struct service +{ + unsigned index; + pj_uint16_t port; + pj_bool_t is_stream; + pj_sock_t sock; + pj_ioqueue_key_t *key; + pj_ioqueue_op_key_t recv_opkey, + send_opkey; + + pj_stun_session *sess; + + int src_addr_len; + pj_sockaddr_in src_addr; + pj_ssize_t rx_pkt_len; + pj_uint8_t rx_pkt[MAX_PKT_LEN]; + pj_uint8_t tx_pkt[MAX_PKT_LEN]; +}; + +static struct stun_server +{ + pj_caching_pool cp; + pj_pool_t *pool; + pj_stun_endpoint *endpt; + pj_ioqueue_t *ioqueue; + pj_timer_heap_t *timer_heap; + unsigned service_cnt; + struct service services[MAX_SERVICE]; + + pj_bool_t thread_quit_flag; + unsigned thread_cnt; + pj_thread_t *threads[16]; + + +} server; + +static struct options +{ + char *realm; + char *user_name; + char *password; + char *nonce; + pj_bool_t use_fingerprint; +} o; + +static pj_status_t server_perror(const char *sender, const char *title, + pj_status_t status) +{ + char errmsg[PJ_ERR_MSG_SIZE]; + pj_strerror(status, errmsg, sizeof(errmsg)); + + PJ_LOG(3,(sender, "%s: %s", title, errmsg)); + + return status; +} + + +/* Callback to be called to send outgoing message */ +static pj_status_t on_send_msg(pj_stun_session *sess, + const void *pkt, + pj_size_t pkt_size, + const pj_sockaddr_t *dst_addr, + unsigned addr_len) +{ + struct service *svc; + pj_ssize_t length; + pj_status_t status; + + svc = (struct service*) pj_stun_session_get_user_data(sess); + + /* Send packet */ + length = pkt_size; + if (svc->is_stream) { + status = pj_ioqueue_send(svc->key, &svc->send_opkey, pkt, &length, 0); + } else { +#if 0 + pj_pool_t *pool; + char *buf; + pj_stun_msg *msg; + + pool = pj_pool_create(&server.cp.factory, "", 4000, 4000, NULL); + status = pj_stun_msg_decode(pool, pkt, pkt_size, PJ_STUN_CHECK_PACKET, &msg, NULL, NULL); + buf = pj_pool_alloc(pool, 512); + PJ_LOG(3,("", "%s", pj_stun_msg_dump(msg, buf, 512, NULL))); +#endif + status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, pkt, &length, + 0, dst_addr, addr_len); + } + + return (status == PJ_SUCCESS || status == PJ_EPENDING) ? + PJ_SUCCESS : status; +} + + +/* Handle STUN binding request */ +static pj_status_t on_rx_binding_request(pj_stun_session *sess, + const pj_uint8_t *pkt, + unsigned pkt_len, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + struct service *svc = (struct service *) pj_stun_session_get_user_data(sess); + pj_stun_tx_data *tdata; + pj_status_t status; + + /* Create response */ + status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); + if (status != PJ_SUCCESS) + return status; + + /* Create MAPPED-ADDRESS attribute */ + status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_MAPPED_ADDR, + PJ_FALSE, + src_addr, src_addr_len); + if (status != PJ_SUCCESS) { + server_perror(THIS_FILE, "Error creating response", status); + pj_stun_msg_destroy_tdata(sess, tdata); + return status; + } + + /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */ + if (msg->hdr.magic == PJ_STUN_MAGIC) { + status = + pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, + PJ_TRUE, + src_addr, src_addr_len); + if (status != PJ_SUCCESS) { + server_perror(THIS_FILE, "Error creating response", status); + pj_stun_msg_destroy_tdata(sess, tdata); + return status; + } + } + + /* Send */ + status = pj_stun_session_send_msg(sess, PJ_TRUE, + src_addr, src_addr_len, tdata); + return status; +} + + +/* Handle unknown request */ +static pj_status_t on_rx_unknown_request(pj_stun_session *sess, + const pj_uint8_t *pkt, + unsigned pkt_len, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + pj_stun_tx_data *tdata; + pj_status_t status; + + /* Create response */ + status = pj_stun_session_create_response(sess, msg, + PJ_STUN_STATUS_BAD_REQUEST, + NULL, &tdata); + if (status != PJ_SUCCESS) + return status; + + /* Send */ + status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); + return status; +} + +/* Callback to be called by STUN session on incoming STUN requests */ +static pj_status_t on_rx_request(pj_stun_session *sess, + const pj_uint8_t *pkt, + unsigned pkt_len, + const pj_stun_msg *msg, + const pj_sockaddr_t *src_addr, + unsigned src_addr_len) +{ + switch (PJ_STUN_GET_METHOD(msg->hdr.type)) { + case PJ_STUN_BINDING_METHOD: + return on_rx_binding_request(sess, pkt, pkt_len, msg, + src_addr, src_addr_len); + default: + return on_rx_unknown_request(sess, pkt, pkt_len, msg, + src_addr, src_addr_len); + } +} + + +/* Callback on ioqueue read completion */ +static void on_read_complete(pj_ioqueue_key_t *key, + pj_ioqueue_op_key_t *op_key, + pj_ssize_t bytes_read) +{ + struct service *svc = (struct service *) pj_ioqueue_get_user_data(key); + pj_status_t status; + + if (bytes_read <= 0) + goto next_read; + + /* Handle packet to session */ + status = pj_stun_session_on_rx_pkt(svc->sess, svc->rx_pkt, bytes_read, + PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, + NULL, &svc->src_addr, svc->src_addr_len); + if (status != PJ_SUCCESS) { + server_perror(THIS_FILE, "Error processing incoming packet", status); + } + +next_read: + if (bytes_read < 0) { + server_perror(THIS_FILE, "on_read_complete()", -bytes_read); + } + + svc->rx_pkt_len = sizeof(svc->rx_pkt); + svc->src_addr_len = sizeof(svc->src_addr); + + status = pj_ioqueue_recvfrom(svc->key, &svc->recv_opkey, + svc->rx_pkt, &svc->rx_pkt_len, + PJ_IOQUEUE_ALWAYS_ASYNC, + &svc->src_addr, &svc->src_addr_len); + if (status != PJ_EPENDING) + server_perror(THIS_FILE, "error starting async read", status); +} + + +static pj_status_t init_service(struct service *svc) +{ + pj_status_t status; + pj_ioqueue_callback service_callback; + pj_stun_session_cb sess_cb; + pj_sockaddr_in addr; + + status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &svc->sock); + if (status != PJ_SUCCESS) + return status; + + status = pj_sockaddr_in_init(&addr, NULL, svc->port); + if (status != PJ_SUCCESS) + goto on_error; + + status = pj_sock_bind(svc->sock, &addr, sizeof(addr)); + if (status != PJ_SUCCESS) + goto on_error; + + pj_bzero(&sess_cb, sizeof(sess_cb)); + sess_cb.on_send_msg = &on_send_msg; + sess_cb.on_rx_request = &on_rx_request; + status = pj_stun_session_create(server.endpt, "session", + &sess_cb, + o.use_fingerprint!=0, + &svc->sess); + if (status != PJ_SUCCESS) + goto on_error; + + pj_stun_session_set_user_data(svc->sess, (void*)svc); + + if (o.user_name) { + pj_stun_auth_cred cred; + + pj_bzero(&cred, sizeof(cred)); + + cred.type = PJ_STUN_AUTH_CRED_STATIC; + cred.data.static_cred.realm = pj_str(o.realm); + cred.data.static_cred.username = pj_str(o.user_name); + cred.data.static_cred.data_type = 0; + cred.data.static_cred.data = pj_str(o.password); + cred.data.static_cred.nonce = pj_str(o.nonce); + + pj_stun_session_set_credential(svc->sess, &cred); + puts("Session credential set"); + } else { + puts("Credential not set"); + } + + pj_bzero(&service_callback, sizeof(service_callback)); + service_callback.on_read_complete = &on_read_complete; + + status = pj_ioqueue_register_sock(server.pool, server.ioqueue, svc->sock, + svc, &service_callback, &svc->key); + if (status != PJ_SUCCESS) + goto on_error; + + + pj_ioqueue_op_key_init(&svc->recv_opkey, sizeof(svc->recv_opkey)); + pj_ioqueue_op_key_init(&svc->send_opkey, sizeof(svc->send_opkey)); + + on_read_complete(svc->key, &svc->recv_opkey, 0); + + PJ_LOG(4,(THIS_FILE, "Service started on port %d", svc->port)); + return PJ_SUCCESS; + +on_error: + if (svc->key != NULL) { + pj_ioqueue_unregister(svc->key); + svc->key = NULL; + svc->sock = PJ_INVALID_SOCKET; + } else if (svc->sock != 0 && svc->sock != PJ_INVALID_SOCKET) { + pj_sock_close(svc->sock); + svc->sock = PJ_INVALID_SOCKET; + } + + return status; +} + + +static int worker_thread(void *p) +{ + PJ_UNUSED_ARG(p); + + while (!server.thread_quit_flag) { + pj_time_val timeout = { 0, 50 }; + pj_timer_heap_poll(server.timer_heap, NULL); + pj_ioqueue_poll(server.ioqueue, &timeout); + } + + return 0; +} + + +pj_status_t server_init(void) +{ + pj_status_t status; + + status = pj_init(); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "pj_init() error", status); + + status = pjlib_util_init(); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "pjlib_util_init() error", status); + + pj_caching_pool_init(&server.cp, + &pj_pool_factory_default_policy, 0); + + + server.pool = pj_pool_create(&server.cp.factory, "server", 4000, 4000, + NULL); + + status = pj_ioqueue_create(server.pool, PJ_IOQUEUE_MAX_HANDLES, + &server.ioqueue); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "pj_ioqueue_create()", status); + + status = pj_timer_heap_create(server.pool, 1024, &server.timer_heap); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "Error creating timer heap", status); + + status = pj_stun_endpoint_create(&server.cp.factory, 0, + server.ioqueue, server.timer_heap, + &server.endpt); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "Error creating endpoint", status); + + server.service_cnt = 1; + server.services[0].index = 0; + server.services[0].port = PJ_STUN_PORT; + + status = init_service(&server.services[0]); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "init_service() error", status); + + return PJ_SUCCESS; +} + + +pj_status_t server_main(void) +{ +#if 0 + for (;;) { + pj_time_val timeout = { 0, 50 }; + pj_timer_heap_poll(server.timer_heap, NULL); + pj_ioqueue_poll(server.ioqueue, &timeout); + + if (kbhit() && _getch()==27) + break; + } +#else + pj_status_t status; + + status = pj_thread_create(server.pool, "stun_server", &worker_thread, NULL, + 0, 0, &server.threads[0]); + if (status != PJ_SUCCESS) + return server_perror(THIS_FILE, "create_thread() error", status); + + while (!server.thread_quit_flag) { + char line[10]; + + printf("Menu:\n" + " q Quit\n" + "Choice:"); + + fgets(line, sizeof(line), stdin); + if (line[0] == 'q') + server.thread_quit_flag = 1; + } + +#endif + + return PJ_SUCCESS; +} + + +pj_status_t server_destroy(void) +{ + unsigned i; + + for (i=0; ikey != NULL) { + pj_ioqueue_unregister(svc->key); + svc->key = NULL; + svc->sock = PJ_INVALID_SOCKET; + } else if (svc->sock != 0 && svc->sock != PJ_INVALID_SOCKET) { + pj_sock_close(svc->sock); + svc->sock = PJ_INVALID_SOCKET; + } + } + + server.thread_quit_flag = PJ_TRUE; + for (i=0; i - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include - -#include -#include - - -#define THIS_FILE "server_main.c" -#define MAX_THREADS 8 -#define MAX_SERVICE 16 -#define MAX_PKT_LEN 512 - -struct service -{ - unsigned index; - pj_uint16_t port; - pj_bool_t is_stream; - pj_sock_t sock; - pj_ioqueue_key_t *key; - pj_ioqueue_op_key_t recv_opkey, - send_opkey; - - pj_stun_session *sess; - - int src_addr_len; - pj_sockaddr_in src_addr; - pj_ssize_t rx_pkt_len; - pj_uint8_t rx_pkt[MAX_PKT_LEN]; - pj_uint8_t tx_pkt[MAX_PKT_LEN]; -}; - -static struct stun_server -{ - pj_caching_pool cp; - pj_pool_t *pool; - pj_stun_endpoint *endpt; - pj_ioqueue_t *ioqueue; - pj_timer_heap_t *timer_heap; - unsigned service_cnt; - struct service services[MAX_SERVICE]; - - pj_bool_t thread_quit_flag; - unsigned thread_cnt; - pj_thread_t *threads[16]; - - -} server; - -static struct options -{ - char *realm; - char *user_name; - char *password; - char *nonce; - pj_bool_t use_fingerprint; -} o; - -static pj_status_t server_perror(const char *sender, const char *title, - pj_status_t status) -{ - char errmsg[PJ_ERR_MSG_SIZE]; - pj_strerror(status, errmsg, sizeof(errmsg)); - - PJ_LOG(3,(sender, "%s: %s", title, errmsg)); - - return status; -} - - -/* Callback to be called to send outgoing message */ -static pj_status_t on_send_msg(pj_stun_session *sess, - const void *pkt, - pj_size_t pkt_size, - const pj_sockaddr_t *dst_addr, - unsigned addr_len) -{ - struct service *svc; - pj_ssize_t length; - pj_status_t status; - - svc = (struct service*) pj_stun_session_get_user_data(sess); - - /* Send packet */ - length = pkt_size; - if (svc->is_stream) { - status = pj_ioqueue_send(svc->key, &svc->send_opkey, pkt, &length, 0); - } else { -#if 0 - pj_pool_t *pool; - char *buf; - pj_stun_msg *msg; - - pool = pj_pool_create(&server.cp.factory, "", 4000, 4000, NULL); - status = pj_stun_msg_decode(pool, pkt, pkt_size, PJ_STUN_CHECK_PACKET, &msg, NULL, NULL); - buf = pj_pool_alloc(pool, 512); - PJ_LOG(3,("", "%s", pj_stun_msg_dump(msg, buf, 512, NULL))); -#endif - status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, pkt, &length, - 0, dst_addr, addr_len); - } - - return (status == PJ_SUCCESS || status == PJ_EPENDING) ? - PJ_SUCCESS : status; -} - - -/* Handle STUN binding request */ -static pj_status_t on_rx_binding_request(pj_stun_session *sess, - const pj_uint8_t *pkt, - unsigned pkt_len, - const pj_stun_msg *msg, - const pj_sockaddr_t *src_addr, - unsigned src_addr_len) -{ - struct service *svc = (struct service *) pj_stun_session_get_user_data(sess); - pj_stun_tx_data *tdata; - pj_status_t status; - - /* Create response */ - status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); - if (status != PJ_SUCCESS) - return status; - - /* Create MAPPED-ADDRESS attribute */ - status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_MAPPED_ADDR, - PJ_FALSE, - src_addr, src_addr_len); - if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "Error creating response", status); - pj_stun_msg_destroy_tdata(sess, tdata); - return status; - } - - /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */ - if (msg->hdr.magic == PJ_STUN_MAGIC) { - status = - pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, - PJ_TRUE, - src_addr, src_addr_len); - if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "Error creating response", status); - pj_stun_msg_destroy_tdata(sess, tdata); - return status; - } - } - - /* Send */ - status = pj_stun_session_send_msg(sess, PJ_TRUE, - src_addr, src_addr_len, tdata); - return status; -} - - -/* Handle unknown request */ -static pj_status_t on_rx_unknown_request(pj_stun_session *sess, - const pj_uint8_t *pkt, - unsigned pkt_len, - const pj_stun_msg *msg, - const pj_sockaddr_t *src_addr, - unsigned src_addr_len) -{ - pj_stun_tx_data *tdata; - pj_status_t status; - - /* Create response */ - status = pj_stun_session_create_response(sess, msg, - PJ_STUN_STATUS_BAD_REQUEST, - NULL, &tdata); - if (status != PJ_SUCCESS) - return status; - - /* Send */ - status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); - return status; -} - -/* Callback to be called by STUN session on incoming STUN requests */ -static pj_status_t on_rx_request(pj_stun_session *sess, - const pj_uint8_t *pkt, - unsigned pkt_len, - const pj_stun_msg *msg, - const pj_sockaddr_t *src_addr, - unsigned src_addr_len) -{ - switch (PJ_STUN_GET_METHOD(msg->hdr.type)) { - case PJ_STUN_BINDING_METHOD: - return on_rx_binding_request(sess, pkt, pkt_len, msg, - src_addr, src_addr_len); - default: - return on_rx_unknown_request(sess, pkt, pkt_len, msg, - src_addr, src_addr_len); - } -} - - -/* Callback on ioqueue read completion */ -static void on_read_complete(pj_ioqueue_key_t *key, - pj_ioqueue_op_key_t *op_key, - pj_ssize_t bytes_read) -{ - struct service *svc = (struct service *) pj_ioqueue_get_user_data(key); - pj_status_t status; - - if (bytes_read <= 0) - goto next_read; - - /* Handle packet to session */ - status = pj_stun_session_on_rx_pkt(svc->sess, svc->rx_pkt, bytes_read, - PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, - NULL, &svc->src_addr, svc->src_addr_len); - if (status != PJ_SUCCESS) { - server_perror(THIS_FILE, "Error processing incoming packet", status); - } - -next_read: - if (bytes_read < 0) { - server_perror(THIS_FILE, "on_read_complete()", -bytes_read); - } - - svc->rx_pkt_len = sizeof(svc->rx_pkt); - svc->src_addr_len = sizeof(svc->src_addr); - - status = pj_ioqueue_recvfrom(svc->key, &svc->recv_opkey, - svc->rx_pkt, &svc->rx_pkt_len, - PJ_IOQUEUE_ALWAYS_ASYNC, - &svc->src_addr, &svc->src_addr_len); - if (status != PJ_EPENDING) - server_perror(THIS_FILE, "error starting async read", status); -} - - -static pj_status_t init_service(struct service *svc) -{ - pj_status_t status; - pj_ioqueue_callback service_callback; - pj_stun_session_cb sess_cb; - pj_sockaddr_in addr; - - status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &svc->sock); - if (status != PJ_SUCCESS) - return status; - - status = pj_sockaddr_in_init(&addr, NULL, svc->port); - if (status != PJ_SUCCESS) - goto on_error; - - status = pj_sock_bind(svc->sock, &addr, sizeof(addr)); - if (status != PJ_SUCCESS) - goto on_error; - - pj_bzero(&sess_cb, sizeof(sess_cb)); - sess_cb.on_send_msg = &on_send_msg; - sess_cb.on_rx_request = &on_rx_request; - status = pj_stun_session_create(server.endpt, "session", - &sess_cb, - o.use_fingerprint!=0, - &svc->sess); - if (status != PJ_SUCCESS) - goto on_error; - - pj_stun_session_set_user_data(svc->sess, (void*)svc); - - if (o.user_name) { - pj_stun_auth_cred cred; - - pj_bzero(&cred, sizeof(cred)); - - cred.type = PJ_STUN_AUTH_CRED_STATIC; - cred.data.static_cred.realm = pj_str(o.realm); - cred.data.static_cred.username = pj_str(o.user_name); - cred.data.static_cred.data_type = 0; - cred.data.static_cred.data = pj_str(o.password); - cred.data.static_cred.nonce = pj_str(o.nonce); - - pj_stun_session_set_credential(svc->sess, &cred); - puts("Session credential set"); - } else { - puts("Credential not set"); - } - - pj_bzero(&service_callback, sizeof(service_callback)); - service_callback.on_read_complete = &on_read_complete; - - status = pj_ioqueue_register_sock(server.pool, server.ioqueue, svc->sock, - svc, &service_callback, &svc->key); - if (status != PJ_SUCCESS) - goto on_error; - - - pj_ioqueue_op_key_init(&svc->recv_opkey, sizeof(svc->recv_opkey)); - pj_ioqueue_op_key_init(&svc->send_opkey, sizeof(svc->send_opkey)); - - on_read_complete(svc->key, &svc->recv_opkey, 0); - - PJ_LOG(4,(THIS_FILE, "Service started on port %d", svc->port)); - return PJ_SUCCESS; - -on_error: - if (svc->key != NULL) { - pj_ioqueue_unregister(svc->key); - svc->key = NULL; - svc->sock = PJ_INVALID_SOCKET; - } else if (svc->sock != 0 && svc->sock != PJ_INVALID_SOCKET) { - pj_sock_close(svc->sock); - svc->sock = PJ_INVALID_SOCKET; - } - - return status; -} - - -static int worker_thread(void *p) -{ - PJ_UNUSED_ARG(p); - - while (!server.thread_quit_flag) { - pj_time_val timeout = { 0, 50 }; - pj_timer_heap_poll(server.timer_heap, NULL); - pj_ioqueue_poll(server.ioqueue, &timeout); - } - - return 0; -} - - -pj_status_t server_init(void) -{ - pj_status_t status; - - status = pj_init(); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "pj_init() error", status); - - status = pjlib_util_init(); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "pjlib_util_init() error", status); - - pj_caching_pool_init(&server.cp, - &pj_pool_factory_default_policy, 0); - - - server.pool = pj_pool_create(&server.cp.factory, "server", 4000, 4000, - NULL); - - status = pj_ioqueue_create(server.pool, PJ_IOQUEUE_MAX_HANDLES, - &server.ioqueue); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "pj_ioqueue_create()", status); - - status = pj_timer_heap_create(server.pool, 1024, &server.timer_heap); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "Error creating timer heap", status); - - status = pj_stun_endpoint_create(&server.cp.factory, 0, - server.ioqueue, server.timer_heap, - &server.endpt); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "Error creating endpoint", status); - - server.service_cnt = 1; - server.services[0].index = 0; - server.services[0].port = PJ_STUN_PORT; - - status = init_service(&server.services[0]); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "init_service() error", status); - - return PJ_SUCCESS; -} - - -pj_status_t server_main(void) -{ -#if 0 - for (;;) { - pj_time_val timeout = { 0, 50 }; - pj_timer_heap_poll(server.timer_heap, NULL); - pj_ioqueue_poll(server.ioqueue, &timeout); - - if (kbhit() && _getch()==27) - break; - } -#else - pj_status_t status; - - status = pj_thread_create(server.pool, "stun_server", &worker_thread, NULL, - 0, 0, &server.threads[0]); - if (status != PJ_SUCCESS) - return server_perror(THIS_FILE, "create_thread() error", status); - - while (!server.thread_quit_flag) { - char line[10]; - - printf("Menu:\n" - " q Quit\n" - "Choice:"); - - fgets(line, sizeof(line), stdin); - if (line[0] == 'q') - server.thread_quit_flag = 1; - } - -#endif - - return PJ_SUCCESS; -} - - -pj_status_t server_destroy(void) -{ - unsigned i; - - for (i=0; ikey != NULL) { - pj_ioqueue_unregister(svc->key); - svc->key = NULL; - svc->sock = PJ_INVALID_SOCKET; - } else if (svc->sock != 0 && svc->sock != PJ_INVALID_SOCKET) { - pj_sock_close(svc->sock); - svc->sock = PJ_INVALID_SOCKET; - } - } - - server.thread_quit_flag = PJ_TRUE; - for (i=0; i