Line |
Branch |
Exec |
Source |
1 |
|
|
/* |
2 |
|
|
* Unix socket protocol |
3 |
|
|
* Copyright (c) 2013 Luca Barbato |
4 |
|
|
* |
5 |
|
|
* This file is part of FFmpeg. |
6 |
|
|
* |
7 |
|
|
* FFmpeg is free software; you can redistribute it and/or |
8 |
|
|
* modify it under the terms of the GNU Lesser General Public |
9 |
|
|
* License as published by the Free Software Foundation; either |
10 |
|
|
* version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
* |
12 |
|
|
* FFmpeg is distributed in the hope that it will be useful, |
13 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 |
|
|
* Lesser General Public License for more details. |
16 |
|
|
* |
17 |
|
|
* You should have received a copy of the GNU Lesser General Public |
18 |
|
|
* License along with FFmpeg; if not, write to the Free Software |
19 |
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
/** |
23 |
|
|
* @file |
24 |
|
|
* |
25 |
|
|
* Unix socket url_protocol |
26 |
|
|
*/ |
27 |
|
|
|
28 |
|
|
#include "libavutil/avstring.h" |
29 |
|
|
#include "libavutil/opt.h" |
30 |
|
|
#include "os_support.h" |
31 |
|
|
#include "network.h" |
32 |
|
|
#include <sys/un.h> |
33 |
|
|
#include "url.h" |
34 |
|
|
|
35 |
|
|
typedef struct UnixContext { |
36 |
|
|
const AVClass *class; |
37 |
|
|
struct sockaddr_un addr; |
38 |
|
|
int timeout; |
39 |
|
|
int listen; |
40 |
|
|
int type; |
41 |
|
|
int fd; |
42 |
|
|
} UnixContext; |
43 |
|
|
|
44 |
|
|
#define OFFSET(x) offsetof(UnixContext, x) |
45 |
|
|
#define ED AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_ENCODING_PARAM |
46 |
|
|
static const AVOption unix_options[] = { |
47 |
|
|
{ "listen", "Open socket for listening", OFFSET(listen), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ED }, |
48 |
|
|
{ "timeout", "Timeout in ms", OFFSET(timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ED }, |
49 |
|
|
{ "type", "Socket type", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = SOCK_STREAM }, INT_MIN, INT_MAX, ED, .unit = "type" }, |
50 |
|
|
{ "stream", "Stream (reliable stream-oriented)", 0, AV_OPT_TYPE_CONST, { .i64 = SOCK_STREAM }, INT_MIN, INT_MAX, ED, .unit = "type" }, |
51 |
|
|
{ "datagram", "Datagram (unreliable packet-oriented)", 0, AV_OPT_TYPE_CONST, { .i64 = SOCK_DGRAM }, INT_MIN, INT_MAX, ED, .unit = "type" }, |
52 |
|
|
{ "seqpacket", "Seqpacket (reliable packet-oriented", 0, AV_OPT_TYPE_CONST, { .i64 = SOCK_SEQPACKET }, INT_MIN, INT_MAX, ED, .unit = "type" }, |
53 |
|
|
{ NULL } |
54 |
|
|
}; |
55 |
|
|
|
56 |
|
|
static const AVClass unix_class = { |
57 |
|
|
.class_name = "unix", |
58 |
|
|
.item_name = av_default_item_name, |
59 |
|
|
.option = unix_options, |
60 |
|
|
.version = LIBAVUTIL_VERSION_INT, |
61 |
|
|
}; |
62 |
|
|
|
63 |
|
✗ |
static int unix_open(URLContext *h, const char *filename, int flags) |
64 |
|
|
{ |
65 |
|
✗ |
UnixContext *s = h->priv_data; |
66 |
|
|
int fd, ret; |
67 |
|
|
|
68 |
|
✗ |
av_strstart(filename, "unix:", &filename); |
69 |
|
✗ |
s->addr.sun_family = AF_UNIX; |
70 |
|
✗ |
av_strlcpy(s->addr.sun_path, filename, sizeof(s->addr.sun_path)); |
71 |
|
|
|
72 |
|
✗ |
if ((fd = ff_socket(AF_UNIX, s->type, 0, h)) < 0) |
73 |
|
✗ |
return ff_neterrno(); |
74 |
|
|
|
75 |
|
✗ |
if (s->timeout < 0 && h->rw_timeout) |
76 |
|
✗ |
s->timeout = h->rw_timeout / 1000; |
77 |
|
|
|
78 |
|
✗ |
if (s->listen) { |
79 |
|
✗ |
ret = ff_listen_bind(fd, (struct sockaddr *)&s->addr, |
80 |
|
|
sizeof(s->addr), s->timeout, h); |
81 |
|
✗ |
if (ret < 0) |
82 |
|
✗ |
goto fail; |
83 |
|
✗ |
fd = ret; |
84 |
|
|
} else { |
85 |
|
✗ |
ret = ff_listen_connect(fd, (struct sockaddr *)&s->addr, |
86 |
|
|
sizeof(s->addr), s->timeout, h, 0); |
87 |
|
✗ |
if (ret < 0) |
88 |
|
✗ |
goto fail; |
89 |
|
|
} |
90 |
|
|
|
91 |
|
✗ |
s->fd = fd; |
92 |
|
|
|
93 |
|
✗ |
return 0; |
94 |
|
|
|
95 |
|
✗ |
fail: |
96 |
|
✗ |
if (s->listen && AVUNERROR(ret) != EADDRINUSE) |
97 |
|
✗ |
unlink(s->addr.sun_path); |
98 |
|
✗ |
if (fd >= 0) |
99 |
|
✗ |
closesocket(fd); |
100 |
|
✗ |
return ret; |
101 |
|
|
} |
102 |
|
|
|
103 |
|
✗ |
static int unix_read(URLContext *h, uint8_t *buf, int size) |
104 |
|
|
{ |
105 |
|
✗ |
UnixContext *s = h->priv_data; |
106 |
|
|
int ret; |
107 |
|
|
|
108 |
|
✗ |
if (!(h->flags & AVIO_FLAG_NONBLOCK)) { |
109 |
|
✗ |
ret = ff_network_wait_fd(s->fd, 0); |
110 |
|
✗ |
if (ret < 0) |
111 |
|
✗ |
return ret; |
112 |
|
|
} |
113 |
|
✗ |
ret = recv(s->fd, buf, size, 0); |
114 |
|
✗ |
if (!ret && s->type == SOCK_STREAM) |
115 |
|
✗ |
return AVERROR_EOF; |
116 |
|
✗ |
return ret < 0 ? ff_neterrno() : ret; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
✗ |
static int unix_write(URLContext *h, const uint8_t *buf, int size) |
120 |
|
|
{ |
121 |
|
✗ |
UnixContext *s = h->priv_data; |
122 |
|
|
int ret; |
123 |
|
|
|
124 |
|
✗ |
if (!(h->flags & AVIO_FLAG_NONBLOCK)) { |
125 |
|
✗ |
ret = ff_network_wait_fd(s->fd, 1); |
126 |
|
✗ |
if (ret < 0) |
127 |
|
✗ |
return ret; |
128 |
|
|
} |
129 |
|
✗ |
ret = send(s->fd, buf, size, MSG_NOSIGNAL); |
130 |
|
✗ |
return ret < 0 ? ff_neterrno() : ret; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
✗ |
static int unix_close(URLContext *h) |
134 |
|
|
{ |
135 |
|
✗ |
UnixContext *s = h->priv_data; |
136 |
|
✗ |
if (s->listen) |
137 |
|
✗ |
unlink(s->addr.sun_path); |
138 |
|
✗ |
closesocket(s->fd); |
139 |
|
✗ |
return 0; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
✗ |
static int unix_get_file_handle(URLContext *h) |
143 |
|
|
{ |
144 |
|
✗ |
UnixContext *s = h->priv_data; |
145 |
|
✗ |
return s->fd; |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
const URLProtocol ff_unix_protocol = { |
149 |
|
|
.name = "unix", |
150 |
|
|
.url_open = unix_open, |
151 |
|
|
.url_read = unix_read, |
152 |
|
|
.url_write = unix_write, |
153 |
|
|
.url_close = unix_close, |
154 |
|
|
.url_get_file_handle = unix_get_file_handle, |
155 |
|
|
.priv_data_size = sizeof(UnixContext), |
156 |
|
|
.priv_data_class = &unix_class, |
157 |
|
|
.flags = URL_PROTOCOL_FLAG_NETWORK, |
158 |
|
|
}; |
159 |
|
|
|