FFmpeg  2.1.1
libssh.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 <fcntl.h>
22 #include <libssh/sftp.h>
23 #include "libavutil/avstring.h"
24 #include "libavutil/opt.h"
25 #include "avformat.h"
26 #include "internal.h"
27 #include "url.h"
28 
29 typedef struct {
30  const AVClass *class;
31  ssh_session session;
32  sftp_session sftp;
33  sftp_file file;
34  int64_t filesize;
36  int trunc;
38 
39 static int libssh_close(URLContext *h)
40 {
42  if (s->file)
43  sftp_close(s->file);
44  if (s->sftp)
45  sftp_free(s->sftp);
46  if (s->session) {
47  ssh_disconnect(s->session);
48  ssh_free(s->session);
49  }
50  return 0;
51 }
52 
53 static int libssh_open(URLContext *h, const char *url, int flags)
54 {
55  static const int verbosity = SSH_LOG_NOLOG;
57  char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024];
58  int port = 22, access, ret;
59  long timeout = s->rw_timeout * 1000;
60  const char *user = NULL, *pass = NULL;
61  char *end = NULL;
62  sftp_attributes stat;
63 
64  av_url_split(proto, sizeof(proto),
65  credencials, sizeof(credencials),
66  hostname, sizeof(hostname),
67  &port,
68  path, sizeof(path),
69  url);
70 
71  if (port <= 0 || port > 65535)
72  port = 22;
73 
74  if (!(s->session = ssh_new())) {
75  ret = AVERROR(ENOMEM);
76  goto fail;
77  }
78  user = av_strtok(credencials, ":", &end);
79  pass = av_strtok(end, ":", &end);
80  ssh_options_set(s->session, SSH_OPTIONS_HOST, hostname);
81  ssh_options_set(s->session, SSH_OPTIONS_PORT, &port);
82  ssh_options_set(s->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
83  if (timeout > 0)
84  ssh_options_set(s->session, SSH_OPTIONS_TIMEOUT_USEC, &timeout);
85  if (user)
86  ssh_options_set(s->session, SSH_OPTIONS_USER, user);
87 
88  if (ssh_connect(s->session) != SSH_OK) {
89  av_log(h, AV_LOG_ERROR, "Connection failed. %s\n", ssh_get_error(s->session));
90  ret = AVERROR(EIO);
91  goto fail;
92  }
93 
94  if (pass && ssh_userauth_password(s->session, NULL, pass) != SSH_AUTH_SUCCESS) {
95  av_log(h, AV_LOG_ERROR, "Error authenticating with password: %s\n", ssh_get_error(s->session));
96  ret = AVERROR(EACCES);
97  goto fail;
98  }
99 
100  if (!(s->sftp = sftp_new(s->session))) {
101  av_log(h, AV_LOG_ERROR, "SFTP session creation failed: %s\n", ssh_get_error(s->session));
102  ret = AVERROR(ENOMEM);
103  goto fail;
104  }
105 
106  if (sftp_init(s->sftp) != SSH_OK) {
107  av_log(h, AV_LOG_ERROR, "Error initializing sftp session: %s\n", ssh_get_error(s->session));
108  ret = AVERROR(EIO);
109  goto fail;
110  }
111 
112  if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
113  access = O_CREAT | O_RDWR;
114  if (s->trunc)
115  access |= O_TRUNC;
116  } else if (flags & AVIO_FLAG_WRITE) {
117  access = O_CREAT | O_WRONLY;
118  if (s->trunc)
119  access |= O_TRUNC;
120  } else {
121  access = O_RDONLY;
122  }
123 
124  if (!(s->file = sftp_open(s->sftp, path, access, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH))) {
125  av_log(h, AV_LOG_ERROR, "Error opening sftp file: %s\n", ssh_get_error(s->session));
126  ret = AVERROR(EIO);
127  goto fail;
128  }
129 
130  if (!(stat = sftp_fstat(s->file))) {
131  av_log(h, AV_LOG_WARNING, "Cannot stat remote file %s.\n", path);
132  s->filesize = -1;
133  } else {
134  s->filesize = stat->size;
135  sftp_attributes_free(stat);
136  }
137 
138  return 0;
139 
140  fail:
141  libssh_close(h);
142  return ret;
143 }
144 
145 static int64_t libssh_seek(URLContext *h, int64_t pos, int whence)
146 {
147  LIBSSHContext *s = h->priv_data;
148  int64_t newpos;
149 
150  if (s->filesize == -1 && (whence == AVSEEK_SIZE || whence == SEEK_END)) {
151  av_log(h, AV_LOG_ERROR, "Error during seeking.\n");
152  return AVERROR(EIO);
153  }
154 
155  switch(whence) {
156  case AVSEEK_SIZE:
157  return s->filesize;
158  case SEEK_SET:
159  newpos = pos;
160  break;
161  case SEEK_CUR:
162  newpos = sftp_tell64(s->file);
163  break;
164  case SEEK_END:
165  newpos = s->filesize + pos;
166  break;
167  default:
168  return AVERROR(EINVAL);
169  }
170 
171  if (sftp_seek64(s->file, newpos)) {
172  av_log(h, AV_LOG_ERROR, "Error during seeking.\n");
173  return AVERROR(EIO);
174  }
175 
176  return newpos;
177 }
178 
179 static int libssh_read(URLContext *h, unsigned char *buf, int size)
180 {
181  LIBSSHContext *s = h->priv_data;
182  int bytes_read;
183 
184  if ((bytes_read = sftp_read(s->file, buf, size)) < 0) {
185  av_log(h, AV_LOG_ERROR, "Read error.\n");
186  return AVERROR(EIO);
187  }
188  return bytes_read;
189 }
190 
191 static int libssh_write(URLContext *h, const unsigned char *buf, int size)
192 {
193  LIBSSHContext *s = h->priv_data;
194  int bytes_written;
195 
196  if ((bytes_written = sftp_write(s->file, buf, size)) < 0) {
197  av_log(h, AV_LOG_ERROR, "Write error.\n");
198  return AVERROR(EIO);
199  }
200  return bytes_written;
201 }
202 
203 #define OFFSET(x) offsetof(LIBSSHContext, x)
204 #define D AV_OPT_FLAG_DECODING_PARAM
205 #define E AV_OPT_FLAG_ENCODING_PARAM
206 static const AVOption options[] = {
207  {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
208  {"truncate", "Truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
209  {NULL}
210 };
211 
213  .class_name = "libssh",
214  .item_name = av_default_item_name,
215  .option = options,
216  .version = LIBAVUTIL_VERSION_INT,
217 };
218 
220  .name = "sftp",
221  .url_open = libssh_open,
222  .url_read = libssh_read,
223  .url_write = libssh_write,
224  .url_seek = libssh_seek,
225  .url_close = libssh_close,
226  .priv_data_size = sizeof(LIBSSHContext),
227  .priv_data_class = &libssh_context_class,
229 };
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition: utils.c:3800
const char * s
Definition: avisynth_c.h:668
#define OFFSET(x)
Definition: libssh.c:203
int size
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:35
static int libssh_write(URLContext *h, const unsigned char *buf, int size)
Definition: libssh.c:191
AVOption.
Definition: opt.h:253
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: avcodec.h:4153
int rw_timeout
Definition: libssh.c:35
#define LIBAVUTIL_VERSION_INT
Definition: avcodec.h:820
#define AVSEEK_SIZE
Passing this as the &quot;whence&quot; parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:222
#define pass
Definition: fft.c:511
void av_log(void *avcl, int level, const char *fmt,...) av_printf_format(3
Send the specified message to the log if the level is less than or equal to the current av_log_level...
#define MAX_URL_SIZE
Definition: internal.h:27
const char * av_default_item_name(void *ctx)
Return the context name.
Definition: log.c:145
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:55
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:67
const OptionDef options[]
Definition: ffserver.c:4682
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: avcodec.h:4147
#define AVIO_FLAG_READ
read-only
Definition: avio.h:332
sftp_session sftp
Definition: libssh.c:32
goto fail
Definition: avfilter.c:963
ret
Definition: avfilter.c:961
static av_always_inline av_const double trunc(double x)
Definition: libm.h:176
static int libssh_close(URLContext *h)
Definition: libssh.c:39
static const AVClass libssh_context_class
Definition: libssh.c:212
ssh_session session
Definition: libssh.c:31
int64_t filesize
Definition: libssh.c:34
static int64_t libssh_seek(URLContext *h, int64_t pos, int whence)
Definition: libssh.c:145
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
#define E
Definition: libssh.c:205
void * buf
Definition: avisynth_c.h:594
Definition: url.h:41
Describe the class of an AVClass context structure.
Definition: log.h:50
void * priv_data
Definition: url.h:44
static int libssh_read(URLContext *h, unsigned char *buf, int size)
Definition: libssh.c:179
#define D
Definition: options_table.h:39
const char * name
Definition: url.h:55
static int flags
Definition: cpu.c:45
sftp_file file
Definition: libssh.c:33
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok()...
Definition: avstring.c:183
static int libssh_open(URLContext *h, const char *url, int flags)
Definition: libssh.c:53
Main libavformat public API header.
int trunc
Definition: libssh.c:36
URLProtocol ff_libssh_protocol
Definition: libssh.c:219
#define AVERROR(e)
unbuffered private I/O API