00001
00032 #include "lwip/opt.h"
00033
00034 #include "lwip/mem.h"
00035 #include "lwip/raw.h"
00036 #include "lwip/icmp.h"
00037 #include "lwip/netif.h"
00038 #include "lwip/sys.h"
00039 #include "lwip/sockets.h"
00040 #include "lwip/inet.h"
00041 #include "lwip/inet_chksum.h"
00042 #include "lwip/tcp.h"
00043 #include "lwip/udp.h"
00044
00045 #include "ttcp.h"
00046 #include "timer.h"
00047 #include "util.h"
00048
00049 #include "getopt.h"
00050
00051 #define TTCP_MODE_TRANSMIT 0
00052 #define TTCP_MODE_RECEIVE 1
00053
00054 typedef void (ttcp_done_cb_t)(void *opaque, int result);
00055
00056
00057 struct ttcp {
00058
00059
00060 struct ip_addr addr;
00061 uint16_t port;
00062 uint16_t nbuf;
00063 int mode;
00064 int verbose;
00065 int udp;
00066
00067
00068 uint16_t print_cnt;
00069 uint32_t start_time;
00070 uint32_t left;
00071 uint32_t recved;
00072 ttcp_done_cb_t* done_cb;
00073 void* opaque;
00074 uint32_t buflen;
00075 uint32_t tid;
00076
00077
00078 struct tcp_pcb* tpcb;
00079 struct tcp_pcb* lpcb;
00080 char* payload;
00081
00082
00083 int udp_started;
00084 uint16_t udp_end_marker_left;
00085 struct udp_pcb* upcb;
00086 };
00087
00088
00092 static void
00093 ttcp_print_stats(struct ttcp *ttcp)
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 }
00106
00107
00111 static void
00112 ttcp_destroy(struct ttcp* ttcp)
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 }
00138
00139
00143 static void
00144 ttcp_done(struct ttcp* ttcp, int result)
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 }
00154
00155 static void
00156 tcp_timeout_cb(void *ctx);
00157
00164 static void
00165 tcp_send_data(struct ttcp *ttcp)
00166 {
00167 err_t err;
00168 uint32_t len;
00169
00170 len = ttcp->left;
00171
00172
00173 if (len > ttcp->buflen)
00174 len = ttcp->buflen;
00175
00176
00177
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 }
00196
00197
00202 static void
00203 tcp_timeout_cb(void *ctx)
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
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 }
00225
00226
00227 #if 0
00228
00232 static err_t
00233 tcp_sent_cb(void *arg, struct tcp_pcb *pcb, u16_t len)
00234 {
00235 struct ttcp *ttcp = arg;
00236
00237 if (ttcp->left > 0) {
00238 tcp_send_data(ttcp);
00239 if (ttcp->verbose) {
00240 printk(".");
00241 if (ttcp->print_cnt % 80 == 0)
00242 printk("\n");
00243 ttcp->print_cnt++;
00244 }
00245
00246 } else if (pcb->snd_queuelen == 0) {
00247 ttcp_done(ttcp, 0);
00248 }
00249
00250 return ERR_OK;
00251 }
00252 #endif
00253
00257 static err_t
00258 tcp_connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
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 }
00271
00272
00276 static void
00277 tcp_conn_err_cb(void *arg, err_t err)
00278 {
00279 struct ttcp* ttcp = arg;
00280
00281 printk("TTCP [%p]: connection error\n", ttcp);
00282
00283 ttcp->tpcb = NULL;
00284 ttcp_done(ttcp, err);
00285 }
00286
00287
00291 static err_t
00292 tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
00293 {
00294 struct ttcp* ttcp = arg;
00295
00296
00297 if (p == NULL) {
00298 ttcp_done(ttcp, 0);
00299 return ERR_OK;
00300 }
00301
00302
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 }
00315
00316
00320 static err_t
00321 tcp_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err)
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 }
00333
00334
00335
00336
00340 static int
00341 tcp_start(struct ttcp* ttcp)
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 }
00378
00379
00380 static void
00381 udp_send_data(struct ttcp* ttcp);
00382
00387 static void udp_timeout_cb(void *ctx)
00388 {
00389 struct ttcp* ttcp = ctx;
00390 udp_send_data(ttcp);
00391 }
00392
00393
00394 static int
00395 udp_send_bytes(struct ttcp* ttcp, uint32_t len)
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 }
00412
00418 static void
00419 udp_send_data(struct ttcp* ttcp)
00420 {
00421
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
00430 else if (ttcp->left) {
00431
00432 if (udp_send_bytes(ttcp, ttcp->buflen) == 0)
00433 ttcp->left -= ttcp->buflen;
00434 }
00435
00436
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
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 }
00451
00452
00457 static void
00458 udp_recv_cb(void *arg, struct udp_pcb *upcb, struct pbuf *p,
00459 struct ip_addr *addr, u16_t port)
00460 {
00461 struct ttcp* ttcp = arg;
00462
00463
00464
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
00473
00474
00475 if (ttcp->recved && p->tot_len <= 4) {
00476 ttcp_done(ttcp, 0);
00477 goto out;
00478 }
00479
00480
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 }
00492
00493
00497 static int
00498 udp_start(struct ttcp* ttcp)
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 }
00520
00521
00528 int
00529 ttcp_start(struct ip_addr addr, uint16_t port, void *opaque,
00530 ttcp_done_cb_t *done_cb,
00531 int mode, uint16_t nbuf, uint16_t buflen, int udp, int verbose)
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 }
00587
00588 char usage[] = "Usage: ttcp -t/-r [-options] host\n\
00589 -l length of bufs written to network (default 1024)\n\
00590 -n number of bufs written to network (default 1024)\n\
00591 -p port number to send to (default 2000)\n\
00592 -u udp\n\
00593 -v verbose\n";
00594
00598 cmd_state_t
00599 cmd_ttcp(int argc, char* argv[], void* ctx)
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 }