2
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
3
* Copyright (c) 2002 Fabrice Bellard
5
* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 3 of the License, or
10
* (at your option) any later version.
12
* This program 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
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
* Additional permission under GNU GPL version 3 section 7:
23
* If you modify this program, or any covered work, by linking or
24
* combining it with the OpenSSL project's OpenSSL library (or a
25
* modified version of that library), containing parts covered by the
26
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
27
* grants you additional permission to convey the resulting work.
28
* Corresponding Source for a non-source form of such a combination
29
* shall include the source code for the parts of OpenSSL used as well
30
* as that of the covered work.
33
#include "socket_pair.h"
34
#include "scoped_lock.h"
40
#include <sys/types.h>
41
#include <sys/socket.h>
46
#include <libavutil/avstring.h>
47
#include <libavformat/avformat.h>
52
int ff_network_wait_fd(int fd)
54
struct pollfd p = { fd, POLLOUT, 0 };
56
ret = poll(&p, 1, 100);
57
return ret < 0 ? errno : p.revents & (POLLOUT | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
61
udp_resolve_host(const char *node, int service)
63
struct addrinfo hints = { 0 }, *res = 0;
67
snprintf(sport, sizeof(sport), "%d", service);
69
hints.ai_socktype = SOCK_DGRAM;
70
hints.ai_family = AF_UNSPEC;
71
hints.ai_flags = AI_PASSIVE;
72
if ((error = getaddrinfo(node, sport, &hints, &res))) {
74
ERROR("%s\n", gai_strerror(error));
81
udp_set_url(struct sockaddr_storage *addr,
82
const char *hostname, int port)
84
struct addrinfo *res0;
87
res0 = udp_resolve_host(hostname, port);
88
if (res0 == 0) return 0;
89
memcpy(addr, res0->ai_addr, res0->ai_addrlen);
90
addr_len = res0->ai_addrlen;
97
udp_socket_create(sockaddr_storage *addr, socklen_t *addr_len,
101
struct addrinfo *res0 = NULL, *res = NULL;
103
res0 = udp_resolve_host(0, local_port);
106
for (res = res0; res; res=res->ai_next) {
107
udp_fd = socket(res->ai_family, SOCK_DGRAM | SOCK_NONBLOCK, 0);
108
if (udp_fd != -1) break;
109
ERROR("socket error");
117
memcpy(addr, res->ai_addr, res->ai_addrlen);
118
*addr_len = res->ai_addrlen;
120
#if HAVE_SDP_CUSTOM_IO
121
// bind socket so that we send from and receive
123
if (bind(udp_fd, reinterpret_cast<sockaddr*>(addr), *addr_len) < 0) {
124
ERROR("Bind failed: %s", strerror(errno));
135
const int RTP_BUFFER_SIZE = 1472;
139
namespace sfl_video {
141
SocketPair::SocketPair(const char *uri, int localPort) :
151
pthread_mutex_init(&rtcpWriteMutex_, NULL);
152
openSockets(uri, localPort);
155
SocketPair::~SocketPair()
160
// destroy in reverse order
161
pthread_mutex_destroy(&rtcpWriteMutex_);
165
SocketPair::interrupt()
171
SocketPair::closeSockets()
173
if (rtcpHandle_ > 0 and close(rtcpHandle_))
174
ERROR("%s", strerror(errno));
175
if (rtpHandle_ > 0 and close(rtpHandle_))
176
ERROR("%s", strerror(errno));
181
SocketPair::openSockets(const char *uri, int local_rtp_port)
188
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
189
path, sizeof(path), uri);
191
const int rtcp_port = rtp_port + 1;
193
#if HAVE_SDP_CUSTOM_IO
194
const int local_rtcp_port = local_rtp_port + 1;
196
WARN("libavformat too old for socket reuse, using random source ports");
198
const int local_rtcp_port = 0;
201
sockaddr_storage rtp_addr, rtcp_addr;
202
socklen_t rtp_len, rtcp_len;
204
// Open sockets and store addresses for sending
205
if ((rtpHandle_ = udp_socket_create(&rtp_addr, &rtp_len, local_rtp_port)) == -1 or
206
(rtcpHandle_ = udp_socket_create(&rtcp_addr, &rtcp_len, local_rtcp_port)) == -1 or
207
(rtpDestAddrLen_ = udp_set_url(&rtpDestAddr_, hostname, rtp_port)) == 0 or
208
(rtcpDestAddrLen_ = udp_set_url(&rtcpDestAddr_, hostname, rtcp_port)) == 0) {
210
// Handle failed socket creation
212
throw std::runtime_error("Socket creation failed");
217
SocketPair::createAVIOContext()
219
// FIXME: Caller must free buffer!
220
unsigned char *buffer(static_cast<unsigned char *>(av_malloc(RTP_BUFFER_SIZE)));
222
AVIOContext *context = avio_alloc_context(buffer,
223
RTP_BUFFER_SIZE, 1, reinterpret_cast<void*>(this),
224
&readCallback, &writeCallback, 0);
226
context->max_packet_size = RTP_BUFFER_SIZE;
231
SocketPair::readCallback(void *opaque, uint8_t *buf, int buf_size)
233
SocketPair *context = static_cast<SocketPair*>(opaque);
235
struct sockaddr_storage from;
238
struct pollfd p[2] = { {context->rtpHandle_, POLLIN, 0}, {context->rtcpHandle_, POLLIN, 0}};
241
if (context->interrupted_)
244
/* build fdset to listen to RTP and RTCP packets */
248
if (p[1].revents & POLLIN) {
249
from_len = sizeof(from);
252
len = recvfrom(context->rtcpHandle_, buf, buf_size, 0,
253
(struct sockaddr *)&from, &from_len);
257
if (errno == EAGAIN or errno == EINTR)
264
if (p[0].revents & POLLIN) {
265
from_len = sizeof(from);
268
len = recvfrom(context->rtpHandle_, buf, buf_size, 0,
269
(struct sockaddr *)&from, &from_len);
273
if (errno == EAGAIN or errno == EINTR)
288
/* RTCP packet types */
296
#define RTP_PT_IS_RTCP(x) (((x) >= RTCP_FIR && (x) <= RTCP_IJ) || \
297
((x) >= RTCP_SR && (x) <= RTCP_TOKEN))
300
SocketPair::writeCallback(void *opaque, uint8_t *buf, int buf_size)
302
SocketPair *context = static_cast<SocketPair*>(opaque);
306
if (RTP_PT_IS_RTCP(buf[1])) {
307
/* RTCP payload type */
308
sfl::ScopedLock lock(context->rtcpWriteMutex_);
309
ret = ff_network_wait_fd(context->rtcpHandle_);
313
ret = sendto(context->rtcpHandle_, buf, buf_size, 0,
314
(sockaddr*) &context->rtcpDestAddr_, context->rtcpDestAddrLen_);
316
/* RTP payload type */
317
ret = ff_network_wait_fd(context->rtpHandle_);
321
ret = sendto(context->rtpHandle_, buf, buf_size, 0,
322
(sockaddr*) &context->rtpDestAddr_, context->rtpDestAddrLen_);
325
return ret < 0 ? errno : ret;