vlc/src/network/udp.c

748 lines
21 KiB
C
Raw Normal View History

2005-12-05 10:36:39 +01:00
/*****************************************************************************
* udp.c:
*****************************************************************************
LGPL Re-license almost all of libVLC and libVLCcore to LGPLv2.1+ This move was authorized by the developers, either: - by e-mail, - by vote at the VideoLAN Dev Days 2011, - on the license website, - in a contract, oral or written. No objection was raised, so far. The developers agreeing are: Justus Piater Alexis Ballier Alexander Bethke Mohammed Adnène Trojette Alex Converse Alexey Sokolov Alexis de Lattre Andre Pang Anthony Loiseau Cyril Deguet André Weber Boris Dorès Brieuc Jeunhomme Benjamin Drung Hugo Beauzée-Luyssen Benoit Steiner Benjamin Pracht Bernie Purcell Przemyslaw Fiala Arnaud de Bossoreille de Ribou Brad Smith Nick Briggs Christopher Rath Christophe Courtaut Christopher Mueller Clement Chesnin Andres Krapf Damien Fouilleul David Flynn Sebastien Zwickert Antoine Cellerier Jérôme Decoodt Jérome Decoodt Dylan Yudaken Eduard Babayan Eugenio Jarosiewicz Elliot Murphy Eric Petit Erwan Tulou Etienne Membrives Ludovic Fauvet Fabio Ritrovato Tobias Güntner Jakub Wieczorek Frédéric Crozat Francois Cartegnie Laurent Aimar Florian G. Pflug Felix Paul Kühne Frank Enderle Rafaël Carré Simon Latapie Gildas Bazin Geoffroy Couprie Julien / Gellule Gildas Bazin Arnaud Schauly Toralf Niebuhr Vicente Jimenez Aguilar Derk-Jan Hartman Henri Fallon Ilkka Ollakka Olivier Teulière Rémi Duraffort Jakob Leben Jean-Baptiste Kempf Jean-Paul Saman Jean-Philippe Grimaldi Jean-François Massol Gaël Hendryckx Jakob Leben Jean-Marc Dressler Jai Menon Johan Bilien Johann Ransay Joris van Rooij JP Dinger Jean-Philippe André Adrien Grand Juha Jeronen Juho Vähä-Herttua Kaarlo Raiha Kaarlo Raiha Kamil Baldyga Keary Griffin Ken Self KO Myung-Hun Pierre Ynard Filippo Carone Loïc Minier Luca Barbato Lucas C. Villa Real Lukas Durfina Adrien Maglo Marc Ariberti Mark Lee Mark Moriarty Martin Storsjö Christophe Massiot Michel Kaempf Marian Ďurkovič Mirsal Ennaime Carlo Calabrò Damien Lucas Naohiro Koriyama Basos G Pierre Baillet Vincent Penquerc'h Olivier Aubert Pankaj Yadav Paul Corke Pierre d'Herbemont Philippe Morin Antoine Lejeune Michael Ploujnikov Jean-Marc Dressler Michael Hanselmann Rafaël Carré Ramiro Polla Rémi Denis-Courmont Renaud Dartus Richard Shepherd Faustino Osuna Arnaud Vallat Rob Jonson Robert Jedrzejczyk Steve Lhomme Rocky Bernstein Romain Goyet Rov Juvano Sam Hocevar Martin T. H. Sandsmark Sebastian Birk Sébastien Escudier Vincent Seguin Fabio Ritrovato Sigmund Augdal Helberg Casian Andrei Srikanth Raju Hannes Domani Stéphane Borel Stephan Krempel Stephan Assmus Tony Castley Pavlov Konstantin Eric Petit Tanguy Krotoff Dennis van Amerongen Michel Lespinasse Can Wu Xavier Marchesini Sébastien Toque Christophe Mutricy Yoann Peronneau Yohann Martineau Yuval Tze Scott Caudle Clément Stenac It is possible, that some minor piece of code was badly tracked, for some reasons (SVN, mainly) or that some small developers did not answer. However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3", and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and the very vast majority of developers have agreed (> 99.99% of the code, > 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
* Copyright (C) 2004-2006 VLC authors and VideoLAN
* Copyright © 2006-2007 Rémi Denis-Courmont
*
2005-12-05 10:36:39 +01:00
*
* Authors: Laurent Aimar <fenrir@videolan.org>
2019-09-04 21:10:51 +02:00
* Rémi Denis-Courmont
2005-12-05 10:36:39 +01:00
*
LGPL Re-license almost all of libVLC and libVLCcore to LGPLv2.1+ This move was authorized by the developers, either: - by e-mail, - by vote at the VideoLAN Dev Days 2011, - on the license website, - in a contract, oral or written. No objection was raised, so far. The developers agreeing are: Justus Piater Alexis Ballier Alexander Bethke Mohammed Adnène Trojette Alex Converse Alexey Sokolov Alexis de Lattre Andre Pang Anthony Loiseau Cyril Deguet André Weber Boris Dorès Brieuc Jeunhomme Benjamin Drung Hugo Beauzée-Luyssen Benoit Steiner Benjamin Pracht Bernie Purcell Przemyslaw Fiala Arnaud de Bossoreille de Ribou Brad Smith Nick Briggs Christopher Rath Christophe Courtaut Christopher Mueller Clement Chesnin Andres Krapf Damien Fouilleul David Flynn Sebastien Zwickert Antoine Cellerier Jérôme Decoodt Jérome Decoodt Dylan Yudaken Eduard Babayan Eugenio Jarosiewicz Elliot Murphy Eric Petit Erwan Tulou Etienne Membrives Ludovic Fauvet Fabio Ritrovato Tobias Güntner Jakub Wieczorek Frédéric Crozat Francois Cartegnie Laurent Aimar Florian G. Pflug Felix Paul Kühne Frank Enderle Rafaël Carré Simon Latapie Gildas Bazin Geoffroy Couprie Julien / Gellule Gildas Bazin Arnaud Schauly Toralf Niebuhr Vicente Jimenez Aguilar Derk-Jan Hartman Henri Fallon Ilkka Ollakka Olivier Teulière Rémi Duraffort Jakob Leben Jean-Baptiste Kempf Jean-Paul Saman Jean-Philippe Grimaldi Jean-François Massol Gaël Hendryckx Jakob Leben Jean-Marc Dressler Jai Menon Johan Bilien Johann Ransay Joris van Rooij JP Dinger Jean-Philippe André Adrien Grand Juha Jeronen Juho Vähä-Herttua Kaarlo Raiha Kaarlo Raiha Kamil Baldyga Keary Griffin Ken Self KO Myung-Hun Pierre Ynard Filippo Carone Loïc Minier Luca Barbato Lucas C. Villa Real Lukas Durfina Adrien Maglo Marc Ariberti Mark Lee Mark Moriarty Martin Storsjö Christophe Massiot Michel Kaempf Marian Ďurkovič Mirsal Ennaime Carlo Calabrò Damien Lucas Naohiro Koriyama Basos G Pierre Baillet Vincent Penquerc'h Olivier Aubert Pankaj Yadav Paul Corke Pierre d'Herbemont Philippe Morin Antoine Lejeune Michael Ploujnikov Jean-Marc Dressler Michael Hanselmann Rafaël Carré Ramiro Polla Rémi Denis-Courmont Renaud Dartus Richard Shepherd Faustino Osuna Arnaud Vallat Rob Jonson Robert Jedrzejczyk Steve Lhomme Rocky Bernstein Romain Goyet Rov Juvano Sam Hocevar Martin T. H. Sandsmark Sebastian Birk Sébastien Escudier Vincent Seguin Fabio Ritrovato Sigmund Augdal Helberg Casian Andrei Srikanth Raju Hannes Domani Stéphane Borel Stephan Krempel Stephan Assmus Tony Castley Pavlov Konstantin Eric Petit Tanguy Krotoff Dennis van Amerongen Michel Lespinasse Can Wu Xavier Marchesini Sébastien Toque Christophe Mutricy Yoann Peronneau Yohann Martineau Yuval Tze Scott Caudle Clément Stenac It is possible, that some minor piece of code was badly tracked, for some reasons (SVN, mainly) or that some small developers did not answer. However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3", and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and the very vast majority of developers have agreed (> 99.99% of the code, > 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
2005-12-05 10:36:39 +01:00
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
LGPL Re-license almost all of libVLC and libVLCcore to LGPLv2.1+ This move was authorized by the developers, either: - by e-mail, - by vote at the VideoLAN Dev Days 2011, - on the license website, - in a contract, oral or written. No objection was raised, so far. The developers agreeing are: Justus Piater Alexis Ballier Alexander Bethke Mohammed Adnène Trojette Alex Converse Alexey Sokolov Alexis de Lattre Andre Pang Anthony Loiseau Cyril Deguet André Weber Boris Dorès Brieuc Jeunhomme Benjamin Drung Hugo Beauzée-Luyssen Benoit Steiner Benjamin Pracht Bernie Purcell Przemyslaw Fiala Arnaud de Bossoreille de Ribou Brad Smith Nick Briggs Christopher Rath Christophe Courtaut Christopher Mueller Clement Chesnin Andres Krapf Damien Fouilleul David Flynn Sebastien Zwickert Antoine Cellerier Jérôme Decoodt Jérome Decoodt Dylan Yudaken Eduard Babayan Eugenio Jarosiewicz Elliot Murphy Eric Petit Erwan Tulou Etienne Membrives Ludovic Fauvet Fabio Ritrovato Tobias Güntner Jakub Wieczorek Frédéric Crozat Francois Cartegnie Laurent Aimar Florian G. Pflug Felix Paul Kühne Frank Enderle Rafaël Carré Simon Latapie Gildas Bazin Geoffroy Couprie Julien / Gellule Gildas Bazin Arnaud Schauly Toralf Niebuhr Vicente Jimenez Aguilar Derk-Jan Hartman Henri Fallon Ilkka Ollakka Olivier Teulière Rémi Duraffort Jakob Leben Jean-Baptiste Kempf Jean-Paul Saman Jean-Philippe Grimaldi Jean-François Massol Gaël Hendryckx Jakob Leben Jean-Marc Dressler Jai Menon Johan Bilien Johann Ransay Joris van Rooij JP Dinger Jean-Philippe André Adrien Grand Juha Jeronen Juho Vähä-Herttua Kaarlo Raiha Kaarlo Raiha Kamil Baldyga Keary Griffin Ken Self KO Myung-Hun Pierre Ynard Filippo Carone Loïc Minier Luca Barbato Lucas C. Villa Real Lukas Durfina Adrien Maglo Marc Ariberti Mark Lee Mark Moriarty Martin Storsjö Christophe Massiot Michel Kaempf Marian Ďurkovič Mirsal Ennaime Carlo Calabrò Damien Lucas Naohiro Koriyama Basos G Pierre Baillet Vincent Penquerc'h Olivier Aubert Pankaj Yadav Paul Corke Pierre d'Herbemont Philippe Morin Antoine Lejeune Michael Ploujnikov Jean-Marc Dressler Michael Hanselmann Rafaël Carré Ramiro Polla Rémi Denis-Courmont Renaud Dartus Richard Shepherd Faustino Osuna Arnaud Vallat Rob Jonson Robert Jedrzejczyk Steve Lhomme Rocky Bernstein Romain Goyet Rov Juvano Sam Hocevar Martin T. H. Sandsmark Sebastian Birk Sébastien Escudier Vincent Seguin Fabio Ritrovato Sigmund Augdal Helberg Casian Andrei Srikanth Raju Hannes Domani Stéphane Borel Stephan Krempel Stephan Assmus Tony Castley Pavlov Konstantin Eric Petit Tanguy Krotoff Dennis van Amerongen Michel Lespinasse Can Wu Xavier Marchesini Sébastien Toque Christophe Mutricy Yoann Peronneau Yohann Martineau Yuval Tze Scott Caudle Clément Stenac It is possible, that some minor piece of code was badly tracked, for some reasons (SVN, mainly) or that some small developers did not answer. However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3", and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and the very vast majority of developers have agreed (> 99.99% of the code, > 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
2005-12-05 10:36:39 +01:00
*
LGPL Re-license almost all of libVLC and libVLCcore to LGPLv2.1+ This move was authorized by the developers, either: - by e-mail, - by vote at the VideoLAN Dev Days 2011, - on the license website, - in a contract, oral or written. No objection was raised, so far. The developers agreeing are: Justus Piater Alexis Ballier Alexander Bethke Mohammed Adnène Trojette Alex Converse Alexey Sokolov Alexis de Lattre Andre Pang Anthony Loiseau Cyril Deguet André Weber Boris Dorès Brieuc Jeunhomme Benjamin Drung Hugo Beauzée-Luyssen Benoit Steiner Benjamin Pracht Bernie Purcell Przemyslaw Fiala Arnaud de Bossoreille de Ribou Brad Smith Nick Briggs Christopher Rath Christophe Courtaut Christopher Mueller Clement Chesnin Andres Krapf Damien Fouilleul David Flynn Sebastien Zwickert Antoine Cellerier Jérôme Decoodt Jérome Decoodt Dylan Yudaken Eduard Babayan Eugenio Jarosiewicz Elliot Murphy Eric Petit Erwan Tulou Etienne Membrives Ludovic Fauvet Fabio Ritrovato Tobias Güntner Jakub Wieczorek Frédéric Crozat Francois Cartegnie Laurent Aimar Florian G. Pflug Felix Paul Kühne Frank Enderle Rafaël Carré Simon Latapie Gildas Bazin Geoffroy Couprie Julien / Gellule Gildas Bazin Arnaud Schauly Toralf Niebuhr Vicente Jimenez Aguilar Derk-Jan Hartman Henri Fallon Ilkka Ollakka Olivier Teulière Rémi Duraffort Jakob Leben Jean-Baptiste Kempf Jean-Paul Saman Jean-Philippe Grimaldi Jean-François Massol Gaël Hendryckx Jakob Leben Jean-Marc Dressler Jai Menon Johan Bilien Johann Ransay Joris van Rooij JP Dinger Jean-Philippe André Adrien Grand Juha Jeronen Juho Vähä-Herttua Kaarlo Raiha Kaarlo Raiha Kamil Baldyga Keary Griffin Ken Self KO Myung-Hun Pierre Ynard Filippo Carone Loïc Minier Luca Barbato Lucas C. Villa Real Lukas Durfina Adrien Maglo Marc Ariberti Mark Lee Mark Moriarty Martin Storsjö Christophe Massiot Michel Kaempf Marian Ďurkovič Mirsal Ennaime Carlo Calabrò Damien Lucas Naohiro Koriyama Basos G Pierre Baillet Vincent Penquerc'h Olivier Aubert Pankaj Yadav Paul Corke Pierre d'Herbemont Philippe Morin Antoine Lejeune Michael Ploujnikov Jean-Marc Dressler Michael Hanselmann Rafaël Carré Ramiro Polla Rémi Denis-Courmont Renaud Dartus Richard Shepherd Faustino Osuna Arnaud Vallat Rob Jonson Robert Jedrzejczyk Steve Lhomme Rocky Bernstein Romain Goyet Rov Juvano Sam Hocevar Martin T. H. Sandsmark Sebastian Birk Sébastien Escudier Vincent Seguin Fabio Ritrovato Sigmund Augdal Helberg Casian Andrei Srikanth Raju Hannes Domani Stéphane Borel Stephan Krempel Stephan Assmus Tony Castley Pavlov Konstantin Eric Petit Tanguy Krotoff Dennis van Amerongen Michel Lespinasse Can Wu Xavier Marchesini Sébastien Toque Christophe Mutricy Yoann Peronneau Yohann Martineau Yuval Tze Scott Caudle Clément Stenac It is possible, that some minor piece of code was badly tracked, for some reasons (SVN, mainly) or that some small developers did not answer. However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3", and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and the very vast majority of developers have agreed (> 99.99% of the code, > 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
2005-12-05 10:36:39 +01:00
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
2005-12-05 10:36:39 +01:00
#include <errno.h>
#include <assert.h>
2005-12-05 10:36:39 +01:00
#include <vlc_network.h>
2005-12-05 10:36:39 +01:00
#ifdef _WIN32
# undef EAFNOSUPPORT
2005-12-05 17:46:49 +01:00
# define EAFNOSUPPORT WSAEAFNOSUPPORT
# include <wincrypt.h>
# include <iphlpapi.h>
#else
# include <unistd.h>
2006-02-12 17:36:41 +01:00
# ifdef HAVE_NET_IF_H
# include <net/if.h>
# endif
2005-12-05 10:36:39 +01:00
#endif
2005-12-05 11:00:14 +01:00
2007-09-19 16:51:44 +02:00
#ifdef HAVE_LINUX_DCCP_H
# include <linux/dccp.h>
# ifndef SOCK_DCCP /* provisional API */
# define SOCK_DCCP 6
# endif
#endif
2005-12-05 11:00:14 +01:00
#ifndef SOL_IP
# define SOL_IP IPPROTO_IP
#endif
#ifndef SOL_IPV6
# define SOL_IPV6 IPPROTO_IPV6
#endif
#ifndef IPPROTO_IPV6
# define IPPROTO_IPV6 41 /* IANA */
#endif
#ifndef SOL_DCCP
# define SOL_DCCP IPPROTO_DCCP
#endif
#ifndef IPPROTO_DCCP
# define IPPROTO_DCCP 33 /* IANA */
#endif
#ifndef SOL_UDPLITE
# define SOL_UDPLITE IPPROTO_UDPLITE
#endif
#ifndef IPPROTO_UDPLITE
# define IPPROTO_UDPLITE 136 /* IANA */
#endif
#if defined (HAVE_NETINET_UDPLITE_H)
# include <netinet/udplite.h>
#elif defined (__linux__)
/* still missing from glibc 2.6 */
# define UDPLITE_SEND_CSCOV 10
# define UDPLITE_RECV_CSCOV 11
2005-12-05 10:36:39 +01:00
#endif
/* */
static int net_SetupDgramSocket (vlc_object_t *p_obj, int fd,
const struct addrinfo *ptr)
{
#ifdef SO_REUSEPORT
setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int));
#endif
#if defined (_WIN32)
/* Check windows version so we know if we need to increase receive buffers
* for Windows 7 and earlier
* SetSocketMediaStreamingMode is present in win 8 and later, so we set
* receive buffer if that isn't present
*/
#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
HINSTANCE h_Network = LoadLibrary(TEXT("Windows.Networking.dll"));
if( (h_Network == NULL) ||
(GetProcAddress( h_Network, "SetSocketMediaStreamingMode" ) == NULL ) )
{
setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
(void *)&(int){ 0x80000 }, sizeof (int));
}
if( h_Network )
FreeLibrary( h_Network );
#endif
if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
&& (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
{
// This works for IPv4 too - don't worry!
struct sockaddr_in6 dumb =
{
.sin6_family = ptr->ai_addr->sa_family,
.sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
};
bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
}
else
#endif
if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
{
msg_Err( p_obj, "socket bind error: %s", vlc_strerror_c(net_errno) );
net_Close (fd);
return -1;
}
return fd;
}
2018-11-10 10:43:19 +01:00
static int net_Subscribe(vlc_object_t *obj, int fd,
const struct sockaddr *addr, socklen_t addrlen);
/* */
static int net_ListenSingle (vlc_object_t *obj, const char *host, unsigned port,
int protocol)
{
struct addrinfo hints = {
.ai_socktype = SOCK_DGRAM,
.ai_protocol = protocol,
.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_IDN,
}, *res;
if (host && !*host)
host = NULL;
2018-07-11 15:24:42 +02:00
msg_Dbg (obj, "net: opening %s datagram port %u",
2009-05-17 10:16:03 +02:00
host ? host : "any", port);
int val = vlc_getaddrinfo (host, port, &hints, &res);
if (val)
{
2018-07-11 15:24:42 +02:00
msg_Err (obj, "Cannot resolve %s port %u : %s", host, port,
gai_strerror (val));
return -1;
}
val = -1;
for (const struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
{
int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (fd == -1)
{
msg_Dbg (obj, "socket error: %s", vlc_strerror_c(net_errno));
continue;
}
#ifdef IPV6_V6ONLY
/* Try dual-mode IPv6 if available. */
if (ptr->ai_family == AF_INET6)
setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &(int){ 0 }, sizeof (int));
#endif
fd = net_SetupDgramSocket( obj, fd, ptr );
if( fd == -1 )
continue;
if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
&& net_Subscribe (obj, fd, ptr->ai_addr, ptr->ai_addrlen))
{
net_Close (fd);
continue;
}
val = fd;
break;
}
2010-04-28 22:50:08 +02:00
freeaddrinfo (res);
return val;
}
2005-12-05 11:00:14 +01:00
2005-12-05 17:46:49 +01:00
static int net_SetMcastHopLimit( vlc_object_t *p_this,
int fd, int family, int hlim )
2005-12-05 11:00:14 +01:00
{
int proto, cmd;
2007-09-10 20:56:52 +02:00
/* There is some confusion in the world whether IP_MULTICAST_TTL
2005-12-05 11:00:14 +01:00
* takes a byte or an int as an argument.
* BSD seems to indicate byte so we are going with that and use
* int as a fallback to be safe */
switch( family )
{
2006-11-24 17:35:23 +01:00
#ifdef IP_MULTICAST_TTL
2005-12-05 11:00:14 +01:00
case AF_INET:
proto = SOL_IP;
cmd = IP_MULTICAST_TTL;
break;
2006-11-24 17:35:23 +01:00
#endif
2005-12-05 11:00:14 +01:00
#ifdef IPV6_MULTICAST_HOPS
case AF_INET6:
proto = SOL_IPV6;
cmd = IPV6_MULTICAST_HOPS;
break;
#endif
default:
errno = EAFNOSUPPORT;
msg_Warn( p_this, "%s", vlc_strerror_c(EAFNOSUPPORT) );
2005-12-05 17:46:49 +01:00
return VLC_EGENERIC;
2005-12-05 11:00:14 +01:00
}
if( setsockopt( fd, proto, cmd, &hlim, sizeof( hlim ) ) < 0 )
{
/* BSD compatibility */
unsigned char buf;
msg_Dbg( p_this, "cannot set hop limit (%d): %s", hlim,
vlc_strerror_c(net_errno) );
2005-12-05 11:00:14 +01:00
buf = (unsigned char)(( hlim > 255 ) ? 255 : hlim);
2005-12-05 17:46:49 +01:00
if( setsockopt( fd, proto, cmd, &buf, sizeof( buf ) ) )
2010-04-11 21:42:11 +02:00
{
msg_Err( p_this, "cannot set hop limit (%d): %s", hlim,
vlc_strerror_c(net_errno) );
2005-12-05 17:46:49 +01:00
return VLC_EGENERIC;
2010-04-11 21:42:11 +02:00
}
2005-12-05 11:00:14 +01:00
}
2006-11-24 17:35:23 +01:00
2005-12-05 17:46:49 +01:00
return VLC_SUCCESS;
2005-12-05 11:00:14 +01:00
}
static int net_SetMcastOut (vlc_object_t *p_this, int fd, int family,
const char *iface)
2005-12-05 17:46:49 +01:00
{
int scope = if_nametoindex (iface);
if (scope == 0)
{
msg_Err (p_this, "invalid multicast interface: %s", iface);
return -1;
}
switch (family)
2005-12-05 17:46:49 +01:00
{
#ifdef IPV6_MULTICAST_IF
case AF_INET6:
if (setsockopt (fd, SOL_IPV6, IPV6_MULTICAST_IF,
&scope, sizeof (scope)) == 0)
return 0;
2013-08-09 17:41:52 +02:00
break;
#endif
#ifdef __linux__
2005-12-05 17:46:49 +01:00
case AF_INET:
{
struct ip_mreqn req = { .imr_ifindex = scope };
if (setsockopt (fd, SOL_IP, IP_MULTICAST_IF,
&req, sizeof (req)) == 0)
return 0;
2013-08-09 17:41:52 +02:00
break;
}
#endif
default:
errno = EAFNOSUPPORT;
2005-12-05 17:46:49 +01:00
}
msg_Err (p_this, "cannot force multicast interface %s: %s", iface,
vlc_strerror_c(errno));
return -1;
2005-12-05 17:46:49 +01:00
}
2019-04-14 08:53:18 +02:00
#ifdef MCAST_JOIN_GROUP
static unsigned var_GetIfIndex (vlc_object_t *obj)
{
char *ifname = var_InheritString (obj, "miface");
if (ifname == NULL)
return 0;
unsigned ifindex = if_nametoindex (ifname);
if (ifindex == 0)
msg_Err (obj, "invalid multicast interface: %s", ifname);
free (ifname);
return ifindex;
}
2019-04-14 08:53:18 +02:00
#endif
2006-11-05 20:20:52 +01:00
/**
* IP-agnostic multicast join,
* with fallback to old APIs, and fallback from SSM to ASM.
*/
static int
net_SourceSubscribe (vlc_object_t *obj, int fd,
const struct sockaddr *src, socklen_t srclen,
const struct sockaddr *grp, socklen_t grplen)
{
/* MCAST_JOIN_SOURCE_GROUP was introduced to OS X in v10.7, but it doesn't work,
* so ignore it to use the same code path as on 10.5 or 10.6 */
#if defined (MCAST_JOIN_SOURCE_GROUP) && !defined (__APPLE__)
2016-10-27 22:57:12 +02:00
/* Family-agnostic Source-Specific Multicast join */
int level;
struct group_source_req gsr;
memset (&gsr, 0, sizeof (gsr));
gsr.gsr_interface = var_GetIfIndex (obj);
2006-11-05 20:20:52 +01:00
switch (grp->sa_family)
{
2006-11-24 21:33:26 +01:00
#ifdef AF_INET6
2006-11-05 20:20:52 +01:00
case AF_INET6:
{
const struct sockaddr_in6 *g6 = (const struct sockaddr_in6 *)grp;
level = SOL_IPV6;
assert(grplen >= (socklen_t)sizeof (struct sockaddr_in6));
if (g6->sin6_scope_id != 0)
gsr.gsr_interface = g6->sin6_scope_id;
break;
}
2006-11-24 21:33:26 +01:00
#endif
case AF_INET:
level = SOL_IP;
break;
default:
errno = EAFNOSUPPORT;
return -1;
}
assert(grplen <= (socklen_t)sizeof (gsr.gsr_group));
memcpy (&gsr.gsr_source, src, srclen);
assert(srclen <= (socklen_t)sizeof (gsr.gsr_source));
memcpy (&gsr.gsr_group, grp, grplen);
if (setsockopt (fd, level, MCAST_JOIN_SOURCE_GROUP,
&gsr, sizeof (gsr)) == 0)
return 0;
#else
if (src->sa_family != grp->sa_family)
2006-11-24 21:33:26 +01:00
{
errno = EAFNOSUPPORT;
return -1;
}
2006-11-24 21:33:26 +01:00
switch (grp->sa_family)
{
# ifdef IP_ADD_SOURCE_MEMBERSHIP
/* IPv4-specific API */
case AF_INET:
{
struct ip_mreq_source imr;
memset (&imr, 0, sizeof (imr));
assert(grplen >= (socklen_t)sizeof (struct sockaddr_in));
imr.imr_multiaddr = ((const struct sockaddr_in *)grp)->sin_addr;
assert(srclen >= (socklen_t)sizeof (struct sockaddr_in));
imr.imr_sourceaddr = ((const struct sockaddr_in *)src)->sin_addr;
if (setsockopt (fd, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP,
&imr, sizeof (imr)) == 0)
return 0;
break;
}
# endif
default:
errno = EAFNOSUPPORT;
}
#endif
msg_Err (obj, "cannot join source multicast group: %s",
vlc_strerror_c(net_errno));
msg_Warn (obj, "trying ASM instead of SSM...");
return net_Subscribe (obj, fd, grp, grplen);
}
2018-11-10 10:43:19 +01:00
static int net_Subscribe(vlc_object_t *obj, int fd,
const struct sockaddr *grp, socklen_t grplen)
{
/* MCAST_JOIN_GROUP was introduced to OS X in v10.7, but it doesn't work,
* so ignore it to use the same code as on 10.5 or 10.6 */
#if defined (MCAST_JOIN_GROUP) && !defined (__APPLE__)
2016-10-27 22:57:12 +02:00
/* Family-agnostic Any-Source Multicast join */
int level;
struct group_req gr;
memset (&gr, 0, sizeof (gr));
gr.gr_interface = var_GetIfIndex (obj);
switch (grp->sa_family)
{
#ifdef AF_INET6
case AF_INET6:
{
const struct sockaddr_in6 *g6 = (const struct sockaddr_in6 *)grp;
level = SOL_IPV6;
assert(grplen >= (socklen_t)sizeof (struct sockaddr_in6));
if (g6->sin6_scope_id != 0)
gr.gr_interface = g6->sin6_scope_id;
break;
}
2006-11-05 20:20:52 +01:00
#endif
case AF_INET:
level = SOL_IP;
break;
default:
errno = EAFNOSUPPORT;
return -1;
2006-11-05 20:20:52 +01:00
}
assert(grplen <= (socklen_t)sizeof (gr.gr_group));
memcpy (&gr.gr_group, grp, grplen);
if (setsockopt (fd, level, MCAST_JOIN_GROUP, &gr, sizeof (gr)) == 0)
return 0;
#else
switch (grp->sa_family)
{
# ifdef IPV6_JOIN_GROUP
case AF_INET6:
{
struct ipv6_mreq ipv6mr;
const struct sockaddr_in6 *g6 = (const struct sockaddr_in6 *)grp;
memset (&ipv6mr, 0, sizeof (ipv6mr));
assert(grplen >= (socklen_t)sizeof (struct sockaddr_in6));
ipv6mr.ipv6mr_multiaddr = g6->sin6_addr;
ipv6mr.ipv6mr_interface = g6->sin6_scope_id;
if (!setsockopt (fd, SOL_IPV6, IPV6_JOIN_GROUP,
&ipv6mr, sizeof (ipv6mr)))
return 0;
break;
}
# endif
# ifdef IP_ADD_MEMBERSHIP
case AF_INET:
{
struct ip_mreq imr;
memset (&imr, 0, sizeof (imr));
assert(grplen >= (socklen_t)sizeof (struct sockaddr_in));
imr.imr_multiaddr = ((const struct sockaddr_in *)grp)->sin_addr;
if (setsockopt (fd, SOL_IP, IP_ADD_MEMBERSHIP,
&imr, sizeof (imr)) == 0)
return 0;
break;
}
# endif
default:
errno = EAFNOSUPPORT;
}
#endif
msg_Err (obj, "cannot join multicast group: %s",
vlc_strerror_c(net_errno));
2006-11-05 20:20:52 +01:00
return -1;
}
2007-08-16 22:05:06 +02:00
static int net_SetDSCP( int fd, uint8_t dscp )
{
struct sockaddr_storage addr;
if( getsockname( fd, (struct sockaddr *)&addr, &(socklen_t){ sizeof (addr) }) )
return -1;
int level, cmd;
switch( addr.ss_family )
{
#ifdef IPV6_TCLASS
case AF_INET6:
level = SOL_IPV6;
cmd = IPV6_TCLASS;
break;
#endif
case AF_INET:
level = SOL_IP;
cmd = IP_TOS;
break;
default:
#ifdef ENOPROTOOPT
errno = ENOPROTOOPT;
#endif
return -1;
}
return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int));
}
2010-02-07 11:51:50 +01:00
#undef net_ConnectDgram
2005-12-05 10:36:39 +01:00
/*****************************************************************************
2010-02-07 11:51:50 +01:00
* net_ConnectDgram:
2005-12-05 10:36:39 +01:00
*****************************************************************************
2007-02-05 18:21:56 +01:00
* Open a datagram socket to send data to a defined destination, with an
* optional hop limit.
2005-12-05 10:36:39 +01:00
*****************************************************************************/
int net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, unsigned i_port,
2010-02-07 11:51:50 +01:00
int i_hlim, int proto )
2005-12-05 10:36:39 +01:00
{
struct addrinfo hints = {
.ai_socktype = SOCK_DGRAM,
.ai_protocol = proto,
.ai_flags = AI_NUMERICSERV | AI_IDN,
}, *res;
int i_handle = -1;
bool b_unreach = false;
2005-12-05 10:36:39 +01:00
if( i_hlim < 0 )
2010-11-10 17:41:38 +01:00
i_hlim = var_InheritInteger( p_this, "ttl" );
2005-12-05 11:00:14 +01:00
2018-07-11 15:24:42 +02:00
msg_Dbg( p_this, "net: connecting to [%s]:%u", psz_host, i_port );
2005-12-05 10:36:39 +01:00
int val = vlc_getaddrinfo (psz_host, i_port, &hints, &res);
if (val)
2005-12-05 10:36:39 +01:00
{
2018-07-11 15:24:42 +02:00
msg_Err (p_this, "cannot resolve [%s]:%u : %s", psz_host, i_port,
gai_strerror (val));
2005-12-05 10:36:39 +01:00
return -1;
}
for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
2005-12-05 10:36:39 +01:00
{
char *str;
int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (fd == -1)
2005-12-05 10:36:39 +01:00
continue;
/* Allow broadcast sending */
setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int));
2005-12-05 10:36:39 +01:00
if( i_hlim >= 0 )
net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim );
2010-11-10 17:41:38 +01:00
str = var_InheritString (p_this, "miface");
if (str != NULL)
{
net_SetMcastOut (p_this, fd, ptr->ai_family, str);
free (str);
2005-12-05 17:46:49 +01:00
}
2005-12-05 11:00:14 +01:00
2010-11-10 17:41:38 +01:00
net_SetDSCP (fd, var_InheritInteger (p_this, "dscp"));
2005-12-05 10:36:39 +01:00
if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
{
/* success */
i_handle = fd;
break;
}
#if defined( _WIN32 )
2005-12-05 10:36:39 +01:00
if( WSAGetLastError () == WSAENETUNREACH )
#else
if( errno == ENETUNREACH )
#endif
b_unreach = true;
2005-12-05 10:36:39 +01:00
else
2018-07-11 15:24:42 +02:00
msg_Warn( p_this, "%s port %u : %s", psz_host, i_port,
vlc_strerror_c(errno) );
2013-07-19 21:24:50 +02:00
net_Close( fd );
2005-12-05 10:36:39 +01:00
}
2010-04-28 22:50:08 +02:00
freeaddrinfo( res );
2005-12-05 10:36:39 +01:00
if( i_handle == -1 )
{
if( b_unreach )
2018-07-11 15:24:42 +02:00
msg_Err( p_this, "Host %s port %u is unreachable", psz_host,
2005-12-05 10:36:39 +01:00
i_port );
return -1;
}
return i_handle;
}
2010-02-07 11:51:50 +01:00
#undef net_OpenDgram
2005-12-05 10:36:39 +01:00
/*****************************************************************************
2010-02-07 11:51:50 +01:00
* net_OpenDgram:
2005-12-05 10:36:39 +01:00
*****************************************************************************
* OpenDgram a datagram socket and return a handle
2005-12-05 10:36:39 +01:00
*****************************************************************************/
int net_OpenDgram( vlc_object_t *obj, const char *psz_bind, unsigned i_bind,
const char *psz_server, unsigned i_server, int protocol )
2005-12-05 10:36:39 +01:00
{
if ((psz_server == NULL) || (psz_server[0] == '\0'))
return net_ListenSingle (obj, psz_bind, i_bind, protocol);
2018-07-11 15:24:42 +02:00
msg_Dbg (obj, "net: connecting to [%s]:%u from [%s]:%u",
psz_server, i_server, psz_bind, i_bind);
struct addrinfo hints = {
.ai_socktype = SOCK_DGRAM,
.ai_protocol = protocol,
.ai_flags = AI_NUMERICSERV | AI_IDN,
}, *loc, *rem;
2005-12-05 10:36:39 +01:00
int val = vlc_getaddrinfo (psz_server, i_server, &hints, &rem);
if (val)
{
2018-07-11 15:24:42 +02:00
msg_Err (obj, "cannot resolve %s port %u : %s", psz_server, i_server,
gai_strerror (val));
return -1;
}
2005-12-05 10:36:39 +01:00
hints.ai_flags |= AI_PASSIVE;
val = vlc_getaddrinfo (psz_bind, i_bind, &hints, &loc);
if (val)
{
2018-07-11 15:24:42 +02:00
msg_Err (obj, "cannot resolve %s port %u : %s", psz_bind, i_bind,
gai_strerror (val));
2010-04-28 22:50:08 +02:00
freeaddrinfo (rem);
return -1;
}
val = -1;
for (struct addrinfo *ptr = loc; ptr != NULL; ptr = ptr->ai_next)
{
int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (fd == -1)
continue; // usually, address family not supported
2005-12-05 10:36:39 +01:00
fd = net_SetupDgramSocket( obj, fd, ptr );
if( fd == -1 )
continue;
2005-12-05 10:36:39 +01:00
for (struct addrinfo *ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next)
{
if ((ptr2->ai_family != ptr->ai_family)
|| (ptr2->ai_socktype != ptr->ai_socktype)
|| (ptr2->ai_protocol != ptr->ai_protocol))
continue;
2005-12-05 10:36:39 +01:00
if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
? net_SourceSubscribe (obj, fd,
ptr2->ai_addr, ptr2->ai_addrlen,
ptr->ai_addr, ptr->ai_addrlen)
: connect (fd, ptr2->ai_addr, ptr2->ai_addrlen))
{
2018-07-11 15:24:42 +02:00
msg_Err (obj, "cannot connect to %s port %u: %s",
psz_server, i_server, vlc_strerror_c(net_errno));
continue;
}
val = fd;
break;
}
2005-12-05 10:36:39 +01:00
if (val != -1)
break;
2005-12-05 10:36:39 +01:00
2008-09-13 21:20:13 +02:00
net_Close (fd);
2005-12-05 10:36:39 +01:00
}
2010-04-28 22:50:08 +02:00
freeaddrinfo (rem);
freeaddrinfo (loc);
return val;
2005-12-05 10:36:39 +01:00
}
/**
* net_SetCSCov:
* Sets the send and receive checksum coverage of a socket:
* @param fd socket
* @param sendcov payload coverage of sent packets (bytes), -1 for full
* @param recvcov minimum payload coverage of received packets, -1 for full
*/
int net_SetCSCov (int fd, int sendcov, int recvcov)
{
int type;
if (getsockopt (fd, SOL_SOCKET, SO_TYPE,
&type, &(socklen_t){ sizeof (type) }))
return VLC_EGENERIC;
switch (type)
{
#ifdef UDPLITE_RECV_CSCOV
case SOCK_DGRAM: /* UDP-Lite */
if (sendcov == -1)
sendcov = 0;
else
sendcov += 8; /* partial */
if (setsockopt (fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &sendcov,
sizeof (sendcov)))
return VLC_EGENERIC;
if (recvcov == -1)
recvcov = 0;
else
recvcov += 8;
if (setsockopt (fd, SOL_UDPLITE, UDPLITE_RECV_CSCOV,
&recvcov, sizeof (recvcov)))
return VLC_EGENERIC;
return VLC_SUCCESS;
#endif
#ifdef DCCP_SOCKOPT_SEND_CSCOV
case SOCK_DCCP: /* DCCP and its ill-named socket type */
if ((sendcov == -1) || (sendcov > 56))
sendcov = 0;
else
sendcov = (sendcov + 3) / 4;
if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV,
&sendcov, sizeof (sendcov)))
return VLC_EGENERIC;
2007-09-09 22:04:14 +02:00
if ((recvcov == -1) || (recvcov > 56))
recvcov = 0;
else
2007-09-09 22:04:14 +02:00
recvcov = (recvcov + 3) / 4;
if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_RECV_CSCOV,
&recvcov, sizeof (recvcov)))
return VLC_EGENERIC;
return VLC_SUCCESS;
#endif
}
2008-01-28 17:40:32 +01:00
#if !defined( UDPLITE_RECV_CSCOV ) && !defined( DCCP_SOCKOPT_SEND_CSCOV )
VLC_UNUSED(sendcov);
VLC_UNUSED(recvcov);
#endif
return VLC_EGENERIC;
}