2018-04-18 01:43:46 -04:00
/* Icecast
*
* This program is distributed under the GNU General Public License , version 2.
* A copy of this license is included with this source .
*
2020-02-14 09:05:01 -05:00
* Copyright 2018 - 2020 , Philipp " ph3-der-loewe " Schafft < lion @ lion . leolix . org > ,
2018-04-18 01:43:46 -04:00
*/
/**
* Listen socket operations .
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# ifdef HAVE_POLL
# include <poll.h>
2018-07-08 19:39:35 -04:00
# elif HAVE_SYS_SELECT_H
2018-04-18 01:43:46 -04:00
# include <sys/select.h>
# endif
# include <string.h>
# include "common/net/sock.h"
2018-05-11 04:08:38 -04:00
# include "common/thread/thread.h"
2018-04-18 01:43:46 -04:00
# include "listensocket.h"
# include "global.h"
# include "connection.h"
# include "refobject.h"
# include "logging.h"
# define CATMODULE "listensocket"
struct listensocket_container_tag {
refobject_base_t __base ;
2022-03-21 04:48:23 -04:00
rwlock_t rwlock ;
2022-03-07 04:56:41 -05:00
bool prefer_inet6 ;
2018-04-18 01:43:46 -04:00
listensocket_t * * sock ;
int * sockref ;
size_t sock_len ;
2018-05-09 05:58:09 -04:00
void ( * sockcount_cb ) ( size_t count , void * userdata ) ;
void * sockcount_userdata ;
2018-04-18 01:43:46 -04:00
} ;
struct listensocket_tag {
refobject_base_t __base ;
size_t sockrefc ;
2018-05-11 04:08:38 -04:00
mutex_t lock ;
rwlock_t listener_rwlock ;
2018-04-18 01:43:46 -04:00
listener_t * listener ;
2018-05-11 02:52:03 -04:00
listener_t * listener_update ;
2018-04-18 01:43:46 -04:00
sock_t sock ;
} ;
2018-05-11 04:08:38 -04:00
static int listensocket_container_configure__unlocked ( listensocket_container_t * self , const ice_config_t * config ) ;
static int listensocket_container_setup__unlocked ( listensocket_container_t * self ) ;
static ssize_t listensocket_container_sockcount__unlocked ( listensocket_container_t * self ) ;
2018-04-18 01:43:46 -04:00
static listensocket_t * listensocket_new ( const listener_t * listener ) ;
2018-05-11 02:52:03 -04:00
static int listensocket_apply_config ( listensocket_t * self ) ;
2018-05-11 04:08:38 -04:00
static int listensocket_apply_config__unlocked ( listensocket_t * self ) ;
2018-05-11 02:52:03 -04:00
static int listensocket_set_update ( listensocket_t * self , const listener_t * listener ) ;
2022-03-07 04:56:41 -05:00
static int listensocket_refsock ( listensocket_t * self , bool prefer_inet6 ) ;
static int listensocket_unrefsock ( listensocket_t * self ) ;
2018-04-18 01:43:46 -04:00
# ifdef HAVE_POLL
2018-05-10 03:10:19 -04:00
static inline int listensocket__poll_fill ( listensocket_t * self , struct pollfd * p ) ;
2018-04-18 01:43:46 -04:00
# else
2018-05-10 03:10:19 -04:00
static inline int listensocket__select_set ( listensocket_t * self , fd_set * set , int * max ) ;
static inline int listensocket__select_isset ( listensocket_t * self , fd_set * set ) ;
2018-04-18 01:43:46 -04:00
# endif
2018-05-10 04:25:17 -04:00
static inline const char * __string_default ( const char * str , const char * def )
{
return str ! = NULL ? str : def ;
}
2018-09-28 09:52:39 -04:00
static inline int __socket_listen ( sock_t serversock , const listener_t * listener )
{
int listen_backlog = listener - > listen_backlog ;
if ( listen_backlog < 1 )
listen_backlog = ICECAST_LISTEN_QUEUE ;
if ( listen_backlog > 128 ) {
listen_backlog = 128 ;
ICECAST_LOG_WARN ( " Listen backlog for listen socket on %s port %i is set insanely high. Limiting to sane range. " , __string_default ( listener - > bind_address , " <ANY> " ) , listener - > port ) ;
}
return sock_listen ( serversock , listen_backlog ) ;
}
2018-05-10 04:30:34 -04:00
static inline int __listener_cmp ( const listener_t * a , const listener_t * b )
{
if ( a = = b )
return 1 ;
if ( a - > port ! = b - > port )
return 0 ;
if ( ( a - > bind_address = = NULL & & b - > bind_address ! = NULL ) | |
( a - > bind_address ! = NULL & & b - > bind_address = = NULL ) )
return 0 ;
if ( a - > bind_address ! = NULL & & b - > bind_address ! = NULL & & strcmp ( a - > bind_address , b - > bind_address ) ! = 0 )
return 0 ;
return 1 ;
}
2018-05-09 05:58:09 -04:00
static inline void __call_sockcount_cb ( listensocket_container_t * self )
{
if ( self - > sockcount_cb = = NULL )
return ;
2018-05-11 04:08:38 -04:00
self - > sockcount_cb ( listensocket_container_sockcount__unlocked ( self ) , self - > sockcount_userdata ) ;
2018-05-09 05:58:09 -04:00
}
2018-05-11 04:08:38 -04:00
static void __listensocket_container_clear_sockets ( listensocket_container_t * self )
2018-04-18 01:43:46 -04:00
{
size_t i ;
if ( self - > sock = = NULL )
return ;
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sock [ i ] ! = NULL ) {
if ( self - > sockref [ i ] ) {
listensocket_unrefsock ( self - > sock [ i ] ) ;
}
refobject_unref ( self - > sock [ i ] ) ;
self - > sock [ i ] = NULL ;
}
}
self - > sock_len = 0 ;
free ( self - > sock ) ;
free ( self - > sockref ) ;
self - > sock = NULL ;
self - > sockref = NULL ;
2018-05-09 05:58:09 -04:00
__call_sockcount_cb ( self ) ;
2018-04-18 01:43:46 -04:00
}
static void __listensocket_container_free ( refobject_t self , void * * userdata )
{
listensocket_container_t * container = REFOBJECT_TO_TYPE ( self , listensocket_container_t * ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_wlock ( & container - > rwlock ) ;
2018-05-11 04:08:38 -04:00
__listensocket_container_clear_sockets ( container ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & container - > rwlock ) ;
thread_rwlock_destroy ( & container - > rwlock ) ;
2018-04-18 01:43:46 -04:00
}
2018-10-10 11:06:45 -04:00
int __listensocket_container_new ( refobject_t self , const refobject_type_t * type , va_list ap )
2018-04-18 01:43:46 -04:00
{
2018-10-10 11:06:45 -04:00
listensocket_container_t * ret = REFOBJECT_TO_TYPE ( self , listensocket_container_t * ) ;
2018-04-18 01:43:46 -04:00
2018-10-10 11:06:45 -04:00
ret - > sock = NULL ;
ret - > sock_len = 0 ;
ret - > sockcount_cb = NULL ;
ret - > sockcount_userdata = NULL ;
2018-04-18 01:43:46 -04:00
2022-03-21 04:48:23 -04:00
thread_rwlock_create ( & ret - > rwlock ) ;
2018-05-11 04:08:38 -04:00
2018-10-10 11:06:45 -04:00
return 0 ;
2018-04-18 01:43:46 -04:00
}
2018-10-10 11:06:45 -04:00
REFOBJECT_DEFINE_TYPE ( listensocket_container_t ,
REFOBJECT_DEFINE_TYPE_FREE ( __listensocket_container_free ) ,
REFOBJECT_DEFINE_TYPE_NEW ( __listensocket_container_new )
) ;
2018-05-11 02:52:03 -04:00
static inline void __find_matching_entry ( listensocket_container_t * self , const listener_t * listener , listensocket_t * * * found , int * * ref )
{
const listener_t * b ;
2018-05-11 04:08:38 -04:00
int test ;
2018-05-11 02:52:03 -04:00
size_t i ;
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sock [ i ] ! = NULL ) {
if ( self - > sockref [ i ] ) {
b = listensocket_get_listener ( self - > sock [ i ] ) ;
2018-05-11 04:08:38 -04:00
test = __listener_cmp ( listener , b ) ;
listensocket_release_listener ( self - > sock [ i ] ) ;
if ( test = = 1 ) {
2018-05-11 02:52:03 -04:00
* found = & ( self - > sock [ i ] ) ;
* ref = & ( self - > sockref [ i ] ) ;
return ;
}
}
}
}
* found = NULL ;
* ref = NULL ;
}
2018-04-18 01:43:46 -04:00
int listensocket_container_configure ( listensocket_container_t * self , const ice_config_t * config )
2018-05-11 04:08:38 -04:00
{
int ret ;
if ( ! self )
return - 1 ;
2022-03-21 04:48:23 -04:00
thread_rwlock_wlock ( & self - > rwlock ) ;
2018-05-11 04:08:38 -04:00
ret = listensocket_container_configure__unlocked ( self , config ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-05-11 04:08:38 -04:00
return ret ;
}
static int listensocket_container_configure__unlocked ( listensocket_container_t * self , const ice_config_t * config )
2018-04-18 01:43:46 -04:00
{
listensocket_t * * n ;
2018-05-11 02:52:03 -04:00
listensocket_t * * match ;
2018-04-18 01:43:46 -04:00
listener_t * cur ;
int * r ;
2018-05-11 02:52:03 -04:00
int * m ;
2018-04-18 01:43:46 -04:00
size_t i ;
if ( ! self | | ! config )
return - 1 ;
if ( ! config - > listen_sock_count ) {
2018-05-11 04:08:38 -04:00
__listensocket_container_clear_sockets ( self ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
}
n = calloc ( config - > listen_sock_count , sizeof ( listensocket_t * ) ) ;
r = calloc ( config - > listen_sock_count , sizeof ( int ) ) ;
if ( ! n | | ! r ) {
free ( n ) ;
free ( r ) ;
return - 1 ;
}
cur = config - > listen_sock ;
for ( i = 0 ; i < config - > listen_sock_count ; i + + ) {
if ( cur ) {
2018-05-11 02:52:03 -04:00
__find_matching_entry ( self , cur , & match , & m ) ;
if ( match ) {
n [ i ] = * match ;
r [ i ] = 1 ;
* match = NULL ;
* m = 0 ;
listensocket_set_update ( n [ i ] , cur ) ;
} else {
n [ i ] = listensocket_new ( cur ) ;
}
2018-04-18 01:43:46 -04:00
} else {
n [ i ] = NULL ;
}
if ( n [ i ] = = NULL ) {
for ( ; i ; i - - ) {
refobject_unref ( n [ i - 1 ] ) ;
}
return - 1 ;
}
cur = cur - > next ;
}
2018-05-11 04:08:38 -04:00
__listensocket_container_clear_sockets ( self ) ;
2018-04-18 01:43:46 -04:00
self - > sock = n ;
self - > sockref = r ;
self - > sock_len = config - > listen_sock_count ;
return 0 ;
}
2018-05-10 04:33:19 -04:00
int listensocket_container_configure_and_setup ( listensocket_container_t * self , const ice_config_t * config )
{
void ( * cb ) ( size_t count , void * userdata ) ;
int ret ;
2022-03-07 04:56:41 -05:00
bool prefer_inet6 ;
2018-05-10 04:33:19 -04:00
if ( ! self )
return - 1 ;
2022-03-07 04:56:41 -05:00
prefer_inet6 = sock_is_ipv4_mapped_supported ( ) ; /* test before we enter lock to minimise locked time */
2022-03-21 04:48:23 -04:00
thread_rwlock_wlock ( & self - > rwlock ) ;
2022-03-07 04:56:41 -05:00
self - > prefer_inet6 = prefer_inet6 ;
2018-05-10 04:33:19 -04:00
cb = self - > sockcount_cb ;
self - > sockcount_cb = NULL ;
2018-05-11 04:08:38 -04:00
if ( listensocket_container_configure__unlocked ( self , config ) = = 0 ) {
ret = listensocket_container_setup__unlocked ( self ) ;
2018-05-10 04:33:19 -04:00
} else {
ret = - 1 ;
}
self - > sockcount_cb = cb ;
__call_sockcount_cb ( self ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-05-10 04:33:19 -04:00
return ret ;
}
2018-05-11 04:08:38 -04:00
int listensocket_container_setup ( listensocket_container_t * self )
{
int ret ;
2022-03-07 04:56:41 -05:00
bool prefer_inet6 ;
2018-04-18 01:43:46 -04:00
if ( ! self )
return - 1 ;
2022-03-07 04:56:41 -05:00
prefer_inet6 = sock_is_ipv4_mapped_supported ( ) ; /* test before we enter lock to minimise locked time */
2022-03-21 04:48:23 -04:00
thread_rwlock_wlock ( & self - > rwlock ) ;
2022-03-07 04:56:41 -05:00
self - > prefer_inet6 = prefer_inet6 ;
2018-05-11 04:08:38 -04:00
ret = listensocket_container_setup__unlocked ( self ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-05-11 04:08:38 -04:00
return ret ;
}
static int listensocket_container_setup__unlocked ( listensocket_container_t * self )
{
2018-05-18 09:49:15 -04:00
listener_type_t type ;
2018-05-11 04:08:38 -04:00
size_t i ;
int ret = 0 ;
2018-04-18 01:43:46 -04:00
for ( i = 0 ; i < self - > sock_len ; i + + ) {
2018-05-18 09:49:15 -04:00
listensocket_apply_config ( self - > sock [ i ] ) ;
type = listensocket_get_type ( self - > sock [ i ] ) ;
if ( self - > sockref [ i ] & & type = = LISTENER_TYPE_VIRTUAL ) {
if ( listensocket_unrefsock ( self - > sock [ i ] ) = = 0 ) {
self - > sockref [ i ] = 0 ;
}
} else if ( ! self - > sockref [ i ] & & type ! = LISTENER_TYPE_VIRTUAL ) {
2022-03-07 04:56:41 -05:00
if ( listensocket_refsock ( self - > sock [ i ] , self - > prefer_inet6 ) = = 0 ) {
2018-05-11 02:52:03 -04:00
self - > sockref [ i ] = 1 ;
} else {
ICECAST_LOG_DEBUG ( " Can not ref socket. " ) ;
ret = 1 ;
}
2018-04-18 01:43:46 -04:00
}
}
2018-05-09 05:58:09 -04:00
__call_sockcount_cb ( self ) ;
2018-04-18 01:43:46 -04:00
return ret ;
}
2018-05-18 09:58:51 -04:00
static listensocket_t * listensocket_container_accept__inner ( listensocket_container_t * self , int timeout )
2018-04-18 01:43:46 -04:00
{
# ifdef HAVE_POLL
struct pollfd ufds [ self - > sock_len ] ;
listensocket_t * socks [ self - > sock_len ] ;
size_t i , found , p ;
int ok ;
int ret ;
for ( i = 0 , found = 0 ; i < self - > sock_len ; i + + ) {
ok = self - > sockref [ i ] ;
if ( ok & & listensocket__poll_fill ( self - > sock [ i ] , & ( ufds [ found ] ) ) = = - 1 ) {
ICECAST_LOG_WARN ( " Can not poll on closed socket. " ) ;
ok = 0 ;
}
if ( ok ) {
socks [ found ] = self - > sock [ i ] ;
found + + ;
}
}
if ( ! found ) {
ICECAST_LOG_ERROR ( " No sockets found to poll on. " ) ;
return NULL ;
}
ret = poll ( ufds , found , timeout ) ;
if ( ret < = 0 )
return NULL ;
for ( i = 0 ; i < found ; i + + ) {
if ( ufds [ i ] . revents & POLLIN ) {
2018-05-18 09:58:51 -04:00
return socks [ i ] ;
2018-04-18 01:43:46 -04:00
}
if ( ! ( ufds [ i ] . revents & ( POLLHUP | POLLERR | POLLNVAL ) ) )
continue ;
for ( p = 0 ; p < self - > sock_len ; p + + ) {
if ( self - > sock [ p ] = = socks [ i ] ) {
if ( self - > sockref [ p ] ) {
ICECAST_LOG_ERROR ( " Closing listen socket in error state. " ) ;
listensocket_unrefsock ( socks [ i ] ) ;
self - > sockref [ p ] = 0 ;
2018-05-09 05:58:09 -04:00
__call_sockcount_cb ( self ) ;
2018-04-18 01:43:46 -04:00
}
}
}
}
return NULL ;
# else
fd_set rfds ;
size_t i ;
struct timeval tv , * p = NULL ;
int ret ;
int max = - 1 ;
FD_ZERO ( & rfds ) ;
if ( timeout > = 0 ) {
tv . tv_sec = timeout / 1000 ;
tv . tv_usec = ( timeout % 1000 ) * 1000 ;
p = & tv ;
}
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sockref [ i ] ) {
listensocket__select_set ( self - > sock [ i ] , & rfds , & max ) ;
}
}
ret = select ( max + 1 , & rfds , NULL , NULL , p ) ;
if ( ret < = 0 )
return NULL ;
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sockref [ i ] ) {
if ( listensocket__select_isset ( self - > sock [ i ] , & rfds ) ) {
2018-05-18 09:58:51 -04:00
return self - > sock [ i ] ;
2018-04-18 01:43:46 -04:00
}
}
}
return NULL ;
# endif
}
connection_t * listensocket_container_accept ( listensocket_container_t * self , int timeout )
{
2018-05-18 09:58:51 -04:00
listensocket_t * ls ;
2018-05-11 04:08:38 -04:00
connection_t * ret ;
2018-04-18 01:43:46 -04:00
if ( ! self )
return NULL ;
2022-03-21 04:48:23 -04:00
thread_rwlock_rlock ( & self - > rwlock ) ;
2018-05-18 09:58:51 -04:00
ls = listensocket_container_accept__inner ( self , timeout ) ;
refobject_ref ( ls ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-05-18 09:58:51 -04:00
ret = listensocket_accept ( ls , self ) ;
refobject_unref ( ls ) ;
2018-05-11 04:08:38 -04:00
return ret ;
2018-04-18 01:43:46 -04:00
}
2018-05-09 05:58:09 -04:00
int listensocket_container_set_sockcount_cb ( listensocket_container_t * self , void ( * cb ) ( size_t count , void * userdata ) , void * userdata )
{
if ( ! self )
return - 1 ;
2022-03-21 04:48:23 -04:00
thread_rwlock_wlock ( & self - > rwlock ) ;
2018-05-09 05:58:09 -04:00
self - > sockcount_cb = cb ;
self - > sockcount_userdata = userdata ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-05-09 05:58:09 -04:00
return 0 ;
}
ssize_t listensocket_container_sockcount ( listensocket_container_t * self )
{
2018-05-11 04:08:38 -04:00
ssize_t ret ;
2018-05-09 05:58:09 -04:00
if ( ! self )
return - 1 ;
2022-03-21 04:48:23 -04:00
thread_rwlock_rlock ( & self - > rwlock ) ;
2018-05-11 04:08:38 -04:00
ret = listensocket_container_sockcount__unlocked ( self ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-05-11 04:08:38 -04:00
return ret ;
}
static ssize_t listensocket_container_sockcount__unlocked ( listensocket_container_t * self )
{
ssize_t count = 0 ;
size_t i ;
2018-05-09 05:58:09 -04:00
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sockref [ i ] ) {
count + + ;
}
}
return count ;
}
2020-04-22 15:35:35 -04:00
listensocket_t * listensocket_container_get_by_id ( listensocket_container_t * self , const char * id )
2018-06-30 09:51:42 -04:00
{
size_t i ;
const listener_t * listener ;
2022-03-21 04:48:23 -04:00
thread_rwlock_rlock ( & self - > rwlock ) ;
2018-06-30 09:51:42 -04:00
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sock [ i ] ! = NULL ) {
listener = listensocket_get_listener ( self - > sock [ i ] ) ;
if ( listener ) {
2018-08-08 04:59:34 -04:00
if ( listener - > id ! = NULL & & strcmp ( listener - > id , id ) = = 0 ) {
2018-06-30 09:51:42 -04:00
if ( refobject_ref ( self - > sock [ i ] ) = = 0 ) {
2020-02-14 09:05:01 -05:00
listensocket_release_listener ( self - > sock [ i ] ) ;
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-06-30 09:51:42 -04:00
return self - > sock [ i ] ;
}
}
listensocket_release_listener ( self - > sock [ i ] ) ;
}
}
}
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2018-06-30 09:51:42 -04:00
return NULL ;
}
2022-03-21 19:13:30 -04:00
/* may return NULL if there is no default */
listensocket_t * listensocket_container_get_default ( listensocket_container_t * self )
{
listensocket_t * ret = NULL ;
thread_rwlock_rlock ( & self - > rwlock ) ;
if ( self - > sock_len = = 1 ) {
if ( refobject_ref ( self - > sock [ 0 ] ) = = 0 ) {
ret = self - > sock [ 0 ] ;
}
}
thread_rwlock_unlock ( & self - > rwlock ) ;
return ret ;
}
2022-03-06 13:29:30 -05:00
listensocket_t * * listensocket_container_list_sockets ( listensocket_container_t * self )
{
listensocket_t * * res ;
size_t idx = 0 ;
size_t i ;
2022-03-21 04:48:23 -04:00
thread_rwlock_rlock ( & self - > rwlock ) ;
2022-03-06 13:29:30 -05:00
res = calloc ( self - > sock_len + 1 , sizeof ( * res ) ) ;
if ( ! res ) {
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2022-03-06 13:29:30 -05:00
return NULL ;
}
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sock [ i ] ! = NULL ) {
refobject_ref ( res [ idx + + ] = self - > sock [ i ] ) ;
}
}
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2022-03-06 13:29:30 -05:00
return res ;
}
2022-03-06 13:49:11 -05:00
bool listensocket_container_is_family_included ( listensocket_container_t * self , sock_family_t family )
{
size_t i ;
2022-03-21 04:48:23 -04:00
thread_rwlock_rlock ( & self - > rwlock ) ;
2022-03-06 13:49:11 -05:00
for ( i = 0 ; i < self - > sock_len ; i + + ) {
if ( self - > sock [ i ] ! = NULL ) {
if ( listensocket_get_family ( self - > sock [ i ] ) = = family ) {
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2022-03-06 13:49:11 -05:00
return true ;
}
}
}
2022-03-21 04:48:23 -04:00
thread_rwlock_unlock ( & self - > rwlock ) ;
2022-03-06 13:49:11 -05:00
return false ;
}
2018-05-11 04:08:38 -04:00
/* ---------------------------------------------------------------------------- */
2018-04-18 01:43:46 -04:00
static void __listensocket_free ( refobject_t self , void * * userdata )
{
listensocket_t * listensocket = REFOBJECT_TO_TYPE ( self , listensocket_t * ) ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & listensocket - > lock ) ;
2018-04-18 01:43:46 -04:00
if ( listensocket - > sockrefc ) {
ICECAST_LOG_ERROR ( " BUG: listensocket->sockrefc == 0 && listensocket->sockrefc == %zu " , listensocket - > sockrefc ) ;
listensocket - > sockrefc = 1 ;
listensocket_unrefsock ( listensocket ) ;
}
2018-05-11 02:52:03 -04:00
while ( ( listensocket - > listener_update = config_clear_listener ( listensocket - > listener_update ) ) ) ;
2018-05-11 04:08:38 -04:00
thread_rwlock_wlock ( & listensocket - > listener_rwlock ) ;
while ( ( listensocket - > listener = config_clear_listener ( listensocket - > listener ) ) ) ;
thread_rwlock_unlock ( & listensocket - > listener_rwlock ) ;
thread_rwlock_destroy ( & listensocket - > listener_rwlock ) ;
thread_mutex_unlock ( & listensocket - > lock ) ;
thread_mutex_destroy ( & listensocket - > lock ) ;
2018-04-18 01:43:46 -04:00
}
2018-10-10 07:15:39 -04:00
REFOBJECT_DEFINE_TYPE ( listensocket_t ,
REFOBJECT_DEFINE_TYPE_FREE ( __listensocket_free )
) ;
2018-04-18 01:43:46 -04:00
static listensocket_t * listensocket_new ( const listener_t * listener ) {
listensocket_t * self ;
if ( listener = = NULL )
return NULL ;
2018-10-10 07:15:39 -04:00
self = refobject_new__new ( listensocket_t , NULL , NULL , NULL ) ;
2018-04-18 01:43:46 -04:00
if ( ! self )
return NULL ;
self - > sock = SOCK_ERROR ;
2018-05-11 04:08:38 -04:00
thread_mutex_create ( & self - > lock ) ;
thread_rwlock_create ( & self - > listener_rwlock ) ;
2018-04-18 01:43:46 -04:00
self - > listener = config_copy_listener_one ( listener ) ;
if ( self - > listener = = NULL ) {
refobject_unref ( self ) ;
return NULL ;
}
return self ;
}
2018-05-11 02:52:03 -04:00
static int listensocket_apply_config ( listensocket_t * self )
2018-05-11 04:08:38 -04:00
{
int ret ;
if ( ! self )
return - 1 ;
thread_mutex_lock ( & self - > lock ) ;
ret = listensocket_apply_config__unlocked ( self ) ;
thread_mutex_unlock ( & self - > lock ) ;
return ret ;
}
static int listensocket_apply_config__unlocked ( listensocket_t * self )
2018-05-10 04:25:17 -04:00
{
2018-05-11 02:52:03 -04:00
const listener_t * listener ;
2018-05-10 04:25:17 -04:00
2018-05-11 02:52:03 -04:00
if ( ! self )
2018-05-10 04:25:17 -04:00
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_rwlock_wlock ( & self - > listener_rwlock ) ;
2018-05-11 02:52:03 -04:00
if ( self - > listener_update ) {
if ( __listener_cmp ( self - > listener , self - > listener_update ) ! = 1 ) {
2022-03-12 05:04:19 -05:00
ICECAST_LOG_ERROR ( " Tried to apply incomplete configuration to listensocket: bind address mismatch: have %s:%i, got %s:%i " ,
2018-05-10 04:25:17 -04:00
__string_default ( self - > listener - > bind_address , " <ANY> " ) ,
2018-05-10 04:30:34 -04:00
self - > listener - > port ,
2018-05-11 02:52:03 -04:00
__string_default ( self - > listener_update - > bind_address , " <ANY> " ) ,
self - > listener_update - > port
2018-05-10 04:25:17 -04:00
) ;
2018-05-11 04:08:38 -04:00
thread_rwlock_unlock ( & self - > listener_rwlock ) ;
2018-05-10 04:25:17 -04:00
return - 1 ;
}
2018-05-11 02:52:03 -04:00
listener = self - > listener_update ;
} else {
listener = self - > listener ;
2018-05-10 04:25:17 -04:00
}
2018-05-18 09:49:15 -04:00
if ( self - > sock ! = SOCK_ERROR ) {
if ( listener - > so_sndbuf )
sock_set_send_buffer ( self - > sock , listener - > so_sndbuf ) ;
2018-05-10 04:25:17 -04:00
2018-05-18 09:49:15 -04:00
sock_set_blocking ( self - > sock , 0 ) ;
2018-09-28 09:52:39 -04:00
__socket_listen ( self - > sock , listener ) ;
2018-05-18 09:49:15 -04:00
}
2018-05-10 04:25:17 -04:00
2018-05-11 02:52:03 -04:00
if ( self - > listener_update ) {
2018-05-10 04:25:17 -04:00
while ( ( self - > listener = config_clear_listener ( self - > listener ) ) ) ;
2018-05-11 02:52:03 -04:00
self - > listener = self - > listener_update ;
self - > listener_update = NULL ;
2018-05-10 04:25:17 -04:00
}
2018-05-11 04:08:38 -04:00
thread_rwlock_unlock ( & self - > listener_rwlock ) ;
2018-05-10 04:25:17 -04:00
return 0 ;
}
2018-05-11 02:52:03 -04:00
static int listensocket_set_update ( listensocket_t * self , const listener_t * listener )
{
listener_t * n ;
if ( ! self | | ! listener )
return - 1 ;
n = config_copy_listener_one ( listener ) ;
if ( n = = NULL )
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
2018-05-11 02:52:03 -04:00
while ( ( self - > listener_update = config_clear_listener ( self - > listener_update ) ) ) ;
self - > listener_update = n ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-05-11 02:52:03 -04:00
return 0 ;
}
2022-03-07 04:56:41 -05:00
static int listensocket_refsock ( listensocket_t * self , bool prefer_inet6 )
2018-04-18 01:43:46 -04:00
{
if ( ! self )
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
if ( self - > sockrefc ) {
self - > sockrefc + + ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
}
2018-05-11 04:08:38 -04:00
thread_rwlock_rlock ( & self - > listener_rwlock ) ;
2022-03-07 04:56:41 -05:00
self - > sock = sock_get_server_socket ( self - > listener - > port , self - > listener - > bind_address , self - > listener - > bind_address ? false : prefer_inet6 ) ;
2018-05-11 04:08:38 -04:00
thread_rwlock_unlock ( & self - > listener_rwlock ) ;
if ( self - > sock = = SOCK_ERROR ) {
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return - 1 ;
2018-05-11 04:08:38 -04:00
}
2018-04-18 01:43:46 -04:00
2018-09-28 09:52:39 -04:00
if ( __socket_listen ( self - > sock , self - > listener ) = = 0 ) {
2018-04-18 01:43:46 -04:00
sock_close ( self - > sock ) ;
self - > sock = SOCK_ERROR ;
2018-05-11 04:08:38 -04:00
thread_rwlock_rlock ( & self - > listener_rwlock ) ;
2018-05-10 04:25:17 -04:00
ICECAST_LOG_ERROR ( " Can not listen on socket: %s port %i " , __string_default ( self - > listener - > bind_address , " <ANY> " ) , self - > listener - > port ) ;
2018-05-11 04:08:38 -04:00
thread_rwlock_unlock ( & self - > listener_rwlock ) ;
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return - 1 ;
}
2018-05-11 04:08:38 -04:00
if ( listensocket_apply_config__unlocked ( self ) = = - 1 ) {
thread_mutex_unlock ( & self - > lock ) ;
2018-05-10 04:25:17 -04:00
return - 1 ;
2018-05-11 04:08:38 -04:00
}
2018-04-18 01:43:46 -04:00
self - > sockrefc + + ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
}
2022-03-07 04:56:41 -05:00
static int listensocket_unrefsock ( listensocket_t * self )
2018-04-18 01:43:46 -04:00
{
if ( ! self )
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
self - > sockrefc - - ;
2018-05-11 04:08:38 -04:00
if ( self - > sockrefc ) {
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
2018-05-11 04:08:38 -04:00
}
2018-04-18 01:43:46 -04:00
2018-05-11 04:08:38 -04:00
if ( self - > sock = = SOCK_ERROR ) {
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
2018-05-11 04:08:38 -04:00
}
2018-04-18 01:43:46 -04:00
sock_close ( self - > sock ) ;
self - > sock = SOCK_ERROR ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
}
2018-05-18 09:58:51 -04:00
connection_t * listensocket_accept ( listensocket_t * self , listensocket_container_t * container )
2018-04-18 01:43:46 -04:00
{
connection_t * con ;
2018-05-18 09:58:51 -04:00
listensocket_t * effective = NULL ;
2018-04-18 01:43:46 -04:00
sock_t sock ;
char * ip ;
if ( ! self )
return NULL ;
ip = calloc ( MAX_ADDR_LEN , 1 ) ;
if ( ! ip )
return NULL ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
sock = sock_accept ( self - > sock , ip , MAX_ADDR_LEN ) ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
if ( sock = = SOCK_ERROR ) {
free ( ip ) ;
return NULL ;
}
2022-03-07 06:19:21 -05:00
ICECAST_LOG_DEBUG ( " Client (sock=%R, ip=%#H) on socket %p (%#H). " , sock , ip , self , self - > listener - > id ) ;
2018-04-18 01:43:46 -04:00
if ( strncmp ( ip , " ::ffff: " , 7 ) = = 0 ) {
memmove ( ip , ip + 7 , strlen ( ip + 7 ) + 1 ) ;
}
2018-06-30 09:51:42 -04:00
if ( self - > listener - > on_behalf_of ) {
2022-03-07 06:19:21 -05:00
ICECAST_LOG_DEBUG ( " This socket is acting on behalf of %#H " , self - > listener - > on_behalf_of ) ;
2018-06-30 09:51:42 -04:00
effective = listensocket_container_get_by_id ( container , self - > listener - > on_behalf_of ) ;
if ( ! effective ) {
2022-03-07 06:19:21 -05:00
ICECAST_LOG_ERROR ( " Can not find listen socket with ID %#H. Will continue on behalf of myself. " , self - > listener - > on_behalf_of ) ;
2018-06-30 09:51:42 -04:00
}
}
2018-05-18 09:58:51 -04:00
if ( ! effective ) {
effective = self ;
refobject_ref ( effective ) ;
}
con = connection_create ( sock , self , effective , ip ) ;
refobject_unref ( effective ) ;
2018-04-18 01:43:46 -04:00
if ( con = = NULL ) {
sock_close ( sock ) ;
free ( ip ) ;
return NULL ;
}
return con ;
}
const listener_t * listensocket_get_listener ( listensocket_t * self )
{
2018-05-11 04:08:38 -04:00
const listener_t * ret ;
2018-04-18 01:43:46 -04:00
if ( ! self )
return NULL ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
thread_rwlock_rlock ( & self - > listener_rwlock ) ;
ret = self - > listener ;
thread_mutex_unlock ( & self - > lock ) ;
return ret ;
}
int listensocket_release_listener ( listensocket_t * self )
{
if ( ! self )
return - 1 ;
/* This is safe with no self->lock holding as unref requires a wlock.
* A wlock can not be acquired when someone still holds the rlock .
* In fact this must be done in unlocked state as otherwise we could end up in a
* dead lock with some 3 rd party holding the self - > lock for an unrelated operation
* waiting for a wlock to be come available .
* - - ph3 - der - loewe , 2018 - 05 - 11
*/
thread_rwlock_unlock ( & self - > listener_rwlock ) ;
return 0 ;
2018-04-18 01:43:46 -04:00
}
2018-05-18 09:49:15 -04:00
listener_type_t listensocket_get_type ( listensocket_t * self )
{
listener_type_t ret ;
if ( ! self )
return LISTENER_TYPE_ERROR ;
thread_mutex_lock ( & self - > lock ) ;
ret = self - > listener - > type ;
thread_mutex_unlock ( & self - > lock ) ;
return ret ;
}
2022-03-06 13:26:20 -05:00
sock_family_t listensocket_get_family ( listensocket_t * self )
{
sock_family_t ret ;
if ( ! self )
return SOCK_FAMILY__ERROR ;
thread_mutex_lock ( & self - > lock ) ;
ret = sock_get_family ( self - > sock ) ;
thread_mutex_unlock ( & self - > lock ) ;
return ret ;
}
2018-04-18 01:43:46 -04:00
# ifdef HAVE_POLL
2018-05-10 03:10:19 -04:00
static inline int listensocket__poll_fill ( listensocket_t * self , struct pollfd * p )
2018-04-18 01:43:46 -04:00
{
2018-05-11 04:08:38 -04:00
if ( ! self )
2018-04-18 01:43:46 -04:00
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
if ( self - > sock = = SOCK_ERROR ) {
thread_mutex_unlock ( & self - > lock ) ;
return - 1 ;
}
2018-04-18 01:43:46 -04:00
memset ( p , 0 , sizeof ( * p ) ) ;
p - > fd = self - > sock ;
p - > events = POLLIN ;
p - > revents = 0 ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
}
# else
2018-05-10 03:10:19 -04:00
static inline int listensocket__select_set ( listensocket_t * self , fd_set * set , int * max )
2018-04-18 01:43:46 -04:00
{
2018-05-11 04:08:38 -04:00
if ( ! self )
2018-04-18 01:43:46 -04:00
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
if ( self - > sock = = SOCK_ERROR ) {
thread_mutex_unlock ( & self - > lock ) ;
return - 1 ;
}
2018-04-18 01:43:46 -04:00
if ( * max < self - > sock )
* max = self - > sock ;
FD_SET ( self - > sock , set ) ;
2018-05-11 04:08:38 -04:00
thread_mutex_unlock ( & self - > lock ) ;
2018-04-18 01:43:46 -04:00
return 0 ;
}
2018-05-10 03:10:19 -04:00
static inline int listensocket__select_isset ( listensocket_t * self , fd_set * set )
2018-04-18 01:43:46 -04:00
{
2018-05-11 04:08:38 -04:00
int ret ;
if ( ! self )
2018-04-18 01:43:46 -04:00
return - 1 ;
2018-05-11 04:08:38 -04:00
thread_mutex_lock ( & self - > lock ) ;
if ( self - > sock = = SOCK_ERROR ) {
thread_mutex_unlock ( & self - > lock ) ;
return - 1 ;
}
ret = FD_ISSET ( self - > sock , set ) ;
thread_mutex_unlock ( & self - > lock ) ;
return ret ;
2018-04-18 01:43:46 -04:00
}
# endif
2022-03-05 15:34:55 -05:00
/* ---------------------------------------------------------------------------- */
const char * listensocket_type_to_string ( listener_type_t type )
{
switch ( type ) {
case LISTENER_TYPE_ERROR :
return NULL ;
break ;
case LISTENER_TYPE_NORMAL :
return " normal " ;
break ;
case LISTENER_TYPE_VIRTUAL :
return " virtual " ;
break ;
}
return NULL ;
}
const char * listensocket_tlsmode_to_string ( tlsmode_t mode )
{
switch ( mode ) {
case ICECAST_TLSMODE_DISABLED :
return " disabled " ;
break ;
case ICECAST_TLSMODE_AUTO :
return " auto " ;
break ;
case ICECAST_TLSMODE_AUTO_NO_PLAIN :
return " auto_no_plain " ;
break ;
case ICECAST_TLSMODE_RFC2817 :
return " rfc2817 " ;
break ;
case ICECAST_TLSMODE_RFC2818 :
return " rfc2818 " ;
break ;
}
return NULL ;
}