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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libnetworking/] [lib/] [ftpfs.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1026 ivang
/*
2
 * File Transfer Protocol client
3
 *
4
 * Transfer file to/from remote host
5
 *
6
 * This driver can be added to the RTEMS file system with a call to
7
 * "rtems_bsdnet_initialize_ftp_filesystem () ".
8
 * From then on, you can open, read and close files on a remote FTP server
9
 * using the following syntax:
10
 * To open a file "myfile.txt" in the directory "mydir" (relative to home
11
 * directory) on a server named "myserver" using the user id
12
 * "myuserid" and the password "my_very_secret_password" you must
13
 * specify the following path:
14
 *
15
 * /FTP/myuserid:my_very_secret_password/@myserver/mydirectory/myfile.txt
16
 *
17
 * If the server is the default server specified in BOOTP, it can be ommitted:
18
 *
19
 * /FTP/myuserid:my_very_secret_password/mydirectory/myfile.txt
20
 *
21
 * WARNING: write accesses have not yet been tested.
22
 *
23
 *
24
 * (c) Copyright 2002
25
 * Thomas Doerfler
26
 * IMD Ingenieurbuero fuer Microcomputertechnik
27
 * Herbststr. 8
28
 * 82178 Puchheim, Germany
29
 * <Thomas.Doerfler@imd-systems.de>
30
 *
31
 * This code has been created after closly inspecting
32
 * "tftpdriver.c" from Eric Norum.
33
 *
34
 *  ftpfs.c,v 1.1 2002/06/27 21:59:23 joel Exp
35
 */
36
 
37
#include <stdio.h>
38
#include <errno.h>
39
#include <malloc.h>
40
#include <string.h>
41
#include <stdlib.h>
42
#include <fcntl.h>
43
#include <unistd.h>
44
#include <ctype.h>
45
#include <rtems.h>
46
#include <rtems/libio.h>
47
#include <rtems/rtems_bsdnet.h>
48
#include <sys/types.h>
49
#include <sys/socket.h>
50
#include <netinet/in.h>
51
#include <arpa/inet.h>
52
#include <netdb.h>
53
#include <rtems/ftpfs.h>
54
 
55
 
56
#ifndef set_errno_and_return_minus_one
57
#define set_errno_and_return_minus_one( _error ) \
58
  do { errno = (_error); return -1; } while(0)
59
#endif
60
 
61
/* #define DEBUG_OUT */
62
 
63
/*
64
 * Well-known port for FTP
65
 */
66
#define FTP_PORT_NUM    21
67
 
68
/*
69
 * Pathname prefix
70
 */
71
#define FTP_PATHNAME_PREFIX     "/FTP/"
72
/*
73
 * reply codes
74
 */
75
#define FTP_REPLY_CONNECT 220  /* Connection established       */
76
#define FTP_REPLY_PASSREQ 331  /* user ok, password required   */
77
#define FTP_REPLY_LOGIN   230  /* login finished               */
78
#define FTP_REPLY_SUCCESS 200  /* xxx successful               */
79
#define FTP_REPLY_OPENCONN 150 /* opening connection for tfer  */
80
#define FTP_REPLY_TFERCMPL 226 /* transfer complete            */
81
 
82
extern rtems_filesystem_operations_table  rtems_ftp_ops;
83
extern rtems_filesystem_file_handlers_r rtems_ftp_handlers;
84
 
85
/*
86
 * FTP command strings
87
 */
88
#define FTP_USER_CMD   "USER "
89
#define FTP_PASS_CMD   "PASS "
90
#define FTP_BINARY_CMD "TYPE I"
91
#define FTP_PORT_CMD   "PORT "
92
#define FTP_STOR_CMD   "STOR "
93
#define FTP_RETR_CMD   "RETR "
94
#define FTP_QUIT_CMD   "QUIT"
95
 
96
/*
97
 * State of each FTP stream
98
 */
99
struct ftpStream {
100
  /*
101
   * Control connection socket
102
   */
103
  int ctrl_socket;
104
  struct sockaddr_in    myCtrlAddress;
105
  struct sockaddr_in    farCtrlAddress;
106
  /*
107
   * Data transfer socket
108
   */
109
  int port_socket;
110
  int data_socket;
111
  struct sockaddr_in    myDataAddress;
112
  struct sockaddr_in    farDataAddress;
113
  /*
114
   * other stuff to remember
115
   */
116
  boolean eof_reached;
117
};
118
 
119
/*
120
 * Number of streams open at the same time
121
 */
122
static rtems_id ftp_mutex;
123
static int nStreams;
124
static struct ftpStream ** volatile ftpStreams;
125
 
126
extern rtems_filesystem_operations_table  rtems_tftp_ops;
127
extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;
128
 
129
/*
130
 *  Direct copy from the IMFS/TFTP.  Look at this.
131
 */
132
 
133
rtems_filesystem_limits_and_options_t rtems_ftp_limits_and_options = {
134
   5,   /* link_max */
135
   6,   /* max_canon */
136
   7,   /* max_input */
137
   255, /* name_max */
138
   255, /* path_max */
139
   2,   /* pipe_buf */
140
   1,   /* posix_async_io */
141
   2,   /* posix_chown_restrictions */
142
   3,   /* posix_no_trunc */
143
   4,   /* posix_prio_io */
144
   5,   /* posix_sync_io */
145
   6    /* posix_vdisable */
146
};
147
 
148
int rtems_ftp_mount_me(
149
  rtems_filesystem_mount_table_entry_t *temp_mt_entry
150
)
151
{
152
  rtems_status_code  sc;
153
 
154
  temp_mt_entry->mt_fs_root.handlers = &rtems_ftp_handlers;
155
  temp_mt_entry->mt_fs_root.ops      = &rtems_ftp_ops;
156
 
157
  /*
158
   *   We have no ftp filesystem specific data to maintain.  This
159
   *   filesystem may only be mounted ONCE.
160
   *
161
   *   And we maintain no real filesystem nodes, so there is no real root.
162
   */
163
 
164
  temp_mt_entry->fs_info                = NULL;
165
  temp_mt_entry->mt_fs_root.node_access = NULL;
166
 
167
  /*
168
   *  These need to be looked at for full POSIX semantics.
169
   */
170
 
171
  temp_mt_entry->pathconf_limits_and_options = rtems_ftp_limits_and_options;
172
 
173
 
174
  /*
175
   *  Now allocate a semaphore for mutual exclusion.
176
   *
177
   *  NOTE:  This could be in an fsinfo for this filesystem type.
178
   */
179
 
180
  sc = rtems_semaphore_create (rtems_build_name('F','T','P',' '),
181
                               1,
182
                               RTEMS_FIFO |
183
                               RTEMS_BINARY_SEMAPHORE |
184
                               RTEMS_NO_INHERIT_PRIORITY |
185
                               RTEMS_NO_PRIORITY_CEILING |
186
                               RTEMS_LOCAL,
187
                               0,
188
                               &ftp_mutex);
189
 
190
  if (sc != RTEMS_SUCCESSFUL)
191
    set_errno_and_return_minus_one( ENOMEM );
192
 
193
  return 0;
194
}
195
 
196
/*
197
 * Initialize the FTP driver
198
 */
199
 
200
int rtems_bsdnet_initialize_ftp_filesystem ()
201
{
202
 int                                   status;
203
 rtems_filesystem_mount_table_entry_t *entry;
204
 
205
 status = mkdir( FTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
206
 if ( status == -1 )
207
   return status;
208
 
209
  status = mount(
210
     &entry,
211
     &rtems_ftp_ops,
212
     RTEMS_FILESYSTEM_READ_ONLY,
213
     NULL,
214
     FTP_PATHNAME_PREFIX
215
  );
216
 
217
  if ( status )
218
    perror( "FTP mount failed" );
219
 
220
  return status;
221
}
222
 
223
/*
224
 * read and return message code from ftp control connection
225
 */
226
int rtems_ftp_get_message
227
(
228
  const struct ftpStream *fsp,  /* ptr to ftp control structure */
229
  int *msg_code                 /* ptr to return message code   */
230
)
231
{
232
  char rd_buffer[4];
233
  size_t rd_size;
234
  size_t tmp_size;
235
  int eno = 0;
236
  rtems_boolean finished = FALSE;
237
  do {
238
    /*
239
     * fetch (at least) 4 characters from control connection
240
     * FIXME: how about a timeout?
241
     */
242
    rd_size = 0;
243
    while ((eno == 0) &&
244
           (rd_size < sizeof(rd_buffer))) {
245
      tmp_size = read(fsp->ctrl_socket,
246
                      (&rd_buffer)+rd_size,
247
                      sizeof(rd_buffer)-rd_size);
248
      if (tmp_size < 0) {
249
        eno = EIO;
250
      }
251
      else {
252
#ifdef DEBUG_OUT
253
        write(1,(&rd_buffer)+rd_size,tmp_size);
254
#endif
255
        rd_size += tmp_size;
256
      }
257
    }
258
    /*
259
     * check for 3 digits and space, otherwise not finished
260
     */
261
    if ((eno == 0) &&
262
        (isdigit((unsigned int)rd_buffer[0])) &&
263
        (isdigit((unsigned int)rd_buffer[1])) &&
264
        (isdigit((unsigned int)rd_buffer[2])) &&
265
        (rd_buffer[3] == ' ')) {
266
      finished = TRUE;
267
      rd_buffer[3] = '\0';
268
      *msg_code = atol(rd_buffer);
269
    }
270
    /*
271
     * skip rest until end-of-line
272
     */
273
    do {
274
      tmp_size = read(fsp->ctrl_socket,
275
                      &rd_buffer,
276
                      1);
277
      if (tmp_size < 0) {
278
        eno = EIO;
279
      }
280
#ifdef DEBUG_OUT
281
      else {
282
        write(1,(&rd_buffer),tmp_size);
283
      }
284
#endif
285
    } while ((eno == 0) &&
286
             (rd_buffer[0] != '\n'));
287
  } while ((eno == 0) && !finished);
288
  return eno;
289
}
290
 
291
/*
292
 * split a pseudo file name into host, user, password, filename
293
 * NOTE: this function will allocate space for these strings,
294
 * the calling function should free the space, when no longer needed
295
 * exception: when we return any error, we will also cleanup
296
 * the strings
297
 * valid forms:
298
 * /FTP/user:pass/filepath
299
 * /FTP/user:pass@hostname/filepath
300
 
301
 * /FTP/user:pass/filepath
302
 * /FTP/user:pass/@hostname/filepath
303
 * NOTE: /FTP is already stripped from the name
304
 */
305
int rtems_ftp_split_names
306
( const char *pathname,         /* total path name (including prefix)     */
307
  char **usernamep,             /* ptr to ptr to user name                */
308
  char **passwordp,             /* ptr to ptr to password                 */
309
  char **hostnamep,             /* ptr to ptr to host name                */
310
  char **filenamep)             /* ptr to ptr to hostremaining file name  */
311
{
312
  const char  *chunk_start;
313
  const char  *chunk_end;
314
  size_t chunk_len;
315
  int rc = 0;
316
 
317
  /*
318
   * ensure, that result pointers are NULL...
319
   */
320
  *usernamep = NULL;
321
  *passwordp = NULL;
322
  *hostnamep = NULL;
323
  *filenamep = NULL;
324
 
325
#if 1
326
  chunk_start = pathname;
327
#else /* no longer needed with IMFS */
328
  /*
329
   * check, that total path is long enough, skip prefix
330
   */
331
  if (rc == 0) {
332
    if (strlen (pathname) <= strlen (FTP_PATHNAME_PREFIX)) {
333
      rc = ENOENT;
334
    }
335
    else {
336
      chunk_start = pathname + strlen (FTP_PATHNAME_PREFIX);
337
    }
338
  }
339
#endif
340
  /*
341
   * fetch user name: terminated with ":"
342
   */
343
  if (rc == 0) {
344
    chunk_end = strchr(chunk_start,':');
345
    if ((chunk_end == NULL) ||         /* No ':' found or                  */
346
        (chunk_end == chunk_start)) {  /* ':' is first character-> no name */
347
      rc = ENOENT;
348
    }
349
    else {
350
      chunk_len = chunk_end-chunk_start;
351
      *usernamep = malloc(chunk_len);
352
      if (*usernamep == NULL) {
353
        rc = ENOMEM;
354
      }
355
      else {
356
        memcpy(*usernamep,chunk_start,chunk_len);
357
        (*usernamep)[chunk_len] = '\0';
358
      }
359
    }
360
  }
361
  /*
362
   * fetch password: terminated with "/" or "@"
363
   */
364
  if (rc == 0) {
365
    chunk_start = chunk_end + 1; /* skip ":" after user name */
366
    chunk_end = strchr(chunk_start,'/');
367
    if ((chunk_end == NULL) ||         /* No '/' found or                  */
368
        (chunk_end == chunk_start)) {  /* '/' is first character-> no pwd  */
369
      rc = ENOENT;
370
    }
371
    else {
372
      /*
373
       * we have found a proper '/'
374
       * this is the end of the password
375
       */
376
      chunk_len = chunk_end-chunk_start;
377
      *passwordp = malloc(chunk_len);
378
      if (*passwordp == NULL) {
379
        rc = ENOMEM;
380
      }
381
      else {
382
        memcpy(*passwordp,chunk_start,chunk_len);
383
        (*passwordp)[chunk_len] = '\0';
384
      }
385
    }
386
  }
387
  /*
388
   * if first char after '/' is '@', then this is the hostname
389
   * fetch hostname terminated with "/"
390
   * if exists at all. otherwise take default server from bootp
391
   */
392
  if (rc == 0) {
393
    chunk_start = chunk_end+1;
394
    if (*chunk_start == '@') {
395
      /*
396
       * hostname follows
397
       */
398
      chunk_start = chunk_start + 1; /* skip "@" after password */
399
      chunk_end = strchr(chunk_start,'/');
400
      if ((chunk_end == NULL) ||         /* No '/' found or                  */
401
          (chunk_end == chunk_start)) {  /* '/' is first character-> no host */
402
        rc = ENOENT;
403
      }
404
      else {
405
        /*
406
         * we have found a proper '/'
407
         */
408
        chunk_len = chunk_end-chunk_start;
409
        *hostnamep = malloc(chunk_len);
410
        if (*hostnamep == NULL) {
411
          rc = ENOMEM;
412
        }
413
        else {
414
          memcpy(*hostnamep,chunk_start,chunk_len);
415
          (*hostnamep)[chunk_len] = '\0';
416
        }
417
      }
418
    }
419
    else { /* chunk_start != '@' */
420
      /*
421
       * no host name given, keep string empty
422
       */
423
      *hostnamep = malloc(1);
424
      if (*hostnamep == NULL) {
425
        rc = ENOMEM;
426
      }
427
      else {
428
        (*hostnamep)[0] = '\0';
429
      }
430
    }
431
  }
432
  /*
433
   * fetch filename. This is all the rest...
434
   */
435
  if (rc == 0) {
436
    chunk_start = chunk_end+1;
437
    if (*chunk_start == '\0') {  /* nothing left for filename */
438
      rc = ENOENT;
439
    }
440
    else {
441
      chunk_len = strlen(chunk_start);
442
      *filenamep = malloc(chunk_len);
443
      if (*filenamep == NULL) {
444
        rc = ENOMEM;
445
      }
446
      else {
447
        memcpy(*filenamep,chunk_start,chunk_len);
448
        (*filenamep)[chunk_len] = '\0';
449
      }
450
    }
451
  }
452
 
453
  /*
454
   * cleanup anything, if error occured
455
   */
456
  if (rc != 0) {
457
    if (*hostnamep != NULL) {
458
      free(*hostnamep);
459
      *hostnamep = NULL;
460
    }
461
    if (*usernamep != NULL) {
462
      free(*usernamep);
463
      *usernamep = NULL;
464
    }
465
    if (*passwordp != NULL) {
466
      free(*passwordp);
467
      *passwordp = NULL;
468
    }
469
    if (*filenamep != NULL) {
470
      free(*filenamep);
471
      *filenamep = NULL;
472
    }
473
  }
474
  return rc;
475
}
476
 
477
int rtems_ftp_evaluate_for_make(
478
   const char                         *path,       /* IN     */
479
   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
480
   const char                        **name        /* OUT    */
481
)
482
{
483
  set_errno_and_return_minus_one( EIO );
484
}
485
 
486
/*
487
 * XXX - Fix return values.
488
 */
489
 
490
int rtems_ftp_eval_path(
491
  const char                        *pathname,     /* IN     */
492
  int                                flags,        /* IN     */
493
  rtems_filesystem_location_info_t  *pathloc       /* IN/OUT */
494
)
495
{
496
 
497
  /*
498
   * Read-only for now
499
   */
500
 
501
  if ( ((flags & O_RDONLY) != O_RDONLY ) &&
502
       ((flags & O_WRONLY) != O_WRONLY )) {
503
    set_errno_and_return_minus_one( ENOENT );
504
  }
505
  /*
506
   * The File system is mounted at FTP_PATHNAME_PREFIX
507
   * the caller of this routine has striped off this part of the
508
   * name. Save the remainder of the name for use by the open routine.
509
   */
510
 
511
  pathloc->node_access = (void * ) pathname;
512
  pathloc->handlers    = &rtems_ftp_handlers;
513
 
514
  return 0;
515
}
516
 
517
/*
518
 * Open a FTP stream
519
 */
520
int rtems_ftp_open(
521
  rtems_libio_t *iop,
522
  const char    *new_name,
523
  unsigned32     flag,
524
  unsigned32     mode
525
)
526
{
527
  int s = 0;
528
  char *filename  = NULL;
529
  char *uname     = NULL;
530
  char *upass     = NULL;
531
  char *hostname  = NULL;
532
  char port_buffer[sizeof(FTP_PORT_CMD)+6*4+1+1];
533
  rtems_unsigned32 my_ip;
534
  rtems_unsigned16 my_port;
535
  int eno = 0;
536
  rtems_status_code rc;
537
  rtems_boolean is_write = FALSE;
538
  rtems_boolean sema_obtained = FALSE;
539
  struct ftpStream *fsp = NULL;
540
  int msg_tmp;
541
  int sockaddr_size;
542
  /*
543
   * check for R/O or W/O flags
544
   */
545
  if (eno == 0) {
546
    if ((0 != (iop->flags & LIBIO_FLAGS_WRITE)) &&
547
        (0 != (iop->flags & LIBIO_FLAGS_READ))) {
548
      eno = ENOTSUP;
549
    }
550
    else {
551
      is_write = (0 != (iop->flags & LIBIO_FLAGS_WRITE));
552
    }
553
  }
554
  /*
555
   * split pathname into parts
556
   */
557
  if (eno == 0) {
558
    eno = rtems_ftp_split_names(iop->file_info,
559
                                &uname,
560
                                &upass,
561
                                &hostname,
562
                                &filename);
563
  }
564
 
565
  /*
566
   * Find a free stream
567
   */
568
  if (eno == 0) {
569
    rc = rtems_semaphore_obtain (ftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
570
    if (rc == RTEMS_SUCCESSFUL) {
571
      sema_obtained = TRUE;
572
    }
573
    else {
574
      eno = EBUSY;
575
    }
576
  }
577
  if (eno == 0) {
578
    for (s = 0 ; s < nStreams ; s++) {
579
      if (ftpStreams[s] == NULL)
580
        break;
581
    }
582
    if (s == nStreams) {
583
      /*
584
       * Reallocate stream pointers
585
       * Guard against the case where realloc() returns NULL.
586
       */
587
      struct ftpStream **np;
588
 
589
      np = realloc (ftpStreams, ++nStreams * sizeof *ftpStreams);
590
      if (np == NULL) {
591
        eno = ENOMEM;
592
      }
593
      else {
594
        ftpStreams = np;
595
      }
596
    }
597
  }
598
  if (eno == 0) {
599
    fsp = ftpStreams[s] = malloc (sizeof (struct ftpStream));
600
    rtems_semaphore_release (ftp_mutex);
601
    sema_obtained = FALSE;
602
    if (fsp == NULL) {
603
      eno = ENOMEM;
604
    }
605
    else {
606
      iop->data0 = s;
607
      iop->data1 = fsp;
608
      fsp->ctrl_socket = -1; /* mark, that sockets not yet created */
609
      fsp->port_socket = -1;
610
      fsp->data_socket = -1;
611
      fsp->eof_reached = FALSE;
612
    }
613
  }
614
  if (eno == 0) {
615
  /*
616
   * Create the socket for control connection
617
   */
618
    if ((fsp->ctrl_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
619
      eno = ENOMEM;
620
    }
621
  }
622
 
623
  if (eno == 0) {
624
    /*
625
     * Set the destination to the FTP server
626
     * port on the remote machine.
627
     */
628
    memset(&(fsp->farCtrlAddress),sizeof(fsp->farCtrlAddress),0);
629
    fsp->farCtrlAddress.sin_family = AF_INET;
630
    if (*hostname == '\0') {
631
      fsp->farCtrlAddress.sin_addr.s_addr = rtems_bsdnet_bootp_server_address.s_addr;
632
    }
633
    else if (1 != inet_aton(hostname,&(fsp->farCtrlAddress.sin_addr))) {
634
      struct hostent *hent;
635
      struct hostent *gethostbyname(const char *name);
636
 
637
      hent = gethostbyname(hostname);
638
      if (hent != NULL) {
639
        bcopy(hent->h_addr,
640
              (char *)(&(fsp->farCtrlAddress.sin_addr)),
641
              sizeof(fsp->farCtrlAddress.sin_addr));
642
      }
643
      else {
644
        eno = ENOENT;
645
      }
646
    }
647
    if (eno == 0) {
648
      fsp->farCtrlAddress.sin_port = htons (FTP_PORT_NUM);
649
      fsp->farCtrlAddress.sin_len  = sizeof(fsp->farCtrlAddress);
650
      if (0 > connect(fsp->ctrl_socket,
651
                      (struct sockaddr *)&(fsp->farCtrlAddress),
652
                      sizeof(fsp->farCtrlAddress))) {
653
        eno = ENOENT;
654
      }
655
    }
656
    if (eno == 0) {
657
      /*
658
       * fetch IP address of interface used
659
       */
660
      memset(&(fsp->myCtrlAddress),sizeof(fsp->myCtrlAddress),0);
661
      fsp->myCtrlAddress.sin_family = AF_INET;
662
      fsp->myCtrlAddress.sin_addr.s_addr = INADDR_ANY;
663
      fsp->myCtrlAddress.sin_port   = 0;
664
      fsp->myCtrlAddress.sin_len  = sizeof(fsp->myDataAddress);
665
      sockaddr_size = sizeof(fsp->myCtrlAddress);
666
      if (0 > getsockname(fsp->ctrl_socket,
667
                          (struct sockaddr *)&(fsp->myCtrlAddress),
668
                          &sockaddr_size)) {
669
        eno = ENOMEM;
670
      }
671
    }
672
  }
673
  if (eno == 0) {
674
    /*
675
     * now we should get a connect message from the FTP server
676
     */
677
    eno = rtems_ftp_get_message(fsp,&msg_tmp);
678
    if ((eno == 0) &&
679
        (msg_tmp != FTP_REPLY_CONNECT)) {
680
      eno = ENOENT;
681
    }
682
  }
683
  if (eno == 0) {
684
    /*
685
     * send user ID to server
686
     * NOTE: the following lines will be executed in order
687
     * and will be aborted whenever an error occures... (see your ANSI C book)
688
     */
689
    if ((0 > send(fsp->ctrl_socket,FTP_USER_CMD,strlen(FTP_USER_CMD),0)) ||
690
        (0 > send(fsp->ctrl_socket,uname,       strlen(uname),       0)) ||
691
        (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
692
      eno = EIO;
693
    }
694
  }
695
  if (eno == 0) {
696
    /*
697
     * now we should get a request for the password or a login...
698
     */
699
    eno = rtems_ftp_get_message(fsp,&msg_tmp);
700
    if (eno == 0) {
701
      if (msg_tmp == FTP_REPLY_PASSREQ) {
702
        /*
703
         * send password to server
704
         */
705
#ifdef DEBUG_OUT
706
        write(1,FTP_PASS_CMD,strlen(FTP_PASS_CMD));
707
        write(1,upass,       strlen(upass)       );
708
        write(1,"\n",        1                   );
709
#endif    
710
        if ((0 > send(fsp->ctrl_socket,FTP_PASS_CMD,strlen(FTP_PASS_CMD),0)) ||
711
            (0 > send(fsp->ctrl_socket,upass,       strlen(upass),       0)) ||
712
            (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
713
          eno = EIO;
714
        }
715
        /*
716
         * at least now a login reply should come up...
717
         * this is checked some lines downwards the code
718
         */
719
        if (eno == 0) {
720
          eno = rtems_ftp_get_message(fsp,&msg_tmp);
721
        }
722
      }
723
    }
724
  }
725
  if (eno == 0) {
726
    /*
727
     * check for a login reply. this should be present now...
728
     */
729
    if (msg_tmp != FTP_REPLY_LOGIN) {
730
      eno = EACCES; /* pseudo for wrong user/pass */
731
    }
732
  }
733
  if (eno == 0) {
734
    /*
735
     * set binary mode for all transfers
736
     */
737
#ifdef DEBUG_OUT
738
    write(1,FTP_BINARY_CMD,strlen(FTP_BINARY_CMD));
739
    write(1,"\n",        1                   );
740
#endif    
741
    if ((0 > send(fsp->ctrl_socket,FTP_BINARY_CMD,strlen(FTP_BINARY_CMD),0)) ||
742
        (0 > send(fsp->ctrl_socket,"\n",          1,                     0))) {
743
      eno = EIO;
744
    }
745
    else {
746
      eno = rtems_ftp_get_message(fsp,&msg_tmp);
747
    }
748
  }
749
  if (eno == 0) {
750
    /*
751
     * check for a "BINARY TYPE command successful" reply
752
     */
753
    if (msg_tmp != FTP_REPLY_SUCCESS) {
754
      eno = EIO;
755
    }
756
  }
757
  if (eno == 0) {
758
    /*
759
     * create and bind socket for data connection
760
     */
761
    if ((fsp->port_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
762
      eno = ENOMEM;
763
    }
764
    else {
765
      memset(&(fsp->myDataAddress),sizeof(fsp->myDataAddress),0);
766
      fsp->myDataAddress.sin_family = AF_INET;
767
      fsp->myDataAddress.sin_addr.s_addr = INADDR_ANY;
768
      fsp->myDataAddress.sin_port   = 0; /* unique port will be assigned */
769
      fsp->myDataAddress.sin_len  = sizeof(fsp->myDataAddress);
770
      if (0 > bind(fsp->port_socket,
771
                   (struct sockaddr *)&(fsp->myDataAddress),
772
                   sizeof(fsp->myDataAddress))) {
773
        eno = EBUSY;
774
      }
775
      else {
776
        /*
777
         * fetch port number of data socket
778
         */
779
        memset(&(fsp->myDataAddress),sizeof(fsp->myDataAddress),0);
780
        fsp->myDataAddress.sin_family = AF_INET;
781
        fsp->myDataAddress.sin_addr.s_addr = INADDR_ANY;
782
        fsp->myDataAddress.sin_port   = 0;
783
        fsp->myDataAddress.sin_len  = sizeof(fsp->myDataAddress);
784
        sockaddr_size = sizeof(fsp->myDataAddress);
785
        if (0 > getsockname(fsp->port_socket,
786
                            (struct sockaddr *)&(fsp->myDataAddress),
787
                            &sockaddr_size)) {
788
          eno = ENOMEM;
789
        }
790
      }
791
    }
792
  }
793
  if (eno == 0) {
794
    /*
795
     * propagate data connection port to server
796
     */
797
    my_ip   = ntohl(fsp->myCtrlAddress.sin_addr.s_addr);
798
    my_port = ntohs(fsp->myDataAddress.sin_port);
799
    sprintf(port_buffer,"%s%u,%u,%u,%u,%u,%u\n",
800
            FTP_PORT_CMD,
801
            (my_ip >> 24) & 0x00ff,
802
            (my_ip >> 16) & 0x00ff,
803
            (my_ip >>  8) & 0x00ff,
804
            (my_ip >>  0) & 0x00ff,
805
            (my_port>> 8) & 0x00ff,
806
            (my_port>> 0) & 0x00ff);
807
#ifdef DEBUG_OUT
808
    write(1,port_buffer,strlen(port_buffer));
809
#endif
810
    if (0 > send(fsp->ctrl_socket,port_buffer,strlen(port_buffer),0)) {
811
      eno = EIO;
812
    }
813
    else {
814
      eno = rtems_ftp_get_message(fsp,&msg_tmp);
815
    }
816
  }
817
  if (eno == 0) {
818
    /*
819
     * check for a "PORT command successful" reply
820
     */
821
    if (msg_tmp != FTP_REPLY_SUCCESS) {
822
      eno = EBUSY;
823
    }
824
  }
825
  /*
826
   * prepare port socket to listen for incoming connections
827
   */
828
  if (eno == 0) {
829
    if (0 > listen(fsp->port_socket,1)) {
830
      eno = EBUSY;
831
    }
832
  }
833
  if (eno == 0) {
834
    /*
835
     * send retrive/store command with filename
836
     */
837
    if (is_write) {
838
#ifdef DEBUG_OUT
839
    write(1,FTP_STOR_CMD,strlen(FTP_STOR_CMD));
840
    write(1,filename    ,strlen(filename)    );
841
    write(1,"\n",1);
842
#endif
843
      if ((0 > send(fsp->ctrl_socket,FTP_STOR_CMD,strlen(FTP_STOR_CMD),0)) ||
844
          (0 > send(fsp->ctrl_socket,filename,    strlen(filename),    0)) ||
845
          (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
846
        eno = EIO;
847
      }
848
    }
849
    else {
850
#ifdef DEBUG_OUT
851
    write(1,FTP_RETR_CMD,strlen(FTP_RETR_CMD));
852
    write(1,filename    ,strlen(filename)    );
853
    write(1,"\n",1);
854
#endif
855
      if ((0 > send(fsp->ctrl_socket,FTP_RETR_CMD,strlen(FTP_RETR_CMD),0)) ||
856
          (0 > send(fsp->ctrl_socket,filename,    strlen(filename),    0)) ||
857
          (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
858
        eno = EIO;
859
      }
860
    }
861
  }
862
#if 1
863
  if (eno == 0) {
864
    eno = rtems_ftp_get_message(fsp,&msg_tmp);
865
  }
866
  if (eno == 0) {
867
    /*
868
     * check for a "OPENING binary connection" reply
869
     */
870
    if (msg_tmp != FTP_REPLY_OPENCONN) {
871
      eno = EACCES;
872
    }
873
  }
874
#endif
875
  /*
876
   * wait for connect on data connection
877
   * FIXME: this should become a select instead with a timeout
878
   */
879
  if (eno == 0) {
880
    sockaddr_size = sizeof(fsp->farDataAddress);
881
    fsp->data_socket = accept(fsp->port_socket,
882
                              (struct sockaddr *)&(fsp->farDataAddress),
883
                              &sockaddr_size);
884
    if (0 > fsp->data_socket) {
885
      eno = EIO;
886
    }
887
  }
888
  /*
889
   * FIXME: check, that fardataAddr is really from our ftp server
890
   */
891
 
892
  /*
893
   * clean up temp strings...
894
   */
895
  if (uname != NULL) {
896
    free(uname);
897
    uname = NULL;
898
  }
899
  if (upass != NULL) {
900
    free(upass);
901
    upass = NULL;
902
  }
903
  if (hostname != NULL) {
904
    free(hostname);
905
    hostname = NULL;
906
  }
907
  if (filename != NULL) {
908
    free(filename);
909
    filename = NULL;
910
  }
911
  /*
912
   * close part socket, no longer needed
913
   */
914
  if (fsp->port_socket != -1) {
915
    close(fsp->port_socket);
916
    fsp->port_socket = -1;
917
  }
918
  /*
919
   * if error, clean up everything
920
   */
921
  if (eno != 0) {
922
    if (fsp != NULL) {
923
      /*
924
       * check and close ctrl/data connection
925
       */
926
      if (fsp->data_socket != -1) {
927
        close(fsp->data_socket);
928
        fsp->data_socket = -1;
929
      }
930
      if (fsp->ctrl_socket != -1) {
931
        close(fsp->ctrl_socket);
932
        fsp->ctrl_socket = -1;
933
      }
934
      /*
935
       * free ftpStream structure
936
       */
937
      ftpStreams[s] = NULL;
938
      free(fsp);
939
      fsp = NULL;
940
    }
941
  }
942
  /*
943
   * return sema, if still occupied
944
   */
945
  if (sema_obtained) {
946
    rtems_semaphore_release (ftp_mutex);
947
    sema_obtained = FALSE;
948
  }
949
#if 0
950
  if (eno != 0) {
951
    set_errno_and_return_minus_one(eno);
952
  }
953
  return 0;
954
#else
955
  return eno;
956
#endif
957
}
958
 
959
/*
960
 * Read from a FTP stream
961
 */
962
int rtems_ftp_read(
963
  rtems_libio_t *iop,
964
  void          *buffer,
965
  unsigned32     count
966
)
967
{
968
  int eno = 0;
969
  struct ftpStream *fsp;
970
  size_t want_cnt;
971
  ssize_t rd_cnt;
972
  int msg_tmp;
973
 
974
  fsp = iop->data1;
975
  want_cnt = count;
976
  /*
977
   * check, that data connection present
978
   */
979
  if (eno == 0) {
980
    if ((fsp == NULL) ||
981
        (fsp->data_socket < 0)) {
982
      eno = EBADF;
983
    }
984
  }
985
 
986
  /*
987
   * perform read from data socket
988
   * read multiple junks, if smaller than wanted
989
   */
990
  while ((eno == 0) &&
991
         (want_cnt > 0) &&
992
         !(fsp->eof_reached) ) {
993
    rd_cnt = read(fsp->data_socket,buffer,want_cnt);
994
    if (rd_cnt > 0) {
995
      buffer += rd_cnt;
996
      want_cnt -= rd_cnt;
997
    }
998
    else {
999
      eno = rtems_ftp_get_message(fsp,&msg_tmp);
1000
      fsp->eof_reached = TRUE;
1001
      if ((eno == 0) &&
1002
          (msg_tmp != FTP_REPLY_TFERCMPL)) {
1003
        eno = EIO;
1004
      }
1005
      if (rd_cnt < 0) {
1006
        eno = EIO;
1007
      }
1008
    }
1009
  }
1010
  if (eno != 0) {
1011
    set_errno_and_return_minus_one(eno);
1012
  }
1013
  return count - want_cnt;
1014
}
1015
 
1016
int rtems_ftp_write(
1017
  rtems_libio_t *iop,
1018
  const void    *buffer,
1019
  unsigned32     count
1020
)
1021
{
1022
  int eno = EIO;
1023
  struct ftpStream *fsp;
1024
  size_t want_cnt;
1025
  ssize_t wr_cnt;
1026
  int msg_tmp;
1027
 
1028
  fsp = iop->data1;
1029
  want_cnt = count;
1030
  /*
1031
   * check, that data connection present
1032
   */
1033
  if (eno == 0) {
1034
    if ((fsp == NULL) ||
1035
        (fsp->data_socket < 0)) {
1036
      eno = EBADF;
1037
    }
1038
  }
1039
 
1040
  /*
1041
   * perform write to data socket
1042
   */
1043
  if (eno == 0) {
1044
    wr_cnt = write(fsp->data_socket,buffer,want_cnt);
1045
    if (wr_cnt > 0) {
1046
      buffer += wr_cnt;
1047
      want_cnt -= wr_cnt;
1048
    }
1049
    else {
1050
      eno = rtems_ftp_get_message(fsp,&msg_tmp);
1051
      if ((eno == 0) &&
1052
          (msg_tmp != FTP_REPLY_TFERCMPL)) {
1053
        eno = EIO;
1054
      }
1055
      if (wr_cnt < 0) {
1056
        eno = EIO;
1057
      }
1058
    }
1059
  }
1060
  if (eno != 0) {
1061
    set_errno_and_return_minus_one(eno);
1062
  }
1063
  return count - want_cnt;
1064
}
1065
 
1066
/*
1067
 * Close a FTP stream
1068
 */
1069
int rtems_ftp_close(
1070
  rtems_libio_t *iop
1071
)
1072
{
1073
  int s = iop->data0;
1074
  struct ftpStream *fsp = iop->data1;
1075
 
1076
  /*
1077
   * close ctrl/data connection, if needed
1078
   */
1079
  if (fsp->data_socket >= 0) {
1080
    close(fsp->data_socket);
1081
    fsp->data_socket = -1;
1082
  }
1083
  if (fsp->ctrl_socket >= 0) {
1084
    close(fsp->ctrl_socket);
1085
    fsp->ctrl_socket = -1;
1086
  }
1087
  /*
1088
   * free any used space...
1089
   */
1090
  rtems_semaphore_obtain (ftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
1091
  free (ftpStreams[s]);
1092
  ftpStreams[s] = NULL;
1093
  rtems_semaphore_release (ftp_mutex);
1094
 
1095
  return 0;
1096
}
1097
 
1098
rtems_device_driver rtems_ftp_control(
1099
  rtems_device_major_number major,
1100
  rtems_device_minor_number minor,
1101
  void *pargp
1102
)
1103
{
1104
  return RTEMS_NOT_CONFIGURED;
1105
}
1106
 
1107
/*
1108
 * Dummy version to let fopen(xxxx,"w") work properly.
1109
 */
1110
static int rtems_ftp_ftruncate(
1111
    rtems_libio_t   *iop,
1112
    off_t           count
1113
)
1114
{
1115
    return 0;
1116
}
1117
 
1118
rtems_filesystem_node_types_t rtems_ftp_node_type(
1119
     rtems_filesystem_location_info_t        *pathloc                 /* IN */
1120
)
1121
{
1122
    return RTEMS_FILESYSTEM_MEMORY_FILE;
1123
}
1124
 
1125
rtems_filesystem_operations_table  rtems_ftp_ops = {
1126
    rtems_ftp_eval_path,             /* eval_path */
1127
    rtems_ftp_evaluate_for_make,     /* evaluate_for_make */
1128
    NULL,                            /* link */
1129
    NULL,                            /* unlink */
1130
    rtems_ftp_node_type,             /* node_type */
1131
    NULL,                            /* mknod */
1132
    NULL,                            /* chown */
1133
    NULL,                            /* freenodinfo */
1134
    NULL,                            /* mount */
1135
    rtems_ftp_mount_me,              /* initialize */
1136
    NULL,                            /* unmount */
1137
    NULL,                            /* fsunmount */
1138
    NULL,                            /* utime, */
1139
    NULL,                            /* evaluate_link */
1140
    NULL,                            /* symlink */
1141
    NULL,                            /* readlin */
1142
};
1143
 
1144
rtems_filesystem_file_handlers_r rtems_ftp_handlers = {
1145
    rtems_ftp_open,      /* open */
1146
    rtems_ftp_close,     /* close */
1147
    rtems_ftp_read,      /* read */
1148
    rtems_ftp_write,     /* write */
1149
    NULL,                /* ioctl */
1150
    NULL,                /* lseek */
1151
    NULL,                /* fstat */
1152
    NULL,                /* fchmod */
1153
    rtems_ftp_ftruncate, /* ftruncate */
1154
    NULL,                /* fpathconf */
1155
    NULL,                /* fsync */
1156
    NULL,                /* fdatasync */
1157
    NULL,                /* fcntl */
1158
    NULL                 /* rmnod */
1159
};

powered by: WebSVN 2.1.0

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