annotate ffmpeg/libavformat/sctp.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * SCTP protocol
yading@11 3 * Copyright (c) 2012 Luca Barbato
yading@11 4 *
yading@11 5 * This file is part of Libav.
yading@11 6 *
yading@11 7 * Libav is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * Libav is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with Libav; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 *
yading@11 25 * sctp url_protocol
yading@11 26 *
yading@11 27 * url syntax: sctp://host:port[?option=val...]
yading@11 28 * option: 'listen' : listen for an incoming connection
yading@11 29 * 'max_streams=n' : set the maximum number of streams
yading@11 30 * 'reuse=1' : enable reusing the socket [TBD]
yading@11 31 *
yading@11 32 * by setting the maximum number of streams the protocol will use the
yading@11 33 * first two bytes of the incoming/outgoing buffer to store the
yading@11 34 * stream number of the packet being read/written.
yading@11 35 * @see sctp_read
yading@11 36 * @see sctp_write
yading@11 37 */
yading@11 38
yading@11 39
yading@11 40 #include <netinet/in.h>
yading@11 41 #include <netinet/sctp.h>
yading@11 42
yading@11 43 #include "config.h"
yading@11 44
yading@11 45 #if HAVE_POLL_H
yading@11 46 #include <poll.h>
yading@11 47 #endif
yading@11 48
yading@11 49 #include "libavutil/intreadwrite.h"
yading@11 50 #include "libavutil/parseutils.h"
yading@11 51 #include "avformat.h"
yading@11 52 #include "internal.h"
yading@11 53 #include "network.h"
yading@11 54 #include "os_support.h"
yading@11 55 #include "url.h"
yading@11 56
yading@11 57 /*
yading@11 58 * The sctp_recvmsg and sctp_sendmsg functions are part of the user
yading@11 59 * library that offers support
yading@11 60 * for the SCTP kernel Implementation. The main purpose of this
yading@11 61 * code is to provide the SCTP Socket API mappings for user
yading@11 62 * application to interface with the SCTP in kernel.
yading@11 63 *
yading@11 64 * This implementation is based on the Socket API Extensions for SCTP
yading@11 65 * defined in <draft-ietf-tsvwg-sctpsocket-10.txt>
yading@11 66 *
yading@11 67 * Copyright (c) 2003 International Business Machines, Corp.
yading@11 68 *
yading@11 69 * Written or modified by:
yading@11 70 * Ryan Layer <rmlayer@us.ibm.com>
yading@11 71 */
yading@11 72
yading@11 73 static int ff_sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from,
yading@11 74 socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo,
yading@11 75 int *msg_flags)
yading@11 76 {
yading@11 77 int recvb;
yading@11 78 struct iovec iov;
yading@11 79 char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
yading@11 80 struct msghdr inmsg = { 0 };
yading@11 81 struct cmsghdr *cmsg = NULL;
yading@11 82
yading@11 83 iov.iov_base = msg;
yading@11 84 iov.iov_len = len;
yading@11 85
yading@11 86 inmsg.msg_name = from;
yading@11 87 inmsg.msg_namelen = fromlen ? *fromlen : 0;
yading@11 88 inmsg.msg_iov = &iov;
yading@11 89 inmsg.msg_iovlen = 1;
yading@11 90 inmsg.msg_control = incmsg;
yading@11 91 inmsg.msg_controllen = sizeof(incmsg);
yading@11 92
yading@11 93 if ((recvb = recvmsg(s, &inmsg, msg_flags ? *msg_flags : 0)) < 0)
yading@11 94 return recvb;
yading@11 95
yading@11 96 if (fromlen)
yading@11 97 *fromlen = inmsg.msg_namelen;
yading@11 98 if (msg_flags)
yading@11 99 *msg_flags = inmsg.msg_flags;
yading@11 100
yading@11 101 for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL;
yading@11 102 cmsg = CMSG_NXTHDR(&inmsg, cmsg)) {
yading@11 103 if ((IPPROTO_SCTP == cmsg->cmsg_level) &&
yading@11 104 (SCTP_SNDRCV == cmsg->cmsg_type))
yading@11 105 break;
yading@11 106 }
yading@11 107
yading@11 108 /* Copy sinfo. */
yading@11 109 if (cmsg)
yading@11 110 memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo));
yading@11 111
yading@11 112 return recvb;
yading@11 113 }
yading@11 114
yading@11 115 static int ff_sctp_send(int s, const void *msg, size_t len,
yading@11 116 const struct sctp_sndrcvinfo *sinfo, int flags)
yading@11 117 {
yading@11 118 struct msghdr outmsg;
yading@11 119 struct iovec iov;
yading@11 120
yading@11 121 outmsg.msg_name = NULL;
yading@11 122 outmsg.msg_namelen = 0;
yading@11 123 outmsg.msg_iov = &iov;
yading@11 124 iov.iov_base = (void*)msg;
yading@11 125 iov.iov_len = len;
yading@11 126 outmsg.msg_iovlen = 1;
yading@11 127 outmsg.msg_controllen = 0;
yading@11 128
yading@11 129 if (sinfo) {
yading@11 130 char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
yading@11 131 struct cmsghdr *cmsg;
yading@11 132
yading@11 133 outmsg.msg_control = outcmsg;
yading@11 134 outmsg.msg_controllen = sizeof(outcmsg);
yading@11 135 outmsg.msg_flags = 0;
yading@11 136
yading@11 137 cmsg = CMSG_FIRSTHDR(&outmsg);
yading@11 138 cmsg->cmsg_level = IPPROTO_SCTP;
yading@11 139 cmsg->cmsg_type = SCTP_SNDRCV;
yading@11 140 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
yading@11 141
yading@11 142 outmsg.msg_controllen = cmsg->cmsg_len;
yading@11 143 memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo));
yading@11 144 }
yading@11 145
yading@11 146 return sendmsg(s, &outmsg, flags);
yading@11 147 }
yading@11 148
yading@11 149 typedef struct SCTPContext {
yading@11 150 int fd;
yading@11 151 int max_streams;
yading@11 152 struct sockaddr_storage dest_addr;
yading@11 153 socklen_t dest_addr_len;
yading@11 154 } SCTPContext;
yading@11 155
yading@11 156 static int sctp_open(URLContext *h, const char *uri, int flags)
yading@11 157 {
yading@11 158 struct addrinfo *ai, *cur_ai;
yading@11 159 struct addrinfo hints = { 0 };
yading@11 160 struct sctp_event_subscribe event = { 0 };
yading@11 161 struct sctp_initmsg initparams = { 0 };
yading@11 162 int port;
yading@11 163 int fd = -1;
yading@11 164 SCTPContext *s = h->priv_data;
yading@11 165 const char *p;
yading@11 166 char buf[256];
yading@11 167 int ret, listen_socket = 0;
yading@11 168 char hostname[1024], proto[1024], path[1024];
yading@11 169 char portstr[10];
yading@11 170
yading@11 171 av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
yading@11 172 &port, path, sizeof(path), uri);
yading@11 173 if (strcmp(proto, "sctp"))
yading@11 174 return AVERROR(EINVAL);
yading@11 175 if (port <= 0 || port >= 65536) {
yading@11 176 av_log(s, AV_LOG_ERROR, "Port missing in uri\n");
yading@11 177 return AVERROR(EINVAL);
yading@11 178 }
yading@11 179
yading@11 180 s->max_streams = 0;
yading@11 181 p = strchr(uri, '?');
yading@11 182 if (p) {
yading@11 183 if (av_find_info_tag(buf, sizeof(buf), "listen", p))
yading@11 184 listen_socket = 1;
yading@11 185 if (av_find_info_tag(buf, sizeof(buf), "max_streams", p))
yading@11 186 s->max_streams = strtol(buf, NULL, 10);
yading@11 187 }
yading@11 188
yading@11 189 hints.ai_family = AF_UNSPEC;
yading@11 190 hints.ai_socktype = SOCK_STREAM;
yading@11 191 snprintf(portstr, sizeof(portstr), "%d", port);
yading@11 192 ret = getaddrinfo(hostname, portstr, &hints, &ai);
yading@11 193 if (ret) {
yading@11 194 av_log(h, AV_LOG_ERROR, "Failed to resolve hostname %s: %s\n",
yading@11 195 hostname, gai_strerror(ret));
yading@11 196 return AVERROR(EIO);
yading@11 197 }
yading@11 198
yading@11 199 cur_ai = ai;
yading@11 200
yading@11 201 fd = socket(cur_ai->ai_family, SOCK_STREAM, IPPROTO_SCTP);
yading@11 202 if (fd < 0)
yading@11 203 goto fail;
yading@11 204
yading@11 205 s->dest_addr_len = sizeof(s->dest_addr);
yading@11 206
yading@11 207 if (listen_socket) {
yading@11 208 int fd1;
yading@11 209 ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
yading@11 210 listen(fd, 100);
yading@11 211 fd1 = accept(fd, NULL, NULL);
yading@11 212 closesocket(fd);
yading@11 213 fd = fd1;
yading@11 214 } else
yading@11 215 ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
yading@11 216
yading@11 217 ff_socket_nonblock(fd, 1);
yading@11 218
yading@11 219 event.sctp_data_io_event = 1;
yading@11 220 /* TODO: Subscribe to more event types and handle them */
yading@11 221
yading@11 222 if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event,
yading@11 223 sizeof(event)) != 0) {
yading@11 224 av_log(h, AV_LOG_ERROR,
yading@11 225 "SCTP ERROR: Unable to subscribe to events\n");
yading@11 226 goto fail;
yading@11 227 }
yading@11 228
yading@11 229 if (s->max_streams) {
yading@11 230 initparams.sinit_max_instreams = s->max_streams;
yading@11 231 initparams.sinit_num_ostreams = s->max_streams;
yading@11 232 if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initparams,
yading@11 233 sizeof(initparams)) < 0)
yading@11 234 av_log(h, AV_LOG_ERROR,
yading@11 235 "SCTP ERROR: Unable to initialize socket max streams %d\n",
yading@11 236 s->max_streams);
yading@11 237 }
yading@11 238
yading@11 239 h->priv_data = s;
yading@11 240 h->is_streamed = 1;
yading@11 241 s->fd = fd;
yading@11 242 freeaddrinfo(ai);
yading@11 243 return 0;
yading@11 244
yading@11 245 fail:
yading@11 246 ret = AVERROR(EIO);
yading@11 247 freeaddrinfo(ai);
yading@11 248 return ret;
yading@11 249 }
yading@11 250
yading@11 251 static int sctp_wait_fd(int fd, int write)
yading@11 252 {
yading@11 253 int ev = write ? POLLOUT : POLLIN;
yading@11 254 struct pollfd p = { .fd = fd, .events = ev, .revents = 0 };
yading@11 255 int ret;
yading@11 256
yading@11 257 ret = poll(&p, 1, 100);
yading@11 258 return ret < 0 ? ff_neterrno() : p.revents & ev ? 0 : AVERROR(EAGAIN);
yading@11 259 }
yading@11 260
yading@11 261 static int sctp_read(URLContext *h, uint8_t *buf, int size)
yading@11 262 {
yading@11 263 SCTPContext *s = h->priv_data;
yading@11 264 int ret;
yading@11 265
yading@11 266 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
yading@11 267 ret = sctp_wait_fd(s->fd, 0);
yading@11 268 if (ret < 0)
yading@11 269 return ret;
yading@11 270 }
yading@11 271
yading@11 272 if (s->max_streams) {
yading@11 273 /*StreamId is introduced as a 2byte code into the stream*/
yading@11 274 struct sctp_sndrcvinfo info = { 0 };
yading@11 275 ret = ff_sctp_recvmsg(s->fd, buf + 2, size - 2, NULL, 0, &info, 0);
yading@11 276 AV_WB16(buf, info.sinfo_stream);
yading@11 277 ret = ret < 0 ? ret : ret + 2;
yading@11 278 } else
yading@11 279 ret = recv(s->fd, buf, size, 0);
yading@11 280
yading@11 281 return ret < 0 ? ff_neterrno() : ret;
yading@11 282 }
yading@11 283
yading@11 284 static int sctp_write(URLContext *h, const uint8_t *buf, int size)
yading@11 285 {
yading@11 286 SCTPContext *s = h->priv_data;
yading@11 287 int ret;
yading@11 288
yading@11 289 if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
yading@11 290 ret = sctp_wait_fd(s->fd, 1);
yading@11 291 if (ret < 0)
yading@11 292 return ret;
yading@11 293 }
yading@11 294
yading@11 295 if (s->max_streams) {
yading@11 296 /*StreamId is introduced as a 2byte code into the stream*/
yading@11 297 struct sctp_sndrcvinfo info = { 0 };
yading@11 298 info.sinfo_stream = AV_RB16(buf);
yading@11 299 if (info.sinfo_stream > s->max_streams) {
yading@11 300 av_log(h, AV_LOG_ERROR, "bad input data\n");
yading@11 301 return AVERROR(EINVAL);
yading@11 302 }
yading@11 303 ret = ff_sctp_send(s->fd, buf + 2, size - 2, &info, MSG_EOR);
yading@11 304 } else
yading@11 305 ret = send(s->fd, buf, size, 0);
yading@11 306
yading@11 307 return ret < 0 ? ff_neterrno() : ret;
yading@11 308 }
yading@11 309
yading@11 310 static int sctp_close(URLContext *h)
yading@11 311 {
yading@11 312 SCTPContext *s = h->priv_data;
yading@11 313 closesocket(s->fd);
yading@11 314 return 0;
yading@11 315 }
yading@11 316
yading@11 317 static int sctp_get_file_handle(URLContext *h)
yading@11 318 {
yading@11 319 SCTPContext *s = h->priv_data;
yading@11 320 return s->fd;
yading@11 321 }
yading@11 322
yading@11 323 URLProtocol ff_sctp_protocol = {
yading@11 324 .name = "sctp",
yading@11 325 .url_open = sctp_open,
yading@11 326 .url_read = sctp_read,
yading@11 327 .url_write = sctp_write,
yading@11 328 .url_close = sctp_close,
yading@11 329 .url_get_file_handle = sctp_get_file_handle,
yading@11 330 .priv_data_size = sizeof(SCTPContext),
yading@11 331 .flags = URL_PROTOCOL_FLAG_NETWORK,
yading@11 332 };