source: trunk/kernel/syscalls/sys_socket.c @ 684

Last change on this file since 684 was 683, checked in by alain, 4 years ago

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

File size: 18.3 KB
Line 
1/*
2 * sys_socket.c - implement the various socket related system calls
3 *
4 * Author    Alain Greiner (2016,2017,2018,2019,2020)
5 * 
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_kernel_types.h>
25#include <hal_uspace.h>
26#include <hal_vmm.h>
27#include <errno.h>
28#include <vmm.h>
29#include <cluster.h>
30#include <thread.h>
31#include <process.h>
32#include <ksocket.h>
33#include <string.h>
34#include <shared_syscalls.h>
35#include <shared_socket.h> 
36#include <remote_barrier.h>
37#include <vfs.h>
38#include <mapper.h>
39
40#include <syscalls.h>
41
42/////////////////////////////////////////////////////////////////////////////////
43// This function returns a printable string for the socket related command type.
44/////////////////////////////////////////////////////////////////////////////////
45
46#if DEBUG_SYS_SOCKET
47static char* socket_user_cmd_str( uint32_t type )
48{
49    if     ( type == SOCK_CREATE      ) return "CREATE"; 
50    else if( type == SOCK_BIND        ) return "BIND"; 
51    else if( type == SOCK_LISTEN      ) return "LISTEN"; 
52    else if( type == SOCK_CONNECT     ) return "CONNECT"; 
53    else if( type == SOCK_ACCEPT      ) return "ACCEPT";
54    else if( type == SOCK_SEND        ) return "SEND"; 
55    else if( type == SOCK_RECV        ) return "RECV"; 
56    else if( type == SOCK_SENDTO      ) return "SENDTO"; 
57    else if( type == SOCK_RECVFROM    ) return "RECVFROM"; 
58    else                                return "undefined";
59}
60#endif
61
62/////////////////////////////
63int sys_socket( reg_t  arg0,
64                reg_t  arg1,
65                reg_t  arg2,
66                reg_t  arg3 )
67{
68    int             ret;
69    vseg_t        * vseg;
70
71    sockaddr_in_t   k_sockaddr;  // kernel buffer for one socket address
72
73    thread_t      * this    = CURRENT_THREAD;
74    process_t     * process = this->process;
75
76    uint32_t        cmd = arg0;
77
78#if DEBUG_SYS_SOCKET || DEBUG_SYSCALLS_ERROR || CONFIG_INSTRUMENTATION_SYSCALLS
79uint64_t     tm_start = hal_get_cycles();
80#endif
81
82#if DEBUG_SYS_SOCKET
83char kbuf[64];
84if( DEBUG_SYS_SOCKET < (uint32_t)tm_start )
85printk("\n[%s] thread[%x,%x] enter for %s / a1 %x / a2 %x / a3 %x / cycle %d\n",
86__FUNCTION__, process->pid, this->trdid, socket_user_cmd_str(cmd), 
87arg1, arg2, arg3, (uint32_t)tm_start );
88#endif
89
90    switch( cmd )
91    {
92        /////////////////
93        case SOCK_CREATE:
94        {
95            uint32_t domain = arg1;
96            uint32_t type   = arg2;
97
98            if( domain != AF_INET )
99            {
100
101#if DEBUG_SYSCALLS_ERROR
102printk("\n[ERROR] in %s : thread[%x,%x] / CREATE / domain %d =! AF_INET / cycle %d\n",
103__FUNCTION__ , process->pid , this->trdid , domain , (uint32_t)tm_start );
104#endif
105                this->errno = EINVAL;
106                ret = -1;
107                break;
108            }
109
110            if( (type != SOCK_DGRAM) && (type != SOCK_STREAM) )
111            {
112
113#if DEBUG_SYSCALLS_ERROR
114printk("\n[ERROR] in %s : thread[%x,%x] / CREATE / illegal socket type / cycle %d\n",
115__FUNCTION__ , process->pid , this->trdid  , (uint32_t)tm_start);
116#endif
117                this->errno = EINVAL;
118                ret = -1;
119                break;
120            }
121
122            // call relevant kernel socket function
123            ret = socket_build( domain , type );
124
125            if( ret < 0 )
126            {
127
128#if DEBUG_SYSCALLS_ERROR
129printk("\n[ERROR] in %s : thread[%x,%x] / CREATE / cannot create socket / cycle %d\n",
130__FUNCTION__ , process->pid , this->trdid  , (uint32_t)tm_start);
131#endif
132                this->errno = EINVAL;
133                ret = -1;
134                break;
135            }
136
137            break;
138        }
139        ///////////////
140        case SOCK_BIND:
141        {
142            uint32_t        fdid = arg1;
143            sockaddr_in_t * u_sockaddr = (sockaddr_in_t *)(intptr_t)arg2;
144
145            // check addr pointer in user space
146            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
147            {
148
149#if DEBUG_SYSCALLS_ERROR
150printk("\n[ERROR] in %s : thread[%x,%x] / BIND / socket address %x unmapped / cycle %d\n",
151__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
152#endif
153                this->errno = EINVAL;
154                ret = -1;
155                break;
156            }
157
158            // copy sockaddr structure from uspace to kernel space
159            hal_copy_from_uspace( XPTR( local_cxy , &k_sockaddr ),
160                                  u_sockaddr, 
161                                  sizeof(sockaddr_in_t) );
162
163            // call relevant kernel socket function
164                ret = socket_bind( fdid,
165                               k_sockaddr.sin_addr,
166                               k_sockaddr.sin_port );
167
168            if( ret < 0 )
169            {
170
171#if DEBUG_SYSCALLS_ERROR
172printk("\n[ERROR] in %s : thread[%x,%x] / BIND / cannot access socket[%x,%d] / cycle %d\n",
173__FUNCTION__ , process->pid , this->trdid ,  process->pid, fdid , (uint32_t)tm_start );
174#endif
175                this->errno = EINVAL;
176                ret = -1;
177                break;
178            }
179
180            break;
181        }
182        /////////////////
183        case SOCK_LISTEN:
184        {
185            uint32_t     fdid        = (uint32_t)arg1;
186            uint32_t     max_pending = (uint32_t)arg2;
187
188            // call relevant kernel socket function
189                ret = socket_listen( fdid , max_pending );
190
191            if( ret < 0 )
192            {
193
194#if DEBUG_SYSCALLS_ERROR
195printk("\n[ERROR] in %s : thread[%x,%x] / LISTEN / cannot access socket[%x,%d] / cycle %d\n",
196__FUNCTION__ , process->pid , this->trdid ,  process->pid, fdid , (uint32_t)tm_start );
197#endif
198                this->errno = EINVAL;
199                ret = -1;
200                break;
201            }
202
203            break;
204        }
205        //////////////////
206        case SOCK_CONNECT:
207        {
208            uint32_t        fdid = (uint32_t)arg1;
209            sockaddr_in_t * u_sockaddr = (sockaddr_in_t *)(intptr_t)arg2;
210
211            // check addr pointer in user space
212            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
213            {
214
215#if DEBUG_SYSCALLS_ERROR
216printk("\n[ERROR] in %s : thread[%x,%x] / CONNECT / server address %x unmapped / cycle %d\n",
217__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
218#endif
219                this->errno = EINVAL;
220                ret = -1;
221                break;
222            }
223
224            // copy sockaddr structure from uspace to kernel space
225            hal_copy_from_uspace( XPTR( local_cxy , &k_sockaddr ),
226                                  u_sockaddr ,
227                                  sizeof(sockaddr_in_t) );
228
229            // call relevant kernel function
230                ret = socket_connect( fdid,
231                                  k_sockaddr.sin_addr,
232                                  k_sockaddr.sin_port );
233            if( ret < 0 )
234            {
235
236#if DEBUG_SYSCALLS_ERROR
237printk("\n[ERROR] in %s : thread[%x,%x] / LISTEN / cannot access socket[%x,%d] / cycle %d\n",
238__FUNCTION__ , process->pid , this->trdid ,  process->pid, fdid , (uint32_t)tm_start );
239#endif
240                this->errno = EINVAL;
241                ret = -1;
242                break;
243            }
244
245            break;
246        }
247        /////////////////
248        case SOCK_ACCEPT:
249        {
250            uint32_t        fdid = (uint32_t)arg1;
251            sockaddr_in_t * u_sockaddr = (sockaddr_in_t *)(intptr_t)arg2;
252
253            // check addr pointer in user space
254            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
255            {
256
257#if DEBUG_SYSCALLS_ERROR
258printk("\n[ERROR] in %s : thread[%x,%x] / CONNECT / server address %x unmapped / cycle %d\n",
259__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
260#endif
261                this->errno = EINVAL;
262                ret = -1;
263                break;
264            }
265
266            // call relevant kernel function
267            ret = socket_accept( fdid,
268                                 &k_sockaddr.sin_addr, 
269                                 &k_sockaddr.sin_port );
270
271            if( ret < 0 )
272            {
273
274#if DEBUG_SYSCALLS_ERROR
275printk("\n[ERROR] in %s : thread[%x,%x] / ACCEPT / cannot access socket[%x,%d] / cycle %d\n",
276__FUNCTION__ , process->pid , this->trdid , process->pid, fdid , (uint32_t)tm_start );
277#endif
278                this->errno = EINVAL;
279            }
280
281            // copy sockaddr structure from kernel space to uspace
282            hal_copy_to_uspace( u_sockaddr,
283                                XPTR( local_cxy , &k_sockaddr ),
284                                sizeof(sockaddr_in_t) );
285
286            break;
287        }
288        ///////////////
289        case SOCK_SEND:
290        {
291            uint32_t     fdid   = (uint32_t)arg1;
292            uint8_t    * u_buf  = (uint8_t *)(intptr_t)arg2;
293            uint32_t     length = (uint32_t)arg3;
294
295            // check buffer is mapped in user space
296            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
297            {
298
299#if DEBUG_SYSCALLS_ERROR
300printk("\n[ERROR] in %s : thread[%x,%x] / SEND / u_buf %x unmapped / cycle %d\n",
301__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
302#endif
303                this->errno = EINVAL;
304                ret = -1;
305                break;
306            }
307
308            // check length argument
309            if( (length == 0) || (length > (1<<CONFIG_SOCK_TX_BUF_ORDER)) )
310            {
311
312#if DEBUG_SYSCALLS_ERROR
313printk("\n[ERROR] in %s : thread[%x,%x] / SEND / bad buffer length %d / cycle %d\n",
314__FUNCTION__ , process->pid , this->trdid , length , (uint32_t)tm_start );
315#endif
316                this->errno = EINVAL;
317                ret = -1;
318                break;
319            }
320
321            // cal relevant socket function
322            ret = socket_send( fdid,
323                               u_buf,
324                               length );
325            if( ret < 0 )
326            {
327
328#if DEBUG_SYSCALLS_ERROR
329printk("\n[ERROR] in %s : thread[%x,%x] / SEND / cannot access socket[%x,%d] / cycle %d\n",
330__FUNCTION__ , process->pid , this->trdid , process->pid, fdid , (uint32_t)tm_start );
331#endif
332                this->errno = EINVAL;
333            }
334
335#if DEBUG_SYS_SOCKET
336if( DEBUG_SYS_SOCKET < (uint32_t)tm_start )
337{
338    hal_copy_from_uspace( XPTR( local_cxy , &kbuf ) , u_buf , ret );
339    printk("\n[%s] thread[%x,%x] send %d bytes <%s>\n",
340    __FUNCTION__, process->pid, this->trdid , ret, kbuf );
341}
342#endif
343            break;
344        }
345        ///////////////
346        case SOCK_RECV:
347        {
348            uint32_t     fdid   = (uint32_t)arg1;
349            uint8_t    * u_buf  = (uint8_t *)(intptr_t)arg2;
350            uint32_t     length = (uint32_t)arg3;
351
352            // check buffer is mapped in user space
353            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
354            {
355
356#if DEBUG_SYSCALLS_ERROR
357printk("\n[ERROR] in %s : thread[%x,%x] / RECV / u_buf %x unmapped / cycle %d\n",
358__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
359#endif
360                this->errno = EINVAL;
361                ret = -1;
362                break;
363            }
364
365            // check length argument
366            if( (length == 0) || (length > (1<<CONFIG_SOCK_RX_BUF_ORDER)) )
367            {
368
369#if DEBUG_SYSCALLS_ERROR
370printk("\n[ERROR] in %s : thread[%x,%x] / RECV / bad buffer length %d / cycle %d\n",
371__FUNCTION__ , process->pid , this->trdid , length , (uint32_t)tm_start );
372#endif
373                this->errno = EINVAL;
374                ret = -1;
375                break;
376            }
377
378            // cal relevant kernel socket function
379            ret =  socket_recv( fdid, 
380                                u_buf,
381                                length );
382            if( ret < 0 )
383            {
384
385#if DEBUG_SYSCALLS_ERROR
386printk("\n[ERROR] in %s : thread[%x,%x] / RECV / cannot access socket[%x,%d] / cycle %d\n",
387__FUNCTION__ , process->pid , this->trdid , process->pid, fdid , (uint32_t)tm_start );
388#endif
389                this->errno = EINVAL;
390            }
391
392#if DEBUG_SYS_SOCKET
393if( DEBUG_SYS_SOCKET < (uint32_t)tm_start )
394{
395    hal_copy_from_uspace( XPTR( local_cxy , &kbuf ) , u_buf , ret );
396    printk("\n[%s] thread[%x,%x] received %d bytes <%s>\n",
397    __FUNCTION__, process->pid, this->trdid , ret, kbuf );
398}
399#endif
400            break;
401        }
402        /////////////////
403        case SOCK_SENDTO:
404        {
405            sockaddr_in_t k_remote_addr;
406
407            uint32_t      fdid          = (uint32_t)arg1 & 0x0000FFFF;
408            uint32_t      length        = (uint32_t)arg1 >> 16;
409            uint8_t     * u_buf         = (uint8_t *)(intptr_t)arg2;
410            sockaddr_t  * u_remote_addr = (sockaddr_t *)(intptr_t)arg3;
411
412            // check u_buf mapped in user space
413            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
414            {
415
416#if DEBUG_SYSCALLS_ERROR
417printk("\n[ERROR] in %s : thread[%x,%x] / SENDTO / u_buf %x unmapped / cycle %d\n",
418__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
419#endif
420                this->errno = EINVAL;
421                ret = -1;
422                break;
423            }
424
425            // check u_remote_addr mapped in user space
426            if( vmm_get_vseg( process , (intptr_t)arg3 , &vseg ) )
427            {
428
429#if DEBUG_SYSCALLS_ERROR
430printk("\n[ERROR] in %s : thread[%x,%x] / SENDTO / u_remote_addr %x unmapped / cycle %d\n",
431__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg3 , (uint32_t)tm_start );
432#endif
433                this->errno = EINVAL;
434                ret = -1;
435                break;
436            }
437
438            // check length argument
439            if( (length == 0) || (length > (1<<CONFIG_SOCK_TX_BUF_ORDER)) )
440            {
441
442#if DEBUG_SYSCALLS_ERROR
443printk("\n[ERROR] in %s : thread[%x,%x] / SENDTO / bad length %d / cycle %d\n",
444__FUNCTION__ , process->pid , this->trdid , length , (uint32_t)tm_start );
445#endif
446                this->errno = EINVAL;
447                ret = -1;
448                break;
449            }
450
451            // make a kernel copy of the sockaddr_t structure
452            hal_copy_from_uspace( XPTR( local_cxy , &k_remote_addr ),
453                                  u_remote_addr, sizeof(sockaddr_t) );
454
455            // cal relevant socket function
456            ret = socket_sendto( fdid,
457                                 u_buf,
458                                 length,
459                                 k_remote_addr.sin_addr,
460                                 k_remote_addr.sin_port );
461            if( ret < 0 )
462            {
463
464#if DEBUG_SYSCALLS_ERROR
465printk("\n[ERROR] in %s : thread[%x,%x] / SENDTO / cannot access socket[%x,%d] / cycle %d\n",
466__FUNCTION__ , process->pid , this->trdid , process->pid, fdid , (uint32_t)tm_start );
467#endif
468                this->errno = EINVAL;
469            }
470
471            break;
472        }
473        ///////////////////
474        case SOCK_RECVFROM:
475        {
476            sockaddr_in_t k_remote_addr;
477
478            uint32_t      fdid          = (uint32_t)arg1 & 0x0000FFFF;
479            uint32_t      length        = (uint32_t)arg1 >> 16;
480            uint8_t     * u_buf         = (uint8_t *)(intptr_t)arg2;
481            sockaddr_t  * u_remote_addr = (sockaddr_t *)(intptr_t)arg3;
482
483            // check buffer is mapped in user space
484            if( vmm_get_vseg( process , (intptr_t)arg2 , &vseg ) )
485            {
486
487#if DEBUG_SYSCALLS_ERROR
488printk("\n[ERROR] in %s : thread[%x,%x] / RECVFROM / u_buf %x unmapped / cycle %d\n",
489__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg2 , (uint32_t)tm_start );
490#endif
491                this->errno = EINVAL;
492                ret = -1;
493                break;
494            }
495
496            // check u_remote_addr mapped in user space
497            if( vmm_get_vseg( process , (intptr_t)arg3 , &vseg ) )
498            {
499
500#if DEBUG_SYSCALLS_ERROR
501printk("\n[ERROR] in %s : thread[%x,%x] / RECVFROM / u_remote_addr %x unmapped / cycle %d\n",
502__FUNCTION__ , process->pid , this->trdid , (intptr_t)arg3 , (uint32_t)tm_start );
503#endif
504                this->errno = EINVAL;
505                ret = -1;
506                break;
507            }
508
509            // check length argument
510            if( (length == 0) || (length > (1<<CONFIG_SOCK_RX_BUF_ORDER)) )
511            {
512
513#if DEBUG_SYSCALLS_ERROR
514printk("\n[ERROR] in %s : thread[%x,%x] / RECVFROM / bad length %d / cycle %d\n",
515__FUNCTION__ , process->pid , this->trdid , length , (uint32_t)tm_start );
516#endif
517                this->errno = EINVAL;
518                ret = -1;
519                break;
520            }
521
522            // make a kernel copy of the sockaddr_t structure
523            hal_copy_from_uspace( XPTR( local_cxy , &k_remote_addr ),
524                                  u_remote_addr, sizeof(sockaddr_t) );
525
526            // cal relevant socket function
527            ret = socket_recvfrom( fdid,
528                                   u_buf,
529                                   length,
530                                   k_remote_addr.sin_addr,
531                                   k_remote_addr.sin_port );
532            if( ret < 0 )
533            {
534
535#if DEBUG_SYSCALLS_ERROR
536printk("\n[ERROR] in %s : thread[%x,%x] / RECVFROM / cannot access socket[%x,%d] / cycle %d\n",
537__FUNCTION__ , process->pid , this->trdid , process->pid, fdid , (uint32_t)tm_start );
538#endif
539                this->errno = EINVAL;
540            }
541
542            break;
543        }
544        ////////
545        default: 
546        {
547
548#if DEBUG_SYSCALLS_ERROR
549printk("\n[ERROR] in %s : thread[%x,%x] / undefined socket operation %d / cycle %d\n",
550__FUNCTION__ , process->pid , this->trdid , cmd , (uint32_t)tm_start );
551#endif
552            this->errno = EINVAL;
553            ret = -1;
554            break;
555        }
556    }  // end switch on cmd
557
558#if (DEBUG_SYS_SOCKET || CONFIG_INSTRUMENTATION_SYSCALLS)
559uint64_t     tm_end = hal_get_cycles();
560#endif
561
562#if DEBUG_SYS_SOCKET
563printk("\n[%s] thread[%x,%x] exit for %s / cycle %d\n",
564__FUNCTION__, process->pid, this->trdid, socket_user_cmd_str(cmd), (uint32_t)tm_end );
565#endif
566
567#if CONFIG_INSTRUMENTATION_SYSCALLS
568hal_atomic_add( &syscalls_cumul_cost[SYS_SOCKET] , tm_end - tm_start );
569hal_atomic_add( &syscalls_occurences[SYS_SOCKET] , 1 );
570#endif
571
572    return ret;
573
574}  // end sys_socket()
Note: See TracBrowser for help on using the repository browser.