Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 | ||
29 | #include "libavutil/avstring.h" | |
30 | #include "libavutil/opt.h" | |
31 | #include "os_support.h" | |
32 | #include "network.h" | |
33 | #include <sys/un.h> | |
34 | #include "url.h" | |
35 | ||
36 | typedef struct UnixContext { | |
37 | const AVClass *class; | |
38 | struct sockaddr_un addr; | |
39 | int timeout; | |
40 | int listen; | |
41 | int type; | |
42 | int fd; | |
43 | } UnixContext; | |
44 | ||
45 | #define OFFSET(x) offsetof(UnixContext, x) | |
46 | #define ED AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_ENCODING_PARAM | |
47 | static const AVOption unix_options[] = { | |
48 | { "listen", "Open socket for listening", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ED }, | |
49 | { "timeout", "Timeout in ms", OFFSET(timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ED }, | |
50 | { "type", "Socket type", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = SOCK_STREAM }, INT_MIN, INT_MAX, ED, "type" }, | |
51 | { "stream", "Stream (reliable stream-oriented)", 0, AV_OPT_TYPE_CONST, { .i64 = SOCK_STREAM }, INT_MIN, INT_MAX, ED, "type" }, | |
52 | { "datagram", "Datagram (unreliable packet-oriented)", 0, AV_OPT_TYPE_CONST, { .i64 = SOCK_DGRAM }, INT_MIN, INT_MAX, ED, "type" }, | |
53 | { "seqpacket", "Seqpacket (reliable packet-oriented", 0, AV_OPT_TYPE_CONST, { .i64 = SOCK_SEQPACKET }, INT_MIN, INT_MAX, ED, "type" }, | |
54 | { NULL } | |
55 | }; | |
56 | ||
57 | static const AVClass unix_class = { | |
58 | .class_name = "unix", | |
59 | .item_name = av_default_item_name, | |
60 | .option = unix_options, | |
61 | .version = LIBAVUTIL_VERSION_INT, | |
62 | }; | |
63 | ||
64 | static int unix_open(URLContext *h, const char *filename, int flags) | |
65 | { | |
66 | UnixContext *s = h->priv_data; | |
67 | int fd, ret; | |
68 | ||
69 | av_strstart(filename, "unix:", &filename); | |
70 | s->addr.sun_family = AF_UNIX; | |
71 | av_strlcpy(s->addr.sun_path, filename, sizeof(s->addr.sun_path)); | |
72 | ||
73 | if ((fd = ff_socket(AF_UNIX, s->type, 0)) < 0) | |
74 | return ff_neterrno(); | |
75 | ||
76 | if (s->listen) { | |
77 | fd = ff_listen_bind(fd, (struct sockaddr *)&s->addr, | |
78 | sizeof(s->addr), s->timeout, h); | |
79 | if (fd < 0) { | |
80 | ret = fd; | |
81 | goto fail; | |
82 | } | |
83 | } else { | |
84 | ret = ff_listen_connect(fd, (struct sockaddr *)&s->addr, | |
85 | sizeof(s->addr), s->timeout, h, 0); | |
86 | if (ret < 0) | |
87 | goto fail; | |
88 | } | |
89 | ||
90 | s->fd = fd; | |
91 | ||
92 | return 0; | |
93 | ||
94 | fail: | |
95 | if (s->listen && AVUNERROR(ret) != EADDRINUSE) | |
96 | unlink(s->addr.sun_path); | |
97 | if (fd >= 0) | |
98 | closesocket(fd); | |
99 | return ret; | |
100 | } | |
101 | ||
102 | static int unix_read(URLContext *h, uint8_t *buf, int size) | |
103 | { | |
104 | UnixContext *s = h->priv_data; | |
105 | int ret; | |
106 | ||
107 | if (!(h->flags & AVIO_FLAG_NONBLOCK)) { | |
108 | ret = ff_network_wait_fd(s->fd, 0); | |
109 | if (ret < 0) | |
110 | return ret; | |
111 | } | |
112 | ret = recv(s->fd, buf, size, 0); | |
113 | return ret < 0 ? ff_neterrno() : ret; | |
114 | } | |
115 | ||
116 | static int unix_write(URLContext *h, const uint8_t *buf, int size) | |
117 | { | |
118 | UnixContext *s = h->priv_data; | |
119 | int ret; | |
120 | ||
121 | if (!(h->flags & AVIO_FLAG_NONBLOCK)) { | |
122 | ret = ff_network_wait_fd(s->fd, 1); | |
123 | if (ret < 0) | |
124 | return ret; | |
125 | } | |
126 | ret = send(s->fd, buf, size, MSG_NOSIGNAL); | |
127 | return ret < 0 ? ff_neterrno() : ret; | |
128 | } | |
129 | ||
130 | static int unix_close(URLContext *h) | |
131 | { | |
132 | UnixContext *s = h->priv_data; | |
133 | if (s->listen) | |
134 | unlink(s->addr.sun_path); | |
135 | closesocket(s->fd); | |
136 | return 0; | |
137 | } | |
138 | ||
139 | static int unix_get_file_handle(URLContext *h) | |
140 | { | |
141 | UnixContext *s = h->priv_data; | |
142 | return s->fd; | |
143 | } | |
144 | ||
145 | URLProtocol ff_unix_protocol = { | |
146 | .name = "unix", | |
147 | .url_open = unix_open, | |
148 | .url_read = unix_read, | |
149 | .url_write = unix_write, | |
150 | .url_close = unix_close, | |
151 | .url_get_file_handle = unix_get_file_handle, | |
152 | .priv_data_size = sizeof(UnixContext), | |
153 | .priv_data_class = &unix_class, | |
154 | .flags = URL_PROTOCOL_FLAG_NETWORK, | |
155 | }; |