source: trunk/kernel/kern/ksocket.c @ 690

Last change on this file since 690 was 683, checked in by alain, 3 years ago

All modifications required to support the <tcp_chat> application
including error recovery in case of packet loss.A

File size: 88.8 KB
Line 
1/*
2 * ksocket.c - kernel socket implementation.
3 *
4 * Authors  Alain Greiner        (2016,2017,2018,2019,2020)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <kernel_config.h>
25#include <hal_kernel_types.h>
26#include <hal_remote.h>
27#include <hal_uspace.h>
28#include <shared_socket.h>
29#include <process.h>
30#include <remote_buf.h>
31#include <bits.h>
32#include <printk.h>
33#include <kmem.h>
34#include <thread.h>
35#include <vfs.h>
36#include <alarm.h>
37#include <dev_nic.h>
38#include <ksocket.h>
39
40//////////////////////////////////////////////////////////////////////////////////////
41// Extern global variables
42//////////////////////////////////////////////////////////////////////////////////////
43
44extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
45
46///////////////////////////////////////////
47char * socket_domain_str( uint32_t domain )
48{
49    switch( domain )
50    {
51        case AF_INET         : return "INET";
52        case AF_LOCAL        : return "LOCAL";
53
54        default              : return "undefined";
55    }
56}
57   
58///////////////////////////////////////
59char * socket_type_str( uint32_t type )
60{
61    switch( type )
62    {
63        case SOCK_DGRAM         : return "UDP";
64        case SOCK_STREAM        : return "TCP";
65
66        default                 : return "undefined";
67    }
68}
69   
70/////////////////////////////////////////
71char * socket_state_str( uint32_t state )
72{
73    switch( state )
74    {
75        case UDP_STATE_UNBOUND    : return "UDP_UNBOUND";
76        case UDP_STATE_BOUND      : return "UDP_BOUND";
77        case UDP_STATE_ESTAB      : return "UDP_ESTAB";
78
79        case TCP_STATE_UNBOUND    : return "TCP_UNBOUND";
80        case TCP_STATE_BOUND      : return "TCP_BOUND";
81        case TCP_STATE_LISTEN     : return "TCP_LISTEN";
82        case TCP_STATE_SYN_SENT   : return "TCP_SYN_SENT";
83        case TCP_STATE_SYN_RCVD   : return "TCP_SYN_RCVD";
84        case TCP_STATE_ESTAB      : return "TCP_ESTAB";
85        case TCP_STATE_FIN_WAIT1  : return "TCP_FIN_WAIT1";
86        case TCP_STATE_FIN_WAIT2  : return "TCP_FIN_WAIT2";
87        case TCP_STATE_CLOSING    : return "TCP_CLOSING";
88        case TCP_STATE_TIME_WAIT  : return "TCP_TIME_WAIT";
89        case TCP_STATE_CLOSE_WAIT : return "TCP_CLOSE_WAIT";
90        case TCP_STATE_LAST_ACK   : return "TCP_LAST_ACK";
91        case TCP_STATE_CLOSED     : return "TCP_CLOSED";
92
93        default                   : return "undefined";
94    }
95}
96
97///////////////////////////////////////////
98char * socket_cmd_type_str( uint32_t type )
99{
100    switch( type )
101    {
102        case CMD_TX_CONNECT  : return "TX_CONNECT";
103        case CMD_TX_ACCEPT   : return "TX_ACCEPT";
104        case CMD_TX_CLOSE    : return "TX_CLOSE";
105        case CMD_TX_SEND     : return "TX_SEND";
106
107        case CMD_RX_ACCEPT   : return "RX_ACCEPT";
108        case CMD_RX_RECV     : return "RX_RECV";
109       
110        default                 : return "undefined";
111    }
112}
113   
114///////////////////////////////////////////
115char * socket_cmd_sts_str( uint32_t sts )
116{
117    switch( sts )
118    {
119        case CMD_STS_SUCCESS  : return "SUCCESS";
120        case CMD_STS_EOF      : return "EOF";
121        case CMD_STS_RST      : return "RST";
122        case CMD_STS_BADACK   : return "BADACK";
123        case CMD_STS_BADSTATE : return "BADSTATE";
124        case CMD_STS_BADCMD   : return "BADCMD";
125       
126        default               : return "undefined";
127    }
128}
129
130///////////////////////////////////////////////////////////////////////////////////////////
131// This static function implements the alarm handler used by a TX client thread to
132// handle a retransmission timeout for a TX command (ACCEPT / CONNECT / CLOSE / SEND).
133// The <args_xp> argument is actually an extended pointer on the involved socket.
134// First, it updates the retransmission timeout. Then, it get the type of TX command,
135// and request the NIC_TX server thread to re-send the unacknowledged segment.
136///////////////////////////////////////////////////////////////////////////////////////////
137// @ sock_xp    : extended pointer on the involved socket.
138///////////////////////////////////////////////////////////////////////////////////////////
139static void __attribute__((noinline)) socket_alarm_handler( xptr_t sock_xp )
140{
141    // get cluster and local pointer on socket descriptor
142    socket_t * sock_ptr = GET_PTR( sock_xp );
143    cxy_t      sock_cxy = GET_CXY( sock_xp );
144
145#if DEBUG_SOCKET_ALARM
146uint32_t cycle = (uint32_t)hal_get_cycles();
147#endif
148
149   // build extended pointer on lock protecting socket
150    xptr_t socket_lock_xp = XPTR( sock_cxy , &sock_ptr->lock );
151
152    // take the socket lock
153    remote_queuelock_acquire( socket_lock_xp );
154
155    // get relevant infos from socket descriptor
156    uint32_t   tx_cmd    = hal_remote_l32( XPTR( sock_cxy , &sock_ptr->tx_cmd )); 
157    uint32_t   channel   = hal_remote_l32( XPTR( sock_cxy , &sock_ptr->nic_channel ));
158    xptr_t     thread_xp = hal_remote_l64( XPTR( sock_cxy , &sock_ptr->tx_client ));
159
160assert( __FUNCTION__, (thread_xp != XPTR_NULL), 
161"illegal tx_client field for a retransmission timeout" );
162
163    // get TX client thread cluster
164    cxy_t      thread_cxy = GET_CXY( thread_xp );
165
166assert( __FUNCTION__, (thread_cxy == local_cxy),
167"the client thread must be running in the same cluster as the alarm handler" );
168
169    // get pointers on NIC_TX[index] chdev
170    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[channel];
171    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
172    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
173
174    // get pointers on NIC_TX[channel] server thread
175    thread_t * tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
176    xptr_t     tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
177
178    // update the date in alarm
179    alarm_update( thread_xp , hal_get_cycles() + CONFIG_SOCK_RETRY_TIMEOUT );
180   
181    //////////////////////////////
182    if( tx_cmd == CMD_TX_CONNECT ) 
183    {
184
185#if DEBUG_SOCKET_ALARM
186if( DEBUG_SOCKET_ALARM < cycle )
187printk("\n[%s] rings for CONNECT : request a new SYN segment / cycle %d\n",
188__FUNCTION__ , cycle );
189#endif
190        // set tx_valid to request the NIC_TX server to send a new SYN segment
191        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->tx_valid ) , true );
192
193        // update socket state
194        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->state ) , TCP_STATE_BOUND );
195
196        // unblock the NIC_TX server thread
197        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
198    }
199    /////////////////////////////
200    if( tx_cmd == CMD_TX_ACCEPT ) 
201    {
202
203#if DEBUG_SOCKET_ALARM
204if( DEBUG_SOCKET_ALARM < cycle )
205printk("\n[%s] rings for ACCEPT : request a new SYN-ACK segment / cycle %d\n",
206__FUNCTION__ , cycle );
207#endif
208        // set tx_valid to request the NIC_TX server to send a new SYN-ACK segment
209        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->tx_valid ) , true );
210
211        // update socket state
212        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->state ) , TCP_STATE_SYN_RCVD );
213
214        // unblock the NIC_TX server thread
215        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
216    }
217    ////////////////////////////
218    if( tx_cmd == CMD_TX_CLOSE )
219    {
220
221#if DEBUG_SOCKET_ALARM
222if( DEBUG_SOCKET_ALARM < cycle )
223printk("\n[%s] rings for CLOSE : request a new FIN-ACK segment / cycle %d\n",
224__FUNCTION__ , cycle );
225#endif
226        // set tx_valid to request the NIC_TX server to send a new FIN-ACK segment
227        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->tx_valid ) , true );
228
229        // update socket state
230        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->state ) , TCP_STATE_ESTAB );
231
232        // unblock the NIC_TX server thread
233        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
234    }
235    ///////////////////////////
236    if( tx_cmd == CMD_TX_SEND )
237    {
238        // get get relevant infos from socket pointer
239        uint32_t  tx_una = hal_remote_l32( XPTR( sock_cxy , &sock_ptr->tx_una ));
240        uint32_t  tx_ack = hal_remote_l32( XPTR( sock_cxy , &sock_ptr->tx_ack ));
241        uint32_t  tx_len = hal_remote_l32( XPTR( sock_cxy , &sock_ptr->tx_len ));
242
243#if DEBUG_SOCKET_ALARM       
244if( DEBUG_SOCKET_ALARM < cycle )
245printk("\n[%s] rings for SEND : request %d bytes / cycle %d\n",
246__FUNCTION__ , tx_len , cycle );
247#endif
248        // update command fields in socket
249        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->tx_nxt    ) , tx_una );
250        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->tx_todo   ) , tx_len - tx_ack );
251        hal_remote_s32( XPTR( sock_cxy , &sock_ptr->tx_valid  ) , true );
252
253        // unblock the NIC_TX server thread
254        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
255    }
256
257    // release the socket lock
258    remote_queuelock_release( socket_lock_xp );
259
260}   // end socket_alarm_handler()
261
262/////////////////////////////////////////////////////////////////////////////////////////
263// This static function registers the socket defined by the <socket_xp> argument into
264// the lists of sockets attached to the relevant NIC_TX and NIC_TX chdevs identified
265// by the <channel> argument, and update the channel field in socket descriptor.
266/////////////////////////////////////////////////////////////////////////////////////////
267// @ socket_xp   : [in]  extended pointer on socket descriptor.
268// @ channel     : [in]  NIC channel index.
269/////////////////////////////////////////////////////////////////////////////////////////
270static void socket_link_to_servers( xptr_t   socket_xp,
271                                    uint32_t channel )
272{
273    cxy_t      socket_cxy = GET_CXY( socket_xp );
274    socket_t * socket_ptr = GET_PTR( socket_xp );
275
276#if DEBUG_SOCKET_LINK
277thread_t  * this        = CURRENT_THREAD;
278process_t * process     = this->process;
279pid_t       socket_pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
280fdid_t      socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
281uint32_t   cycle        = (uint32_t)hal_get_cycles();
282if( DEBUG_SOCKET_LINK < cycle )
283printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / cycle %d\n",
284__FUNCTION__, process->pid, this->trdid, socket_pid, socket_fdid, cycle ); 
285#endif
286
287    // get pointers on NIC_TX[channel] chdev
288    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[channel];
289    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
290    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
291
292    // build various TX extended pointers
293    xptr_t    tx_root_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_root );
294    xptr_t    tx_lock_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_lock );
295    xptr_t    tx_list_xp = XPTR( socket_cxy   , &socket_ptr->tx_list );
296
297    // get pointers on NIC_RX[channel] chdev
298    xptr_t    rx_chdev_xp  = chdev_dir.nic_rx[channel];
299    chdev_t * rx_chdev_ptr = GET_PTR( rx_chdev_xp );
300    cxy_t     rx_chdev_cxy = GET_CXY( rx_chdev_xp );
301
302    // build various RX extended pointers
303    xptr_t    rx_root_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_root );
304    xptr_t    rx_lock_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_lock );
305    xptr_t    rx_list_xp = XPTR( socket_cxy   , &socket_ptr->rx_list );
306
307    // register socket in the NIC_TX[channel] chdev clients queue
308    remote_busylock_acquire( tx_lock_xp );
309    xlist_add_last( tx_root_xp , tx_list_xp );
310    remote_busylock_release( tx_lock_xp );
311
312    // register socket in the NIC_RX[channel] chdev clients queue
313    remote_busylock_acquire( rx_lock_xp );
314    xlist_add_last( rx_root_xp , rx_list_xp );
315    remote_busylock_release( rx_lock_xp );
316
317#if DEBUG_SOCKET_LINK
318cycle = (uint32_t)hal_get_cycles();
319if( DEBUG_SOCKET_LINK < cycle )
320printk("\n[%s] thread[%x,%x] linked socket[%x,%d] to channel %d / cycle %d\n",
321__FUNCTION__, process->pid, this->trdid, process->pid, socket_pid, socket_fdid, channel, cycle );
322#endif
323
324}  // end socket_link_to_servers()
325
326/////////////////////////////////////////////////////////////////////////////////////////
327// This function removes the socket defined by the <socket_xp> argument from the
328// lists of sockets attached to the relevant NIC_TX and NIC_TX chdevs.
329/////////////////////////////////////////////////////////////////////////////////////////
330// @ socket_xp   : [in]  extended pointer on socket descriptor
331/////////////////////////////////////////////////////////////////////////////////////////
332static void socket_unlink_from_servers( xptr_t socket_xp )
333{
334    cxy_t      socket_cxy = GET_CXY( socket_xp );
335    socket_t * socket_ptr = GET_PTR( socket_xp );
336
337#if DEBUG_SOCKET_LINK
338thread_t  * this        = CURRENT_THREAD;
339process_t * process     = this->process;
340pid_t       socket_pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
341fdid_t      socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
342uint32_t   cycle        = (uint32_t)hal_get_cycles();
343if( DEBUG_SOCKET_LINK < cycle )
344printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / cycle %d\n",
345__FUNCTION__, process->pid, this->trdid, socket_pid, socket_fdid, cycle ); 
346#endif
347
348    // get NIC channel
349    uint32_t channel = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->nic_channel ));
350
351    // get pointers on NIC_TX[channel] chdev
352    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[channel];
353    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
354    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
355
356    // build various TX extended pointers
357    xptr_t    tx_lock_xp   = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_lock );
358    xptr_t    tx_list_xp   = XPTR( socket_cxy   , &socket_ptr->tx_list );
359    xptr_t    tx_list_next = hal_remote_l64( tx_list_xp );
360    xptr_t    tx_list_pred = hal_remote_l64( tx_list_xp + sizeof(xptr_t) );
361
362    // get pointers on NIC_RX[channel] chdev
363    xptr_t    rx_chdev_xp  = chdev_dir.nic_rx[channel];
364    chdev_t * rx_chdev_ptr = GET_PTR( rx_chdev_xp );
365    cxy_t     rx_chdev_cxy = GET_CXY( rx_chdev_xp );
366
367    // build various RX extended pointers
368    xptr_t    rx_lock_xp   = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_lock );
369    xptr_t    rx_list_xp   = XPTR( socket_cxy   , &socket_ptr->rx_list );
370    xptr_t    rx_list_next = hal_remote_l64( rx_list_xp );
371    xptr_t    rx_list_pred = hal_remote_l64( rx_list_xp + sizeof(xptr_t) );
372
373    // remove socket from the NIC_TX[channel] chdev clients queue if registered
374    if( (tx_list_next != XPTR_NULL) || (tx_list_pred != XPTR_NULL) )
375    {
376        remote_busylock_acquire( tx_lock_xp );
377        xlist_unlink( tx_list_xp );
378        remote_busylock_release( tx_lock_xp );
379    }
380
381    // remove socket from the NIC_RX[channel] chdev clients queue if registered
382    if( (rx_list_next != XPTR_NULL) || (rx_list_pred != XPTR_NULL) )
383    {
384        remote_busylock_acquire( rx_lock_xp );
385        xlist_unlink( rx_list_xp );
386        remote_busylock_release( rx_lock_xp );
387    }
388
389#if DEBUG_SOCKET_LINK
390cycle = (uint32_t)hal_get_cycles();
391if( DEBUG_SOCKET_LINK < cycle )
392printk("\n[%s] thread[%x,%x] unlinked socket [%x,%d] / cycle %d\n",
393__FUNCTION__, process->pid, this->trdid, socket_pid, socket_fdid, cycle ); 
394#endif
395
396}  // end socket_unlink_from_servers()
397       
398/////////////////////////////////////////////////////////////////////////////////////////
399// This function registers the socket defined by the <socket_xp> argument into the
400// list of listening sockets rooted in the nic_rx[0] chdev.
401/////////////////////////////////////////////////////////////////////////////////////////
402// @ socket_xp   : [in]  extended pointer on socket descriptor
403/////////////////////////////////////////////////////////////////////////////////////////
404static void socket_link_to_listen( xptr_t socket_xp )
405{
406    // get socket cluster and local pointer
407    socket_t * socket_ptr = GET_PTR( socket_xp );
408    cxy_t      socket_cxy = GET_CXY( socket_xp );
409
410    // get pointers on NIC_RX[0] chdev
411    xptr_t    rx0_chdev_xp  = chdev_dir.nic_rx[0];
412    chdev_t * rx0_chdev_ptr = GET_PTR( rx0_chdev_xp );
413    cxy_t     rx0_chdev_cxy = GET_CXY( rx0_chdev_xp );
414   
415    // build extended pointers on list of listening sockets
416    xptr_t    rx0_root_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.root );
417    xptr_t    rx0_lock_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.lock );
418
419    // build extended pointer on socket rx_list field
420    xptr_t    list_entry_xp = XPTR( socket_cxy , &socket_ptr->rx_list );
421
422    // register socket in listening sockets list
423    remote_busylock_acquire( rx0_lock_xp );
424    xlist_add_last( rx0_root_xp , list_entry_xp );
425    remote_busylock_release( rx0_lock_xp );
426
427}  // end socket_link_to_listen()
428
429/////////////////////////////////////////////////////////////////////////////////////////
430// This function removes the socket defined by the <socket_xp> argument from the
431// list of listening sockets rooted in the nic_rx[0] chdev.
432/////////////////////////////////////////////////////////////////////////////////////////
433// @ socket_xp   : [in]  extended pointer on socket descriptor
434/////////////////////////////////////////////////////////////////////////////////////////
435static void socket_unlink_from_listen( xptr_t socket_xp )
436{
437    // get socket cluster and local pointer
438    socket_t * socket_ptr = GET_PTR( socket_xp );
439    cxy_t      socket_cxy = GET_CXY( socket_xp );
440
441    // get pointers on NIC_RX[0] chdev
442    xptr_t    rx0_chdev_xp  = chdev_dir.nic_rx[0];
443    chdev_t * rx0_chdev_ptr = GET_PTR( rx0_chdev_xp );
444    cxy_t     rx0_chdev_cxy = GET_CXY( rx0_chdev_xp );
445   
446    // build extended pointers on lock protecting list of listening sockets
447    xptr_t    rx0_lock_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.lock );
448
449    // build extended pointer on socket rx_list field
450    xptr_t    list_entry_xp = XPTR( socket_cxy , &socket_ptr->rx_list );
451
452    // register socket in listening sockets list
453    remote_busylock_acquire( rx0_lock_xp );
454    xlist_unlink( list_entry_xp );
455    remote_busylock_release( rx0_lock_xp );
456
457}  // end socket_unlink_from_listen()
458
459/////////////////////////////////////////////////////////////////////////////////////////
460// This static function is called by the socket_build() and socket_accept() functions.
461// It allocates memory in cluster defined by the <cxy> argument for all structures
462// associated to a socket: file descriptor, socket descriptor, RX buffer, R2T queue,
463// and CRQ queue. It allocates an fdid, and register it in the process fd_array.
464// It initialise the socket desccriptor static fields, other than local_addr,
465// local_port, remote_addr, remote_port), and set the socket state to UNBOUND.
466// It returns the local pointer on socket descriptor and the fdid value in buffers
467// defined by the <socket_ptr> & <fdid_ptr> arguments.
468/////////////////////////////////////////////////////////////////////////////////////////
469// @ cxy        : [in]  target cluster fo socket & file descriptors.
470// @ domain     : [in]  socket domain.
471// @ type       : [in]  socket type.
472// @ socket_ptr : [out] local pointer on buffer for socket pointer.
473// @ fdid_ptr   : [out] local pointer on buffer for fdid value.
474// # return 0 if success / return -1 if no memory.
475/////////////////////////////////////////////////////////////////////////////////////////
476static error_t socket_create( cxy_t       cxy,
477                              uint32_t    domain,
478                              uint32_t    type,
479                              socket_t ** socket_ptr,
480                              uint32_t  * fdid_ptr )
481{
482    uint32_t       fdid;
483    socket_t     * socket;
484    vfs_file_t   * file;
485    uint32_t       state;
486    void         * tx_buf;
487    error_t        error;
488
489
490    thread_t  * this    = CURRENT_THREAD;
491    process_t * process = this->process;
492
493#if DEBUG_SOCKET_CREATE || DEBUG_SOCKET_ERROR
494uint32_t cycle = (uint32_t)hal_get_cycles();
495#endif
496
497#if DEBUG_SOCKET_CREATE
498if( DEBUG_SOCKET_CREATE < cycle )
499printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
500__FUNCTION__, process->pid, this->trdid, cycle ); 
501#endif
502   
503    // 1. allocate memory for socket descriptor
504    socket = kmem_remote_alloc( cxy , bits_log2(sizeof(socket_t)) , AF_ZERO );
505
506    if( socket == NULL )
507    {
508
509#if DEBUG_SOCKET_ERROR
510printk("\n[ERROR] in %s : cannot allocate socket descriptor / thread[%x,%x] / cycle %d\n",
511__FUNCTION__, process->pid, this->trdid, cycle );
512#endif
513        return -1;
514    }
515
516    // 2. allocate memory for rx_buf data buffer
517    error = remote_buf_init( XPTR( cxy , &socket->rx_buf ),
518                             CONFIG_SOCK_RX_BUF_ORDER );
519
520    if( error )
521    {
522
523#if DEBUG_SOCKET_ERROR
524printk("\n[ERROR] in %s : no memory for rx_buf / thread[%x,%x] / cycle %d\n",
525__FUNCTION__, process->pid, this->trdid, cycle );
526#endif
527        kmem_remote_free( cxy , socket , bits_log2(sizeof(socket_t)) );  // 1
528        return -1;
529    }
530
531    // 3. allocate memory for tx_buf
532    tx_buf = kmem_remote_alloc( cxy , CONFIG_SOCK_TX_BUF_ORDER , AF_NONE );
533
534    if( tx_buf == NULL )
535    {
536
537#if DEBUG_SOCKET_ERROR
538printk("\n[ERROR] in %s : no memory for tx_buf / thread[%x,%x] / cycle %d\n",
539__FUNCTION__, process->pid, this->trdid, cycle );
540#endif
541        remote_buf_release_data( XPTR( cxy , &socket->rx_buf ) );        // 2
542        kmem_remote_free( cxy , socket , bits_log2(sizeof(socket_t)) );  // 1
543        return -1;
544    }
545
546    // 4. allocate memory for r2tq queue
547    error = remote_buf_init( XPTR( cxy , &socket->r2tq ),
548                             bits_log2( CONFIG_SOCK_R2T_BUF_SIZE ) );
549    if( error )
550    {
551
552#if DEBUG_SOCKET_ERROR
553printk("\n[ERROR] in %s : cannot allocate R2T queue / thread[%x,%x] / cycle %d\n",
554__FUNCTION__, process->pid, this->trdid, cycle );
555#endif
556        kmem_remote_free( cxy , tx_buf , CONFIG_SOCK_TX_BUF_ORDER );     // 3
557        remote_buf_release_data( XPTR( cxy , &socket->rx_buf ) );        // 2
558        kmem_remote_free( cxy , socket , bits_log2(sizeof(socket_t)) );  // 1
559        return -1;
560    }
561
562    // don't allocate memory for CRQ queue / done by the socket_listen function
563
564    // 5. allocate memory for file descriptor
565        file = kmem_remote_alloc( cxy , bits_log2(sizeof(vfs_file_t)) , AF_ZERO );
566
567    if( file == NULL ) 
568    {
569
570#if DEBUG_SOCKET_ERROR
571printk("\n[ERROR] in %s : cannot allocate file descriptor / thread[%x,%x] / cycle %d\n",
572__FUNCTION__, process->pid, this->trdid, cycle );
573#endif
574        remote_buf_release_data( XPTR( cxy , &socket->r2tq ) );          // 4
575        kmem_remote_free( cxy , tx_buf , CONFIG_SOCK_TX_BUF_ORDER );     // 3
576        remote_buf_release_data( XPTR( cxy , &socket->rx_buf ) );        // 2
577        kmem_remote_free( cxy , socket , bits_log2(sizeof(socket_t)) );  // 1
578        return -1;
579    }
580   
581    // 6. get an fdid value, and register file descriptor in fd_array[]
582    error = process_fd_register( process->ref_xp,
583                                 XPTR( cxy , file ),
584                                 &fdid );
585    if ( error ) 
586    {
587
588#if DEBUG_SOCKET_ERROR
589if( DEBUG_SOCKET_ERROR < cycle )
590printk("\n[ERROR] in %s : cannot register file descriptor / thread[%x,%x] / cycle %d\n",
591__FUNCTION__, process->pid, this->trdid, cycle );
592#endif
593        kmem_remote_free( cxy , file , bits_log2(sizeof(vfs_file_t)) );  // 5
594        remote_buf_release_data( XPTR( cxy , &socket->r2tq ) );          // 4
595        kmem_remote_free( cxy , tx_buf , CONFIG_SOCK_TX_BUF_ORDER );     // 3
596        remote_buf_release_data( XPTR( cxy , &socket->rx_buf ) );        // 2
597        kmem_remote_free( cxy , socket , bits_log2(sizeof(socket_t)) );  // 1
598        return -1;
599    }
600
601    state = (type == SOCK_STREAM) ? TCP_STATE_UNBOUND : UDP_STATE_UNBOUND;
602
603    // initialise socket descriptor
604    hal_remote_s32( XPTR( cxy , &socket->pid         ) , process->pid );
605    hal_remote_s32( XPTR( cxy , &socket->fdid        ) , fdid );
606    hal_remote_s32( XPTR( cxy , &socket->domain      ) , domain );
607    hal_remote_s32( XPTR( cxy , &socket->type        ) , type );
608    hal_remote_s32( XPTR( cxy , &socket->state       ) , state );
609    hal_remote_s64( XPTR( cxy , &socket->tx_client   ) , XPTR_NULL );
610    hal_remote_s64( XPTR( cxy , &socket->rx_client   ) , XPTR_NULL );
611    hal_remote_s32( XPTR( cxy , &socket->tx_valid    ) , false );
612    hal_remote_s32( XPTR( cxy , &socket->rx_valid    ) , false );
613    hal_remote_s32( XPTR( cxy , &socket->nic_channel ) , 0 );
614    hal_remote_spt( XPTR( cxy , &socket->tx_buf      ) , tx_buf );
615
616    // initialize file descriptor
617    hal_remote_s32( XPTR( cxy , &file->type        ) , FILE_TYPE_SOCK );
618    hal_remote_spt( XPTR( cxy , &file->socket      ) , socket );
619
620    // initialize socket lock
621    remote_queuelock_init( XPTR( cxy , &socket->lock ) , LOCK_SOCKET_STATE );
622
623#if DEBUG_SOCKET_CREATE
624cycle = (uint32_t)hal_get_cycles();
625if( DEBUG_SOCKET_CREATE < cycle )
626printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / xptr[%x,%x] / cycle %d\n",
627__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cxy, socket, cycle );
628#endif
629   
630    // return success
631    *socket_ptr = socket;
632    *fdid_ptr   = fdid;
633
634    return 0;
635
636}  // end socket_create
637
638/////////////////////////////////////////////////////////////////////////////////////////
639// This static function is called by the socket_close() function to destroy a socket
640// identified by the <file_xp> argument.
641// It remove the associated file from the reference process fd_array. It unlink the
642// socket from the NIC_TX [k] and NIC_RX[k] chdevs. It release all memory allocated
643// for the structures associated to the target socket : file descriptor, socket
644// descriptor, RX buffer, R2T queue, CRQ queue.
645/////////////////////////////////////////////////////////////////////////////////////////
646// @ file_xp  : extended pointer on the file descriptor.
647/////////////////////////////////////////////////////////////////////////////////////////
648static void socket_destroy( xptr_t file_xp )
649{
650    thread_t  * this    = CURRENT_THREAD;
651    process_t * process = this->process;
652
653// check file_xp argument
654assert( __FUNCTION__, (file_xp != XPTR_NULL), "illegal argument\n" );
655
656    // get cluster & local pointer for file descriptor
657    vfs_file_t * file_ptr = GET_PTR( file_xp );
658    cxy_t        file_cxy = GET_CXY( file_xp );
659
660    // get local pointer for socket and file type
661    socket_t * socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
662    uint32_t   file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
663   
664// check file descriptor type
665assert( __FUNCTION__, (file_type == FILE_TYPE_SOCK), "illegal file type\n" );
666
667    // get socket nic_channel, state, pid and fdid
668    uint32_t state   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
669    uint32_t fdid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->fdid ));
670   
671#if DEBUG_SOCKET_DESTROY
672uint32_t cycle = (uint32_t)hal_get_cycles();
673pid_t    pid   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->pid ));
674if( DEBUG_SOCKET_DESTROY < cycle )
675printk("\n[%s] thread[%x,%x] enter / file[%x,%x] / cycle %d\n",
676__FUNCTION__, process->pid, this->trdid, pid, fdid, cycle );
677#endif
678
679    // remove socket from NIC_TX & NIC_RX chdev queues
680    //  or from the listening sockets list
681    if( state == TCP_STATE_LISTEN ) 
682    {
683        socket_unlink_from_listen( XPTR( file_cxy , socket_ptr ) );
684    }
685    else
686    {
687        socket_unlink_from_servers( XPTR( file_cxy , socket_ptr ) );
688    }
689
690    // remove the file descriptor from the fd_array
691    process_fd_remove( process->owner_xp , fdid );
692
693    // release memory allocated for file descriptor
694    kmem_remote_free( file_cxy , file_ptr , bits_log2(sizeof(vfs_file_t)) );
695
696    // release memory allocated for buffers attached to socket descriptor
697    remote_buf_release_data( XPTR( file_cxy , &socket_ptr->crqq ) );
698    remote_buf_release_data( XPTR( file_cxy , &socket_ptr->r2tq ) );
699    remote_buf_release_data( XPTR( file_cxy , &socket_ptr->rx_buf ) );
700
701    // release memory allocated for socket descriptor
702    kmem_remote_free( file_cxy , socket_ptr , bits_log2(sizeof(socket_t)) );
703
704#if DEBUG_SOCKET_DESTROY
705cycle = (uint32_t)hal_get_cycles();
706if( DEBUG_SOCKET_DESTROY < cycle )
707printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
708__FUNCTION__, process->pid, this->trdid, cycle );
709#endif
710
711}  // end socket_destroy()
712
713////////////////////////////////////////////////
714void socket_put_r2t_request( xptr_t    queue_xp,
715                             uint8_t   flags,
716                             uint32_t  channel )
717{
718    xptr_t     chdev_xp;
719    cxy_t      chdev_cxy;
720    chdev_t  * chdev_ptr;
721    thread_t * server_ptr;
722    xptr_t     server_xp;
723
724    while( 1 )
725    {
726        // try to register R2T request
727        error_t error = remote_buf_put_from_kernel( queue_xp,
728                                                    &flags,
729                                                    1 );
730        if( error )
731        {
732            // queue full => wait and retry
733            sched_yield( "waiting R2T queue" );
734        }
735        else
736        {
737            // get NIC_TX chdev pointers
738            chdev_xp = chdev_dir.nic_tx[channel];
739            chdev_cxy = GET_CXY( chdev_xp );
740            chdev_ptr = GET_PTR( chdev_xp );
741 
742            // get NIC_TX server thread pointers
743            server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server ) );
744            server_xp  = XPTR( chdev_cxy , server_ptr );
745
746            // unblocks NIC_TX server thread
747            thread_unblock( server_xp , THREAD_BLOCKED_CLIENT );
748
749            return;
750        }
751    }
752}  // end socket_put_r2t_request()
753
754///////////////////////////////////////////////////
755error_t socket_get_r2t_request( xptr_t    queue_xp,
756                                uint8_t * flags )
757{
758    // get one request from R2T queue
759    return remote_buf_get_to_kernel( queue_xp,
760                                     flags,
761                                     1 );
762}  // end socket_get_r2T_request()
763 
764///////////////////////////////////////////////////
765error_t socket_put_crq_request( xptr_t    queue_xp,
766                                uint32_t  remote_addr,
767                                uint32_t  remote_port,
768                                uint32_t  remote_iss,
769                                uint32_t  remote_window )
770{
771    connect_request_t   req;
772
773    // build request
774    req.addr   = remote_addr;
775    req.port   = remote_port;
776    req.iss    = remote_iss;
777    req.window = remote_window;
778
779    // try to register request in CRQ
780    return remote_buf_put_from_kernel( queue_xp,
781                                       (uint8_t *)(&req),
782                                       sizeof(connect_request_t) );
783}  // end socket_put_crq_request()
784 
785////////////////////////////////////////////////////
786error_t socket_get_crq_request( xptr_t     queue_xp,
787                                uint32_t * remote_addr,
788                                uint32_t * remote_port,
789                                uint32_t * remote_iss,
790                                uint32_t * remote_window )
791{
792    connect_request_t   req;
793    error_t             error;
794
795    // get request from CRQ
796    error = remote_buf_get_to_kernel( queue_xp,
797                                      (uint8_t *)(&req),
798                                      sizeof(connect_request_t) );
799    // extract request arguments
800    *remote_addr   = req.addr;
801    *remote_port   = req.port;
802    *remote_iss    = req.iss;
803    *remote_window = req.window;
804
805    return error;
806
807}  // end socket_get_crq_request()
808 
809
810/////////////////////////////////////////////////////////////////////////////////////////
811//                 Functions implementing the SOCKET related syscalls
812/////////////////////////////////////////////////////////////////////////////////////////
813
814//////////////////////////////////////
815int socket_build( uint32_t   domain,
816                  uint32_t   type )
817{
818    uint32_t    fdid;
819    socket_t  * socket;
820    error_t     error;
821
822#if DEBUG_SOCKET_BUILD
823uint32_t    cycle   = (uint32_t)hal_get_cycles();
824thread_t  * this    = CURRENT_THREAD;
825process_t * process = this->process;
826if( DEBUG_SOCKET_BUILD < cycle )
827printk("\n[%s] thread[%x,%x] enter / %s / %s / cycle %d\n",
828__FUNCTION__, process->pid, this->trdid, 
829socket_domain_str(domain), socket_type_str(type), cycle );
830#endif
831
832
833    // allocate memory for the file descriptor and for the socket
834    error = socket_create( local_cxy,
835                           domain,
836                           type,
837                           &socket, 
838                           &fdid );
839
840#if DEBUG_SOCKET_BUILD
841cycle = (uint32_t)hal_get_cycles();
842if( DEBUG_SOCKET_BUILD < cycle )
843printk("\n[%s] thread[%x,%x] exit / socket %x / fdid %d / %s / cycle %d\n",
844__FUNCTION__, process->pid, this->trdid, socket, fdid, 
845socket_state_str(hal_remote_l32(XPTR(local_cxy , &socket->state))),
846cycle );
847#endif
848
849    if( error ) return -1;
850    return fdid;
851}
852
853////////////////////////////////
854int socket_bind( uint32_t  fdid,
855                 uint32_t  addr,
856                 uint16_t  port )
857{
858    vfs_file_type_t    file_type;
859    socket_t          * socket;
860    uint32_t            socket_type;
861    uint32_t            socket_state;
862
863    thread_t  * this    = CURRENT_THREAD;
864    process_t * process = this->process;
865
866#if DEBUG_SOCKET_BIND || DEBUG_SOCKET_ERROR
867uint32_t cycle = (uint32_t)hal_get_cycles();
868#endif
869
870#if DEBUG_SOCKET_BIND
871if( DEBUG_SOCKET_BIND < cycle )
872printk("\n[%s] thread[%x,%x] enter / socket[%x,%d] / addr %x / port %x / cycle %d\n",
873__FUNCTION__, process->pid, this->trdid, process->pid, fdid, addr, port, cycle );
874#endif
875
876    // get pointers on file descriptor
877    xptr_t       file_xp  = process_fd_get_xptr_from_local( process , fdid );
878    vfs_file_t * file_ptr = GET_PTR( file_xp );
879    cxy_t        file_cxy = GET_CXY( file_xp );
880
881    // check file_xp
882    if( file_xp == XPTR_NULL )
883    {
884
885#if DEBUG_SOCKET_ERROR
886printk("\n[ERROR] in %s : undefined fdid %d / thread[%x,%x] / cycle %d\n",
887__FUNCTION__, fdid, process->pid, this->trdid, cycle );
888#endif
889        return -1;
890    }
891
892    file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
893    socket    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
894
895    // check file descriptor type
896    if( file_type != FILE_TYPE_SOCK )
897    {
898
899#if DEBUG_SOCKET_ERROR
900printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x] / cycle %d",
901__FUNCTION__, vfs_inode_type_str( file_type ), process->pid, this->trdid, cycle );
902#endif
903        return -1;
904    }
905
906    // get socket type
907    socket_type = hal_remote_l32(XPTR( file_cxy , &socket->type ));
908
909    // compute socket state
910    socket_state = (socket_type == SOCK_STREAM) ? TCP_STATE_BOUND : UDP_STATE_BOUND;
911
912    // update the socket descriptor
913    hal_remote_s32( XPTR( file_cxy , &socket->local_addr ) , addr );
914    hal_remote_s32( XPTR( file_cxy , &socket->local_port ) , port );
915    hal_remote_s32( XPTR( file_cxy , &socket->state      ) , socket_state );
916
917#if DEBUG_SOCKET_BIND
918cycle = (uint32_t)hal_get_cycles();
919if( DEBUG_SOCKET_BIND < cycle )
920printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / %s / addr %x / port %x / cycle %d\n",
921__FUNCTION__, process->pid, this->trdid, process->pid, fdid,
922socket_state_str(hal_remote_l32( XPTR( file_cxy , &socket->state ))),
923hal_remote_l32( XPTR( file_cxy , &socket->local_addr )),
924hal_remote_l32( XPTR( file_cxy , &socket->local_port )),
925cycle );
926#endif
927
928    return 0;
929
930}  // end socket_bind()
931
932//////////////////////////////////
933int socket_listen( uint32_t fdid,
934                   uint32_t crq_depth )
935{
936    xptr_t              file_xp;
937    vfs_file_t        * file_ptr;
938    cxy_t               file_cxy;
939    vfs_file_type_t    file_type;
940    socket_t          * socket_ptr;
941    uint32_t            socket_type;
942    uint32_t            socket_state;
943    uint32_t            socket_local_addr;
944    uint32_t            socket_local_port;
945    error_t             error;
946
947    thread_t  * this    = CURRENT_THREAD;
948    process_t * process = this->process;
949
950#if DEBUG_SOCKET_LISTEN || DEBUG_SOCKET_ERROR
951uint32_t cycle = (uint32_t)hal_get_cycles();
952#endif
953
954#if DEBUG_SOCKET_LISTEN
955if( DEBUG_SOCKET_LISTEN < cycle )
956printk("\n[%s] thread[%x,%x] enter / socket[%x,%d] / crq_depth %x / cycle %d\n",
957__FUNCTION__, process->pid, this->trdid, process->pid, fdid, crq_depth, cycle );
958#endif
959
960    // get pointers on file descriptor
961    file_xp  = process_fd_get_xptr_from_local( process , fdid );
962    file_ptr = GET_PTR( file_xp );
963    file_cxy = GET_CXY( file_xp );
964
965    // check file_xp
966    if( file_xp == XPTR_NULL )
967    {
968
969#if DEBUG_SOCKET_ERROR
970printk("\n[ERROR] in %s : undefined fdid %d / thread[%x,%x] / cycle %d\n",
971__FUNCTION__, fdid, process->pid, this->trdid, cycle );
972#endif
973        return -1;
974    }
975
976    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
977    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
978
979    // check file descriptor type
980    if( file_type != FILE_TYPE_SOCK )
981    {
982
983#if DEBUG_SOCKET_ERROR
984printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x] / cycle %d\n",
985__FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid, cycle );
986#endif
987        return -1;
988    }
989
990    // get relevant infos from socket descriptor
991    socket_type       = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type )); 
992    socket_state      = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state )); 
993    socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_addr )); 
994    socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_port )); 
995
996    // check socket type
997    if( socket_type != SOCK_STREAM )
998    {
999
1000#if DEBUG_SOCKET_ERROR
1001printk("\n[ERROR] in %s : illegal socket type %s / thread[%x,%x] / cycle %d\n",
1002__FUNCTION__, socket_type_str(socket_type), process->pid, this->trdid, cycle );
1003#endif
1004        return -1;
1005    }
1006   
1007    // check socket state
1008    if( socket_state != TCP_STATE_BOUND )
1009    {
1010
1011#if DEBUG_SOCKET_ERROR
1012printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x] / cycle %d\n",
1013__FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid, cycle );
1014#endif
1015        return -1;
1016    }
1017   
1018    // compute CRQ queue depth : max( crq_depth , CONFIG_SOCK_CRQ_BUF_SIZE )
1019    uint32_t depth = ( crq_depth > CONFIG_SOCK_CRQ_BUF_SIZE ) ? 
1020                     crq_depth : CONFIG_SOCK_CRQ_BUF_SIZE;
1021
1022    // allocate memory for the CRQ queue
1023    error = remote_buf_init( XPTR( file_cxy , &socket_ptr->crqq ),
1024                                   bits_log2( depth * sizeof(connect_request_t)) );
1025    if( error )
1026    {
1027
1028#if DEBUG_SOCKET_ERROR
1029printk("\n[ERROR] in %s : cannot allocate CRQ queue / thread[%x,%x] / cycle %d\n",
1030__FUNCTION__, process->pid, this->trdid, cycle );
1031#endif
1032        return -1;
1033    }
1034
1035    // update socket.state
1036    hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , TCP_STATE_LISTEN );
1037
1038    // register socket in the list of listening socket
1039    socket_link_to_listen( XPTR( file_cxy , socket_ptr ) );
1040
1041#if DEBUG_SOCKET_LISTEN
1042cycle = (uint32_t)hal_get_cycles();
1043if( DEBUG_SOCKET_LISTEN < cycle )
1044printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / %s / cycle %d\n",
1045__FUNCTION__, process->pid, this->trdid, process->pid, fdid,
1046socket_state_str(socket_state), cycle );
1047#endif
1048
1049    return 0;
1050
1051}  // end socket_listen()
1052
1053///////////////////////////////////
1054int socket_accept( uint32_t   fdid,
1055                   uint32_t * remote_addr,
1056                   uint16_t * remote_port )
1057{
1058    xptr_t              file_xp;             // extended pointer on remote file
1059    vfs_file_t        * file_ptr;
1060    cxy_t               file_cxy;
1061    vfs_file_type_t     file_type;           // file descriptor type
1062    socket_t          * socket_ptr;          // local pointer on remote waiting socket
1063    uint32_t            socket_type;         // listening socket type   
1064    uint32_t            socket_state;        // listening socket state
1065    uint32_t            socket_domain;       // listening socket domain
1066    uint32_t            socket_local_addr;   // listening socket local IP address
1067    uint32_t            socket_local_port;   // listening socket local port
1068    uint32_t            socket_tx_nxt;       // listening socket tx_nxt
1069    bool_t              socket_tx_valid;     // listening socket tx_valid
1070    xptr_t              socket_tx_client;    // listening socket tx_client thread
1071    bool_t              socket_rx_valid;     // listening socket rx_valid
1072    xptr_t              socket_rx_client;    // listening socket rx_client thread
1073    xptr_t              socket_lock_xp;      // listening socket lock
1074    xptr_t              crq_xp;              // listening socket CRQ queue
1075    uint32_t            crq_status;          // number of bytes in CRQ
1076    cxy_t               new_socket_cxy;      // new socket cluster identifier
1077    socket_t          * new_socket_ptr;      // local pointer on new socket
1078    xptr_t              new_socket_xp;       // extended pointer on new socket
1079    volatile uint32_t   new_state;           // new socket state (modified by NIC_RX thread)
1080    uint32_t            new_fdid;            // new socket file descriptor index
1081    uint32_t            new_remote_addr;     // new socket remote IP address
1082    uint32_t            new_remote_port;     // new socket remote port
1083    uint32_t            new_remote_iss;      // new socket remote iss
1084    uint32_t            new_remote_window;   // new socket receive window
1085    xptr_t              tx_server_xp;        // extended pointer on TX server thread
1086    thread_t          * tx_server_ptr;       // local pointer on TX server thread
1087    uint32_t            cmd_status;          // command status (rx_sts or tx_sts)
1088    bool_t              cmd_valid;           // valid command (rx_valid or tx_valid)
1089    error_t             error;
1090
1091    thread_t  * this      = CURRENT_THREAD;
1092    xptr_t      client_xp = XPTR( local_cxy , this );
1093    process_t * process   = this->process;
1094
1095#if DEBUG_SOCKET_ACCEPT || DEBUG_SOCKET_ERROR
1096uint32_t cycle = (uint32_t)hal_get_cycles();
1097#endif
1098
1099#if DEBUG_SOCKET_ACCEPT
1100if( DEBUG_SOCKET_ACCEPT < cycle )
1101printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / cycle %d\n",
1102__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
1103#endif
1104
1105    // 1) get pointers on file descriptor
1106    file_xp  = process_fd_get_xptr_from_local( process , fdid );
1107    file_ptr = GET_PTR( file_xp );
1108    file_cxy = GET_CXY( file_xp );
1109
1110    // check file_xp
1111    if( file_xp == XPTR_NULL )
1112    {
1113
1114#if DEBUG_SOCKET_ERROR
1115printk("\n[ERROR] in %s : undefined fdid %d / thead[%x,%x] / cycle %d",
1116__FUNCTION__, fdid, process->pid, this->trdid, cycle );
1117#endif
1118        return -1;
1119    }
1120 
1121    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
1122    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
1123
1124    // check file descriptor type
1125    if( file_type != FILE_TYPE_SOCK )
1126    {
1127
1128#if DEBUG_SOCKET_ERROR
1129printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x] / cycle %d\n",
1130__FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid, cycle );
1131#endif
1132        return -1;
1133    }
1134
1135    // build extended pointer on listening socket lock
1136    socket_lock_xp = XPTR( file_cxy , &socket_ptr->lock );
1137
1138    // acquire listening socket lock
1139    remote_queuelock_acquire( socket_lock_xp );
1140                   
1141    // get listening socket type, domain, state, local_addr, local_port & tx_nxt
1142    socket_type       = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type )); 
1143    socket_state      = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state )); 
1144    socket_domain     = hal_remote_l32( XPTR( file_cxy , &socket_ptr->domain )); 
1145    socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_addr )); 
1146    socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_port )); 
1147    socket_tx_nxt     = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_nxt ));
1148    socket_tx_valid   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid )); 
1149    socket_tx_client  = hal_remote_l64( XPTR( file_cxy , &socket_ptr->tx_client ));
1150    socket_rx_valid   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid )); 
1151    socket_rx_client  = hal_remote_l64( XPTR( file_cxy , &socket_ptr->rx_client ));
1152
1153    // check socket type
1154    if( socket_type != SOCK_STREAM )
1155    {
1156                   
1157#if DEBUG_SOCKET_ERROR
1158printk("\n[ERROR] in %s : illegal socket type %s / thread[%x,%x] / cycle %d\n",
1159__FUNCTION__, socket_type_str(socket_type), process->pid , this->trdid, cycle );
1160#endif
1161        remote_queuelock_release( socket_lock_xp );
1162        return -1;
1163    }
1164   
1165    // check socket state
1166    if( socket_state != TCP_STATE_LISTEN ) 
1167    {
1168
1169#if DEBUG_SOCKET_ERROR
1170printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x] / cycle %d\n",
1171__FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid, cycle );
1172#endif
1173        remote_queuelock_release( socket_lock_xp );
1174        return -1;
1175    }
1176   
1177    // check no previous RX command
1178    if( (socket_rx_valid == true) || (socket_rx_client != XPTR_NULL) )
1179    { 
1180
1181#if DEBUG_SOCKET_ERROR
1182printk("\n[ERROR] in %s : previous RX cmd on socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1183__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
1184#endif
1185        remote_queuelock_release( socket_lock_xp );
1186        return -1;
1187    }
1188
1189    // check no previous TX command
1190    if( (socket_tx_valid == true) || (socket_tx_client != XPTR_NULL) )
1191    { 
1192                   
1193#if DEBUG_SOCKET_ERROR
1194printk("\n[ERROR] in %s : previous TX cmd on socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1195__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
1196#endif
1197        remote_queuelock_release( socket_lock_xp );
1198        return -1;
1199    }
1200
1201    // 2) check the listenig socket CRQ
1202    crq_xp  = XPTR( file_cxy , &socket_ptr->crqq );
1203
1204    // get CRQ status
1205    crq_status = remote_buf_status( crq_xp );
1206
1207    // block & deschedule to wait a client request when CRQ empty
1208    if( crq_status == 0 )
1209    {
1210        // register command arguments for NIC_RX server in listening socket
1211        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_cmd    ), CMD_RX_ACCEPT );
1212        hal_remote_s64( XPTR( file_cxy , &socket_ptr->rx_client ), client_xp );
1213        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_valid  ), true );
1214
1215        // release listening socket lock
1216        remote_queuelock_release( socket_lock_xp );
1217
1218#if DEBUG_SOCKET_ACCEPT
1219cycle = (uint32_t)hal_get_cycles();
1220if( DEBUG_SOCKET_ACCEPT < cycle )
1221printk("\n[%s] thread[%x,%x] socket[%x,%d] / CRQ empty => blocks on <IO> / cycle %d\n",
1222__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
1223#endif
1224        // block & deschedule when CRQQ empty
1225        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
1226        sched_yield( "CRQ queue empty");
1227
1228#if DEBUG_SOCKET_ACCEPT
1229cycle = (uint32_t)hal_get_cycles();
1230if( DEBUG_SOCKET_ACCEPT < cycle )
1231printk("\n[%s] thread[%x,%x] socket[%x,%d] / resumes / cycle %d\n",
1232__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
1233#endif
1234        // take listening socket lock
1235        remote_queuelock_acquire( socket_lock_xp );
1236
1237        // get CRQ status & command status
1238        cmd_valid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid ) );
1239        cmd_status   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_sts ) );
1240        crq_status   = remote_buf_status( crq_xp );
1241
1242assert( __FUNCTION__,
1243(((crq_status > 0) || (cmd_status!= CMD_STS_SUCCESS)) && (cmd_valid == false)),
1244"illegal socket state when client thread resumes after RX_ACCEPT" );
1245
1246        // reset socket.rx_client
1247        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_client ) , XPTR_NULL );
1248
1249        if( cmd_status != CMD_STS_SUCCESS )
1250        {
1251
1252#if DEBUG_SOCKET_ERROR
1253printk("\n[ERROR] in %s : reported for RX / socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1254__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
1255#endif
1256            remote_queuelock_release( socket_lock_xp );
1257            return -1;
1258        }
1259    }  // end blocking on CRQ empty
1260
1261    // from this point, we can extract a request from listening socket CRQ
1262    error = socket_get_crq_request( crq_xp,
1263                                    &new_remote_addr,
1264                                    &new_remote_port,
1265                                    &new_remote_iss,
1266                                    &new_remote_window );
1267assert( __FUNCTION__, (error == 0),
1268"cannot get a connection request from a non-empty CRQ" ); 
1269
1270    // release listening socket lock
1271    remote_queuelock_release( socket_lock_xp );
1272
1273#if DEBUG_SOCKET_ACCEPT
1274cycle = (uint32_t)hal_get_cycles();
1275if( DEBUG_SOCKET_ACCEPT < cycle )
1276printk("\n[%s] thread[%x,%x] socket[%x,%d] / CRQ request [addr %x / port %x] / cycle %d\n",
1277__FUNCTION__, process->pid, this->trdid, process->pid, fdid,
1278new_remote_addr, new_remote_port, cycle );
1279#endif
1280
1281    // 3) select a cluster for the new socket
1282    new_socket_cxy = cluster_random_select();
1283
1284    // allocate memory for the new socket descriptor
1285    error = socket_create( new_socket_cxy,
1286                           socket_domain,
1287                           socket_type,
1288                           &new_socket_ptr,
1289                           &new_fdid );
1290    if( error )
1291    {
1292
1293#if DEBUG_SOCKET_ERROR
1294printk("\n[ERROR] in %s : cannot create new socket / thread[%x,%x] / cycle %d\n",
1295__FUNCTION__, process->pid, this->trdid, cycle );
1296#endif
1297        return -1;
1298    }
1299   
1300    // build extended poiner on new socket
1301    new_socket_xp = XPTR( new_socket_cxy , new_socket_ptr );
1302
1303#if DEBUG_SOCKET_ACCEPT
1304cycle = (uint32_t)hal_get_cycles();
1305if( DEBUG_SOCKET_ACCEPT < cycle )
1306printk("\n[%s] thread[%x,%x] created new socket[%x,%d] / cycle %d\n",
1307__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid, cycle );
1308#endif
1309       
1310    // compute NIC channel index from remote_addr and remote_port
1311    uint32_t new_nic_channel = dev_nic_get_key( new_remote_addr , new_remote_port );
1312
1313    // update new socket descriptor
1314    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->local_addr ) , socket_local_addr );
1315    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->local_port ) , socket_local_port );
1316    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->remote_addr) , new_remote_addr );
1317    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->remote_port) , new_remote_port );
1318    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->nic_channel) , new_nic_channel );
1319    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->state      ) , TCP_STATE_SYN_RCVD );
1320
1321    // set new socket TCB : increment tx_nxt / initialize rx_nxt, rx_irs, rx_wnd
1322    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->tx_nxt ), socket_tx_nxt + 1 );
1323    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->rx_nxt ), new_remote_iss + 1 );
1324    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->rx_irs ), new_remote_iss );
1325    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->rx_wnd ), new_remote_window );
1326
1327    // link new socket to chdev servers
1328    socket_link_to_servers( new_socket_xp , new_nic_channel );
1329
1330    // 3) get pointers on NIC_TX[channel] chdev
1331    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[new_nic_channel];
1332    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
1333    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
1334
1335    // get pointers on NIC_TX[channel] server thread
1336    tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
1337    tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
1338
1339    // register command arguments in new socket to request a SYN_ACK segment
1340    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->tx_cmd    ), CMD_TX_ACCEPT );
1341    hal_remote_s64( XPTR( new_socket_cxy , &new_socket_ptr->tx_client ), client_xp );
1342    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->tx_valid  ), true );
1343
1344    // unblock NIC_TX server thread
1345    thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
1346 
1347    // start retransmission timer
1348    alarm_start( client_xp,
1349                 hal_get_cycles() + CONFIG_SOCK_RETRY_TIMEOUT,
1350                 &socket_alarm_handler,
1351                 new_socket_xp );
1352
1353#if DEBUG_SOCKET_ACCEPT
1354cycle = (uint32_t)hal_get_cycles();
1355if( DEBUG_SOCKET_ACCEPT < cycle )
1356printk("\n[%s] thread[%x,%x] for socket[%x,%d] request SYN-ACK & blocks on <IO> / cycle %d\n",
1357__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid, cycle );
1358#endif
1359
1360    // client thread blocks & deschedules
1361    thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
1362    sched_yield( "waiting new socket connection");
1363
1364#if DEBUG_SOCKET_ACCEPT
1365cycle = (uint32_t)hal_get_cycles();
1366if( DEBUG_SOCKET_ACCEPT < cycle )
1367printk("\n[%s] thread[%x,%x] new_socket[%x,%d] resumes  / cycle %d\n",
1368__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid, cycle );
1369#endif
1370
1371    // stop retransmission timer in thread descriptor
1372    alarm_stop( client_xp );
1373
1374    // get new socket state, tx_valid and tx_sts
1375    new_state  = hal_remote_l32( XPTR( new_socket_cxy , &new_socket_ptr->state ));
1376    cmd_valid  = hal_remote_l32( XPTR( new_socket_cxy , &new_socket_ptr->tx_valid ));
1377    cmd_status = hal_remote_l32( XPTR( new_socket_cxy , &new_socket_ptr->tx_sts ));
1378
1379assert( __FUNCTION__,
1380(((new_state == TCP_STATE_ESTAB) || (cmd_status != CMD_STS_SUCCESS)) && (cmd_valid == false)), 
1381"illegal socket state when client thread resumes after TX_ACCEPT" ); 
1382
1383    // reset socket.tx_client
1384    hal_remote_s64( XPTR( new_socket_cxy , &new_socket_ptr->tx_client ) , XPTR_NULL );
1385
1386    if( cmd_status != CMD_STS_SUCCESS ) 
1387    {
1388
1389#if DEBUG_SOCKET_ERROR
1390printk("\n[ERROR] in %s reported for TX / socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1391__FUNCTION__, process->pid, new_fdid, process->pid, this->trdid, cycle );
1392#endif
1393        return -1;
1394    }
1395    else
1396    {
1397
1398#if DEBUG_SOCKET_ACCEPT
1399cycle = (uint32_t)hal_get_cycles();
1400if( DEBUG_SOCKET_ACCEPT < cycle )
1401printk("\n[%s] thread[%x,%x] new_socket[%x,%d] / state %s / addr %x / port %x / cycle %d\n",
1402__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid,
1403socket_state_str(new_state), new_remote_addr, new_remote_port, cycle );
1404#endif
1405
1406        // return success
1407        *remote_addr = new_remote_addr;
1408        *remote_port = new_remote_port;
1409        return new_fdid;
1410    }
1411 
1412}  // end socket_accept()
1413
1414//////////////////////////////////
1415int socket_connect( uint32_t fdid,
1416                    uint32_t remote_addr,
1417                    uint16_t remote_port )
1418{
1419    vfs_file_type_t    file_type;
1420    xptr_t              socket_xp;        // extended pointer on socket descriptor
1421    socket_t          * socket_ptr;       // local pointer on socket descriptor
1422    volatile uint32_t   socket_state;     // socket state (modified by the NIC_TX thread)
1423    uint32_t            socket_type;      // socket type 
1424    uint32_t            local_addr;       // local IP address
1425    uint32_t            local_port;       // local port
1426    xptr_t              tx_server_xp;     // extended pointer on TX server thread
1427    thread_t          * tx_server_ptr;    // local pointer on TX server thread
1428    uint32_t            nic_channel;      // NIC channel index
1429    uint32_t            cmd_status;       // command status (tx_sts field)
1430    bool_t              cmd_valid;        // command valid (tx_valid field)
1431
1432    thread_t  * this      = CURRENT_THREAD;
1433    xptr_t      client_xp = XPTR( local_cxy , this );
1434    pid_t       pid       = this->process->pid;
1435    trdid_t     trdid     = this->trdid;
1436
1437#if DEBUG_SOCKET_CONNECT || DEBUG_SOCKET_ERROR
1438uint32_t cycle = (uint32_t)hal_get_cycles();
1439#endif
1440
1441    // get pointers on file descriptor
1442    xptr_t       file_xp  = process_fd_get_xptr_from_local( this->process , fdid );
1443    vfs_file_t * file_ptr = GET_PTR( file_xp );
1444    cxy_t        file_cxy = GET_CXY( file_xp );
1445
1446    // check file_xp
1447    if( file_xp == XPTR_NULL )
1448    {
1449
1450#if DEBUG_SOCKET_ERROR
1451printk("\n[ERROR] in %s : undefined fdid %d / thread[%x,%x] / cycle %d",
1452__FUNCTION__, fdid, pid, trdid, cycle );
1453#endif
1454        return -1;
1455    }
1456
1457    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
1458    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
1459    socket_xp  = XPTR( file_cxy , socket_ptr );
1460
1461#if DEBUG_SOCKET_CONNECT
1462if( DEBUG_SOCKET_CONNECT < cycle )
1463printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / addr %x / port %x / cycle %d\n",
1464__FUNCTION__,  pid, trdid, pid, fdid, remote_addr, remote_port, cycle );
1465#endif
1466
1467    // check file descriptor type
1468    if( file_type != FILE_TYPE_SOCK )
1469    {
1470
1471#if DEBUG_SOCKET_ERROR
1472printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x] / cycle %d",
1473__FUNCTION__, vfs_inode_type_str( file_type ), pid, trdid, cycle );
1474#endif
1475        return -1;
1476    }
1477
1478    // get relevant socket infos
1479    socket_type   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ) );
1480    socket_state  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ) );
1481    local_addr    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_addr ) );
1482    local_port    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_port ) );
1483
1484    if( socket_type == SOCK_DGRAM )       // UDP
1485    {
1486        if( socket_state != UDP_STATE_BOUND )
1487        {
1488
1489#if DEBUG_SOCKET_ERROR
1490printk("\n[ERROR] in %s : illegal socket state %s for type %s / thread[%x,%x] / cycle %d",
1491__FUNCTION__, socket_state_str(socket_state), socket_type_str(socket_type), pid, trdid, cycle );
1492#endif
1493            return -1;
1494        }
1495    }
1496    else if( socket_type == SOCK_STREAM )  // TCP
1497    {
1498        if( socket_state != TCP_STATE_BOUND )
1499        {
1500
1501#if DEBUG_SOCKET_ERROR
1502printk("\n[ERROR] in %s : illegal socket state %s for type %s / thread[%x,%x] / cycle %d",
1503__FUNCTION__, socket_state_str(socket_state), socket_type_str(socket_type), pid, trdid, cycle );
1504#endif
1505            return -1;
1506        }
1507    }
1508    else
1509    {
1510
1511#if DEBUG_SOCKET_ERROR
1512printk("\n[ERROR] in %s : illegal socket type / thread[%x,%x] / cycle %d",
1513__FUNCTION__, pid, trdid, cycle );
1514#endif
1515        return -1;
1516    }
1517
1518    // compute nic_channel index from remote_addr and remote_port
1519    nic_channel = dev_nic_get_key( remote_addr , remote_port );
1520
1521    // link socket to chdev servers
1522    socket_link_to_servers( XPTR( file_cxy , socket_ptr ), nic_channel );
1523
1524    // update the socket descriptor
1525    hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_addr ) , remote_addr  );
1526    hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_port ) , remote_port  );
1527    hal_remote_s32( XPTR( file_cxy , &socket_ptr->nic_channel ) , nic_channel  );
1528
1529    // the actual connection mechanism depends on socket type
1530    // UDP : client thread updates the local socket state without blocking
1531    // TCP : client thread request TX server thread to start the 3 steps handshake
1532
1533    if( socket_type == SOCK_DGRAM )  // UDP
1534    {
1535        // directly update the local socket state
1536        hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , UDP_STATE_ESTAB );
1537
1538        return 0;
1539    }
1540    else                             // TCP
1541    {
1542        // get pointers on NIC_TX[channel] chdev
1543        xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
1544        chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
1545        cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
1546
1547        // get pointers on NIC_TX[channel] server thread
1548        tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
1549        tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
1550
1551        // register command arguments in socket descriptor for a SYN segment
1552        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd    ), CMD_TX_CONNECT );
1553        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ), client_xp );
1554        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_valid  ), true );
1555
1556        // unblock NIC_TX server thread
1557        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
1558 
1559        // start retransmission timer
1560        alarm_start( client_xp,
1561                     hal_get_cycles() + CONFIG_SOCK_RETRY_TIMEOUT,
1562                     &socket_alarm_handler,
1563                     socket_xp );
1564
1565#if DEBUG_SOCKET_CONNECT
1566cycle = (uint32_t)hal_get_cycles();
1567if( DEBUG_SOCKET_CONNECT < cycle )
1568printk("\n[%s] thread[%x,%x] socket[%x,%d] blocks on <IO> waiting connexion / cycle %d \n",
1569__FUNCTION__, pid, trdid, pid, fdid, cycle );
1570#endif
1571        // block itself and deschedule
1572        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
1573        sched_yield( "waiting connection" );
1574
1575#if DEBUG_SOCKET_CONNECT
1576cycle = (uint32_t)hal_get_cycles();
1577if( DEBUG_SOCKET_CONNECT < cycle )
1578printk("\n[%s] thread[%x,%x] socket[%x,%d] / resumes / cycle %d \n",
1579__FUNCTION__, pid, trdid, pid, fdid, cycle );
1580#endif
1581
1582        // stop retransmission timer in thread descriptor
1583        alarm_stop( client_xp );
1584
1585        // get socket state, tx_valid and tx_sts
1586        cmd_valid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ));
1587        cmd_status   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_sts ));
1588        socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
1589
1590assert( __FUNCTION__, (((socket_state == TCP_STATE_ESTAB) || (cmd_status != CMD_STS_SUCCESS))
1591        && (cmd_valid == false)),
1592"illegal socket state when client thread resumes after TX_CONNECT" );
1593
1594        // reset socket.tx_client
1595        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ) , XPTR_NULL );
1596
1597        if( cmd_status != CMD_STS_SUCCESS )
1598        {
1599
1600#if DEBUG_SOCKET_ERROR
1601printk("\n[ERROR] in %s reported by server / socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1602__FUNCTION__, pid, fdid, pid, trdid, cycle );
1603#endif
1604            return -1;
1605        }
1606        else
1607        {
1608
1609#if DEBUG_SOCKET_CONNECT
1610cycle = (uint32_t)hal_get_cycles();
1611if( DEBUG_SOCKET_CONNECT < cycle )
1612printk("\n[%s] thread[%x,%x] exit for socket[%x,%d] / %s / cycle %d \n",
1613__FUNCTION__, pid, trdid, pid, fdid, socket_state_str(socket_state),cycle );
1614#endif
1615             return 0;
1616        }
1617    }  // end TCP
1618
1619}  // end socket_connect()
1620
1621///////////////////////////////////
1622int socket_close( xptr_t   file_xp,
1623                  uint32_t fdid )
1624{
1625    uint32_t     socket_type;
1626    uint32_t     socket_state;
1627    uint32_t     nic_channel;
1628    uint32_t     cmd_status;      // socket.tx_sts
1629    bool_t       cmd_valid;       // socket.tx_valid
1630    thread_t   * tx_server_ptr;   // local pointer on NIC_TX server thread
1631    xptr_t       tx_server_xp;    // extended pointer on NIC_TX server thread
1632    xptr_t       socket_lock_xp;  // extended pointer on socket lock
1633
1634    thread_t   * this      = CURRENT_THREAD;
1635    xptr_t       client_xp = XPTR( local_cxy , this );
1636    pid_t        pid       = this->process->pid;
1637    trdid_t      trdid     = this->trdid;
1638
1639#if DEBUG_SOCKET_CLOSE || DEBUG_SOCKET_ERROR
1640uint32_t cycle = (uint32_t)hal_get_cycles();
1641#endif
1642
1643    // get pointers on socket descriptor
1644    cxy_t        file_cxy   = GET_CXY( file_xp );
1645    vfs_file_t * file_ptr   = GET_PTR( file_xp );
1646    socket_t   * socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
1647    xptr_t       socket_xp  = XPTR( file_cxy , socket_ptr );
1648
1649assert( __FUNCTION__, (hal_remote_l32( XPTR( file_cxy , &socket_ptr->fdid )) == fdid),
1650"unconsistent file_xp & fdid arguments");
1651
1652#if DEBUG_SOCKET_CLOSE
1653if (DEBUG_SOCKET_CLOSE < cycle )
1654printk("\n[%s] thread[%x,%x] enters for socket[%x,%d] / cycle %d\n",
1655__FUNCTION__, pid, trdid, pid, fdid, cycle );
1656#endif
1657
1658    // build extended pointer on lock protecting socket
1659    socket_lock_xp = XPTR( file_cxy , &socket_ptr->lock );
1660
1661    // take socket lock
1662    remote_queuelock_acquire( socket_lock_xp );
1663
1664    // check no previous TX command
1665    if( (hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid )) == true) || 
1666        (hal_remote_l64( XPTR( file_cxy , &socket_ptr->tx_client)) != XPTR_NULL) )
1667    { 
1668                   
1669#if DEBUG_SOCKET_ERROR
1670printk("\n[ERROR] in %s : previous TX cmd on socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1671__FUNCTION__, pid, fdid, pid, trdid, cycle );
1672#endif
1673        remote_queuelock_release( socket_lock_xp );
1674        return -1;
1675    }
1676
1677    // get relevant socket infos
1678    socket_type   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
1679    nic_channel   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
1680    socket_state  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
1681
1682
1683    // the actual close mechanism depends on socket type and state:
1684    // UDP or TCP not connected : client thread directly destroy the socket descriptor
1685    // TCP connected : client thread request TX server thread to make the TCP close handshake
1686
1687    if( socket_type == SOCK_DGRAM )                   // UDP
1688    {
1689
1690#if DEBUG_SOCKET_CLOSE
1691cycle = (uint32_t)hal_get_cycles();
1692if( cycle > DEBUG_DEV_NIC_TX )
1693printk("\n[%s] thread[%x,%x] socket[%x,%d] %s => directly destroy socket / cycle %d\n",
1694__FUNCTION__, pid, trdid, pid, fdid, socket_state_str( socket_state ), cycle );
1695#endif
1696        // directly destroy socket
1697        socket_destroy( file_xp );
1698
1699        return 0;
1700    }
1701    else if( (socket_state == TCP_STATE_BOUND) ||
1702             (socket_state == TCP_STATE_LISTEN) ||
1703             (socket_state == TCP_STATE_SYN_SENT) )   // TCP not connected
1704    {
1705
1706#if DEBUG_SOCKET_CLOSE
1707cycle = (uint32_t)hal_get_cycles();
1708if( cycle > DEBUG_DEV_NIC_TX )
1709printk("\n[%s] thread[%x,%x] socket[%x,%d] %s => directly destroy socket / cycle %d\n",
1710__FUNCTION__, pid, trdid, pid, fdid, socket_state_str( socket_state ), cycle );
1711#endif
1712        // directly destroy socket
1713        socket_destroy( file_xp );
1714
1715        return 0;
1716    }
1717    else                                             // TCP connected
1718    {
1719        // get pointers on NIC_TX[index] chdev
1720        xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
1721        chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
1722        cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
1723
1724        // get pointers on NIC_TX[channel] server thread
1725        tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
1726        tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
1727
1728        // register command arguments in socket descriptor
1729        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd    ), CMD_TX_CLOSE );
1730        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ), client_xp );
1731        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_valid  ), true );
1732       
1733        // release socket lock
1734        remote_queuelock_release( socket_lock_xp );
1735
1736        // unblock NIC_TX server thread
1737        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
1738
1739        // start retransmission timer
1740        alarm_start( client_xp,
1741                     hal_get_cycles() + CONFIG_SOCK_RETRY_TIMEOUT,
1742                     &socket_alarm_handler,
1743                     socket_xp );
1744
1745#if DEBUG_SOCKET_CLOSE
1746cycle = (uint32_t)hal_get_cycles();
1747if( DEBUG_SOCKET_CLOSE < cycle )
1748printk("\n[%s] thread[%x,%x] socket[%x,%d] %s => blocks on <IO> waiting close / cycle %d \n",
1749__FUNCTION__, pid, trdid, pid, fdid, socket_state_str( socket_state ), cycle );
1750#endif
1751        // client thread block itself and deschedule
1752        thread_block( client_xp , THREAD_BLOCKED_IO );
1753        sched_yield( "blocked in close" );
1754
1755#if DEBUG_SOCKET_CLOSE
1756cycle = (uint32_t)hal_get_cycles();
1757if( DEBUG_SOCKET_CLOSE < cycle )
1758printk("\n[%s] thread[%x,%x] socket[%x,%d] / resumes / cycle %d \n",
1759__FUNCTION__, pid, trdid, pid, fdid, cycle );
1760#endif
1761        // stop retransmission timer in thread descriptor
1762        alarm_stop( client_xp );
1763
1764        // take socket lock
1765        remote_queuelock_acquire( socket_lock_xp );
1766
1767        // get socket state & command status
1768        socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ) );
1769        cmd_status   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_sts) );
1770        cmd_valid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ) );
1771
1772assert( __FUNCTION__,
1773(((socket_state == TCP_STATE_CLOSED) || (cmd_status != CMD_STS_SUCCESS)) && (cmd_valid == false)),
1774" socket_state = %s / cmd_status = %d / cmd_valid = %d",
1775socket_state_str(socket_state), cmd_status, cmd_valid );
1776
1777        // reset socket.tx_client
1778        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ) , XPTR_NULL );
1779
1780        if( cmd_status != CMD_STS_SUCCESS )  // error reported
1781        {
1782
1783#if DEBUG_SOCKET_ERROR
1784printk("\n[ERROR] in %s for command TX_CLOSE / socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1785__FUNCTION__, pid, fdid, pid, this->trdid, cycle );
1786#endif
1787            return -1;
1788        }
1789        else                                 // success
1790        {
1791
1792#if DEBUG_SOCKET_CLOSE
1793cycle = (uint32_t)hal_get_cycles();
1794if( DEBUG_SOCKET_CLOSE < cycle )
1795printk("\n[%s] thread[%x,%x] socket[%x,%d] / destroy socket / cycle %d\n",
1796__FUNCTION__, pid, trdid, pid, fdid, socket_state_str(socket_state) , cycle );
1797#endif
1798            // destroy socket
1799            socket_destroy( file_xp );
1800
1801            return 0;
1802        }
1803    }   // end if TCP
1804}  // end socket_close()
1805
1806////////////////////////////////////////////////////////////////////////////////////////
1807// This static function is called by the two functions socket_send() & socket_recv().
1808// It is used for both UDP and TCP sockets.
1809////////////////////////////////////////////////////////////////////////////////////////
1810// @ is_send   : send when true / receive when false.
1811// @ fdid      : socket identifier.
1812// @ u_buf     : pointer on user buffer in user space.
1813// @ length    : number of bytes in buffer.
1814////////////////////////////////////////////////////////////////////////////////////////
1815// Implementation note : The behavior is different for SEND & RECV
1816// - For a SEND, the client thread checks that there is no TX command registered
1817//   in the socket. It registers the command arguments in the socket descriptor
1818//   (tx_client, tx_cmd, tx_buf, tx_len). Then the client thread unblocks the
1819//   TX server thread from the BLOCKED_CLIENT condition, blocks itself on the
1820//   BLOCKED_IO condition, and deschedules. It is unblocked by the TX server thread
1821//   when the last byte has been sent (for UDP) or acknowledged (for TCP).
1822//   When the client thread resumes, it reset the command in socket, and returns.
1823// - For a RECV, the client thread checks that there is no RX command registered
1824//   in the socket. It registers itself in socket (rx_client). It checks the status
1825//   of the receive buffer. It the rx_buf is empty, it blocks on the BLOCKED_IO
1826//   condition, and deschedules. It is unblocked by the RX server thread when an UDP
1827//   packet or TCP segment has been writen in the rx_buf. When it resumes, it moves
1828//   the available data from the rx_buf to the user buffer, reset its registration
1829//   in socket (reset the rx_buf for an UDP socket), and returns.
1830////////////////////////////////////////////////////////////////////////////////////////
1831int socket_move_data( bool_t     is_send,
1832                      uint32_t   fdid,
1833                      uint8_t  * u_buf,
1834                      uint32_t   length )
1835{
1836    vfs_file_type_t    file_type;       // file descriptor type
1837    xptr_t              socket_xp;       // extended pointer on socket descriptor
1838    socket_t          * socket_ptr;      // local pointer on socket descriptor
1839    uint32_t            socket_state;    // current socket state
1840    uint32_t            socket_type;     // socket type (UDP/TCP)
1841    uint32_t            nic_channel;     // NIC channel for this socket
1842    xptr_t              socket_lock_xp;  // extended pointer on socket lock
1843    xptr_t              file_xp;         // extended pointer on file descriptor
1844    vfs_file_t        * file_ptr;
1845    cxy_t               file_cxy;
1846    xptr_t              chdev_xp;        // extended pointer on NIC_TX[channel] chdev
1847    chdev_t           * chdev_ptr;
1848    cxy_t               chdev_cxy;
1849    int32_t             moved_bytes;     // total number of moved bytes (fot return)
1850    xptr_t              server_xp;       // ext pointer on NIC_TX / NIC_RX thread
1851    thread_t          * server_ptr;      // local pointer on NIC_TX / NIC_RX thread
1852    uint8_t           * tx_buf;          // pointer on kernel buffer for TX transfer
1853    bool_t              cmd_valid;       // RX or TX command from socket descriptor
1854    uint32_t            cmd_sts;         // RX or TX command from socket descriptor
1855    uint32_t            tx_todo;         // number of bytes still to send
1856    xptr_t              rx_buf_xp;       // extended pointer on socket rx_buf
1857    uint32_t            rx_buf_sts;      // current status of socket rx_buf
1858
1859    thread_t  * this    = CURRENT_THREAD;
1860    process_t * process = this->process;
1861
1862#if DEBUG_SOCKET_SEND || DEBUG_SOCKET_RECV || DEBUG_SOCKET_ERROR
1863uint32_t cycle = (uint32_t)hal_get_cycles();
1864#endif
1865
1866#if DEBUG_SOCKET_SEND || DEBUG_SOCKET_RECV
1867if( is_send )
1868printk("\n[%s] thread[%x,%x] socket[%x,%d] enter : SEND / buf %x / length %d / cycle %d\n",
1869__FUNCTION__, process->pid, this->trdid, process->pid, fdid, u_buf, length, cycle );
1870else
1871printk("\n[%s] thread[%x,%x] socket[%x,%d] enter : RECV / buf %x / length %d / cycle %d\n",
1872__FUNCTION__, process->pid, this->trdid, process->pid, fdid, u_buf, length, cycle );
1873#endif
1874
1875    // build extended pointer on client thread
1876    xptr_t client_xp = XPTR( local_cxy , this );
1877
1878    // get pointers on file descriptor identifying the socket
1879    file_xp  = process_fd_get_xptr_from_local( process , fdid );
1880    file_ptr = GET_PTR( file_xp );
1881    file_cxy = GET_CXY( file_xp );
1882
1883    if( file_xp == XPTR_NULL )
1884    {
1885
1886#if DEBUG_SOCKET_ERROR
1887printk("\n[ERROR] in %s : undefined fdid %d / thread%x,%x] / cycle %d\n",
1888__FUNCTION__, fdid , process->pid, this->trdid, cycle );
1889#endif
1890        return -1;
1891    }
1892 
1893    // get file type and socket pointer
1894    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
1895
1896    // get pointers on socket
1897    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
1898    socket_xp  = XPTR( file_cxy , socket_ptr );
1899
1900    // check file descriptor type
1901    if( file_type != FILE_TYPE_SOCK )
1902    {
1903
1904#if DEBUG_SOCKET_ERROR
1905printk("\n[ERROR] in %s : illegal file type thread[%x,%x] / cycle %d\n",
1906__FUNCTION__, process->pid, this->trdid, cycle );
1907#endif
1908        return -1;
1909    }
1910
1911    // build extended pointer on lock protecting socket
1912    socket_lock_xp = XPTR( file_cxy , &socket_ptr->lock );
1913
1914    // take the socket lock
1915    remote_queuelock_acquire( socket_lock_xp );
1916
1917    // get socket type, state, and channel
1918    socket_type  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
1919    socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
1920    nic_channel  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
1921
1922    //////////////////////////////////////////////////////
1923    if( is_send )                       // SEND command
1924    {
1925
1926#if DEBUG_SOCKET_SEND
1927cycle = (uint32_t)hal_get_cycles();
1928if (DEBUG_SOCKET_SEND < cycle )
1929printk("\n[%s] thread[%x,%x] / socket[%x,%d] get SEND / length %d / cycle %d\n",
1930__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, cycle );
1931#endif
1932
1933        // check no previous TX command
1934        if( hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid )) == true ) 
1935        { 
1936                   
1937#if DEBUG_SOCKET_ERROR
1938printk("\n[ERROR] in %s : previous TX command / socket[%x,%d] / thread[%x,%x] / cycle %d\n",
1939__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
1940#endif
1941            remote_queuelock_release( socket_lock_xp );
1942            return -1;
1943        }
1944
1945        // get tx_buf pointer from socket pointer
1946        tx_buf = (uint8_t*)hal_remote_lpt( XPTR( file_cxy , &socket_ptr->tx_buf ));
1947
1948        // copy data from user u_buf to kernel socket tx_buf   
1949        hal_copy_from_uspace( XPTR( file_cxy , tx_buf ),
1950                              u_buf,
1951                              length );
1952#if DEBUG_SOCKET_SEND
1953if (DEBUG_SOCKET_SEND < cycle )
1954printk("\n[%s] thread[%x,%x] / socket[%x,%d] copied %d bytes to tx_buf (%x,%x)\n",
1955__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, file_cxy, tx_buf );
1956putb("tx_buf : 16 first data bytes" , tx_buf , 16 ); 
1957#endif
1958
1959        // register command in socket descriptor
1960        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ) , client_xp );
1961        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd    ) , CMD_TX_SEND );
1962        hal_remote_spt( XPTR( file_cxy , &socket_ptr->tx_buf    ) , tx_buf );
1963        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_len    ) , length );
1964        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_todo   ) , length );
1965        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_ack    ) , 0 );
1966        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_valid  ) , true );
1967
1968        // release socket lock
1969        remote_queuelock_release( socket_lock_xp );
1970                   
1971        // get pointers on relevant chdev
1972        chdev_xp  = chdev_dir.nic_tx[nic_channel];
1973        chdev_ptr = GET_PTR( chdev_xp );
1974        chdev_cxy = GET_CXY( chdev_xp );
1975
1976        // get pointers on NIC_TX[channel] server thread
1977        server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server ));
1978        server_xp  = XPTR( chdev_cxy , server_ptr );
1979
1980        // unblocks the NIC_TX server thread
1981        thread_unblock( server_xp , THREAD_BLOCKED_CLIENT );
1982
1983        // start retransmission timer for TCP socket
1984        if( socket_type == SOCK_STREAM ) 
1985        {
1986            alarm_start( client_xp,
1987                         hal_get_cycles() + CONFIG_SOCK_RETRY_TIMEOUT,
1988                         &socket_alarm_handler,
1989                         socket_xp );
1990        }
1991
1992#if DEBUG_SOCKET_SEND   
1993if( DEBUG_SOCKET_SEND < cycle )
1994printk("\n[%s] thread[%x,%x] / socket[%x,%d] registers SEND => blocks on <IO>\n",
1995__FUNCTION__, process->pid, this->trdid, process->pid, fdid );
1996#endif
1997        // client thread blocks itself and deschedules
1998        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
1999        sched_yield( "blocked in nic_io" );
2000
2001#if DEBUG_SOCKET_SEND   
2002cycle = (uint32_t)hal_get_cycles();
2003if( DEBUG_SOCKET_SEND < cycle )
2004printk("\n[%s] thread[%x,%x] / socket[%x,%d] resumes for SEND / cycle %d\n",
2005__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
2006#endif
2007        // stop retransmission timer for TCP socket
2008        if( socket_type == SOCK_STREAM )
2009        {
2010            alarm_stop( client_xp );
2011        }
2012
2013        // take socket lock
2014        remote_queuelock_acquire( socket_lock_xp );
2015     
2016        // get tx_valid, tx_todo, and tx_sts
2017        tx_todo    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_todo ));
2018        cmd_valid  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ));
2019        cmd_sts    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_sts ));
2020
2021        // reset tx_client in socket descriptor
2022        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client  ) , XPTR_NULL );
2023
2024        // release socket lock
2025        remote_queuelock_release( socket_lock_xp );
2026     
2027// check SEND command completed when TX client thread resumes
2028assert( __FUNCTION__, 
2029(((tx_todo == 0) || (cmd_sts != CMD_STS_SUCCESS)) && (cmd_valid == false)),
2030"client thread resumes from SEND / bad state : tx_todo %d / tx_sts %d / tx_valid %d",
2031tx_todo, cmd_sts, cmd_valid );
2032
2033        if( cmd_sts != CMD_STS_SUCCESS )
2034        {
2035
2036#if DEBUG_SOCKET_ERROR   
2037printk("\n[ERROR] in %s : reported for SEND / socket[%x,%d] / thread[%x,%x] / cycle %d\n",
2038__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
2039#endif
2040            return -1;
2041        }
2042        else
2043        {
2044
2045#if DEBUG_SOCKET_SEND
2046cycle = (uint32_t)hal_get_cycles();
2047if (DEBUG_SOCKET_SEND < cycle )
2048printk("\n[%s] thread[%x,%x] SEND success / socket[%x,%d] / bytes %d / cycle %d\n",
2049__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, cycle );
2050#endif
2051            return length;
2052        }
2053
2054    }  // end SEND command
2055
2056    /////////////////////////////////////////////////////////////
2057    else                                       // RECV command
2058    {
2059
2060#if DEBUG_SOCKET_RECV
2061if (DEBUG_SOCKET_RECV < cycle )
2062printk("\n[%s] thread[%x,%x] / socket[%x,%d] get RECV / length %d / cycle %d\n",
2063__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, cycle );
2064#endif
2065        // check no previous RX command
2066        if( hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid )) == true )
2067        {
2068                   
2069#if DEBUG_SOCKET_ERROR   
2070printk("\n[ERROR] in %s : previous RX command on socket[%x,%d] / thread[%x,%x] / cycle %d\n",
2071__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
2072#endif
2073            remote_queuelock_release( socket_lock_xp );
2074            return -1;
2075        }
2076
2077        // return EOF for a TCP socket not in ESTAB state
2078        if( (socket_type == SOCK_STREAM ) && (socket_state != TCP_STATE_ESTAB) )
2079        { 
2080            // release socket lock
2081            remote_queuelock_release( socket_lock_xp );
2082                   
2083#if DEBUG_SOCKET_RECV 
2084cycle = (uint32_t)hal_get_cycles();
2085if( DEBUG_SOCKET_RECV < cycle )
2086printk("\n[%s] thread[%x,%x] / socket[%x,%d] TCP connection closed / cycle %d\n",
2087__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
2088#endif
2089            return 0;
2090        }
2091
2092        // build extended pointer on socket rx_buf
2093        rx_buf_xp = XPTR( file_cxy , &socket_ptr->rx_buf );
2094
2095        // get socket rx_buf status
2096        rx_buf_sts = remote_buf_status( rx_buf_xp );
2097
2098        // register RECV command and deschedule when rx_buf empty
2099        if( rx_buf_sts == 0 )
2100        {
2101            // registers RX_RECV command in socket descriptor
2102            hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_cmd    ) , CMD_RX_RECV );
2103            hal_remote_s64( XPTR( file_cxy , &socket_ptr->rx_client ) , client_xp );
2104            hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_valid  ) , true );
2105
2106            // release socket lock
2107            remote_queuelock_release( socket_lock_xp );
2108
2109#if DEBUG_SOCKET_RECV 
2110if( DEBUG_SOCKET_RECV < cycle )
2111printk("\n[%s] thread[%x,%x] socket[%x,%d] for RECV : rx_buf empty => blocks on <IO>\n",
2112__FUNCTION__, process->pid, this->trdid, process->pid, fdid );
2113#endif
2114            // client thread blocks itself and deschedules
2115            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
2116            sched_yield( "blocked in nic_io" );
2117
2118#if DEBUG_SOCKET_RECV 
2119cycle = (uint32_t)hal_get_cycles();
2120if( DEBUG_SOCKET_RECV < cycle )
2121printk("\n[%s] thread[%x,%x] socket[%x,%d] for RECV : resumes / cycle %d\n",
2122__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
2123#endif
2124            // take socket lock
2125            remote_queuelock_acquire( socket_lock_xp );
2126
2127            // get command status, command valid, and rx_buf status
2128            cmd_valid  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid ));
2129            cmd_sts    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_sts ));
2130            rx_buf_sts = remote_buf_status( rx_buf_xp );
2131       
2132assert( __FUNCTION__, (cmd_valid == false),
2133"client thread resumes from RECV but rx_valid is true" );
2134
2135            if( cmd_sts == CMD_STS_EOF )           // EOF reported by RX server
2136            {
2137
2138#if DEBUG_SOCKET_RECV
2139if( DEBUG_SOCKET_RECV < cycle )
2140printk("\n[%s] EOF received for socket[%x,%d] / thread[%x,%x]\n",
2141__FUNCTION__, process->pid, fdid, process->pid, this->trdid );
2142#endif
2143                // release socket lock
2144                remote_queuelock_release( socket_lock_xp );
2145
2146                return 0;
2147            }
2148            else if( cmd_sts != CMD_STS_SUCCESS )   // error reported by RX server
2149            {
2150
2151#if DEBUG_SOCKET_ERROR
2152printk("\n[ERROR] in %s : rx_server for socket[%x,%d] / thread[%x,%x] / cycle %d\n",
2153__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
2154#endif
2155                // release socket lock
2156                remote_queuelock_release( socket_lock_xp );
2157
2158                return -1;
2159            }
2160            else if( rx_buf_sts == 0 )              // annormally empty rx_buf
2161            {
2162
2163#if DEBUG_SOCKET_ERROR
2164printk("\n[ERROR] in %s : rx_buf empty for socket[%x,%d] / thread[%x,%x] / cycle %d\n",
2165__FUNCTION__, process->pid, fdid, process->pid, this->trdid, cycle );
2166#endif
2167                // release socket lock
2168                remote_queuelock_release( socket_lock_xp );
2169
2170                return -1;
2171            }
2172        }
2173
2174        // number of bytes extracted from rx_buf cannot be larger than u_buf size
2175        moved_bytes = ( length < rx_buf_sts ) ? length : rx_buf_sts;
2176
2177        // move data from kernel rx_buf to user u_buf
2178        remote_buf_get_to_user( rx_buf_xp,
2179                                u_buf,
2180                                moved_bytes );
2181#if DEBUG_SOCKET_RECV
2182cycle = (uint32_t)hal_get_cycles();
2183if (DEBUG_SOCKET_RECV < cycle )
2184printk("\n[%s] thread[%x,%x] : RECV success / socket[%x,%d] / bytes %d / cycle %d\n",
2185__FUNCTION__, process->pid, this->trdid, process->pid, fdid, moved_bytes, cycle );
2186#endif
2187        // release socket lock
2188        remote_queuelock_release( socket_lock_xp );
2189
2190        return moved_bytes;
2191
2192    }  // end RECV command
2193} // end socket_move_data()
2194
2195///////////////////////////////////
2196int socket_send( uint32_t    fdid,
2197                 uint8_t   * u_buf,
2198                 uint32_t    length )
2199{
2200    return socket_move_data( true,           // SEND
2201                             fdid,
2202                             u_buf,
2203                             length );
2204}  // end socket_send()
2205
2206///////////////////////////////////
2207int socket_recv( uint32_t    fdid,
2208                 uint8_t   * u_buf,
2209                 uint32_t    length )
2210{
2211    return socket_move_data( false,          // RECV
2212                             fdid,
2213                             u_buf,
2214                             length );
2215} // end socket_recv()
2216
2217////////////////////////////////////
2218int socket_sendto( uint32_t    fdid,
2219                   uint8_t   * u_buf,
2220                   uint32_t    length,
2221                   uint32_t    remote_ip,
2222                   uint16_t    remote_port )
2223{
2224    printk("\n[ERROR] in %s : this function is not implemented yet\n",
2225    __FUNCTION__, fdid, u_buf, length, remote_ip, remote_port );
2226    return -1;
2227
2228}  // end socket_sendto()
2229
2230//////////////////////////////////////
2231int socket_recvfrom( uint32_t    fdid,
2232                     uint8_t   * u_buf,
2233                     uint32_t    length,
2234                     uint32_t    remote_ip,
2235                     uint16_t    remote_port )
2236{
2237    printk("\n[ERROR] in %s : this function is not implemented yet\n", 
2238    __FUNCTION__, fdid, u_buf, length, remote_ip, remote_port );
2239    return -1;
2240
2241} // end socket_recvfrom()
2242
2243////////////////////////////////////////////
2244void socket_display( xptr_t       socket_xp,
2245                     const char * func_str,
2246                     const char * string )
2247{
2248    uint32_t   cycle = (uint32_t)hal_get_cycles();
2249
2250    socket_t * socket = GET_PTR( socket_xp );
2251    cxy_t      cxy    = GET_CXY( socket_xp );
2252
2253    pid_t      pid         = hal_remote_l32( XPTR( cxy , &socket->pid ));
2254    fdid_t     fdid        = hal_remote_l32( XPTR( cxy , &socket->fdid ));
2255    uint32_t   state       = hal_remote_l32( XPTR( cxy , &socket->state ));
2256    uint32_t   channel     = hal_remote_l32( XPTR( cxy , &socket->nic_channel ));
2257    uint32_t   local_addr  = hal_remote_l32( XPTR( cxy , &socket->local_addr ));
2258    uint32_t   local_port  = hal_remote_l32( XPTR( cxy , &socket->local_port ));
2259    uint32_t   remote_addr = hal_remote_l32( XPTR( cxy , &socket->remote_addr ));
2260    uint32_t   remote_port = hal_remote_l32( XPTR( cxy , &socket->remote_port ));
2261    uint32_t   tx_valid    = hal_remote_l32( XPTR( cxy , &socket->tx_valid ));
2262    xptr_t     tx_client   = hal_remote_l64( XPTR( cxy , &socket->tx_client ));
2263    uint32_t   tx_cmd      = hal_remote_l32( XPTR( cxy , &socket->tx_cmd ));
2264    uint32_t   tx_sts      = hal_remote_l32( XPTR( cxy , &socket->tx_sts ));
2265    uint32_t   tx_len      = hal_remote_l32( XPTR( cxy , &socket->tx_len ));
2266    uint32_t   tx_todo     = hal_remote_l32( XPTR( cxy , &socket->tx_todo ));
2267    uint32_t   tx_una      = hal_remote_l32( XPTR( cxy , &socket->tx_una ));         
2268    uint32_t   tx_nxt      = hal_remote_l32( XPTR( cxy , &socket->tx_nxt ));         
2269    uint32_t   tx_wnd      = hal_remote_l32( XPTR( cxy , &socket->tx_wnd ));         
2270    uint32_t   tx_ack      = hal_remote_l32( XPTR( cxy , &socket->tx_ack ));         
2271    uint32_t   rx_valid    = hal_remote_l32( XPTR( cxy , &socket->rx_valid ));
2272    xptr_t     rx_client   = hal_remote_l64( XPTR( cxy , &socket->rx_client ));
2273    uint32_t   rx_cmd      = hal_remote_l32( XPTR( cxy , &socket->rx_cmd ));
2274    uint32_t   rx_sts      = hal_remote_l32( XPTR( cxy , &socket->rx_sts ));
2275    uint32_t   rx_nxt      = hal_remote_l32( XPTR( cxy , &socket->rx_nxt ));         
2276    uint32_t   rx_wnd      = hal_remote_l32( XPTR( cxy , &socket->rx_wnd ));         
2277    uint32_t   rx_irs      = hal_remote_l32( XPTR( cxy , &socket->rx_irs )); 
2278
2279    remote_queuelock_t * lock_ptr = &socket->lock; 
2280    uint32_t   taken       = hal_remote_l32( XPTR( cxy , &lock_ptr->taken ));
2281
2282    thread_t * tx_ptr = GET_PTR( tx_client );
2283    cxy_t      tx_cxy = GET_CXY( tx_client );
2284    trdid_t    tx_tid = hal_remote_l32( XPTR( tx_cxy , &tx_ptr->trdid ));
2285
2286    thread_t * rx_ptr = GET_PTR( rx_client );
2287    cxy_t      rx_cxy = GET_CXY( rx_client );
2288    trdid_t    rx_tid = hal_remote_l32( XPTR( rx_cxy , &rx_ptr->trdid ));
2289
2290    if( string == NULL )
2291    {
2292        printk("\n****** socket[%x,%d] / lock %d / in %s / cycle %d *****\n",
2293        pid, fdid, taken, func_str, cycle );
2294    }
2295    else
2296    {
2297        printk("\n***** socket[%x,%d] / lock %d / in %s %s / cycle %d *****\n",
2298        pid, fdid, taken, func_str, string, cycle );
2299    }
2300    printk(" - state %s / channel %d / local [%x,%x] / remote[%x,%x]\n"
2301           " - tx : valid %d / client [%x,%x] / cmd %s \n"
2302           "        sts %d / len %x / todo %x / ack %x / una %x / nxt %x / wnd %x\n"
2303           " - rx : valid %d / client [%x,%x] / cmd %s\n"
2304           "        sts %d / nxt %x / wnd %x / irs %x\n",
2305           socket_state_str(state), channel, 
2306           local_addr, local_port, remote_addr, remote_port,
2307           tx_valid, pid, tx_tid, socket_cmd_type_str(tx_cmd),
2308           tx_sts, tx_len, tx_todo, tx_ack, tx_una, tx_nxt, tx_wnd,
2309           rx_valid, pid, rx_tid, socket_cmd_type_str(rx_cmd),
2310           rx_sts, rx_nxt, rx_wnd, rx_irs );
2311
2312}  // end socket_display()
2313
2314
2315
2316
2317
Note: See TracBrowser for help on using the repository browser.