Subversion Repositories HelenOS

Rev

Rev 4582 | Rev 4603 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4578 mejdrech 1
/*
2
 * Copyright (c) 2009 Lukas Mejdrech
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
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.
16
 *
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.
27
 */
28
 
29
/** @addtogroup socket
30
 *  @{
31
 */
32
 
33
/** @file
34
 *  Socket application program interface (API) implementation.
35
 *  @see socket.h for more information.
36
 *  This is a part of the network application library.
37
 */
38
 
39
#include <assert.h>
40
#include <async.h>
4582 mejdrech 41
#include <fibril_sync.h>
4578 mejdrech 42
 
43
#include <ipc/services.h>
44
 
45
#include "../err.h"
46
#include "../modules.h"
47
 
48
#include "../include/in.h"
49
#include "../include/socket.h"
50
#include "../include/socket_errno.h"
51
 
4589 mejdrech 52
#include "../structures/dynamic_fifo.h"
4578 mejdrech 53
#include "../structures/int_map.h"
54
 
55
#include "socket_messages.h"
56
 
4589 mejdrech 57
#define SOCKET_INITIAL_RECEIVED_SIZE	4
58
#define SOCKET_MAX_RECEIVED_SIZE		64
59
 
60
#define SOCKET_INITIAL_ACCEPTED_SIZE	1
61
#define SOCKET_MAX_ACCEPTED_SIZE		64
62
 
4578 mejdrech 63
typedef struct socket	socket_t;
64
typedef socket_t *		socket_ref;
65
 
66
struct socket{
67
	int					socket_id;
68
	int					phone;
69
	services_t			service;
4589 mejdrech 70
	int					header_size;
71
	int					data_fragment_size;
72
	dyn_fifo_t			received;
4582 mejdrech 73
	fibril_mutex_t		receive_lock;
74
	fibril_condvar_t	receive_signal;
4589 mejdrech 75
	dyn_fifo_t			accepted;
4582 mejdrech 76
	fibril_mutex_t		accept_lock;
77
	fibril_condvar_t	accept_signal;
4578 mejdrech 78
};
79
 
80
INT_MAP_DECLARE( sockets, socket_t );
81
 
82
static struct{
83
	int	tcp_phone;
84
	int	udp_phone;
85
	sockets_ref	sockets;
86
} socket_globals = { -1, -1, NULL };
87
 
88
INT_MAP_IMPLEMENT( sockets, socket_t );
89
 
90
static int	socket_get_tcp_phone();
91
static int	socket_get_tcp_phone();
92
static sockets_ref	socket_get_sockets();
93
void	socket_connection( ipc_callid_t iid, ipc_call_t * icall );
94
int	socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength );
95
void	socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
4589 mejdrech 96
void	socket_destroy( socket_ref socket );
97
int	recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen );
98
int	sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen );
4578 mejdrech 99
 
100
static int socket_get_tcp_phone(){
101
	if( socket_globals.tcp_phone < 0 ){
102
		socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection );
103
	}
104
	return socket_globals.tcp_phone;
105
}
106
 
107
static int socket_get_udp_phone(){
108
	if( socket_globals.udp_phone < 0 ){
109
		socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection );
110
	}
111
	return socket_globals.udp_phone;
112
}
113
 
114
static sockets_ref socket_get_sockets(){
115
	if( ! socket_globals.sockets ){
116
		socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t ));
117
		if( ! socket_globals.sockets ) return NULL;
118
		if( sockets_initialize( socket_globals.sockets ) != EOK ){
119
			free( socket_globals.sockets );
120
			socket_globals.sockets = NULL;
121
		}
122
	}
123
	return socket_globals.sockets;
124
}
125
 
126
void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){
127
	socket->socket_id = socket_id;
128
	socket->phone = phone;
129
	socket->service = service;
4589 mejdrech 130
	dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE );
131
	dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE );
4582 mejdrech 132
	fibril_mutex_initialize( & socket->receive_lock );
133
	fibril_condvar_initialize( & socket->receive_signal );
134
	fibril_mutex_initialize( & socket->accept_lock );
135
	fibril_condvar_initialize( & socket->accept_signal );
4578 mejdrech 136
}
137
 
138
void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){
139
	ERROR_DECLARE;
140
 
141
	ipc_callid_t	callid;
142
	ipc_call_t		call;
143
	socket_ref		socket;
144
	socket_ref		new_socket;
145
 
146
	while( true ){
147
 
148
		callid = async_get_call( & call );
149
		switch( IPC_GET_METHOD( call )){
150
			case NET_SOCKET_RECEIVED:
4589 mejdrech 151
				// find the socket
4578 mejdrech 152
				socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
153
				if( ! socket ){
154
					ERROR_CODE = ENOTSOCK;
155
					break;
156
				}
4582 mejdrech 157
				fibril_mutex_lock( & socket->receive_lock );
4589 mejdrech 158
				// push the number of received packet fragments
159
				if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( & call ), SOCKET_MAX_RECEIVED_SIZE ))){
160
					// signal the received packet
161
					fibril_condvar_signal( & socket->receive_signal );
162
				}
4582 mejdrech 163
				fibril_mutex_unlock( & socket->receive_lock );
4578 mejdrech 164
				break;
165
			case NET_SOCKET_ACCEPTED:
4589 mejdrech 166
				// find the socket
4578 mejdrech 167
				socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
168
				if( ! socket ){
169
					ERROR_CODE = ENOTSOCK;
170
					break;
171
				}
4589 mejdrech 172
				// create a new scoket
4578 mejdrech 173
				new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
174
				if( ! new_socket ){
175
					ERROR_CODE = ENOMEM;
176
					break;
177
				}
4589 mejdrech 178
				socket_initialize( new_socket, SOCKET_GET_SOCKET_ID( & call ), socket->phone, socket->service );
179
				ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket );
180
				if( ERROR_CODE < 0 ){
181
					free( new_socket );
182
				}else{
183
					// push the new socket identifier
184
					fibril_mutex_lock( & socket->accept_lock );
185
					if( ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, new_socket->socket_id, SOCKET_MAX_ACCEPTED_SIZE ))){
186
						sockets_exclude( socket_get_sockets(), new_socket->socket_id );
187
						free( new_socket );
188
					}else{
189
						// signal the accepted socket
190
						fibril_condvar_signal( & socket->accept_signal );
191
					}
192
					fibril_mutex_unlock( & socket->accept_lock );
193
					ERROR_CODE = EOK;
4578 mejdrech 194
				}
195
				break;
4589 mejdrech 196
			case NET_SOCKET_DATA_FRAGMENT_SIZE:
197
				// find the socket
4578 mejdrech 198
				socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
199
				if( ! socket ){
200
					ERROR_CODE = ENOTSOCK;
201
					break;
202
				}
4589 mejdrech 203
				// set the data fragment size
204
				socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( & call );
4578 mejdrech 205
				ERROR_CODE = EOK;
206
				break;
4589 mejdrech 207
			default:
4578 mejdrech 208
				ERROR_CODE = ENOTSUP;
209
		}
210
		ipc_answer_0( callid, ERROR_CODE );
211
	}
212
}
213
 
214
int socket( int domain, int type, int protocol ){
4589 mejdrech 215
	ERROR_DECLARE;
216
 
4578 mejdrech 217
	socket_ref	socket;
218
	int			phone;
219
	int			socket_id;
220
	services_t	service;
221
 
4589 mejdrech 222
	// find the appropriate service
4578 mejdrech 223
	switch( domain ){
224
		case PF_INET:
225
			switch( type ){
226
				case SOCK_STREAM:
227
					if( ! protocol ) protocol = IPPROTO_TCP;
228
					switch( protocol ){
229
						case IPPROTO_TCP:
230
							phone = socket_get_tcp_phone();
231
							service = SERVICE_TCP;
232
							break;
233
						default:
234
							return EPROTONOSUPPORT;
235
					}
236
					break;
237
				case SOCK_DGRAM:
238
					if( ! protocol ) protocol = IPPROTO_UDP;
239
					switch( protocol ){
240
						case IPPROTO_UDP:
241
							phone = socket_get_udp_phone();
242
							service = SERVICE_UDP;
243
							break;
244
						default:
245
							return EPROTONOSUPPORT;
246
					}
247
					break;
248
				case SOCK_RAW:
249
				default:
250
					return ESOCKTNOSUPPORT;
251
			}
252
			break;
253
		// TODO IPv6
254
		default:
255
			return EPFNOSUPPORT;
256
	}
4589 mejdrech 257
	// create a new socket structure
4578 mejdrech 258
	socket = ( socket_ref ) malloc( sizeof( socket_t ));
259
	if( ! socket ) return ENOMEM;
4589 mejdrech 260
	if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){
4578 mejdrech 261
		free( socket );
4589 mejdrech 262
		return ERROR_CODE;
4578 mejdrech 263
	}
4589 mejdrech 264
	if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){
265
		dyn_fifo_destroy( & socket->received );
266
		free( socket );
267
		return ERROR_CODE;
268
	}
269
	// request a new socket
270
	if( ERROR_OCCURRED( async_req_3_3( phone, NET_SOCKET, 0, 0, service, ( ipcarg_t * ) & socket_id, ( ipcarg_t * ) & socket->header_size, ( ipcarg_t * ) & socket->data_fragment_size ))){
271
		dyn_fifo_destroy( & socket->received );
272
		dyn_fifo_destroy( & socket->accepted );
273
		free( socket );
274
		return ERROR_CODE;
275
	}
276
	// finish the new socket initialization
277
	socket_initialize( socket, socket_id, phone, service );
278
	// store the new socket
279
	ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket );
280
	if( ERROR_CODE < 0 ){
281
		dyn_fifo_destroy( & socket->received );
282
		dyn_fifo_destroy( & socket->accepted );
283
		free( socket );
284
		async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service );
285
		return ERROR_CODE;
286
	}
287
 
4578 mejdrech 288
	return socket_id;
289
}
290
 
291
int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ){
292
	socket_ref		socket;
293
	aid_t			message_id;
294
	ipcarg_t		result;
295
 
296
	if( ! data ) return EBADMEM;
297
	if( ! datalength ) return NO_DATA;
4589 mejdrech 298
	// find the socket
4578 mejdrech 299
	socket = sockets_find( socket_get_sockets(), socket_id );
300
	if( ! socket ) return ENOTSOCK;
4589 mejdrech 301
	// request the message
4578 mejdrech 302
	message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL );
4589 mejdrech 303
	// send the address
4578 mejdrech 304
	ipc_data_write_start( socket->phone, data, datalength );
305
	async_wait_for( message_id, & result );
306
	return ( int ) result;
307
}
308
 
309
int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){
4589 mejdrech 310
	// send the address
4578 mejdrech 311
	return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen );
312
}
313
 
314
int listen( int socket_id, int backlog ){
315
	socket_ref		socket;
316
 
317
	if( backlog <= 0 ) return EINVAL;
4589 mejdrech 318
	// find the socket
4578 mejdrech 319
	socket = sockets_find( socket_get_sockets(), socket_id );
320
	if( ! socket ) return ENOTSOCK;
4589 mejdrech 321
	// request listen backlog change
4578 mejdrech 322
	return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service );
323
}
324
 
325
int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
326
	socket_ref		socket;
327
	aid_t			message_id;
4589 mejdrech 328
	int				result;
4578 mejdrech 329
 
330
	if( ! cliaddr ) return EBADMEM;
331
	if( ! addrlen ) return NO_DATA;
4589 mejdrech 332
	// find the socket
4578 mejdrech 333
	socket = sockets_find( socket_get_sockets(), socket_id );
334
	if( ! socket ) return ENOTSOCK;
4582 mejdrech 335
	fibril_mutex_lock( & socket->accept_lock );
4589 mejdrech 336
	// wait for an accepted socket
337
	while( dyn_fifo_value( & socket->accepted ) <= 0 ){
4582 mejdrech 338
		fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock );
4578 mejdrech 339
	}
4589 mejdrech 340
	// request accept
341
	message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, dyn_fifo_value( & socket->accepted ), socket->service, NULL );
342
	// read address
4578 mejdrech 343
	ipc_data_read_start( socket->phone, cliaddr, * addrlen );
4589 mejdrech 344
	async_wait_for( message_id, ( ipcarg_t * ) & result );
4578 mejdrech 345
	if( result > 0 ){
4589 mejdrech 346
		// dequeue the accepted apcket if successful
347
		dyn_fifo_pop( & socket->accepted );
4578 mejdrech 348
	}
4582 mejdrech 349
	fibril_mutex_unlock( & socket->accept_lock );
4589 mejdrech 350
	return result;
4578 mejdrech 351
}
352
 
353
int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){
4589 mejdrech 354
	// send the address
4578 mejdrech 355
	return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen );
356
}
357
 
358
int closesocket( int socket_id ){
4589 mejdrech 359
	ERROR_DECLARE;
360
 
4578 mejdrech 361
	socket_ref		socket;
362
 
363
	socket = sockets_find( socket_get_sockets(), socket_id );
364
	if( ! socket ) return ENOTSOCK;
4589 mejdrech 365
	// request close
366
	ERROR_PROPAGATE( async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service ));
367
	// free the socket structure
368
	socket_destroy( socket );
369
	return EOK;
4578 mejdrech 370
}
371
 
4589 mejdrech 372
void socket_destroy( socket_ref socket ){
373
	int	accepted_id;
374
 
375
	// destroy all accepted sockets
376
	while(( accepted_id = dyn_fifo_pop( & socket->accepted ))){
377
		socket_destroy( sockets_find( socket_get_sockets(), accepted_id ));
378
	}
379
	dyn_fifo_destroy( & socket->received );
380
	dyn_fifo_destroy( & socket->accepted );
381
	sockets_exclude( socket_get_sockets(), socket->socket_id );
382
}
383
 
4578 mejdrech 384
int send( int socket_id, void * data, size_t datalength, int flags ){
4589 mejdrech 385
	// without the address
386
	return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 );
4578 mejdrech 387
}
388
 
389
int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
390
	if( ! toaddr ) return EBADMEM;
391
	if( ! addrlen ) return NO_DATA;
4589 mejdrech 392
	// with the address
393
	return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen );
4578 mejdrech 394
}
395
 
4589 mejdrech 396
int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
4578 mejdrech 397
	socket_ref		socket;
398
	aid_t			message_id;
399
	ipcarg_t		result;
4589 mejdrech 400
	int				fragments;
4578 mejdrech 401
 
402
	if( ! data ) return EBADMEM;
403
	if( ! datalength ) return NO_DATA;
4589 mejdrech 404
	// find socket
4578 mejdrech 405
	socket = sockets_find( socket_get_sockets(), socket_id );
406
	if( ! socket ) return ENOTSOCK;
4589 mejdrech 407
	// compute data fragment count
408
	fragments = ( datalength + socket->header_size ) / socket->data_fragment_size;
409
	if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments;
410
	// request send
411
	message_id = async_send_4( socket->phone, message, socket->socket_id, fragments, socket->service, flags, NULL );
412
	// send the address if given
413
	if(( ! toaddr ) || ( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){
414
		if( fragments == 1 ){
415
			// send all if only one fragment
416
			ipc_data_write_start( socket->phone, data, datalength );
417
		}else{
418
			// send the first fragment
419
			ipc_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size );
420
			data += socket->data_fragment_size - socket->header_size;
421
			// send the middle fragments
422
			while(( -- fragments ) > 1 ){
423
				ipc_data_write_start( socket->phone, data, socket->data_fragment_size );
424
				data += socket->data_fragment_size;
425
			}
426
			// send the last fragment
427
			ipc_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size );
428
		}
4578 mejdrech 429
	}
430
	async_wait_for( message_id, & result );
431
	return ( int ) result;
432
}
433
 
4589 mejdrech 434
int recv( int socket_id, void * data, size_t datalength, int flags ){
435
	// without the address
436
	return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL );
437
}
438
 
4578 mejdrech 439
int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
4589 mejdrech 440
	if( ! fromaddr ) return EBADMEM;
441
	if( ! addrlen ) return NO_DATA;
442
	// with the address
443
	return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen );
444
}
445
 
446
int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
4578 mejdrech 447
	socket_ref		socket;
448
	aid_t			message_id;
4589 mejdrech 449
	int				result;
450
	int				fragments;
451
	int *			lengths;
452
	int				index;
453
	ipc_call_t		answer;
4578 mejdrech 454
 
455
	if( ! data ) return EBADMEM;
456
	if( ! datalength ) return NO_DATA;
4589 mejdrech 457
	// find the socket
4578 mejdrech 458
	socket = sockets_find( socket_get_sockets(), socket_id );
459
	if( ! socket ) return ENOTSOCK;
4582 mejdrech 460
	fibril_mutex_lock( & socket->receive_lock );
4589 mejdrech 461
	// wait for a received packet
462
	while(( fragments = dyn_fifo_value( & socket->received )) <= 0 ){
4582 mejdrech 463
		fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
4578 mejdrech 464
	}
4589 mejdrech 465
	// prepare lengths if more fragments
466
	if( fragments > 1 ){
467
		lengths = ( int * ) malloc( sizeof( int ) * ( fragments + 1 ));
468
		if( ! lengths ){
469
			fibril_mutex_unlock( & socket->receive_lock );
470
			return ENOMEM;
471
		}
4578 mejdrech 472
	}
4589 mejdrech 473
	// request packet data
474
	message_id = async_send_4( socket->phone, message, socket->socket_id, 0, socket->service, flags, & answer );
475
	// read the address if desired
476
	if( fromaddr ){
477
		* addrlen = sizeof( struct sockaddr_in );
4578 mejdrech 478
	}
4589 mejdrech 479
	if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){
480
		if( fragments == 1 ){
481
			// read all if only one fragment
482
			ipc_data_read_start( socket->phone, data, datalength );
483
		}else{
484
		// read the fragment lengths
485
			if( ipc_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){
486
				if( lengths[ fragments ] <= datalength ){
487
				// read all fragments if long enough
488
					for( index = 0; index < fragments; ++ index ){
489
						ipc_data_read_start( socket->phone, data, lengths[ index ] );
490
						data += lengths[ index ];
491
					}
492
				}
493
			}
494
			free( lengths );
495
		}
496
	}else if( fragments > 1 ){
497
		free( lengths );
498
	}
499
	async_wait_for( message_id, ( ipcarg_t * ) & result );
500
	// if successful
501
	if( result == EOK ){
502
		// dequeue the received packet
503
		dyn_fifo_pop( & socket->received );
504
		// return read data length
505
		result = SOCKET_GET_READ_DATA_LENGTH( & answer );
506
	}
4582 mejdrech 507
	fibril_mutex_unlock( & socket->receive_lock );
4589 mejdrech 508
	return result;
4578 mejdrech 509
}
510
 
511
int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){
512
	socket_ref		socket;
513
	aid_t			message_id;
514
	ipcarg_t		result;
515
 
4589 mejdrech 516
	if( !( value && optlen )) return EBADMEM;
517
	if( !( * optlen )) return NO_DATA;
518
	// find the socket
4578 mejdrech 519
	socket = sockets_find( socket_get_sockets(), socket_id );
520
	if( ! socket ) return ENOTSOCK;
4589 mejdrech 521
	// request option value
4578 mejdrech 522
	message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL );
4589 mejdrech 523
	// read the length
524
	if( ipc_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){
525
		// read the value
526
		ipc_data_read_start( socket->phone, value, * optlen );
527
	}
4578 mejdrech 528
	async_wait_for( message_id, & result );
529
	return ( int ) result;
530
}
531
 
532
int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){
4589 mejdrech 533
	// send the value
4578 mejdrech 534
	return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen );
4589 mejdrech 535
 
4578 mejdrech 536
}
537
 
538
/** @}
539
 */