[FFmpeg-trac] #8372(avformat:new): SRT Handling Does Not Clean Up Connection
FFmpeg
trac at avcodec.org
Fri Nov 8 15:26:34 EET 2019
#8372: SRT Handling Does Not Clean Up Connection
-------------------------------------+-------------------------------------
Reporter: whitik | Owner:
Type: defect | Status: new
Priority: normal | Component: avformat
Version: unspecified | Resolution:
Keywords: SRT | Blocked By:
Reconnection |
Blocking: | Reproduced by developer: 0
Analyzed by developer: 0 |
-------------------------------------+-------------------------------------
Comment (by whitik):
I've fixed the problem, at least with my usage. I changed the libsrt_setup
function in libsrt.c as follows:
{{{
static int libsrt_setup(URLContext *h, const char *uri, int flags)
{
struct addrinfo hints = {0}, *ai, *cur_ai;
int port;
SRTSOCKET fd = SRT_INVALID_SOCK; // Socket that will be created on this
side (will be stored in context).
// whitik- added socket to hold original socket (for listener).
SRTSOCKET listenerSock = SRT_INVALID_SOCK;
SRTContext *s = h->priv_data;
const char *p;
char buf[256];
int ret;
char hostname[1024], proto[1024], path[1024];
char portstr[10];
int open_timeout = 5000000;
int eid;
av_log(h, AV_LOG_INFO, "libsrt_setup\n");
eid = srt_epoll_create();
if (eid < 0)
return libsrt_neterrno(h);
s->eid = eid;
av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
&port, path, sizeof(path), uri);
if (strcmp(proto, "srt"))
return AVERROR(EINVAL);
if (port <= 0 || port >= 65536)
{
av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
return AVERROR(EINVAL);
}
p = strchr(uri, '?');
if (p)
{
if (av_find_info_tag(buf, sizeof(buf), "timeout", p))
{
s->rw_timeout = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p))
{
s->listen_timeout = strtol(buf, NULL, 10);
}
}
if (s->rw_timeout >= 0)
{
open_timeout = h->rw_timeout = s->rw_timeout;
}
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
snprintf(portstr, sizeof(portstr), "%d", port);
if (s->mode == SRT_MODE_LISTENER)
hints.ai_flags |= AI_PASSIVE;
ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
if (ret)
{
av_log(h, AV_LOG_ERROR,
"Failed to resolve hostname %s: %s\n",
hostname, gai_strerror(ret));
return AVERROR(EIO);
}
cur_ai = ai;
restart:
// whitik - create a socket. e.g. This will be the listener socket. Will
be stored in context.
fd = srt_create_socket(); // srt_socket(cur_ai->ai_family,
cur_ai->ai_socktype, 0);
if (fd < 0)
{
ret = libsrt_neterrno(h);
goto fail;
}
if ((ret = libsrt_set_options_pre(h, fd)) < 0)
{
goto fail;
}
/* Set the socket's send or receive buffer sizes, if specified.
If unspecified or setting fails, system default is used. */
if (s->recv_buffer_size > 0)
{
srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size,
sizeof(s->recv_buffer_size));
}
if (s->send_buffer_size > 0)
{
srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size,
sizeof(s->send_buffer_size));
}
if (s->mode == SRT_MODE_LISTENER)
{
// multi-client
// whitik - this returns the connection-side socket, if one has
connected.
if ((ret = libsrt_listen(s->eid, fd, cur_ai->ai_addr,
cur_ai->ai_addrlen, h, open_timeout / 1000)) < 0)
goto fail1;
// whitik - make sure we remember original listener socket, since we
need to close this at the end.
listenerSock = fd;
fd = ret; // .. replace socket we're going to read from as context
socket, but listenerSock is original one.
}
else
{
if (s->mode == SRT_MODE_RENDEZVOUS)
{
ret = srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
if (ret)
goto fail1;
}
if ((ret = libsrt_listen_connect(s->eid, fd, cur_ai->ai_addr,
cur_ai->ai_addrlen,
open_timeout / 1000, h,
!!cur_ai->ai_next)) < 0)
{
if (ret == AVERROR_EXIT)
goto fail1;
else
goto fail;
}
}
if ((ret = libsrt_set_options_post(h, fd)) < 0)
{
goto fail;
}
if (flags & AVIO_FLAG_WRITE)
{
int packet_size = 0;
int optlen = sizeof(packet_size);
ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE",
&packet_size, &optlen);
if (ret < 0)
goto fail1;
if (packet_size > 0)
h->max_packet_size = packet_size;
}
h->is_streamed = 1;
s->fd = fd;
s->listenerSock = listenerSock; // whitik - Keep original socket in
context for closing.
freeaddrinfo(ai);
return 0;
fail:
if (cur_ai->ai_next)
{
/* Retry with the next sockaddr */
cur_ai = cur_ai->ai_next;
if (fd >= 0)
srt_close(fd);
ret = 0;
goto restart;
}
fail1:
if (fd >= 0)
srt_close(fd);
freeaddrinfo(ai);
return ret;
}
}}}
Note the use of 'listenerSock' which stores the listener socket separately
in the context to fd which is the 'accept'ed connection socket. In
'libsrt_close', 's->listenerSock' is then closed in addition to s->fd.
--
Ticket URL: <https://trac.ffmpeg.org/ticket/8372#comment:3>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker
More information about the FFmpeg-trac
mailing list