Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Xiph.Org
Icecast-common
Commits
29cf9fe7
Commit
29cf9fe7
authored
Nov 22, 2002
by
Michael Smith
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Karl Heyes: patches for better networking code. IPv6 support (complete? Not
sure). svn path=/trunk/net/; revision=4114
parent
4453518a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
421 additions
and
220 deletions
+421
-220
net/resolver.c
net/resolver.c
+137
-123
net/sock.c
net/sock.c
+262
-96
net/sock.h
net/sock.h
+22
-1
No files found.
net/resolver.c
View file @
29cf9fe7
...
...
@@ -13,174 +13,188 @@
#ifndef _WIN32
#include <netdb.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#define sethostent(x)
#endif
#include "../thread/thread.h"
#include "resolver.h"
#include "sock.h"
/* internal function */
static
void
_lock_resolver
(
void
);
static
void
_unlock_resolver
(
void
);
static
char
*
_lookup
(
const
char
*
what
,
char
*
buff
,
int
len
);
static
int
_isip
(
const
char
*
what
);
/* internal data */
#ifdef _WIN32
#define mutex_t CRITICAL_SECTION
#else
#define mutex_t pthread_mutex_t
#endif
static
mutex_t
_resolver_mutex
;
static
int
_initialized
=
0
;
char
*
resolver_getname
(
const
char
*
ip
,
char
*
buff
,
int
len
)
#ifdef HAVE_INET_PTON
static
int
_isip
(
const
char
*
what
)
{
if
(
!
_isip
(
ip
))
{
strncpy
(
buff
,
ip
,
len
);
return
buff
;
}
union
{
struct
in_addr
v4addr
;
struct
in6_addr
v6addr
;
}
addr_u
;
if
(
inet_pton
(
AF_INET
,
what
,
&
addr_u
.
v4addr
)
<=
0
)
return
inet_pton
(
AF_INET6
,
what
,
&
addr_u
.
v6addr
)
>
0
?
1
:
0
;
return
_lookup
(
ip
,
buff
,
len
)
;
return
1
;
}
char
*
resolver_getip
(
const
char
*
name
,
char
*
buff
,
int
len
)
#else
static
int
_isip
(
const
char
*
what
)
{
if
(
_isip
(
name
))
{
strncpy
(
buff
,
name
,
len
);
return
buff
;
}
struct
in_addr
inp
;
return
_lookup
(
name
,
buff
,
len
);
return
inet_aton
(
what
,
&
inp
);
}
#endif
static
int
_isip
(
const
char
*
what
)
#if defined (HAVE_GETNAMEINFO) && defined (HAVE_GETADDRINFO)
char
*
resolver_getname
(
const
char
*
ip
,
char
*
buff
,
int
len
)
{
#ifdef HAVE_IPV6
union
{
struct
in_addr
v4addr
;
struct
in6_addr
v6addr
;
}
addr_u
;
struct
addrinfo
*
head
=
NULL
,
hints
;
char
*
ret
=
NULL
;
if
(
!
_isip
(
ip
))
{
strncpy
(
buff
,
ip
,
len
);
buff
[
len
-
1
]
=
'\0'
;
return
buff
;
}
memset
(
&
hints
,
0
,
sizeof
(
hints
));
hints
.
ai_family
=
AF_UNSPEC
;
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_flags
=
AI_CANONNAME
;
if
(
getaddrinfo
(
ip
,
NULL
,
&
hints
,
&
head
))
return
NULL
;
if
(
head
)
{
if
(
getnameinfo
(
head
->
ai_addr
,
head
->
ai_addrlen
,
buff
,
len
,
NULL
,
0
,
NI_NAMEREQD
)
==
0
)
ret
=
buff
;
freeaddrinfo
(
head
);
}
return
ret
;
}
if
(
inet_pton
(
AF_INET
,
what
,
&
addr_u
.
v4addr
)
<=
0
)
return
inet_pton
(
AF_INET6
,
what
,
&
addr_u
.
v6addr
)
>
0
?
1
:
0
;
return
1
;
char
*
resolver_getip
(
const
char
*
name
,
char
*
buff
,
int
len
)
{
struct
addrinfo
*
head
,
hints
;
char
*
ret
=
NULL
;
if
(
_isip
(
name
))
{
strncpy
(
buff
,
name
,
len
);
buff
[
len
-
1
]
=
'\0'
;
return
buff
;
}
memset
(
&
hints
,
0
,
sizeof
(
hints
));
hints
.
ai_family
=
AF_UNSPEC
;
hints
.
ai_socktype
=
SOCK_STREAM
;
if
(
getaddrinfo
(
name
,
NULL
,
&
hints
,
&
head
))
return
NULL
;
if
(
head
)
{
if
(
getnameinfo
(
head
->
ai_addr
,
head
->
ai_addrlen
,
buff
,
len
,
NULL
,
0
,
NI_NUMERICHOST
)
==
0
)
ret
=
buff
;
freeaddrinfo
(
head
);
}
return
ret
;
}
#else
struct
in_addr
inp
;
return
inet_aton
(
what
,
&
inp
);
#endif
char
*
resolver_getname
(
const
char
*
ip
,
char
*
buff
,
int
len
)
{
struct
hostent
*
host
;
char
*
ret
=
NULL
;
struct
in_addr
addr
;
if
(
!
_isip
(
ip
))
{
strncpy
(
buff
,
ip
,
len
);
buff
[
len
-
1
]
=
'\0'
;
return
buff
;
}
thread_mutex_lock
(
&
_resolver_mutex
);
if
(
inet_aton
(
ip
,
&
addr
))
{
if
((
host
=
gethostbyaddr
(
&
addr
,
sizeof
(
struct
in_addr
),
AF_INET
)))
{
ret
=
strncpy
(
buff
,
host
->
h_name
,
len
);
buff
[
len
-
1
]
=
'\0'
;
}
}
thread_mutex_unlock
(
&
_resolver_mutex
);
return
ret
;
}
static
char
*
_looku
p
(
const
char
*
what
,
char
*
buff
,
int
len
)
char
*
resolver_geti
p
(
const
char
*
name
,
char
*
buff
,
int
len
)
{
/* linux doesn't appear to have getipnodebyname as of glibc-2.2.3, so the IPV6 lookup is untested */
#ifdef HAVE_GETIPNODEBYNAME
int
err
;
#else
struct
in_addr
inp
;
struct
hostent
*
host
;
char
*
ret
=
NULL
;
if
(
_isip
(
name
))
{
strncpy
(
buff
,
name
,
len
);
buff
[
len
-
1
]
=
'\0'
;
return
buff
;
}
thread_mutex_lock
(
&
_resolver_mutex
);
host
=
gethostbyname
(
name
);
if
(
host
)
{
char
*
temp
=
inet_ntoa
(
*
(
struct
in_addr
*
)
host
->
h_addr
);
ret
=
strncpy
(
buff
,
temp
,
len
);
buff
[
len
-
1
]
=
'\0'
;
}
thread_mutex_unlock
(
&
_resolver_mutex
);
return
ret
;
}
#endif
struct
hostent
*
host
=
NULL
;
char
*
temp
;
/* do a little sanity checking */
if
(
what
==
NULL
||
buff
==
NULL
||
len
<=
0
)
return
NULL
;
#ifdef HAVE_GETIPNODEBYNAME
host
=
getipnodebyname
(
what
,
AF_INET6
,
AI_DEFAULT
,
&
err
);
if
(
host
)
{
if
(
_isip
(
what
))
strncpy
(
buff
,
host
->
h_name
,
len
);
else
inet_ntop
(
host
->
h_addrtype
,
host
->
h_addr_list
[
0
],
buff
,
len
);
freehostent
(
host
);
}
else
buff
=
NULL
;
#else
if
(
_isip
(
what
))
{
/* gotta lock calls for now, since gethostbyname and such
* aren't threadsafe */
_lock_resolver
();
host
=
gethostbyaddr
((
char
*
)
&
inp
,
sizeof
(
struct
in_addr
),
AF_INET
);
_unlock_resolver
();
if
(
host
==
NULL
)
{
buff
=
NULL
;
}
else
{
strncpy
(
buff
,
host
->
h_name
,
len
);
}
}
else
{
_lock_resolver
();
host
=
gethostbyname
(
what
);
_unlock_resolver
();
if
(
host
==
NULL
)
{
buff
=
NULL
;
}
else
{
// still need to be locked here?
temp
=
inet_ntoa
(
*
(
struct
in_addr
*
)
host
->
h_addr
);
strncpy
(
buff
,
temp
,
len
);
}
}
#endif
return
buff
;
}
void
resolver_initialize
()
{
/* initialize the lib if we havne't done so already */
/* initialize the lib if we havne't done so already */
if
(
!
_initialized
)
{
_initialized
=
1
;
#ifndef _WIN32
pthread_mutex_init
(
&
_resolver_mutex
,
NULL
);
#else
InitializeCriticalSection
(
&
_resolver_mutex
);
#endif
if
(
!
_initialized
)
{
_initialized
=
1
;
thread_mutex_create
(
&
_resolver_mutex
);
/* keep dns connects (TCP) open */
sethostent
(
1
);
}
}
void
resolver_shutdown
(
void
)
{
if
(
_initialized
)
{
#ifndef _WIN32
pthread_mutex_destroy
(
&
_resolver_mutex
);
#else
DeleteCriticalSection
(
&
_resolver_mutex
);
/* keep dns connects (TCP) open */
#ifdef HAVE_SETHOSTENT
sethostent
(
1
);
#endif
_initialized
=
0
;
}
}
}
static
void
_lock_resolver
(
)
void
resolver_shutdown
(
void
)
{
#ifndef _WIN32
pthread_mutex_lock
(
&
_resolver_mutex
);
#else
EnterCriticalSection
(
&
_resolver_mutex
);
if
(
_initialized
)
{
thread_mutex_destroy
(
&
_resolver_mutex
);
_initialized
=
0
;
#ifdef HAVE_ENDHOSTENT
endhostent
();
#endif
}
}
static
void
_unlock_resolver
()
{
#ifndef _WIN32
pthread_mutex_unlock
(
&
_resolver_mutex
);
#else
LeaveCriticalSection
(
&
_resolver_mutex
);
#endif
}
net/sock.c
View file @
29cf9fe7
...
...
@@ -47,10 +47,6 @@
#include "sock.h"
#include "resolver.h"
#ifndef _WIN32
extern
int
errno
;
#endif
/* sock_initialize
**
** initializes the socket library. you must call this
...
...
@@ -118,7 +114,24 @@ int sock_error(void)
*/
int
sock_recoverable
(
int
error
)
{
return
(
error
==
0
||
error
==
EAGAIN
||
error
==
EINTR
||
error
==
EINPROGRESS
||
error
==
EWOULDBLOCK
);
return
(
error
==
0
||
error
==
EAGAIN
||
error
==
EINTR
||
error
==
EINPROGRESS
||
error
==
EWOULDBLOCK
);
}
int
sock_stalled
(
int
error
)
{
return
error
==
EAGAIN
||
error
==
EINPROGRESS
||
error
==
EWOULDBLOCK
||
error
==
EALREADY
;
}
int
sock_success
(
int
error
)
{
return
error
==
0
;
}
int
sock_connect_pending
(
int
error
)
{
return
error
==
EINPROGRESS
||
error
==
EALREADY
;
}
/* sock_valid_socket
...
...
@@ -127,13 +140,14 @@ int sock_recoverable(int error)
*/
int
sock_valid_socket
(
sock_t
sock
)
{
int
ret
;
int
optval
,
optlen
;
int
ret
;
int
optval
;
socklen_t
optlen
;
optlen
=
sizeof
(
int
);
ret
=
getsockopt
(
sock
,
SOL_SOCKET
,
SO_TYPE
,
&
optval
,
&
optlen
);
optlen
=
sizeof
(
int
);
ret
=
getsockopt
(
sock
,
SOL_SOCKET
,
SO_TYPE
,
&
optval
,
&
optlen
);
return
(
ret
==
0
);
return
(
ret
==
0
);
}
/* inet_aton
...
...
@@ -180,13 +194,15 @@ int sock_set_blocking(sock_t sock, const int block)
int
sock_set_nolinger
(
sock_t
sock
)
{
struct
linger
lin
=
{
0
,
0
};
return
setsockopt
(
sock
,
SOL_SOCKET
,
SO_LINGER
,
(
void
*
)
&
lin
,
sizeof
(
struct
linger
));
return
setsockopt
(
sock
,
SOL_SOCKET
,
SO_LINGER
,
(
void
*
)
&
lin
,
sizeof
(
struct
linger
));
}
int
sock_set_keepalive
(
sock_t
sock
)
{
int
keepalive
=
1
;
return
setsockopt
(
sock
,
SOL_SOCKET
,
SO_KEEPALIVE
,
(
void
*
)
&
keepalive
,
sizeof
(
int
));
return
setsockopt
(
sock
,
SOL_SOCKET
,
SO_KEEPALIVE
,
(
void
*
)
&
keepalive
,
sizeof
(
int
));
}
/* sock_close
...
...
@@ -202,12 +218,51 @@ int sock_close(sock_t sock)
#endif
}
/* sock_writev
*
* write multiple buffers at once, return bytes actually written
*/
#ifdef HAVE_WRITEV
ssize_t
sock_writev
(
int
sock
,
const
struct
iovec
*
iov
,
const
size_t
count
)
{
return
writev
(
sock
,
iov
,
count
);
}
#else
ssize_t
sock_writev
(
int
sock
,
const
struct
iovec
*
iov
,
const
size_t
count
)
{
int
i
=
count
,
accum
=
0
,
ret
;
const
struct
iovec
*
v
=
iov
;
while
(
i
)
{
if
(
v
->
iov_base
&&
v
->
iov_len
)
{
ret
=
sock_write_bytes
(
sock
,
v
->
iov_base
,
v
->
iov_len
);
if
(
ret
==
-
1
&&
accum
==
0
)
return
-
1
;
if
(
ret
==
-
1
)
ret
=
0
;
accum
+=
ret
;
if
(
ret
<
(
int
)
v
->
iov_len
)
break
;
}
v
++
;
i
--
;
}
return
accum
;
}
#endif
/* sock_write_bytes
**
** write bytes to the socket
** this function will _NOT_ block
*/
int
sock_write_bytes
(
sock_t
sock
,
const
char
*
buff
,
const
in
t
len
)
int
sock_write_bytes
(
sock_t
sock
,
const
void
*
buff
,
const
size_
t
len
)
{
/* sanity check */
if
(
!
buff
)
{
...
...
@@ -301,97 +356,207 @@ int sock_read_line(sock_t sock, char *buff, const int len)
}
}
/* sock_connect_wto
**
** Connect to hostname on specified port and return the created socket.
** timeout specifies the maximum time to wait for this to finish and
** returns when it expires whether it connected or not
** setting timeout to 0 disable the timeout.
/* see if a connection can be written to
** return -1 unable to check
** return 0 for not yet
** return 1 for ok
*/
int
sock_connected
(
int
sock
,
unsigned
timeout
)
{
fd_set
wfds
;
int
val
=
SOCK_ERROR
;
socklen_t
size
=
sizeof
val
;
struct
timeval
tv
;
tv
.
tv_sec
=
timeout
;
tv
.
tv_usec
=
0
;
FD_ZERO
(
&
wfds
);
FD_SET
(
sock
,
&
wfds
);
switch
(
select
(
sock
+
1
,
NULL
,
&
wfds
,
NULL
,
&
tv
))
{
case
0
:
return
SOCK_TIMEOUT
;
default:
if
(
getsockopt
(
sock
,
SOL_SOCKET
,
SO_ERROR
,
&
val
,
&
size
)
<
0
)
val
=
SOCK_ERROR
;
case
-
1
:
return
val
;
}
}
#ifdef HAVE_GETADDRINFO
int
sock_connect_non_blocking
(
const
char
*
hostname
,
const
unsigned
port
)
{
int
sock
=
SOCK_ERROR
;
struct
addrinfo
*
ai
,
*
head
,
hints
;
char
service
[
8
];
memset
(
&
hints
,
0
,
sizeof
(
hints
));
hints
.
ai_family
=
AF_UNSPEC
;
hints
.
ai_socktype
=
SOCK_STREAM
;
snprintf
(
service
,
sizeof
(
service
),
"%u"
,
port
);
if
(
getaddrinfo
(
hostname
,
service
,
&
hints
,
&
head
))
return
SOCK_ERROR
;
ai
=
head
;
while
(
ai
)
{
if
((
sock
=
socket
(
ai
->
ai_family
,
ai
->
ai_socktype
,
ai
->
ai_protocol
))
>
-
1
)
{
sock_set_blocking
(
sock
,
SOCK_NONBLOCK
);
if
(
connect
(
sock
,
ai
->
ai_addr
,
ai
->
ai_addrlen
)
<
0
&&
!
sock_connect_pending
(
sock_error
()))
{
sock_close
(
sock
);
sock
=
SOCK_ERROR
;
}
else
break
;
}
ai
=
ai
->
ai_next
;
}
if
(
head
)
freeaddrinfo
(
head
);
return
sock
;
}
sock_t
sock_connect_wto
(
const
char
*
hostname
,
const
int
port
,
const
int
timeout
)
{
sock_t
sock
;
struct
sockaddr_in
sin
,
server
;
char
ip
[
20
];
int
sock
=
SOCK_ERROR
;
struct
addrinfo
*
ai
,
*
head
,
hints
;
char
service
[
8
];
memset
(
&
hints
,
0
,
sizeof
(
hints
));
hints
.
ai_family
=
AF_UNSPEC
;
hints
.
ai_socktype
=
SOCK_STREAM
;
snprintf
(
service
,
sizeof
(
service
),
"%u"
,
port
);
if
(
getaddrinfo
(
hostname
,
service
,
&
hints
,
&
head
))
return
SOCK_ERROR
;
ai
=
head
;
while
(
ai
)
{
if
((
sock
=
socket
(
ai
->
ai_family
,
ai
->
ai_socktype
,
ai
->
ai_protocol
))
>
-
1
)
{
if
(
timeout
)
{
sock_set_blocking
(
sock
,
SOCK_NONBLOCK
);
if
(
connect
(
sock
,
ai
->
ai_addr
,
ai
->
ai_addrlen
)
<
0
)
{
int
ret
=
sock_connected
(
sock
,
timeout
);
if
(
ret
<=
0
)
{
sock_close
(
sock
);
sock
=
SOCK_ERROR
;
}
}
sock_set_blocking
(
sock
,
SOCK_BLOCK
);
}
else
{
if
(
connect
(
sock
,
ai
->
ai_addr
,
ai
->
ai_addrlen
)
<
0
)
{
sock_close
(
sock
);
sock
=
SOCK_ERROR
;
}
}
}
ai
=
ai
->
ai_next
;
}
if
(
head
)
freeaddrinfo
(
head
);
return
sock
;
}
if
(
!
hostname
||
!
hostname
[
0
])
{
return
SOCK_ERROR
;
}
else
if
(
port
<=
0
)
{
return
SOCK_ERROR
;
}
sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
sock
==
SOCK_ERROR
)
{
sock_close
(
sock
);
return
SOCK_ERROR
;
}
#else
memset
(
&
sin
,
0
,
sizeof
(
struct
sockaddr_in
));
memset
(
&
server
,
0
,
sizeof
(
struct
sockaddr_in
));
if
(
!
resolver_getip
(
hostname
,
ip
,
20
))
return
SOCK_ERROR
;
if
(
inet_aton
(
ip
,
(
struct
in_addr
*
)
&
sin
.
sin_addr
)
==
0
)
{
sock_close
(
sock
);
return
SOCK_ERROR
;
}
int
sock_try_connection
(
int
sock
,
const
char
*
hostname
,
const
unsigned
port
)
{
struct
sockaddr_in
sin
,
server
;
char
ip
[
20
];
memcpy
(
&
server
.
sin_addr
,
&
sin
.
sin_addr
,
sizeof
(
struct
sockaddr_in
));
server
.
sin_family
=
AF_INET
;
server
.
sin_port
=
htons
(
port
);
/* if we have a timeout, use select, if not, use connect straight. */
/* dunno if this is portable, and it sure is complicated for such a
simple thing to want to do. damn BSD sockets! */
if
(
timeout
>
0
)
{
fd_set
wfds
;
struct
timeval
tv
;
int
retval
;
int
val
;
int
valsize
=
sizeof
(
int
);
FD_ZERO
(
&
wfds
);
FD_SET
(
sock
,
&
wfds
);
tv
.
tv_sec
=
timeout
;
tv
.
tv_usec
=
0
;
sock_set_blocking
(
sock
,
SOCK_NONBLOCK
);
retval
=
connect
(
sock
,
(
struct
sockaddr
*
)
&
server
,
sizeof
(
server
));
if
(
retval
==
0
)
{
sock_set_blocking
(
sock
,
SOCK_BLOCK
);
return
sock
;
}
else
{
if
(
!
sock_recoverable
(
sock_error
()))
{
sock_close
(
sock
);
return
SOCK_ERROR
;
}
}
if
(
!
hostname
||
!
hostname
[
0
]
||
port
==
0
)
return
-
1
;
if
(
select
(
sock
+
1
,
NULL
,
&
wfds
,
NULL
,
&
tv
))
{
retval
=
getsockopt
(
sock
,
SOL_SOCKET
,
SO_ERROR
,
(
void
*
)
&
val
,
(
int
*
)
&
valsize
);
if
((
retval
==
0
)
&&
(
val
==
0
))
{