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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [common/] [current/] [src/] [tftp_client.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      lib/tftp_client.c
4
//
5
//      TFTP client support
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, 2003 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY 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        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas, andrew.lunn@ascom.ch
44
// Date:         2000-04-06
45
// Purpose:      
46
// Description:  
47
//              
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
// TFTP client support
54
 
55
#include <network.h>
56
#include <arpa/tftp.h>
57
#include <tftp_support.h>
58
#include <stdlib.h>
59
#include <stdio.h>
60
 
61
#define min(x,y) (x<y ? x : y)
62
 
63
//
64
// Read a file from a host into a local buffer.  Returns the
65
// number of bytes actually read, or (-1) if an error occurs.
66
// On error, *err will hold the reason.
67
// This version uses the server name. This can be a name for DNS lookup
68
// or a dotty or colony number format for IPv4 or IPv6.
69
static int tftp_client_get_inner(char *data,
70
                    const char * const filename,
71
                    const char * const server,
72
                    const int port,
73
                    char *buf,
74
                    int len,
75
                    const int mode,
76
                    int * const err
77
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
78
                    ,int negotiate
79
#endif
80
                    ) {
81
 
82
        int blksize=SEGSIZE;
83
    int result = 0;
84
    int s=-1;
85
    int actual_len, data_len;
86
    socklen_t from_len, recv_len;
87
    static int get_port = 7700;
88
    struct addrinfo * addrinfo;
89
    struct addrinfo * res;
90
    struct addrinfo hints;
91
    int error;
92
 
93
    struct sockaddr local_addr, from_addr;
94
    struct tftphdr *hdr = (struct tftphdr *)data;
95
    const char *fp;
96
    char *cp, *bp;
97
    struct timeval timeout;
98
    unsigned short last_good_block = 0;
99
    fd_set fds;
100
    int total_timeouts = 0;
101
 
102
    *err = 0;  // Just in case
103
 
104
    // Create initial request
105
    hdr->th_opcode = htons(RRQ);  // Read file
106
    cp = (char *)&hdr->th_stuff;
107
    fp = filename;
108
    while (*fp) *cp++ = *fp++;
109
    *cp++ = '\0';
110
    if (mode == TFTP_NETASCII) {
111
        fp = "NETASCII";
112
    } else if (mode == TFTP_OCTET) {
113
        fp = "OCTET";
114
    } else {
115
        *err = TFTP_INVALID;
116
        return -1;
117
    }
118
    while (*fp) *cp++ = *fp++;
119
    *cp++ = '\0';
120
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
121
    if (negotiate) {
122
        fp="blksize";
123
        while (*fp)
124
          *cp++ = *fp++;
125
        *cp++ = '\0';
126
        cp+=sprintf(cp, "%d", CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET_SIZE);
127
        *cp++ = '\0';
128
    }
129
#endif
130
 
131
    memset(&hints,0,sizeof(hints));
132
    hints.ai_family = PF_UNSPEC;
133
    error = getaddrinfo(server, "tftp", &hints, &res);
134
    if (error) {
135
      *err = TFTP_NETERR;
136
      return -1;
137
    }
138
 
139
    addrinfo = res;
140
    while (addrinfo) {
141
      s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
142
                 addrinfo->ai_protocol);
143
      if (s >= 0) {
144
        memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
145
        switch(addrinfo->ai_addr->sa_family) {
146
        case AF_INET: {
147
          struct sockaddr_in * saddr =
148
            (struct sockaddr_in *) addrinfo->ai_addr;
149
          struct sockaddr_in * laddr =
150
            (struct sockaddr_in *) &local_addr;
151
          if (port) {
152
            saddr->sin_port = htons(port);
153
          }
154
          laddr->sin_port = htons(get_port++);
155
          laddr->sin_addr.s_addr = INADDR_ANY;
156
          break;
157
        }
158
#ifdef CYGPKG_NET_INET6
159
        case AF_INET6: {
160
          struct sockaddr_in6 * saddr =
161
            (struct sockaddr_in6 *) addrinfo->ai_addr;
162
          struct sockaddr_in6 * laddr =
163
            (struct sockaddr_in6 *) &local_addr;
164
          if (port) {
165
            saddr->sin6_port = htons(port);
166
          }
167
          laddr->sin6_port = htons(get_port++);
168
          laddr->sin6_addr = in6addr_any;
169
          break;
170
        }
171
#endif
172
        default:
173
          *err = TFTP_NETERR;
174
          goto out;
175
        }
176
 
177
        if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) {
178
          *err = TFTP_NETERR;
179
          goto out;
180
        }
181
 
182
        // Send request
183
        if (sendto(s, data, (int)(cp-data), 0,
184
                   addrinfo->ai_addr,
185
                   addrinfo->ai_addrlen) < 0) {
186
          // Problem sending request
187
          *err = TFTP_NETERR;
188
          goto nextaddr;
189
        }
190
 
191
        // Read data
192
        bp = buf;
193
        while (true) {
194
          timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
195
          timeout.tv_usec = 0;
196
          FD_ZERO(&fds);
197
          FD_SET(s, &fds);
198
          if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
199
            total_timeouts++;
200
            if ((last_good_block == 0) && (total_timeouts > TFTP_RETRIES_MAX)) {
201
              // Timeout - no data received. Probably no server.
202
              *err = TFTP_TIMEOUT;
203
              goto nextaddr;
204
            }
205
            if (total_timeouts > TFTP_TIMEOUT_MAX) {
206
              // Timeout - have received data. Network problem?
207
              *err = TFTP_TIMEOUT;
208
              goto out;
209
            }
210
 
211
            if (last_good_block == 0 ) {
212
              // Send request
213
              if (sendto(s, data, (int)(cp-data), 0,
214
                         addrinfo->ai_addr,
215
                         addrinfo->ai_addrlen) < 0) {
216
                // Problem sending request
217
                *err = TFTP_NETERR;
218
                goto nextaddr;
219
              }
220
            } else {
221
              // Try resending last ACK
222
              hdr->th_opcode = htons(ACK);
223
              hdr->th_block = htons(last_good_block);
224
              if (sendto(s, data, 4 /* FIXME */, 0,
225
                         &from_addr, from_len) < 0) {
226
                // Problem sending request
227
                *err = TFTP_NETERR;
228
                goto out;
229
              }
230
            }
231
          } else {
232
            recv_len = blksize+sizeof(struct tftphdr);
233
            from_len = sizeof(from_addr);
234
            if ((data_len = recvfrom(s, data, recv_len, 0,
235
                                     &from_addr, &from_len)) < 0) {
236
              // What happened?
237
              *err = TFTP_NETERR;
238
              goto out;
239
            }
240
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
241
            if (ntohs(hdr->th_opcode) == OACK) {
242
              // We can have only *one* option, the one we sent..
243
              if (strncmp(data+2, "blksize", data_len)==0) {
244
                blksize=atol(data+2+strlen("blksize")+1);
245
              } else {
246
                // option ignored, use default.
247
              }
248
              // Send out the ACK
249
              hdr->th_opcode = htons(ACK);
250
              hdr->th_block = htons(last_good_block);
251
              if (sendto(s, data, 4 /* FIXME */, 0,
252
                         &from_addr, from_len) < 0) {
253
                // Problem sending request
254
                *err = TFTP_NETERR;
255
                goto out;
256
              }
257
            } else
258
#endif
259
              if (ntohs(hdr->th_opcode) == DATA) {
260
                actual_len = 0;
261
                if (ntohs(hdr->th_block) == (last_good_block+1)) {
262
                  // Consume this data
263
                  cp = hdr->th_data;
264
                  data_len -= 4;  /* Sizeof TFTP header */
265
                  actual_len = data_len;
266
                  result += actual_len;
267
                  if (len<data_len)
268
                    {
269
                      // Buffer overflow
270
                      *err = TFTP_TOOLARGE;
271
                      goto out;
272
                    }
273
                  memcpy(bp, cp, data_len);
274
                  bp+=data_len;
275
                  len-=data_len;
276
                  last_good_block++;
277
                } else {
278
                  // To prevent an out-of-sequence packet from
279
                  // terminating transmission prematurely, set
280
                  // actual_len to a full size packet.
281
                  actual_len = blksize;
282
                }
283
                // Send out the ACK
284
                hdr->th_opcode = htons(ACK);
285
                hdr->th_block = htons(last_good_block);
286
                if (sendto(s, data, 4 /* FIXME */, 0,
287
                           &from_addr, from_len) < 0) {
288
                  // Problem sending request
289
                  *err = TFTP_NETERR;
290
                  goto out;
291
                }
292
                // A short packet marks the end of the file.
293
                /* 4 = Sizeof TFTP header */
294
                if ((actual_len >= 0) && (actual_len < blksize)) {
295
                  // End of data
296
                  close(s);
297
                  freeaddrinfo(res);
298
                  return result;
299
                }
300
              } else
301
                if (ntohs(hdr->th_opcode) == ERROR) {
302
                  *err = ntohs(hdr->th_code);
303
                  goto out;
304
                } else {
305
                  // What kind of packet is this?
306
                  *err = TFTP_PROTOCOL;
307
                  goto out;
308
                }
309
          }
310
        }
311
      }
312
      // If we got here, it means there was a problem connecting to the 
313
      // server. Try the next address returned by getaddrinfo
314
    nextaddr:
315
      if (-1 != s) {
316
        close(s);
317
      }
318
      addrinfo=addrinfo->ai_next;
319
    }
320
    // We ran into problems. Cleanup
321
 out:
322
    if (-1 != s) {
323
      close (s);
324
    }
325
    freeaddrinfo(res);
326
    return -1;
327
}
328
 
329
 
330
int tftp_client_get(const char * const filename,
331
                    const char * const server,
332
                    const int port,
333
                    char *buf,
334
                    int len,
335
                    const int mode,
336
                    int * const err) {
337
        int result;
338
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
339
        char *data = malloc(CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET_SIZE+
340
                            sizeof(struct tftphdr));
341
        if (data==NULL) {
342
          *err=TFTP_ENOSPACE;
343
          return -1;
344
        }
345
#else
346
        char data[SEGSIZE+sizeof(struct tftphdr)];
347
#endif
348
        result=tftp_client_get_inner(data, filename, server,
349
                                     port, buf, len, mode, err
350
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
351
                                     ,1
352
#endif
353
                                     );
354
        if (result<0)
355
          {
356
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
357
            // try without negotiating packet size. The serves that do
358
            // not support options negotiation may or may not ignore the
359
            // options. If they return an error in the case of options
360
            // this code path will try without packet size negotiation.
361
            result=tftp_client_get_inner(data, filename, server,
362
                                         port, buf, len, mode, err,
363
                                         0);
364
#endif
365
          }
366
 
367
#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET
368
        free(data);
369
#endif
370
 
371
        return result;
372
}
373
 
374
//
375
// Read a file from a host into a local buffer.  Returns the
376
// number of bytes actually read, or (-1) if an error occurs.
377
// On error, *err will hold the reason.
378
//
379
// Depreciated. Use tftp_client_get instead.
380
int
381
tftp_get(const char * const filename,
382
         const struct sockaddr_in * const server,
383
         char *buf,
384
         int len,
385
         const int mode,
386
         int * const err)
387
{
388
  char server_name[20];
389
  char *ret;
390
  int port;
391
 
392
  ret = inet_ntop(AF_INET, (void *)&server->sin_addr,
393
                  server_name, sizeof(server_name));
394
  if (NULL == ret) {
395
      *err = TFTP_NETERR;
396
      return -1;
397
  }
398
  port = server->sin_port;
399
 
400
  return tftp_client_get(filename, server_name, port, buf, len, mode, err);
401
}
402
 
403
//
404
// Send data to a file on a server via TFTP.
405
//
406
int
407
tftp_put(const char * const filename,
408
         const struct sockaddr_in * const server,
409
         const char *buf,
410
         int len,
411
         const int mode,
412
         int * const err)
413
{
414
  char server_name[20];
415
  char *ret;
416
  int port;
417
 
418
  ret = inet_ntop(AF_INET, (void *)&server->sin_addr,
419
                  server_name, sizeof(server_name));
420
  if (NULL == ret) {
421
      *err = TFTP_NETERR;
422
      return -1;
423
  }
424
  port = server->sin_port;
425
 
426
  return tftp_client_put(filename, server_name, port, buf, len, mode, err);
427
}
428
 
429
//
430
// Put a file to a host from a local buffer.  Returns the
431
// number of bytes actually writen, or (-1) if an error occurs.
432
// On error, *err will hold the reason.
433
// This version uses the server name. This can be a name for DNS lookup
434
// or a dotty or colony number format for IPv4 or IPv6.
435
int tftp_client_put(const char * const filename,
436
                    const char * const server,
437
                    const int port,
438
                    const char *buf,
439
                    int len,
440
                    const int mode,
441
                    int * const err) {
442
 
443
    int result = 0;
444
    int s = -1, actual_len, data_len;
445
    socklen_t recv_len, from_len;
446
    static int put_port = 7800;
447
    struct sockaddr local_addr, from_addr;
448
    char data[SEGSIZE+sizeof(struct tftphdr)];
449
    struct tftphdr *hdr = (struct tftphdr *)data;
450
    const char *fp, *sfp;
451
    char *cp;
452
    struct timeval timeout;
453
    unsigned short last_good_block = 0;
454
    fd_set fds;
455
    int total_timeouts = 0;
456
    struct addrinfo hints;
457
    struct addrinfo * addrinfo;
458
    struct addrinfo * res;
459
    int error;
460
 
461
    *err = 0;  // Just in case
462
 
463
    memset(&hints,0,sizeof(hints));
464
    hints.ai_family = PF_UNSPEC;
465
    error = getaddrinfo(server, "tftp", &hints, &res);
466
    if (error) {
467
      *err = TFTP_NETERR;
468
      return -1;
469
    }
470
 
471
    addrinfo = res;
472
    while (addrinfo) {
473
      s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
474
                 addrinfo->ai_protocol);
475
      if (s >= 0) {
476
        memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
477
        switch(addrinfo->ai_addr->sa_family) {
478
        case AF_INET: {
479
          struct sockaddr_in * saddr =
480
            (struct sockaddr_in *) addrinfo->ai_addr;
481
          struct sockaddr_in * laddr =
482
            (struct sockaddr_in *) &local_addr;
483
          if (port) {
484
            saddr->sin_port = htons(port);
485
          }
486
          laddr->sin_port = htons(put_port++);
487
          laddr->sin_addr.s_addr = INADDR_ANY;
488
          break;
489
        }
490
#ifdef CYGPKG_NET_INET6
491
        case AF_INET6: {
492
          struct sockaddr_in6 * saddr =
493
            (struct sockaddr_in6 *) addrinfo->ai_addr;
494
          struct sockaddr_in6 * laddr =
495
            (struct sockaddr_in6 *) &local_addr;
496
          if (port) {
497
            saddr->sin6_port = htons(port);
498
          }
499
          laddr->sin6_port = htons(put_port++);
500
          laddr->sin6_addr = in6addr_any;
501
          break;
502
        }
503
#endif
504
        default:
505
          *err = TFTP_NETERR;
506
          goto out;
507
        }
508
        if (bind(s,
509
                 (struct sockaddr *)&local_addr,
510
                 addrinfo->ai_addrlen) < 0) {
511
          // Problem setting up my end
512
          *err = TFTP_NETERR;
513
          goto out;
514
        }
515
 
516
        while (1) {
517
          // Create initial request
518
          hdr->th_opcode = htons(WRQ);  // Create/write file
519
          cp = (char *)&hdr->th_stuff;
520
          fp = filename;
521
          while (*fp) *cp++ = *fp++;
522
          *cp++ = '\0';
523
          if (mode == TFTP_NETASCII) {
524
            fp = "NETASCII";
525
          } else if (mode == TFTP_OCTET) {
526
            fp = "OCTET";
527
          } else {
528
            *err = TFTP_INVALID;
529
            goto out;
530
          }
531
          while (*fp) *cp++ = *fp++;
532
          *cp++ = '\0';
533
          // Send request
534
          if (sendto(s, data, (int)(cp-data), 0,
535
                     addrinfo->ai_addr,
536
                     addrinfo->ai_addrlen) < 0) {
537
            // Problem sending request
538
            *err = TFTP_NETERR;
539
            goto nextaddr;
540
          }
541
          // Wait for ACK
542
          timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
543
          timeout.tv_usec = 0;
544
          FD_ZERO(&fds);
545
          FD_SET(s, &fds);
546
          if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
547
            if (++total_timeouts > TFTP_RETRIES_MAX) {
548
              // Timeout - no ACK received
549
              *err = TFTP_TIMEOUT;
550
              goto nextaddr;
551
            }
552
          } else {
553
            recv_len = sizeof(data);
554
            from_len = sizeof(from_addr);
555
            if ((data_len = recvfrom(s, &data, recv_len, 0,
556
                                     &from_addr, &from_len)) < 0) {
557
              // What happened?
558
              *err = TFTP_NETERR;
559
              goto out;
560
            }
561
            if (ntohs(hdr->th_opcode) == ACK) {
562
              // Write request accepted - start sending data
563
              break;
564
            } else
565
              if (ntohs(hdr->th_opcode) == ERROR) {
566
                *err = ntohs(hdr->th_code);
567
                goto out;
568
              } else {
569
                // What kind of packet is this?
570
                goto out;
571
              }
572
          }
573
        }
574
 
575
        // Send data
576
        sfp = buf;
577
        last_good_block = 1;
578
        while (result < len) {
579
          // Build packet of data to send
580
          data_len = min(SEGSIZE, len-result);
581
          hdr->th_opcode = htons(DATA);
582
          hdr->th_block = htons(last_good_block);
583
          cp = hdr->th_data;
584
          fp = sfp;
585
          actual_len = data_len + 4;
586
          // FIXME - what about "netascii" data?
587
          while (data_len-- > 0) *cp++ = *fp++;
588
          // Send data packet
589
          if (sendto(s, data, actual_len, 0,
590
                     &from_addr, from_len) < 0) {
591
            // Problem sending request
592
            *err = TFTP_NETERR;
593
            goto out;
594
          }
595
          // Wait for ACK
596
          timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
597
          timeout.tv_usec = 0;
598
          FD_ZERO(&fds);
599
          FD_SET(s, &fds);
600
          if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
601
            if (++total_timeouts > TFTP_TIMEOUT_MAX) {
602
              // Timeout - no data received
603
              *err = TFTP_TIMEOUT;
604
              goto out;
605
            }
606
          } else {
607
            recv_len = sizeof(data);
608
            from_len = sizeof(from_addr);
609
            if ((data_len = recvfrom(s, &data, recv_len, 0,
610
                                     &from_addr, &from_len)) < 0) {
611
              // What happened?
612
              *err = TFTP_NETERR;
613
              goto out;
614
            }
615
            if (ntohs(hdr->th_opcode) == ACK) {
616
              if (ntohs(hdr->th_block) == last_good_block) {
617
                // Advance pointers, etc
618
                sfp = fp;
619
                result += (actual_len - 4);
620
                last_good_block++;
621
              } else {
622
                diag_printf("Send block #%d, got ACK for #%d\n",
623
                            last_good_block, ntohs(hdr->th_block));
624
              }
625
            } else
626
              if (ntohs(hdr->th_opcode) == ERROR) {
627
                *err = ntohs(hdr->th_code);
628
                goto out;
629
              } else {
630
                // What kind of packet is this?
631
                *err = TFTP_PROTOCOL;
632
                goto out;
633
              }
634
          }
635
        }
636
        close (s);
637
        return result;
638
      }
639
 
640
      // If we got here, it means there was a problem connecting to the 
641
      // server. Try the next address returned by getaddrinfo
642
    nextaddr:
643
      if (-1 != s) {
644
        close(s);
645
      }
646
      addrinfo=addrinfo->ai_next;
647
    }
648
    // We ran into problems. Cleanup
649
 out:
650
    if (-1 != s) {
651
      close (s);
652
    }
653
    freeaddrinfo(res);
654
    return -1;
655
}
656
 
657
// EOF tftp_client.c

powered by: WebSVN 2.1.0

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