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 36typedef 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 47static 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 57static 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 64static 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 94fail: 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 102static 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 116static 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, 0); 127 return ret < 0 ? ff_neterrno() : ret; 128} 129 130static 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 139static int unix_get_file_handle(URLContext *h) 140{ 141 UnixContext *s = h->priv_data; 142 return s->fd; 143} 144 145URLProtocol 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}; 156