2010-01-13 10:19:24 +03:00
# include <pthread.h>
# include <unistd.h>
# include <stdio.h>
# include <list.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <stdlib.h>
2010-01-13 18:04:31 +03:00
# include <debug.h>
2010-01-13 18:53:55 +03:00
# include <simpleconfig.h>
2010-01-15 03:56:32 +03:00
# include <errno.h>
# include <fcntl.h>
2010-01-13 10:19:24 +03:00
2010-01-13 18:53:55 +03:00
# include "serial.h"
2010-01-13 10:19:24 +03:00
struct socket_list {
list_head ( ) ;
char * domain_name ;
char * socket_path ;
int socket_fd ;
} ;
static struct socket_list * socks = NULL ;
static pthread_mutex_t sock_list_mutex = PTHREAD_MUTEX_INITIALIZER ;
2010-01-15 03:56:32 +03:00
static int
connect_nb ( int fd , struct sockaddr * dest , socklen_t len , int timeout )
{
int ret , flags , err ;
unsigned l ;
fd_set rfds , wfds ;
struct timeval tv ;
/*
Set up non - blocking connect
*/
flags = fcntl ( fd , F_GETFL , 0 ) ;
fcntl ( fd , F_SETFL , flags | O_NONBLOCK ) ;
ret = connect ( fd , dest , len ) ;
if ( ( ret < 0 ) & & ( errno ! = EINPROGRESS ) )
return - 1 ;
if ( ret = = 0 )
2010-01-15 03:58:16 +03:00
goto done ;
2010-01-15 03:56:32 +03:00
FD_ZERO ( & rfds ) ;
FD_SET ( fd , & rfds ) ;
FD_ZERO ( & wfds ) ;
FD_SET ( fd , & wfds ) ;
tv . tv_sec = timeout ;
tv . tv_usec = 0 ;
if ( select ( fd + 1 , & rfds , & wfds , NULL , & tv ) = = 0 ) {
errno = ETIMEDOUT ;
return - 1 ;
}
if ( ! FD_ISSET ( fd , & rfds ) & & ! FD_ISSET ( fd , & wfds ) ) {
errno = EIO ;
return - 1 ;
}
l = sizeof ( err ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_ERROR ,
( void * ) & err , & l ) < 0 ) {
return - 1 ;
}
if ( err ! = 0 ) {
errno = err ;
return - 1 ;
}
2010-01-15 03:58:16 +03:00
done :
2010-01-15 03:56:32 +03:00
fcntl ( fd , F_SETFL , flags ) ;
return 0 ;
}
2010-01-13 10:19:24 +03:00
int
domain_sock_setup ( const char * domain , const char * socket_path )
{
struct sockaddr_un * sun = NULL ;
struct socket_list * node = NULL ;
socklen_t sun_len ;
int sock = - 1 ;
sun_len = sizeof ( * sun ) + strlen ( socket_path ) + 1 ;
sun = malloc ( sun_len ) ;
if ( ! sun )
return - 1 ;
memset ( ( char * ) sun , 0 , sun_len ) ;
sun - > sun_family = PF_LOCAL ;
strncpy ( sun - > sun_path , socket_path , sun_len - sizeof ( * sun ) ) ;
sock = socket ( PF_LOCAL , SOCK_STREAM , 0 ) ;
if ( sock < 0 )
goto out_fail ;
2010-01-15 03:56:32 +03:00
if ( connect_nb ( sock , ( struct sockaddr * ) sun , SUN_LEN ( sun ) , 3 ) < 0 )
2010-01-13 10:19:24 +03:00
goto out_fail ;
2010-01-15 02:46:21 +03:00
free ( sun ) ;
sun = NULL ;
2012-10-17 19:34:43 +04:00
node = calloc ( 1 , sizeof ( * node ) ) ;
2010-01-13 10:19:24 +03:00
if ( ! node )
goto out_fail ;
node - > domain_name = strdup ( domain ) ;
if ( ! node - > domain_name )
goto out_fail ;
node - > socket_path = strdup ( socket_path ) ;
if ( ! node - > socket_path )
goto out_fail ;
node - > socket_fd = sock ;
pthread_mutex_lock ( & sock_list_mutex ) ;
list_insert ( & socks , node ) ;
pthread_mutex_unlock ( & sock_list_mutex ) ;
2010-01-13 18:04:31 +03:00
dbg_printf ( 3 , " Registered %s on %d \n " , domain , sock ) ;
2010-01-13 10:19:24 +03:00
return 0 ;
out_fail :
2011-09-20 19:40:39 +04:00
if ( node ) {
2010-01-13 10:19:24 +03:00
free ( node - > domain_name ) ;
2011-09-20 19:40:39 +04:00
if ( node - > socket_path )
free ( node - > socket_path ) ;
free ( node ) ;
}
2010-01-13 10:19:24 +03:00
free ( sun ) ;
if ( sock > = 0 )
close ( sock ) ;
return - 1 ;
}
int
domain_sock_close ( const char * domain )
{
struct socket_list * node = NULL ;
struct socket_list * dead = NULL ;
int x ;
pthread_mutex_lock ( & sock_list_mutex ) ;
list_for ( & socks , node , x ) {
if ( ! strcasecmp ( domain , node - > domain_name ) ) {
list_remove ( & socks , node ) ;
dead = node ;
break ;
}
}
pthread_mutex_unlock ( & sock_list_mutex ) ;
if ( dead ) {
2010-01-13 18:04:31 +03:00
dbg_printf ( 3 , " Unregistered %s, fd%d \n " ,
dead - > domain_name ,
dead - > socket_fd ) ;
2010-01-13 10:19:24 +03:00
close ( dead - > socket_fd ) ;
free ( dead - > domain_name ) ;
free ( dead - > socket_path ) ;
2010-01-13 18:53:55 +03:00
free ( dead ) ;
2010-01-13 10:19:24 +03:00
}
return 0 ;
}
int
domain_sock_fdset ( fd_set * fds , int * max )
{
struct socket_list * node = NULL ;
int x = 0 , _max = - 1 ;
pthread_mutex_lock ( & sock_list_mutex ) ;
list_for ( & socks , node , x ) {
FD_SET ( node - > socket_fd , fds ) ;
if ( node - > socket_fd > _max )
_max = node - > socket_fd ;
}
pthread_mutex_unlock ( & sock_list_mutex ) ;
if ( max )
* max = _max ;
return x ;
}
2010-01-13 17:26:32 +03:00
int
domain_sock_name ( int fd , char * outbuf , size_t buflen )
{
struct socket_list * node = NULL ;
int ret = 1 , x = 0 ;
pthread_mutex_lock ( & sock_list_mutex ) ;
list_for ( & socks , node , x ) {
if ( node - > socket_fd = = fd ) {
snprintf ( outbuf , buflen , " %s " , node - > domain_name ) ;
ret = 0 ;
break ;
}
}
pthread_mutex_unlock ( & sock_list_mutex ) ;
return ret ;
}
2010-01-13 18:53:55 +03:00
int
domain_sock_cleanup ( void )
{
struct socket_list * dead = NULL ;
pthread_mutex_lock ( & sock_list_mutex ) ;
while ( socks ) {
dead = socks ;
list_remove ( & socks , dead ) ;
close ( dead - > socket_fd ) ;
free ( dead - > domain_name ) ;
free ( dead - > socket_path ) ;
free ( dead ) ;
}
pthread_mutex_unlock ( & sock_list_mutex ) ;
return 0 ;
}