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