From 13a633b5ca7098b1ecb496474e901404e42dae8b Mon Sep 17 00:00:00 2001 From: Thomas Hornschuh Date: Sat, 22 Jul 2017 01:57:54 +0200 Subject: [PATCH] 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. --- src/elua_uip.c | 277 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 180 insertions(+), 97 deletions(-) diff --git a/src/elua_uip.c b/src/elua_uip.c index adb7758d..dddd6f4f 100644 --- a/src/elua_uip.c +++ b/src/elua_uip.c @@ -51,7 +51,7 @@ void elua_uip_mainloop() // Increment uIP timers temp = platform_eth_get_elapsed_time(); periodic_timer += temp; - arp_timer += temp; + arp_timer += temp; // Check for an RX packet and read it if( ( packet_len = platform_eth_get_packet_nb( uip_buf, sizeof( uip_buf ) ) ) > 0 ) @@ -87,7 +87,7 @@ void elua_uip_mainloop() device_driver_send(); } } - + // Process TCP/IP Periodic Timer here. // Also process the "force interrupt" events (platform_eth_force_interrupt) if( periodic_timer >= UIP_PERIODIC_TIMER_MS ) @@ -126,13 +126,13 @@ void elua_uip_mainloop() } } #endif // UIP_UDP - + // Process ARP Timer here. if( arp_timer >= UIP_ARP_TIMER_MS ) { arp_timer = 0; uip_arp_timer(); - } + } } // ***************************************************************************** @@ -146,8 +146,8 @@ void dhcpc_configured(const struct dhcpc_state *s) if( s->ipaddr[ 0 ] != 0 ) { uip_sethostaddr( s->ipaddr ); - uip_setnetmask( s->netmask ); - uip_setdraddr( s->default_router ); + uip_setnetmask( s->netmask ); + uip_setdraddr( s->default_router ); resolv_conf( ( u16_t* )s->dnsaddr ); elua_uip_configured = 1; } @@ -201,7 +201,7 @@ static void elua_uip_telnet_handle_input( volatile struct elua_uip_state* s ) char *orig = ( char* )s->ptr; int skip; elua_net_size maxsize = s->len; - + // Traverse the input buffer, skipping over TELNET sequences while( ( dptr < ( u8* )uip_appdata + uip_datalen() ) && ( s->ptr - orig < s->len ) ) { @@ -221,7 +221,7 @@ static void elua_uip_telnet_handle_input( volatile struct elua_uip_state* s ) } dptr += skip; } - } + } if( s->ptr > orig ) { s->res = ELUA_NET_ERR_OK; @@ -240,14 +240,14 @@ static elua_net_size elua_uip_telnet_prep_send( const char* src, elua_net_size s { elua_net_size actsize = size, i; char* dest = ( char* )uip_sappdata; - + for( i = 0; i < size; i ++ ) { if( *src == '\n' ) { *dest ++ = '\r'; actsize ++; - } + } *dest ++ = *src ++; } return actsize; @@ -259,20 +259,33 @@ 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() { volatile struct elua_uip_state *s; elua_net_size temp; int sockno; - + // If uIP is not yet configured (DHCP response not received), do nothing if( !elua_uip_configured ) return; - + s = ( struct elua_uip_state* )&( uip_conn->appstate ); // Need to find the actual socket location, since UIP doesn't provide this ... for( temp = 0; temp < UIP_CONNS; temp ++ ) @@ -282,8 +295,14 @@ void elua_uip_appcall() if( uip_connected() ) { -#ifdef BUILD_CON_TCP - if( uip_conn->lport == HTONS( ELUA_NET_TELNET_PORT ) ) // special case: telnet server + // 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 + else if( uip_conn->lport == HTONS( ELUA_NET_TELNET_PORT ) ) // special case: telnet server { if( elua_uip_telnet_socket != -1 ) { @@ -293,24 +312,36 @@ void elua_uip_appcall() else elua_uip_telnet_socket = sockno; } - else + #endif - if( elua_uip_accept_request ) - { - 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; - } - else if( s->state == ELUA_UIP_STATE_CONNECT ) - s->state = ELUA_UIP_STATE_IDLE; + else { // add to list of pending accepts + int i; + BOOL found=FALSE; + for(i=0;iripaddr[ 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; + } + } + if (!found) { // no free slot + uip_close(); + return; + } + } + uip_stop(); return; } if( s->state == ELUA_UIP_STATE_IDLE ) return; - + // Do we need to read? if( s->state == ELUA_UIP_STATE_RECV ) { @@ -319,27 +350,27 @@ void elua_uip_appcall() uip_restart(); return; } - + if( uip_aborted() || uip_timedout() || uip_closed() ) { // Signal this error s->res = uip_aborted() ? ELUA_NET_ERR_ABORTED : ( uip_timedout() ? ELUA_NET_ERR_TIMEDOUT : ELUA_NET_ERR_CLOSED ); -#ifdef BUILD_CON_TCP +#ifdef BUILD_CON_TCP if( sockno == elua_uip_telnet_socket ) - elua_uip_telnet_socket = -1; -#endif + elua_uip_telnet_socket = -1; +#endif s->state = ELUA_UIP_STATE_IDLE; return; } - - // Handle data send + + // Handle data send if( ( uip_acked() || uip_rexmit() || uip_poll() ) && ( s->state == ELUA_UIP_STATE_SEND ) ) { // Special translation for TELNET: prepend all '\n' with '\r' - // We write directly in UIP's buffer + // We write directly in UIP's buffer if( uip_acked() ) { - elua_net_size minlen = UMIN( s->len, uip_mss() ); + elua_net_size minlen = UMIN( s->len, uip_mss() ); s->len -= minlen; s->ptr += minlen; if( s->len == 0 ) @@ -354,12 +385,12 @@ void elua_uip_appcall() uip_send( uip_sappdata, temp ); } else -#endif +#endif uip_send( s->ptr, UMIN( s->len, uip_mss() ) ); } return; } - + // Handle close if( s->state == ELUA_UIP_STATE_CLOSE ) { @@ -367,40 +398,40 @@ void elua_uip_appcall() s->state = ELUA_UIP_STATE_IDLE; return; } - - // Handle data receive + + // Handle data receive if( uip_newdata() ) { if( s->state == ELUA_UIP_STATE_RECV_2 ) { -#ifdef BUILD_CON_TCP +#ifdef BUILD_CON_TCP if( sockno == elua_uip_telnet_socket ) { elua_uip_telnet_handle_input( s ); return; } -#endif +#endif int lastfound = 0; - + // Check end of transmission if( uip_datalen() < UIP_RECEIVE_WINDOW ) lastfound = 1; // Check overflow if( s->len < uip_datalen() ) { - s->res = ELUA_NET_ERR_OVERFLOW; + s->res = ELUA_NET_ERR_OVERFLOW; temp = s->len; } else temp = uip_datalen(); - + if( s->readto != ELUA_NET_NO_LASTCHAR ) { char *tptr = ( char* )uip_appdata; char *last = ( char* )uip_appdata + temp - 1; luaL_Buffer *pbuf = ( luaL_Buffer* )s->ptr; char* dest = ( char* )s->ptr; - + while( tptr <= last ) { if( *tptr == s->readto ) @@ -422,12 +453,12 @@ void elua_uip_appcall() else { if( s->res ) - luaL_addlstring( ( luaL_Buffer* )s->ptr, ( const char* )uip_appdata, temp ); + luaL_addlstring( ( luaL_Buffer* )s->ptr, ( const char* )uip_appdata, temp ); else memcpy( ( char* )s->ptr, ( const char* )uip_appdata, temp ); s->len -= temp; } - + // Do we need to read another packet? if( s->len == 0 || lastfound ) { @@ -447,11 +478,11 @@ static void elua_uip_conf_static() uip_ipaddr( ipaddr, ELUA_CONF_IPADDR0, ELUA_CONF_IPADDR1, ELUA_CONF_IPADDR2, ELUA_CONF_IPADDR3 ); uip_sethostaddr( ipaddr ); uip_ipaddr( ipaddr, ELUA_CONF_NETMASK0, ELUA_CONF_NETMASK1, ELUA_CONF_NETMASK2, ELUA_CONF_NETMASK3 ); - uip_setnetmask( ipaddr ); + uip_setnetmask( ipaddr ); uip_ipaddr( ipaddr, ELUA_CONF_DEFGW0, ELUA_CONF_DEFGW1, ELUA_CONF_DEFGW2, ELUA_CONF_DEFGW3 ); - uip_setdraddr( ipaddr ); + uip_setdraddr( ipaddr ); uip_ipaddr( ipaddr, ELUA_CONF_DNS0, ELUA_CONF_DNS1, ELUA_CONF_DNS2, ELUA_CONF_DNS3 ); - resolv_conf( ipaddr ); + resolv_conf( ipaddr ); elua_uip_configured = 1; } @@ -460,23 +491,29 @@ void elua_uip_init( const struct uip_eth_addr *paddr ) { // Set hardware address uip_setethaddr( (*paddr) ); - + // Initialize the uIP TCP/IP stack. uip_init(); - uip_arp_init(); - + uip_arp_init(); + + int i; + for(i=0;iaddr, sizeof( *paddr ) ); dhcpc_request(); #else elua_uip_conf_static(); #endif - + resolv_init(); - + #ifdef BUILD_CON_TCP uip_listen( HTONS( ELUA_NET_TELNET_PORT ) ); -#endif +#endif } // ***************************************************************************** @@ -494,7 +531,7 @@ void elua_uip_udp_appcall() #define ELUA_UIP_IS_SOCK_OK( sock ) ( elua_uip_configured && sock >= 0 && sock < UIP_CONNS ) static void elua_prep_socket_state( volatile struct elua_uip_state *pstate, void* buf, elua_net_size len, s16 readto, u8 res, u8 state ) -{ +{ pstate->ptr = ( char* )buf; pstate->len = len; pstate->res = res; @@ -507,18 +544,18 @@ int elua_net_socket( int type ) int i; struct uip_conn* pconn; int old_status; - + // [TODO] add UDP support at some point. if( type == ELUA_NET_SOCK_DGRAM ) return -1; - + old_status = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE ); // Iterate through the list of connections, looking for a free one for( i = 0; i < UIP_CONNS; i ++ ) { pconn = uip_conns + i; if( pconn->tcpstateflags == UIP_CLOSED ) - { + { // Found a free connection, reserve it for later use uip_conn_reserve( i ); break; @@ -532,7 +569,7 @@ int elua_net_socket( int type ) elua_net_size elua_net_send( int s, const void* buf, elua_net_size len ) { volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); - + if( !ELUA_UIP_IS_SOCK_OK( s ) || !uip_conn_active( s ) ) return -1; if( len == 0 ) @@ -549,7 +586,7 @@ static elua_net_size elua_net_recv_internal( int s, void* buf, elua_net_size max volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); timer_data_type tmrstart = 0; int old_status; - + if( !ELUA_UIP_IS_SOCK_OK( s ) || !uip_conn_active( s ) ) return -1; if( maxsize == 0 ) @@ -565,7 +602,7 @@ static elua_net_size elua_net_recv_internal( int s, void* buf, elua_net_size max { old_status = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE ); if( pstate->state != ELUA_UIP_STATE_IDLE ) - { + { pstate->res = ELUA_NET_ERR_TIMEDOUT; pstate->state = ELUA_UIP_STATE_IDLE; } @@ -593,20 +630,20 @@ elua_net_size elua_net_recvbuf( int s, luaL_Buffer* buf, elua_net_size maxsize, int elua_net_get_telnet_socket() { int res = -1; - -#ifdef BUILD_CON_TCP + +#ifdef BUILD_CON_TCP if( elua_uip_telnet_socket != -1 ) if( uip_conn_active( elua_uip_telnet_socket ) ) res = elua_uip_telnet_socket; -#endif +#endif return res; } // Close socket int elua_net_close( int s ) { - volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); - + volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); + if( !ELUA_UIP_IS_SOCK_OK( s ) || !uip_conn_active( s ) ) return -1; elua_prep_socket_state( pstate, NULL, 0, ELUA_NET_NO_LASTCHAR, ELUA_NET_ERR_OK, ELUA_UIP_STATE_CLOSE ); @@ -618,65 +655,111 @@ int elua_net_close( int s ) // Get last error on specific socket int elua_net_get_last_err( int s ) { - volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); - + volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); + if( !ELUA_UIP_IS_SOCK_OK( s ) ) return -1; return pstate->res; } + +// New TH: listen/unlistens a port +int elua_listen(u16 port,BOOL flisten) +{ +int old_status; + + if( !elua_uip_configured ) + return -1; +#ifdef BUILD_CON_TCP + 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 ); + + return 0; + +} + + +int elua_net_find_pending(u16 port) +{ +int i; + + + for(i=0;i 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 ) { volatile struct elua_uip_state *pstate = ( volatile struct elua_uip_state* )&( uip_conns[ s ].appstate ); uip_ipaddr_t ipaddr; - + if( !ELUA_UIP_IS_SOCK_OK( s ) ) return -1; // The socket should have been reserved by a previous call to "elua_net_socket" if( !uip_conn_is_reserved( s ) ) return -1; - // Initiate the connect call + // 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_prep_socket_state( pstate, NULL, 0, ELUA_NET_NO_LASTCHAR, ELUA_NET_ERR_OK, ELUA_UIP_STATE_CONNECT ); + 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; } @@ -684,11 +767,11 @@ int elua_net_connect( int s, elua_net_ip addr, u16 port ) elua_net_ip elua_net_lookup( const char* hostname ) { elua_net_ip res; - - res.ipaddr = 0; + + res.ipaddr = 0; #ifdef BUILD_DNS u16_t *data; - + if( ( data = resolv_lookup( ( char* )hostname ) ) != NULL ) { // Name already saved locally @@ -705,7 +788,7 @@ elua_net_ip elua_net_lookup( const char* hostname ) res = elua_resolv_ip; } #endif - return res; + return res; } #endif // #ifdef BUILD_UIP