Ignore:
Timestamp:
Mar 1, 2007 11:39:08 PM (17 years ago)
Author:
bennylp
Message:

More STUN work

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c

    r1008 r1030  
    2020#include <pjlib.h> 
    2121 
    22 #include <conio.h> 
    23  
    2422 
    2523#define THIS_FILE       "client_main.c" 
     24 
     25static struct global 
     26{ 
     27    pj_stun_endpoint    *endpt; 
     28    pj_pool_t           *pool; 
     29    pj_caching_pool      cp; 
     30    pj_timer_heap_t     *th; 
     31    pj_stun_session     *sess; 
     32    unsigned             sess_options; 
     33    pj_sock_t            sock; 
     34    pj_thread_t         *thread; 
     35    pj_bool_t            quit; 
     36 
     37    pj_sockaddr_in       dst_addr;  /**< destination addr */ 
     38 
     39} g; 
     40 
     41static struct options 
     42{ 
     43    char    *dst_addr; 
     44    char    *dst_port; 
     45    char    *realm; 
     46    char    *user_name; 
     47    char    *password; 
     48    pj_bool_t use_fingerprint; 
     49} o; 
    2650 
    2751 
     
    3458} 
    3559 
    36 static pj_status_t on_send_msg(pj_stun_tx_data *tdata, 
     60static pj_status_t on_send_msg(pj_stun_session *sess, 
    3761                               const void *pkt, 
    3862                               pj_size_t pkt_size, 
    39                                unsigned addr_len,  
    40                                const pj_sockaddr_t *dst_addr) 
    41 { 
    42     pj_sock_t sock; 
     63                               const pj_sockaddr_t *dst_addr, 
     64                               unsigned addr_len) 
     65{ 
    4366    pj_ssize_t len; 
    4467    pj_status_t status; 
    4568 
    46     sock = (pj_sock_t) pj_stun_session_get_user_data(tdata->sess); 
    47  
    4869    len = pkt_size; 
    49     status = pj_sock_sendto(sock, pkt, &len, 0, dst_addr, addr_len); 
     70    status = pj_sock_sendto(g.sock, pkt, &len, 0, dst_addr, addr_len); 
    5071 
    5172    if (status != PJ_SUCCESS) 
     
    5576} 
    5677 
    57 static void on_bind_response(pj_stun_session *sess,  
    58                              pj_status_t status,  
    59                              pj_stun_tx_data *request, 
    60                              const pj_stun_msg *response) 
    61 { 
    62     my_perror("on_bind_response()", status); 
    63 } 
    64  
    65 int main() 
    66 { 
    67     pj_stun_endpoint *endpt = NULL; 
    68     pj_pool_t *pool = NULL; 
    69     pj_caching_pool cp; 
    70     pj_timer_heap_t *th = NULL; 
    71     pj_stun_session *sess; 
    72     pj_sock_t sock = PJ_INVALID_SOCKET; 
     78static void on_request_complete(pj_stun_session *sess, 
     79                                pj_status_t status, 
     80                                pj_stun_tx_data *tdata, 
     81                                const pj_stun_msg *response) 
     82{ 
     83    if (status == PJ_SUCCESS) { 
     84        puts("Client transaction completes"); 
     85    } else { 
     86        my_perror("Client transaction error", status); 
     87    } 
     88} 
     89 
     90static int worker_thread(void *unused) 
     91{ 
     92    PJ_UNUSED_ARG(unused); 
     93 
     94    while (!g.quit) { 
     95        pj_time_val timeout =  {0, 50}; 
     96        pj_fd_set_t readset; 
     97        int n; 
     98 
     99        pj_timer_heap_poll(g.th, NULL); 
     100 
     101        PJ_FD_ZERO(&readset); 
     102        PJ_FD_SET(g.sock, &readset); 
     103 
     104        n = pj_sock_select(g.sock+1, &readset, NULL, NULL, &timeout); 
     105        if (n > 0) { 
     106            if (PJ_FD_ISSET(g.sock, &readset)) { 
     107                char buffer[512]; 
     108                pj_ssize_t len; 
     109                pj_sockaddr_in addr; 
     110                int addrlen; 
     111                pj_status_t rc; 
     112 
     113                len = sizeof(buffer); 
     114                addrlen = sizeof(addr); 
     115                rc = pj_sock_recvfrom(g.sock, buffer, &len, 0, &addr, &addrlen); 
     116                if (rc == PJ_SUCCESS && len > 0) { 
     117                    rc = pj_stun_session_on_rx_pkt(g.sess, buffer, len,  
     118                                                   PJ_STUN_IS_DATAGRAM|PJ_STUN_CHECK_PACKET,  
     119                                                   NULL, &addr, addrlen); 
     120                    if (rc != PJ_SUCCESS) 
     121                        my_perror("Error processing packet", rc); 
     122                } 
     123            } 
     124        } else if (n < 0) 
     125            pj_thread_sleep(50); 
     126    } 
     127 
     128    return 0; 
     129} 
     130 
     131static int init() 
     132{ 
    73133    pj_sockaddr_in addr; 
    74134    pj_stun_session_cb stun_cb; 
    75     pj_stun_tx_data *tdata; 
    76     pj_str_t s; 
    77135    pj_status_t status; 
     136 
     137    g.sock = PJ_INVALID_SOCKET; 
    78138 
    79139    status = pj_init(); 
    80140    status = pjlib_util_init(); 
    81141 
    82     pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); 
    83      
    84     pool = pj_pool_create(&cp.factory, NULL, 1000, 1000, NULL); 
    85  
    86     status = pj_timer_heap_create(pool, 1000, &th); 
    87     pj_assert(status == PJ_SUCCESS); 
    88  
    89     status = pj_stun_endpoint_create(&cp.factory, 0, NULL, th, &endpt); 
    90     pj_assert(status == PJ_SUCCESS); 
    91  
    92     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
    93     pj_assert(status == PJ_SUCCESS); 
    94  
    95     status = pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), PJ_STUN_PORT); 
     142    pj_caching_pool_init(&g.cp, &pj_pool_factory_default_policy, 0); 
     143 
     144    if (o.dst_addr) { 
     145        pj_str_t s; 
     146        pj_uint16_t port; 
     147 
     148        if (o.dst_port) 
     149            port = (pj_uint16_t) atoi(o.dst_port); 
     150        else 
     151            port = PJ_STUN_PORT; 
     152 
     153        status = pj_sockaddr_in_init(&g.dst_addr, pj_cstr(&s, o.dst_addr), port); 
     154        if (status != PJ_SUCCESS) { 
     155            my_perror("Invalid address", status); 
     156            return status; 
     157        } 
     158 
     159        printf("Destination address set to %s:%d\n", o.dst_addr, (int)port); 
     160    } else { 
     161        printf("Error: address must be specified\n"); 
     162        return PJ_EINVAL; 
     163    } 
     164 
     165    g.pool = pj_pool_create(&g.cp.factory, NULL, 1000, 1000, NULL); 
     166 
     167    status = pj_timer_heap_create(g.pool, 1000, &g.th); 
     168    pj_assert(status == PJ_SUCCESS); 
     169 
     170    status = pj_stun_endpoint_create(&g.cp.factory, 0, NULL, g.th, &g.endpt); 
     171    pj_assert(status == PJ_SUCCESS); 
     172 
     173    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &g.sock); 
     174    pj_assert(status == PJ_SUCCESS); 
     175 
     176    status = pj_sockaddr_in_init(&addr, NULL, 0); 
    96177    pj_assert(status == PJ_SUCCESS); 
    97178 
    98179    pj_memset(&stun_cb, 0, sizeof(stun_cb)); 
    99180    stun_cb.on_send_msg = &on_send_msg; 
    100     stun_cb.on_bind_response = &on_bind_response; 
    101  
    102     status = pj_stun_session_create(endpt, NULL, &stun_cb, &sess); 
    103     pj_assert(status == PJ_SUCCESS); 
    104  
    105     pj_stun_session_set_user_data(sess, (void*)sock); 
    106  
    107     status = pj_stun_session_create_bind_req(sess, &tdata); 
    108     pj_assert(status == PJ_SUCCESS); 
    109  
    110     status = pj_stun_session_send_msg(sess, 0, sizeof(addr), &addr, tdata); 
    111     pj_assert(status == PJ_SUCCESS); 
    112  
    113     while (1) { 
    114         pj_fd_set_t rset; 
    115         int n; 
    116         pj_time_val timeout; 
    117  
    118         if (kbhit()) { 
    119             if (_getch()==27) 
    120                 break; 
     181    stun_cb.on_request_complete = &on_request_complete; 
     182 
     183    status = pj_stun_session_create(g.endpt, NULL, &stun_cb, &g.sess); 
     184    pj_assert(status == PJ_SUCCESS); 
     185 
     186    if (o.realm) { 
     187        pj_str_t r, u, p; 
     188 
     189        if (o.user_name == NULL) { 
     190            printf("error: username must be specified\n"); 
     191            return PJ_EINVAL; 
    121192        } 
    122  
    123         PJ_FD_ZERO(&rset); 
    124         PJ_FD_SET(sock, &rset); 
    125  
    126         timeout.sec = 0; timeout.msec = 100; 
    127  
    128         n = pj_sock_select(FD_SETSIZE, &rset, NULL, NULL, &timeout); 
    129  
    130         if (PJ_FD_ISSET(sock, &rset)) { 
    131             char pkt[512]; 
    132             pj_ssize_t len; 
    133  
    134             len = sizeof(pkt); 
    135             status = pj_sock_recv(sock, pkt, &len, 0); 
    136             if (status == PJ_SUCCESS) { 
    137                 pj_stun_session_on_rx_pkt(sess, pkt, len, NULL); 
     193        if (o.password == NULL) 
     194            o.password = ""; 
     195        g.sess_options = PJ_STUN_USE_LONG_TERM_CRED; 
     196        pj_stun_session_set_long_term_credential(g.sess, pj_cstr(&r, o.realm), 
     197                                                 pj_cstr(&u, o.user_name), 
     198                                                 pj_cstr(&p, o.password)); 
     199        puts("Using long term credential"); 
     200    } else if (o.user_name) { 
     201        pj_str_t u, p; 
     202 
     203        if (o.password == NULL) 
     204            o.password = ""; 
     205        g.sess_options = PJ_STUN_USE_SHORT_TERM_CRED; 
     206        pj_stun_session_set_short_term_credential(g.sess,  
     207                                                  pj_cstr(&u, o.user_name), 
     208                                                  pj_cstr(&p, o.password)); 
     209        puts("Using short term credential"); 
     210    } else { 
     211        puts("Credential not set"); 
     212    } 
     213 
     214    if (o.use_fingerprint) 
     215        g.sess_options |= PJ_STUN_USE_FINGERPRINT; 
     216 
     217    status = pj_thread_create(g.pool, "stun", &worker_thread, NULL,  
     218                              0, 0, &g.thread); 
     219    if (status != PJ_SUCCESS) 
     220        return status; 
     221 
     222    return PJ_SUCCESS; 
     223} 
     224 
     225 
     226static int shutdown() 
     227{ 
     228    if (g.thread) { 
     229        g.quit = 1; 
     230        pj_thread_join(g.thread); 
     231        pj_thread_destroy(g.thread); 
     232        g.thread = NULL; 
     233    } 
     234    if (g.sess) 
     235        pj_stun_session_destroy(g.sess); 
     236    if (g.endpt) 
     237        pj_stun_endpoint_destroy(g.endpt); 
     238    if (g.sock != PJ_INVALID_SOCKET) 
     239        pj_sock_close(g.sock); 
     240    if (g.th) 
     241        pj_timer_heap_destroy(g.th); 
     242    if (g.pool) 
     243        pj_pool_release(g.pool); 
     244 
     245    pj_pool_factory_dump(&g.cp.factory, PJ_TRUE); 
     246    pj_caching_pool_destroy(&g.cp); 
     247 
     248    return PJ_SUCCESS; 
     249} 
     250 
     251static void menu(void) 
     252{ 
     253    puts("Menu:"); 
     254    puts("  b      Send Bind request"); 
     255    puts("  q      Quit"); 
     256    puts(""); 
     257    printf("Choice: "); 
     258} 
     259 
     260static void console_main(void) 
     261{ 
     262    while (!g.quit) { 
     263        char input[10]; 
     264 
     265        menu(); 
     266 
     267        fgets(input, sizeof(input), stdin); 
     268         
     269        switch (input[0]) { 
     270        case 'b': 
     271            { 
     272                pj_stun_tx_data *tdata; 
     273                pj_status_t rc; 
     274 
     275                rc = pj_stun_session_create_bind_req(g.sess, &tdata); 
     276                pj_assert(rc == PJ_SUCCESS); 
     277 
     278                rc = pj_stun_session_send_msg(g.sess, g.sess_options,  
     279                                              &g.dst_addr, sizeof(g.dst_addr), 
     280                                              tdata); 
     281                if (rc != PJ_SUCCESS) 
     282                    my_perror("Error sending STUN request", rc); 
    138283            } 
     284            break; 
     285        case 'q': 
     286            g.quit = 1; 
     287            break; 
     288        default: 
     289            break; 
    139290        } 
    140  
    141         pj_timer_heap_poll(th, NULL); 
    142     } 
     291    } 
     292} 
     293 
     294 
     295static void usage(void) 
     296{ 
     297    puts("Usage: pjstun_client TARGET [OPTIONS]"); 
     298    puts(""); 
     299    puts("where TARGET is \"host[:port]\""); 
     300    puts(""); 
     301    puts("and OPTIONS:"); 
     302    puts(" --realm, -r       Set realm of the credential"); 
     303    puts(" --username, -u    Set username of the credential"); 
     304    puts(" --password, -p    Set password of the credential"); 
     305    puts(" --fingerprint, -F Use fingerprint for outgoing requests"); 
     306    puts(" --help, -h"); 
     307} 
     308 
     309int main(int argc, char *argv[]) 
     310{ 
     311    struct pj_getopt_option long_options[] = { 
     312        { "realm",      1, 0, 'r'}, 
     313        { "username",   1, 0, 'u'}, 
     314        { "password",   1, 0, 'p'}, 
     315        { "fingerprint",0, 0, 'F'}, 
     316        { "help",       0, 0, 'h'} 
     317    }; 
     318    int c, opt_id; 
     319    char *pos; 
     320    pj_status_t status; 
     321 
     322    while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) { 
     323        switch (c) { 
     324        case 'r': 
     325            o.realm = pj_optarg; 
     326            break; 
     327        case 'u': 
     328            o.user_name = pj_optarg; 
     329            break; 
     330        case 'p': 
     331            o.password = pj_optarg; 
     332            break; 
     333        case 'h': 
     334            usage(); 
     335            return 0; 
     336        case 'F': 
     337            o.use_fingerprint = PJ_TRUE; 
     338            break; 
     339        default: 
     340            printf("Argument \"%s\" is not valid. Use -h to see help", 
     341                   argv[pj_optind]); 
     342            return 1; 
     343        } 
     344    } 
     345 
     346    if (pj_optind == argc) { 
     347        puts("Error: TARGET is needed"); 
     348        return 1; 
     349    } 
     350 
     351    if ((pos=pj_ansi_strchr(argv[pj_optind], ':')) != NULL) { 
     352        o.dst_addr = argv[pj_optind]; 
     353        *pos = '\0'; 
     354        o.dst_port = pos+1; 
     355    } else { 
     356        o.dst_addr = argv[pj_optind]; 
     357    } 
     358 
     359    status = init(); 
     360    if (status != PJ_SUCCESS) 
     361        goto on_return; 
     362     
     363    console_main(); 
    143364 
    144365on_return: 
    145     if (sock != PJ_INVALID_SOCKET) 
    146         pj_sock_close(sock); 
    147     if (endpt) 
    148         pj_stun_endpoint_destroy(endpt); 
    149     if (th) 
    150         pj_timer_heap_destroy(th); 
    151     if (pool) 
    152         pj_pool_release(pool); 
    153     pj_caching_pool_destroy(&cp); 
    154  
    155     return 0; 
    156 } 
    157  
    158  
     366    shutdown(); 
     367    return status ? 1 : 0; 
     368} 
     369 
Note: See TracChangeset for help on using the changeset viewer.