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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [common/] [v2_0/] [src/] [tftp_client.c] - Blame information for rev 790

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
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 Red Hat, 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 version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):    gthomas
44
// Contributors: gthomas
45
// Date:         2000-04-06
46
// Purpose:      
47
// Description:  
48
//              
49
//
50
//####DESCRIPTIONEND####
51
//
52
//==========================================================================
53
 
54
// TFTP client support
55
 
56
#include <network.h>
57
#include <arpa/tftp.h>
58
#include <tftp_support.h>
59
 
60
#define min(x,y) (x<y ? x : y)
61
 
62
//
63
// Read a file from a host into a local buffer.  Returns the
64
// number of bytes actually read, or (-1) if an error occurs.
65
// On error, *err will hold the reason.
66
//
67
int
68
tftp_get(char *filename,
69
         struct sockaddr_in *server,
70
         char *buf,
71
         int len,
72
         int mode,
73
         int *err)
74
{
75
    int res = 0;
76
    int s, actual_len, data_len, recv_len, from_len;
77
    static int get_port = 7700;
78
    struct sockaddr_in local_addr, server_addr, from_addr;
79
    char data[SEGSIZE+sizeof(struct tftphdr)];
80
    struct tftphdr *hdr = (struct tftphdr *)data;
81
    char *cp, *fp;
82
    struct timeval timeout;
83
    unsigned short last_good_block = 0;
84
    struct servent *server_info;
85
    fd_set fds;
86
    int total_timeouts = 0;
87
 
88
    *err = 0;  // Just in case
89
 
90
    // Create initial request
91
    hdr->th_opcode = htons(RRQ);  // Read file
92
    cp = (char *)&hdr->th_stuff;
93
    fp = filename;
94
    while (*fp) *cp++ = *fp++;
95
    *cp++ = '\0';
96
    if (mode == TFTP_NETASCII) {
97
        fp = "NETASCII";
98
    } else if (mode == TFTP_OCTET) {
99
        fp = "OCTET";
100
    } else {
101
        *err = TFTP_INVALID;
102
        return -1;
103
    }
104
    while (*fp) *cp++ = *fp++;
105
    *cp++ = '\0';
106
    server_info = getservbyname("tftp", "udp");
107
    if (server_info == (struct servent *)0) {
108
        *err = TFTP_NETERR;
109
        return -1;
110
    }
111
 
112
    s = socket(AF_INET, SOCK_DGRAM, 0);
113
    if (s < 0) {
114
        // Couldn't open a communications channel
115
        *err = TFTP_NETERR;
116
        return -1;
117
    }
118
    memset((char *)&local_addr, 0, sizeof(local_addr));
119
    local_addr.sin_family = AF_INET;
120
    local_addr.sin_len = sizeof(local_addr);
121
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
122
    local_addr.sin_port = htons(get_port++);
123
    if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
124
        // Problem setting up my end
125
        *err = TFTP_NETERR;
126
        close(s);
127
        return -1;
128
    }
129
    memset((char *)&server_addr, 0, sizeof(server_addr));
130
    server_addr.sin_family = AF_INET;
131
    server_addr.sin_len = sizeof(server_addr);
132
    server_addr.sin_addr = server->sin_addr;
133
    if (server->sin_port == 0) {
134
        server_addr.sin_port = server_info->s_port; // Network order already
135
    } else {
136
        server_addr.sin_port = server->sin_port;
137
    }
138
 
139
    // Send request
140
    if (sendto(s, data, sizeof(data), 0,
141
               (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
142
        // Problem sending request
143
        *err = TFTP_NETERR;
144
        close(s);
145
        return -1;
146
    }
147
 
148
    // Read data
149
    fp = buf;
150
    while (true) {
151
        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
152
        timeout.tv_usec = 0;
153
        FD_ZERO(&fds);
154
        FD_SET(s, &fds);
155
        if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
156
            if ((++total_timeouts > TFTP_TIMEOUT_MAX) || (last_good_block == 0)) {
157
                // Timeout - no data received
158
                *err = TFTP_TIMEOUT;
159
                close(s);
160
                return -1;
161
            }
162
            // Try resending last ACK
163
            hdr->th_opcode = htons(ACK);
164
            hdr->th_block = htons(last_good_block);
165
            if (sendto(s, data, 4 /* FIXME */, 0,
166
                       (struct sockaddr *)&from_addr, from_len) < 0) {
167
                // Problem sending request
168
                *err = TFTP_NETERR;
169
                close(s);
170
                return -1;
171
            }
172
        } else {
173
            recv_len = sizeof(data);
174
            from_len = sizeof(from_addr);
175
            if ((data_len = recvfrom(s, &data, recv_len, 0,
176
                                     (struct sockaddr *)&from_addr, &from_len)) < 0) {
177
                // What happened?
178
                *err = TFTP_NETERR;
179
                close(s);
180
                return -1;
181
            }
182
            if (ntohs(hdr->th_opcode) == DATA) {
183
                actual_len = 0;
184
                if (ntohs(hdr->th_block) == (last_good_block+1)) {
185
                    // Consume this data
186
                    cp = hdr->th_data;
187
                    data_len -= 4;  /* Sizeof TFTP header */
188
                    actual_len = data_len;
189
                    res += actual_len;
190
                    while (data_len-- > 0) {
191
                        if (len-- > 0) {
192
                            *fp++ = *cp++;
193
                        } else {
194
                            // Buffer overflow
195
                            *err = TFTP_TOOLARGE;
196
                            close(s);
197
                            return -1;
198
                        }
199
                    }
200
                    last_good_block++;
201
                }
202
                // Send out the ACK
203
                hdr->th_opcode = htons(ACK);
204
                hdr->th_block = htons(last_good_block);
205
                if (sendto(s, data, 4 /* FIXME */, 0,
206
                           (struct sockaddr *)&from_addr, from_len) < 0) {
207
                    // Problem sending request
208
                    *err = TFTP_NETERR;
209
                    close(s);
210
                    return -1;
211
                }
212
                if ((actual_len >= 0) && (actual_len < SEGSIZE)) {
213
                    // End of data
214
                    close(s);
215
                    return res;
216
                }
217
            } else
218
            if (ntohs(hdr->th_opcode) == ERROR) {
219
                *err = ntohs(hdr->th_code);
220
                close(s);
221
                return -1;
222
            } else {
223
                // What kind of packet is this?
224
                *err = TFTP_PROTOCOL;
225
                close(s);
226
                return -1;
227
            }
228
        }
229
    }
230
}
231
 
232
//
233
// Send data to a file on a server via TFTP.
234
//
235
int
236
tftp_put(char *filename,
237
         struct sockaddr_in *server,
238
         char *buf,
239
         int len,
240
         int mode,
241
         int *err)
242
{
243
    int res = 0;
244
    int s, actual_len, data_len, recv_len, from_len;
245
    static int put_port = 7800;
246
    struct sockaddr_in local_addr, server_addr, from_addr;
247
    char data[SEGSIZE+sizeof(struct tftphdr)];
248
    struct tftphdr *hdr = (struct tftphdr *)data;
249
    char *cp, *fp, *sfp;
250
    struct timeval timeout;
251
    unsigned short last_good_block = 0;
252
    struct servent *server_info;
253
    fd_set fds;
254
    int total_timeouts = 0;
255
 
256
    *err = 0;  // Just in case
257
 
258
    server_info = getservbyname("tftp", "udp");
259
    if (server_info == (struct servent *)0) {
260
        *err = TFTP_NETERR;
261
        return -1;
262
    }
263
 
264
    s = socket(AF_INET, SOCK_DGRAM, 0);
265
    if (s < 0) {
266
        // Couldn't open a communications channel
267
        *err = TFTP_NETERR;
268
        return -1;
269
    }
270
    memset((char *)&local_addr, 0, sizeof(local_addr));
271
    local_addr.sin_family = AF_INET;
272
    local_addr.sin_len = sizeof(local_addr);
273
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
274
    local_addr.sin_port = htons(put_port++);
275
    if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
276
        // Problem setting up my end
277
        *err = TFTP_NETERR;
278
        close(s);
279
        return -1;
280
    }
281
    memset((char *)&server_addr, 0, sizeof(server_addr));
282
    server_addr.sin_family = AF_INET;
283
    server_addr.sin_len = sizeof(server_addr);
284
    server_addr.sin_addr = server->sin_addr;
285
    if (server->sin_port == 0) {
286
        server_addr.sin_port = server_info->s_port; // Network order already
287
    } else {
288
        server_addr.sin_port = server->sin_port;
289
    }
290
 
291
    while (1) {
292
        // Create initial request
293
        hdr->th_opcode = htons(WRQ);  // Create/write file
294
        cp = (char *)&hdr->th_stuff;
295
        fp = filename;
296
        while (*fp) *cp++ = *fp++;
297
        *cp++ = '\0';
298
        if (mode == TFTP_NETASCII) {
299
            fp = "NETASCII";
300
        } else if (mode == TFTP_OCTET) {
301
            fp = "OCTET";
302
        } else {
303
            *err = TFTP_INVALID;
304
            return -1;
305
        }
306
        while (*fp) *cp++ = *fp++;
307
        *cp++ = '\0';
308
        // Send request
309
        if (sendto(s, data, sizeof(data), 0,
310
                   (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
311
            // Problem sending request
312
            *err = TFTP_NETERR;
313
            close(s);
314
            return -1;
315
        }
316
        // Wait for ACK
317
        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
318
        timeout.tv_usec = 0;
319
        FD_ZERO(&fds);
320
        FD_SET(s, &fds);
321
        if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
322
            if (++total_timeouts > TFTP_TIMEOUT_MAX) {
323
                // Timeout - no ACK received
324
                *err = TFTP_TIMEOUT;
325
                close(s);
326
                return -1;
327
            }
328
        } else {
329
            recv_len = sizeof(data);
330
            from_len = sizeof(from_addr);
331
            if ((data_len = recvfrom(s, &data, recv_len, 0,
332
                                     (struct sockaddr *)&from_addr, &from_len)) < 0) {
333
                // What happened?
334
                *err = TFTP_NETERR;
335
                close(s);
336
                return -1;
337
            }
338
            if (ntohs(hdr->th_opcode) == ACK) {
339
                // Write request accepted - start sending data
340
                break;
341
            } else
342
            if (ntohs(hdr->th_opcode) == ERROR) {
343
                *err = ntohs(hdr->th_code);
344
                close(s);
345
                return -1;
346
            } else {
347
                // What kind of packet is this?
348
                *err = TFTP_PROTOCOL;
349
                close(s);
350
                return -1;
351
            }
352
        }
353
    }
354
 
355
    // Send data
356
    sfp = buf;
357
    last_good_block = 1;
358
    while (res < len) {
359
        // Build packet of data to send
360
        data_len = min(SEGSIZE, len-res);
361
        hdr->th_opcode = htons(DATA);
362
        hdr->th_block = htons(last_good_block);
363
        cp = hdr->th_data;
364
        fp = sfp;
365
        actual_len = data_len + 4;
366
        // FIXME - what about "netascii" data?
367
        while (data_len-- > 0) *cp++ = *fp++;
368
        // Send data packet
369
        if (sendto(s, data, actual_len, 0,
370
                   (struct sockaddr *)&from_addr, from_len) < 0) {
371
            // Problem sending request
372
            *err = TFTP_NETERR;
373
            close(s);
374
            return -1;
375
        }
376
        // Wait for ACK
377
        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
378
        timeout.tv_usec = 0;
379
        FD_ZERO(&fds);
380
        FD_SET(s, &fds);
381
        if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
382
            if (++total_timeouts > TFTP_TIMEOUT_MAX) {
383
                // Timeout - no data received
384
                *err = TFTP_TIMEOUT;
385
                close(s);
386
                return -1;
387
            }
388
        } else {
389
            recv_len = sizeof(data);
390
            from_len = sizeof(from_addr);
391
            if ((data_len = recvfrom(s, &data, recv_len, 0,
392
                                     (struct sockaddr *)&from_addr, &from_len)) < 0) {
393
                // What happened?
394
                *err = TFTP_NETERR;
395
                close(s);
396
                return -1;
397
            }
398
            if (ntohs(hdr->th_opcode) == ACK) {
399
                if (ntohs(hdr->th_block) == last_good_block) {
400
                    // Advance pointers, etc
401
                    sfp = fp;
402
                    res += (actual_len - 4);
403
                    last_good_block++;
404
                } else {
405
                    diag_printf("Send block #%d, got ACK for #%d\n",
406
                                last_good_block, ntohs(hdr->th_block));
407
                }
408
            } else
409
            if (ntohs(hdr->th_opcode) == ERROR) {
410
                *err = ntohs(hdr->th_code);
411
                close(s);
412
                return -1;
413
            } else {
414
                // What kind of packet is this?
415
                *err = TFTP_PROTOCOL;
416
                close(s);
417
                return -1;
418
            }
419
        }
420
    }
421
    close(s);
422
    return res;
423
}
424
 
425
// EOF tftp_client.c

powered by: WebSVN 2.1.0

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