Ignore:
Timestamp:
Mar 1, 2007 12:08:27 AM (17 years ago)
Author:
bennylp
Message:

More work on STUN session framework

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/src/pjstun-srv-test/server_main.c

    r1004 r1021  
    1919#include <pjlib-util.h> 
    2020#include <pjlib.h> 
    21 #include "server.h" 
    2221 
    2322#include <stdio.h> 
     
    2726#define THIS_FILE       "server_main.c" 
    2827#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 
     31struct 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 
     50static 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 
     67static pj_status_t server_perror(const char *sender, const char *title,  
     68                                 pj_status_t status) 
    3569{ 
    3670    char errmsg[PJ_ERR_MSG_SIZE]; 
     
    4377 
    4478 
    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 */ 
     80static 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; 
    8187    pj_ssize_t length; 
    8288    pj_status_t status; 
    8389 
    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); 
    9991 
    10092    /* Send packet */ 
     93    length = pkt_size; 
    10194    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); 
    10496    } 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    } 
    113110 
    114111    return (status == PJ_SUCCESS || status == PJ_EPENDING) ?  
     
    117114 
    118115 
    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 */ 
     117static 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); 
    132153    if (status != PJ_SUCCESS) { 
    133154        server_perror(THIS_FILE, "Error creating response", status); 
     155        pj_stun_msg_destroy_tdata(sess, tdata); 
    134156        return status; 
    135157    } 
    136158 
    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  
    173159    /* 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) { 
    175161        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); 
    181166        if (status != PJ_SUCCESS) { 
    182167            server_perror(THIS_FILE, "Error creating response", status); 
    183             return; 
     168            pj_stun_msg_destroy_tdata(sess, tdata); 
     169            return status; 
    184170        } 
    185171    } 
    186172 
    187173    /* 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 */ 
     180static 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 */ 
     203static 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 */ 
    201222static void on_read_complete(pj_ioqueue_key_t *key,  
    202223                             pj_ioqueue_op_key_t *op_key,  
     
    204225{ 
    205226    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]; 
    209227    pj_status_t status; 
    210228 
     
    212230        goto next_read; 
    213231 
    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); 
    219236    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); 
    242238    } 
    243239 
    244240next_read: 
    245     if (pool != NULL) 
    246         pj_pool_release(pool); 
    247  
    248241    if (bytes_read < 0) { 
    249242        server_perror(THIS_FILE, "on_read_complete()", -bytes_read); 
     
    266259    pj_status_t status; 
    267260    pj_ioqueue_callback service_callback; 
     261    pj_stun_session_cb sess_cb; 
    268262    pj_sockaddr_in addr; 
    269263 
     
    279273    if (status != PJ_SUCCESS) 
    280274        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); 
    281285 
    282286    pj_bzero(&service_callback, sizeof(service_callback)); 
     
    317321    while (!server.thread_quit_flag) { 
    318322        pj_time_val timeout = { 0, 50 }; 
     323        pj_timer_heap_poll(server.timer_heap, NULL); 
    319324        pj_ioqueue_poll(server.ioqueue, &timeout); 
    320325    } 
     
    347352    if (status != PJ_SUCCESS) 
    348353        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); 
    349364 
    350365    server.service_cnt = 1; 
     
    362377pj_status_t server_main(void) 
    363378{ 
    364 #if 1 
     379#if 0 
    365380    for (;;) { 
    366381        pj_time_val timeout = { 0, 50 }; 
     382        pj_timer_heap_poll(server.timer_heap, NULL); 
    367383        pj_ioqueue_poll(server.ioqueue, &timeout); 
    368384 
     
    414430    } 
    415431 
     432    pj_stun_session_destroy(server.services[0].sess); 
     433    pj_stun_endpoint_destroy(server.endpt); 
    416434    pj_ioqueue_destroy(server.ioqueue); 
    417435    pj_pool_release(server.pool); 
     436 
     437    pj_pool_factory_dump(&server.cp.factory, PJ_TRUE); 
    418438    pj_caching_pool_destroy(&server.cp); 
    419439 
Note: See TracChangeset for help on using the changeset viewer.