6358726034033a265f8363a1d3980db176b50b4f
[ffmpeg.git] / libavformat / ftp.c
1 /*
2  * Copyright (c) 2013 Lukasz Marek <lukasz.m.luki@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include <stdlib.h>
22 #include "libavutil/avstring.h"
23 #include "libavutil/time.h"
24 #include "avformat.h"
25 #include "internal.h"
26 #include "network.h"
27 #include "os_support.h"
28 #include "url.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/bprint.h"
31
32 #define CONTROL_BUFFER_SIZE 1024
33 #define CREDENTIALS_BUFFER_SIZE 128
34
35 typedef enum {
36     UNKNOWN,
37     READY,
38     DOWNLOADING,
39     UPLOADING,
40     DISCONNECTED
41 } FTPState;
42
43 typedef struct {
44     const AVClass *class;
45     URLContext *conn_control;                    /**< Control connection */
46     URLContext *conn_data;                       /**< Data connection, NULL when not connected */
47     uint8_t control_buffer[CONTROL_BUFFER_SIZE]; /**< Control connection buffer */
48     uint8_t *control_buf_ptr, *control_buf_end;
49     int server_data_port;                        /**< Data connection port opened by server, -1 on error. */
50     int server_control_port;                     /**< Control connection port, default is 21 */
51     char hostname[512];                          /**< Server address. */
52     char credencials[CREDENTIALS_BUFFER_SIZE];   /**< Authentication data */
53     char path[MAX_URL_SIZE];                     /**< Path to resource on server. */
54     int64_t filesize;                            /**< Size of file on server, -1 on error. */
55     int64_t position;                            /**< Current position, calculated. */
56     int rw_timeout;                              /**< Network timeout. */
57     const char *anonymous_password;              /**< Password to be used for anonymous user. An email should be used. */
58     int write_seekable;                          /**< Control seekability, 0 = disable, 1 = enable. */
59     FTPState state;                              /**< State of data connection */
60 } FTPContext;
61
62 #define OFFSET(x) offsetof(FTPContext, x)
63 #define D AV_OPT_FLAG_DECODING_PARAM
64 #define E AV_OPT_FLAG_ENCODING_PARAM
65 static const AVOption options[] = {
66     {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
67     {"ftp-write-seekable", "control seekability of connection during encoding", OFFSET(write_seekable), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
68     {"ftp-anonymous-password", "password for anonymous login. E-mail address should be used.", OFFSET(anonymous_password), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
69     {NULL}
70 };
71
72 static const AVClass ftp_context_class = {
73     .class_name     = "ftp",
74     .item_name      = av_default_item_name,
75     .option         = options,
76     .version        = LIBAVUTIL_VERSION_INT,
77 };
78
79 static int ftp_getc(FTPContext *s)
80 {
81     int len;
82     if (s->control_buf_ptr >= s->control_buf_end) {
83         len = ffurl_read(s->conn_control, s->control_buffer, CONTROL_BUFFER_SIZE);
84         if (len < 0) {
85             return len;
86         } else if (!len) {
87             return -1;
88         } else {
89             s->control_buf_ptr = s->control_buffer;
90             s->control_buf_end = s->control_buffer + len;
91         }
92     }
93     return *s->control_buf_ptr++;
94 }
95
96 static int ftp_get_line(FTPContext *s, char *line, int line_size)
97 {
98     int ch;
99     char *q = line;
100
101     for (;;) {
102         ch = ftp_getc(s);
103         if (ch < 0) {
104             return ch;
105         }
106         if (ch == '\n') {
107             /* process line */
108             if (q > line && q[-1] == '\r')
109                 q--;
110             *q = '\0';
111             return 0;
112         } else {
113             if ((q - line) < line_size - 1)
114                 *q++ = ch;
115         }
116     }
117 }
118
119 /*
120  * This routine returns ftp server response code.
121  * Server may send more than one response for a certain command, following priorities are used:
122  *   - When pref_codes are set then pref_code is return if occurred. (expected result)
123  *   - 0 is returned when no pref_codes or not occurred
124  */
125 static int ftp_status(FTPContext *s, char **line, const int response_codes[])
126 {
127     int err, i, dash = 0, result = 0, code_found = 0;
128     char buf[CONTROL_BUFFER_SIZE];
129     AVBPrint line_buffer;
130
131     if (line)
132         av_bprint_init(&line_buffer, 0, AV_BPRINT_SIZE_AUTOMATIC);
133
134     while (!code_found || dash) {
135         if ((err = ftp_get_line(s, buf, sizeof(buf))) < 0) {
136             av_bprint_finalize(&line_buffer, NULL);
137             return err;
138         }
139
140         av_log(s, AV_LOG_DEBUG, "%s\n", buf);
141
142         if (strlen(buf) < 4)
143             continue;
144
145         err = 0;
146         for (i = 0; i < 3; ++i) {
147             if (buf[i] < '0' || buf[i] > '9')
148                 continue;
149             err *= 10;
150             err += buf[i] - '0';
151         }
152         dash = !!(buf[3] == '-');
153
154         for (i = 0; response_codes[i]; ++i) {
155             if (err == response_codes[i]) {
156                 if (line)
157                     av_bprintf(&line_buffer, "%s", buf);
158                 code_found = 1;
159                 result = err;
160                 break;
161             }
162         }
163     }
164
165     if (line)
166         av_bprint_finalize(&line_buffer, line);
167     return result;
168 }
169
170 static int ftp_send_command(FTPContext *s, const char *command,
171                             const int response_codes[], char **response)
172 {
173     int err;
174
175     if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0)
176         return err;
177     if (!err)
178         return -1;
179
180     /* return status */
181     if (response_codes) {
182         return ftp_status(s, response, response_codes);
183     }
184     return 0;
185 }
186
187 static void ftp_close_data_connection(FTPContext *s)
188 {
189     ffurl_closep(&s->conn_data);
190     s->position = 0;
191     s->state = DISCONNECTED;
192 }
193
194 static void ftp_close_both_connections(FTPContext *s)
195 {
196     ffurl_closep(&s->conn_control);
197     ftp_close_data_connection(s);
198 }
199
200 static int ftp_auth(FTPContext *s)
201 {
202     const char *user = NULL, *pass = NULL;
203     char *end = NULL, buf[CONTROL_BUFFER_SIZE], credencials[CREDENTIALS_BUFFER_SIZE];
204     int err;
205     const int user_codes[] = {331, 230, 500, 530, 0}; /* 500, 530 are incorrect codes */
206     const int pass_codes[] = {230, 503, 530, 0}; /* 503, 530 are incorrect codes */
207
208     /* Authentication may be repeated, original string has to be saved */
209     av_strlcpy(credencials, s->credencials, sizeof(credencials));
210
211     user = av_strtok(credencials, ":", &end);
212     pass = av_strtok(end, ":", &end);
213
214     if (!user) {
215         user = "anonymous";
216         pass = s->anonymous_password ? s->anonymous_password : "nopassword";
217     }
218
219     snprintf(buf, sizeof(buf), "USER %s\r\n", user);
220     err = ftp_send_command(s, buf, user_codes, NULL);
221     if (err == 331) {
222         if (pass) {
223             snprintf(buf, sizeof(buf), "PASS %s\r\n", pass);
224             err = ftp_send_command(s, buf, pass_codes, NULL);
225         } else
226             return AVERROR(EACCES);
227     }
228     if (err != 230)
229         return AVERROR(EACCES);
230
231     return 0;
232 }
233
234 static int ftp_passive_mode(FTPContext *s)
235 {
236     char *res = NULL, *start = NULL, *end = NULL;
237     int i;
238     const char *command = "PASV\r\n";
239     const int pasv_codes[] = {227, 501, 0}; /* 501 is incorrect code */
240
241     if (ftp_send_command(s, command, pasv_codes, &res) != 227 || !res)
242         goto fail;
243
244     for (i = 0; res[i]; ++i) {
245         if (res[i] == '(') {
246             start = res + i + 1;
247         } else if (res[i] == ')') {
248             end = res + i;
249             break;
250         }
251     }
252     if (!start || !end)
253         goto fail;
254
255     *end  = '\0';
256     /* skip ip */
257     if (!av_strtok(start, ",", &end)) goto fail;
258     if (!av_strtok(end, ",", &end)) goto fail;
259     if (!av_strtok(end, ",", &end)) goto fail;
260     if (!av_strtok(end, ",", &end)) goto fail;
261
262     /* parse port number */
263     start = av_strtok(end, ",", &end);
264     if (!start) goto fail;
265     s->server_data_port = atoi(start) * 256;
266     start = av_strtok(end, ",", &end);
267     if (!start) goto fail;
268     s->server_data_port += atoi(start);
269     av_dlog(s, "Server data port: %d\n", s->server_data_port);
270
271     av_free(res);
272     return 0;
273
274   fail:
275     av_free(res);
276     s->server_data_port = -1;
277     return AVERROR(EIO);
278 }
279
280 static int ftp_current_dir(FTPContext *s)
281 {
282     char *res = NULL, *start = NULL, *end = NULL;
283     int i;
284     const char *command = "PWD\r\n";
285     const int pwd_codes[] = {257, 0};
286
287     if (ftp_send_command(s, command, pwd_codes, &res) != 257 || !res)
288         goto fail;
289
290     for (i = 0; res[i]; ++i) {
291         if (res[i] == '"') {
292             if (!start) {
293                 start = res + i + 1;
294                 continue;
295             }
296             end = res + i;
297             break;
298         }
299     }
300
301     if (!end)
302         goto fail;
303
304     if (end > res && end[-1] == '/') {
305         end[-1] = '\0';
306     } else
307         *end = '\0';
308     av_strlcpy(s->path, start, sizeof(s->path));
309
310     av_free(res);
311     return 0;
312
313   fail:
314     av_free(res);
315     return AVERROR(EIO);
316 }
317
318 static int ftp_file_size(FTPContext *s)
319 {
320     char command[CONTROL_BUFFER_SIZE];
321     char *res = NULL;
322     const int size_codes[] = {213, 501, 550, 0}; /* 501, 550 are incorrect codes */
323
324     snprintf(command, sizeof(command), "SIZE %s\r\n", s->path);
325     if (ftp_send_command(s, command, size_codes, &res) == 213 && res) {
326         s->filesize = strtoll(&res[4], NULL, 10);
327     } else {
328         s->filesize = -1;
329         av_free(res);
330         return AVERROR(EIO);
331     }
332
333     av_free(res);
334     return 0;
335 }
336
337 static int ftp_retrieve(FTPContext *s)
338 {
339     char command[CONTROL_BUFFER_SIZE];
340     const int retr_codes[] = {150, 550, 554, 0}; /* 550, 554 are incorrect codes */
341
342     snprintf(command, sizeof(command), "RETR %s\r\n", s->path);
343     if (ftp_send_command(s, command, retr_codes, NULL) != 150)
344         return AVERROR(EIO);
345
346     s->state = DOWNLOADING;
347
348     return 0;
349 }
350
351 static int ftp_store(FTPContext *s)
352 {
353     char command[CONTROL_BUFFER_SIZE];
354     const int stor_codes[] = {150, 0};
355
356     snprintf(command, sizeof(command), "STOR %s\r\n", s->path);
357     if (ftp_send_command(s, command, stor_codes, NULL) != 150)
358         return AVERROR(EIO);
359
360     s->state = UPLOADING;
361
362     return 0;
363 }
364
365 static int ftp_type(FTPContext *s)
366 {
367     const char *command = "TYPE I\r\n";
368     const int type_codes[] = {200, 500, 504, 0}; /* 500, 504 are incorrect codes */
369
370     if (ftp_send_command(s, command, type_codes, NULL) != 200)
371         return AVERROR(EIO);
372
373     return 0;
374 }
375
376 static int ftp_restart(FTPContext *s, int64_t pos)
377 {
378     char command[CONTROL_BUFFER_SIZE];
379     const int rest_codes[] = {350, 500, 501, 0}; /* 500, 501 are incorrect codes */
380
381     snprintf(command, sizeof(command), "REST %"PRId64"\r\n", pos);
382     if (ftp_send_command(s, command, rest_codes, NULL) != 350)
383         return AVERROR(EIO);
384
385     return 0;
386 }
387
388 static int ftp_connect_control_connection(URLContext *h)
389 {
390     char buf[CONTROL_BUFFER_SIZE], opts_format[20];
391     int err;
392     AVDictionary *opts = NULL;
393     FTPContext *s = h->priv_data;
394     const int connect_codes[] = {220, 0};
395
396     if (!s->conn_control) {
397         ff_url_join(buf, sizeof(buf), "tcp", NULL,
398                     s->hostname, s->server_control_port, NULL);
399         if (s->rw_timeout != -1) {
400             snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
401             av_dict_set(&opts, "timeout", opts_format, 0);
402         } /* if option is not given, don't pass it and let tcp use its own default */
403         err = ffurl_open(&s->conn_control, buf, AVIO_FLAG_READ_WRITE,
404                          &h->interrupt_callback, &opts);
405         av_dict_free(&opts);
406         if (err < 0) {
407             av_log(h, AV_LOG_ERROR, "Cannot open control connection\n");
408             return err;
409         }
410
411         /* consume all messages from server */
412         if (ftp_status(s, NULL, connect_codes) != 220) {
413             av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
414             return AVERROR(EACCES);
415         }
416
417         if ((err = ftp_auth(s)) < 0) {
418             av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
419             return err;
420         }
421
422         if ((err = ftp_type(s)) < 0) {
423             av_dlog(h, "Set content type failed\n");
424             return err;
425         }
426     }
427     return 0;
428 }
429
430 static int ftp_connect_data_connection(URLContext *h)
431 {
432     int err;
433     char buf[CONTROL_BUFFER_SIZE], opts_format[20];
434     AVDictionary *opts = NULL;
435     FTPContext *s = h->priv_data;
436
437     if (!s->conn_data) {
438         /* Enter passive mode */
439         if ((err = ftp_passive_mode(s)) < 0) {
440             av_dlog(h, "Set passive mode failed\n");
441             return err;
442         }
443         /* Open data connection */
444         ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
445         if (s->rw_timeout != -1) {
446             snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
447             av_dict_set(&opts, "timeout", opts_format, 0);
448         } /* if option is not given, don't pass it and let tcp use its own default */
449         err = ffurl_open(&s->conn_data, buf, h->flags,
450                          &h->interrupt_callback, &opts);
451         av_dict_free(&opts);
452         if (err < 0)
453             return err;
454
455         if (s->position)
456             if ((err = ftp_restart(s, s->position)) < 0)
457                 return err;
458     }
459     s->state = READY;
460     return 0;
461 }
462
463 static int ftp_abort(URLContext *h)
464 {
465     const char *command = "ABOR\r\n";
466     int err;
467     const int abor_codes[] = {225, 226, 0};
468     FTPContext *s = h->priv_data;
469
470     /* According to RCF 959:
471        "ABOR command tells the server to abort the previous FTP
472        service command and any associated transfer of data."
473
474        There are FTP server implementations that don't response
475        to any commands during data transfer in passive mode (including ABOR).
476
477        This implementation closes data connection by force.
478     */
479
480     if (ftp_send_command(s, command, NULL, NULL) < 0) {
481         ftp_close_both_connections(s);
482         if ((err = ftp_connect_control_connection(h)) < 0) {
483             av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
484             return err;
485         }
486     } else {
487         ftp_close_data_connection(s);
488     }
489
490     if (ftp_status(s, NULL, abor_codes) < 225) {
491         /* wu-ftpd also closes control connection after data connection closing */
492         ffurl_closep(&s->conn_control);
493         if ((err = ftp_connect_control_connection(h)) < 0) {
494             av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
495             return err;
496         }
497     }
498
499     return 0;
500 }
501
502 static int ftp_open(URLContext *h, const char *url, int flags)
503 {
504     char proto[10], path[MAX_URL_SIZE];
505     int err;
506     FTPContext *s = h->priv_data;
507
508     av_dlog(h, "ftp protocol open\n");
509
510     s->state = DISCONNECTED;
511     s->filesize = -1;
512     s->position = 0;
513
514     av_url_split(proto, sizeof(proto),
515                  s->credencials, sizeof(s->credencials),
516                  s->hostname, sizeof(s->hostname),
517                  &s->server_control_port,
518                  path, sizeof(path),
519                  url);
520
521     if (s->server_control_port < 0 || s->server_control_port > 65535)
522         s->server_control_port = 21;
523
524     if ((err = ftp_connect_control_connection(h)) < 0)
525         goto fail;
526
527     if ((err = ftp_current_dir(s)) < 0)
528         goto fail;
529     av_strlcat(s->path, path, sizeof(s->path));
530
531     if (ftp_restart(s, 0) < 0) {
532         h->is_streamed = 1;
533     } else {
534         if (ftp_file_size(s) < 0 && flags & AVIO_FLAG_READ)
535             h->is_streamed = 1;
536         if (s->write_seekable != 1 && flags & AVIO_FLAG_WRITE)
537             h->is_streamed = 1;
538     }
539
540     return 0;
541
542   fail:
543     av_log(h, AV_LOG_ERROR, "FTP open failed\n");
544     ffurl_closep(&s->conn_control);
545     ffurl_closep(&s->conn_data);
546     return err;
547 }
548
549 static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
550 {
551     FTPContext *s = h->priv_data;
552     int err;
553     int64_t new_pos, fake_pos;
554
555     av_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence);
556
557     switch(whence) {
558     case AVSEEK_SIZE:
559         return s->filesize;
560     case SEEK_SET:
561         new_pos = pos;
562         break;
563     case SEEK_CUR:
564         new_pos = s->position + pos;
565         break;
566     case SEEK_END:
567         if (s->filesize < 0)
568             return AVERROR(EIO);
569         new_pos = s->filesize + pos;
570         break;
571     default:
572         return AVERROR(EINVAL);
573     }
574
575     if  (h->is_streamed)
576         return AVERROR(EIO);
577
578     new_pos = FFMAX(0, new_pos);
579     fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos;
580
581     if (fake_pos != s->position) {
582         if ((err = ftp_abort(h)) < 0)
583             return err;
584         s->position = fake_pos;
585     }
586     return new_pos;
587 }
588
589 static int ftp_read(URLContext *h, unsigned char *buf, int size)
590 {
591     FTPContext *s = h->priv_data;
592     int read, err, retry_done = 0;
593
594     av_dlog(h, "ftp protocol read %d bytes\n", size);
595   retry:
596     if (s->state == DISCONNECTED) {
597         if (s->position >= s->filesize)
598             return 0;
599         if ((err = ftp_connect_data_connection(h)) < 0)
600             return err;
601     }
602     if (s->state == READY) {
603         if (s->position >= s->filesize)
604             return 0;
605         if ((err = ftp_retrieve(s)) < 0)
606             return err;
607     }
608     if (s->conn_data && s->state == DOWNLOADING) {
609         read = ffurl_read(s->conn_data, buf, size);
610         if (read >= 0) {
611             s->position += read;
612             if (s->position >= s->filesize) {
613                 /* server will terminate, but keep current position to avoid madness */
614                 int64_t pos = s->position;
615                 if (ftp_abort(h) < 0) {
616                     s->position = pos;
617                     return AVERROR(EIO);
618                 }
619                 s->position = pos;
620             }
621         }
622         if (read <= 0 && s->position < s->filesize && !h->is_streamed) {
623             /* Server closed connection. Probably due to inactivity */
624             int64_t pos = s->position;
625             av_log(h, AV_LOG_INFO, "Reconnect to FTP server.\n");
626             if ((err = ftp_abort(h)) < 0)
627                 return err;
628             if ((err = ftp_seek(h, pos, SEEK_SET)) < 0) {
629                 av_log(h, AV_LOG_ERROR, "Position cannot be restored.\n");
630                 return err;
631             }
632             if (!retry_done) {
633                 retry_done = 1;
634                 goto retry;
635             }
636         }
637         return read;
638     }
639
640     av_log(h, AV_LOG_DEBUG, "FTP read failed\n");
641     return AVERROR(EIO);
642 }
643
644 static int ftp_write(URLContext *h, const unsigned char *buf, int size)
645 {
646     int err;
647     FTPContext *s = h->priv_data;
648     int written;
649
650     av_dlog(h, "ftp protocol write %d bytes\n", size);
651
652     if (s->state == DISCONNECTED) {
653         if ((err = ftp_connect_data_connection(h)) < 0)
654             return err;
655     }
656     if (s->state == READY) {
657         if ((err = ftp_store(s)) < 0)
658             return err;
659     }
660     if (s->conn_data && s->state == UPLOADING) {
661         written = ffurl_write(s->conn_data, buf, size);
662         if (written > 0) {
663             s->position += written;
664             s->filesize = FFMAX(s->filesize, s->position);
665         }
666         return written;
667     }
668
669     av_log(h, AV_LOG_ERROR, "FTP write failed\n");
670     return AVERROR(EIO);
671 }
672
673 static int ftp_close(URLContext *h)
674 {
675     av_dlog(h, "ftp protocol close\n");
676
677     ftp_close_both_connections(h->priv_data);
678
679     return 0;
680 }
681
682 static int ftp_get_file_handle(URLContext *h)
683 {
684     FTPContext *s = h->priv_data;
685
686     av_dlog(h, "ftp protocol get_file_handle\n");
687
688     if (s->conn_data)
689         return ffurl_get_file_handle(s->conn_data);
690
691     return AVERROR(EIO);
692 }
693
694 static int ftp_shutdown(URLContext *h, int flags)
695 {
696     FTPContext *s = h->priv_data;
697
698     av_dlog(h, "ftp protocol shutdown\n");
699
700     if (s->conn_data)
701         return ffurl_shutdown(s->conn_data, flags);
702
703     return AVERROR(EIO);
704 }
705
706 URLProtocol ff_ftp_protocol = {
707     .name                = "ftp",
708     .url_open            = ftp_open,
709     .url_read            = ftp_read,
710     .url_write           = ftp_write,
711     .url_seek            = ftp_seek,
712     .url_close           = ftp_close,
713     .url_get_file_handle = ftp_get_file_handle,
714     .url_shutdown        = ftp_shutdown,
715     .priv_data_size      = sizeof(FTPContext),
716     .priv_data_class     = &ftp_context_class,
717     .flags               = URL_PROTOCOL_FLAG_NETWORK,
718 };