aboutsummaryrefslogtreecommitdiffstats
path: root/ftp/atftp
diff options
context:
space:
mode:
authorkevlo <kevlo@FreeBSD.org>2010-10-11 13:46:21 +0800
committerkevlo <kevlo@FreeBSD.org>2010-10-11 13:46:21 +0800
commit4d6b849dd2bce8d2c5ff66264f1f114263393127 (patch)
tree28795a8f236e8d00e5943d140a8091eaad709520 /ftp/atftp
parent28762757639963da6eda436b0b409595d8105b78 (diff)
downloadfreebsd-ports-graphics-4d6b849dd2bce8d2c5ff66264f1f114263393127.tar.gz
freebsd-ports-graphics-4d6b849dd2bce8d2c5ff66264f1f114263393127.tar.zst
freebsd-ports-graphics-4d6b849dd2bce8d2c5ff66264f1f114263393127.zip
Missed multicast fix patches in previous commit
Diffstat (limited to 'ftp/atftp')
-rw-r--r--ftp/atftp/Makefile1
-rw-r--r--ftp/atftp/files/patch-options.c15
-rw-r--r--ftp/atftp/files/patch-options.h11
-rw-r--r--ftp/atftp/files/patch-tftp.c93
-rw-r--r--ftp/atftp/files/patch-tftp_def.c17
-rw-r--r--ftp/atftp/files/patch-tftp_file.c68
-rw-r--r--ftp/atftp/files/patch-tftp_io.c35
-rw-r--r--ftp/atftp/files/patch-tftpd.c50
-rw-r--r--ftp/atftp/files/patch-tftpd.h14
-rw-r--r--ftp/atftp/files/patch-tftpd_file.c353
-rw-r--r--ftp/atftp/files/patch-tftpd_list.c45
-rw-r--r--ftp/atftp/files/patch-tftpd_mtftp.c40
12 files changed, 624 insertions, 118 deletions
diff --git a/ftp/atftp/Makefile b/ftp/atftp/Makefile
index 54c63e43cd5..18c6919b327 100644
--- a/ftp/atftp/Makefile
+++ b/ftp/atftp/Makefile
@@ -7,6 +7,7 @@
PORTNAME= atftp
PORTVERSION= 0.7
+PORTREVISION= 1
CATEGORIES= ftp
MASTER_SITES= ${MASTER_SITE_DEBIAN}
MASTER_SITE_SUBDIR= pool/main/a/${PORTNAME}
diff --git a/ftp/atftp/files/patch-options.c b/ftp/atftp/files/patch-options.c
new file mode 100644
index 00000000000..fd96417175f
--- /dev/null
+++ b/ftp/atftp/files/patch-options.c
@@ -0,0 +1,15 @@
+--- options.c.orig 2003-04-25 08:16:18.000000000 +0800
++++ options.c 2010-10-11 10:23:20.000000000 +0800
+@@ -273,6 +273,12 @@
+ return ERR;
+ }
+
++int opt_equal(struct tftp_opt *opt1, struct tftp_opt *opt2)
++{
++ return ((strncmp(opt1->option, opt2->option, OPT_SIZE) == 0) &&
++ (strncmp(opt1->value, opt2->value, OPT_SIZE) == 0));
++}
++
+ void opt_set_tsize(int tsize, struct tftp_opt *options)
+ {
+ snprintf(options[OPT_TSIZE].value, VAL_SIZE, "%d", tsize);
diff --git a/ftp/atftp/files/patch-options.h b/ftp/atftp/files/patch-options.h
new file mode 100644
index 00000000000..09e2acff81a
--- /dev/null
+++ b/ftp/atftp/files/patch-options.h
@@ -0,0 +1,11 @@
+--- options.h.orig 2001-07-07 07:35:18.000000000 +0800
++++ options.h 2010-10-11 13:11:41.000000000 +0800
+@@ -39,6 +39,8 @@
+ int opt_get_timeout(struct tftp_opt *options);
+ int opt_get_blksize(struct tftp_opt *options);
+ int opt_get_multicast(struct tftp_opt *options, char *addr, int *port, int *mc);
++int opt_equal(struct tftp_opt *opt1, struct tftp_opt *opt2);
++int opt_same_file(struct tftp_opt *opt1, struct tftp_opt *opt2);
+ void opt_set_tsize(int tsize, struct tftp_opt *options);
+ void opt_set_timeout(int timeout, struct tftp_opt *options);
+ void opt_set_blksize(int blksize, struct tftp_opt *options);
diff --git a/ftp/atftp/files/patch-tftp.c b/ftp/atftp/files/patch-tftp.c
index 3b1a356e38e..a66573d3d22 100644
--- a/ftp/atftp/files/patch-tftp.c
+++ b/ftp/atftp/files/patch-tftp.c
@@ -1,5 +1,5 @@
---- tftp.c.orig 2010-10-05 09:35:38.000000000 +0800
-+++ tftp.c 2010-10-05 09:42:03.000000000 +0800
+--- tftp.c.orig 2010-10-11 11:19:25.000000000 +0800
++++ tftp.c 2010-10-11 11:19:12.000000000 +0800
@@ -354,7 +354,7 @@
void make_arg(char *string, int *argc, char ***argv)
{
@@ -9,7 +9,88 @@
/* split the string to an argz vector */
if (argz_create_sep(string, ' ', &tmp, &argz_len) != 0)
-@@ -608,9 +608,16 @@
+@@ -408,8 +408,7 @@
+ */
+ int set_peer(int argc, char **argv)
+ {
+- struct hostent *host; /* for host name lookup */
+- struct servent *sp; /* server entry for tftp service */
++ int port = -1;
+
+ /* sanity check */
+ if ((argc < 2) || (argc > 3))
+@@ -418,13 +417,34 @@
+ return ERR;
+ }
+
+- /* get the server entry */
+- sp = getservbyname("tftp", "udp");
+- if (sp == 0) {
+- fprintf(stderr, "tftp: udp/tftp, unknown service.\n");
+- return ERR;
++ /* get the server port */
++ if (argc == 3)
++ {
++ port = htons(atoi(argv[2]));
++ if (port < 0)
++ {
++ fprintf(stderr, "%s: bad port number.\n", argv[2]);
++ data.connected = 0;
++ return ERR;
++ }
++ data.sa_peer.sin_port = port;
++ }
++ else
++ {
++ /* get the server entry */
++ struct servent *sp;
++ sp = getservbyname("tftp", "udp");
++ if (sp == 0) {
++ fprintf(stderr, "tftp: udp/tftp, unknown service.\n");
++ return ERR;
++ }
++ else
++ {
++ port = sp->s_port;
++ }
+ }
+
++ struct hostent *host; /* for host name lookup */
+ /* look up the host */
+ host = gethostbyname(argv[1]);
+ /* if valid, update s_inn structure */
+@@ -437,7 +457,7 @@
+ Strncpy(data.hostname, host->h_name,
+ sizeof(data.hostname));
+ data.hostname[sizeof(data.hostname)-1] = 0;
+- data.sa_peer.sin_port = sp->s_port;
++ data.sa_peer.sin_port = port;
+ }
+ else
+ {
+@@ -445,20 +465,8 @@
+ data.connected = 0;
+ return ERR;
+ }
+- /* get the server port */
+- if (argc == 3)
+- {
+- sp->s_port = htons(atoi(argv[2]));
+- if (sp->s_port < 0)
+- {
+- fprintf(stderr, "%s: bad port number.\n", argv[2]);
+- data.connected = 0;
+- return ERR;
+- }
+- data.sa_peer.sin_port = sp->s_port;
+- }
+ /* copy port number to data structure */
+- data.port = ntohs(sp->s_port);
++ data.port = ntohs(port);
+
+ data.connected = 1;
+ return OK;
+@@ -608,9 +616,16 @@
exit(ERR);
}
memset(&data.sa_local, 0, sizeof(data.sa_local));
@@ -29,7 +110,7 @@
/* do the transfer */
gettimeofday(&data.start_time, NULL);
-@@ -621,7 +628,7 @@
+@@ -621,7 +636,7 @@
fsync(data.sockfd);
close(data.sockfd);
@@ -38,7 +119,7 @@
}
/*
-@@ -712,9 +719,16 @@
+@@ -712,9 +727,16 @@
exit(ERR);
}
memset(&data.sa_local, 0, sizeof(data.sa_local));
@@ -58,7 +139,7 @@
/* do the transfer */
gettimeofday(&data.start_time, NULL);
-@@ -731,7 +745,7 @@
+@@ -731,7 +753,7 @@
fsync(data.sockfd);
close(data.sockfd);
diff --git a/ftp/atftp/files/patch-tftp_def.c b/ftp/atftp/files/patch-tftp_def.c
index a56e5ee8470..f1e0eb61379 100644
--- a/ftp/atftp/files/patch-tftp_def.c
+++ b/ftp/atftp/files/patch-tftp_def.c
@@ -1,15 +1,20 @@
---- tftp_def.c.orig 2010-10-05 09:43:06.000000000 +0800
-+++ tftp_def.c 2010-10-05 09:43:53.000000000 +0800
-@@ -140,8 +140,10 @@
+--- tftp_def.c.orig 2010-10-11 11:20:48.000000000 +0800
++++ tftp_def.c 2010-10-11 11:20:40.000000000 +0800
+@@ -140,11 +140,14 @@
*/
inline char *Strncpy(char *to, const char *from, size_t size)
{
- to[size-1] = '\000';
- return strncpy(to, from, size - 1);
-+ strncpy(to, from, size);
+ if (size > 0)
++ {
+ to[size-1] = '\000';
-+ return to;
++ return strncpy(to, from, size - 1);
++ } else
++ return to;
}
-
+-
+ /*
+ * gethostbyname replacement that is reentrant. This function is copyied
+ * from the libc manual.
diff --git a/ftp/atftp/files/patch-tftp_file.c b/ftp/atftp/files/patch-tftp_file.c
index 59b08f46739..8f2e1931393 100644
--- a/ftp/atftp/files/patch-tftp_file.c
+++ b/ftp/atftp/files/patch-tftp_file.c
@@ -1,5 +1,5 @@
---- tftp_file.c.orig 2004-02-13 11:16:09.000000000 +0800
-+++ tftp_file.c 2010-10-04 18:46:54.000000000 +0800
+--- tftp_file.c.orig 2010-10-11 11:21:54.000000000 +0800
++++ tftp_file.c 2010-10-11 11:27:01.000000000 +0800
@@ -59,7 +59,7 @@
unsigned int next_word;
@@ -9,17 +9,7 @@
next_word_no = next_hole / 32;
next_bit_no = next_hole % 32;
next_word = bitmap[next_word_no];
-@@ -150,7 +150,8 @@
- memset(&file_bitmap, 0, sizeof(file_bitmap));
-
- /* make sure the socket is not connected */
-- sa.sin_family = AF_UNSPEC;
-+ memset(&sa, 0, sizeof(sa));
-+ sa.sin_family = AF_INET;
- connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
- connected = 0;
-
-@@ -238,9 +239,13 @@
+@@ -238,9 +238,13 @@
tftp_find_bitmap_hole(prev_bitmap_hole, file_bitmap);
block_number = prev_bitmap_hole;
}
@@ -27,40 +17,26 @@
- fprintf(stderr, "sent ACK <block: %d>\n", block_number);
- tftp_send_ack(sockfd, &sa, block_number);
+ result = tftp_send_ack(sockfd, &sa, block_number);
-+ if (result == OK)
-+ {
-+ if (data->trace)
-+ fprintf(stderr, "sent ACK <block: %d>\n",
-+ block_number);
++ if (result == OK)
++ {
++ if (data->trace)
++ fprintf(stderr, "sent ACK <block: %d>\n",
++ block_number);
+ }
/* if we just ACK the last block we are done */
if (block_number == last_block_number)
state = S_END;
-@@ -627,7 +632,8 @@
- from.sin_addr.s_addr = 0;
-
- /* make sure the socket is not connected */
-- sa.sin_family = AF_UNSPEC;
-+ memset(&sa, 0, sizeof(sa));
-+ sa.sin_family = AF_INET;
- connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
- connected = 0;
-
-@@ -761,7 +767,7 @@
- /* if the socket if not connected, connect it */
- if (!connected)
- {
-- //connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
-+ connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
- connected = 1;
- }
- block_number = ntohs(tftphdr->th_block);
-@@ -780,7 +786,7 @@
- /* if the socket if not connected, connect it */
- if (!connected)
- {
-- //connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
-+ connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
- connected = 1;
- }
- state = S_OACK_RECEIVED;
+@@ -484,6 +488,13 @@
+ sa_mcast.sin_family = AF_INET;
+ sa_mcast.sin_addr.s_addr = htonl(INADDR_ANY);
+ sa_mcast.sin_port = htons(mc_port);
++ int yes = 1;
++ if (setsockopt(mcast_sockfd, SOL_SOCKET,
++ SO_REUSEADDR, &yes, sizeof(yes)) < 0)
++ {
++ perror("setsockopt");
++ exit(1);
++ }
+
+ if (bind(mcast_sockfd, (struct sockaddr *)&sa_mcast,
+ sizeof(sa_mcast)) < 0)
diff --git a/ftp/atftp/files/patch-tftp_io.c b/ftp/atftp/files/patch-tftp_io.c
index 1c2672e978f..28bf686a7af 100644
--- a/ftp/atftp/files/patch-tftp_io.c
+++ b/ftp/atftp/files/patch-tftp_io.c
@@ -1,39 +1,44 @@
--- tftp_io.c.orig 2004-02-19 09:30:00.000000000 +0800
-+++ tftp_io.c 2010-10-04 18:45:56.000000000 +0800
-@@ -102,8 +102,8 @@
- tftphdr.th_opcode = htons(ACK);
++++ tftp_io.c 2010-10-11 13:01:28.000000000 +0800
+@@ -103,7 +103,8 @@
tftphdr.th_block = htons(block_number);
-- result = sendto(socket, &tftphdr, 4, 0, (struct sockaddr *)sa,
+ result = sendto(socket, &tftphdr, 4, 0, (struct sockaddr *)sa,
- sizeof(*sa));
-+ result = write(socket, &tftphdr, 4);
++ sizeof(*sa));
+
if (result < 0)
return ERR;
return OK;
-@@ -141,8 +141,8 @@
- }
+@@ -142,7 +143,8 @@
}
/* send the buffer */
-- result = sendto(socket, buffer, index, 0, (struct sockaddr *)sa,
+ result = sendto(socket, buffer, index, 0, (struct sockaddr *)sa,
- sizeof(*sa));
-+ result = write(socket, buffer, index);
++ sizeof(*sa));
+
if (result < 0)
return ERR;
return OK;
-@@ -191,8 +191,8 @@
- tftphdr->th_opcode = htons(DATA);
+@@ -171,6 +173,7 @@
+
+ result = sendto(socket, tftphdr, size, 0, (struct sockaddr *)sa,
+ sizeof(*sa));
++
+ if (result < 0)
+ return ERR;
+ return OK;
+@@ -192,7 +195,8 @@
tftphdr->th_block = htons(block_number);
-- result = sendto(socket, data, size, 0, (struct sockaddr *)sa,
+ result = sendto(socket, data, size, 0, (struct sockaddr *)sa,
- sizeof(*sa));
-+ result = write(socket, data, size);
++ sizeof(*sa));
+
if (result < 0)
return ERR;
return OK;
-@@ -214,7 +214,6 @@
+@@ -214,7 +218,6 @@
struct msghdr msg; /* used to get client's packet info */
struct cmsghdr *cmsg;
@@ -41,7 +46,7 @@
struct iovec iov;
char cbuf[1024];
-@@ -284,11 +283,12 @@
+@@ -284,11 +287,12 @@
cmsg != NULL && cmsg->cmsg_len >= sizeof(*cmsg);
cmsg = CMSG_NXTHDR(&msg, cmsg))
{
diff --git a/ftp/atftp/files/patch-tftpd.c b/ftp/atftp/files/patch-tftpd.c
index 00d8c2a5768..b9b3f4f8a0c 100644
--- a/ftp/atftp/files/patch-tftpd.c
+++ b/ftp/atftp/files/patch-tftpd.c
@@ -1,5 +1,5 @@
---- tftpd.c.orig 2010-10-04 18:26:05.000000000 +0800
-+++ tftpd.c 2010-10-04 18:30:20.000000000 +0800
+--- tftpd.c.orig 2010-10-11 11:30:50.000000000 +0800
++++ tftpd.c 2010-10-11 11:31:42.000000000 +0800
@@ -60,6 +60,9 @@
char directory[MAXLEN] = "/tftpboot/";
int retry_timeout = S_TIMEOUT;
@@ -57,8 +57,13 @@
}
#ifdef RATE_CONTROL
-@@ -466,7 +478,7 @@
+@@ -463,10 +475,12 @@
+ exit(1);
+ }
+ new->client_info->done = 0;
++ new->client_info->bytes_sent = 0;
new->client_info->next = NULL;
++ new->client_info->last_ack = -1;
/* Start a new server thread. */
- if (pthread_create(&new->tid, NULL, tftpd_receive_request,
@@ -66,7 +71,7 @@
(void *)new) != 0)
{
logger(LOG_ERR, "Failed to start new thread");
-@@ -567,7 +579,8 @@
+@@ -567,7 +581,8 @@
/* Detach ourself. That way the main thread does not have to
* wait for us with pthread_join. */
@@ -76,7 +81,7 @@
/* Read the first packet from stdin. */
data_size = data->data_buffer_size;
-@@ -615,7 +628,25 @@
+@@ -615,7 +630,25 @@
data->sockfd = socket(PF_INET, SOCK_DGRAM, 0);
to.sin_family = AF_INET;
to.sin_port = 0;
@@ -99,11 +104,34 @@
+ logger(LOG_INFO, "socket may listen on any address, including broadcast");
+ }
+
-+ if (data->sockfd != -1)
++ if (data->sockfd >= 0)
{
/* bind the socket to the interface */
if (bind(data->sockfd, (struct sockaddr *)&to, len) == -1)
-@@ -732,8 +763,8 @@
+@@ -630,17 +663,14 @@
+ logger(LOG_ERR, "getsockname: %s", strerror(errno));
+ retval = ABORT;
+ }
+- /* connect the socket, faster for kernel operation */
+- if (connect(data->sockfd,
+- (struct sockaddr *)&data->client_info->client,
+- sizeof(data->client_info->client)) == -1)
+- {
+- logger(LOG_ERR, "connect: %s", strerror(errno));
+- retval = ABORT;
+- }
+ logger(LOG_DEBUG, "Creating new socket: %s:%d",
+ inet_ntoa(to.sin_addr), ntohs(to.sin_port));
+
++ /* save the dest ip address to bind multicast to correct
++ * interface
++ */
++ data->mcastaddr.imr_interface.s_addr = to.sin_addr.s_addr;
++
+ /* read options from request */
+ opt_parse_request(data->data_buffer, data_size,
+ data->tftp_options);
+@@ -732,8 +762,8 @@
tftpd_clientlist_free(data);
/* free the thread structure */
@@ -114,7 +142,7 @@
logger(LOG_INFO, "Server thread exiting");
pthread_exit(NULL);
}
-@@ -811,6 +842,7 @@
+@@ -811,6 +841,7 @@
{ "no-multicast", 0, NULL, 'M' },
{ "logfile", 1, NULL, 'L' },
{ "pidfile", 1, NULL, 'I'},
@@ -122,7 +150,7 @@
{ "daemon", 0, NULL, 'D' },
{ "no-fork", 0, NULL, 'N'},
{ "user", 1, NULL, 'U'},
-@@ -888,6 +920,9 @@
+@@ -888,6 +919,9 @@
case 'I':
pidfile = strdup(optarg);
break;
@@ -132,7 +160,7 @@
case 'D':
tftpd_daemon = 1;
break;
-@@ -1015,6 +1050,10 @@
+@@ -1015,6 +1049,10 @@
logger(LOG_INFO, " log file: %s", (log_file==NULL) ? "syslog":log_file);
if (pidfile)
logger(LOG_INFO, " pid file: %s", pidfile);
@@ -143,7 +171,7 @@
if (tftpd_daemon == 1)
logger(LOG_INFO, " server timeout: Not used");
else
-@@ -1111,11 +1150,12 @@
+@@ -1111,11 +1149,12 @@
" output messages\n"
" --trace : log all sent and received packets\n"
" --no-timeout : disable 'timeout' from RFC2349\n"
diff --git a/ftp/atftp/files/patch-tftpd.h b/ftp/atftp/files/patch-tftpd.h
new file mode 100644
index 00000000000..49b9794f301
--- /dev/null
+++ b/ftp/atftp/files/patch-tftpd.h
@@ -0,0 +1,14 @@
+--- tftpd.h.orig 2010-10-11 11:33:53.000000000 +0800
++++ tftpd.h 2010-10-11 11:34:33.000000000 +0800
+@@ -71,6 +71,11 @@
+ struct client_info {
+ struct sockaddr_in client;
+ int done; /* that client as receive it's file */
++ int bytes_sent;
++ int number_of_timeout; /* number of timeouts while sending to
++ * this client
++ */
++ int last_ack; /* last ACK received from this client */
+ struct client_info *next;
+ };
+
diff --git a/ftp/atftp/files/patch-tftpd_file.c b/ftp/atftp/files/patch-tftpd_file.c
index e11ad6aac6b..7f81c6935a4 100644
--- a/ftp/atftp/files/patch-tftpd_file.c
+++ b/ftp/atftp/files/patch-tftpd_file.c
@@ -1,6 +1,43 @@
---- tftpd_file.c.orig 2010-10-04 18:33:31.000000000 +0800
-+++ tftpd_file.c 2010-10-04 18:37:08.000000000 +0800
-@@ -240,9 +240,13 @@
+--- tftpd_file.c.orig 2004-02-18 10:21:47.000000000 +0800
++++ tftpd_file.c 2010-10-11 13:22:54.000000000 +0800
+@@ -89,6 +89,28 @@
+ return OK;
+ }
+
++int opt_same_file(struct tftp_opt *opt1, struct tftp_opt *opt2)
++{
++ if ((strncmp(opt1->option, "filename", OPT_SIZE) == 0) &&
++ (strncmp(opt2->option, "filename", OPT_SIZE) == 0))
++ {
++ char tofilename[MAXLEN];
++ char fromfilename[MAXLEN];
++ struct stat tostat;
++ struct stat fromstat;
++
++ Strncpy(tofilename, opt1->value, MAXLEN);
++ tftpd_rules_check(tofilename);
++ Strncpy(fromfilename, opt2->value, MAXLEN);
++ tftpd_rules_check(fromfilename);
++ if (stat(tofilename, &tostat) || stat(fromfilename, &fromstat))
++ return 0;
++
++ return (tostat.st_ino == fromstat.st_ino);
++ }
++ return 0;
++}
++
+ /*
+ * Receive a file. It is implemented as a state machine using a while loop
+ * and a switch statement. Function flow is as follow:
+@@ -117,7 +139,6 @@
+ char filename[MAXLEN];
+ char string[MAXLEN];
+ int timeout = data->timeout;
+- int number_of_timeout = 0;
+ int all_blocks_received = 0; /* temporary kludge */
+ int convert = 0; /* if true, do netascii convertion */
+
+@@ -240,9 +261,13 @@
break;
case S_SEND_ACK:
timeout_state = state;
@@ -8,30 +45,163 @@
- if (data->trace)
- logger(LOG_DEBUG, "sent ACK <block: %d>", block_number);
+ result = tftp_send_ack(sockfd, sa, block_number);
-+ if (result == OK)
-+ {
++ if (result == OK)
++ {
+ if (data->trace)
+ logger(LOG_DEBUG, "sent ACK <block: %d>",
-+ block_number);
++ block_number);
+ }
if (all_blocks_received)
state = S_END;
else
-@@ -660,8 +664,12 @@
- data->mc_port, 1);
+@@ -265,8 +290,8 @@
+ switch (result)
+ {
+ case GET_TIMEOUT:
+- number_of_timeout++;
+- if (number_of_timeout > NB_OF_RETRY)
++ data->client_info->number_of_timeout++;
++ if (data->client_info->number_of_timeout > NB_OF_RETRY)
+ {
+ logger(LOG_INFO, "client (%s) not responding",
+ inet_ntoa(data->client_info->client.sin_addr));
+@@ -322,7 +347,7 @@
+ else
+ logger(LOG_WARNING, "source port mismatch, check bypassed");
+ }
+- number_of_timeout = 0;
++ data->client_info->number_of_timeout = 0;
+ state = S_DATA_RECEIVED;
+ break;
+ case GET_DISCARD:
+@@ -413,13 +438,13 @@
+ char filename[MAXLEN];
+ char string[MAXLEN];
+ int timeout = data->timeout;
+- int number_of_timeout = 0;
+ int mcast_switch = data->mcast_switch_client;
+ struct stat file_stat;
+ int convert = 0; /* if true, do netascii conversion */
+ struct thread_data *thread = NULL; /* used when looking for a multicast
+ thread */
+ int multicast = 0; /* set to 1 if multicast */
++ time_t last_send_time = -1;
+
+ struct client_info *client_info = data->client_info;
+ struct client_info *client_old = NULL;
+@@ -428,6 +453,8 @@
+ int prev_block_number = 0; /* needed to support netascii convertion */
+ int prev_file_pos = 0;
+ int temp = 0;
++ int total_bytes_sent = 0;
++ int clients_served = 0;
+
+ /* look for mode option */
+ if (strcasecmp(data->tftp_options[OPT_MODE].value, "netascii") == 0)
+@@ -535,6 +562,34 @@
+ return ERR;
+ }
+
++ /* make sure that the oack packet will fit in the buffer */
++ int oacklen = 2;
++ int i;
++ for (i = 2; i < OPT_NUMBER; i++)
++ {
++ if (data->tftp_options[i].enabled &&
++ data->tftp_options[i].specified)
++ {
++ oacklen += strlen(data->tftp_options[i].option);
++ oacklen++;
++ oacklen += strlen(data->tftp_options[i].value);
++ oacklen++;
++ }
++ }
++
++ if (oacklen > result)
++ {
++ logger(LOG_NOTICE, "OACK will not fit in buffer of size %d.",
++ " Options rejected.", result);
++ tftp_send_error(sockfd, sa, EOPTNEG, data->data_buffer,
++ data->data_buffer_size);
++ if (data->trace)
++ logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>",
++ EOPTNEG, tftp_errmsg[EOPTNEG]);
++ fclose(fp);
++ return ERR;
++ }
++
+ data->data_buffer_size = result + 4;
+ data->data_buffer = realloc(data->data_buffer, data->data_buffer_size);
+
+@@ -559,11 +614,16 @@
+ logger(LOG_INFO, "blksize option -> %d", result);
+ }
+
++ /* multicast option */
++ if (data->tftp_options[OPT_MULTICAST].specified &&
++ data->tftp_options[OPT_MULTICAST].enabled && !convert)
++ {
+ /* Verify that the file can be sent in 2^16 block of BLKSIZE octets */
+ if ((file_stat.st_size / (data->data_buffer_size - 4)) > 65535)
+ {
+ tftp_send_error(sockfd, sa, EUNDEF, data->data_buffer, data->data_buffer_size);
+- logger(LOG_NOTICE, "Requested file to big, increase BLKSIZE");
++ logger(LOG_NOTICE, "Requested file too big, increase BLKSIZE, ",
++ "cannot rollover in multicast transfer");
+ if (data->trace)
+ logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EUNDEF,
+ tftp_errmsg[EUNDEF]);
+@@ -571,10 +631,6 @@
+ return ERR;
+ }
+
+- /* multicast option */
+- if (data->tftp_options[OPT_MULTICAST].specified &&
+- data->tftp_options[OPT_MULTICAST].enabled && !convert)
+- {
+ /*
+ * Find a server with the same options to give up the client.
+ */
+@@ -649,10 +705,16 @@
+ /* initialise multicast address structure */
+ data->mcastaddr.imr_multiaddr.s_addr =
+ data->sa_mcast.sin_addr.s_addr;
+- data->mcastaddr.imr_interface.s_addr = htonl(INADDR_ANY);
++
+ setsockopt(data->sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &data->mcast_ttl, sizeof(data->mcast_ttl));
+
++ logger(LOG_DEBUG, "Multicast interface = %s",
++ inet_ntoa(data->mcastaddr.imr_interface));
++ setsockopt(data->sockfd, IPPROTO_IP, IP_MULTICAST_IF,
++ &(data->mcastaddr.imr_interface.s_addr),
++ sizeof(data->mcastaddr.imr_interface.s_addr));
++
+ /* set options data for OACK */
+ opt_set_multicast(data->tftp_options, data->mc_addr,
+ data->mc_port, 1);
+@@ -661,7 +723,7 @@
/* the socket must be unconnected for multicast */
-+#ifdef __linux__
sa->sin_family = AF_UNSPEC;
- connect(sockfd, (struct sockaddr *)sa, sizeof(sa));
-+#else
-+ sa->sin_family = AF_INET;
-+#endif
+ connect(sockfd, (struct sockaddr *)sa, sizeof(*sa));
/* set multicast flag */
multicast = 1;
-@@ -706,10 +714,14 @@
+@@ -669,6 +731,11 @@
+ tftpd_clientlist_ready(data);
+ }
+ }
++ if ((file_stat.st_size / (data->data_buffer_size - 4)) > 65535)
++ {
++ logger(LOG_NOTICE, "Requested file bigger than tftp is designed to ",
++ "handle, attempting rollover, but not officially in a tftp spec");
++ }
+
+ /* copy options to local structure, used when falling back a client to slave */
+ memcpy(options, data->tftp_options, sizeof(options));
+@@ -706,10 +773,14 @@
case S_SEND_OACK:
timeout_state = state;
opt_options_to_string(data->tftp_options, string, MAXLEN);
@@ -43,14 +213,14 @@
+ data->data_buffer,
+ data->data_buffer_size);
+ if (result == OK)
-+ {
++ {
+ if (data->trace)
-+ logger(LOG_DEBUG, "sent OACK <%s>", string);
++ logger(LOG_DEBUG, "sent OACK <%s>", string);
+ }
state = S_WAIT_PACKET;
break;
case S_SEND_DATA:
-@@ -725,19 +737,25 @@
+@@ -725,18 +796,24 @@
if (multicast)
{
@@ -60,6 +230,7 @@
+ result = tftp_send_data(sockfd, &data->sa_mcast,
+ block_number + 1, data_size,
+ data->data_buffer);
++ client_info->bytes_sent += data_size-4;
}
else
{
@@ -67,21 +238,149 @@
- data_size, data->data_buffer);
+ result = tftp_send_data(sockfd, sa, block_number + 1,
+ data_size, data->data_buffer);
-+ }
+ }
+- if (data->trace)
+- logger(LOG_DEBUG, "sent DATA <block: %d, size %d>",
+- block_number + 1, data_size - 4);
+
-+ if (result == ERR)
-+ state = S_ABORT;
-+ else
++ if (result == OK)
+ {
+ if (data->trace)
+ logger(LOG_DEBUG, "sent DATA <block: %d, size %d>",
+ block_number + 1, data_size - 4);
-+ state = S_WAIT_PACKET;
- }
-- if (data->trace)
-- logger(LOG_DEBUG, "sent DATA <block: %d, size %d>",
-- block_number + 1, data_size - 4);
-- state = S_WAIT_PACKET;
++ }
++ time(&last_send_time);
+ state = S_WAIT_PACKET;
break;
case S_WAIT_PACKET:
- data_size = data->data_buffer_size;
+@@ -746,12 +823,14 @@
+ switch (result)
+ {
+ case GET_TIMEOUT:
+- number_of_timeout++;
++ client_info->number_of_timeout++;
+
+- if (number_of_timeout > NB_OF_RETRY)
++ if (client_info->number_of_timeout > NB_OF_RETRY)
+ {
+- logger(LOG_INFO, "client (%s) not responding",
+- inet_ntoa(client_info->client.sin_addr));
++ logger(LOG_INFO, "client (%s) not responding.",
++ " state=%d block_number=%d",
++ inet_ntoa(client_info->client.sin_addr),
++ timeout_state,block_number);
+ state = S_END;
+ }
+ else
+@@ -779,7 +858,8 @@
+ /* Proceed normally with the next client,
+ going to OACK state */
+ logger(LOG_INFO,
+- "Serving next client: %s:%d",
++ "Serving next client after timeout: state=%d, block_number=%d: %s:%d",
++ timeout_state,block_number,
+ inet_ntoa(client_info->client.sin_addr),
+ ntohs(client_info->client.sin_port));
+ sa = &client_info->client;
+@@ -796,7 +876,9 @@
+ break;
+ }
+ }
+- logger(LOG_WARNING, "timeout: retrying...");
++ logger(LOG_WARNING, "timeout: retrying... state=%d,",
++ " block_number=%d", timeout_state,
++ block_number);
+ state = timeout_state;
+ }
+ break;
+@@ -811,7 +893,13 @@
+ * If this is an ACK for the last block, mark this client as
+ * done
+ */
+- if ((last_block != -1) && (block_number > last_block))
++ logger(LOG_DEBUG,
++ "received ACK <block: %d> from wrong client: %s:%d",
++ ntohs(tftphdr->th_block),
++ inet_ntoa(from.sin_addr),
++ ntohs(from.sin_port));
++
++ if ((last_block != -1) && (ntohs(tftphdr->th_block) > last_block))
+ {
+ if (tftpd_clientlist_done(data, NULL, &from) == 1)
+ logger(LOG_DEBUG, "client done <%s>",
+@@ -851,8 +939,33 @@
+ }
+ }
+ /* The ACK is from the current client */
+- number_of_timeout = 0;
+- block_number = ntohs(tftphdr->th_block);
++ client_info->number_of_timeout = 0;
++ int ACK_block_number = ntohs(tftphdr->th_block);
++ if (ACK_block_number == client_info->last_ack)
++ {
++ /* duplicate ACK, ignore */
++ time_t now;
++ time(&now);
++ /* if a timeout has occurred, resend last block */
++ if ((now-last_send_time) > timeout)
++ {
++ state = S_SEND_DATA;
++ logger(LOG_DEBUG, "Duplicate ACK packet discarded <%d>, timeout. Resend last block.", ACK_block_number);
++ }
++ else
++ {
++ logger(LOG_DEBUG, "Duplicate ACK packet discarded <%d>.", ACK_block_number);
++ }
++ break;
++ }
++
++ client_info->last_ack = ACK_block_number;
++
++ if (block_number < 65534)
++ block_number = ACK_block_number;
++ else
++ block_number++;
++
+ if (data->trace)
+ logger(LOG_DEBUG, "received ACK <block: %d>",
+ block_number);
+@@ -932,10 +1045,16 @@
+ }
+ break;
+ case S_END:
++ total_bytes_sent += client_info->bytes_sent;
+ if (multicast)
+ {
+ logger(LOG_DEBUG, "End of multicast transfer");
++ logger(LOG_INFO,
++ "Bytes sent while this client was master: %d",
++ client_info->bytes_sent);
++
+ /* mark the current client done */
++ clients_served++;
+ tftpd_clientlist_done(data, client_info, NULL);
+ /* Look if there is another client to serve. We lock list of
+ client to make sure no other thread try to add clients in
+@@ -948,13 +1067,20 @@
+ ntohs(client_info->client.sin_port));
+ /* client is a new client structure */
+ sa = &client_info->client;
+- /* nedd to send an oack to that client */
++ /* send an oack to that client */
+ state = S_SEND_OACK;
+ fseek(fp, 0, SEEK_SET);
+ }
+ else
+ {
+- logger(LOG_INFO, "No more client, end of tranfers");
++ int fs = file_stat.st_size;
++ int blksze = (data->data_buffer_size - 4);
++ int ttlblks = fs / blksze;
++ int blksretry = (total_bytes_sent-file_stat.st_size) / blksze;
++ logger(LOG_INFO, "No more client, end of tranfers. %d clients served", clients_served);
++ logger(LOG_INFO, "Bytes saved over unicast: %ld", (clients_served*file_stat.st_size) - total_bytes_sent);
++ logger(LOG_INFO, "File size: %d, total data bytes sent %d", file_stat.st_size, total_bytes_sent);
++ logger(LOG_INFO, "Block re-sent: %d of %d = %f percent", blksretry, ttlblks, ((float)blksretry/(float)ttlblks) * 100);
+ fclose(fp);
+ return OK;
+ }
diff --git a/ftp/atftp/files/patch-tftpd_list.c b/ftp/atftp/files/patch-tftpd_list.c
index 1a087d64a2d..42ffd38fe0c 100644
--- a/ftp/atftp/files/patch-tftpd_list.c
+++ b/ftp/atftp/files/patch-tftpd_list.c
@@ -1,11 +1,42 @@
---- tftpd_list.c.orig 2010-10-05 13:11:12.000000000 +0800
-+++ tftpd_list.c 2010-10-05 13:18:09.000000000 +0800
-@@ -149,7 +149,7 @@
+--- tftpd_list.c.orig 2010-10-11 12:44:39.000000000 +0800
++++ tftpd_list.c 2010-10-11 12:44:34.000000000 +0800
+@@ -137,23 +137,17 @@
+ struct thread_data *data,
+ struct client_info *client)
+ {
+- struct thread_data *current = thread_data; /* head of the list */
++ struct thread_data *current;
+ struct tftp_opt *tftp_options = data->tftp_options;
+ struct client_info *tmp;
+- char options[MAXLEN];
+- char string[MAXLEN];
+- char *index;
+- int len;
- opt_request_to_string(tftp_options, options, MAXLEN);
- index = strstr(options, "multicast");
-- len = (int)index - (int)options;
-+ len = strlen(options) - strlen(index);
+ *thread = NULL;
+- opt_request_to_string(tftp_options, options, MAXLEN);
+- index = strstr(options, "multicast");
+- len = (int)index - (int)options;
+-
/* lock the whole list before walking it */
pthread_mutex_lock(&thread_list_mutex);
+
++ current = thread_data; /* head of the list */
++
+ while (current)
+ {
+ if (current != data)
+@@ -162,9 +156,9 @@
+ pthread_mutex_lock(&current->client_mutex);
+ if (current->client_ready == 1)
+ {
+- opt_request_to_string(current->tftp_options, string, MAXLEN);
+- /* must have exact same option string */
+- if (strncmp(string, options, len) == 0)
++ /* must have exact same mode and refer to the same file */
++ if (opt_same_file(current->tftp_options,tftp_options) &&
++ opt_equal(&(current->tftp_options[OPT_MODE]), &(tftp_options[OPT_MODE])))
+ {
+ *thread = current;
+ /* insert the new client at the end. If the client is already
diff --git a/ftp/atftp/files/patch-tftpd_mtftp.c b/ftp/atftp/files/patch-tftpd_mtftp.c
new file mode 100644
index 00000000000..29dc26de7c0
--- /dev/null
+++ b/ftp/atftp/files/patch-tftpd_mtftp.c
@@ -0,0 +1,40 @@
+--- tftpd_mtftp.c.orig 2010-10-11 12:45:36.000000000 +0800
++++ tftpd_mtftp.c 2010-10-11 12:46:29.000000000 +0800
+@@ -369,6 +369,13 @@
+ logger(LOG_ERR, "mtftp: can't open socket");
+ pthread_exit(NULL);
+ }
++
++ int one = 1;
++ if (setsockopt(sockfd, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(one)) != 0)
++ {
++ logger(LOG_WARNING, "Failed to set socket option: %s",
++ strerror(errno));
++ }
+ /* bind the socket to the tftp port */
+ if (bind(sockfd, (struct sockaddr*)&sa, sizeof(sa)) < 0)
+ {
+@@ -389,7 +396,8 @@
+ that file name */
+ memset(&sa, 0, sizeof(sa)); /* this will hold the client info */
+ data_size = data->data_buffer_size;
+- retval = tftp_get_packet(sockfd, -1, NULL, &sa, NULL, NULL,
++ struct sockaddr_in toaddr;
++ retval = tftp_get_packet(sockfd, -1, NULL, &sa, NULL, &toaddr,
+ data->timeout,
+ &data_size, data->data_buffer);
+
+@@ -472,8 +480,11 @@
+ getsockname(thread->sockfd, (struct sockaddr *)&(sa), &len);
+
+ /* configure multicast socket */
+- thread->mcastaddr.imr_multiaddr.s_addr = thread->sa_mcast.sin_addr.s_addr;
+- thread->mcastaddr.imr_interface.s_addr = htonl(INADDR_ANY);
++ thread->mcastaddr.imr_interface.s_addr = toaddr.sin_addr.s_addr;
++ setsockopt(thread->sockfd, IPPROTO_IP, IP_MULTICAST_IF,
++ &(thread->mcastaddr.imr_interface.s_addr),
++ sizeof(thread->mcastaddr.imr_interface.s_addr));
++
+ setsockopt(thread->sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &data->mcast_ttl, sizeof(data->mcast_ttl));
+