1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

Fixed elua_uip.c behaviour for accept calls

Allow new incomming connections to be queued between accept calls. This
allows to build servers which accept several connection and server them
all with the help of coroutines.
This commit is contained in:
Thomas Hornschuh 2017-07-22 01:57:54 +02:00
parent 1c744f03eb
commit 13a633b5ca

View File

@ -259,9 +259,22 @@ static elua_net_size elua_uip_telnet_prep_send( const char* src, elua_net_size s
// eLua UIP application (used to implement the eLua TCP/IP services)
// Special handling for "accept"
volatile static u8 elua_uip_accept_request;
volatile static int elua_uip_accept_sock;
volatile static elua_net_ip elua_uip_accept_remote;
//volatile static u8 elua_uip_accept_request;
//volatile static int elua_uip_accept_sock;
//volatile static elua_net_ip elua_uip_accept_remote;
typedef struct {
u8 accept_request; // 0=accepted 1=pending, 255=not used
int sock; // socket number when accepted
elua_net_ip remote; // remote IP
int port; // local port bound to
} elua_uip_accept_pending_t;
static elua_uip_accept_pending_t elua_uip_accept_pending[UIP_CONF_MAX_CONNECTIONS];
static struct uip_conn *elua_net_connecting=NULL;
void elua_uip_appcall()
{
@ -282,8 +295,14 @@ void elua_uip_appcall()
if( uip_connected() )
{
// check if we are currenty in a conncet call and the socket
// is the connection is the right one...
if ( s->state == ELUA_UIP_STATE_CONNECT && uip_conn==elua_net_connecting )
s->state = ELUA_UIP_STATE_IDLE;
#ifdef BUILD_CON_TCP
if( uip_conn->lport == HTONS( ELUA_NET_TELNET_PORT ) ) // special case: telnet server
else if( uip_conn->lport == HTONS( ELUA_NET_TELNET_PORT ) ) // special case: telnet server
{
if( elua_uip_telnet_socket != -1 )
{
@ -293,17 +312,29 @@ void elua_uip_appcall()
else
elua_uip_telnet_socket = sockno;
}
else
#endif
if( elua_uip_accept_request )
else { // add to list of pending accepts
int i;
BOOL found=FALSE;
for(i=0;i<UIP_CONF_MAX_CONNECTIONS && !found;i++)
{
elua_uip_accept_sock = sockno;
elua_uip_accept_remote.ipwords[ 0 ] = uip_conn->ripaddr[ 0 ];
elua_uip_accept_remote.ipwords[ 1 ] = uip_conn->ripaddr[ 1 ];
elua_uip_accept_request = 0;
if (elua_uip_accept_pending[i].accept_request!=1) {// free slot
elua_uip_accept_pending[i].sock=sockno;
elua_uip_accept_pending[i].remote.ipwords[0]=uip_conn->ripaddr[ 0 ];
elua_uip_accept_pending[i].remote.ipwords[1]=uip_conn->ripaddr[ 1 ];
elua_uip_accept_pending[i].accept_request=1;
elua_uip_accept_pending[i].port= HTONS(uip_conn->lport);
//printk("Pending accept for port %d, index %d\n", elua_uip_accept_pending[i].port,i);
found=TRUE;
}
else if( s->state == ELUA_UIP_STATE_CONNECT )
s->state = ELUA_UIP_STATE_IDLE;
}
if (!found) { // no free slot
uip_close();
return;
}
}
uip_stop();
return;
}
@ -465,6 +496,12 @@ void elua_uip_init( const struct uip_eth_addr *paddr )
uip_init();
uip_arp_init();
int i;
for(i=0;i<UIP_CONF_MAX_CONNECTIONS;i++) {
elua_uip_accept_pending[i].accept_request=255;
}
#ifdef BUILD_DHCPC
dhcpc_init( paddr->addr, sizeof( *paddr ) );
dhcpc_request();
@ -625,10 +662,10 @@ int elua_net_get_last_err( int s )
return pstate->res;
}
// Accept a connection on the given port, return its socket id (and the IP of the remote host by side effect)
int elua_accept( u16 port, unsigned timer_id, timer_data_type to_us, elua_net_ip* pfrom )
// New TH: listen/unlistens a port
int elua_listen(u16 port,BOOL flisten)
{
timer_data_type tmrstart = 0;
int old_status;
if( !elua_uip_configured )
@ -637,28 +674,72 @@ int elua_accept( u16 port, unsigned timer_id, timer_data_type to_us, elua_net_ip
if( port == ELUA_NET_TELNET_PORT )
return -1;
#endif
old_status = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE );
uip_unlisten( htons( port ) );
if (flisten)
uip_listen( htons( port ) );
platform_cpu_set_global_interrupts( old_status );
elua_uip_accept_sock = -1;
elua_uip_accept_request = 1;
return 0;
}
int elua_net_find_pending(u16 port)
{
int i;
for(i=0;i<UIP_CONF_MAX_CONNECTIONS;i++)
{
if (elua_uip_accept_pending[i].accept_request==1
&& elua_uip_accept_pending[i].port==port )
return i;
}
return -1;
}
// Accept a connection on the given port, return its socket id (and the IP of the remote host by side effect)
int elua_accept( u16 port, unsigned timer_id, timer_data_type to_us, elua_net_ip* pfrom )
{
timer_data_type tmrstart = 0;
int old_status;
int i;
if( !elua_uip_configured )
return -1;
elua_listen(port,TRUE); // Need to be changed....
if( to_us > 0 )
tmrstart = platform_timer_start( timer_id );
while( 1 )
{
if( elua_uip_accept_request == 0 )
break;
i=elua_net_find_pending(port);
if( i >= 0 ) {
*pfrom = elua_uip_accept_pending[i].remote;
old_status=platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE );
elua_uip_accept_pending[i].accept_request=0;
platform_cpu_set_global_interrupts( old_status );
return elua_uip_accept_pending[i].sock;
}
if( to_us > 0 && platform_timer_get_diff_crt( timer_id, tmrstart ) >= to_us )
{
elua_uip_accept_request = 0;
break;
return -1;
}
}
*pfrom = elua_uip_accept_remote;
return elua_uip_accept_sock;
}
// Connect to a specified machine
int elua_net_connect( int s, elua_net_ip addr, u16 port )
{
@ -673,10 +754,12 @@ int elua_net_connect( int s, elua_net_ip addr, u16 port )
// Initiate the connect call
uip_ipaddr( ipaddr, addr.ipbytes[ 0 ], addr.ipbytes[ 1 ], addr.ipbytes[ 2 ], addr.ipbytes[ 3 ] );
elua_prep_socket_state( pstate, NULL, 0, ELUA_NET_NO_LASTCHAR, ELUA_NET_ERR_OK, ELUA_UIP_STATE_CONNECT );
if( uip_connect_socket( s, &ipaddr, htons( port ) ) == NULL )
elua_net_connecting=uip_connect_socket( s, &ipaddr, htons( port ) ) ;
if( elua_net_connecting == NULL )
return -1;
// And wait for it to finish
while( pstate->state != ELUA_UIP_STATE_IDLE );
elua_net_connecting=NULL;
return pstate->res == ELUA_NET_ERR_OK ? 0 : -1;
}