blob: 92e50fb56fb437aaf4c4d9c75076354dc20a4c6e [file] [log] [blame]
adamdunkelsa2f3c422004-09-12 20:24:53 +00001/*
2 * Copyright (c) 2004, Adam Dunkels.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
oliverschmidt19c18762005-04-17 22:42:33 +000033 * $Id: ftpc.c,v 1.3 2005/04/17 22:42:33 oliverschmidt Exp $
adamdunkelsa2f3c422004-09-12 20:24:53 +000034 */
adamdunkels499d1b52004-08-09 20:09:27 +000035#include "contiki.h"
36#include "ftpc.h"
37
38#include <string.h>
oliverschmidt19c18762005-04-17 22:42:33 +000039#include <stdio.h>
adamdunkels499d1b52004-08-09 20:09:27 +000040
41#define ISO_nl 0x0a
42#define ISO_cr 0x0d
43
44#define DATAPORT 6510
45
46#define MAX_FILENAMELEN 32
47
48struct ftp_dataconn {
49 unsigned char type;
50 unsigned char conntype;
51#define CONNTYPE_LIST 0
52#define CONNTYPE_FILE 1
53
54 u16_t port;
55
56 unsigned char filenameptr;
57 char filename[MAX_FILENAMELEN];
58
59
60};
61
62struct ftp_connection {
63 unsigned char type;
64#define TYPE_CONTROL 1
65#define TYPE_DATA 2
66#define TYPE_ABORT 3
67#define TYPE_CLOSE 4
68
69 unsigned char state;
70#define STATE_NONE 0
71#define STATE_INITIAL 1
72#define STATE_SEND_USER 2
73#define STATE_USER_SENT 3
74#define STATE_SEND_PASS 4
75#define STATE_PASS_SENT 5
76#define STATE_SEND_PORT 6
77#define STATE_PORT_SENT 7
78#define STATE_SEND_OPTIONS 8
79#define STATE_OPTION_SENT 9
80#define STATE_CONNECTED 10
81#define STATE_SEND_NLST 11
82#define STATE_NLST_SENT 12
83#define STATE_SEND_RETR 13
84#define STATE_RETR_SENT 14
85
86#define STATE_SEND_CWD 15
87#define STATE_CWD_SENT 16
88
89#define STATE_SEND_CDUP 17
90#define STATE_CDUP_SENT 18
91
92#define STATE_SEND_QUIT 19
93#define STATE_QUIT_SENT 20
94
95 unsigned char connected_confirmed;
96
97 struct ftp_dataconn dataconn;
98
99 char code[3];
100 unsigned char codeptr;
101
102 unsigned char optionsptr;
103
104 char filename[MAX_FILENAMELEN];
105
106};
107
108#define NUM_OPTIONS 1
109static const struct {
110 unsigned char num;
111 char *commands[NUM_OPTIONS];
112} options = {
113 NUM_OPTIONS,
114 {"TYPE I\r\n"}
115};
116
117static struct ftp_connection *waiting_for_dataconn;
118
119MEMB(connections, sizeof(struct ftp_connection), 1);
120
121/*---------------------------------------------------------------------------*/
122void
123ftpc_init(void)
124{
125 memb_init(&connections);
126 /* tcp_listen(HTONS(DATAPORT));*/
127}
128/*---------------------------------------------------------------------------*/
129void *
130ftpc_connect(u16_t *ipaddr, u16_t port)
131{
132 struct ftp_connection *c;
133
134 c = (struct ftp_connection *)memb_alloc(&connections);
135 if(c == NULL) {
136 return NULL;
137 }
138 c->type = TYPE_CONTROL;
139 c->state = STATE_INITIAL;
140 c->connected_confirmed = 0;
141 c->codeptr = 0;
142 c->dataconn.type = TYPE_DATA;
143 c->dataconn.port = DATAPORT;
144 tcp_listen(HTONS(DATAPORT));
145
146 if(tcp_connect(ipaddr, port, c) == NULL) {
147 memb_free(&connections, c);
148 return NULL;
149 }
150
151 return c;
152}
153/*---------------------------------------------------------------------------*/
154static void
155handle_input(struct ftp_connection *c)
156{
157 int code;
158
159 code = (c->code[0] - '0') * 100 +
160 (c->code[1] - '0') * 10 +
161 (c->code[2] - '0');
162 /* printf("Handle input code %d state %d\n", code, c->state);*/
163
164 if(c->state == STATE_INITIAL) {
165 if(code == 220) {
166 c->state = STATE_SEND_USER;
167 }
168 } else if(c->state == STATE_USER_SENT) {
169 if(code == 331) {
170 c->state = STATE_SEND_PASS;
171 }
172 } else if(c->state == STATE_PASS_SENT) {
173 if(code == 230) {
174 c->state = STATE_SEND_OPTIONS;
175 c->optionsptr = 0;
176 }
177 } else if(c->state == STATE_PORT_SENT) {
178 c->state = STATE_CONNECTED;
179 if(c->connected_confirmed == 0) {
180 ftpc_connected(c);
181 c->connected_confirmed = 1;
182 }
183 } else if(c->state == STATE_OPTION_SENT) {
184 if(c->optionsptr >= options.num) {
185 c->state = STATE_SEND_PORT;
186 } else {
187 c->state = STATE_SEND_OPTIONS;
188 }
189 } else if((c->state == STATE_NLST_SENT ||
190 c->state == STATE_RETR_SENT ||
191 c->state == STATE_CONNECTED)) {
192 if(code == 226 || code == 550) {
193 tcp_unlisten(htons(c->dataconn.port));
194 ++c->dataconn.port;
195 tcp_listen(htons(c->dataconn.port));
196 c->state = STATE_SEND_PORT;
197 }
198
199 if(code == 550) {
200 ftpc_list_file(NULL);
201 }
202 } else if(c->state == STATE_CWD_SENT ||
203 c->state == STATE_CDUP_SENT) {
204 c->state = STATE_CONNECTED;
205 ftpc_cwd_done(code);
206 /* } else if(c->state == STATE_) {
207 c->state = STATE_CONNECTED;*/
208 }
209}
210/*---------------------------------------------------------------------------*/
211static void
212newdata(struct ftp_connection *c)
213{
214 u16_t i;
215 u8_t d;
216
217 for(i = 0; i < uip_datalen(); ++i) {
218 d = ((char *)uip_appdata)[i];
219 if(c->codeptr < sizeof(c->code)) {
220 c->code[c->codeptr] = d;
221 ++c->codeptr;
222 }
223
224 if(d == ISO_nl) {
225 handle_input(c);
226 c->codeptr = 0;
227 }
228 }
229}
230/*---------------------------------------------------------------------------*/
231static void
232acked(struct ftp_connection *c)
233{
234 switch(c->state) {
235 case STATE_SEND_USER:
236 c->state = STATE_USER_SENT;
237 break;
238 case STATE_SEND_PASS:
239 c->state = STATE_PASS_SENT;
240 break;
241 case STATE_SEND_PORT:
242 c->state = STATE_PORT_SENT;
243 break;
244 case STATE_SEND_OPTIONS:
245 ++c->optionsptr;
246 c->state = STATE_OPTION_SENT;
247 break;
248 case STATE_SEND_NLST:
249 c->state = STATE_NLST_SENT;
250 break;
251 case STATE_SEND_RETR:
252 c->state = STATE_RETR_SENT;
253 break;
254 case STATE_SEND_CWD:
255 c->state = STATE_CWD_SENT;
256 break;
257 case STATE_SEND_CDUP:
258 c->state = STATE_CDUP_SENT;
259 break;
260 case STATE_SEND_QUIT:
261 c->state = STATE_QUIT_SENT;
262 uip_close();
263 break;
264 }
265}
266/*---------------------------------------------------------------------------*/
267static void
268senddata(struct ftp_connection *c)
269{
270 u16_t len;
271
272 switch(c->state) {
273 case STATE_SEND_USER:
274 strcpy(uip_appdata, "USER ");
275 strncpy(uip_appdata + 5, ftpc_username(), uip_mss() - 7);
276 len = strlen(ftpc_username());
277 strcpy(uip_appdata + 5 + len, "\r\n");
278 uip_send(uip_appdata, len + 2 + 5);
279 break;
280 case STATE_SEND_PASS:
281 strcpy(uip_appdata, "PASS ");
282 strncpy(uip_appdata + 5, ftpc_password(), uip_mss() - 7);
283 len = strlen(ftpc_password());
284 strcpy(uip_appdata + 5 + len, "\r\n");
285 uip_send(uip_appdata, len + 2 + 5);
286 break;
287 case STATE_SEND_PORT:
288 len = sprintf(uip_appdata, "PORT %d,%d,%d,%d,%d,%d\n",
289 uip_ipaddr1(uip_hostaddr),
290 uip_ipaddr2(uip_hostaddr),
291 uip_ipaddr3(uip_hostaddr),
292 uip_ipaddr4(uip_hostaddr),
293 (c->dataconn.port) >> 8,
294 (c->dataconn.port) & 0xff);
295 uip_send(uip_appdata, len);
296 break;
297 case STATE_SEND_OPTIONS:
298 len = strlen(options.commands[c->optionsptr]);
299 uip_send(options.commands[c->optionsptr], len);
300 break;
301 case STATE_SEND_NLST:
302 uip_send("NLST\r\n", 6);
303 break;
304 case STATE_SEND_RETR:
305 len = sprintf(uip_appdata, "RETR %s\r\n", c->filename);
306 uip_send(uip_appdata, len);
307 break;
308 case STATE_SEND_CWD:
309 len = sprintf(uip_appdata, "CWD %s\r\n", c->filename);
310 uip_send(uip_appdata, len);
311 break;
312 case STATE_SEND_CDUP:
313 uip_send("CDUP\r\n", 6);
314 break;
315 case STATE_SEND_QUIT:
316 uip_send("QUIT\r\n", 6);
317 break;
318 }
319}
320/*---------------------------------------------------------------------------*/
321void
322ftpc_appcall(void *state)
323{
324 int i, t;
325 struct ftp_connection *c = (struct ftp_connection *)state;
326 struct ftp_dataconn *d = (struct ftp_dataconn *)state;
327
328 if(uip_connected()) {
329 if(state == NULL) {
330 if(waiting_for_dataconn != NULL) {
331 d = &waiting_for_dataconn->dataconn;
332 waiting_for_dataconn = NULL;
333 tcp_markconn(uip_conn, d);
334 d->filenameptr = 0;
335
336 } else {
337 uip_abort();
338 }
339 } else {
340 /* tcp_listen(uip_conn->lport);*/
341 senddata(c);
342 }
343 return;
344 }
345
346 if(c->type == TYPE_ABORT) {
347 uip_abort();
348 return;
349 }
350
351 if(c->type == TYPE_CLOSE) {
352 uip_close();
353 c->type = TYPE_CONTROL;
354 return;
355 }
356
357 if(c->type == TYPE_CONTROL) {
358 if(uip_closed()) {
359 c->dataconn.type = TYPE_ABORT;
360 ftpc_closed();
361 memb_free(&connections, c);
362 }
363 if(uip_aborted()) {
364 c->dataconn.type = TYPE_ABORT;
365 ftpc_aborted();
366 memb_free(&connections, c);
367 }
368 if(uip_timedout()) {
369 c->dataconn.type = TYPE_ABORT;
370 ftpc_timedout();
371 memb_free(&connections, c);
372 }
373
374
375 if(uip_acked()) {
376 acked(c);
377 }
378 if(uip_newdata()) {
379 newdata(c);
380 }
381 if(uip_rexmit() ||
382 uip_newdata() ||
383 uip_acked()) {
384 senddata(c);
385 } else if(uip_poll()) {
386 senddata(c);
387 }
388 } else {
389 if(d->conntype == CONNTYPE_LIST) {
390 if(uip_newdata()) {
391 for(i = 0; i < uip_datalen(); ++i) {
392 t = ((char *)uip_appdata)[i];
393
394 if(d->filenameptr < sizeof(d->filename) - 1 &&
395 t != ISO_cr &&
396 t != ISO_nl) {
397 d->filename[d->filenameptr] = t;
398 ++d->filenameptr;
399 }
400
401 if(t == ISO_nl) {
402 d->filename[d->filenameptr] = 0;
403 ftpc_list_file(d->filename);
404 d->filenameptr = 0;
405 }
406
407 }
408 }
409 if(uip_closed()) {
410 ftpc_list_file(NULL);
411 }
412 } else {
413 if(uip_newdata()) {
414 ftpc_data(uip_appdata, uip_datalen());
415 /* printf("Received %d data bytes: '%s'\n",
416 uip_datalen(), uip_appdata);*/
417 } else if(uip_closed() || uip_timedout() || uip_aborted()) {
418 ftpc_data(NULL, 0);
419 }
420 }
421 }
422}
423/*---------------------------------------------------------------------------*/
424char
425ftpc_list(void *conn)
426{
427 struct ftp_connection *c;
428
429 c = conn;
430
431 if(c == NULL ||
432 c->state != STATE_CONNECTED) {
433 return 0;
434 }
435
436 c->state = STATE_SEND_NLST;
437 c->dataconn.conntype = CONNTYPE_LIST;
438 waiting_for_dataconn = c;
439 return 1;
440}
441/*---------------------------------------------------------------------------*/
442char
443ftpc_get(void *conn, char *filename)
444{
445 struct ftp_connection *c;
446
447 c = conn;
448
449 if(c == NULL ||
450 c->state != STATE_CONNECTED) {
451 return 0;
452 }
453
454 strncpy(c->filename, filename, sizeof(c->filename));
455
456 c->state = STATE_SEND_RETR;
457 c->dataconn.conntype = CONNTYPE_FILE;
458 waiting_for_dataconn = c;
459 return 1;
460}
461/*---------------------------------------------------------------------------*/
462void
463ftpc_close(void *conn)
464{
465 struct ftp_connection *c;
466
467 c = conn;
468
469 if(c == NULL) {
470 return;
471 }
472
473 c->type = TYPE_CLOSE;
474}
475/*---------------------------------------------------------------------------*/
476void
477ftpc_cwd(void *conn, char *dirname)
478{
479 struct ftp_connection *c;
480
481 c = conn;
482
483 if(c == NULL ||
484 c->state != STATE_CONNECTED) {
485 return;
486 }
487
488 strncpy(c->filename, dirname, sizeof(c->filename));
489 c->state = STATE_SEND_CWD;
490}
491/*---------------------------------------------------------------------------*/
492void
493ftpc_cdup(void *conn)
494{
495 struct ftp_connection *c;
496
497 c = conn;
498
499 if(c == NULL ||
500 c->state != STATE_CONNECTED) {
501 return;
502 }
503
504 c->state = STATE_SEND_CDUP;
505}
506/*---------------------------------------------------------------------------*/