1#include <stdio.h>
2#include <sys/types.h>
3#include <fcntl.h>
4#include <sys/stat.h>
5#include <inttypes.h>
6#include "pico_stack.h"
7#include "pico_config.h"
8#include "pico_ipv4.h"
9#include "pico_icmp4.h"
10#include "pico_socket.h"
11#include "pico_stack.h"
12#include "pico_device.h"
13#include "pico_dev_vde.h"
14#include "pico_tftp.h"
15
16static struct pico_device *pico_dev;
17
18int32_t get_filesize(const char *filename)
19{
20    int ret;
21    struct stat buf;
22
23    ret = stat(filename, &buf);
24    if (ret)
25        return -1;
26
27    return buf.st_size;
28}
29
30void start_rx(struct pico_tftp_session *session, int *synchro, const char *filename, int options)
31{
32    int ret;
33    int fd;
34    int32_t len;
35    uint8_t buf[PICO_TFTP_PAYLOAD_SIZE];
36    int left = 1000;
37    int countdown = 0;
38
39    printf("Start receiving file %s with options set to %d\n", filename, options);
40
41    if (options) {
42        ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0);
43        if (ret) {
44            fprintf(stderr, "Error in pico_tftp_set_option\n");
45            exit(1);
46        }
47    }
48
49    ret = pico_tftp_app_start_rx(session, filename);
50    if (ret) {
51        fprintf(stderr, "Error in pico_tftp_app_start_rx\n");
52        exit(1);
53    }
54
55    fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0664);
56    if (!fd) {
57        fprintf(stderr, "Error in open\n");
58        countdown = 1;
59    }
60
61    for(; left; left -= countdown) {
62        usleep(2000); /* PICO_IDLE(); */
63        pico_stack_tick();
64        if (countdown)
65            continue;
66
67        if (*synchro) {
68            len = pico_tftp_get(session, buf, PICO_TFTP_PAYLOAD_SIZE);
69            if (len < 0) {
70                fprintf(stderr, "Failure in pico_tftp_get\n");
71                close(fd);
72                countdown = 1;
73                continue;
74            }
75
76            ret = write(fd, buf, len);
77            if (ret < 0) {
78                fprintf(stderr, "Error in write\n");
79                pico_tftp_abort(session, TFTP_ERR_EXCEEDED, "File write error");
80                close(fd);
81                countdown = 1;
82                continue;
83            }
84
85            printf("Written %" PRId32 " bytes to file (synchro=%d)\n", len, *synchro);
86
87            if (len != PICO_TFTP_PAYLOAD_SIZE) {
88                close(fd);
89                printf("Transfer complete!\n");
90                countdown = 1;
91            }
92        }
93    }
94}
95
96void start_tx(struct pico_tftp_session *session, int *synchro, const char *filename, int options)
97{
98    int ret;
99    int fd;
100    int32_t len;
101    uint8_t buf[PICO_TFTP_PAYLOAD_SIZE];
102    int left = 1000;
103    int countdown = 0;
104
105    printf("Start sending file %s with options set to %d\n", filename, options);
106
107    if (options) {
108        ret = get_filesize(filename);
109        if (ret < 0) {
110            fprintf(stderr, "Error in get_filesize\n");
111            exit(1);
112        }
113
114        ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret);
115        if (ret) {
116            fprintf(stderr, "Error in pico_tftp_set_option\n");
117            exit(1);
118        }
119    }
120
121    ret = pico_tftp_app_start_tx(session, filename);
122    if (ret) {
123        fprintf(stderr, "Error in pico_tftp_app_start_rx\n");
124        exit(1);
125    }
126
127    fd = open(filename, O_RDONLY, 0444);
128    if (!fd) {
129        fprintf(stderr, "Error in open\n");
130        pico_tftp_abort(session, TFTP_ERR_EACC, "Error opening file");
131        countdown = 1;
132    }
133
134    for(; left; left -= countdown) {
135        usleep(2000); /* PICO_IDLE(); */
136        pico_stack_tick();
137        if (countdown)
138            continue;
139
140        if (*synchro) {
141            ret = read(fd, buf, PICO_TFTP_PAYLOAD_SIZE);
142            if (ret < 0) {
143                fprintf(stderr, "Error in read\n");
144                pico_tftp_abort(session, TFTP_ERR_EACC, "File read error");
145                close(fd);
146                countdown = 1;
147                continue;
148            }
149
150            printf("Read %" PRId32 " bytes from file (synchro=%d)\n", len, *synchro);
151
152            len = pico_tftp_put(session, buf, ret);
153            if (len < 0) {
154                fprintf(stderr, "Failure in pico_tftp_put\n");
155                close(fd);
156                countdown = 1;
157                continue;
158            }
159
160            if (len != PICO_TFTP_PAYLOAD_SIZE) {
161                close(fd);
162                printf("Transfer complete!\n");
163                countdown = 1;
164            }
165        }
166    }
167}
168
169void usage(const char *text)
170{
171    fprintf(stderr, "%s\nArguments must be <filename> <mode>\n"
172            "<mode> can be:\n"
173            "\tg => GET request without options\n"
174            "\tG => GET request WITH options\n"
175            "\tp => PUT request without options\n"
176            "\tP => PUT request WITH options\n\n",
177            text);
178    exit(1);
179}
180
181int main(int argc, char**argv)
182{
183    struct pico_ip4 my_ip;
184    union pico_address server_address;
185    struct pico_ip4 netmask;
186    struct pico_tftp_session *session;
187    int synchro;
188    int options = 0;
189    void (*operation)(struct pico_tftp_session *session, int *synchro, const char *filename, int options);
190
191    unsigned char macaddr[6] = {
192        0, 0, 0, 0xa, 0xb, 0x0
193    };
194
195    uint16_t *macaddr_low = (uint16_t *) (macaddr + 2);
196    *macaddr_low = *macaddr_low ^ (uint16_t)((uint16_t)getpid() & (uint16_t)0xFFFFU);
197    macaddr[4] ^= (uint8_t)(getpid() >> 8);
198    macaddr[5] ^= (uint8_t) (getpid() & 0xFF);
199
200    pico_string_to_ipv4("10.40.0.10", &my_ip.addr);
201    pico_string_to_ipv4("255.255.255.0", &netmask.addr);
202    pico_string_to_ipv4("10.40.0.2", &server_address.ip4.addr);
203
204    if (argc != 3) {
205        usage("Invalid number or arguments");
206    }
207
208    switch (argv[2][0]) {
209    case 'G':
210        options = 1;
211    case 'g':
212        operation = start_rx;
213        break;
214    case 'P':
215        options = 1;
216    case 'p':
217        operation = start_tx;
218        break;
219    default:
220        usage("Invalid mode");
221    }
222
223    printf("%s start!\n", argv[0]);
224    pico_stack_init();
225    pico_dev = (struct pico_device *) pico_vde_create("/tmp/vde_switch", "tap0", macaddr);
226
227    if(!pico_dev) {
228        fprintf(stderr, "Error creating pico device, got enough privileges? Exiting...\n");
229        exit(1);
230    }
231
232    pico_ipv4_link_add(pico_dev, my_ip, netmask);
233    printf("Starting picoTCP loop\n");
234
235    session = pico_tftp_app_setup(&server_address, short_be(PICO_TFTP_PORT), PICO_PROTO_IPV4, &synchro);
236    if (!session) {
237        fprintf(stderr, "Error in pico_tftp_app_setup\n");
238        exit(1);
239    }
240
241    printf("synchro %d\n", synchro);
242
243    operation(session, &synchro, argv[1], options);
244}
245