[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