3 * Copyright (c) 2012 Luca Barbato
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 * url syntax: sctp://host:port[?option=val...]
28 * option: 'listen' : listen for an incoming connection
29 * 'max_streams=n' : set the maximum number of streams
30 * 'reuse=1' : enable reusing the socket [TBD]
32 * by setting the maximum number of streams the protocol will use the
33 * first two bytes of the incoming/outgoing buffer to store the
34 * stream number of the packet being read/written.
40 #include <netinet/in.h>
41 #include <netinet/sctp.h>
49 #include "libavutil/intreadwrite.h"
50 #include "libavutil/parseutils.h"
51 #include "libavutil/opt.h"
55 #include "os_support.h"
59 * The sctp_recvmsg and sctp_sendmsg functions are part of the user
60 * library that offers support for the SCTP kernel Implementation.
61 * To avoid build-time clashes the functions sport an ff_-prefix here.
62 * The main purpose of this code is to provide the SCTP Socket API
63 * mappings for user applications to interface with SCTP in the kernel.
65 * This implementation is based on the Socket API Extensions for SCTP
66 * defined in <draft-ietf-tsvwg-sctpsocket-10.txt>
68 * Copyright (c) 2003 International Business Machines, Corp.
70 * Written or modified by:
71 * Ryan Layer <rmlayer@us.ibm.com>
74 static int ff_sctp_recvmsg(int s
, void *msg
, size_t len
, struct sockaddr
*from
,
75 socklen_t
*fromlen
, struct sctp_sndrcvinfo
*sinfo
,
80 char incmsg
[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo
))];
81 struct msghdr inmsg
= { 0 };
82 struct cmsghdr
*cmsg
= NULL
;
87 inmsg
.msg_name
= from
;
88 inmsg
.msg_namelen
= fromlen ?
*fromlen
: 0;
91 inmsg
.msg_control
= incmsg
;
92 inmsg
.msg_controllen
= sizeof(incmsg
);
94 if ((recvb
= recvmsg(s
, &inmsg
, msg_flags ?
*msg_flags
: 0)) < 0)
98 *fromlen
= inmsg
.msg_namelen
;
100 *msg_flags
= inmsg
.msg_flags
;
102 for (cmsg
= CMSG_FIRSTHDR(&inmsg
); cmsg
!= NULL
;
103 cmsg
= CMSG_NXTHDR(&inmsg
, cmsg
)) {
104 if ((IPPROTO_SCTP
== cmsg
->cmsg_level
) &&
105 (SCTP_SNDRCV
== cmsg
->cmsg_type
))
111 memcpy(sinfo
, CMSG_DATA(cmsg
), sizeof(struct sctp_sndrcvinfo
));
116 static int ff_sctp_send(int s
, const void *msg
, size_t len
,
117 const struct sctp_sndrcvinfo
*sinfo
, int flags
)
119 struct msghdr outmsg
;
122 outmsg
.msg_name
= NULL
;
123 outmsg
.msg_namelen
= 0;
124 outmsg
.msg_iov
= &iov
;
127 outmsg
.msg_iovlen
= 1;
128 outmsg
.msg_controllen
= 0;
131 char outcmsg
[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo
))];
132 struct cmsghdr
*cmsg
;
134 outmsg
.msg_control
= outcmsg
;
135 outmsg
.msg_controllen
= sizeof(outcmsg
);
136 outmsg
.msg_flags
= 0;
138 cmsg
= CMSG_FIRSTHDR(&outmsg
);
139 cmsg
->cmsg_level
= IPPROTO_SCTP
;
140 cmsg
->cmsg_type
= SCTP_SNDRCV
;
141 cmsg
->cmsg_len
= CMSG_LEN(sizeof(struct sctp_sndrcvinfo
));
143 outmsg
.msg_controllen
= cmsg
->cmsg_len
;
144 memcpy(CMSG_DATA(cmsg
), sinfo
, sizeof(struct sctp_sndrcvinfo
));
147 return sendmsg(s
, &outmsg
, flags
| MSG_NOSIGNAL
);
150 typedef struct SCTPContext
{
151 const AVClass
*class;
157 struct sockaddr_storage dest_addr
;
160 #define OFFSET(x) offsetof(SCTPContext, x)
161 #define D AV_OPT_FLAG_DECODING_PARAM
162 #define E AV_OPT_FLAG_ENCODING_PARAM
163 static const AVOption options
[] = {
164 { "listen", "Listen for incoming connections", OFFSET(listen
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 1, .flags
= D
|E
},
165 { "timeout", "Connection timeout (in milliseconds)", OFFSET(timeout
), AV_OPT_TYPE_INT
, { .i64
= 10000 }, INT_MIN
, INT_MAX
, .flags
= D
|E
},
166 { "listen_timeout", "Bind timeout (in milliseconds)", OFFSET(listen_timeout
), AV_OPT_TYPE_INT
, { .i64
= -1 }, INT_MIN
, INT_MAX
, .flags
= D
|E
},
167 { "max_streams", "Max stream to allocate", OFFSET(max_streams
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, INT16_MAX
, .flags
= D
|E
},
171 static const AVClass sctp_class
= {
172 .class_name
= "sctp",
173 .item_name
= av_default_item_name
,
175 .version
= LIBAVUTIL_VERSION_INT
,
178 static int sctp_open(URLContext
*h
, const char *uri
, int flags
)
180 struct addrinfo
*ai
, *cur_ai
;
181 struct addrinfo hints
= { 0 };
182 struct sctp_event_subscribe event
= { 0 };
183 struct sctp_initmsg initparams
= { 0 };
186 SCTPContext
*s
= h
->priv_data
;
190 char hostname
[1024], proto
[1024], path
[1024];
193 av_url_split(proto
, sizeof(proto
), NULL
, 0, hostname
, sizeof(hostname
),
194 &port
, path
, sizeof(path
), uri
);
195 if (strcmp(proto
, "sctp"))
196 return AVERROR(EINVAL
);
197 if (port
<= 0 || port
>= 65536) {
198 av_log(s
, AV_LOG_ERROR
, "Port missing in uri\n");
199 return AVERROR(EINVAL
);
202 p
= strchr(uri
, '?');
204 if (av_find_info_tag(buf
, sizeof(buf
), "listen", p
))
206 if (av_find_info_tag(buf
, sizeof(buf
), "max_streams", p
))
207 s
->max_streams
= strtol(buf
, NULL
, 10);
210 hints
.ai_family
= AF_UNSPEC
;
211 hints
.ai_socktype
= SOCK_STREAM
;
212 snprintf(portstr
, sizeof(portstr
), "%d", port
);
213 ret
= getaddrinfo(hostname
, portstr
, &hints
, &ai
);
215 av_log(h
, AV_LOG_ERROR
, "Failed to resolve hostname %s: %s\n",
216 hostname
, gai_strerror(ret
));
223 fd
= ff_socket(cur_ai
->ai_family
, SOCK_STREAM
, IPPROTO_SCTP
);
230 if ((fd
= ff_listen_bind(fd
, cur_ai
->ai_addr
, cur_ai
->ai_addrlen
,
231 s
->listen_timeout
, h
)) < 0) {
236 if ((ret
= ff_listen_connect(fd
, cur_ai
->ai_addr
, cur_ai
->ai_addrlen
,
237 s
->timeout
, h
, !!cur_ai
->ai_next
)) < 0) {
239 if (ret
== AVERROR_EXIT
)
246 event
.sctp_data_io_event
= 1;
247 /* TODO: Subscribe to more event types and handle them */
249 if (setsockopt(fd
, IPPROTO_SCTP
, SCTP_EVENTS
, &event
,
250 sizeof(event
)) != 0) {
251 av_log(h
, AV_LOG_ERROR
,
252 "SCTP ERROR: Unable to subscribe to events\n");
256 if (s
->max_streams
) {
257 initparams
.sinit_max_instreams
= s
->max_streams
;
258 initparams
.sinit_num_ostreams
= s
->max_streams
;
259 if (setsockopt(fd
, IPPROTO_SCTP
, SCTP_INITMSG
, &initparams
,
260 sizeof(initparams
)) < 0) {
261 av_log(h
, AV_LOG_ERROR
,
262 "SCTP ERROR: Unable to initialize socket max streams %d\n",
276 if (cur_ai
->ai_next
) {
277 /* Retry with the next sockaddr */
278 cur_ai
= cur_ai
->ai_next
;
290 static int sctp_wait_fd(int fd
, int write
)
292 int ev
= write ? POLLOUT
: POLLIN
;
293 struct pollfd p
= { .fd
= fd
, .events
= ev
, .revents
= 0 };
296 ret
= poll(&p
, 1, 100);
297 return ret
< 0 ?
ff_neterrno() : p
.revents
& ev ?
0 : AVERROR(EAGAIN
);
300 static int sctp_read(URLContext
*h
, uint8_t *buf
, int size
)
302 SCTPContext
*s
= h
->priv_data
;
305 if (!(h
->flags
& AVIO_FLAG_NONBLOCK
)) {
306 ret
= sctp_wait_fd(s
->fd
, 0);
311 if (s
->max_streams
) {
312 /*StreamId is introduced as a 2byte code into the stream*/
313 struct sctp_sndrcvinfo info
= { 0 };
314 ret
= ff_sctp_recvmsg(s
->fd
, buf
+ 2, size
- 2, NULL
, 0, &info
, 0);
315 AV_WB16(buf
, info
.sinfo_stream
);
316 ret
= ret
< 0 ? ret
: ret
+ 2;
318 ret
= recv(s
->fd
, buf
, size
, 0);
320 return ret
< 0 ?
ff_neterrno() : ret
;
323 static int sctp_write(URLContext
*h
, const uint8_t *buf
, int size
)
325 SCTPContext
*s
= h
->priv_data
;
328 if (!(h
->flags
& AVIO_FLAG_NONBLOCK
)) {
329 ret
= sctp_wait_fd(s
->fd
, 1);
334 if (s
->max_streams
) {
335 /*StreamId is introduced as a 2byte code into the stream*/
336 struct sctp_sndrcvinfo info
= { 0 };
337 info
.sinfo_stream
= AV_RB16(buf
);
338 if (info
.sinfo_stream
> s
->max_streams
)
340 ret
= ff_sctp_send(s
->fd
, buf
+ 2, size
- 2, &info
, MSG_EOR
);
342 ret
= send(s
->fd
, buf
, size
, MSG_NOSIGNAL
);
344 return ret
< 0 ?
ff_neterrno() : ret
;
347 static int sctp_close(URLContext
*h
)
349 SCTPContext
*s
= h
->priv_data
;
354 static int sctp_get_file_handle(URLContext
*h
)
356 SCTPContext
*s
= h
->priv_data
;
360 URLProtocol ff_sctp_protocol
= {
362 .url_open
= sctp_open
,
363 .url_read
= sctp_read
,
364 .url_write
= sctp_write
,
365 .url_close
= sctp_close
,
366 .url_get_file_handle
= sctp_get_file_handle
,
367 .priv_data_size
= sizeof(SCTPContext
),
368 .flags
= URL_PROTOCOL_FLAG_NETWORK
,
369 .priv_data_class
= &sctp_class
,