1 //==========================================================================
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002 Andrew Lunn.
13 // Copyright (C) 2004 Gary Thomas
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //==========================================================================
43 //#####DESCRIPTIONBEGIN####
45 // Author(s): andrew.lunn@ascom.ch
46 // Contributors: andrew.lunn@ascom.ch
51 //####DESCRIPTIONEND####
53 //==========================================================================
55 #include <pkgconf/system.h>
56 #include <pkgconf/net_ftpclient.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
65 #include "ftpclient.h"
67 /* Build one command to send to the FTP server */
77 cnt = snprintf(buf,bufsize,"%s %s\r\n",cmd,arg1);
79 cnt = snprintf(buf,bufsize,"%s\r\n",cmd);
89 /* Read one line from the server, being careful not to overrun the
90 buffer. If we do reach the end of the buffer, discard the rest of
93 get_line(int s, char *buf, unsigned buf_size, ftp_printf_t ftp_printf)
104 ftp_printf(1,"read %s\n",strerror(errno));
113 if (cnt < buf_size) {
117 if (cnt < buf_size) {
120 buf[buf_size -1] = '\0';
125 /* Read the reply from the server and return the MSB from the return
126 code. This gives us a basic idea if the command failed/worked. The
127 reply can be spread over multiple lines. When this happens the line
128 will start with a - to indicate there is more*/
130 get_reply(int s, ftp_printf_t ftp_printf)
140 if ((ret=get_line(s,buf,sizeof(buf),ftp_printf)) < 0) {
144 ftp_printf(0,"FTP: %s\n",buf);
147 code = strtoul(buf,NULL,0);
149 more = (buf[3] == '-');
151 if (isdigit(buf[0]) && isdigit(buf[1]) && isdigit(buf[2]) &&
152 (code == strtoul(buf,NULL,0)) &&
161 return (buf[0] - '0');
164 /* Send a command to the server */
166 send_cmd(int s, char * msgbuf, ftp_printf_t ftp_printf)
169 int slen = strlen(msgbuf);
171 if ((len = write(s,msgbuf,slen)) != slen) {
173 ftp_printf(1,"write %s\n",strerror(errno));
176 ftp_printf(1,"write truncated!\n");
183 /* Send a complete command to the server and receive the reply. Return the
184 MSB of the reply code. */
191 ftp_printf_t ftp_printf)
195 if (!build_cmd(msgbuf,msgbuflen,cmd,arg)) {
196 ftp_printf(1,"FTP: %s command to long\n",cmd);
200 ftp_printf(0,"FTP: Sending %s command\n",cmd);
202 if ((err=send_cmd(s,msgbuf,ftp_printf)) < 0) {
206 return (get_reply(s,ftp_printf));
209 /* Open a socket and connect it to the server. Also print out the
210 address of the server for debug purposes.*/
213 connect_to_server(char *hostname,
214 struct sockaddr * local,
215 ftp_printf_t ftp_printf)
220 struct addrinfo *res, *nai;
224 error = getaddrinfo(hostname, "ftp", NULL, &res);
225 if (error != EAI_NONE) {
226 return FTP_NOSUCHHOST;
231 s = socket(nai->ai_family, nai->ai_socktype,nai->ai_protocol);
237 if (connect(s, nai->ai_addr, nai->ai_addrlen) < 0) {
238 getnameinfo(nai->ai_addr, nai->ai_addrlen,
239 name, sizeof(name), NULL,0, NI_NUMERICHOST);
240 ftp_printf(1,"FTP Connect to %s failed: %s\n",name, strerror(errno));
246 len = sizeof(struct sockaddr);
247 if (getsockname(s, (struct sockaddr *)local, &len) < 0) {
248 ftp_printf(1,"getsockname failed %s\n",strerror(errno));
253 getnameinfo(nai->ai_addr, nai->ai_addrlen,
254 name, sizeof(name), port, sizeof(port),
255 NI_NUMERICHOST|NI_NUMERICSERV);
257 ftp_printf(0,"FTP: Connected to %s:%s\n", name, port);
262 return FTP_NOSUCHHOST;
265 /* Perform a login to the server. Pass the username and password and
266 put the connection into binary mode. This assumes a passwd is
267 always needed. Is this true? */
270 login(char * username,
275 ftp_printf_t ftp_printf) {
279 ret = command("USER",username,s,msgbuf,msgbuflen,ftp_printf);
281 ftp_printf(1,"FTP: User %s not accepted\n",username);
282 return (FTP_BADUSER);
285 ret = command("PASS",passwd,s,msgbuf,msgbuflen,ftp_printf);
290 ftp_printf(1,"FTP: Login failed for User %s\n",username);
291 return (FTP_BADUSER);
294 ftp_printf(0,"FTP: Login sucessfull\n");
296 ret = command("TYPE","I",s,msgbuf,msgbuflen,ftp_printf);
301 ftp_printf(1,"FTP: TYPE failed!\n");
308 /* Open a data socket. This is a client socket, i.e. its listening
309 waiting for the FTP server to connect to it. Once the socket has been
310 opened send the port command to the server so the server knows which
311 port we are listening on.*/
313 opendatasock(int ctrl_s,
314 struct sockaddr *ctrl,
317 ftp_printf_t ftp_printf)
319 struct sockaddr local;
328 s = socket(ctrl->sa_family, SOCK_STREAM, 0);
330 ftp_printf(1,"socket: %s\n",strerror(errno));
334 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
335 ftp_printf(1,"setsockopt: %s\n",strerror(errno));
340 memcpy(&local,ctrl,sizeof(struct sockaddr));
341 switch (ctrl->sa_family) {
343 struct sockaddr_in * sa4 = (struct sockaddr_in *) &local;
347 #ifdef CYGPKG_NET_INET6
349 struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *) &local;
359 if (bind(s,&local,local.sa_len) < 0) {
360 ftp_printf(1,"bind: %s\n",strerror(errno));
366 if (getsockname(s,&local,&len) < 0) {
367 ftp_printf(1,"getsockname: %s\n",strerror(errno));
372 if (listen(s, 1) < 0) {
373 ftp_printf(1,"listen: %s\n",strerror(errno));
378 getnameinfo(&local, sizeof(local), name, sizeof(name), port, sizeof(port),
379 NI_NUMERICHOST|NI_NUMERICSERV);
380 switch (local.sa_family) {
382 snprintf(buf, sizeof(buf), "|1|%s|%s|", name, port);
385 #ifdef CYGPKG_NET_INET6
387 snprintf(buf, sizeof(buf), "|2|%s|%s|", name, port);
396 ret = command("EPRT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
403 int _port = atoi(port);
406 if (*str == '.') *str = ',';
409 snprintf(buf, sizeof(buf), "%s,%d,%d", name, _port/256, _port%256);
410 ret = command("PORT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
416 ftp_printf(1,"FTP: PORT failed!\n");
424 /* Receive the file into the buffer and close the data socket
427 receive_file(int data_s, ftp_write_t ftp_write, void *ftp_write_priv, ftp_printf_t ftp_printf)
435 if ((buf = (char *)malloc(CYGNUM_NET_FTPCLIENT_BUFSIZE)) == (char *)0) {
438 s = accept(data_s, NULL, 0);
440 ftp_printf(1, "listen: %s\n",strerror(errno));
446 len = read(s, buf, CYGNUM_NET_FTPCLIENT_BUFSIZE);
448 ftp_printf(1, "read: %s\n",strerror(errno));
457 wlen = (*ftp_write)(buf, len, ftp_write_priv);
459 ftp_printf(1, "FTP: File too big!\n");
473 /* Receive the file into the buffer and close the socket afterwards*/
475 send_file(int data_s, ftp_read_t ftp_read, void *ftp_read_priv, ftp_printf_t ftp_printf)
481 if ((buf = (char *)malloc(CYGNUM_NET_FTPCLIENT_BUFSIZE)) == (char *)0) {
484 s = accept(data_s,NULL,0);
486 ftp_printf(1,"listen: %s\n",strerror(errno));
492 rlen = (*ftp_read)(buf, CYGNUM_NET_FTPCLIENT_BUFSIZE, ftp_read_priv);
494 len = write(s, buf, rlen);
496 ftp_printf(1,"write: %s\n",strerror(errno));
509 /* All done, say bye, bye */
510 static int quit(int s,
513 ftp_printf_t ftp_printf) {
517 ret = command("QUIT",NULL,s,msgbuf,msgbuflen,ftp_printf);
522 ftp_printf(1,"FTP: Quit failed!\n");
526 ftp_printf(0,"FTP: Connection closed\n");
530 /* Get a file from an FTP server. Hostname is the name/IP address of
531 the server. username is the username used to connect to the server
532 with. Passwd is the password used to authentificate the
533 username. filename is the name of the file to receive. It should be
534 the full pathname of the file. buf is a pointer to a buffer the
535 contents of the file should be placed in and buf_size is the size
536 of the buffer. If the file is bigger than the buffer, buf_size
537 bytes will be retrieved and an error code returned. ftp_printf is a
538 function to be called to perform printing. On success the number of
539 bytes received is returned. On error a negative value is returned
540 indicating the type of error. */
548 static int _ftp_read(char *buf, int len, void *priv)
550 struct _ftp_data *dp = (struct _ftp_data *)priv;
553 // FTP data channel desires to write 'len' bytes. Fetch up
554 // to that amount into 'buf'
557 if (res > len) res = len;
558 memcpy(buf, dp->buf, res);
565 static int _ftp_write(char *buf, int len, void *priv)
567 struct _ftp_data *dp = (struct _ftp_data *)priv;
570 // FTP data channel has 'len' bytes that have been read.
571 // Move into 'buf', respecting the max size of 'buf'
572 if (dp->len < dp->max_len) {
573 res = dp->max_len - dp->len;
577 memcpy(dp->buf, buf, res);
584 int ftp_get(char * hostname,
590 ftp_printf_t ftp_printf)
592 struct _ftp_data ftp_data;
596 ftp_data.max_len = buf_size;
597 return ftp_get_var(hostname, username, passwd, filename, _ftp_write, &ftp_data, ftp_printf);
600 int ftp_get_var(char *hostname,
604 ftp_write_t ftp_write,
605 void *ftp_write_priv,
606 ftp_printf_t ftp_printf)
609 struct sockaddr local;
615 s = connect_to_server(hostname,&local,ftp_printf);
620 /* Read the welcome message from the server */
621 if (get_reply(s,ftp_printf) != 2) {
622 ftp_printf(0,"FTP: Server refused connection\n");
627 ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
633 /* We are now logged in and ready to transfer the file. Open the
634 data socket ready to receive the file. It also build the PORT
635 command ready to send */
636 data_s = opendatasock(s,&local,msgbuf,sizeof(msgbuf),ftp_printf);
642 /* Ask for the file */
643 ret = command("RETR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
651 ftp_printf(0,"FTP: RETR failed!\n");
654 return (FTP_BADFILENAME);
657 if ((bytes=receive_file(data_s,ftp_write,ftp_write_priv,ftp_printf)) < 0) {
658 ftp_printf(0,"FTP: Receiving file failed\n");
664 if (get_reply(s,ftp_printf) != 2) {
665 ftp_printf(0,"FTP: Transfer failed!\n");
671 ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
683 /* Put a file on an FTP server. Hostname is the name/IP address of the
684 server. username is the username used to connect to the server
685 with. Passwd is the password used to authentificate the
686 username. filename is the name of the file to receive. It should be
687 the full pathname of the file. buf is a pointer to a buffer the
688 contents of the file should be placed in and buf_size is the size
689 of the buffer. ftp_printf is a function to be called to perform
690 printing. On success 0 is returned. On error a negative value is
691 returned indicating the type of error. */
693 int ftp_put(char * hostname,
699 ftp_printf_t ftp_printf)
701 struct _ftp_data ftp_data;
704 ftp_data.len = buf_size;
705 return ftp_put_var(hostname, username, passwd, filename, _ftp_read, &ftp_data, ftp_printf);
708 int ftp_put_var(char *hostname,
714 ftp_printf_t ftp_printf)
717 struct sockaddr local;
722 s = connect_to_server(hostname,&local,ftp_printf);
727 /* Read the welcome message from the server */
728 if (get_reply(s,ftp_printf) != 2) {
729 ftp_printf(1,"FTP: Server refused connection\n");
734 ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
740 /* We are now logged in and ready to transfer the file. Open the
741 data socket ready to receive the file. It also build the PORT
742 command ready to send */
743 data_s = opendatasock(s,&local,msgbuf,sizeof(msgbuf),ftp_printf);
749 /* Ask for the file */
750 ret = command("STOR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
758 ftp_printf(1,"FTP: STOR failed!\n");
761 return (FTP_BADFILENAME);
764 if ((ret = send_file(data_s,ftp_read,ftp_read_priv,ftp_printf)) < 0) {
765 ftp_printf(1,"FTP: Sending file failed\n");
771 if (get_reply(s,ftp_printf) != 2) {
772 ftp_printf(1,"FTP: Transfer failed!\n");
778 ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
790 /* An example ftp_printf function. This uses the standard eCos diag
791 output device for outputting error and diagnostic messages. The
792 function take one addition parameter to the normal printf function. The
793 first parameter indicates when the message is an error message when
794 true. This can be used to filter errors from diagnostic output. In
795 this example the error parameter is ignored and everything printed. */
797 void ftpclient_printf(unsigned error, const char *fmt, ...)
802 diag_vprintf( fmt, ap);