summaryrefslogtreecommitdiff
path: root/pjlib-util/src/pjstun-client/client_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjlib-util/src/pjstun-client/client_main.c')
-rw-r--r--pjlib-util/src/pjstun-client/client_main.c229
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]);