2011-02-23 20:48:06 +00:00
// (c) 2011 Thomas Schoebel-Theuer / 1&1 Internet AG
//#define BRICK_DEBUGGING
//#define MARS_DEBUGGING
//#define IO_DEBUGGING
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/string.h>
2012-01-19 15:57:10 +00:00
# include <linux/kthread.h>
2011-02-23 20:48:06 +00:00
# include "mars.h"
# include "mars_net.h"
2011-07-22 10:43:40 +00:00
static
void mars_check_meta ( const struct meta * meta , void * data ) ;
2011-02-23 20:48:06 +00:00
/* Low-level network traffic
*/
/* TODO: allow binding to specific source addresses instead of catch-all.
* TODO : make all the socket options configurable .
* TODO : implement signal handling .
* TODO : add authentication .
* TODO : add compression / encryption .
*/
struct mars_tcp_params default_tcp_params = {
. window_size = 8 * 1024 * 1024 , // for long distance replications
. tcp_timeout = 20 ,
. tcp_keepcnt = 6 ,
. tcp_keepintvl = 10 , // keepalive ping time
. tcp_keepidle = 10 ,
. tos = IPTOS_LOWDELAY ,
} ;
EXPORT_SYMBOL ( default_tcp_params ) ;
2012-01-11 11:35:09 +00:00
static
void _check ( int status )
2011-02-23 20:48:06 +00:00
{
if ( status < 0 ) {
2011-07-20 13:11:44 +00:00
MARS_WRN ( " cannot set socket option, status = %d \n " , status ) ;
2011-02-23 20:48:06 +00:00
}
}
int mars_create_sockaddr ( struct sockaddr_storage * addr , const char * spec )
{
struct sockaddr_in * sockaddr = ( void * ) addr ;
2011-02-27 14:17:58 +00:00
char * new_spec ;
char * tmp_spec ;
int status = 0 ;
2011-07-28 11:41:06 +00:00
memset ( addr , 0 , sizeof ( * addr ) ) ;
2011-02-23 20:48:06 +00:00
sockaddr - > sin_family = AF_INET ;
sockaddr - > sin_port = htons ( MARS_DEFAULT_PORT ) ;
2011-02-27 14:17:58 +00:00
/* Try to translate hostnames to IPs if possible.
*/
2011-07-22 10:43:40 +00:00
if ( mars_translate_hostname ) {
new_spec = mars_translate_hostname ( spec ) ;
} else {
2011-08-12 11:09:48 +00:00
new_spec = brick_strdup ( spec ) ;
2011-07-22 10:43:40 +00:00
}
2011-02-27 14:17:58 +00:00
tmp_spec = new_spec ;
2011-02-23 20:48:06 +00:00
/* This is PROVISIONARY!
* TODO : add IPV6 syntax and many more features : )
*/
2011-02-27 14:17:58 +00:00
if ( ! * tmp_spec )
goto done ;
if ( * tmp_spec ! = ' : ' ) {
2011-02-23 20:48:06 +00:00
unsigned char u0 = 0 , u1 = 0 , u2 = 0 , u3 = 0 ;
2011-02-27 14:17:58 +00:00
status = sscanf ( tmp_spec , " %hhu.%hhu.%hhu.%hhu " , & u0 , & u1 , & u2 , & u3 ) ;
if ( status ! = 4 ) {
status = - EINVAL ;
goto done ;
}
2011-02-23 20:48:06 +00:00
sockaddr - > sin_addr . s_addr = ( __be32 ) u0 | ( __be32 ) u1 < < 8 | ( __be32 ) u2 < < 16 | ( __be32 ) u3 < < 24 ;
}
2011-02-27 14:17:58 +00:00
while ( * tmp_spec & & * tmp_spec + + ! = ' : ' )
2011-02-23 20:48:06 +00:00
/*empty*/ ;
2011-02-27 14:17:58 +00:00
if ( * tmp_spec ) {
2011-02-23 20:48:06 +00:00
int port = 0 ;
2011-02-27 14:17:58 +00:00
status = sscanf ( tmp_spec , " %d " , & port ) ;
if ( status ! = 1 ) {
status = - EINVAL ;
goto done ;
}
2011-02-23 20:48:06 +00:00
sockaddr - > sin_port = htons ( port ) ;
}
2011-02-27 14:17:58 +00:00
status = 0 ;
done :
2011-08-12 11:09:48 +00:00
brick_string_free ( new_spec ) ;
2011-02-27 14:17:58 +00:00
return status ;
2011-02-23 20:48:06 +00:00
}
EXPORT_SYMBOL_GPL ( mars_create_sockaddr ) ;
2012-01-11 11:35:09 +00:00
static int current_debug_nr = 0 ; // no locking, just for debugging
2011-08-31 11:42:04 +00:00
2012-01-18 14:33:39 +00:00
static
void _set_socketopts ( struct socket * sock )
{
int x_true = 1 ;
int status ;
/* TODO: improve this by a table-driven approach
*/
sock - > sk - > sk_rcvtimeo = sock - > sk - > sk_sndtimeo = default_tcp_params . tcp_timeout * HZ ;
sock - > sk - > sk_reuse = 1 ;
status = kernel_setsockopt ( sock , SOL_SOCKET , SO_SNDBUF , ( char * ) & default_tcp_params . window_size , sizeof ( default_tcp_params . window_size ) ) ;
_check ( status ) ;
status = kernel_setsockopt ( sock , SOL_SOCKET , SO_RCVBUF , ( char * ) & default_tcp_params . window_size , sizeof ( default_tcp_params . window_size ) ) ;
_check ( status ) ;
status = kernel_setsockopt ( sock , SOL_IP , SO_PRIORITY , ( char * ) & default_tcp_params . tos , sizeof ( default_tcp_params . tos ) ) ;
_check ( status ) ;
#if 0
status = kernel_setsockopt ( sock , IPPROTO_TCP , TCP_NODELAY , ( char * ) & x_true , sizeof ( x_true ) ) ;
# endif
_check ( status ) ;
status = kernel_setsockopt ( sock , SOL_SOCKET , SO_KEEPALIVE , ( char * ) & x_true , sizeof ( x_true ) ) ;
_check ( status ) ;
status = kernel_setsockopt ( sock , IPPROTO_TCP , TCP_KEEPCNT , ( char * ) & default_tcp_params . tcp_keepcnt , sizeof ( default_tcp_params . tcp_keepcnt ) ) ;
_check ( status ) ;
status = kernel_setsockopt ( sock , IPPROTO_TCP , TCP_KEEPINTVL , ( char * ) & default_tcp_params . tcp_keepintvl , sizeof ( default_tcp_params . tcp_keepintvl ) ) ;
_check ( status ) ;
status = kernel_setsockopt ( sock , IPPROTO_TCP , TCP_KEEPIDLE , ( char * ) & default_tcp_params . tcp_keepidle , sizeof ( default_tcp_params . tcp_keepidle ) ) ;
_check ( status ) ;
# if 1
{
struct timeval t = {
. tv_sec = default_tcp_params . tcp_timeout ,
} ;
status = kernel_setsockopt ( sock , SOL_SOCKET , SO_SNDTIMEO , ( char * ) & t , sizeof ( t ) ) ;
status = kernel_setsockopt ( sock , SOL_SOCKET , SO_RCVTIMEO , ( char * ) & t , sizeof ( t ) ) ;
_check ( status ) ;
}
# endif
#if 0 // do not use for now
if ( ! do_block & & sock - > file ) { // switch back to blocking mode
sock - > file - > f_flags & = ~ O_NONBLOCK ;
}
# endif
}
2012-01-11 11:35:09 +00:00
int mars_create_socket ( struct mars_socket * msock , struct sockaddr_storage * addr , bool is_server )
2011-02-23 20:48:06 +00:00
{
2011-08-31 11:42:04 +00:00
struct socket * sock ;
2011-02-23 20:48:06 +00:00
struct sockaddr * sockaddr = ( void * ) addr ;
2012-01-11 11:35:09 +00:00
int status = - EEXIST ;
2011-02-23 20:48:06 +00:00
2012-01-11 11:35:09 +00:00
if ( unlikely ( atomic_read ( & msock - > s_count ) ) ) {
MARS_WRN ( " #%d socket already in use \n " , msock - > s_debug_nr ) ;
goto final ;
}
if ( unlikely ( msock - > s_socket ) ) {
MARS_WRN ( " #%d socket already open \n " , msock - > s_debug_nr ) ;
goto final ;
}
2011-08-31 11:42:04 +00:00
status = sock_create_kern ( AF_INET , SOCK_STREAM , IPPROTO_TCP , & msock - > s_socket ) ;
if ( unlikely ( status < 0 ) ) {
2012-01-11 11:35:09 +00:00
msock - > s_socket = NULL ;
2011-08-31 11:42:04 +00:00
MARS_WRN ( " cannot create socket, status = %d \n " , status ) ;
2012-01-11 11:35:09 +00:00
goto final ;
2011-08-31 11:42:04 +00:00
}
atomic_set ( & msock - > s_count , 1 ) ;
2012-01-11 11:35:09 +00:00
msock - > s_debug_nr = + + current_debug_nr ;
2011-08-31 11:42:04 +00:00
sock = msock - > s_socket ;
CHECK_PTR ( sock , done ) ;
2012-01-18 14:33:39 +00:00
_set_socketopts ( sock ) ;
2011-02-23 20:48:06 +00:00
2011-03-04 15:14:20 +00:00
if ( is_server ) {
2011-08-31 11:42:04 +00:00
status = kernel_bind ( sock , sockaddr , sizeof ( * sockaddr ) ) ;
2011-03-04 15:14:20 +00:00
if ( unlikely ( status < 0 ) ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d bind failed, status = %d \n " , msock - > s_debug_nr , status ) ;
2011-03-04 15:14:20 +00:00
goto done ;
}
2011-08-31 11:42:04 +00:00
status = kernel_listen ( sock , 16 ) ;
2011-03-04 15:14:20 +00:00
if ( status < 0 ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d listen failed, status = %d \n " , msock - > s_debug_nr , status ) ;
2011-03-04 15:14:20 +00:00
}
} else {
2011-08-31 11:42:04 +00:00
status = kernel_connect ( sock , sockaddr , sizeof ( * sockaddr ) , 0 ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 ) {
2012-01-11 11:35:09 +00:00
MARS_DBG ( " #%d connect failed, status = %d \n " , msock - > s_debug_nr , status ) ;
2011-02-23 20:48:06 +00:00
}
}
2011-03-04 15:14:20 +00:00
done :
2011-08-31 11:42:04 +00:00
if ( status < 0 ) {
mars_put_socket ( msock ) ;
2012-01-11 11:35:09 +00:00
} else {
MARS_DBG ( " successfully created socket #%d \n " , msock - > s_debug_nr ) ;
2011-08-31 11:42:04 +00:00
}
2012-01-11 11:35:09 +00:00
final :
return status ;
2011-02-23 20:48:06 +00:00
}
EXPORT_SYMBOL_GPL ( mars_create_socket ) ;
2012-01-19 12:09:22 +00:00
int mars_accept_socket ( struct mars_socket * new_msock , struct mars_socket * old_msock )
2011-08-31 11:42:04 +00:00
{
int status = - ENOENT ;
2012-01-11 11:35:09 +00:00
struct socket * new_socket = NULL ;
bool ok ;
2011-08-31 11:42:04 +00:00
2012-01-11 11:35:09 +00:00
ok = mars_get_socket ( old_msock ) ;
if ( likely ( ok ) ) {
2012-01-19 15:57:10 +00:00
status = kernel_accept ( old_msock - > s_socket , & new_socket , O_NONBLOCK ) ;
2011-08-31 11:42:04 +00:00
if ( unlikely ( status < 0 ) ) {
goto err ;
}
2011-11-03 16:23:34 +00:00
if ( unlikely ( ! new_socket ) ) {
2011-11-03 11:17:59 +00:00
status = - EBADF ;
goto err ;
}
2012-01-11 11:35:09 +00:00
MARS_IO ( " old#%d status = %d file = %p flags = 0x%x \n " , old_msock - > s_debug_nr , status , new_socket - > file , new_socket - > file ? new_socket - > file - > f_flags : 0 ) ;
2012-01-18 14:33:39 +00:00
_set_socketopts ( new_socket ) ;
2012-01-11 11:35:09 +00:00
memset ( new_msock , 0 , sizeof ( struct mars_socket ) ) ;
2011-08-31 11:42:04 +00:00
new_msock - > s_socket = new_socket ;
2012-01-11 11:35:09 +00:00
atomic_set ( & new_msock - > s_count , 1 ) ;
new_msock - > s_debug_nr = + + current_debug_nr ;
MARS_DBG ( " #%d successfully accepted socket #%d \n " , old_msock - > s_debug_nr , new_msock - > s_debug_nr ) ;
status = 0 ;
2011-08-31 11:42:04 +00:00
err :
2012-01-11 11:35:09 +00:00
mars_put_socket ( old_msock ) ;
}
return status ;
2011-08-31 11:42:04 +00:00
}
EXPORT_SYMBOL_GPL ( mars_accept_socket ) ;
2012-01-11 11:35:09 +00:00
bool mars_get_socket ( struct mars_socket * msock )
2011-08-31 11:42:04 +00:00
{
2012-01-11 11:35:09 +00:00
MARS_IO ( " try socket #%d %p s_dead = %d s_count=%d \n " , msock - > s_debug_nr , msock - > s_socket , msock - > s_dead , atomic_read ( & msock - > s_count ) ) ;
if ( unlikely ( atomic_read ( & msock - > s_count ) < = 0 ) )
return false ;
atomic_inc ( & msock - > s_count ) ;
if ( unlikely ( ! msock - > s_socket | | msock - > s_dead ) ) {
mars_put_socket ( msock ) ;
return false ;
2011-08-31 11:42:04 +00:00
}
2012-01-11 11:35:09 +00:00
MARS_IO ( " got socket #%d \n " , msock - > s_debug_nr ) ;
return true ;
2011-08-31 11:42:04 +00:00
}
EXPORT_SYMBOL_GPL ( mars_get_socket ) ;
void mars_put_socket ( struct mars_socket * msock )
{
2012-01-11 11:35:09 +00:00
MARS_IO ( " try socket #%d %p s_dead = %d s_count=%d \n " , msock - > s_debug_nr , msock - > s_socket , msock - > s_dead , atomic_read ( & msock - > s_count ) ) ;
if ( unlikely ( atomic_read ( & msock - > s_count ) < = 0 ) ) {
MARS_ERR ( " bad nesting on msock = %p \n " , msock ) ;
} else if ( atomic_dec_and_test ( & msock - > s_count ) ) {
struct socket * sock = msock - > s_socket ;
MARS_DBG ( " closing socket #%d %p \n " , msock - > s_debug_nr , sock ) ;
if ( likely ( sock ) ) {
kernel_sock_shutdown ( sock , SHUT_WR ) ;
sock_release ( sock ) ;
2011-08-31 11:42:04 +00:00
}
2012-01-11 11:35:09 +00:00
memset ( msock , 0 , sizeof ( struct mars_socket ) ) ;
2011-08-31 11:42:04 +00:00
}
}
EXPORT_SYMBOL_GPL ( mars_put_socket ) ;
void mars_shutdown_socket ( struct mars_socket * msock )
{
2012-01-11 11:35:09 +00:00
struct socket * sock = msock - > s_socket ;
MARS_IO ( " try socket #%d %p s_dead = %d s_count=%d \n " , msock - > s_debug_nr , msock - > s_socket , msock - > s_dead , atomic_read ( & msock - > s_count ) ) ;
if ( likely ( sock ) ) {
if ( unlikely ( atomic_read ( & msock - > s_count ) < = 0 ) ) {
MARS_ERR ( " bad nesting on msock = %p sock = %p \n " , msock , sock ) ;
}
if ( ! msock - > s_dead ) {
2011-08-31 11:42:04 +00:00
msock - > s_dead = true ;
2012-01-11 11:35:09 +00:00
MARS_DBG ( " shutdown socket #%d %p \n " , msock - > s_debug_nr , sock ) ;
2011-08-31 11:42:04 +00:00
kernel_sock_shutdown ( sock , SHUT_WR ) ;
}
}
}
EXPORT_SYMBOL_GPL ( mars_shutdown_socket ) ;
bool mars_socket_is_alive ( struct mars_socket * msock )
{
2012-01-11 11:35:09 +00:00
bool res = false ;
if ( ! msock - > s_socket )
goto done ;
if ( unlikely ( atomic_read ( & msock - > s_count ) < = 0 ) ) {
MARS_ERR ( " bad nesting on msock = %p \n " , msock ) ;
goto done ;
}
if ( msock - > s_dead )
goto done ;
res = true ;
done :
MARS_IO ( " #%d %p s_count = %d s_dead = %d \n " , msock - > s_debug_nr , msock - > s_socket , atomic_read ( & msock - > s_count ) , msock - > s_dead ) ;
return res ;
2011-08-31 11:42:04 +00:00
}
EXPORT_SYMBOL_GPL ( mars_socket_is_alive ) ;
2012-01-11 11:35:09 +00:00
int mars_send_raw ( struct mars_socket * msock , void * buf , int len , bool cork )
2011-02-23 20:48:06 +00:00
{
struct kvec iov = {
. iov_base = buf ,
. iov_len = len ,
} ;
struct msghdr msg = {
. msg_iov = ( struct iovec * ) & iov ,
2011-07-08 07:02:14 +00:00
. msg_flags = 0 | MSG_NOSIGNAL ,
2011-02-23 20:48:06 +00:00
} ;
int status = - EIDRM ;
int sent = 0 ;
2011-08-31 11:42:04 +00:00
if ( ! mars_get_socket ( msock ) )
2012-01-11 11:35:09 +00:00
goto final ;
#if 0 // leads to obscure effects (short reads at other end)
if ( cork )
msg . msg_flags | = TCP_CORK ;
# endif
2011-08-31 11:42:04 +00:00
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d buf = %p, len = %d, cork = %d \n " , msock - > s_debug_nr , buf , len , cork ) ;
2011-02-23 20:48:06 +00:00
while ( sent < len ) {
2011-08-31 11:42:04 +00:00
if ( unlikely ( msock - > s_dead ) ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d socket has disappeared \n " , msock - > s_debug_nr ) ;
msleep ( 50 ) ;
2011-02-23 20:48:06 +00:00
status = - EIDRM ;
goto done ;
}
2011-08-31 11:42:04 +00:00
status = kernel_sendmsg ( msock - > s_socket , & msg , & iov , 1 , len ) ;
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d sendmsg status = %d \n " , msock - > s_debug_nr , status ) ;
2011-02-23 20:48:06 +00:00
if ( status = = - EAGAIN ) {
msleep ( 50 ) ;
continue ;
}
if ( status = = - EINTR ) { // ignore it
flush_signals ( current ) ;
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d got signal \n " , msock - > s_debug_nr ) ;
2011-02-23 20:48:06 +00:00
msleep ( 50 ) ;
continue ;
}
if ( status < 0 ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d bad socket sendmsg, len=%d, iov_len=%d, sent=%d, status = %d \n " , msock - > s_debug_nr , len , ( int ) iov . iov_len , sent , status ) ;
msleep ( 50 ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
if ( ! status ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d EOF from socket upon sendmsg \n " , msock - > s_debug_nr ) ;
msleep ( 50 ) ;
2011-02-23 20:48:06 +00:00
status = - ECOMM ;
goto done ;
}
iov . iov_base + = status ;
iov . iov_len - = status ;
sent + = status ;
}
status = sent ;
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d sent %d \n " , msock - > s_debug_nr , sent ) ;
2011-08-31 11:42:04 +00:00
2011-02-23 20:48:06 +00:00
done :
2012-01-18 14:31:39 +00:00
if ( status < 0 & & msock - > s_shutdown_on_err )
mars_shutdown_socket ( msock ) ;
2011-08-31 11:42:04 +00:00
mars_put_socket ( msock ) ;
2012-01-11 11:35:09 +00:00
final :
2011-02-23 20:48:06 +00:00
return status ;
}
2012-01-11 11:35:09 +00:00
EXPORT_SYMBOL_GPL ( mars_send_raw ) ;
2011-02-23 20:48:06 +00:00
2012-01-11 11:35:09 +00:00
int mars_recv_raw ( struct mars_socket * msock , void * buf , int minlen , int maxlen )
2011-02-23 20:48:06 +00:00
{
2011-11-16 11:20:30 +00:00
int sleeptime = 1000 / HZ ;
2011-02-23 20:48:06 +00:00
int status = - EIDRM ;
int done = 0 ;
if ( ! buf ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d bad receive buffer \n " , msock - > s_debug_nr ) ;
2011-02-23 20:48:06 +00:00
return - EINVAL ;
}
2011-08-31 11:42:04 +00:00
if ( ! mars_get_socket ( msock ) )
2012-01-11 11:35:09 +00:00
goto final ;
2011-08-31 11:42:04 +00:00
2011-02-23 20:48:06 +00:00
while ( done < minlen ) {
struct kvec iov = {
. iov_base = buf + done ,
. iov_len = maxlen - done ,
} ;
struct msghdr msg = {
. msg_iovlen = 1 ,
. msg_iov = ( struct iovec * ) & iov ,
2012-01-19 14:31:06 +00:00
#if 0 // There seems to be a race in the kernel: sometimes kernel_recvmsg() blocks forever on a shutdown socket even when sk->sk_rcvtimeo is set. Workaround by using noblocking IO (although it is conceptually broken and may lead to unnecessary throughput degradation)
2011-07-08 07:02:14 +00:00
. msg_flags = 0 | MSG_WAITALL | MSG_NOSIGNAL ,
2012-01-19 12:09:22 +00:00
# else
2012-01-19 14:31:06 +00:00
. msg_flags = 0 | MSG_DONTWAIT | MSG_NOSIGNAL ,
2012-01-19 12:09:22 +00:00
# endif
2011-02-23 20:48:06 +00:00
} ;
2011-08-31 11:42:04 +00:00
if ( unlikely ( msock - > s_dead ) ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d socket has disappeared \n " , msock - > s_debug_nr ) ;
2011-02-23 20:48:06 +00:00
status = - EIDRM ;
goto err ;
}
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d done %d, fetching %d bytes \n " , msock - > s_debug_nr , done , maxlen - done ) ;
2011-02-23 20:48:06 +00:00
2011-08-31 11:42:04 +00:00
status = kernel_recvmsg ( msock - > s_socket , & msg , & iov , 1 , maxlen - done , msg . msg_flags ) ;
2011-02-23 20:48:06 +00:00
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d status = %d \n " , msock - > s_debug_nr , status ) ;
2011-02-23 20:48:06 +00:00
if ( status = = - EAGAIN ) {
2012-01-19 14:31:06 +00:00
msleep ( sleeptime ) ;
2011-11-16 11:20:30 +00:00
// linearly increasing backoff
2012-01-19 15:57:10 +00:00
if ( sleeptime < 100 ) {
2012-01-19 14:31:06 +00:00
sleeptime + = 1000 / HZ ;
2012-01-19 15:57:10 +00:00
} else if ( kthread_should_stop ( ) ) {
MARS_WRN ( " interrupting, done = %d \n " , done ) ;
if ( done > 0 )
status = - EIDRM ;
goto err ;
}
2011-02-23 20:48:06 +00:00
continue ;
}
if ( ! status ) { // EOF
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d got EOF from socket (done=%d, req_size=%d) \n " , msock - > s_debug_nr , done , maxlen - done ) ;
2011-02-23 20:48:06 +00:00
status = - EPIPE ;
goto err ;
}
if ( status < 0 ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d bad recvmsg, status = %d \n " , msock - > s_debug_nr , status ) ;
2011-02-23 20:48:06 +00:00
goto err ;
}
done + = status ;
2011-11-16 11:20:30 +00:00
sleeptime = 1000 / HZ ;
2011-02-23 20:48:06 +00:00
}
status = done ;
err :
2012-01-18 14:31:39 +00:00
if ( status < 0 & & msock - > s_shutdown_on_err )
mars_shutdown_socket ( msock ) ;
2011-08-31 11:42:04 +00:00
mars_put_socket ( msock ) ;
2012-01-11 11:35:09 +00:00
final :
2011-02-23 20:48:06 +00:00
return status ;
}
2012-01-11 11:35:09 +00:00
EXPORT_SYMBOL_GPL ( mars_recv_raw ) ;
2011-02-23 20:48:06 +00:00
///////////////////////////////////////////////////////////////////////
/* Mid-level field data exchange
*/
/* TODO: make this bytesex-aware
*/
2012-03-06 14:01:54 +00:00
# define MARS_NET_MAGIC 0x63f0A2ec6148f48dll
2011-07-20 13:11:44 +00:00
# define MAX_FIELD_LEN 32
2011-02-23 20:48:06 +00:00
struct mars_net_header {
u64 h_magic ;
u16 h_seq ;
u16 h_len ;
2012-01-11 11:35:09 +00:00
char h_name [ MAX_FIELD_LEN ] ;
2011-02-23 20:48:06 +00:00
} ;
2012-01-11 11:35:09 +00:00
int _mars_send_struct ( struct mars_socket * msock , void * data , const struct meta * meta , int * seq , bool cork )
2011-02-23 20:48:06 +00:00
{
int count = 0 ;
int status = 0 ;
2012-01-11 11:35:09 +00:00
if ( ! data ) { // directly send EOR
goto done ;
2011-02-23 20:48:06 +00:00
}
2012-01-11 11:35:09 +00:00
for ( ; meta - > field_name ! = NULL ; meta + + ) {
2011-02-23 20:48:06 +00:00
struct mars_net_header header = {
. h_magic = MARS_NET_MAGIC ,
. h_seq = + + ( * seq ) ,
} ;
void * item = data + meta - > field_offset ;
int len = meta - > field_size ;
# if 1
if ( len > 16 * PAGE_SIZE ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d implausible len=%d, \n " , msock - > s_debug_nr , len ) ;
2011-02-23 20:48:06 +00:00
msleep ( 30000 ) ;
status = - EINVAL ;
break ;
}
# endif
/* Automatically keep the lamport clock correct.
*/
2011-07-22 10:43:40 +00:00
mars_check_meta ( meta , data ) ;
2011-02-23 20:48:06 +00:00
status = 0 ;
switch ( meta - > field_type ) {
case FIELD_STRING :
item = * ( void * * ) item ;
len = 0 ;
if ( item )
2011-08-12 12:25:10 +00:00
len = strlen ( item ) + 1 ;
2011-02-23 20:48:06 +00:00
break ;
case FIELD_REF :
if ( ! meta - > field_ref ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d improper FIELD_REF definition \n " , msock - > s_debug_nr ) ;
2011-02-23 20:48:06 +00:00
status = - EINVAL ;
break ;
}
item = * ( void * * ) item ;
len = meta - > field_ref - > field_size ;
if ( ! item )
len = 0 ;
break ;
case FIELD_DONE :
len = 0 ;
case FIELD_SUB :
case FIELD_RAW :
case FIELD_INT :
case FIELD_UINT :
// all ok
break ;
default :
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d invalid field type %d \n " , msock - > s_debug_nr , meta - > field_type ) ;
2011-02-23 20:48:06 +00:00
status = - EINVAL ;
break ;
}
if ( status < 0 )
break ;
header . h_len = len ;
2012-01-11 11:35:09 +00:00
strncpy ( header . h_name , meta - > field_name , MAX_FIELD_LEN ) ;
header . h_name [ MAX_FIELD_LEN - 1 ] = ' \0 ' ;
2011-02-23 20:48:06 +00:00
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d sending header %d '%s' len = %d \n " , msock - > s_debug_nr , header . h_seq , header . h_name , len ) ;
status = mars_send_raw ( msock , & header , sizeof ( header ) , true ) ;
if ( status < 0 )
2011-02-23 20:48:06 +00:00
break ;
switch ( meta - > field_type ) {
case FIELD_REF :
case FIELD_SUB :
2012-01-11 11:35:09 +00:00
if ( len > 0 ) {
status = _mars_send_struct ( msock , item , meta - > field_ref , seq , true ) ;
if ( status > 0 )
count + = status ;
}
2011-02-23 20:48:06 +00:00
break ;
default :
if ( len > 0 ) {
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d sending extra %d \n " , msock - > s_debug_nr , len ) ;
status = mars_send_raw ( msock , item , len , true ) ;
2011-02-23 20:48:06 +00:00
if ( status > 0 )
count + + ;
}
}
if ( status < 0 ) {
break ;
}
}
2012-01-11 11:35:09 +00:00
done :
if ( status > = 0 ) { // send EOR
struct mars_net_header header = {
. h_magic = MARS_NET_MAGIC ,
. h_seq = + + ( * seq ) ,
// .h_name is left empty
} ;
status = mars_send_raw ( msock , & header , sizeof ( header ) , cork ) ;
}
2011-02-23 20:48:06 +00:00
if ( status > = 0 )
status = count ;
return status ;
}
2011-08-31 11:42:04 +00:00
int mars_send_struct ( struct mars_socket * msock , void * data , const struct meta * meta )
2011-02-23 20:48:06 +00:00
{
int seq = 0 ;
2012-01-11 11:35:09 +00:00
return _mars_send_struct ( msock , data , meta , & seq , false ) ;
2011-02-23 20:48:06 +00:00
}
EXPORT_SYMBOL_GPL ( mars_send_struct ) ;
2011-08-31 11:42:04 +00:00
int _mars_recv_struct ( struct mars_socket * msock , void * data , const struct meta * meta , int * seq , int line )
2011-02-23 20:48:06 +00:00
{
int count = 0 ;
int status = - EINVAL ;
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d called from line %d \n " , msock - > s_debug_nr , line ) ;
2011-02-23 20:48:06 +00:00
if ( ! data ) {
goto done ;
}
for ( ; ; ) {
struct mars_net_header header = { } ;
const struct meta * tmp ;
void * item ;
void * mem ;
2012-01-11 11:35:09 +00:00
status = mars_recv_raw ( msock , & header , sizeof ( header ) , sizeof ( header ) ) ;
2011-02-23 20:48:06 +00:00
if ( status = = - EAGAIN ) {
msleep ( 50 ) ;
continue ;
}
if ( status < 0 ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d status = %d \n " , msock - > s_debug_nr , line , status ) ;
break ;
}
MARS_IO ( " #%d called from line %d got header %d '%s' len = %d \n " , msock - > s_debug_nr , line , header . h_seq , header . h_name , header . h_len ) ;
if ( status ! = sizeof ( header ) ) {
MARS_WRN ( " #%d called from line %d bad header len = %d (required=%d) \n " , msock - > s_debug_nr , line , status , ( int ) sizeof ( header ) ) ;
2011-02-23 20:48:06 +00:00
break ;
}
if ( header . h_magic ! = MARS_NET_MAGIC ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d bad packet header magic = %llx \n " , msock - > s_debug_nr , line , header . h_magic ) ;
2011-02-23 20:48:06 +00:00
status = - ENOMSG ;
break ;
}
2012-01-11 11:35:09 +00:00
if ( ! header . h_name [ 0 ] ) { // got EOR
2011-02-23 20:48:06 +00:00
status = 0 ;
break ;
} ;
if ( header . h_seq < = * seq ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d unexpected packet data, seq=%d (expected=%d) \n " , msock - > s_debug_nr , line , header . h_seq , ( * seq ) + 1 ) ;
2011-02-23 20:48:06 +00:00
status = - ENOMSG ;
break ;
}
* seq = header . h_seq ;
if ( ! header . h_name [ 0 ] ) { // end of record (EOR)
status = 0 ;
break ;
}
tmp = find_meta ( meta , header . h_name ) ;
2012-01-11 11:35:09 +00:00
if ( unlikely ( ! tmp ) ) {
MARS_WRN ( " #%d called from line %d unknown field '%s' \n " , msock - > s_debug_nr , line , header . h_name ) ;
2011-02-23 20:48:06 +00:00
if ( header . h_len > 0 ) { // try to continue by skipping the rest of data
2011-08-12 11:09:48 +00:00
void * dummy = brick_mem_alloc ( header . h_len ) ;
2011-02-23 20:48:06 +00:00
status = - ENOMEM ;
if ( ! dummy )
break ;
2012-01-11 11:35:09 +00:00
status = mars_recv_raw ( msock , dummy , header . h_len , header . h_len ) ;
2011-08-12 11:09:48 +00:00
brick_mem_free ( dummy ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
break ;
}
continue ;
}
status = 0 ;
item = data + tmp - > field_offset ;
switch ( tmp - > field_type ) {
case FIELD_REF :
case FIELD_STRING :
if ( header . h_len < = 0 ) {
mem = NULL ;
} else {
2011-08-12 11:09:48 +00:00
if ( tmp - > field_type = = FIELD_STRING ) {
2011-08-25 10:16:32 +00:00
mem = _brick_string_alloc ( header . h_len + 1 , line ) ;
2011-08-12 11:09:48 +00:00
} else {
mem = brick_zmem_alloc ( header . h_len + 1 ) ;
}
2011-02-23 20:48:06 +00:00
if ( ! mem ) {
status = - ENOMEM ;
goto done ;
}
}
* ( void * * ) item = mem ;
item = mem ;
break ;
}
switch ( tmp - > field_type ) {
case FIELD_REF :
case FIELD_SUB :
if ( ! item ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d bad item \n " , msock - > s_debug_nr , line ) ;
2011-02-23 20:48:06 +00:00
status = - EINVAL ;
break ;
}
2012-01-11 11:35:09 +00:00
if ( header . h_len > 0 ) {
MARS_IO ( " #%d called from line %d starting recursive structure \n " , msock - > s_debug_nr , line ) ;
status = _mars_recv_struct ( msock , item , tmp - > field_ref , seq , line ) ;
MARS_IO ( " #%d called from line %d ending recursive structure, status = %d \n " , msock - > s_debug_nr , line , status ) ;
2011-02-23 20:48:06 +00:00
2012-01-11 11:35:09 +00:00
if ( status > 0 )
count + = status ;
}
2011-02-23 20:48:06 +00:00
break ;
default :
if ( header . h_len > 0 ) {
if ( ! item ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d bad item \n " , msock - > s_debug_nr , line ) ;
2011-02-23 20:48:06 +00:00
status = - EINVAL ;
break ;
}
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d called from line %d reading extra %d \n " , msock - > s_debug_nr , line , header . h_len ) ;
status = mars_recv_raw ( msock , item , header . h_len , header . h_len ) ;
2011-02-23 20:48:06 +00:00
while ( status = = - EAGAIN ) {
msleep ( 50 ) ;
2012-01-11 11:35:09 +00:00
status = mars_recv_raw ( msock , item , header . h_len , header . h_len ) ;
2011-02-23 20:48:06 +00:00
}
if ( status > = 0 ) {
2012-01-11 11:35:09 +00:00
//MARS_IO("#%d got data len = %d status = %d\n", msock->s_debug_nr, header.h_len, status);
2011-02-23 20:48:06 +00:00
count + + ;
} else {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d len = %d, status = %d \n " , msock - > s_debug_nr , line , header . h_len , status ) ;
2011-02-23 20:48:06 +00:00
}
}
}
if ( status < 0 )
break ;
}
done :
if ( status > = 0 ) {
status = count ;
2011-07-22 10:43:40 +00:00
mars_check_meta ( meta , data ) ;
2011-02-23 20:48:06 +00:00
} else {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d called from line %d status = %d \n " , msock - > s_debug_nr , line , status ) ;
2011-02-23 20:48:06 +00:00
}
return status ;
}
2011-08-25 10:16:32 +00:00
EXPORT_SYMBOL_GPL ( _mars_recv_struct ) ;
2011-02-23 20:48:06 +00:00
///////////////////////////////////////////////////////////////////////
/* High-level transport of mars structures
*/
const struct meta mars_cmd_meta [ ] = {
META_INI_SUB ( cmd_stamp , struct mars_cmd , mars_timespec_meta ) ,
META_INI ( cmd_code , struct mars_cmd , FIELD_INT ) ,
META_INI ( cmd_int1 , struct mars_cmd , FIELD_INT ) ,
META_INI ( cmd_str1 , struct mars_cmd , FIELD_STRING ) ,
{ }
} ;
EXPORT_SYMBOL_GPL ( mars_cmd_meta ) ;
2011-07-22 10:43:40 +00:00
static
void mars_check_meta ( const struct meta * meta , void * data )
2011-02-23 20:48:06 +00:00
{
2011-07-22 10:43:40 +00:00
/* Automatically keep the lamport clock correct.
*/
if ( meta = = mars_cmd_meta ) {
struct timespec * stamp = & ( ( struct mars_cmd * ) data ) - > cmd_stamp ;
get_lamport ( stamp ) ;
} else if ( meta = = mars_timespec_meta ) {
set_lamport ( data ) ;
2011-02-23 20:48:06 +00:00
}
}
2011-08-31 11:42:04 +00:00
int mars_send_mref ( struct mars_socket * msock , struct mref_object * mref )
2011-02-23 20:48:06 +00:00
{
struct mars_cmd cmd = {
. cmd_code = CMD_MREF ,
. cmd_int1 = mref - > ref_id ,
} ;
2012-01-11 11:35:09 +00:00
int seq = 0 ;
2011-02-23 20:48:06 +00:00
int status ;
2012-01-11 11:35:09 +00:00
status = _mars_send_struct ( msock , & cmd , mars_cmd_meta , & seq , true ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
goto done ;
2012-01-11 11:35:09 +00:00
seq = 0 ;
status = _mars_send_struct ( msock , mref , mars_mref_meta , & seq , mref - > ref_rw ! = 0 ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
goto done ;
2012-01-11 11:35:09 +00:00
if ( mref - > ref_rw ! = 0 ) {
status = mars_send_raw ( msock , mref - > ref_data , mref - > ref_len , false ) ;
2011-02-23 20:48:06 +00:00
}
done :
return status ;
}
EXPORT_SYMBOL_GPL ( mars_send_mref ) ;
2011-08-31 11:42:04 +00:00
int mars_recv_mref ( struct mars_socket * msock , struct mref_object * mref )
2011-02-23 20:48:06 +00:00
{
2012-01-11 11:35:09 +00:00
int seq = 0 ;
2011-02-23 20:48:06 +00:00
int status ;
2012-01-11 11:35:09 +00:00
status = _mars_recv_struct ( msock , mref , mars_mref_meta , & seq , __LINE__ ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
goto done ;
if ( mref - > ref_rw ) {
if ( ! mref - > ref_data )
2011-08-12 11:09:48 +00:00
mref - > ref_data = brick_zmem_alloc ( mref - > ref_len ) ;
2011-02-23 20:48:06 +00:00
if ( ! mref - > ref_data ) {
status = - ENOMEM ;
goto done ;
}
2012-01-11 11:35:09 +00:00
status = mars_recv_raw ( msock , mref - > ref_data , mref - > ref_len , mref - > ref_len ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d mref_len = %d, status = %d \n " , msock - > s_debug_nr , mref - > ref_len , status ) ;
2011-02-23 20:48:06 +00:00
}
done :
return status ;
}
EXPORT_SYMBOL_GPL ( mars_recv_mref ) ;
2011-08-31 11:42:04 +00:00
int mars_send_cb ( struct mars_socket * msock , struct mref_object * mref )
2011-02-23 20:48:06 +00:00
{
struct mars_cmd cmd = {
. cmd_code = CMD_CB ,
. cmd_int1 = mref - > ref_id ,
} ;
2012-01-11 11:35:09 +00:00
int seq = 0 ;
2011-02-23 20:48:06 +00:00
int status ;
2012-01-11 11:35:09 +00:00
status = _mars_send_struct ( msock , & cmd , mars_cmd_meta , & seq , true ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
goto done ;
2012-01-11 11:35:09 +00:00
seq = 0 ;
status = _mars_send_struct ( msock , mref , mars_mref_meta , & seq , ! mref - > ref_rw ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
goto done ;
2012-01-11 11:35:09 +00:00
2011-02-23 20:48:06 +00:00
if ( ! mref - > ref_rw ) {
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d sending blocklen = %d \n " , msock - > s_debug_nr , mref - > ref_len ) ;
status = mars_send_raw ( msock , mref - > ref_data , mref - > ref_len , false ) ;
2011-02-23 20:48:06 +00:00
}
done :
return status ;
}
EXPORT_SYMBOL_GPL ( mars_send_cb ) ;
2011-08-31 11:42:04 +00:00
int mars_recv_cb ( struct mars_socket * msock , struct mref_object * mref )
2011-02-23 20:48:06 +00:00
{
2012-01-11 11:35:09 +00:00
int seq = 0 ;
2011-02-23 20:48:06 +00:00
int status ;
2012-01-11 11:35:09 +00:00
status = _mars_recv_struct ( msock , mref , mars_mref_meta , & seq , __LINE__ ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 )
goto done ;
if ( ! mref - > ref_rw ) {
if ( ! mref - > ref_data ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " #%d no internal buffer available \n " , msock - > s_debug_nr ) ;
2011-02-23 20:48:06 +00:00
status = - EINVAL ;
goto done ;
}
2012-01-11 11:35:09 +00:00
MARS_IO ( " #%d receiving blocklen = %d \n " , msock - > s_debug_nr , mref - > ref_len ) ;
status = mars_recv_raw ( msock , mref - > ref_data , mref - > ref_len , mref - > ref_len ) ;
2011-02-23 20:48:06 +00:00
}
done :
return status ;
}
EXPORT_SYMBOL_GPL ( mars_recv_cb ) ;
////////////////// module init stuff /////////////////////////
2011-07-22 10:43:40 +00:00
char * ( * mars_translate_hostname ) ( const char * name ) = NULL ;
EXPORT_SYMBOL_GPL ( mars_translate_hostname ) ;
2011-08-25 10:16:32 +00:00
int __init init_mars_net ( void )
2011-02-23 20:48:06 +00:00
{
MARS_INF ( " init_net() \n " ) ;
return 0 ;
}
2011-08-25 10:16:32 +00:00
void __exit exit_mars_net ( void )
2011-02-23 20:48:06 +00:00
{
MARS_INF ( " exit_net() \n " ) ;
}
2011-08-25 10:16:32 +00:00
# ifndef CONFIG_MARS_HAVE_BIGMODULE
2011-02-23 20:48:06 +00:00
MODULE_DESCRIPTION ( " MARS network infrastructure " ) ;
MODULE_AUTHOR ( " Thomas Schoebel-Theuer <tst@1und1.de> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2011-08-25 10:16:32 +00:00
module_init ( init_mars_net ) ;
module_exit ( exit_mars_net ) ;
# endif