- Timestamp:
- Mar 1, 2007 12:08:27 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjlib-util/src/pjstun-srv-test/server_main.c
r1004 r1021 19 19 #include <pjlib-util.h> 20 20 #include <pjlib.h> 21 #include "server.h"22 21 23 22 #include <stdio.h> … … 27 26 #define THIS_FILE "server_main.c" 28 27 #define MAX_THREADS 8 29 30 struct stun_server_tag server; 31 32 33 pj_status_t server_perror(const char *sender, const char *title, 34 pj_status_t status) 28 #define MAX_SERVICE 16 29 #define MAX_PKT_LEN 512 30 31 struct service 32 { 33 unsigned index; 34 pj_uint16_t port; 35 pj_bool_t is_stream; 36 pj_sock_t sock; 37 pj_ioqueue_key_t *key; 38 pj_ioqueue_op_key_t recv_opkey, 39 send_opkey; 40 41 pj_stun_session *sess; 42 43 int src_addr_len; 44 pj_sockaddr_in src_addr; 45 pj_ssize_t rx_pkt_len; 46 pj_uint8_t rx_pkt[MAX_PKT_LEN]; 47 pj_uint8_t tx_pkt[MAX_PKT_LEN]; 48 }; 49 50 static struct stun_server 51 { 52 pj_caching_pool cp; 53 pj_pool_t *pool; 54 pj_stun_endpoint *endpt; 55 pj_ioqueue_t *ioqueue; 56 pj_timer_heap_t *timer_heap; 57 unsigned service_cnt; 58 struct service services[MAX_SERVICE]; 59 60 pj_bool_t thread_quit_flag; 61 unsigned thread_cnt; 62 pj_thread_t *threads[16]; 63 64 } server; 65 66 67 static pj_status_t server_perror(const char *sender, const char *title, 68 pj_status_t status) 35 69 { 36 70 char errmsg[PJ_ERR_MSG_SIZE]; … … 43 77 44 78 45 static pj_status_t create_response(pj_pool_t *pool, 46 const pj_stun_msg *req_msg, 47 unsigned err_code, 48 unsigned uattr_cnt, 49 pj_uint16_t uattr_types[], 50 pj_stun_msg **p_response) 51 { 52 pj_uint32_t msg_type = req_msg->hdr.type; 53 pj_stun_msg *response; 54 pj_status_t status; 55 56 status = pj_stun_msg_create_response(pool, req_msg, err_code, NULL, 57 &response); 58 if (status != PJ_SUCCESS) 59 return status; 60 61 /* Add unknown_attribute attributes if err_code is 420 */ 62 if (err_code == PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE) { 63 pj_stun_unknown_attr *uattr; 64 65 status = pj_stun_unknown_attr_create(pool, uattr_cnt, uattr_types, 66 &uattr); 67 if (status != PJ_SUCCESS) 68 return status; 69 70 pj_stun_msg_add_attr(response, &uattr->hdr); 71 } 72 73 *p_response = response; 74 return PJ_SUCCESS; 75 } 76 77 78 static pj_status_t send_msg(struct service *svc, const pj_stun_msg *msg) 79 { 80 unsigned tx_pkt_len; 79 /* Callback to be called to send outgoing message */ 80 static pj_status_t on_send_msg(pj_stun_session *sess, 81 const void *pkt, 82 pj_size_t pkt_size, 83 const pj_sockaddr_t *dst_addr, 84 unsigned addr_len) 85 { 86 struct service *svc; 81 87 pj_ssize_t length; 82 88 pj_status_t status; 83 89 84 /* Print to log */ 85 PJ_LOG(4,(THIS_FILE, "TX STUN message: \n" 86 "--- begin STUN message ---\n" 87 "%s" 88 "--- end of STUN message ---\n", 89 pj_stun_msg_dump(msg, svc->tx_pkt, sizeof(svc->tx_pkt), NULL))); 90 91 /* Encode packet */ 92 tx_pkt_len = sizeof(svc->tx_pkt); 93 status = pj_stun_msg_encode(msg, svc->tx_pkt, tx_pkt_len, 0, 94 NULL, &tx_pkt_len); 95 if (status != PJ_SUCCESS) 96 return status; 97 98 length = tx_pkt_len; 90 svc = (struct service*) pj_stun_session_get_user_data(sess); 99 91 100 92 /* Send packet */ 93 length = pkt_size; 101 94 if (svc->is_stream) { 102 status = pj_ioqueue_send(svc->key, &svc->send_opkey, svc->tx_pkt, 103 &length, 0); 95 status = pj_ioqueue_send(svc->key, &svc->send_opkey, pkt, &length, 0); 104 96 } else { 105 status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, svc->tx_pkt, 106 &length, 0, &svc->src_addr, 107 svc->src_addr_len); 108 } 109 110 PJ_LOG(4,(THIS_FILE, "Sending STUN %s %s", 111 pj_stun_get_method_name(msg->hdr.type), 112 pj_stun_get_class_name(msg->hdr.type))); 97 #if 0 98 pj_pool_t *pool; 99 char *buf; 100 pj_stun_msg *msg; 101 102 pool = pj_pool_create(&server.cp.factory, "", 4000, 4000, NULL); 103 status = pj_stun_msg_decode(pool, pkt, pkt_size, PJ_STUN_CHECK_PACKET, &msg, NULL, NULL); 104 buf = pj_pool_alloc(pool, 512); 105 PJ_LOG(3,("", "%s", pj_stun_msg_dump(msg, buf, 512, NULL))); 106 #endif 107 status = pj_ioqueue_sendto(svc->key, &svc->send_opkey, pkt, &length, 108 0, dst_addr, addr_len); 109 } 113 110 114 111 return (status == PJ_SUCCESS || status == PJ_EPENDING) ? … … 117 114 118 115 119 static pj_status_t err_respond(struct service *svc, 120 pj_pool_t *pool, 121 const pj_stun_msg *req_msg, 122 unsigned err_code, 123 unsigned uattr_cnt, 124 pj_uint16_t uattr_types[]) 125 { 126 pj_stun_msg *response; 127 pj_status_t status; 128 129 /* Create the error response */ 130 status = create_response(pool, req_msg, err_code, 131 uattr_cnt, uattr_types, &response); 116 /* Handle STUN binding request */ 117 static pj_status_t on_rx_binding_request(pj_stun_session *sess, 118 const pj_uint8_t *pkt, 119 unsigned pkt_len, 120 const pj_stun_msg *msg, 121 const pj_sockaddr_t *src_addr, 122 unsigned src_addr_len) 123 { 124 struct service *svc = (struct service *) pj_stun_session_get_user_data(sess); 125 pj_stun_tx_data *tdata; 126 pj_stun_auth_policy pol; 127 pj_status_t status; 128 129 /* Create response */ 130 status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); 131 if (status != PJ_SUCCESS) 132 return status; 133 134 #if 1 135 pj_memset(&pol, 0, sizeof(pol)); 136 pol.type = PJ_STUN_POLICY_STATIC_LONG_TERM; 137 pol.user_data = NULL; 138 pol.data.static_long_term.realm = pj_str("realm"); 139 pol.data.static_long_term.username = pj_str("user"); 140 pol.data.static_long_term.password = pj_str("password"); 141 pol.data.static_long_term.nonce = pj_str("nonce"); 142 status = pj_stun_verify_credential(pkt, pkt_len, msg, &pol, tdata->pool, 143 &tdata->msg); 144 if (!tdata->msg) 145 return status; 146 #endif 147 148 /* Create MAPPED-ADDRESS attribute */ 149 status = pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, 150 PJ_STUN_ATTR_MAPPED_ADDR, 151 PJ_FALSE, 152 src_addr, src_addr_len); 132 153 if (status != PJ_SUCCESS) { 133 154 server_perror(THIS_FILE, "Error creating response", status); 155 pj_stun_msg_destroy_tdata(sess, tdata); 134 156 return status; 135 157 } 136 158 137 /* Send response */138 status = send_msg(svc, response);139 if (status != PJ_SUCCESS) {140 server_perror(THIS_FILE, "Error sending response", status);141 return status;142 }143 144 return PJ_SUCCESS;145 }146 147 148 static void handle_binding_request(struct service *svc, pj_pool_t *pool,149 const pj_stun_msg *rx_msg)150 {151 pj_stun_msg *response;152 pj_stun_generic_ip_addr_attr *m_attr;153 pj_status_t status;154 155 status = create_response(pool, rx_msg, 0, 0, NULL, &response);156 if (status != PJ_SUCCESS) {157 server_perror(THIS_FILE, "Error creating response", status);158 return;159 }160 161 /* Create MAPPED-ADDRESS attribute */162 status = pj_stun_generic_ip_addr_attr_create(pool,163 PJ_STUN_ATTR_MAPPED_ADDR,164 PJ_FALSE,165 svc->src_addr_len,166 &svc->src_addr, &m_attr);167 if (status != PJ_SUCCESS) {168 server_perror(THIS_FILE, "Error creating response", status);169 return;170 }171 pj_stun_msg_add_attr(response, &m_attr->hdr);172 173 159 /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */ 174 if ( rx_msg->hdr.magic == PJ_STUN_MAGIC) {160 if (msg->hdr.magic == PJ_STUN_MAGIC) { 175 161 status = 176 pj_stun_generic_ip_addr_attr_create(pool, 177 PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, 178 PJ_TRUE, 179 svc->src_addr_len, 180 &svc->src_addr, &m_attr); 162 pj_stun_msg_add_generic_ip_addr_attr(tdata->pool, tdata->msg, 163 PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, 164 PJ_TRUE, 165 src_addr, src_addr_len); 181 166 if (status != PJ_SUCCESS) { 182 167 server_perror(THIS_FILE, "Error creating response", status); 183 return; 168 pj_stun_msg_destroy_tdata(sess, tdata); 169 return status; 184 170 } 185 171 } 186 172 187 173 /* Send */ 188 status = send_msg(svc, response); 189 if (status != PJ_SUCCESS) 190 server_perror(THIS_FILE, "Error sending response", status); 191 } 192 193 194 static void handle_unknown_request(struct service *svc, pj_pool_t *pool, 195 pj_stun_msg *rx_msg) 196 { 197 err_respond(svc, pool, rx_msg, PJ_STUN_STATUS_BAD_REQUEST, 0, NULL); 198 } 199 200 174 status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); 175 return status; 176 } 177 178 179 /* Handle unknown request */ 180 static pj_status_t on_rx_unknown_request(pj_stun_session *sess, 181 const pj_uint8_t *pkt, 182 unsigned pkt_len, 183 const pj_stun_msg *msg, 184 const pj_sockaddr_t *src_addr, 185 unsigned src_addr_len) 186 { 187 pj_stun_tx_data *tdata; 188 pj_status_t status; 189 190 /* Create response */ 191 status = pj_stun_session_create_response(sess, msg, 192 PJ_STUN_STATUS_BAD_REQUEST, 193 NULL, &tdata); 194 if (status != PJ_SUCCESS) 195 return status; 196 197 /* Send */ 198 status = pj_stun_session_send_msg(sess, 0, src_addr, src_addr_len, tdata); 199 return status; 200 } 201 202 /* Callback to be called by STUN session on incoming STUN requests */ 203 static pj_status_t on_rx_request(pj_stun_session *sess, 204 const pj_uint8_t *pkt, 205 unsigned pkt_len, 206 const pj_stun_msg *msg, 207 const pj_sockaddr_t *src_addr, 208 unsigned src_addr_len) 209 { 210 switch (PJ_STUN_GET_METHOD(msg->hdr.type)) { 211 case PJ_STUN_BINDING_METHOD: 212 return on_rx_binding_request(sess, pkt, pkt_len, msg, 213 src_addr, src_addr_len); 214 default: 215 return on_rx_unknown_request(sess, pkt, pkt_len, msg, 216 src_addr, src_addr_len); 217 } 218 } 219 220 221 /* Callback on ioqueue read completion */ 201 222 static void on_read_complete(pj_ioqueue_key_t *key, 202 223 pj_ioqueue_op_key_t *op_key, … … 204 225 { 205 226 struct service *svc = (struct service *) pj_ioqueue_get_user_data(key); 206 pj_pool_t *pool = NULL;207 pj_stun_msg *rx_msg, *response;208 char dump[512];209 227 pj_status_t status; 210 228 … … 212 230 goto next_read; 213 231 214 pool = pj_pool_create(&server.cp.factory, "service", 4000, 4000, NULL); 215 216 rx_msg = NULL; 217 status = pj_stun_msg_decode(pool, svc->rx_pkt, bytes_read, 0, &rx_msg, 218 NULL, &response); 232 /* Handle packet to session */ 233 status = pj_stun_session_on_rx_pkt(svc->sess, svc->rx_pkt, bytes_read, 234 PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 235 NULL, &svc->src_addr, svc->src_addr_len); 219 236 if (status != PJ_SUCCESS) { 220 server_perror(THIS_FILE, "STUN msg_decode() error", status); 221 if (response) { 222 send_msg(svc, response); 223 } 224 goto next_read; 225 } 226 227 PJ_LOG(4,(THIS_FILE, "RX STUN message: \n" 228 "--- begin STUN message ---\n" 229 "%s" 230 "--- end of STUN message ---\n", 231 pj_stun_msg_dump(rx_msg, dump, sizeof(dump), NULL))); 232 233 if (PJ_STUN_IS_REQUEST(rx_msg->hdr.type)) { 234 switch (rx_msg->hdr.type) { 235 case PJ_STUN_BINDING_REQUEST: 236 handle_binding_request(svc, pool, rx_msg); 237 break; 238 default: 239 handle_unknown_request(svc, pool, rx_msg); 240 } 241 237 server_perror(THIS_FILE, "Error processing incoming packet", status); 242 238 } 243 239 244 240 next_read: 245 if (pool != NULL)246 pj_pool_release(pool);247 248 241 if (bytes_read < 0) { 249 242 server_perror(THIS_FILE, "on_read_complete()", -bytes_read); … … 266 259 pj_status_t status; 267 260 pj_ioqueue_callback service_callback; 261 pj_stun_session_cb sess_cb; 268 262 pj_sockaddr_in addr; 269 263 … … 279 273 if (status != PJ_SUCCESS) 280 274 goto on_error; 275 276 pj_bzero(&sess_cb, sizeof(sess_cb)); 277 sess_cb.on_send_msg = &on_send_msg; 278 sess_cb.on_rx_request = &on_rx_request; 279 status = pj_stun_session_create(server.endpt, "session", 280 &sess_cb, &svc->sess); 281 if (status != PJ_SUCCESS) 282 goto on_error; 283 284 pj_stun_session_set_user_data(svc->sess, (void*)svc); 281 285 282 286 pj_bzero(&service_callback, sizeof(service_callback)); … … 317 321 while (!server.thread_quit_flag) { 318 322 pj_time_val timeout = { 0, 50 }; 323 pj_timer_heap_poll(server.timer_heap, NULL); 319 324 pj_ioqueue_poll(server.ioqueue, &timeout); 320 325 } … … 347 352 if (status != PJ_SUCCESS) 348 353 return server_perror(THIS_FILE, "pj_ioqueue_create()", status); 354 355 status = pj_timer_heap_create(server.pool, 1024, &server.timer_heap); 356 if (status != PJ_SUCCESS) 357 return server_perror(THIS_FILE, "Error creating timer heap", status); 358 359 status = pj_stun_endpoint_create(&server.cp.factory, 0, 360 server.ioqueue, server.timer_heap, 361 &server.endpt); 362 if (status != PJ_SUCCESS) 363 return server_perror(THIS_FILE, "Error creating endpoint", status); 349 364 350 365 server.service_cnt = 1; … … 362 377 pj_status_t server_main(void) 363 378 { 364 #if 1379 #if 0 365 380 for (;;) { 366 381 pj_time_val timeout = { 0, 50 }; 382 pj_timer_heap_poll(server.timer_heap, NULL); 367 383 pj_ioqueue_poll(server.ioqueue, &timeout); 368 384 … … 414 430 } 415 431 432 pj_stun_session_destroy(server.services[0].sess); 433 pj_stun_endpoint_destroy(server.endpt); 416 434 pj_ioqueue_destroy(server.ioqueue); 417 435 pj_pool_release(server.pool); 436 437 pj_pool_factory_dump(&server.cp.factory, PJ_TRUE); 418 438 pj_caching_pool_destroy(&server.cp); 419 439
Note: See TracChangeset
for help on using the changeset viewer.