diff options
Diffstat (limited to 'pjlib-util/src/pjstun-client/client_main.c')
-rw-r--r-- | pjlib-util/src/pjstun-client/client_main.c | 229 |
1 files changed, 199 insertions, 30 deletions
diff --git a/pjlib-util/src/pjstun-client/client_main.c b/pjlib-util/src/pjstun-client/client_main.c index c5c73441..be65b516 100644 --- a/pjlib-util/src/pjstun-client/client_main.c +++ b/pjlib-util/src/pjstun-client/client_main.c @@ -21,8 +21,9 @@ #define THIS_FILE "client_main.c" +#define LOCAL_PORT 1998 #define BANDWIDTH 64 /* -1 to disable */ -#define LIFETIME 30 /* -1 to disable */ +#define LIFETIME 600 /* -1 to disable */ #define REQ_TRANSPORT -1 /* 0: udp, 1: tcp, -1: disable */ #define REQ_PORT_PROPS -1 /* -1 to disable */ #define REQ_IP NULL /* IP address string */ @@ -39,8 +40,10 @@ static struct global pj_thread_t *thread; pj_bool_t quit; pj_sockaddr_in peer_addr; - pj_sockaddr_in srv_addr; /**< server addr */ - + pj_sockaddr_in srv_addr; + pj_sockaddr_in relay_addr; + char data_buf[256]; + char *data; } g; static struct options @@ -51,10 +54,14 @@ static struct options char *user_name; char *password; char *nonce; + char *peer_addr; pj_bool_t use_fingerprint; } o; +static pj_status_t parse_addr(const char *input, pj_sockaddr_in *addr); + + static my_perror(const char *title, pj_status_t status) { char errmsg[PJ_ERR_MSG_SIZE]; @@ -87,7 +94,26 @@ static void on_request_complete(pj_stun_session *sess, const pj_stun_msg *response) { if (status == PJ_SUCCESS) { - puts("Client transaction completes"); + switch (response->hdr.type) { + case PJ_STUN_ALLOCATE_RESPONSE: + { + pj_stun_relay_addr_attr *ar; + + ar = (pj_stun_relay_addr_attr*) + pj_stun_msg_find_attr(response, + PJ_STUN_ATTR_RELAY_ADDR, 0); + if (ar) { + pj_memcpy(&g.relay_addr, &ar->addr.ipv4, + sizeof(pj_sockaddr_in)); + PJ_LOG(3,(THIS_FILE, "Relay address is %s:%d", + pj_inet_ntoa(g.relay_addr.sin_addr), + (int)pj_ntohs(g.relay_addr.sin_port))); + } else { + pj_memset(&g.relay_addr, 0, sizeof(g.relay_addr)); + } + } + break; + } } else { my_perror("Client transaction error", status); } @@ -119,12 +145,19 @@ static int worker_thread(void *unused) len = sizeof(buffer); addrlen = sizeof(addr); rc = pj_sock_recvfrom(g.sock, buffer, &len, 0, &addr, &addrlen); - if (rc == PJ_SUCCESS && len > 0) { + if (rc != PJ_SUCCESS || len <= 0) + continue; + + if (pj_stun_msg_check(buffer, len, PJ_STUN_IS_DATAGRAM)==PJ_SUCCESS) { rc = pj_stun_session_on_rx_pkt(g.sess, buffer, len, - PJ_STUN_IS_DATAGRAM|PJ_STUN_CHECK_PACKET, + 0, NULL, &addr, addrlen); if (rc != PJ_SUCCESS) my_perror("Error processing packet", rc); + + } else { + buffer[len] = '\0'; + PJ_LOG(3,(THIS_FILE, "Received data: %s", (char*)buffer)); } } } else if (n < 0) @@ -138,6 +171,7 @@ static int init() { pj_sockaddr_in addr; pj_stun_session_cb stun_cb; + int len; pj_status_t status; g.sock = PJ_INVALID_SOCKET; @@ -182,6 +216,20 @@ static int init() status = pj_sockaddr_in_init(&addr, NULL, 0); pj_assert(status == PJ_SUCCESS); + addr.sin_port = pj_htons((pj_uint16_t)LOCAL_PORT); + status = pj_sock_bind(g.sock, &addr, sizeof(addr)); + pj_assert(status == PJ_SUCCESS); + + len = sizeof(addr); + status = pj_sock_getsockname(g.sock, &addr, &len); + pj_assert(status == PJ_SUCCESS); + + PJ_LOG(3,(THIS_FILE, "Listening on port %d", (int)pj_ntohs(addr.sin_port))); + + pj_memcpy(&g.peer_addr, &addr, sizeof(pj_sockaddr_in)); + if (g.peer_addr.sin_addr.s_addr == 0) + pj_gethostip(&g.peer_addr.sin_addr); + pj_memset(&stun_cb, 0, sizeof(stun_cb)); stun_cb.on_send_msg = &on_send_msg; stun_cb.on_request_complete = &on_request_complete; @@ -208,6 +256,11 @@ static int init() puts("Credential not set"); } + if (o.peer_addr) { + if (parse_addr(o.peer_addr, &g.peer_addr)!=PJ_SUCCESS) + return -1; + } + status = pj_thread_create(g.pool, "stun", &worker_thread, NULL, 0, 0, &g.thread); if (status != PJ_SUCCESS) @@ -296,7 +349,7 @@ static void send_allocate_request(pj_bool_t allocate) pj_str_t tmp; pj_sockaddr_in_init(&addr, pj_cstr(&tmp, REQ_IP), 0); - pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, + pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_REQ_IP, PJ_FALSE, &addr, sizeof(addr)); } @@ -320,11 +373,11 @@ static void send_sad_request(pj_bool_t set) return; } - rc = pj_stun_session_create_req(g.sess, PJ_STUN_ALLOCATE_REQUEST, &tdata); + rc = pj_stun_session_create_req(g.sess, PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST, &tdata); pj_assert(rc == PJ_SUCCESS); if (set) { - pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg, + pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE, &g.peer_addr, sizeof(g.peer_addr)); } @@ -337,18 +390,117 @@ static void send_sad_request(pj_bool_t set) static void send_send_ind(void) { + pj_stun_tx_data *tdata; + int len; + pj_status_t rc; + + if (g.peer_addr.sin_addr.s_addr == 0 || + g.peer_addr.sin_port == 0) + { + puts("Error: peer address is not set"); + return; + } + + len = strlen(g.data); + if (len==0) { + puts("Error: data is not set"); + return; + } + + rc = pj_stun_session_create_ind(g.sess, PJ_STUN_SEND_INDICATION, &tdata); + pj_assert(rc == PJ_SUCCESS); + + pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE, + &g.peer_addr, sizeof(g.peer_addr)); + pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg, + PJ_STUN_ATTR_DATA, g.data, len); + + rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, + &g.srv_addr, sizeof(g.srv_addr), + tdata); + pj_assert(rc == PJ_SUCCESS); + +} + +static void send_raw_data_to_srv(void) +{ + pj_ssize_t len; + + if (g.srv_addr.sin_addr.s_addr == 0 || + g.srv_addr.sin_port == 0) + { + puts("Error: server address is not set"); + return; + } + + len = strlen(g.data); + if (len==0) { + puts("Error: data is not set"); + return; + } + + len = strlen(g.data); + pj_sock_sendto(g.sock, g.data, &len, 0, &g.srv_addr, sizeof(g.srv_addr)); +} + +static void send_raw_data_to_relay(void) +{ + pj_ssize_t len; + + if (g.relay_addr.sin_addr.s_addr == 0 || + g.relay_addr.sin_port == 0) + { + puts("Error: relay address is not set"); + return; + } + + len = strlen(g.data); + if (len==0) { + puts("Error: data is not set"); + return; + } + + len = strlen(g.data); + pj_sock_sendto(g.sock, g.data, &len, 0, &g.relay_addr, sizeof(g.relay_addr)); } -static void send_raw_data(void) +static pj_status_t parse_addr(const char *input, + pj_sockaddr_in *addr) { + const char *pos; + pj_str_t ip; + pj_uint16_t port; + pj_sockaddr_in tmp_addr; + + pos = pj_ansi_strchr(input, ':'); + if (pos==NULL) { + puts("Invalid format"); + return -1; + } + + ip.ptr = (char*)input; + ip.slen = pos - input; + port = (pj_uint16_t)atoi(pos+1); + + if (port==0) { + puts("Invalid port"); + return -1; + } + + if (pj_sockaddr_in_init(&tmp_addr, &ip, port)!=PJ_SUCCESS) { + puts("Invalid address"); + return -1; + } + + pj_memcpy(addr, &tmp_addr, sizeof(tmp_addr)); + + return PJ_SUCCESS; } static void set_peer_addr(void) { - char ip_addr[64]; - pj_str_t tmp; - pj_sockaddr_in addr; - int port; + char addr[64]; printf("Current peer address: %s:%d\n", pj_inet_ntoa(g.peer_addr.sin_addr), @@ -356,18 +508,12 @@ static void set_peer_addr(void) printf("Input peer address in IP:PORT format: "); fflush(stdout); + gets(addr); - if (scanf("%s:%d", ip_addr, &port) != 2) { - puts("Error."); + if (parse_addr(addr, &g.peer_addr) != PJ_SUCCESS) { return; } - if (pj_sockaddr_in_init(&addr, pj_cstr(&tmp,ip_addr), (pj_uint16_t)port) != PJ_SUCCESS) { - puts("Error: invalid address"); - return; - } - - g.peer_addr = addr; } static void menu(void) @@ -375,14 +521,15 @@ static void menu(void) puts("Menu:"); printf(" pr Set peer address (currently %s:%d)\n", pj_inet_ntoa(g.peer_addr.sin_addr), pj_ntohs(g.peer_addr.sin_port)); - puts(""); + printf(" dt Set data (currently \"%s\")\n", g.data); puts(" br Send Bind request"); puts(" ar Send Allocate request"); puts(" dr Send de-Allocate request"); - puts(" sr Send Set Active Indication request"); - puts(" cr Send clear Active Indication request"); + puts(" sr Send Set Active Destination request"); + puts(" cr Send clear Active Destination request"); puts(" si Send data with Send Indication"); - puts(" rw Send raw data"); + puts(" rw Send raw data to TURN server"); + puts(" rW Send raw data to relay address"); puts(" q Quit"); puts(""); printf("Choice: "); @@ -398,7 +545,16 @@ static void console_main(void) fgets(input, sizeof(input), stdin); - if (input[0]=='b' && input[1]=='r') { + if (0) { + + } else if (input[0]=='d' && input[1]=='t') { + printf("Input data: "); + gets(g.data); + + } else if (input[0]=='p' && input[1]=='r') { + set_peer_addr(); + + } else if (input[0]=='b' && input[1]=='r') { send_bind_request(); } else if (input[0]=='a' && input[1]=='r') { @@ -417,10 +573,10 @@ static void console_main(void) send_send_ind(); } else if (input[0]=='r' && input[1]=='w') { - send_raw_data(); + send_raw_data_to_srv(); - } else if (input[0]=='p' && input[1]=='r') { - set_peer_addr(); + } else if (input[0]=='r' && input[1]=='W') { + send_raw_data_to_relay(); } else if (input[0]=='q') { g.quit = 1; @@ -441,6 +597,8 @@ static void usage(void) puts(" --password, -p Set password of the credential"); puts(" --nonce, -N Set NONCE"); puts(" --fingerprint, -F Use fingerprint for outgoing requests"); + puts(" --peer, -P Set peer address (address is in HOST:PORT format)"); + puts(" --data, -D Set data"); puts(" --help, -h"); } @@ -452,12 +610,16 @@ int main(int argc, char *argv[]) { "password", 1, 0, 'p'}, { "nonce", 1, 0, 'N'}, { "fingerprint",0, 0, 'F'}, + { "peer", 1, 0, 'P'}, + { "data", 1, 0, 'D'}, { "help", 0, 0, 'h'} }; int c, opt_id; char *pos; pj_status_t status; + g.data = g.data_buf; + while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) { switch (c) { case 'r': @@ -478,6 +640,13 @@ int main(int argc, char *argv[]) case 'F': o.use_fingerprint = PJ_TRUE; break; + case 'P': + o.peer_addr = pj_optarg; + break; + case 'D': + g.data = pj_optarg; + break; + default: printf("Argument \"%s\" is not valid. Use -h to see help", argv[pj_optind]); |