@ -21,7 +21,6 @@
* OTHER DEALINGS IN THE SOFTWARE .
* OTHER DEALINGS IN THE SOFTWARE .
*
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <stdio.h>
# include <stdio.h>
# include <signal.h>
# include <signal.h>
# include <stdbool.h>
# include <stdbool.h>
@ -39,55 +38,195 @@
# include "vtest_protocol.h"
# include "vtest_protocol.h"
static int vtest_open_socket ( const char * path )
struct vtest_program
{
const char * socket_name ;
int socket ;
const char * read_file ;
int out_fd ;
int in_fd ;
bool do_fork ;
bool loop ;
} ;
struct vtest_program prog = {
. socket_name = VTEST_DEFAULT_SOCKET_NAME ,
. socket = - 1 ,
. read_file = NULL ,
. in_fd = - 1 ,
. out_fd = - 1 ,
. do_fork = true ,
. loop = true ,
} ;
static void vtest_main_parse_args ( int argc , char * * argv ) ;
static void vtest_main_set_signal ( void ) ;
static void vtest_main_open_read_file ( void ) ;
static void vtest_main_open_socket ( void ) ;
static void vtest_main_run_renderer ( int in_fd , int out_fd ) ;
static void vtest_main_wait_for_socket_accept ( void ) ;
static void vtest_main_tidy_fds ( void ) ;
static void vtest_main_close_socket ( void ) ;
int main ( int argc , char * * argv )
{
# ifdef __AFL_LOOP
while ( __AFL_LOOP ( 1000 ) ) {
# endif
vtest_main_parse_args ( argc , argv ) ;
if ( prog . read_file ! = NULL ) {
vtest_main_open_read_file ( ) ;
goto start ;
}
if ( prog . do_fork ) {
vtest_main_set_signal ( ) ;
}
vtest_main_open_socket ( ) ;
restart :
vtest_main_wait_for_socket_accept ( ) ;
start :
if ( prog . do_fork ) {
/* fork a renderer process */
if ( fork ( ) = = 0 ) {
vtest_main_run_renderer ( prog . in_fd , prog . out_fd ) ;
exit ( 0 ) ;
}
} else {
vtest_main_run_renderer ( prog . in_fd , prog . out_fd ) ;
}
vtest_main_tidy_fds ( ) ;
if ( prog . loop ) {
goto restart ;
}
vtest_main_close_socket ( ) ;
# ifdef __AFL_LOOP
}
# endif
}
static void vtest_main_parse_args ( int argc , char * * argv )
{
if ( argc > 1 ) {
if ( ! strcmp ( argv [ 1 ] , " --no-loop-or-fork " ) ) {
prog . do_fork = false ;
prog . loop = false ;
} else if ( ! strcmp ( argv [ 1 ] , " --no-fork " ) ) {
prog . do_fork = false ;
} else {
prog . read_file = argv [ 1 ] ;
prog . loop = false ;
prog . do_fork = false ;
}
}
}
static void vtest_main_set_signal ( void )
{
struct sigaction sa ;
int ret ;
sa . sa_handler = SIG_IGN ;
sigemptyset ( & sa . sa_mask ) ;
sa . sa_flags = 0 ;
ret = sigaction ( SIGCHLD , & sa , 0 ) ;
if ( ret = = - 1 ) {
perror ( NULL ) ;
exit ( 1 ) ;
}
}
static void vtest_main_open_read_file ( void )
{
int ret ;
ret = open ( prog . read_file , O_RDONLY ) ;
if ( ret = = - 1 ) {
perror ( NULL ) ;
exit ( 1 ) ;
}
prog . in_fd = ret ;
ret = open ( " /dev/null " , O_WRONLY ) ;
if ( ret = = - 1 ) {
perror ( NULL ) ;
exit ( 1 ) ;
}
prog . out_fd = ret ;
}
static void vtest_main_open_socket ( void )
{
{
struct sockaddr_un un ;
struct sockaddr_un un ;
int sock ;
sock = socket ( PF_UNIX , SOCK_STREAM , 0 ) ;
prog . socket = socket ( PF_UNIX , SOCK_STREAM , 0 ) ;
if ( sock < 0 ) {
if ( prog . socket < 0 ) {
return - 1 ;
goto err ;
}
}
memset ( & un , 0 , sizeof ( un ) ) ;
memset ( & un , 0 , sizeof ( un ) ) ;
un . sun_family = AF_UNIX ;
un . sun_family = AF_UNIX ;
snprintf ( un . sun_path , sizeof ( un . sun_path ) , " %s " , path ) ;
snprintf ( un . sun_path , sizeof ( un . sun_path ) , " %s " , prog . socket_name ) ;
unlink ( un . sun_path ) ;
unlink ( un . sun_path ) ;
if ( bind ( sock , ( struct sockaddr * ) & un , sizeof ( un ) ) < 0 ) {
if ( bind ( prog . socket , ( struct sockaddr * ) & un , sizeof ( un ) ) < 0 ) {
goto err ;
goto err ;
}
}
if ( listen ( sock , 1 ) < 0 ) {
if ( listen ( prog . socket , 1 ) < 0 ) {
goto err ;
goto err ;
}
}
return sock ;
return ;
err :
err :
close ( sock ) ;
perror ( " Failed to setup socket. " ) ;
return - 1 ;
exit ( 1 ) ;
}
}
static int wait_for_socket_accept ( int sock )
static void vtest_main_wait_for_socket_accept ( void )
{
{
fd_set read_fds ;
fd_set read_fds ;
int new_fd ;
int new_fd ;
int ret ;
int ret ;
FD_ZERO ( & read_fds ) ;
FD_ZERO ( & read_fds ) ;
FD_SET ( sock , & read_fds ) ;
FD_SET ( prog . socket , & read_fds ) ;
ret = select ( sock + 1 , & read_fds , NULL , NULL , NULL ) ;
ret = select ( prog . socket + 1 , & read_fds , NULL , NULL , NULL ) ;
if ( ret < 0 ) {
if ( ret < 0 ) {
return ret ;
perror ( " Failed to select on socket! " ) ;
exit ( 1 ) ;
}
if ( ! FD_ISSET ( prog . socket , & read_fds ) ) {
perror ( " Odd state in fd_set. " ) ;
exit ( 1 ) ;
}
}
if ( FD_ISSET ( sock , & read_fds ) ) {
new_fd = accept ( prog . socket , NULL , NULL ) ;
new_fd = accept ( sock , NULL , NULL ) ;
if ( new_fd < 0 ) {
return new_fd ;
perror ( " Failed to accept socket. " ) ;
exit ( 1 ) ;
}
}
return - 1 ;
prog . in_fd = new_fd ;
prog . out_fd = new_fd ;
}
}
typedef int ( * vtest_cmd_fptr_t ) ( uint32_t ) ;
typedef int ( * vtest_cmd_fptr_t ) ( uint32_t ) ;
@ -110,7 +249,7 @@ static const vtest_cmd_fptr_t vtest_commands[] = {
vtest_transfer_put2 ,
vtest_transfer_put2 ,
} ;
} ;
static int run_renderer ( int in_fd , int out_fd )
static void vtest_main_ run_renderer( int in_fd , int out_fd )
{
{
int err , ret ;
int err , ret ;
uint32_t header [ VTEST_HDR_SIZE ] ;
uint32_t header [ VTEST_HDR_SIZE ] ;
@ -164,94 +303,30 @@ static int run_renderer(int in_fd, int out_fd)
fprintf ( stderr , " socket failed (%d) - closing renderer \n " , err ) ;
fprintf ( stderr , " socket failed (%d) - closing renderer \n " , err ) ;
vtest_destroy_renderer ( ) ;
vtest_destroy_renderer ( ) ;
close ( in_fd ) ;
return 0 ;
}
}
int main ( int argc , char * * argv )
static void vtest_main_tidy_fds ( void )
{
{
int ret , sock = - 1 , in_fd , out_fd ;
// out_fd will be closed by the in_fd clause if they are the same.
pid_t pid ;
if ( prog . out_fd = = prog . in_fd ) {
bool do_fork = true , loop = true ;
prog . out_fd = - 1 ;
struct sigaction sa ;
char * socket_name = VTEST_DEFAULT_SOCKET_NAME ;
# ifdef __AFL_LOOP
while ( __AFL_LOOP ( 1000 ) ) {
# endif
if ( argc > 1 ) {
if ( ! strcmp ( argv [ 1 ] , " --no-loop-or-fork " ) ) {
do_fork = false ;
loop = false ;
} else if ( ! strcmp ( argv [ 1 ] , " --no-fork " ) ) {
do_fork = false ;
} else {
ret = open ( argv [ 1 ] , O_RDONLY ) ;
if ( ret = = - 1 ) {
perror ( 0 ) ;
exit ( 1 ) ;
}
in_fd = ret ;
ret = open ( " /dev/null " , O_WRONLY ) ;
if ( ret = = - 1 ) {
perror ( 0 ) ;
exit ( 1 ) ;
}
out_fd = ret ;
loop = false ;
do_fork = false ;
goto start ;
}
}
}
if ( do_fork ) {
if ( prog . in_fd ! = - 1 ) {
sa . sa_handler = SIG_IGN ;
close ( prog . in_fd ) ;
sigemptyset ( & sa . sa_mask ) ;
prog . in_fd = - 1 ;
sa . sa_flags = 0 ;
if ( sigaction ( SIGCHLD , & sa , 0 ) = = - 1 ) {
perror ( 0 ) ;
exit ( 1 ) ;
}
}
}
sock = vtest_open_socket ( socket_name ) ;
if ( prog . out_fd ! = - 1 ) {
restart :
close ( prog . out_fd ) ;
in_fd = wait_for_socket_accept ( sock ) ;
prog . out_fd = - 1 ;
out_fd = in_fd ;
start :
if ( do_fork ) {
/* fork a renderer process */
switch ( ( pid = fork ( ) ) ) {
case 0 :
run_renderer ( in_fd , out_fd ) ;
exit ( 0 ) ;
break ;
case - 1 :
default :
close ( in_fd ) ;
if ( loop ) {
goto restart ;
}
}
} else {
run_renderer ( in_fd , out_fd ) ;
vtest_destroy_renderer ( ) ;
if ( loop ) {
goto restart ;
}
}
}
}
if ( sock ! = - 1 ) {
static void vtest_main_close_socket ( void )
close ( sock ) ;
{
}
if ( prog . socket ! = - 1 ) {
if ( in_fd ! = out_fd ) {
close ( prog . socket ) ;
close ( out_fd ) ;
prog . socket = - 1 ;
}
}
# ifdef __AFL_LOOP
}
# endif
}
}