2016-02-15 20:01:48 +00:00
# include <stdio.h>
# include <assert.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <sys/epoll.h>
2016-02-15 21:12:26 +00:00
# include <string.h>
2016-02-17 08:05:18 +00:00
# include <errno.h>
2016-02-15 20:01:48 +00:00
# include "airspy_adsb.h"
2016-02-16 03:42:41 +00:00
# include "beast.h"
2016-02-16 02:28:05 +00:00
# include "client.h"
2016-02-15 20:01:48 +00:00
# include "backend.h"
2016-02-17 08:05:18 +00:00
static bool backend_autodetect_parse ( struct backend * , struct packet * ) ;
static void backend_connect ( struct backend * , int ) ;
static void backend_connect_next ( struct backend * , int ) ;
static void backend_connect_handler ( struct peer * , int ) ;
static void backend_read ( struct peer * , int ) ;
2016-02-15 21:12:26 +00:00
2016-02-15 20:01:48 +00:00
static parser parsers [ ] = {
airspy_adsb_parse ,
2016-02-16 03:42:41 +00:00
beast_parse ,
2016-02-15 20:01:48 +00:00
} ;
# define NUM_PARSERS (sizeof(parsers) / sizeof(*parsers))
2016-02-17 08:05:18 +00:00
struct backend * backend_new ( char * node , char * service , int epoll_fd ) {
struct backend * backend = malloc ( sizeof ( * backend ) ) ;
assert ( backend ) ;
backend - > peer . fd = - 1 ;
uuid_gen ( backend - > id ) ;
backend - > node = node ;
backend - > service = service ;
2016-02-15 21:12:26 +00:00
buf_init ( & backend - > buf ) ;
memset ( backend - > parser_state , 0 , PARSER_STATE_LEN ) ;
backend - > parser = backend_autodetect_parse ;
2016-02-17 08:05:18 +00:00
backend_connect ( backend , epoll_fd ) ;
return backend ;
2016-02-15 21:12:26 +00:00
}
2016-02-17 08:05:18 +00:00
static void backend_connect ( struct backend * backend , int epoll_fd ) {
fprintf ( stderr , " B %s: Connecting to %s %s... \n " , backend - > id , backend - > node , backend - > service ) ;
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
struct addrinfo hints = {
. ai_family = AF_UNSPEC ,
. ai_socktype = SOCK_STREAM ,
} ;
2016-02-15 21:22:23 +00:00
2016-02-17 08:05:18 +00:00
int gai_err = getaddrinfo ( backend - > node , backend - > service , & hints , & backend - > addrs ) ;
if ( gai_err ) {
fprintf ( stderr , " B %s: getaddrinfo(%s %s): %s \n " , backend - > id , backend - > node , backend - > service , gai_strerror ( gai_err ) ) ;
return ;
}
backend - > addr = backend - > addrs ;
backend_connect_next ( backend , epoll_fd ) ;
}
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
static void backend_connect_result ( struct backend * backend , int epoll_fd , int result ) {
char hbuf [ NI_MAXHOST ] , sbuf [ NI_MAXSERV ] ;
assert ( getnameinfo ( backend - > addr - > ai_addr , backend - > addr - > ai_addrlen , hbuf , sizeof ( hbuf ) , sbuf , sizeof ( sbuf ) , NI_NUMERICHOST | NI_NUMERICSERV ) = = 0 ) ;
switch ( result ) {
case 0 :
fprintf ( stderr , " B %s: Connected to %s %s \n " , backend - > id , hbuf , sbuf ) ;
freeaddrinfo ( backend - > addrs ) ;
backend - > peer . event_handler = backend_read ;
peer_epoll_add ( ( struct peer * ) backend , epoll_fd , EPOLLIN ) ;
break ;
case EINPROGRESS :
backend - > peer . event_handler = backend_connect_handler ;
peer_epoll_add ( ( struct peer * ) backend , epoll_fd , EPOLLOUT ) ;
break ;
default :
fprintf ( stderr , " B %s: Can't connect to %s %s: %s \n " , backend - > id , hbuf , sbuf , strerror ( result ) ) ;
close ( backend - > peer . fd ) ;
backend - > addr = backend - > addr - > ai_next ;
// Tail recursion :/
backend_connect_next ( backend , epoll_fd ) ;
break ;
}
}
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
static void backend_connect_next ( struct backend * backend , int epoll_fd ) {
if ( backend - > addr = = NULL ) {
freeaddrinfo ( backend - > addrs ) ;
fprintf ( stderr , " B %s: Can't connect to %s %s \n " , backend - > id , backend - > node , backend - > service ) ;
return ;
2016-02-15 20:01:48 +00:00
}
2016-02-17 08:05:18 +00:00
char hbuf [ NI_MAXHOST ] , sbuf [ NI_MAXSERV ] ;
assert ( getnameinfo ( backend - > addr - > ai_addr , backend - > addr - > ai_addrlen , hbuf , sizeof ( hbuf ) , sbuf , sizeof ( sbuf ) , NI_NUMERICHOST | NI_NUMERICSERV ) = = 0 ) ;
fprintf ( stderr , " B %s: Connecting to %s %s... \n " , backend - > id , hbuf , sbuf ) ;
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
backend - > peer . fd = socket ( backend - > addr - > ai_family , backend - > addr - > ai_socktype | SOCK_NONBLOCK , backend - > addr - > ai_protocol ) ;
assert ( backend - > peer . fd > = 0 ) ;
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
int result = connect ( backend - > peer . fd , backend - > addr - > ai_addr , backend - > addr - > ai_addrlen ) ;
backend_connect_result ( backend , epoll_fd , result = = 0 ? result : errno ) ;
}
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
static void backend_connect_handler ( struct peer * peer , int epoll_fd ) {
struct backend * backend = ( struct backend * ) peer ;
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
peer_epoll_del ( peer , epoll_fd ) ;
2016-02-15 20:01:48 +00:00
2016-02-17 08:05:18 +00:00
int error ;
socklen_t len = sizeof ( error ) ;
assert ( getsockopt ( backend - > peer . fd , SOL_SOCKET , SO_ERROR , & error , & len ) = = 0 ) ;
backend_connect_result ( backend , epoll_fd , error ) ;
2016-02-15 20:01:48 +00:00
}
2016-02-17 08:05:18 +00:00
static void backend_read ( struct peer * peer , int epoll_fd ) {
struct backend * backend = ( struct backend * ) peer ;
if ( buf_fill ( & backend - > buf , backend - > peer . fd ) < 0 ) {
2016-02-17 00:21:28 +00:00
fprintf ( stderr , " B %s: Connection closed by backend \n " , backend - > id ) ;
2016-02-17 08:05:18 +00:00
close ( backend - > peer . fd ) ;
peer_epoll_del ( peer , epoll_fd ) ;
// TODO: reconnect
return ;
2016-02-15 20:01:48 +00:00
}
2016-02-17 00:21:28 +00:00
struct packet packet = {
. backend = backend ,
} ;
2016-02-15 20:01:48 +00:00
while ( backend - > parser ( backend , & packet ) ) {
2016-02-16 02:28:05 +00:00
client_write ( & packet ) ;
2016-02-15 20:01:48 +00:00
}
if ( backend - > buf . length = = BUF_LEN_MAX ) {
2016-02-17 00:21:28 +00:00
fprintf ( stderr , " B %s: Input buffer overrun. This probably means that adsbus doesn't understand the protocol that this source is speaking. \n " , backend - > id ) ;
2016-02-17 08:05:18 +00:00
close ( backend - > peer . fd ) ;
peer_epoll_del ( peer , epoll_fd ) ;
// TODO: reconnect
return ;
2016-02-15 20:01:48 +00:00
}
}
2016-02-17 08:05:18 +00:00
static bool backend_autodetect_parse ( struct backend * backend , struct packet * packet ) {
2016-02-15 20:01:48 +00:00
for ( int i = 0 ; i < NUM_PARSERS ; i + + ) {
if ( parsers [ i ] ( backend , packet ) ) {
backend - > parser = parsers [ i ] ;
return true ;
}
}
return false ;
}