Porting PicoTCP WIP
This commit is contained in:
290
kernel/picotcp/test/examples/udp_client.c
Normal file
290
kernel/picotcp/test/examples/udp_client.c
Normal file
@ -0,0 +1,290 @@
|
||||
#include "utils.h"
|
||||
#include <pico_ipv4.h>
|
||||
#include <pico_ipv6.h>
|
||||
#include <pico_socket.h>
|
||||
|
||||
/*** START UDP CLIENT ***/
|
||||
/*
|
||||
* udpclient expects the following format: udpclient:dest_addr:sendto_port[:listen_port:datasize:loops:subloops]
|
||||
* dest_addr: IP address to send datagrams to
|
||||
* sendto_port: port number to send datagrams to
|
||||
* listen_port [OPTIONAL]: port number on which the udpclient listens
|
||||
* datasize [OPTIONAL]: size of the data given to the socket in one go
|
||||
* loops [OPTIONAL]: number of intervals in which data is send
|
||||
* subloops [OPTIONAL]: number of sends in one interval
|
||||
*
|
||||
* REMARK: once an optional parameter is given, all optional parameters need a value!
|
||||
*
|
||||
* f.e.: ./build/test/picoapp.elf --vde pic0:/tmp/pic0.ctl:10.40.0.2:255.255.255.0: -a udpclient:10.40.0.3:6667:6667:1400:100:10
|
||||
*/
|
||||
|
||||
struct udpclient_pas *udpclient_pas;
|
||||
|
||||
static int exit_retry = 0;
|
||||
|
||||
static void request_exit_echo(pico_time now, void *arg)
|
||||
{
|
||||
struct pico_socket *s = (struct pico_socket *)arg;
|
||||
char end[4] = "end";
|
||||
pico_socket_send(s, end, 4);
|
||||
if (exit_retry++ > 3) {
|
||||
if (!pico_timer_add(1000, deferred_exit, udpclient_pas)) {
|
||||
printf("Failed to start exit timer, exiting now\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if (!pico_timer_add(1000, request_exit_echo, s)) {
|
||||
printf("Failed to start request_exit_echo timer, sending request now\n");
|
||||
request_exit_echo((pico_time)0, NULL);
|
||||
exit(1);
|
||||
}
|
||||
printf("%s: requested exit of echo\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
void udpclient_send(pico_time __attribute__((unused)) now, void __attribute__((unused)) *arg)
|
||||
{
|
||||
struct pico_socket *s = udpclient_pas->s;
|
||||
char *buf = NULL;
|
||||
int i = 0, w = 0;
|
||||
static uint16_t loop = 0;
|
||||
|
||||
if (++loop > udpclient_pas->loops) {
|
||||
if (!pico_timer_add(1000, request_exit_echo, s)) {
|
||||
printf("Failed to start request_exit_echo timer, sending request now\n");
|
||||
request_exit_echo((pico_time)0, NULL);
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
buf = calloc(1, udpclient_pas->datasize);
|
||||
if (!buf) {
|
||||
printf("%s: no memory available\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buf, '1', udpclient_pas->datasize);
|
||||
picoapp_dbg("%s: performing loop %u\n", __FUNCTION__, loop);
|
||||
for (i = 0; i < udpclient_pas->subloops; i++) {
|
||||
w = pico_socket_send(s, buf, udpclient_pas->datasize);
|
||||
if (w <= 0)
|
||||
break;
|
||||
}
|
||||
picoapp_dbg("%s: written %u byte(s) in each of %u subloops\n", __FUNCTION__, udpclient_pas->datasize, i);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (!pico_timer_add(100, udpclient_send, NULL)) {
|
||||
printf("Failed to start send timer, sending exit request to echo and exiting\n");
|
||||
request_exit_echo((pico_time)0, NULL);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void cb_udpclient(uint16_t ev, struct pico_socket *s)
|
||||
{
|
||||
char *recvbuf = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (ev & PICO_SOCK_EV_RD) {
|
||||
recvbuf = calloc(1, udpclient_pas->datasize);
|
||||
if (!recvbuf) {
|
||||
printf("%s: no memory available\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
r = pico_socket_recv(s, recvbuf, udpclient_pas->datasize);
|
||||
} while ( r > 0);
|
||||
free(recvbuf);
|
||||
}
|
||||
|
||||
if (ev == PICO_SOCK_EV_ERR) {
|
||||
printf("Socket Error received. Bailing out.\n");
|
||||
free(udpclient_pas);
|
||||
exit(7);
|
||||
}
|
||||
}
|
||||
|
||||
void app_udpclient(char *arg)
|
||||
{
|
||||
char *daddr = NULL, *lport = NULL, *sport = NULL, *s_datasize = NULL, *s_loops = NULL, *s_subloops = NULL;
|
||||
char *nxt = arg;
|
||||
char sinaddr_any[40] = {
|
||||
0
|
||||
};
|
||||
uint16_t listen_port = 0;
|
||||
int ret = 0;
|
||||
|
||||
udpclient_pas = calloc(1, sizeof(struct udpclient_pas));
|
||||
if (!udpclient_pas) {
|
||||
printf("%s: no memory available\n", __FUNCTION__);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
udpclient_pas->s = NULL;
|
||||
udpclient_pas->loops = 100;
|
||||
udpclient_pas->subloops = 10;
|
||||
udpclient_pas->datasize = 1400;
|
||||
|
||||
/* start of argument parsing */
|
||||
if (nxt) {
|
||||
nxt = cpy_arg(&daddr, arg);
|
||||
if (daddr) {
|
||||
if (!IPV6_MODE)
|
||||
pico_string_to_ipv4(daddr, &udpclient_pas->dst.ip4.addr);
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
else
|
||||
pico_string_to_ipv6(daddr, udpclient_pas->dst.ip6.addr);
|
||||
#endif
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* missing dest_addr */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nxt) {
|
||||
nxt = cpy_arg(&sport, nxt);
|
||||
if (sport && atoi(sport)) {
|
||||
udpclient_pas->sport = short_be(atoi(sport));
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* missing send_port */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nxt) {
|
||||
nxt = cpy_arg(&lport, nxt);
|
||||
if (lport && atoi(lport)) {
|
||||
listen_port = short_be(atoi(lport));
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* missing listen_port, use default */
|
||||
listen_port = 0;
|
||||
}
|
||||
|
||||
if (nxt) {
|
||||
nxt = cpy_arg(&s_datasize, nxt);
|
||||
if (s_datasize && atoi(s_datasize)) {
|
||||
udpclient_pas->datasize = atoi(s_datasize);
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* missing datasize, incomplete optional parameters? -> exit */
|
||||
if (lport)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nxt) {
|
||||
nxt = cpy_arg(&s_loops, nxt);
|
||||
if (s_loops && atoi(s_loops)) {
|
||||
udpclient_pas->loops = atoi(s_loops);
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* missing loops, incomplete optional parameters? -> exit */
|
||||
if (s_datasize)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nxt) {
|
||||
nxt = cpy_arg(&s_subloops, nxt);
|
||||
if (s_subloops && atoi(s_subloops)) {
|
||||
udpclient_pas->subloops = atoi(s_subloops);
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* missing subloops, incomplete optional parameters? -> exit */
|
||||
if (s_loops)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* end of argument parsing */
|
||||
|
||||
if (!IPV6_MODE)
|
||||
pico_ipv4_to_string(sinaddr_any, inaddr_any.addr);
|
||||
|
||||
#ifdef PICO_SUPPORT_IPV6
|
||||
else
|
||||
pico_ipv6_to_string(sinaddr_any, inaddr6_any.addr);
|
||||
#endif
|
||||
|
||||
if (!IPV6_MODE)
|
||||
udpclient_pas->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &cb_udpclient);
|
||||
else
|
||||
udpclient_pas->s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_UDP, &cb_udpclient);
|
||||
|
||||
if (!udpclient_pas->s) {
|
||||
printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err));
|
||||
free(udpclient_pas);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!IPV6_MODE)
|
||||
ret = pico_socket_bind(udpclient_pas->s, &inaddr_any, &listen_port);
|
||||
else
|
||||
ret = pico_socket_bind(udpclient_pas->s, &inaddr6_any, &listen_port);
|
||||
|
||||
if (ret < 0) {
|
||||
free(udpclient_pas);
|
||||
printf("%s: error binding socket to %s:%u: %s\n", __FUNCTION__, sinaddr_any, short_be(listen_port), strerror(pico_err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!IPV6_MODE)
|
||||
ret = pico_socket_connect(udpclient_pas->s, &udpclient_pas->dst.ip4, udpclient_pas->sport);
|
||||
else
|
||||
ret = pico_socket_connect(udpclient_pas->s, &udpclient_pas->dst.ip6, udpclient_pas->sport);
|
||||
|
||||
if (ret < 0) {
|
||||
printf("%s: error connecting to [%s]:%u: %s\n", __FUNCTION__, daddr, short_be(udpclient_pas->sport), strerror(pico_err));
|
||||
free(udpclient_pas);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("\n%s: UDP client launched. Sending packets of %u bytes in %u loops and %u subloops to %s:%u\n\n",
|
||||
__FUNCTION__, udpclient_pas->datasize, udpclient_pas->loops, udpclient_pas->subloops, daddr, short_be(udpclient_pas->sport));
|
||||
|
||||
if (!pico_timer_add(100, udpclient_send, NULL)) {
|
||||
printf("Failed to start send timer, sending exit request to echo and exiting\n");
|
||||
request_exit_echo((pico_time)0, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* free strdups */
|
||||
if (daddr)
|
||||
free (daddr);
|
||||
|
||||
if (lport)
|
||||
free (lport);
|
||||
|
||||
if (sport)
|
||||
free (sport);
|
||||
|
||||
if (s_datasize)
|
||||
free (s_datasize);
|
||||
|
||||
if (s_loops)
|
||||
free (s_loops);
|
||||
|
||||
if (s_subloops)
|
||||
free (s_subloops);
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
fprintf(stderr, "udpclient expects the following format: udpclient:dest_addr:dest_port[:listen_port:datasize:loops:subloops]\n");
|
||||
free(udpclient_pas);
|
||||
exit(255);
|
||||
}
|
||||
/*** END UDP CLIENT ***/
|
||||
Reference in New Issue
Block a user