Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
b376f505
Commit
b376f505
authored
May 22, 2005
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
vlc_getaddrinfo, vlc_getnameinfo and vlc_gai_strerror replacements
parent
81c348d6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
662 additions
and
0 deletions
+662
-0
Makefile.am
Makefile.am
+1
-0
src/misc/getaddrinfo.c
src/misc/getaddrinfo.c
+661
-0
No files found.
Makefile.am
View file @
b376f505
...
...
@@ -395,6 +395,7 @@ SOURCES_libvlc_common = \
src/misc/variables.c
\
src/misc/error.c
\
src/misc/net.c
\
src/misc/getaddrinfo.c
\
src/misc/vlm.c
\
src/misc/xml.c
\
src/extras/libc.c
\
...
...
src/misc/getaddrinfo.c
0 → 100644
View file @
b376f505
/*****************************************************************************
* getaddrinfo.c: getaddrinfo/getnameinfo replacement functions
*****************************************************************************
* Copyright (C) 2005 VideoLAN
* Copyright (C) 2002-2004 Rémi Denis-Courmont
* $Id$
*
* Author: Rémi Denis-Courmont <rem # videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <vlc/vlc.h>
#include "network.h"
#include <stddef.h>
/* size_t */
#include <string.h>
/* strncpy(), strlen(), memcpy(), memset(), strchr() */
#include <stdlib.h>
/* malloc(), free(), strtoul() */
#include <sys/types.h>
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#include <errno.h>
#if defined (UNDER_CE)
# include <winsock.h>
#elif defined WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
#else
# include <netdb.h>
#endif
#define _NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|\
NI_DGRAM)
# define _AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
#ifndef HAVE_GAI_STRERROR
static
struct
{
int
code
;
const
char
*
msg
;
}
const
__gai_errlist
[]
=
{
{
0
,
"Error 0"
},
{
EAI_BADFLAGS
,
"Invalid flag used"
},
{
EAI_NONAME
,
"Host or service not found"
},
{
EAI_AGAIN
,
"Temporary name service failure"
},
{
EAI_FAIL
,
"Non-recoverable name service failure"
},
{
EAI_NODATA
,
"No data for host name"
},
{
EAI_FAMILY
,
"Unsupported address family"
},
{
EAI_SOCKTYPE
,
"Unsupported socket type"
},
{
EAI_SERVICE
,
"Incompatible service for socket type"
},
{
EAI_ADDRFAMILY
,
"Unavailable address family for host name"
},
{
EAI_MEMORY
,
"Memory allocation failure"
},
{
EAI_SYSTEM
,
"System error"
},
{
0
,
NULL
}
};
static
const
char
*
__gai_unknownerr
=
"Unrecognized error number"
;
/****************************************************************************
* Converts an EAI_* error code into human readable english text.
****************************************************************************/
const
char
*
vlc_gai_strerror
(
int
errnum
)
{
int
i
;
for
(
i
=
0
;
__gai_errlist
[
i
].
msg
!=
NULL
;
i
++
)
if
(
errnum
==
__gai_errlist
[
i
].
code
)
return
__gai_errlist
[
i
].
msg
;
return
__gai_unknownerr
;
}
# undef _EAI_POSITIVE_MAX
#else
/* ifndef HAVE_GAI_STRERROR */
const
char
*
vlc_gai_strerror
(
int
errnum
)
{
return
gai_strerror
(
errnum
);
}
#endif
#if !(defined (HAVE_GETNAMEINFO) && defined (HAVE_GETADDRINFO))
/*
* Converts the current herrno error value into an EAI_* error code.
* That error code is normally returned by getnameinfo() or getaddrinfo().
*/
static
int
gai_error_from_herrno
(
void
)
{
switch
(
h_errno
)
{
case
HOST_NOT_FOUND
:
return
EAI_NONAME
;
case
NO_ADDRESS
:
# if (NO_ADDRESS != NO_DATA)
case
NO_DATA
:
# endif
return
EAI_NODATA
;
case
NO_RECOVERY
:
return
EAI_FAIL
;
case
TRY_AGAIN
:
return
EAI_AGAIN
;
}
return
EAI_SYSTEM
;
}
#endif
/* if !(HAVE_GETNAMEINFO && HAVE_GETADDRINFO) */
#ifndef HAVE_GETNAMEINFO
/*
* getnameinfo() non-thread-safe IPv4-only implementation,
* Address-family-independant address to hostname translation
* (reverse DNS lookup in case of IPv4).
*
* This is meant for use on old IP-enabled systems that are not IPv6-aware,
* and probably do not have getnameinfo(), but have the old gethostbyaddr()
* function.
*
* GNU C library 2.0.x is known to lack this function, even though it defines
* getaddrinfo().
*/
static
int
__getnameinfo
(
const
struct
sockaddr
*
sa
,
socklen_t
salen
,
char
*
host
,
int
hostlen
,
char
*
serv
,
int
servlen
,
int
flags
)
{
if
(((
unsigned
)
salen
<
sizeof
(
struct
sockaddr_in
))
||
(
sa
->
sa_family
!=
AF_INET
))
return
EAI_FAMILY
;
else
if
(
flags
&
(
~
_NI_MASK
))
return
EAI_BADFLAGS
;
else
{
const
struct
sockaddr_in
*
addr
;
addr
=
(
const
struct
sockaddr_in
*
)
sa
;
if
(
host
!=
NULL
)
{
int
solved
=
0
;
/* host name resolution */
if
(
!
(
flags
&
NI_NUMERICHOST
))
{
struct
hostent
*
hent
;
hent
=
gethostbyaddr
((
const
void
*
)
&
addr
->
sin_addr
,
4
,
AF_INET
);
if
(
hent
!=
NULL
)
{
strncpy
(
host
,
hent
->
h_name
,
hostlen
);
host
[
hostlen
-
1
]
=
'\0'
;
/*
* only keep first part of hostname
* if user don't want fully qualified
* domain name
*/
if
(
flags
&
NI_NOFQDN
)
{
char
*
ptr
;
ptr
=
strchr
(
host
,
'.'
);
if
(
ptr
!=
NULL
)
*
ptr
=
0
;
}
solved
=
1
;
}
else
if
(
flags
&
NI_NAMEREQD
)
return
gai_error_from_herrno
();
}
if
(
!
solved
)
{
/* inet_ntoa() can't fail */
strncpy
(
host
,
inet_ntoa
(
addr
->
sin_addr
),
hostlen
);
host
[
hostlen
-
1
]
=
'\0'
;
}
}
if
(
serv
!=
NULL
)
{
struct
servent
*
sent
=
NULL
;
int
solved
=
0
;
/* service name resolution */
if
(
!
(
flags
&
NI_NUMERICSERV
))
{
sent
=
getservbyport
(
addr
->
sin_port
,
(
flags
&
NI_DGRAM
)
?
"udp"
:
"tcp"
);
if
(
sent
!=
NULL
)
{
strncpy
(
serv
,
sent
->
s_name
,
servlen
);
serv
[
servlen
-
1
]
=
0
;
solved
=
1
;
}
}
if
(
sent
==
NULL
)
{
snprintf
(
serv
,
servlen
,
"%u"
,
(
unsigned
int
)
ntohs
(
addr
->
sin_port
));
serv
[
servlen
-
1
]
=
'\0'
;
}
}
}
return
0
;
}
#endif
/* if !HAVE_GETNAMEINFO */
#ifndef HAVE_GETADDRINFO
/*
* This functions must be used to free the memory allocated by getaddrinfo().
*/
static
void
__freeaddrinfo
(
struct
addrinfo
*
res
)
{
if
(
res
!=
NULL
)
{
if
(
res
->
ai_canonname
!=
NULL
)
free
(
res
->
ai_canonname
);
if
(
res
->
ai_addr
!=
NULL
)
free
(
res
->
ai_addr
);
if
(
res
->
ai_next
!=
NULL
)
free
(
res
->
ai_next
);
free
(
res
);
}
}
/*
* Internal function that builds an addrinfo struct.
*/
static
struct
addrinfo
*
makeaddrinfo
(
int
af
,
int
type
,
int
proto
,
const
struct
sockaddr
*
addr
,
size_t
addrlen
,
const
char
*
canonname
)
{
struct
addrinfo
*
res
;
res
=
(
struct
addrinfo
*
)
malloc
(
sizeof
(
struct
addrinfo
));
if
(
res
!=
NULL
)
{
res
->
ai_flags
=
0
;
res
->
ai_family
=
af
;
res
->
ai_socktype
=
type
;
res
->
ai_protocol
=
proto
;
res
->
ai_addrlen
=
addrlen
;
res
->
ai_addr
=
malloc
(
addrlen
);
res
->
ai_canonname
=
NULL
;
res
->
ai_next
=
NULL
;
if
(
res
->
ai_addr
!=
NULL
)
{
memcpy
(
res
->
ai_addr
,
addr
,
addrlen
);
if
(
canonname
!=
NULL
)
{
res
->
ai_canonname
=
strdup
(
canonname
);
if
(
res
->
ai_canonname
!=
NULL
)
return
res
;
/* success ! */
}
else
return
res
;
}
}
/* failsafe */
freeaddrinfo
(
res
);
return
NULL
;
}
static
struct
addrinfo
*
makeipv4info
(
int
type
,
int
proto
,
u_long
ip
,
u_short
port
,
const
char
*
name
)
{
struct
sockaddr_in
addr
;
memset
(
&
addr
,
0
,
sizeof
(
addr
));
addr
.
sin_family
=
AF_INET
;
# ifdef HAVE_SA_LEN
addr
.
sin_len
=
sizeof
(
addr
);
# endif
addr
.
sin_port
=
port
;
addr
.
sin_addr
.
s_addr
=
ip
;
return
makeaddrinfo
(
PF_INET
,
type
,
proto
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
),
name
);
}
/*
* getaddrinfo() non-thread-safe IPv4-only implementation
* Address-family-independant hostname to address resolution.
*
* This is meant for IPv6-unaware systems that do probably not provide
* getaddrinfo(), but still have old function gethostbyname().
*
* Only UDP and TCP over IPv4 are supported here.
*/
static
int
__getaddrinfo
(
const
char
*
node
,
const
char
*
service
,
const
struct
addrinfo
*
hints
,
struct
addrinfo
**
res
)
{
struct
addrinfo
*
info
;
u_long
ip
;
u_short
port
;
int
protocol
=
0
,
flags
=
0
;
const
char
*
name
=
NULL
;
if
(
hints
!=
NULL
)
{
flags
=
hints
->
ai_flags
;
if
(
flags
&
~
_AI_MASK
)
return
EAI_BADFLAGS
;
/* only accept AF_INET and AF_UNSPEC */
if
(
hints
->
ai_family
&&
(
hints
->
ai_family
!=
AF_INET
))
return
EAI_FAMILY
;
/* protocol sanity check */
switch
(
hints
->
ai_socktype
)
{
case
SOCK_STREAM
:
protocol
=
IPPROTO_TCP
;
break
;
case
SOCK_DGRAM
:
protocol
=
IPPROTO_UDP
;
break
;
case
SOCK_RAW
:
case
0
:
break
;
default:
return
EAI_SOCKTYPE
;
}
if
(
hints
->
ai_protocol
&&
protocol
&&
(
protocol
!=
hints
->
ai_protocol
))
return
EAI_SERVICE
;
}
*
res
=
NULL
;
/* default values */
if
(
node
==
NULL
)
{
if
(
flags
&
AI_PASSIVE
)
ip
=
htonl
(
INADDR_ANY
);
else
ip
=
htonl
(
INADDR_LOOPBACK
);
}
else
if
((
ip
=
inet_addr
(
node
))
==
INADDR_NONE
)
{
struct
hostent
*
entry
=
NULL
;
/* hostname resolution */
if
(
!
(
flags
&
AI_NUMERICHOST
))
entry
=
gethostbyname
(
node
);
if
(
entry
==
NULL
)
return
EAI_NONAME
;
if
((
entry
->
h_length
!=
4
)
||
(
entry
->
h_addrtype
!=
AF_INET
))
return
EAI_FAMILY
;
ip
=
*
((
u_long
*
)
entry
->
h_addr
);
if
(
flags
&
AI_CANONNAME
)
name
=
entry
->
h_name
;
}
if
((
flags
&
AI_CANONNAME
)
&&
(
name
==
NULL
))
name
=
node
;
/* service resolution */
if
(
service
==
NULL
)
port
=
0
;
else
{
long
d
;
char
*
end
;
d
=
strtoul
(
service
,
&
end
,
0
);
if
(
end
[
0
]
/* service is not a number */
||
(
d
>
65535
))
{
struct
servent
*
entry
;
const
char
*
protoname
;
switch
(
protocol
)
{
case
IPPROTO_TCP
:
protoname
=
"tcp"
;
break
;
case
IPPROTO_UDP
:
protoname
=
"udp"
;
break
;
default:
protoname
=
NULL
;
}
entry
=
getservbyname
(
service
,
protoname
);
if
(
entry
==
NULL
)
return
EAI_SERVICE
;
port
=
entry
->
s_port
;
}
else
port
=
htons
((
u_short
)
d
);
}
/* building results... */
if
((
!
protocol
)
||
(
protocol
==
IPPROTO_UDP
))
{
info
=
makeipv4info
(
SOCK_DGRAM
,
IPPROTO_UDP
,
ip
,
port
,
name
);
if
(
info
==
NULL
)
{
errno
=
ENOMEM
;
return
EAI_SYSTEM
;
}
if
(
flags
&
AI_PASSIVE
)
info
->
ai_flags
|=
AI_PASSIVE
;
*
res
=
info
;
}
if
((
!
protocol
)
||
(
protocol
==
IPPROTO_TCP
))
{
info
=
makeipv4info
(
SOCK_STREAM
,
IPPROTO_TCP
,
ip
,
port
,
name
);
if
(
info
==
NULL
)
{
errno
=
ENOMEM
;
return
EAI_SYSTEM
;
}
info
->
ai_next
=
*
res
;
if
(
flags
&
AI_PASSIVE
)
info
->
ai_flags
|=
AI_PASSIVE
;
*
res
=
info
;
}
return
0
;
}
#endif
/* if !HAVE_GETADDRINFO */
int
vlc_getnameinfo
(
vlc_object_t
*
p_this
,
const
struct
sockaddr
*
sa
,
int
salen
,
char
*
host
,
int
hostlen
,
char
*
serv
,
int
servlen
,
int
flags
)
{
#ifdef WIN32
/*
* Here is the kind of kludge you need to keep binary compatibility among
* varying OS versions...
*/
typedef
int
(
CALLBACK
*
GETNAMEINFO
)
(
const
struct
sockaddr
*
,
socklen_t
,
char
*
,
DWORD
,
char
*
,
DWORD
,
int
);
HINSTANCE
wship6_module
;
GETNAMEINFO
ws2_getnameinfo
;
wship6_module
=
LoadLibrary
(
"wship6.dll"
);
if
(
wship6_module
!=
NULL
)
{
ws2_getnameinfo
=
(
GETNAMEINFO
)
GetProcAddress
(
wship6_module
,
"getnameinfo"
);
if
(
ws2_getnameinfo
!=
NULL
)
{
int
i_val
;
i_val
=
ws2_getnameinfo
(
sa
,
salen
,
host
,
hostlen
,
serv
,
servlen
,
flags
);
FreeLibrary
(
wship6_module
);
return
i_val
;
}
FreeLibrary
(
wship6_module
);
}
#endif
#if HAVE_GETNAMEINFO
return
getnameinfo
(
sa
,
salen
,
host
,
hostlen
,
serv
,
servlen
,
flags
);
#else
{
vlc_value_t
lock
;
int
i_val
;
/* my getnameinfo implementation is not thread-safe as it uses
* gethostbyaddr and the likes */
var_Create
(
p_this
->
p_libvlc
,
"getnameinfo_mutex"
,
VLC_VAR_MUTEX
);
var_Get
(
p_this
->
p_libvlc
,
"getnameinfo_mutex"
,
&
lock
);
vlc_mutex_lock
(
lock
.
p_address
);
i_val
=
__getnameinfo
(
sa
,
salen
,
host
,
hostlen
,
serv
,
servlen
,
flags
);
vlc_mutex_unlock
(
lock
.
p_address
);
return
i_val
;
}
#endif
}
/* TODO: support for setting sin6_scope_id */
int
vlc_getaddrinfo
(
vlc_object_t
*
p_this
,
const
char
*
node
,
const
char
*
service
,
const
struct
addrinfo
*
p_hints
,
struct
addrinfo
**
res
)
{
struct
addrinfo
hints
;
char
psz_buf
[
NI_MAXHOST
],
*
psz_node
;
/* Check if we have to force ipv4 or ipv6 */
if
(
p_hints
==
NULL
)
memset
(
&
hints
,
0
,
sizeof
(
hints
)
);
else
memcpy
(
&
hints
,
p_hints
,
sizeof
(
hints
)
);
if
(
hints
.
ai_family
==
AF_UNSPEC
)
{
vlc_value_t
val
;
var_Create
(
p_this
,
"ipv4"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_this
,
"ipv4"
,
&
val
);
if
(
val
.
b_bool
)
hints
.
ai_family
=
AF_INET
;
var_Create
(
p_this
,
"ipv6"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_this
,
"ipv6"
,
&
val
);
if
(
val
.
b_bool
)
hints
.
ai_family
=
AF_INET6
;
}
/*
* VLC extensions :
* - accept "" as NULL
* - ignore square brackets
*/
if
(
(
node
==
NULL
)
||
(
node
[
0
]
==
'\0'
)
)
psz_node
=
NULL
;
else
{
strncpy
(
psz_buf
,
node
,
NI_MAXHOST
);
psz_buf
[
NI_MAXHOST
-
1
]
=
'\0'
;
psz_node
=
psz_buf
;
if
(
psz_buf
[
0
]
==
'['
)
{
char
*
ptr
;
ptr
=
strrchr
(
psz_buf
,
']'
);
if
(
(
ptr
!=
NULL
)
&&
(
ptr
[
1
]
==
'\0'
)
)
{
*
ptr
=
'\0'
;
psz_node
++
;
}
}
}
if
(
(
service
!=
NULL
)
&&
(
*
service
==
'\0'
)
)
/* We could put NULL, but you can't have both node and service NULL */
service
=
"0"
;
#ifdef WIN32
typedef
int
(
CALLBACK
*
GETADDRINFO
)
(
const
char
*
,
const
char
*
,
const
struct
addrinfo
*
,
struct
addrinfo
**
);
HINSTANCE
wship6_module
;
GETADDRINFO
ws2_getaddrinfo
;
wship6_module
=
LoadLibrary
(
"wship6.dll"
);
if
(
wship6_module
!=
NULL
)
{
ws2_getaddrinfo
=
(
GETADDRINFO
)
GetProcAddress
(
wship6_module
,
"getaddrinfo"
);
if
(
ws2_getaddrinfo
!=
NULL
)
{
int
i_ret
;
i_ret
=
ws2_getaddrinfo
(
psz_node
,
service
,
&
hints
,
res
);
FreeLibrary
(
wship6_module
);
/* is this wise ? */
return
i_ret
;
}
FreeLibrary
(
wship6_module
);
}
#endif
#if HAVE_GETADDRINFO
return
getaddrinfo
(
psz_node
,
service
,
&
hints
,
res
);
#else
{
int
i_ret
;
vlc_value_t
lock
;
var_Create
(
p_this
->
p_libvlc
,
"getaddrinfo_mutex"
,
VLC_VAR_MUTEX
);
var_Get
(
p_this
->
p_libvlc
,
"getaddrinfo_mutex"
,
&
lock
);
vlc_mutex_lock
(
lock
.
p_address
);
i_ret
=
__getaddrinfo
(
psz_node
,
service
,
&
hints
,
res
);
vlc_mutex_unlock
(
lock
.
p_address
);
return
i_ret
;
}
#endif
}
void
vlc_freeaddrinfo
(
struct
addrinfo
*
infos
)
{
#ifdef WIN32
typedef
void
(
CALLBACK
*
FREEADDRINFO
)
(
struct
addrinfo
*
);
HINSTANCE
wship6_module
;
FREEADDRINFO
ws2_freeaddrinfo
;
wship6_module
=
LoadLibrary
(
"wship6.dll"
);
if
(
wship6_module
!=
NULL
)
{
ws2_freeaddrinfo
=
(
FREEADDRINFO
)
GetProcAddress
(
wship6_module
,
"freeaddrinfo"
);
/*
* NOTE: it is assumed that wship6.dll defines either both
* getaddrinfo and freeaddrinfo or none of them.
*/
if
(
ws2_freeaddrinfo
!=
NULL
)
{
ws2_freeaddrinfo
(
infos
);
FreeLibrary
(
wship6_module
);
return
;
}
FreeLibrary
(
wship6_module
);
}
#endif
#ifdef HAVE_GETADDRINFO
freeaddrinfo
(
infos
);
#else
__freeaddrinfo
(
infos
);
#endif
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment