OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [ftpclient/] [v2_0/] [src/] [ftpclient.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      ftpclient.c
4
//
5
//      A simple FTP client
6
//
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
//
14
// eCos is free software; you can redistribute it and/or modify it under
15
// the terms of the GNU General Public License as published by the Free
16
// Software Foundation; either version 2 or (at your option) any later version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
// for more details.
22
//
23
// You should have received a copy of the GNU General Public License along
24
// with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
//
27
// As a special exception, if other files instantiate templates or use macros
28
// or inline functions from this file, or you compile this file and link it
29
// with other works to produce a work based on this file, this file does not
30
// by itself cause the resulting work to be covered by the GNU General Public
31
// License. However the source code for this file must still be made available
32
// in accordance with section (3) of the GNU General Public License.
33
//
34
// This exception does not invalidate any other reasons why a work based on
35
// this file might be covered by the GNU General Public License.
36
//
37
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38
// at http://sources.redhat.com/ecos/ecos-license/
39
// -------------------------------------------
40
//####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):    andrew.lunn@ascom.ch
45
// Contributors: andrew.lunn@ascom.ch
46
// Date:         2001-11-4
47
// Purpose:      
48
// Description:  
49
//              
50
//####DESCRIPTIONEND####
51
//
52
//==========================================================================
53
 
54
#include <pkgconf/system.h>
55
 
56
#include <network.h>
57
#include <stdio.h>
58
#include <stdlib.h>
59
#include <sys/socket.h>
60
#include <netinet/in.h>
61
#include <arpa/inet.h>
62
#include <ctype.h>
63
#include "ftpclient.h"
64
 
65
/* Build one command to send to the FTP server */
66
static int
67
build_cmd(char *buf,
68
          unsigned bufsize,
69
          char *cmd,
70
          char *arg1)
71
{
72
  int cnt;
73
 
74
  if (arg1) {
75
    cnt = snprintf(buf,bufsize,"%s %s\r\n",cmd,arg1);
76
  } else {
77
    cnt = snprintf(buf,bufsize,"%s\r\n",cmd);
78
  }
79
 
80
  if (cnt < bufsize)
81
    return 1;
82
 
83
  return 0;
84
}
85
 
86
 
87
/* Read one line from the server, being careful not to overrun the
88
   buffer. If we do reach the end of the buffer, discard the rest of
89
   the line. */
90
static int
91
get_line(int s, char *buf, unsigned buf_size,ftp_printf_t ftp_printf) {
92
 
93
  int eol = 0;
94
  int cnt = 0;
95
  int ret;
96
  char c;
97
 
98
  while(!eol) {
99
    ret = read(s,&c,1);
100
 
101
    if (ret != 1) {
102
      ftp_printf(1,"read %s\n",strerror(errno));
103
      return FTP_BAD;
104
    }
105
 
106
    if (c == '\n') {
107
      eol = 1;
108
      continue;
109
    }
110
 
111
    if (cnt < buf_size) {
112
      buf[cnt++] = c;
113
    }
114
  }
115
  if (cnt < buf_size) {
116
    buf[cnt++] = '\0';
117
  } else {
118
    buf[buf_size -1] = '\0';
119
  }
120
  return 0;
121
}
122
 
123
/* Read the reply from the server and return the MSB from the return
124
   code. This gives us a basic idea if the command failed/worked. The
125
   reply can be spread over multiple lines. When this happens the line
126
   will start with a - to indicate there is more*/
127
static int
128
get_reply(int s,ftp_printf_t ftp_printf) {
129
 
130
  char buf[BUFSIZ];
131
  int more = 0;
132
  int ret;
133
  int first_line=1;
134
  int code=0;
135
 
136
  do {
137
 
138
    if ((ret=get_line(s,buf,sizeof(buf),ftp_printf)) < 0) {
139
      return(ret);
140
    }
141
 
142
    ftp_printf(0,"FTP: %s\n",buf);
143
 
144
    if (first_line) {
145
      code = strtoul(buf,NULL,0);
146
      first_line=0;
147
      more = (buf[3] == '-');
148
    } else {
149
      if (isdigit(buf[0]) && isdigit(buf[1]) && isdigit(buf[2]) &&
150
          (code == strtoul(buf,NULL,0)) &&
151
          buf[3]==' ') {
152
        more=0;
153
      } else {
154
        more =1;
155
      }
156
    }
157
  } while (more);
158
 
159
  return (buf[0] - '0');
160
}
161
 
162
/* Send a command to the server */
163
static int
164
send_cmd(int s,char * msgbuf,ftp_printf_t ftp_printf) {
165
 
166
  int len;
167
  int slen = strlen(msgbuf);
168
 
169
  if ((len = write(s,msgbuf,slen)) != slen) {
170
    if (slen < 0) {
171
      ftp_printf(1,"write %s\n",strerror(errno));
172
      return FTP_BAD;
173
    } else {
174
      ftp_printf(1,"write truncasted!\n");
175
      return FTP_BAD;
176
    }
177
  }
178
  return 1;
179
}
180
 
181
/* Send a complete command to the server and receive the reply. Return the
182
   MSB of the reply code. */
183
static int
184
command(char * cmd,
185
        char * arg,
186
        int s,
187
        char *msgbuf,
188
        int msgbuflen,
189
        ftp_printf_t ftp_printf) {
190
 
191
  int err;
192
 
193
  if (!build_cmd(msgbuf,msgbuflen,cmd,arg)) {
194
    ftp_printf(1,"FTP: %s command to long\n",cmd);
195
    return FTP_BAD;
196
  }
197
 
198
  ftp_printf(0,"FTP: Sending %s command\n",cmd);
199
 
200
  if ((err=send_cmd(s,msgbuf,ftp_printf)) < 0) {
201
    return(err);
202
  }
203
 
204
  return (get_reply(s,ftp_printf));
205
}
206
 
207
/* Open a socket and connect it to the server. Also print out the
208
   address of the server for debug purposes.*/
209
 
210
static int
211
connect_to_server(char *hostname,
212
                  struct sockaddr_in * local,
213
                  ftp_printf_t ftp_printf)
214
{
215
  struct sockaddr_in host;
216
  struct servent *sent;
217
#ifdef CYGPKG_NS_DNS   
218
  struct hostent *hp=NULL;
219
#endif
220
  int s, len;
221
 
222
  s = socket(AF_INET, SOCK_STREAM, 0);
223
  if (s < 0) {
224
    ftp_printf(1,"socket: %s\n",strerror(errno));
225
    return FTP_BAD;
226
  }
227
 
228
  sent = getservbyname("ftp", "tcp");
229
  if (sent == (struct servent *)0) {
230
    ftp_printf(1,"FTP: unknown serivice\n");
231
    close(s);
232
    return FTP_BAD;
233
  }
234
 
235
#ifdef CYGPKG_NS_DNS  
236
  hp = gethostbyname(hostname);
237
 
238
 
239
  if (hp) {           /* try name first */
240
    host.sin_family = hp->h_addrtype;
241
    bcopy(hp->h_addr, &host.sin_addr, hp->h_length);
242
  } else
243
#endif
244
    {                   /* maybe it's a numeric address ?*/
245
    host.sin_family = AF_INET;
246
 
247
    if (inet_aton(hostname,&host.sin_addr) == 0)  {
248
      ftp_printf(1,"host not found: %s\n", hostname);
249
      close (s);
250
      return FTP_NOSUCHHOST;
251
    }
252
  }
253
 
254
  host.sin_port = sent->s_port;
255
 
256
  if (connect(s, (struct sockaddr *)&host, sizeof(host)) < 0) {
257
    ftp_printf(1,"FTP Connect failed: %s\n",strerror(errno));
258
    close (s);
259
    return FTP_NOSUCHHOST;
260
  }
261
 
262
  len = sizeof(struct sockaddr_in);
263
  if (getsockname(s, (struct sockaddr *)local, &len) < 0) {
264
    ftp_printf(1,"getsockname failed %s\n",strerror(errno));
265
    close(s);
266
    return FTP_BAD;
267
  }
268
  ftp_printf(0,"FTP: Connected to %s.%d\n",
269
             inet_ntoa(host.sin_addr), ntohs(host.sin_port));
270
 
271
  return (s);
272
}
273
 
274
/* Perform a login to the server. Pass the username and password and
275
   put the connection into binary mode. This assumes a passwd is
276
   always needed. Is this true? */
277
 
278
static int
279
login(char * username,
280
      char *passwd,
281
      int s,
282
      char *msgbuf,
283
      unsigned msgbuflen,
284
      ftp_printf_t ftp_printf) {
285
 
286
  int ret;
287
 
288
  ret = command("USER",username,s,msgbuf,msgbuflen,ftp_printf);
289
  if (ret != 3) {
290
    ftp_printf(1,"FTP: User %s not accepted\n",username);
291
    return (FTP_BADUSER);
292
  }
293
 
294
  ret = command("PASS",passwd,s,msgbuf,msgbuflen,ftp_printf);
295
  if (ret < 0) {
296
    return (ret);
297
  }
298
  if (ret != 2) {
299
    ftp_printf(1,"FTP: Login failed for User %s\n",username);
300
    return (FTP_BADUSER);
301
  }
302
 
303
  ftp_printf(0,"FTP: Login sucessfull\n");
304
 
305
  ret = command("TYPE","I",s,msgbuf,msgbuflen,ftp_printf);
306
  if (ret < 0) {
307
    return (ret);
308
  }
309
  if (ret != 2) {
310
    ftp_printf(1,"FTP: TYPE failed!\n");
311
    return (FTP_BAD);
312
  }
313
  return (ret);
314
}
315
 
316
 
317
/* Open a data socket. This is a client socket, i.e. its listening
318
waiting for the FTP server to connect to it. Once the socket has been
319
opened send the port command to the server so the server knows which
320
port we are listening on.*/
321
static int
322
opendatasock(int ctrl_s,
323
             struct sockaddr_in ctrl,
324
             char *msgbuf,
325
             unsigned msgbuflen,
326
             ftp_printf_t ftp_printf) {
327
 
328
  struct sockaddr_in local;
329
  socklen_t len;
330
  int on = 1;
331
  char buf[4*6+1];
332
  char *a, *p;
333
  int ret;
334
  int s;
335
 
336
  s = socket(AF_INET, SOCK_STREAM, 0);
337
  if (s < 0) {
338
    ftp_printf(1,"socket: %s\n",strerror(errno));
339
    return FTP_BAD;
340
  }
341
 
342
  if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
343
    ftp_printf(1,"setsockopt: %s\n",strerror(errno));
344
    close(s);
345
    return FTP_BAD;
346
  }
347
 
348
  local = ctrl;
349
  local.sin_family = AF_INET;
350
  local.sin_port = 0;
351
  if (bind(s,(struct sockaddr *)&local,sizeof(local)) < 0) {
352
    ftp_printf(1,"bind: %s\n",strerror(errno));
353
    close(s);
354
    return FTP_BAD;
355
  }
356
 
357
  len = sizeof(local);
358
  if (getsockname(s,(struct sockaddr *)&local,&len) < 0) {
359
    ftp_printf(1,"getsockname: %s\n",strerror(errno));
360
    close(s);
361
    return FTP_BAD;
362
  }
363
 
364
  if (listen(s, 1) < 0) {
365
    ftp_printf(1,"listen: %s\n",strerror(errno));
366
    close(s);
367
    return FTP_BAD;
368
  }
369
 
370
#define BtoI(b) (((int)b)&0xff)
371
  a = (char *)&local.sin_addr;
372
  p = (char *)&local.sin_port;
373
  sprintf(buf,"%d,%d,%d,%d,%d,%d",
374
          BtoI(a[0]),BtoI(a[1]),BtoI(a[2]),BtoI(a[3]),
375
          BtoI(p[0]),BtoI(p[1]));
376
 
377
  ret = command("PORT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
378
  if (ret < 0) {
379
    close(s);
380
    return (ret);
381
  }
382
 
383
  if (ret != 2) {
384
    ftp_printf(1,"FTP: PORT failed!\n");
385
    close(s);
386
    return (FTP_BAD);
387
  }
388
  return (s);
389
}
390
 
391
/* Receive the file into the buffer and close the data socket
392
   afterwards */
393
static int
394
receive_file(int data_s, char *buf, int buf_size,ftp_printf_t ftp_printf)
395
{
396
  int remaining = buf_size;
397
  int finished = 0;
398
  int total_size=0;
399
  char *bufp = buf;
400
  int len;
401
  int s;
402
 
403
  s = accept(data_s,NULL,0);
404
  if (s<0) {
405
    ftp_printf(1,"listen: %s\n",strerror(errno));
406
    return FTP_BAD;
407
  }
408
 
409
  do {
410
    len = read(s,bufp,remaining);
411
    if (len < 0) {
412
      ftp_printf(1,"read: %s\n",strerror(errno));
413
      close(s);
414
      return FTP_BAD;
415
    }
416
 
417
    if (len == 0) {
418
      finished = 1;
419
    } else {
420
      total_size += len;
421
      remaining -= len;
422
      bufp += len;
423
 
424
      if (total_size == buf_size) {
425
        ftp_printf(1,"FTP: File too big!\n");
426
        close(s);
427
        return FTP_TOOBIG;
428
      }
429
    }
430
  } while (!finished);
431
 
432
  close(s);
433
  return total_size;
434
}
435
 
436
/* Receive the file into the buffer and close the socket afterwards*/
437
static int
438
send_file(int data_s, char *buf, int buf_size,ftp_printf_t ftp_printf)
439
{
440
  int remaining=buf_size;
441
  int finished = 0;
442
  char * bufp = buf;
443
  int len;
444
  int s;
445
 
446
  s = accept(data_s,NULL,0);
447
  if (s<0) {
448
    ftp_printf(1,"listen: %s\n",strerror(errno));
449
    return FTP_BAD;
450
  }
451
 
452
  do {
453
    len = write(s,bufp,remaining);
454
    if (len < 0) {
455
      ftp_printf(1,"write: %s\n",strerror(errno));
456
      close(s);
457
      return FTP_BAD;
458
    }
459
 
460
    if (len == remaining) {
461
      finished = 1;
462
    } else {
463
      remaining -= len;
464
      bufp += len;
465
    }
466
  } while (!finished);
467
 
468
  close(s);
469
  return 0;
470
}
471
 
472
/* All done, say bye, bye */
473
static int quit(int s,
474
                char *msgbuf,
475
                unsigned msgbuflen,
476
                ftp_printf_t ftp_printf) {
477
 
478
  int ret;
479
 
480
  ret = command("QUIT",NULL,s,msgbuf,msgbuflen,ftp_printf);
481
  if (ret < 0) {
482
    return (ret);
483
  }
484
  if (ret != 2) {
485
    ftp_printf(1,"FTP: Quit failed!\n");
486
    return (FTP_BAD);
487
  }
488
 
489
  ftp_printf(0,"FTP: Connection closed\n");
490
  return (0);
491
}
492
 
493
/* Get a file from an FTP server. Hostname is the name/IP address of
494
   the server. username is the username used to connect to the server
495
   with. Passwd is the password used to authentificate the
496
   username. filename is the name of the file to receive. It should be
497
   the full pathname of the file. buf is a pointer to a buffer the
498
   contents of the file should be placed in and buf_size is the size
499
   of the buffer. If the file is bigger than the buffer, buf_size
500
   bytes will be retrieved and an error code returned. ftp_printf is a
501
   function to be called to perform printing. On success the number of
502
   bytes received is returned. On error a negative value is returned
503
   indicating the type of error. */
504
 
505
int ftp_get(char * hostname,
506
            char * username,
507
            char * passwd,
508
            char * filename,
509
            char * buf,
510
            unsigned buf_size,
511
            ftp_printf_t ftp_printf)
512
{
513
 
514
  struct sockaddr_in local;
515
  char msgbuf[256];
516
  int s,data_s;
517
  int bytes;
518
  int ret;
519
 
520
  s = connect_to_server(hostname,&local,ftp_printf);
521
  if (s < 0) {
522
    return (s);
523
  }
524
 
525
  /* Read the welcome message from the server */
526
  if (get_reply(s,ftp_printf) != 2) {
527
    ftp_printf(0,"FTP: Server refused connection\n");
528
    close(s);
529
    return FTP_BAD;
530
  }
531
 
532
  ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
533
  if (ret < 0) {
534
    close(s);
535
    return (ret);
536
  }
537
 
538
  /* We are now logged in and ready to transfer the file. Open the
539
     data socket ready to receive the file. It also build the PORT
540
     command ready to send */
541
  data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
542
  if (data_s < 0) {
543
    close (s);
544
    return (data_s);
545
  }
546
 
547
  /* Ask for the file */
548
  ret = command("RETR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
549
  if (ret < 0) {
550
    close(s);
551
    close(data_s);
552
    return (ret);
553
  }
554
 
555
  if (ret != 1) {
556
    ftp_printf(0,"FTP: RETR failed!\n");
557
    close (data_s);
558
    close(s);
559
    return (FTP_BADFILENAME);
560
  }
561
 
562
  if ((bytes=receive_file(data_s,buf,buf_size,ftp_printf)) < 0) {
563
    ftp_printf(0,"FTP: Receiving file failed\n");
564
    close (data_s);
565
    close(s);
566
    return (bytes);
567
  }
568
 
569
  if (get_reply(s,ftp_printf) != 2) {
570
    ftp_printf(0,"FTP: Transfer failed!\n");
571
    close (data_s);
572
    close(s);
573
    return (FTP_BAD);
574
  }
575
 
576
  ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
577
  if (ret < 0) {
578
    close(s);
579
    close(data_s);
580
    return (ret);
581
  }
582
 
583
  close (data_s);
584
  close(s);
585
  return bytes;
586
}
587
 
588
/* Put a file on an FTP server. Hostname is the name/IP address of the
589
   server. username is the username used to connect to the server
590
   with. Passwd is the password used to authentificate the
591
   username. filename is the name of the file to receive. It should be
592
   the full pathname of the file. buf is a pointer to a buffer the
593
   contents of the file should be placed in and buf_size is the size
594
   of the buffer. ftp_printf is a function to be called to perform
595
   printing. On success 0 is returned. On error a negative value is
596
   returned indicating the type of error. */
597
 
598
int ftp_put(char * hostname,
599
            char * username,
600
            char * passwd,
601
            char * filename,
602
            char * buf,
603
            unsigned buf_size,
604
            ftp_printf_t ftp_printf)
605
{
606
 
607
  struct sockaddr_in local;
608
  char msgbuf[256];
609
  int s,data_s;
610
  int ret;
611
 
612
  s = connect_to_server(hostname,&local,ftp_printf);
613
  if (s < 0) {
614
    return (s);
615
  }
616
 
617
  /* Read the welcome message from the server */
618
  if (get_reply(s,ftp_printf) != 2) {
619
    ftp_printf(1,"FTP: Server refused connection\n");
620
    close(s);
621
    return FTP_BAD;
622
  }
623
 
624
  ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
625
  if (ret < 0) {
626
    close(s);
627
    return (ret);
628
  }
629
 
630
  /* We are now logged in and ready to transfer the file. Open the
631
     data socket ready to receive the file. It also build the PORT
632
     command ready to send */
633
  data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
634
  if (data_s < 0) {
635
    close (s);
636
    return (data_s);
637
  }
638
 
639
  /* Ask for the file */
640
  ret = command("STOR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
641
  if (ret < 0) {
642
    close(s);
643
    close(data_s);
644
    return (ret);
645
  }
646
 
647
  if (ret != 1) {
648
    ftp_printf(1,"FTP: STOR failed!\n");
649
    close (data_s);
650
    close(s);
651
    return (FTP_BADFILENAME);
652
  }
653
 
654
  if ((ret = send_file(data_s,buf,buf_size,ftp_printf)) < 0) {
655
    ftp_printf(1,"FTP: Sending file failed\n");
656
    close (data_s);
657
    close(s);
658
    return (ret);
659
  }
660
 
661
  if (get_reply(s,ftp_printf) != 2) {
662
    ftp_printf(1,"FTP: Transfer failed!\n");
663
    close (data_s);
664
    close(s);
665
    return (FTP_BAD);
666
  }
667
 
668
  ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
669
  if (ret < 0) {
670
    close(s);
671
    close(data_s);
672
    return (ret);
673
  }
674
 
675
  close (data_s);
676
  close(s);
677
  return 0;
678
}
679
 
680
/* An example ftp_printf function. This uses the standard eCos diag
681
output device for outputting error and diagnostic messages. The
682
function take one addition parameter to the normal printf function. The
683
first parameter indicates when the message is an error message when
684
true. This can be used to filter errors from diagnostic output. In
685
this example the error parameter is ignored and everything printed. */
686
 
687
void ftpclient_printf(unsigned error, const char *fmt, ...)
688
{
689
  va_list ap;
690
 
691
  va_start(ap, fmt);
692
  diag_vprintf( fmt, ap);
693
  va_end(ap);
694
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.