rtsp: Use getaddrinfo() to support both IPv4 and IPv6.

This commit is contained in:
Peter Kjellerstedt 2009-06-09 14:31:18 +02:00
parent e1a4c8871a
commit 95a606a0bb

View file

@ -76,14 +76,17 @@
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
#include <winsock2.h> #include <winsock2.h>
/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
* minwg32 headers check WINVER before allowing the use of these */
#ifndef WINVER
#define WINVER 0x0501
#endif
#include <ws2tcpip.h> #include <ws2tcpip.h>
#define EINPROGRESS WSAEINPROGRESS #define EINPROGRESS WSAEINPROGRESS
#else #else
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <netdb.h> #include <netdb.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h> #include <fcntl.h>
#endif #endif
@ -95,6 +98,14 @@
#include "gstrtspbase64.h" #include "gstrtspbase64.h"
#include "md5.h" #include "md5.h"
union gst_sockaddr
{
struct sockaddr sa;
struct sockaddr_in sa_in;
struct sockaddr_in6 sa_in6;
struct sockaddr_storage sa_stor;
};
typedef struct typedef struct
{ {
gint state; gint state;
@ -195,22 +206,6 @@ struct _GstRTSPConnection
guint proxy_port; guint proxy_port;
}; };
#ifdef G_OS_WIN32
static int
inet_aton (const char *c, struct in_addr *paddr)
{
/* note that inet_addr is deprecated on unix because
* inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
* address. */
paddr->s_addr = inet_addr (c);
if (paddr->s_addr == INADDR_NONE)
return 0;
return 1;
}
#endif
enum enum
{ {
STATE_START = 0, STATE_START = 0,
@ -336,25 +331,30 @@ GstRTSPResult
gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn) gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn)
{ {
int fd; int fd;
unsigned int address_len;
GstRTSPConnection *newconn = NULL; GstRTSPConnection *newconn = NULL;
struct sockaddr_in address; union gst_sockaddr sa;
socklen_t slen = sizeof (sa);
gchar ip[INET6_ADDRSTRLEN];
GstRTSPUrl *url; GstRTSPUrl *url;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
gulong flags = 1; gulong flags = 1;
#endif #endif
address_len = sizeof (address); memset (&sa, 0, slen);
memset (&address, 0, address_len);
#ifndef G_OS_WIN32 #ifndef G_OS_WIN32
fd = accept (sock, (struct sockaddr *) &address, &address_len); fd = accept (sock, &sa.sa, &slen);
#else #else
fd = accept (sock, (struct sockaddr *) &address, (gint *) & address_len); fd = accept (sock, &sa.sa, (gint *) & slen);
#endif /* G_OS_WIN32 */ #endif /* G_OS_WIN32 */
if (fd == -1) if (fd == -1)
goto accept_failed; goto accept_failed;
if (getnameinfo (&sa.sa, slen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0)
goto getnameinfo_failed;
if (sa.sa.sa_family != AF_INET && sa.sa.sa_family != AF_INET6)
goto wrong_family;
/* set to non-blocking mode so that we can cancel the communication */ /* set to non-blocking mode so that we can cancel the communication */
#ifndef G_OS_WIN32 #ifndef G_OS_WIN32
fcntl (fd, F_SETFL, O_NONBLOCK); fcntl (fd, F_SETFL, O_NONBLOCK);
@ -364,8 +364,11 @@ gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn)
/* create a url for the client address */ /* create a url for the client address */
url = g_new0 (GstRTSPUrl, 1); url = g_new0 (GstRTSPUrl, 1);
url->host = g_strdup_printf ("%s", inet_ntoa (address.sin_addr)); url->host = g_strdup (ip);
url->port = address.sin_port; if (sa.sa.sa_family == AF_INET)
url->port = sa.sa_in.sin_port;
else
url->port = sa.sa_in6.sin6_port;
/* now create the connection object */ /* now create the connection object */
gst_rtsp_connection_create (url, &newconn); gst_rtsp_connection_create (url, &newconn);
@ -386,54 +389,59 @@ accept_failed:
{ {
return GST_RTSP_ESYS; return GST_RTSP_ESYS;
} }
getnameinfo_failed:
wrong_family:
{
close (fd);
return GST_RTSP_ERROR;
}
} }
static gchar * static gchar *
do_resolve (const gchar * host) do_resolve (const gchar * host)
{ {
struct hostent *hostinfo; static gchar ip[INET6_ADDRSTRLEN];
struct in_addr addr; struct addrinfo *aires;
const gchar *ip; struct addrinfo *ai;
#ifdef G_OS_WIN32 gint aierr;
struct in_addr *addrp;
#else
char **addrs;
gchar ipbuf[INET_ADDRSTRLEN];
#endif /* G_OS_WIN32 */
ip = NULL; aierr = getaddrinfo (host, NULL, NULL, &aires);
if (aierr != 0)
goto no_addrinfo;
/* first check if it already is an IP address */ for (ai = aires; ai; ai = ai->ai_next) {
if (inet_aton (host, &addr)) { if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
ip = host; break;
} else { }
hostinfo = gethostbyname (host);
if (!hostinfo)
goto not_resolved; /* h_errno set */
if (hostinfo->h_addrtype != AF_INET)
goto not_ip; /* host not an IP host */
#ifdef G_OS_WIN32
addrp = (struct in_addr *) hostinfo->h_addr_list[0];
/* this is not threadsafe */
ip = inet_ntoa (*addrp);
#else
addrs = hostinfo->h_addr_list;
ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
sizeof (ipbuf));
#endif /* G_OS_WIN32 */
} }
if (ai == NULL)
goto no_family;
aierr = getnameinfo (ai->ai_addr, ai->ai_addrlen, ip, sizeof (ip), NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV);
if (aierr != 0)
goto no_address;
freeaddrinfo (aires);
return g_strdup (ip); return g_strdup (ip);
/* ERRORS */ /* ERRORS */
not_resolved: no_addrinfo:
{ {
GST_ERROR ("could not resolve %s", host); GST_ERROR ("no addrinfo found for %s: %s", host, gai_strerror (aierr));
return NULL; return NULL;
} }
not_ip: no_family:
{ {
GST_ERROR ("not an IP address"); GST_ERROR ("no family found for %s", host);
freeaddrinfo (aires);
return NULL;
}
no_address:
{
GST_ERROR ("no address found for %s: %s", host, gai_strerror (aierr));
freeaddrinfo (aires);
return NULL; return NULL;
} }
} }
@ -443,7 +451,11 @@ do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
GstPoll * fdset, GTimeVal * timeout) GstPoll * fdset, GTimeVal * timeout)
{ {
gint fd; gint fd;
struct sockaddr_in sa_in; struct addrinfo hints;
struct addrinfo *aires;
struct addrinfo *ai;
gint aierr;
gchar service[NI_MAXSERV];
gint ret; gint ret;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
unsigned long flags = 1; unsigned long flags = 1;
@ -451,12 +463,26 @@ do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
GstClockTime to; GstClockTime to;
gint retval; gint retval;
memset (&sa_in, 0, sizeof (sa_in)); memset (&hints, 0, sizeof hints);
sa_in.sin_family = AF_INET; /* network socket */ hints.ai_flags = AI_NUMERICHOST;
sa_in.sin_port = htons (port); /* on port */ hints.ai_family = AF_UNSPEC;
sa_in.sin_addr.s_addr = inet_addr (ip); /* on host ip */ hints.ai_socktype = SOCK_STREAM;
g_snprintf (service, sizeof (service) - 1, "%hu", port);
service[sizeof (service) - 1] = '\0';
fd = socket (AF_INET, SOCK_STREAM, 0); aierr = getaddrinfo (ip, service, &hints, &aires);
if (aierr != 0)
goto no_addrinfo;
for (ai = aires; ai; ai = ai->ai_next) {
if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
break;
}
}
if (ai == NULL)
goto no_family;
fd = socket (ai->ai_family, SOCK_STREAM, 0);
if (fd == -1) if (fd == -1)
goto no_socket; goto no_socket;
@ -471,7 +497,7 @@ do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
ADD_POLLFD (fdset, fdout, fd); ADD_POLLFD (fdset, fdout, fd);
/* we are going to connect ASYNC now */ /* we are going to connect ASYNC now */
ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in)); ret = connect (fd, ai->ai_addr, ai->ai_addrlen);
if (ret == 0) if (ret == 0)
goto done; goto done;
if (!ERRNO_IS_EINPROGRESS) if (!ERRNO_IS_EINPROGRESS)
@ -504,26 +530,42 @@ do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
} }
gst_poll_fd_ignored (fdset, fdout); gst_poll_fd_ignored (fdset, fdout);
done: done:
freeaddrinfo (aires);
return GST_RTSP_OK; return GST_RTSP_OK;
/* ERRORS */ /* ERRORS */
no_addrinfo:
{
GST_ERROR ("no addrinfo found for %s: %s", ip, gai_strerror (aierr));
return GST_RTSP_ERROR;
}
no_family:
{
GST_ERROR ("no family found for %s", ip);
freeaddrinfo (aires);
return GST_RTSP_ERROR;
}
no_socket: no_socket:
{ {
GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno)); GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno));
freeaddrinfo (aires);
return GST_RTSP_ESYS; return GST_RTSP_ESYS;
} }
sys_error: sys_error:
{ {
GST_ERROR ("system error %d (%s)", errno, g_strerror (errno)); GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
REMOVE_POLLFD (fdset, fdout); REMOVE_POLLFD (fdset, fdout);
freeaddrinfo (aires);
return GST_RTSP_ESYS; return GST_RTSP_ESYS;
} }
timeout: timeout:
{ {
GST_ERROR ("timeout"); GST_ERROR ("timeout");
REMOVE_POLLFD (fdset, fdout); REMOVE_POLLFD (fdset, fdout);
freeaddrinfo (aires);
return GST_RTSP_ETIMEOUT; return GST_RTSP_ETIMEOUT;
} }
} }
@ -2329,12 +2371,7 @@ gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
static GstRTSPResult static GstRTSPResult
set_qos_dscp (gint fd, guint qos_dscp) set_qos_dscp (gint fd, guint qos_dscp)
{ {
union gst_sockaddr union gst_sockaddr sa;
{
struct sockaddr sa;
struct sockaddr_in6 sa_in6;
struct sockaddr_storage sa_stor;
} sa;
socklen_t slen = sizeof (sa); socklen_t slen = sizeof (sa);
gint af; gint af;
gint tos; gint tos;