123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053 |
- Index: AUTHORS
- ===================================================================
- RCS file: /var/cvs/busybox/AUTHORS,v
- retrieving revision 1.40
- diff -u -r1.40 AUTHORS
- --- a/AUTHORS 9 Oct 2003 21:19:21 -0000 1.40
- +++ b/AUTHORS 5 Mar 2004 15:45:47 -0000
- @@ -92,6 +92,9 @@
- Original author of BusyBox in 1995, 1996. Some of his code can
- still be found hiding here and there...
- +John Powers <jpp@ti.com>
- + Added multicast option (rfc2090) and timeout option (rfc2349) to tftp.
- +
- Tim Riker <Tim@Rikers.org>
- bug fixes, member of fan club
- Index: include/usage.h
- ===================================================================
- RCS file: /var/cvs/busybox/include/usage.h,v
- retrieving revision 1.191
- diff -u -r1.191 usage.h
- --- a/include/usage.h 25 Feb 2004 10:35:55 -0000 1.191
- +++ b/include/usage.h 5 Mar 2004 15:45:59 -0000
- @@ -2492,6 +2492,21 @@
- #else
- #define USAGE_TFTP_BS(a)
- #endif
- +#ifdef CONFIG_FEATURE_TFTP_TIMEOUT
- + #define USAGE_TFTP_TIMEOUT(a) a
- +#else
- + #define USAGE_TFTP_TIMEOUT(a)
- +#endif
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + #define USAGE_TFTP_MULTICAST(a) a
- +#else
- + #define USAGE_TFTP_MULTICAST(a)
- +#endif
- +#ifdef CONFIG_FEATURE_TFTP_DEBUG
- + #define USAGE_TFTP_DEBUG(a) a
- +#else
- + #define USAGE_TFTP_DEBUG(a)
- +#endif
- #define tftp_trivial_usage \
- "[OPTION]... HOST [PORT]"
- @@ -2508,6 +2523,16 @@
- ) \
- USAGE_TFTP_BS( \
- "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \
- + ) \
- + USAGE_TFTP_TIMEOUT( \
- + "\t-T SEC\tClient timeout SEC seconds (default: 5).\n" \
- + "\t-t SEC\tServer timeout SEC seconds\n" \
- + ) \
- + USAGE_TFTP_MULTICAST( \
- + "\t-m\tMulticast get file.\n" \
- + ) \
- + USAGE_TFTP_DEBUG( \
- + "\t-D\tPrint debug messages.\n" \
- )
- #define time_trivial_usage \
- "[OPTION]... COMMAND [ARGS...]"
- Index: networking/Config.in
- ===================================================================
- RCS file: /var/cvs/busybox/networking/Config.in,v
- retrieving revision 1.27
- diff -u -r1.27 Config.in
- --- a/networking/Config.in 22 Feb 2004 12:25:47 -0000 1.27
- +++ b/networking/Config.in 5 Mar 2004 15:45:59 -0000
- @@ -522,6 +522,13 @@
- Add support for the GET command within the TFTP client. This allows
- a client to retrieve a file from a TFTP server.
- +config CONFIG_FEATURE_TFTP_MULTICAST
- + bool " Enable \"multicast\" option"
- + default n
- + depends on CONFIG_FEATURE_TFTP_GET
- + help
- + Allow the client to receive multicast file transfers.
- +
- config CONFIG_FEATURE_TFTP_PUT
- bool " Enable \"put\" command"
- default y
- @@ -531,12 +538,19 @@
- a client to transfer a file to a TFTP server.
- config CONFIG_FEATURE_TFTP_BLOCKSIZE
- - bool " Enable \"blocksize\" command"
- + bool " Enable \"blksize\" option"
- default n
- depends on CONFIG_TFTP
- help
- Allow the client to specify the desired block size for transfers.
- +config CONFIG_FEATURE_TFTP_TIMEOUT
- + bool " Enable \"timeout\" option"
- + default n
- + depends on CONFIG_TFTP
- + help
- + Allow the client to negotiate timeout option with server.
- +
- config CONFIG_FEATURE_TFTP_DEBUG
- bool " Enable debug"
- default n
- Index: networking/tftp.c
- ===================================================================
- RCS file: /var/cvs/busybox/networking/tftp.c,v
- retrieving revision 1.25
- diff -u -r1.25 tftp.c
- --- a/networking/tftp.c 5 Mar 2004 13:04:39 -0000 1.25
- +++ b/networking/tftp.c 5 Mar 2004 15:46:00 -0000
- @@ -1,11 +1,26 @@
- +/* vi: set sw=4 ts=4: */
- /* ------------------------------------------------------------------------- */
- /* tftp.c */
- +/* Copyright (c) 2003, 2004 Texas Instruments */
- +/* */
- +/* This package is free software; you can redistribute it and/or */
- +/* modify it under the terms of the license found in the file */
- +/* named COPYING that should have accompanied this file. */
- +/* */
- +/* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
- +/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
- +/* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
- /* */
- /* A simple tftp client for busybox. */
- /* Tries to follow RFC1350. */
- /* Only "octet" mode supported. */
- /* Optional blocksize negotiation (RFC2347 + RFC2348) */
- /* */
- +/* New features added at Texas Instruments, October 2003 */
- +/* Author: John Powers */
- +/* Multicast option: rfc2090 */
- +/* Timeout option: rfc2349 */
- +/* */
- /* Copyright (C) 2001 Magnus Damm <damm@opensource.se> */
- /* */
- /* Parts of the code based on: */
- @@ -46,8 +61,20 @@
- #include "busybox.h"
- +#if defined(CONFIG_FEATURE_TFTP_BLOCKSIZE) || defined(CONFIG_FEATURE_TFTP_MULTICAST) || defined(CONFIG_FEATURE_TFTP_TIMEOUT)
- + #define TFTP_OPTIONS
- +#endif
- +
- //#define CONFIG_FEATURE_TFTP_DEBUG
- +#ifdef CONFIG_FEATURE_TFTP_DEBUG
- + static void printtime(void);
- + #define dprintf(fmt...) if (debug) {printtime(); printf(fmt);}
- + int debug = 0;
- +#else
- + #define dprintf(fmt...)
- +#endif
- +
- #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
- #define TFTP_TIMEOUT 5 /* seconds */
- @@ -68,12 +95,24 @@
- "Illegal TFTP operation",
- "Unknown transfer ID",
- "File already exists",
- - "No such user"
- + "No such user",
- +#ifdef TFTP_OPTIONS
- + "Unsupported option",
- +#endif
- };
- const int tftp_cmd_get = 1;
- const int tftp_cmd_put = 2;
- +
- +struct tftp_option {
- + int multicast;
- + int blksize;
- + int client_timeout;
- + int server_timeout;
- +};
- +
- +
- #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
- static int tftp_blocksize_check(int blocksize, int bufsize)
- @@ -93,16 +132,158 @@
- return blocksize;
- }
- +#endif
- +
- +#ifdef CONFIG_FEATURE_TFTP_TIMEOUT
- +
- +static int
- +tftp_timeout_check(int timeout)
- +{
- + /* Check if timeout seconds is valid:
- + * RFC2349 says between 1 and 255.
- + */
- +
- + if (timeout < 1 || timeout > 255) {
- + bb_error_msg("bad timeout value");
- + return 0;
- + }
- + return timeout;
- +}
- +
- +#endif
- +
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- +static int
- +tftp_multicast_check(const char *opt, char **phost, unsigned short *pport, int *pactive)
- +{
- + /* Option string contains comma delimited addr,port,active.
- + * addr = multicast IP address
- + * port = port number
- + * active = 1 if active client
- + * 0 if passive client
- + *
- + * Addr and port will be empty fields when the server notifies a
- + * passive client that it is now the active client.
- + *
- + * The host address string must be freed by the caller. Neither host
- + * nor port will be set/changed if the input fields are empty.
- + *
- + * If any tokenization errors occur in the opt string, the host
- + * address string is automatically freed.
- + *
- + * Return 0 if any tokenization error, 1 if all parameters are good.
- + */
- +
- + char *token = NULL;
- + char *parse_buf = NULL;
- + char *tokenv = NULL;
- + char *host = NULL;
- + int port;
- + int active;
- +
- + parse_buf = bb_xstrdup(opt);
- +
- + dprintf("multicast option=%s\n", opt);
- +
- + /* IP address */
- + if ((token = strtok_r(parse_buf, ",", &tokenv)) == NULL) {
- + dprintf("tftp_multicast_check: cannot parse IP address from %s\n", parse_buf);
- + free(parse_buf);
- + return 0;
- + }
- + if (strlen(token) > 0)
- + *phost = host = bb_xstrdup(token);
- +
- + /* Port */
- + if ((token = strtok_r(NULL, ",", &tokenv)) == NULL) {
- + dprintf("tftp_multicast_check: cannot parse port number from %s\n", tokenv);
- + goto token_error;
- + }
- + if (strlen(token) > 0) {
- + port = atoi(token);
- + if (port < 0 || port > 0xFFFF) {
- + dprintf("tftp_multicast_check: bad port number (%d)\n", port);
- + goto token_error;
- + }
- + *pport = htons(port);
- + }
- +
- + /* Active/passive */
- + if ((token = strtok_r(NULL, ",", &tokenv)) == NULL) {
- + dprintf("tftp_multicast_check: cannot parse active/passive from %s\n", tokenv);
- + goto token_error;
- + }
- + active = atoi(token);
- + if (active != 0 && active != 1) {
- + dprintf("tftp_multicast_check: bad active/passive flag (%d)\n", active);
- + goto token_error;
- + }
- + *pactive = active;
- +
- + free(parse_buf);
- + return 1;
- +
- +token_error:
- + free(parse_buf);
- + if (host != NULL)
- + free(host);
- + *phost = NULL;
- + return 0;
- +
- +}
- +
- +#define VECTOR_QUANTUM_WIDTH 8
- +#define VECTOR_QUANTUM_ALL_ONES ((1<<VECTOR_QUANTUM_WIDTH)-1)
- +
- +static void inline
- +bit_set(int bit, unsigned char *vector)
- +{
- + int offset = bit / VECTOR_QUANTUM_WIDTH;
- + int mask = 1 << (bit % VECTOR_QUANTUM_WIDTH);
- + vector[offset] |= mask;
- +}
- +
- +static int inline
- +bit_isset(int bit, const unsigned char *vector)
- +{
- + int offset = bit / VECTOR_QUANTUM_WIDTH;
- + int mask = 1 << (bit % VECTOR_QUANTUM_WIDTH);
- + return vector[offset] & mask ? 1 : 0;
- +}
- +
- +static int inline
- +bit_lmz(const unsigned char *vector)
- +{
- + /* Return number of left-most zero in bit vector */
- + const unsigned char *vp = vector;
- + int i;
- + unsigned char velem;
- +
- + while (*vp == VECTOR_QUANTUM_ALL_ONES)
- + vp++;
- + velem = *vp;
- + for (i = 0; i < VECTOR_QUANTUM_WIDTH; i++) {
- + if ((velem & (1 << i)) == 0)
- + break;
- + }
- + dprintf("bit_lmz: block=%d\n", (vp - vector)*VECTOR_QUANTUM_WIDTH + i);
- + return (vp - vector)*VECTOR_QUANTUM_WIDTH + i;
- +}
- +
- +#endif
- +
- +
- +
- +#ifdef TFTP_OPTIONS
- +
- static char *tftp_option_get(char *buf, int len, char *option)
- {
- - int opt_val = 0;
- + int opt_val = 0;
- int opt_found = 0;
- int k;
- -
- - while (len > 0) {
- + while (len > 0) {
- /* Make sure the options are terminated correctly */
- -
- for (k = 0; k < len; k++) {
- if (buf[k] == '\0') {
- break;
- @@ -117,9 +298,8 @@
- if (strcasecmp(buf, option) == 0) {
- opt_found = 1;
- }
- - }
- - else {
- - if (opt_found) {
- + } else {
- + if (opt_found) {
- return buf;
- }
- }
- @@ -138,7 +318,8 @@
- #endif
- static inline int tftp(const int cmd, const struct hostent *host,
- - const char *remotefile, int localfd, const unsigned short port, int tftp_bufsize)
- + const char *remotefile, int localfd, const unsigned short port,
- + struct tftp_option *option)
- {
- const int cmd_get = cmd & tftp_cmd_get;
- const int cmd_put = cmd & tftp_cmd_put;
- @@ -155,18 +336,29 @@
- int len;
- int opcode = 0;
- int finished = 0;
- - int timeout = bb_tftp_num_retries;
- + int retry = bb_tftp_num_retries;
- unsigned short block_nr = 1;
- -#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
- - int want_option_ack = 0;
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + struct hostent *mchost;
- + struct sockaddr_in mcsa;
- + char *mchostname;
- + unsigned short mcport;
- + unsigned char *mcblockmap = NULL;
- + int master_client = 1;
- + int mcfd = -1;
- + int mcmaxblock = 0x10000;
- + int ack_oack = 0;
- +#else
- + #define master_client 1
- + #define ack_oack 0
- #endif
- /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
- * size varies meaning BUFFERS_GO_ON_STACK would fail */
- - char *buf=xmalloc(tftp_bufsize + 4);
- + char *buf=xmalloc(option->blksize + 4);
- - tftp_bufsize += 4;
- + int tftp_bufsize = option->blksize + 4;
- if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
- bb_perror_msg("socket");
- @@ -183,15 +375,21 @@
- memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
- sizeof(sa.sin_addr));
- - /* build opcode */
- -
- - if (cmd_get) {
- - opcode = TFTP_RRQ;
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + if (option->multicast) {
- + const int bmsize = 0x10000 / VECTOR_QUANTUM_WIDTH;
- + if ((mcfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
- + bb_perror_msg("multicast socket");
- + return EXIT_FAILURE;
- + }
- + mcblockmap = xmalloc(bmsize+1);
- + memset(mcblockmap, 0, bmsize+1);
- }
- +#endif
- - if (cmd_put) {
- - opcode = TFTP_WRQ;
- - }
- + /* build opcode */
- +
- + opcode = cmd_get ? TFTP_RRQ : TFTP_WRQ;
- while (1) {
- @@ -203,7 +401,7 @@
- cp += 2;
- - /* add filename and mode */
- + /* First packet of file transfer includes file name, mode, and options */
- if ((cmd_get && (opcode == TFTP_RRQ)) ||
- (cmd_put && (opcode == TFTP_WRQ))) {
- @@ -223,7 +421,7 @@
- }
- if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) {
- - bb_error_msg("too long remote-filename");
- + bb_error_msg("too long: remote filename");
- break;
- }
- @@ -238,8 +436,8 @@
- if (len != TFTP_BLOCKSIZE_DEFAULT) {
- - if ((&buf[tftp_bufsize - 1] - cp) < 15) {
- - bb_error_msg("too long remote-filename");
- + if ((&buf[tftp_bufsize - 1] - cp) < 15) {
- + bb_error_msg("buffer too small for blksize option");
- break;
- }
- @@ -249,16 +447,65 @@
- cp += 8;
- cp += snprintf(cp, 6, "%d", len) + 1;
- + }
- +#endif
- +
- +
- +
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- +
- + if (option->multicast) {
- + if ((&buf[tftp_bufsize - 1] - cp) < 12) {
- + bb_error_msg("buffer too small for multicast option");
- + break;
- + }
- +
- + /* add "multicast" option */
- - want_option_ack = 1;
- + memcpy(cp, "multicast\0", 11);
- + cp += 11;
- +
- + option->multicast = 0; /* turn back on when server accepts option */
- + ack_oack = 1; /* acknowledge OACK */
- }
- +
- #endif
- +
- +#ifdef CONFIG_FEATURE_TFTP_TIMEOUT
- +
- + if (option->server_timeout != TFTP_TIMEOUT) {
- + if ((&buf[tftp_bufsize - 1] - cp) < 12) {
- + bb_error_msg("buffer too small for timeout option");
- + break;
- + }
- +
- + /* add "timeout" option */
- +
- + memcpy(cp, "timeout", 8);
- + cp += 8;
- +
- + cp += snprintf(cp, 4, "%d", option->server_timeout) + 1;
- + }
- +#endif
- +
- }
- /* add ack and data */
- - if ((cmd_get && (opcode == TFTP_ACK)) ||
- - (cmd_put && (opcode == TFTP_DATA))) {
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + else if (option->multicast && opcode == TFTP_ACK) {
- + if (master_client || ack_oack) {
- + int blocknum = bit_lmz(mcblockmap);
- + *((unsigned short *) cp) = htons(blocknum);
- + cp += 2;
- + if (blocknum >= mcmaxblock)
- + finished = 1;
- + dprintf("ack block %d/%d %s\n", blocknum, mcmaxblock, finished? "finished": "");
- + }
- + }
- +#endif
- + else if ((cmd_get && opcode == TFTP_ACK) ||
- + (cmd_put && opcode == TFTP_DATA)) {
- *((unsigned short *) cp) = htons(block_nr);
- @@ -275,7 +522,7 @@
- }
- if (len != (tftp_bufsize - 4)) {
- - finished++;
- + finished = 1;
- }
- cp += len;
- @@ -283,82 +530,119 @@
- }
- - /* send packet */
- + /* send packet and receive reply */
- - timeout = bb_tftp_num_retries; /* re-initialize */
- + retry = bb_tftp_num_retries; /* re-initialize */
- do {
- -
- + int selectrc;
- len = cp - buf;
- -#ifdef CONFIG_FEATURE_TFTP_DEBUG
- - fprintf(stderr, "sending %u bytes\n", len);
- - for (cp = buf; cp < &buf[len]; cp++)
- - fprintf(stderr, "%02x ", (unsigned char)*cp);
- - fprintf(stderr, "\n");
- -#endif
- - if (sendto(socketfd, buf, len, 0,
- - (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- - bb_perror_msg("send");
- - len = -1;
- - break;
- - }
- -
- + /* send packet */
- + if ((len > 2) && (! option->multicast || master_client || ack_oack)) {
- - if (finished && (opcode == TFTP_ACK)) {
- - break;
- +#ifdef CONFIG_FEATURE_TFTP_DEBUG
- + dprintf("sending %u bytes\n", len);
- + for (cp = buf; cp < &buf[len]; cp++)
- + if (debug)
- + printf("%02x ", *(unsigned char *)cp);
- + if (debug)
- + printf("\n");
- +#endif
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + ack_oack = 0;
- +#endif
- + if (sendto(socketfd, buf, len, 0, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
- + bb_perror_msg("send");
- + len = -1;
- + break;
- + }
- + if (finished && opcode == TFTP_ACK) {
- + break;
- + }
- }
- - /* receive packet */
- + /* receive reply packet */
- memset(&from, 0, sizeof(from));
- fromlen = sizeof(from);
- - tv.tv_sec = TFTP_TIMEOUT;
- + tv.tv_sec = option->client_timeout;
- tv.tv_usec = 0;
- FD_ZERO(&rfds);
- FD_SET(socketfd, &rfds);
- + dprintf("set to receive from socketfd (%d)\n", socketfd);
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + if (option->multicast) {
- + FD_SET(mcfd, &rfds);
- + dprintf("set to receive from mcfd (%d)\n", mcfd);
- + }
- +#endif
- - switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
- - case 1:
- - len = recvfrom(socketfd, buf, tftp_bufsize, 0,
- - (struct sockaddr *) &from, &fromlen);
- -
- - if (len < 0) {
- - bb_perror_msg("recvfrom");
- - break;
- + dprintf("select\n");
- + selectrc = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
- + if (selectrc > 0) {
- + /* A packet was received */
- + if (FD_ISSET(socketfd, &rfds)) { /* Unicast packet */
- + dprintf("from socketfd\n");
- + len = recvfrom(socketfd, buf, tftp_bufsize, 0, (struct sockaddr *) &from, &fromlen);
- +
- + if (len < 0) {
- + bb_perror_msg("recvfrom");
- + } else {
- + if (sa.sin_port == port) {
- + sa.sin_port = from.sin_port;
- + }
- + if (sa.sin_port == from.sin_port) {
- + retry = 0;
- + } else {
- + /* bad packet */
- + /* discard the packet - treat as timeout */
- + retry = bb_tftp_num_retries;
- + bb_error_msg("timeout");
- + }
- + }
- }
- - timeout = 0;
- -
- - if (sa.sin_port == port) {
- - sa.sin_port = from.sin_port;
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + else if (option->multicast && FD_ISSET(mcfd, &rfds)) { /* Multicast packet */
- + dprintf("from mcfd\n");
- + len = recvfrom(mcfd, buf, tftp_bufsize, 0, (struct sockaddr *) &from, &fromlen);
- + if (len < 0) {
- + bb_perror_msg("multicast recvfrom");
- + } else {
- + if (mcsa.sin_port == mcport) {
- + mcsa.sin_port = from.sin_port;
- + }
- + if (mcsa.sin_port == from.sin_port) {
- + retry = 0;
- + } else {
- + retry = bb_tftp_num_retries;
- + bb_error_msg("multicast timeout");
- + }
- + }
- }
- - if (sa.sin_port == from.sin_port) {
- - break;
- - }
- -
- - /* fall-through for bad packets! */
- - /* discard the packet - treat as timeout */
- - timeout = bb_tftp_num_retries;
- +#endif
- - case 0:
- + } else if (selectrc == 0) {
- + /* Time out */
- + dprintf("timeout\n");
- bb_error_msg("timeout");
- - timeout--;
- - if (timeout == 0) {
- + retry--;
- + if (retry == 0) {
- len = -1;
- bb_error_msg("last timeout");
- }
- - break;
- -
- - default:
- + } else {
- + /* Error condition */
- + dprintf("error\n");
- bb_perror_msg("select");
- len = -1;
- }
- - } while (timeout && (len >= 0));
- + } while (retry && len >= 0);
- if ((finished) || (len < 0)) {
- break;
- @@ -370,9 +654,8 @@
- opcode = ntohs(*((unsigned short *) buf));
- tmp = ntohs(*((unsigned short *) &buf[2]));
- -#ifdef CONFIG_FEATURE_TFTP_DEBUG
- - fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
- -#endif
- + dprintf("received %d bytes: %04x %04x\n", len, opcode, tmp);
- + dprintf("master_client=%d\n", master_client);
- if (opcode == TFTP_ERROR) {
- char *msg = NULL;
- @@ -393,55 +676,116 @@
- break;
- }
- -#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
- - if (want_option_ack) {
- +#ifdef TFTP_OPTIONS
- - want_option_ack = 0;
- + if (opcode == TFTP_OACK) {
- - if (opcode == TFTP_OACK) {
- + /* server seems to support options */
- - /* server seems to support options */
- + char *res;
- +
- + block_nr = 0; /* acknowledge option packet with block number 0 */
- + opcode = cmd_put ? TFTP_DATA : TFTP_ACK;
- - char *res;
- - res = tftp_option_get(&buf[2], len-2,
- - "blksize");
- +#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
- + res = tftp_option_get(&buf[2], len-2, "blksize");
- - if (res) {
- - int blksize = atoi(res);
- -
- - if (tftp_blocksize_check(blksize,
- - tftp_bufsize - 4)) {
- + if (res) {
- + int blksize = atoi(res);
- - if (cmd_put) {
- - opcode = TFTP_DATA;
- - }
- - else {
- - opcode = TFTP_ACK;
- - }
- -#ifdef CONFIG_FEATURE_TFTP_DEBUG
- - fprintf(stderr, "using blksize %u\n", blksize);
- + if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
- + dprintf("using blksize %d\n", blksize);
- + tftp_bufsize = blksize + 4;
- + free(buf);
- + buf = xmalloc(tftp_bufsize);
- + } else {
- + bb_error_msg("bad blksize %d", blksize);
- + break;
- + }
- + }
- #endif
- - tftp_bufsize = blksize + 4;
- - block_nr = 0;
- - continue;
- - }
- - }
- - /* FIXME:
- - * we should send ERROR 8 */
- - bb_error_msg("bad server option");
- - break;
- - }
- - bb_error_msg("warning: blksize not supported by server"
- - " - reverting to 512");
- - tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + res = tftp_option_get(&buf[2], len-2, "multicast");
- +
- + if (res) {
- + ack_oack = 1;
- + if (tftp_multicast_check(res, &mchostname, &mcport, &master_client)) {
- + struct ip_mreq mreq;
- + struct in_addr mcaddr;
- +
- + dprintf("using multicast\n");
- +
- + mchost = xgethostbyname(mchostname);
- + if (mchost) {
- + memcpy(&mcaddr, mchost->h_addr, mchost->h_length);
- + if (! IN_MULTICAST(ntohl(mcaddr.s_addr))) {
- + bb_error_msg("bad multicast address: %s", mchostname);
- + break;
- + }
- + } else {
- + bb_error_msg("bad multicast address: %s", mchostname);
- + break;
- + }
- +
- + memset(&mcsa, 0, sizeof(mcsa));
- + mcsa.sin_family = AF_INET;
- + mcsa.sin_addr.s_addr = htonl(INADDR_ANY);
- + mcsa.sin_port = mcport;
- +
- + bind(mcfd, (struct sockaddr *)&mcsa, sizeof(mcsa));
- +
- + mreq.imr_multiaddr.s_addr = mcaddr.s_addr;
- + mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- +
- + if (setsockopt(mcfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
- + {
- + bb_error_msg("setsockopt");
- + break;
- + }
- +
- + option->multicast = 1;
- + } else {
- + bb_error_msg("bad multicast option value: %s", res);
- + break;
- + }
- + }
- +#endif
- +
- }
- + else
- #endif
- if (cmd_get && (opcode == TFTP_DATA)) {
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + if (option->multicast) {
- + int bn = tmp - 1;
- + /* Do I need this block? */
- + if (! bit_isset(bn, mcblockmap)) {
- + lseek(localfd, bn*(tftp_bufsize-4), SEEK_SET);
- + len = write(localfd, &buf[4], len-4);
- + if (len < 0) {
- + bb_perror_msg("write");
- + break;
- + }
- + bit_set(bn, mcblockmap);
- + if (len != (tftp_bufsize-4)) {
- + mcmaxblock = tmp;
- + dprintf("mcmaxblock=%d, (len(%d) != tftp_bufsize-4(%d))\n", mcmaxblock, len, tftp_bufsize-4);
- + }
- + opcode = TFTP_ACK;
- + }
- + /* Do not acknowledge block if I already have a copy of the block. A situation can arise when the server
- + * and client timeout nearly simultaneously. The server retransmits the block at the same time the client
- + * re-requests the block. From then on out, each block is transmitted twice--not a good use of bandwidth.
- + */
- + }
- + else
- +#endif
- +
- if (tmp == block_nr) {
-
- len = write(localfd, &buf[4], len - 4);
- @@ -452,15 +796,14 @@
- }
- if (len != (tftp_bufsize - 4)) {
- - finished++;
- + finished = 1;
- }
- opcode = TFTP_ACK;
- - continue;
- }
- }
- - if (cmd_put && (opcode == TFTP_ACK)) {
- + else if (cmd_put && opcode == TFTP_ACK) {
- if (tmp == (unsigned short)(block_nr - 1)) {
- if (finished) {
- @@ -468,15 +811,19 @@
- }
- opcode = TFTP_DATA;
- - continue;
- }
- }
- }
- #ifdef CONFIG_FEATURE_CLEAN_UP
- close(socketfd);
- + free(buf);
- +
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + if (mcblockmap != NULL)
- + free(mcblockmap);
- +#endif
- - free(buf);
- #endif
- return finished ? EXIT_SUCCESS : EXIT_FAILURE;
- @@ -487,13 +834,18 @@
- struct hostent *host = NULL;
- char *localfile = NULL;
- char *remotefile = NULL;
- - int port;
- + unsigned short port;
- int cmd = 0;
- int fd = -1;
- int flags = 0;
- int opt;
- int result;
- - int blocksize = TFTP_BLOCKSIZE_DEFAULT;
- + struct tftp_option option = {
- + .multicast = 0,
- + .blksize = TFTP_BLOCKSIZE_DEFAULT,
- + .client_timeout = TFTP_TIMEOUT,
- + .server_timeout = TFTP_TIMEOUT,
- + };
- /* figure out what to pass to getopt */
- @@ -515,13 +867,45 @@
- #define PUT
- #endif
- - while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
- +#ifdef CONFIG_FEATURE_TFTP_TIMEOUT
- +#define TO "T:t:"
- +#else
- +#define TO
- +#endif
- +
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- +#define MC "m"
- +#else
- +#define MC
- +#endif
- +
- +#ifdef CONFIG_FEATURE_TFTP_DEBUG
- +#define DB "D"
- +#else
- +#define DB
- +#endif
- +
- + while ((opt = getopt(argc, argv, BS GET PUT TO MC DB "l:r:")) != -1) {
- switch (opt) {
- #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
- case 'b':
- - blocksize = atoi(optarg);
- - if (!tftp_blocksize_check(blocksize, 0)) {
- - return EXIT_FAILURE;
- + option.blksize = atoi(optarg);
- + if (!tftp_blocksize_check(option.blksize, 0)) {
- + return EXIT_FAILURE;
- + }
- + break;
- +#endif
- +#ifdef CONFIG_FEATURE_TFTP_TIMEOUT
- + case 'T':
- + option.client_timeout = atoi(optarg);
- + if (!tftp_timeout_check(option.client_timeout)) {
- + return EXIT_FAILURE;
- + }
- + break;
- + case 't':
- + option.server_timeout = atoi(optarg);
- + if (!tftp_timeout_check(option.server_timeout)) {
- + return EXIT_FAILURE;
- }
- break;
- #endif
- @@ -537,18 +921,34 @@
- flags = O_RDONLY;
- break;
- #endif
- +#ifdef CONFIG_FEATURE_TFTP_MULTICAST
- + case 'm':
- + option.multicast = 1; /* receive multicast file */
- + break;
- +#endif
- +#ifdef CONFIG_FEATURE_TFTP_DEBUG
- + case 'D':
- + debug = 1;
- + break;
- +#endif
- case 'l':
- localfile = bb_xstrdup(optarg);
- break;
- case 'r':
- remotefile = bb_xstrdup(optarg);
- break;
- + default:
- + bb_show_usage();
- }
- }
- if ((cmd == 0) || (optind == argc)) {
- bb_show_usage();
- }
- + if (cmd == tftp_cmd_put && option.multicast) {
- + fprintf(stderr, "Multicast (-m) invalid option with put (-p) command\n");
- + exit(EXIT_FAILURE);
- + }
- if(localfile && strcmp(localfile, "-") == 0) {
- fd = fileno((cmd==tftp_cmd_get)? stdout : stdin);
- }
- @@ -566,14 +966,12 @@
- host = xgethostbyname(argv[optind]);
- port = bb_lookup_port(argv[optind + 1], "udp", 69);
- -#ifdef CONFIG_FEATURE_TFTP_DEBUG
- - fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
- + dprintf("using server \"%s\", remotefile \"%s\", "
- "localfile \"%s\".\n",
- inet_ntoa(*((struct in_addr *) host->h_addr)),
- remotefile, localfile);
- -#endif
- - result = tftp(cmd, host, remotefile, fd, port, blocksize);
- + result = tftp(cmd, host, remotefile, fd, port, &option);
- #ifdef CONFIG_FEATURE_CLEAN_UP
- if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
- @@ -582,3 +980,18 @@
- #endif
- return(result);
- }
- +
- +
- +#ifdef CONFIG_FEATURE_TFTP_DEBUG
- +
- +#include <sys/time.h>
- +
- +static void
- +printtime(void)
- +{
- + struct timeval tv;
- + gettimeofday(&tv, NULL);
- + printf("%11lu.%06lu ", tv.tv_sec, tv.tv_usec);
- +}
- +
- +#endif
|