#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/raw.h"
#include "lwip/icmp.h"
#include "lwip/netif.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
#include "ttcp.h"
#include "timer.h"
#include "util.h"
#include "getopt.h"
Go to the source code of this file.
Data Structures | |
struct | ttcp |
Defines | |
#define | TTCP_MODE_RECEIVE 1 |
#define | TTCP_MODE_TRANSMIT 0 |
Typedefs | |
typedef void( | ttcp_done_cb_t )(void *opaque, int result) |
Functions | |
cmd_state_t | cmd_ttcp (int argc, char *argv[], void *ctx) |
static err_t | tcp_accept_cb (void *arg, struct tcp_pcb *newpcb, err_t err) |
Only used in TCP mode. | |
static void | tcp_conn_err_cb (void *arg, err_t err) |
Only used in TCP mode. | |
static err_t | tcp_connect_cb (void *arg, struct tcp_pcb *tpcb, err_t err) |
Only used in TCP mode. | |
static err_t | tcp_recv_cb (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) |
Only used in TCP mode. | |
static void | tcp_send_data (struct ttcp *ttcp) |
Only used in TCP mode. | |
static int | tcp_start (struct ttcp *ttcp) |
Start TCP transfer. | |
static void | tcp_timeout_cb (void *ctx) |
Only used in TCP mode. | |
static void | ttcp_destroy (struct ttcp *ttcp) |
Clean up and free the ttcp structure. | |
static void | ttcp_done (struct ttcp *ttcp, int result) |
Invoked when transfer is done or aborted (non-zero result). | |
static void | ttcp_print_stats (struct ttcp *ttcp) |
Calculate bitrate based on number of bytes transmitted and elapsed time. | |
int | ttcp_start (struct ip_addr addr, uint16_t port, void *opaque, ttcp_done_cb_t *done_cb, int mode, uint16_t nbuf, uint16_t buflen, int udp, int verbose) |
Start a new ttcp transfer. | |
static void | udp_recv_cb (void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port) |
Only used in UDP mode. | |
static int | udp_send_bytes (struct ttcp *ttcp, uint32_t len) |
static void | udp_send_data (struct ttcp *ttcp) |
Only used in UDP mode. | |
static int | udp_start (struct ttcp *ttcp) |
Start UDP transfer. | |
static void | udp_timeout_cb (void *ctx) |
Only used in UDP mode. | |
Variables | |
char | usage [] |
#define TTCP_MODE_RECEIVE 1 |
#define TTCP_MODE_TRANSMIT 0 |
Definition at line 51 of file ttcp.c.
Referenced by cmd_ttcp(), tcp_start(), ttcp_print_stats(), ttcp_start(), and udp_start().
typedef void( ttcp_done_cb_t)(void *opaque, int result) |
cmd_state_t cmd_ttcp | ( | int | argc, | |
char * | argv[], | |||
void * | ctx | |||
) |
Definition at line 599 of file ttcp.c.
References ttcp::buflen, CMD_DONE, ttcp::mode, ttcp::nbuf, ttcp::port, printk(), str2ip(), TTCP_MODE_RECEIVE, TTCP_MODE_TRANSMIT, ttcp_start(), ttcp::udp, and ttcp::verbose.
Referenced by wl_init_complete_cb().
00600 { 00601 00602 int c; 00603 int mode = TTCP_MODE_TRANSMIT; 00604 int verbose = 0; 00605 uint16_t buflen = 1024; 00606 uint16_t nbuf = 1024; 00607 uint16_t port = 2000; 00608 int udp = 0; 00609 struct ip_addr addr = { 0 }; 00610 00611 optind = 1; 00612 while ((c = getopt(argc, argv, "utrl:n:p:v")) != -1) { 00613 switch (c) { 00614 case 't': 00615 mode = TTCP_MODE_TRANSMIT; 00616 break; 00617 case 'r': 00618 mode = TTCP_MODE_RECEIVE; 00619 break; 00620 case 'l': 00621 buflen = atoi(optarg); 00622 break; 00623 case 'v': 00624 verbose = 1; 00625 break; 00626 case 'n': 00627 nbuf = atoi(optarg); 00628 break; 00629 case 'u': 00630 udp = 1; 00631 break; 00632 case 'p': 00633 port = atoi(optarg); 00634 break; 00635 } 00636 } 00637 00638 if (mode == TTCP_MODE_TRANSMIT) { 00639 if (optind >= argc) { 00640 printk("%s", usage); 00641 return CMD_DONE; 00642 } 00643 00644 addr = str2ip(argv[optind]); 00645 if (!addr.addr) { 00646 printk("%s", usage); 00647 return CMD_DONE; 00648 } 00649 } 00650 00651 if (ttcp_start(addr, port, NULL, NULL, mode, nbuf, buflen, udp, 00652 verbose)) 00653 return CMD_DONE; 00654 00655 return CMD_DONE; 00656 }
static err_t tcp_accept_cb | ( | void * | arg, | |
struct tcp_pcb * | newpcb, | |||
err_t | err | |||
) | [static] |
Only used in TCP mode.
Definition at line 321 of file ttcp.c.
References printk(), ttcp::start_time, tcp_conn_err_cb(), tcp_recv_cb(), timer_get_ms(), and ttcp::tpcb.
Referenced by tcp_start().
00322 { 00323 struct ttcp* ttcp = arg; 00324 00325 ttcp->tpcb = newpcb; 00326 tcp_recv(ttcp->tpcb, tcp_recv_cb); 00327 tcp_err(ttcp->tpcb, tcp_conn_err_cb); 00328 00329 printk("TTCP [%p]: accept\n", ttcp); 00330 ttcp->start_time = timer_get_ms(); 00331 return ERR_OK; 00332 }
static void tcp_conn_err_cb | ( | void * | arg, | |
err_t | err | |||
) | [static] |
Only used in TCP mode.
Definition at line 277 of file ttcp.c.
References printk(), ttcp::tpcb, and ttcp_done().
Referenced by tcp_accept_cb(), and tcp_start().
00278 { 00279 struct ttcp* ttcp = arg; 00280 00281 printk("TTCP [%p]: connection error\n", ttcp); 00282 00283 ttcp->tpcb = NULL; /* free'd by lwip upon return */ 00284 ttcp_done(ttcp, err); 00285 }
static err_t tcp_connect_cb | ( | void * | arg, | |
struct tcp_pcb * | tpcb, | |||
err_t | err | |||
) | [static] |
Only used in TCP mode.
Definition at line 258 of file ttcp.c.
References printk(), ttcp::start_time, tcp_send_data(), and timer_get_ms().
Referenced by tcp_start().
00259 { 00260 struct ttcp* ttcp = arg; 00261 00262 printk("TTCP [%p]: connect\n", ttcp); 00263 00264 ttcp->start_time = timer_get_ms(); 00265 #if 0 00266 tcp_sent(tpcb, tcp_sent_cb); 00267 #endif 00268 tcp_send_data(ttcp); 00269 return ERR_OK; 00270 }
static err_t tcp_recv_cb | ( | void * | arg, | |
struct tcp_pcb * | pcb, | |||
struct pbuf * | p, | |||
err_t | err | |||
) | [static] |
Only used in TCP mode.
Definition at line 292 of file ttcp.c.
References ttcp::print_cnt, printk(), ttcp::recved, ttcp_done(), and ttcp::verbose.
Referenced by tcp_accept_cb(), and tcp_start().
00293 { 00294 struct ttcp* ttcp = arg; 00295 00296 /* p will be NULL when remote end is done */ 00297 if (p == NULL) { 00298 ttcp_done(ttcp, 0); 00299 return ERR_OK; 00300 } 00301 00302 /* for print_stats() */ 00303 ttcp->recved += p->tot_len; 00304 if (ttcp->verbose) { 00305 printk("."); 00306 if (ttcp->print_cnt % 80 == 0) 00307 printk("\n"); 00308 ttcp->print_cnt++; 00309 } 00310 00311 tcp_recved(pcb, p->tot_len); 00312 pbuf_free(p); 00313 return ERR_OK; 00314 }
static void tcp_send_data | ( | struct ttcp * | ttcp | ) | [static] |
Only used in TCP mode.
Will transmit a maximum of pbuf->tot_len bytes. Called upon connect and when there's space available in the TCP send window
Definition at line 165 of file ttcp.c.
References ttcp::buflen, ttcp::left, ttcp::payload, printk(), tcp_timeout_cb(), ttcp::tid, TIMEOUT_ONESHOT, timer_sched_timeout_cb(), and ttcp::tpcb.
Referenced by tcp_connect_cb(), and tcp_timeout_cb().
00166 { 00167 err_t err; 00168 uint32_t len; 00169 00170 len = ttcp->left; 00171 00172 /* don't send more than we have in the payload */ 00173 if (len > ttcp->buflen) 00174 len = ttcp->buflen; 00175 00176 /* We cannot send more data than space available in the send 00177 buffer. */ 00178 if (len > tcp_sndbuf(ttcp->tpcb)) 00179 len = tcp_sndbuf(ttcp->tpcb); 00180 00181 do { 00182 err = tcp_write(ttcp->tpcb, ttcp->payload, len, 0); 00183 if (err == ERR_MEM) 00184 len /= 2; 00185 } while (err == ERR_MEM && len > 1); 00186 00187 00188 if (err == ERR_OK) 00189 ttcp->left -= len; 00190 else 00191 printk("TTCP [%p]: tcp_write failed\n", ttcp); 00192 00193 ttcp->tid = timer_sched_timeout_cb(0, TIMEOUT_ONESHOT, 00194 tcp_timeout_cb, ttcp); 00195 }
static int tcp_start | ( | struct ttcp * | ttcp | ) | [static] |
Start TCP transfer.
Definition at line 341 of file ttcp.c.
References ttcp::addr, ttcp::buflen, ttcp::lpcb, ttcp::mode, ttcp::payload, ttcp::port, printk(), tcp_accept_cb(), tcp_conn_err_cb(), tcp_connect_cb(), tcp_recv_cb(), ttcp::tpcb, and TTCP_MODE_TRANSMIT.
Referenced by ttcp_start().
00342 { 00343 ttcp->tpcb = tcp_new(); 00344 if (ttcp->tpcb == NULL) { 00345 printk("TTCP [%p]: could not allocate pcb\n", ttcp); 00346 return -1; 00347 } 00348 00349 ttcp->payload = malloc(ttcp->buflen); 00350 if (ttcp->payload == NULL) { 00351 printk("TTCP [%p]: could not allocate payload\n", ttcp); 00352 return -1; 00353 } 00354 00355 tcp_arg(ttcp->tpcb, ttcp); 00356 00357 if (ttcp->mode == TTCP_MODE_TRANSMIT) { 00358 tcp_err(ttcp->tpcb, tcp_conn_err_cb); 00359 tcp_recv(ttcp->tpcb, tcp_recv_cb); 00360 if (tcp_connect(ttcp->tpcb, &ttcp->addr, ttcp->port, 00361 tcp_connect_cb) != ERR_OK) { 00362 printk("TTCP [%p]: tcp connect failed\n", ttcp); 00363 return -1; 00364 } 00365 00366 } else { 00367 tcp_bind(ttcp->tpcb, IP_ADDR_ANY, ttcp->port); 00368 ttcp->lpcb = tcp_listen(ttcp->tpcb); 00369 if (ttcp->lpcb == NULL) { 00370 printk("TTCP [%p]: listen failed\n", ttcp); 00371 return -1; 00372 } 00373 tcp_accept(ttcp->lpcb, tcp_accept_cb); 00374 } 00375 00376 return 0; 00377 }
static void tcp_timeout_cb | ( | void * | ctx | ) | [static] |
Only used in TCP mode.
Scheduled by tcp_send_data(). tcp_sent() is not used for performance reasons.
Definition at line 203 of file ttcp.c.
References ttcp::left, ttcp::print_cnt, printk(), tcp_send_data(), ttcp::tid, TIMEOUT_ONESHOT, timer_sched_timeout_cb(), ttcp::tpcb, ttcp_done(), and ttcp::verbose.
Referenced by tcp_send_data().
00204 { 00205 struct ttcp *ttcp = ctx; 00206 00207 if (ttcp->left > 0) { 00208 tcp_send_data(ttcp); 00209 if (ttcp->verbose) { 00210 printk("."); 00211 if (ttcp->print_cnt % 80 == 0) 00212 printk("\n"); 00213 ttcp->print_cnt++; 00214 } 00215 return; 00216 } 00217 00218 /* all sent - empty queue */ 00219 if (ttcp->tpcb->snd_queuelen) 00220 ttcp->tid = timer_sched_timeout_cb(0, TIMEOUT_ONESHOT, 00221 tcp_timeout_cb, ttcp); 00222 else 00223 ttcp_done(ttcp, 0); 00224 }
static void ttcp_destroy | ( | struct ttcp * | ttcp | ) | [static] |
Clean up and free the ttcp structure.
Definition at line 112 of file ttcp.c.
References ttcp::lpcb, ttcp::payload, ttcp::tpcb, and ttcp::upcb.
Referenced by ttcp_done(), and ttcp_start().
00113 { 00114 if (ttcp->tpcb) { 00115 tcp_arg(ttcp->tpcb, NULL); 00116 tcp_sent(ttcp->tpcb, NULL); 00117 tcp_recv(ttcp->tpcb, NULL); 00118 tcp_err(ttcp->tpcb, NULL); 00119 tcp_close(ttcp->tpcb); 00120 } 00121 00122 if (ttcp->lpcb) { 00123 tcp_arg(ttcp->lpcb, NULL); 00124 tcp_accept(ttcp->lpcb, NULL); 00125 tcp_close(ttcp->lpcb); 00126 } 00127 00128 if (ttcp->upcb) { 00129 udp_disconnect(ttcp->upcb); 00130 udp_remove(ttcp->upcb); 00131 } 00132 00133 if (ttcp->payload) 00134 free(ttcp->payload); 00135 00136 free(ttcp); 00137 }
static void ttcp_done | ( | struct ttcp * | ttcp, | |
int | result | |||
) | [static] |
Invoked when transfer is done or aborted (non-zero result).
Definition at line 144 of file ttcp.c.
References ttcp::done_cb, ttcp::opaque, ttcp_destroy(), and ttcp_print_stats().
Referenced by tcp_conn_err_cb(), tcp_recv_cb(), tcp_timeout_cb(), udp_recv_cb(), and udp_send_data().
00145 { 00146 if (result == 0) 00147 ttcp_print_stats(ttcp); 00148 00149 if (ttcp->done_cb) 00150 ttcp->done_cb(ttcp->opaque, result); 00151 00152 ttcp_destroy(ttcp); 00153 }
static void ttcp_print_stats | ( | struct ttcp * | ttcp | ) | [static] |
Calculate bitrate based on number of bytes transmitted and elapsed time.
Definition at line 93 of file ttcp.c.
References ttcp::buflen, ttcp::mode, ttcp::nbuf, printk(), ttcp::recved, ttcp::start_time, timer_get_ms(), TTCP_MODE_TRANSMIT, ttcp::udp, and ttcp::verbose.
Referenced by ttcp_done().
00094 { 00095 uint32_t ms = timer_get_ms() - ttcp->start_time; 00096 uint32_t bytes = ttcp->mode == TTCP_MODE_TRANSMIT ? 00097 ttcp->nbuf * ttcp->buflen : ttcp->recved; 00098 00099 if (ttcp->verbose) 00100 printk("\n"); 00101 00102 printk("TTCP [%p]: %d bytes processed, %d.%d KB/s (%s/%s)\n", 00103 ttcp, bytes, bytes / ms, bytes % ms, ttcp->udp ? "udp" : "tcp", 00104 ttcp->mode == TTCP_MODE_TRANSMIT ? "tx" : "rx"); 00105 }
int ttcp_start | ( | struct ip_addr | addr, | |
uint16_t | port, | |||
void * | opaque, | |||
ttcp_done_cb_t * | done_cb, | |||
int | mode, | |||
uint16_t | nbuf, | |||
uint16_t | buflen, | |||
int | udp, | |||
int | verbose | |||
) |
Start a new ttcp transfer.
It should be possible to call this function multiple times in order to get multiple ttcp streams. done_cb() will be invoked upon completion.
Definition at line 529 of file ttcp.c.
References ttcp::addr, ttcp::buflen, ttcp::done_cb, ttcp::left, ttcp::mode, ttcp::nbuf, ttcp::opaque, ttcp::port, printk(), tcp_start(), ttcp_destroy(), TTCP_MODE_RECEIVE, TTCP_MODE_TRANSMIT, ttcp::udp, udp_start(), and ttcp::verbose.
Referenced by cmd_ttcp().
00532 { 00533 struct ttcp* ttcp; 00534 int status; 00535 00536 if (mode != TTCP_MODE_TRANSMIT && mode != TTCP_MODE_RECEIVE) { 00537 printk("TTCP [-]: invalid mode\n"); 00538 return -1; 00539 } 00540 00541 if (nbuf == 0) { 00542 printk("TTCP [-]: invalid nbuf\n"); 00543 return -1; 00544 } 00545 00546 if (buflen == 0) { 00547 printk("TTCP [-]: invalid buflen\n"); 00548 return -1; 00549 } 00550 00551 ttcp = calloc(1, sizeof(struct ttcp)); 00552 if (ttcp == NULL) { 00553 printk("TTCP [-]: could not allocate memory for ttcp\n"); 00554 return -1; 00555 } 00556 00557 ttcp->addr = addr; 00558 ttcp->port = port; 00559 ttcp->nbuf = nbuf; 00560 ttcp->mode = mode; 00561 ttcp->left = nbuf * buflen; 00562 ttcp->done_cb = done_cb; 00563 ttcp->opaque = opaque; 00564 ttcp->udp = udp; 00565 ttcp->verbose = verbose; 00566 ttcp->buflen = buflen; 00567 00568 printk("TTCP [%p]: nbuf=%d, buflen=%d, port=%d (%s/%s)\n", 00569 ttcp, ttcp->nbuf, ttcp->buflen, ttcp->port, 00570 ttcp->udp ? "udp" : "tcp", 00571 ttcp->mode == TTCP_MODE_TRANSMIT ? "tx" : "rx"); 00572 00573 if (ttcp->udp) 00574 status = udp_start(ttcp); 00575 else 00576 status = tcp_start(ttcp); 00577 00578 if (status) 00579 goto fail; 00580 00581 return 0; 00582 00583 fail: 00584 ttcp_destroy(ttcp); 00585 return -1; 00586 }
static void udp_recv_cb | ( | void * | arg, | |
struct udp_pcb * | upcb, | |||
struct pbuf * | p, | |||
struct ip_addr * | addr, | |||
u16_t | port | |||
) | [static] |
Only used in UDP mode.
Will finalize the ttcp process when an end marker is seen.
Definition at line 458 of file ttcp.c.
References ttcp::print_cnt, printk(), ttcp::recved, ttcp::start_time, timer_get_ms(), ttcp_done(), ttcp::udp_started, and ttcp::verbose.
Referenced by udp_start().
00460 { 00461 struct ttcp* ttcp = arg; 00462 00463 /* got start marker? we might lose this so if we get it just reset 00464 * the timer 00465 */ 00466 if (!ttcp->udp_started && p->tot_len <= 4) { 00467 ttcp->start_time = timer_get_ms(); 00468 ttcp->udp_started = 1; 00469 goto out; 00470 } 00471 00472 /* after receiving at least 1 byte, check end marker 00473 * don't check udp_started since we might have lost the start marker 00474 */ 00475 if (ttcp->recved && p->tot_len <= 4) { 00476 ttcp_done(ttcp, 0); 00477 goto out; 00478 } 00479 00480 /* for print_stats() */ 00481 ttcp->recved += p->tot_len; 00482 if (ttcp->verbose) { 00483 printk("."); 00484 if (ttcp->print_cnt % 80 == 0) 00485 printk("\n"); 00486 ttcp->print_cnt++; 00487 } 00488 00489 out: 00490 pbuf_free(p); 00491 }
static int udp_send_bytes | ( | struct ttcp * | ttcp, | |
uint32_t | len | |||
) | [static] |
Definition at line 395 of file ttcp.c.
References printk(), and ttcp::upcb.
Referenced by udp_send_data().
00396 { 00397 struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); 00398 if (p == NULL) { 00399 printk("TTCP [%p]: could not allocate pbuf\n", ttcp); 00400 return -1; 00401 } 00402 00403 if (udp_send(ttcp->upcb, p) != ERR_OK) { 00404 printk("TTCP [%p]: udp_send() failed\n", ttcp); 00405 pbuf_free(p); 00406 return -1; 00407 } 00408 00409 pbuf_free(p); 00410 return 0; 00411 }
static void udp_send_data | ( | struct ttcp * | ttcp | ) | [static] |
Only used in UDP mode.
First call will send the start marker. When all ttcp data has been sent, a number of end markers will be sent. After end marker transmission, this function will complete the ttcp process.
Definition at line 419 of file ttcp.c.
References ttcp::buflen, ttcp::left, ttcp::start_time, ttcp::tid, TIMEOUT_ONESHOT, timer_get_ms(), timer_sched_timeout_cb(), ttcp_done(), ttcp::udp_end_marker_left, udp_send_bytes(), ttcp::udp_started, and udp_timeout_cb().
Referenced by udp_start(), and udp_timeout_cb().
00420 { 00421 /* send start marker first time */ 00422 if (!ttcp->udp_started) { 00423 if (udp_send_bytes(ttcp, 4) == 0) { 00424 ttcp->udp_started = 1; 00425 ttcp->start_time = timer_get_ms(); 00426 } 00427 } 00428 00429 /* normal case */ 00430 else if (ttcp->left) { 00431 /* send data */ 00432 if (udp_send_bytes(ttcp, ttcp->buflen) == 0) 00433 ttcp->left -= ttcp->buflen; 00434 } 00435 00436 /* end marker? */ 00437 else if (ttcp->left == 0 && ttcp->udp_end_marker_left) { 00438 if (udp_send_bytes(ttcp, 4) == 0) 00439 ttcp->udp_end_marker_left--; 00440 } 00441 00442 /* all end markers sent */ 00443 else if (ttcp->left == 0) { 00444 ttcp_done(ttcp, 0); 00445 return; 00446 } 00447 00448 ttcp->tid = timer_sched_timeout_cb(0, TIMEOUT_ONESHOT, 00449 udp_timeout_cb, ttcp); 00450 }
static int udp_start | ( | struct ttcp * | ttcp | ) | [static] |
Start UDP transfer.
Definition at line 498 of file ttcp.c.
References ttcp::addr, ttcp::mode, ttcp::port, printk(), TTCP_MODE_TRANSMIT, ttcp::udp_end_marker_left, udp_recv_cb(), udp_send_data(), and ttcp::upcb.
Referenced by ttcp_start().
00499 { 00500 ttcp->udp_end_marker_left = 5; 00501 ttcp->upcb = udp_new(); 00502 if (ttcp->upcb == NULL) { 00503 printk("TTCP [%p]: could not allocate pcb\n", ttcp); 00504 return -1; 00505 } 00506 00507 if (ttcp->mode == TTCP_MODE_TRANSMIT) { 00508 if (udp_connect(ttcp->upcb, &ttcp->addr, ttcp->port) != 00509 ERR_OK) { 00510 printk("TTCP [%p]: udp connect failed\n", ttcp); 00511 return -1; 00512 } 00513 udp_send_data(ttcp); 00514 } else { 00515 udp_recv(ttcp->upcb, udp_recv_cb, ttcp); 00516 } 00517 00518 return 0; 00519 }
static void udp_timeout_cb | ( | void * | ctx | ) | [static] |
Only used in UDP mode.
Scheduled after data has been sent in udp_send_data() if we have more data to send.
Definition at line 387 of file ttcp.c.
References udp_send_data().
Referenced by udp_send_data().
00388 { 00389 struct ttcp* ttcp = ctx; 00390 udp_send_data(ttcp); 00391 }
char usage[] |