2
* Copyright (c) 2009 Lukas Mejdrech
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
9
* - Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* - Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* - The name of the author may not be used to endorse or promote products
15
* derived from this software without specific prior written permission.
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
/** @addtogroup socket
34
* Socket application program interface (API) implementation.
35
* @see socket.h for more information.
36
* This is a part of the network application library.
41
#include <fibril_synch.h>
45
#include <ipc/services.h>
48
#include "../modules.h"
50
#include "../include/in.h"
51
#include "../include/socket.h"
52
#include "../include/socket_errno.h"
54
#include "../structures/dynamic_fifo.h"
55
#include "../structures/int_map.h"
57
#include "socket_messages.h"
59
/** Initial received packet queue size.
61
#define SOCKET_INITIAL_RECEIVED_SIZE 4
63
/** Maximum received packet queue size.
65
#define SOCKET_MAX_RECEIVED_SIZE 0
67
/** Initial waiting sockets queue size.
69
#define SOCKET_INITIAL_ACCEPTED_SIZE 1
71
/** Maximum waiting sockets queue size.
73
#define SOCKET_MAX_ACCEPTED_SIZE 0
75
/** Default timeout for connections in microseconds.
77
#define SOCKET_CONNECT_TIMEOUT ( 1 * 1000 * 1000 )
79
/** Maximum number of random attempts to find a new socket identifier before switching to the sequence.
81
#define SOCKET_ID_TRIES 100
83
/** Type definition of the socket specific data.
86
typedef struct socket socket_t;
88
/** Type definition of the socket specific data pointer.
91
typedef socket_t * socket_ref;
93
/** Socket specific data.
94
* Each socket lock locks only its structure part and any number of them may be locked simultaneously.
97
/** Socket identifier.
100
/** Parent module phone.
103
/** Parent module service.
106
/** Underlying protocol header size.
107
* Sending and receiving optimalization.
110
/** Packet data fragment size.
111
* Sending optimalization.
113
size_t data_fragment_size;
114
/** Sending safety lock.
115
* Locks the header_size and data_fragment_size attributes.
117
fibril_rwlock_t sending_lock;
118
/** Received packets queue.
121
/** Received packets safety lock.
122
* Used for receiving and receive notifications.
123
* Locks the received attribute.
125
fibril_mutex_t receive_lock;
126
/** Received packets signaling.
127
* Signaled upon receive notification.
129
fibril_condvar_t receive_signal;
130
/** Waiting sockets queue.
133
/** Waiting sockets safety lock.
134
* Used for accepting and accept notifications.
135
* Locks the accepted attribute.
137
fibril_mutex_t accept_lock;
138
/** Waiting sockets signaling.
139
* Signaled upon accept notification.
141
fibril_condvar_t accept_signal;
142
/** The number of blocked functions called.
143
* Used while waiting for the received packets or accepted sockets.
149
* Maps socket identifiers to the socket specific data.
152
INT_MAP_DECLARE( sockets, socket_t );
154
/** Socket client library global data.
156
static struct socket_client_globals {
157
/** TCP module phone.
160
/** UDP module phone.
163
// /** The last socket identifier.
170
* Write lock is used only for adding or removing sockets.
171
* When locked for writing, no other socket locks need to be locked.
172
* When locked for reading, any other socket locks may be locked.
173
* No socket lock may be locked if this lock is unlocked.
175
fibril_rwlock_t lock;
185
.prev = & socket_globals.lock.waiters,
186
.next = & socket_globals.lock.waiters
191
INT_MAP_IMPLEMENT( sockets, socket_t );
193
/** Returns the TCP module phone.
194
* Connects to the TCP module if necessary.
195
* @returns The TCP module phone.
196
* @returns Other error codes as defined for the bind_service_timeout() function.
198
static int socket_get_tcp_phone( void );
200
/** Returns the UDP module phone.
201
* Connects to the UDP module if necessary.
202
* @returns The UDP module phone.
203
* @returns Other error codes as defined for the bind_service_timeout() function.
205
static int socket_get_udp_phone( void );
207
/** Returns the active sockets.
208
* @returns The active sockets.
210
static sockets_ref socket_get_sockets( void );
212
/** Tries to find a new free socket identifier.
213
* @returns The new socket identifier.
214
* @returns ELIMIT if there is no socket identifier available.
216
static int socket_generate_new_id( void );
218
/** Default thread for new connections.
219
* @param[in] iid The initial message identifier.
220
* @param[in] icall The initial message call structure.
222
void socket_connection( ipc_callid_t iid, ipc_call_t * icall );
224
/** Sends message to the socket parent module with specified data.
225
* @param[in] socket_id Socket identifier.
226
* @param[in] message The action message.
227
* @param[in] arg2 The second message parameter.
228
* @param[in] data The data to be sent.
229
* @param[in] datalength The data length.
230
* @returns EOK on success.
231
* @returns ENOTSOCK if the socket is not found.
232
* @returns EBADMEM if the data parameter is NULL.
233
* @returns NO_DATA if the datalength parameter is zero (0).
234
* @returns Other error codes as defined for the spcific message.
236
int socket_send_data( int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength );
238
/** Initializes a new socket specific data.
239
* @param[in,out] socket The socket to be initialized.
240
* @param[in] socket_id The new socket identifier.
241
* @param[in] phone The parent module phone.
242
* @param[in] service The parent module service.
244
void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
246
/** Clears and destroys the socket.
247
* @param[in] socket The socket to be destroyed.
249
void socket_destroy( socket_ref socket );
251
/** Receives data via the socket.
252
* @param[in] message The action message.
253
* @param[in] socket_id Socket identifier.
254
* @param[out] data The data buffer to be filled.
255
* @param[in] datalength The data length.
256
* @param[in] flags Various receive flags.
257
* @param[out] fromaddr The source address. May be NULL for connected sockets.
258
* @param[in,out] addrlen The address length. The maximum address length is read. The actual address length is set. Used only if fromaddr is not NULL.
259
* @returns EOK on success.
260
* @returns ENOTSOCK if the socket is not found.
261
* @returns EBADMEM if the data parameter is NULL.
262
* @returns NO_DATA if the datalength or addrlen parameter is zero (0).
263
* @returns Other error codes as defined for the spcific message.
265
int recvfrom_core( ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen );
267
/** Sends data via the socket to the remote address.
268
* Binds the socket to a free port if not already connected/bound.
269
* @param[in] message The action message.
270
* @param[in] socket_id Socket identifier.
271
* @param[in] data The data to be sent.
272
* @param[in] datalength The data length.
273
* @param[in] flags Various send flags.
274
* @param[in] toaddr The destination address. May be NULL for connected sockets.
275
* @param[in] addrlen The address length. Used only if toaddr is not NULL.
276
* @returns EOK on success.
277
* @returns ENOTSOCK if the socket is not found.
278
* @returns EBADMEM if the data or toaddr parameter is NULL.
279
* @returns NO_DATA if the datalength or the addrlen parameter is zero (0).
280
* @returns Other error codes as defined for the NET_SOCKET_SENDTO message.
282
int sendto_core( ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen );
284
static int socket_get_tcp_phone( void ){
285
if( socket_globals.tcp_phone < 0 ){
286
socket_globals.tcp_phone = bind_service_timeout( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection, SOCKET_CONNECT_TIMEOUT );
288
return socket_globals.tcp_phone;
291
static int socket_get_udp_phone( void ){
292
if( socket_globals.udp_phone < 0 ){
293
socket_globals.udp_phone = bind_service_timeout( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection, SOCKET_CONNECT_TIMEOUT );
295
return socket_globals.udp_phone;
298
static sockets_ref socket_get_sockets( void ){
299
if( ! socket_globals.sockets ){
300
socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t ));
301
if( ! socket_globals.sockets ) return NULL;
302
if( sockets_initialize( socket_globals.sockets ) != EOK ){
303
free( socket_globals.sockets );
304
socket_globals.sockets = NULL;
306
srand( task_get_id());
308
return socket_globals.sockets;
311
static int socket_generate_new_id( void ){
316
sockets = socket_get_sockets();
318
// socket_id = socket_globals.last_id;
320
if( count < SOCKET_ID_TRIES ){
321
socket_id = rand() % INT_MAX;
323
}else if( count == SOCKET_ID_TRIES ){
326
// only this branch for last_id
328
if( socket_id < INT_MAX ){
330
/* }else if( socket_globals.last_id ){
331
* socket_globals.last_id = 0;
337
}while( sockets_find( sockets, socket_id ));
338
// last_id = socket_id
342
void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){
343
socket->socket_id = socket_id;
344
socket->phone = phone;
345
socket->service = service;
346
dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE );
347
dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE );
348
fibril_mutex_initialize( & socket->receive_lock );
349
fibril_condvar_initialize( & socket->receive_signal );
350
fibril_mutex_initialize( & socket->accept_lock );
351
fibril_condvar_initialize( & socket->accept_signal );
352
fibril_rwlock_initialize( & socket->sending_lock );
355
void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){
364
callid = async_get_call( & call );
365
switch( IPC_GET_METHOD( call )){
366
case NET_SOCKET_RECEIVED:
367
case NET_SOCKET_ACCEPTED:
368
case NET_SOCKET_DATA_FRAGMENT_SIZE:
369
fibril_rwlock_read_lock( & socket_globals.lock );
371
socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call ));
373
ERROR_CODE = ENOTSOCK;
375
switch( IPC_GET_METHOD( call )){
376
case NET_SOCKET_RECEIVED:
377
fibril_mutex_lock( & socket->receive_lock );
378
// push the number of received packet fragments
379
if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_MAX_RECEIVED_SIZE ))){
380
// signal the received packet
381
fibril_condvar_signal( & socket->receive_signal );
383
fibril_mutex_unlock( & socket->receive_lock );
385
case NET_SOCKET_ACCEPTED:
386
// push the new socket identifier
387
fibril_mutex_lock( & socket->accept_lock );
388
if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, 1, SOCKET_MAX_ACCEPTED_SIZE ))){
389
// signal the accepted socket
390
fibril_condvar_signal( & socket->accept_signal );
392
fibril_mutex_unlock( & socket->accept_lock );
395
ERROR_CODE = ENOTSUP;
397
if(( SOCKET_GET_DATA_FRAGMENT_SIZE( call ) > 0 )
398
&& ( SOCKET_GET_DATA_FRAGMENT_SIZE( call ) != socket->data_fragment_size )){
399
fibril_rwlock_write_lock( & socket->sending_lock );
400
// set the data fragment size
401
socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( call );
402
fibril_rwlock_write_unlock( & socket->sending_lock );
405
fibril_rwlock_read_unlock( & socket_globals.lock );
408
ERROR_CODE = ENOTSUP;
410
ipc_answer_0( callid, ( ipcarg_t ) ERROR_CODE );
414
int socket( int domain, int type, int protocol ){
422
// find the appropriate service
427
if( ! protocol ) protocol = IPPROTO_TCP;
430
phone = socket_get_tcp_phone();
431
service = SERVICE_TCP;
434
return EPROTONOSUPPORT;
438
if( ! protocol ) protocol = IPPROTO_UDP;
441
phone = socket_get_udp_phone();
442
service = SERVICE_UDP;
445
return EPROTONOSUPPORT;
450
return ESOCKTNOSUPPORT;
457
if( phone < 0 ) return phone;
458
// create a new socket structure
459
socket = ( socket_ref ) malloc( sizeof( socket_t ));
460
if( ! socket ) return ENOMEM;
461
bzero( socket, sizeof( * socket ));
462
fibril_rwlock_write_lock( & socket_globals.lock );
463
// request a new socket
464
socket_id = socket_generate_new_id();
465
if( socket_id <= 0 ){
466
fibril_rwlock_write_unlock( & socket_globals.lock );
470
if( ERROR_OCCURRED(( int ) async_req_3_3( phone, NET_SOCKET, socket_id, 0, service, NULL, ( ipcarg_t * ) & socket->data_fragment_size, ( ipcarg_t * ) & socket->header_size ))){
471
fibril_rwlock_write_unlock( & socket_globals.lock );
475
// finish the new socket initialization
476
socket_initialize( socket, socket_id, phone, service );
477
// store the new socket
478
ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket );
479
fibril_rwlock_write_unlock( & socket_globals.lock );
480
if( ERROR_CODE < 0 ){
481
dyn_fifo_destroy( & socket->received );
482
dyn_fifo_destroy( & socket->accepted );
484
async_msg_3( phone, NET_SOCKET_CLOSE, ( ipcarg_t ) socket_id, 0, service );
491
int socket_send_data( int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength ){
496
if( ! data ) return EBADMEM;
497
if( ! datalength ) return NO_DATA;
499
fibril_rwlock_read_lock( & socket_globals.lock );
501
socket = sockets_find( socket_get_sockets(), socket_id );
503
fibril_rwlock_read_unlock( & socket_globals.lock );
506
// request the message
507
message_id = async_send_3( socket->phone, message, ( ipcarg_t ) socket->socket_id, arg2, socket->service, NULL );
509
async_data_write_start( socket->phone, data, datalength );
510
fibril_rwlock_read_unlock( & socket_globals.lock );
511
async_wait_for( message_id, & result );
512
return ( int ) result;
515
int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){
516
if( addrlen <= 0 ) return EINVAL;
518
return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, ( size_t ) addrlen );
521
int listen( int socket_id, int backlog ){
525
if( backlog <= 0 ) return EINVAL;
526
fibril_rwlock_read_lock( & socket_globals.lock );
528
socket = sockets_find( socket_get_sockets(), socket_id );
530
fibril_rwlock_read_unlock( & socket_globals.lock );
533
// request listen backlog change
534
result = ( int ) async_req_3_0( socket->phone, NET_SOCKET_LISTEN, ( ipcarg_t ) socket->socket_id, ( ipcarg_t ) backlog, socket->service );
535
fibril_rwlock_read_unlock( & socket_globals.lock );
539
int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
541
socket_ref new_socket;
547
if(( ! cliaddr ) || ( ! addrlen )) return EBADMEM;
549
fibril_rwlock_write_lock( & socket_globals.lock );
551
socket = sockets_find( socket_get_sockets(), socket_id );
553
fibril_rwlock_write_unlock( & socket_globals.lock );
556
fibril_mutex_lock( & socket->accept_lock );
557
// wait for an accepted socket
559
while( dyn_fifo_value( & socket->accepted ) <= 0 ){
560
fibril_rwlock_write_unlock( & socket_globals.lock );
561
fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock );
562
fibril_rwlock_write_lock( & socket_globals.lock );
566
// create a new scoket
567
new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
569
fibril_mutex_unlock( & socket->accept_lock );
570
fibril_rwlock_write_unlock( & socket_globals.lock );
573
bzero( new_socket, sizeof( * new_socket ));
574
socket_id = socket_generate_new_id();
575
if( socket_id <= 0 ){
576
fibril_mutex_unlock( & socket->accept_lock );
577
fibril_rwlock_write_unlock( & socket_globals.lock );
581
socket_initialize( new_socket, socket_id, socket->phone, socket->service );
582
result = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket );
584
fibril_mutex_unlock( & socket->accept_lock );
585
fibril_rwlock_write_unlock( & socket_globals.lock );
591
message_id = async_send_5( socket->phone, NET_SOCKET_ACCEPT, ( ipcarg_t ) socket->socket_id, 0, socket->service, 0, new_socket->socket_id, & answer );
593
ipc_data_read_start( socket->phone, cliaddr, * addrlen );
594
fibril_rwlock_write_unlock( & socket_globals.lock );
595
async_wait_for( message_id, & ipc_result );
596
result = (int) ipc_result;
598
if( result != socket_id ){
601
// dequeue the accepted socket if successful
602
dyn_fifo_pop( & socket->accepted );
603
// set address length
604
* addrlen = SOCKET_GET_ADDRESS_LENGTH( answer );
605
new_socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( answer );
606
}else if( result == ENOTSOCK ){
607
// empty the queue if no accepted sockets
608
while( dyn_fifo_pop( & socket->accepted ) > 0 );
610
fibril_mutex_unlock( & socket->accept_lock );
614
int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){
615
if( ! serv_addr ) return EDESTADDRREQ;
616
if( ! addrlen ) return EDESTADDRREQ;
618
return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen );
621
int closesocket( int socket_id ){
626
fibril_rwlock_write_lock( & socket_globals.lock );
627
socket = sockets_find( socket_get_sockets(), socket_id );
629
fibril_rwlock_write_unlock( & socket_globals.lock );
632
if( socket->blocked ){
633
fibril_rwlock_write_unlock( & socket_globals.lock );
637
ERROR_PROPAGATE(( int ) async_req_3_0( socket->phone, NET_SOCKET_CLOSE, ( ipcarg_t ) socket->socket_id, 0, socket->service ));
638
// free the socket structure
639
socket_destroy( socket );
640
fibril_rwlock_write_unlock( & socket_globals.lock );
644
void socket_destroy( socket_ref socket ){
647
// destroy all accepted sockets
648
while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){
649
socket_destroy( sockets_find( socket_get_sockets(), accepted_id ));
651
dyn_fifo_destroy( & socket->received );
652
dyn_fifo_destroy( & socket->accepted );
653
sockets_exclude( socket_get_sockets(), socket->socket_id );
656
int send( int socket_id, void * data, size_t datalength, int flags ){
657
// without the address
658
return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 );
661
int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
662
if( ! toaddr ) return EDESTADDRREQ;
663
if( ! addrlen ) return EDESTADDRREQ;
665
return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen );
668
int sendto_core( ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
675
if( ! data ) return EBADMEM;
676
if( ! datalength ) return NO_DATA;
677
fibril_rwlock_read_lock( & socket_globals.lock );
679
socket = sockets_find( socket_get_sockets(), socket_id );
681
fibril_rwlock_read_unlock( & socket_globals.lock );
684
fibril_rwlock_read_lock( & socket->sending_lock );
685
// compute data fragment count
686
if( socket->data_fragment_size > 0 ){
687
fragments = ( datalength + socket->header_size ) / socket->data_fragment_size;
688
if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments;
693
message_id = async_send_5( socket->phone, message, ( ipcarg_t ) socket->socket_id, ( fragments == 1 ? datalength : socket->data_fragment_size ), socket->service, ( ipcarg_t ) flags, fragments, & answer );
694
// send the address if given
695
if(( ! toaddr ) || ( async_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){
696
if( fragments == 1 ){
697
// send all if only one fragment
698
async_data_write_start( socket->phone, data, datalength );
700
// send the first fragment
701
async_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size );
702
data = (( const uint8_t * ) data ) + socket->data_fragment_size - socket->header_size;
703
// send the middle fragments
704
while(( -- fragments ) > 1 ){
705
async_data_write_start( socket->phone, data, socket->data_fragment_size );
706
data = (( const uint8_t * ) data ) + socket->data_fragment_size;
708
// send the last fragment
709
async_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size );
712
async_wait_for( message_id, & result );
713
if(( SOCKET_GET_DATA_FRAGMENT_SIZE( answer ) > 0 )
714
&& ( SOCKET_GET_DATA_FRAGMENT_SIZE( answer ) != socket->data_fragment_size )){
715
// set the data fragment size
716
socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( answer );
718
fibril_rwlock_read_unlock( & socket->sending_lock );
719
fibril_rwlock_read_unlock( & socket_globals.lock );
720
return ( int ) result;
723
int recv( int socket_id, void * data, size_t datalength, int flags ){
724
// without the address
725
return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL );
728
int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
729
if( ! fromaddr ) return EBADMEM;
730
if( ! addrlen ) return NO_DATA;
732
return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen );
735
int recvfrom_core( ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
745
if( ! data ) return EBADMEM;
746
if( ! datalength ) return NO_DATA;
747
if( fromaddr && ( ! addrlen )) return EINVAL;
748
fibril_rwlock_read_lock( & socket_globals.lock );
750
socket = sockets_find( socket_get_sockets(), socket_id );
752
fibril_rwlock_read_unlock( & socket_globals.lock );
755
fibril_mutex_lock( & socket->receive_lock );
756
// wait for a received packet
758
while(( result = dyn_fifo_value( & socket->received )) <= 0 ){
759
fibril_rwlock_read_unlock( & socket_globals.lock );
760
fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
761
fibril_rwlock_read_lock( & socket_globals.lock );
764
fragments = ( size_t ) result;
765
// prepare lengths if more fragments
767
lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t ));
769
fibril_mutex_unlock( & socket->receive_lock );
770
fibril_rwlock_read_unlock( & socket_globals.lock );
773
// request packet data
774
message_id = async_send_4( socket->phone, message, ( ipcarg_t ) socket->socket_id, 0, socket->service, ( ipcarg_t ) flags, & answer );
775
// read the address if desired
776
if(( ! fromaddr ) || ( async_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){
777
// read the fragment lengths
778
if( async_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){
779
if( lengths[ fragments ] <= datalength ){
780
// read all fragments if long enough
781
for( index = 0; index < fragments; ++ index ){
782
async_data_read_start( socket->phone, data, lengths[ index ] );
783
data = (( uint8_t * ) data ) + lengths[ index ];
790
// request packet data
791
message_id = async_send_4( socket->phone, message, ( ipcarg_t ) socket->socket_id, 0, socket->service, ( ipcarg_t ) flags, & answer );
792
// read the address if desired
793
if(( ! fromaddr ) || ( async_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){
794
// read all if only one fragment
795
async_data_read_start( socket->phone, data, datalength );
798
async_wait_for( message_id, & ipc_result );
799
result = (int) ipc_result;
802
// dequeue the received packet
803
dyn_fifo_pop( & socket->received );
804
// return read data length
805
result = SOCKET_GET_READ_DATA_LENGTH( answer );
806
// set address length
807
if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer );
809
fibril_mutex_unlock( & socket->receive_lock );
810
fibril_rwlock_read_unlock( & socket_globals.lock );
814
int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){
819
if( !( value && optlen )) return EBADMEM;
820
if( !( * optlen )) return NO_DATA;
821
fibril_rwlock_read_lock( & socket_globals.lock );
823
socket = sockets_find( socket_get_sockets(), socket_id );
825
fibril_rwlock_read_unlock( & socket_globals.lock );
828
// request option value
829
message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, ( ipcarg_t ) socket->socket_id, ( ipcarg_t ) optname, socket->service, NULL );
831
if( async_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){
833
async_data_read_start( socket->phone, value, * optlen );
835
fibril_rwlock_read_unlock( & socket_globals.lock );
836
async_wait_for( message_id, & result );
837
return ( int ) result;
840
int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){
842
return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, ( ipcarg_t ) optname, value, optlen );