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

Last change on this file since 675 was 669, checked in by alain, 4 years ago

1) Introduce up to 4 command lines arguments in the KSH "load" command.
These arguments are transfered to the user process through the
argc/argv mechanism, using the user space "args" vseg.

2) Introduce the named and anonymous "pipes", for inter-process communication
through the pipe() and mkfifo() syscalls.

3) Introduce the "chat" application to validate the two above mechanisms.

4) Improve printk() and assert() fonctions in printk.c.

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