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