source: mainline/uspace/srv/net/socket/socket_client.c@ 1b053ca2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1b053ca2 was ede63e4, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago
  • socket identifier generation moved to libsocket, + data fragment size fix and enhancement, + [ICMP|TCP|UDP]_HEADER_SIZE definition, + int_map_update() function to alter item key
  • Property mode set to 100644
File size: 27.8 KB
RevLine 
[21580dd]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>
41#include <fibril_synch.h>
[ede63e4]42#include <limits.h>
43#include <stdlib.h>
[21580dd]44
45#include <ipc/services.h>
46
47#include "../err.h"
48#include "../modules.h"
49
50#include "../include/in.h"
51#include "../include/socket.h"
52#include "../include/socket_errno.h"
53
54#include "../structures/dynamic_fifo.h"
55#include "../structures/int_map.h"
56
57#include "socket_messages.h"
58
59/** Initial received packet queue size.
60 */
61#define SOCKET_INITIAL_RECEIVED_SIZE 4
62
63/** Maximum received packet queue size.
64 */
65#define SOCKET_MAX_RECEIVED_SIZE 0
66
67/** Initial waiting sockets queue size.
68 */
69#define SOCKET_INITIAL_ACCEPTED_SIZE 1
70
71/** Maximum waiting sockets queue size.
72 */
73#define SOCKET_MAX_ACCEPTED_SIZE 0
74
[1a0fb3f8]75/** Default timeout for connections in microseconds.
76 */
77#define SOCKET_CONNECT_TIMEOUT ( 1 * 1000 * 1000 )
78
[ede63e4]79/** Maximum number of random attempts to find a new socket identifier before switching to the sequence.
80 */
81#define SOCKET_ID_TRIES 100
82
[21580dd]83/** Type definition of the socket specific data.
84 * @see socket
85 */
86typedef struct socket socket_t;
87
88/** Type definition of the socket specific data pointer.
89 * @see socket
90 */
91typedef socket_t * socket_ref;
92
93/** Socket specific data.
94 * Each socket lock locks only its structure part and any number of them may be locked simultaneously.
95 */
96struct socket{
97 /** Socket identifier.
98 */
99 int socket_id;
100 /** Parent module phone.
101 */
102 int phone;
103 /** Parent module service.
104 */
105 services_t service;
106 /** Underlying protocol header size.
107 * Sending and receiving optimalization.
108 */
109 size_t header_size;
110 /** Packet data fragment size.
111 * Sending optimalization.
112 */
113 size_t data_fragment_size;
114 /** Sending safety lock.
115 * Locks the header_size and data_fragment_size attributes.
116 */
117 fibril_rwlock_t sending_lock;
118 /** Received packets queue.
119 */
120 dyn_fifo_t received;
121 /** Received packets safety lock.
122 * Used for receiving and receive notifications.
123 * Locks the received attribute.
124 */
125 fibril_mutex_t receive_lock;
126 /** Received packets signaling.
127 * Signaled upon receive notification.
128 */
129 fibril_condvar_t receive_signal;
130 /** Waiting sockets queue.
131 */
132 dyn_fifo_t accepted;
133 /** Waiting sockets safety lock.
134 * Used for accepting and accept notifications.
135 * Locks the accepted attribute.
136 */
137 fibril_mutex_t accept_lock;
138 /** Waiting sockets signaling.
139 * Signaled upon accept notification.
140 */
141 fibril_condvar_t accept_signal;
142 /** The number of blocked functions called.
143 * Used while waiting for the received packets or accepted sockets.
144 */
145 int blocked;
146};
147
148/** Sockets map.
149 * Maps socket identifiers to the socket specific data.
150 * @see int_map.h
151 */
152INT_MAP_DECLARE( sockets, socket_t );
153
154/** Socket client library global data.
155 */
156static struct socket_client_globals {
157 /** TCP module phone.
158 */
159 int tcp_phone;
160 /** UDP module phone.
161 */
162 int udp_phone;
[ede63e4]163// /** The last socket identifier.
164// */
165// int last_id;
[21580dd]166 /** Active sockets.
167 */
168 sockets_ref sockets;
169 /** Safety lock.
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.
174 */
175 fibril_rwlock_t lock;
176} socket_globals = {
177 .tcp_phone = -1,
178 .udp_phone = -1,
[ede63e4]179// .last_id = 0,
[21580dd]180 .sockets = NULL,
181 .lock = {
182 .readers = 0,
183 .writers = 0,
184 .waiters = {
185 .prev = & socket_globals.lock.waiters,
186 .next = & socket_globals.lock.waiters
187 }
188 }
189};
190
191INT_MAP_IMPLEMENT( sockets, socket_t );
192
193/** Returns the TCP module phone.
194 * Connects to the TCP module if necessary.
195 * @returns The TCP module phone.
[1a0fb3f8]196 * @returns Other error codes as defined for the bind_service_timeout() function.
[21580dd]197 */
198static int socket_get_tcp_phone( void );
199
200/** Returns the UDP module phone.
201 * Connects to the UDP module if necessary.
202 * @returns The UDP module phone.
[1a0fb3f8]203 * @returns Other error codes as defined for the bind_service_timeout() function.
[21580dd]204 */
205static int socket_get_udp_phone( void );
206
207/** Returns the active sockets.
208 * @returns The active sockets.
209 */
210static sockets_ref socket_get_sockets( void );
211
[ede63e4]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.
215 */
216static int socket_generate_new_id( void );
217
[21580dd]218/** Default thread for new connections.
219 * @param[in] iid The initial message identifier.
220 * @param[in] icall The initial message call structure.
221 */
222void socket_connection( ipc_callid_t iid, ipc_call_t * icall );
223
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.
235 */
236int socket_send_data( int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength );
237
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.
243 */
244void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
245
246/** Clears and destroys the socket.
247 * @param[in] socket The socket to be destroyed.
248 */
249void socket_destroy( socket_ref socket );
250
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.
264 */
265int recvfrom_core( ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen );
266
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.
281 */
282int sendto_core( ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen );
283
284static int socket_get_tcp_phone( void ){
285 if( socket_globals.tcp_phone < 0 ){
[1a0fb3f8]286 socket_globals.tcp_phone = bind_service_timeout( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection, SOCKET_CONNECT_TIMEOUT );
[21580dd]287 }
288 return socket_globals.tcp_phone;
289}
290
291static int socket_get_udp_phone( void ){
292 if( socket_globals.udp_phone < 0 ){
[1a0fb3f8]293 socket_globals.udp_phone = bind_service_timeout( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection, SOCKET_CONNECT_TIMEOUT );
[21580dd]294 }
295 return socket_globals.udp_phone;
296}
297
298static 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;
305 }
[ede63e4]306 srand( task_get_id());
[21580dd]307 }
308 return socket_globals.sockets;
309}
310
[ede63e4]311static int socket_generate_new_id( void ){
312 sockets_ref sockets;
313 int socket_id;
314 int count;
315
316 sockets = socket_get_sockets();
317 count = 0;
318// socket_id = socket_globals.last_id;
319 do{
320 if( count < SOCKET_ID_TRIES ){
321 socket_id = rand() % INT_MAX;
322 ++ count;
323 }else if( count == SOCKET_ID_TRIES ){
324 socket_id = 1;
325 ++ count;
326 // only this branch for last_id
327 }else{
328 if( socket_id < INT_MAX ){
329 ++ socket_id;
330/* }else if( socket_globals.last_id ){
331* socket_globals.last_id = 0;
332* socket_id = 1;
333*/ }else{
334 return ELIMIT;
335 }
336 }
337 }while( sockets_find( sockets, socket_id ));
338// last_id = socket_id
339 return socket_id;
340}
341
[21580dd]342void 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 );
353}
354
355void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){
356 ERROR_DECLARE;
357
358 ipc_callid_t callid;
359 ipc_call_t call;
360 socket_ref socket;
361
362 while( true ){
363
364 callid = async_get_call( & call );
365 switch( IPC_GET_METHOD( call )){
366 case NET_SOCKET_RECEIVED:
367 case NET_SOCKET_ACCEPTED:
[ede63e4]368 case NET_SOCKET_DATA_FRAGMENT_SIZE:
[21580dd]369 fibril_rwlock_read_lock( & socket_globals.lock );
370 // find the socket
371 socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call ));
372 if( ! socket ){
373 ERROR_CODE = ENOTSOCK;
374 }else{
[ede63e4]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 );
382 }
383 fibril_mutex_unlock( & socket->receive_lock );
384 break;
385 case NET_SOCKET_ACCEPTED:
[21580dd]386 // push the new socket identifier
387 fibril_mutex_lock( & socket->accept_lock );
[ede63e4]388 if( ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, SOCKET_GET_NEW_SOCKET_ID( call ), SOCKET_MAX_ACCEPTED_SIZE ))){
389 sockets_exclude( socket_get_sockets(), SOCKET_GET_NEW_SOCKET_ID( call ));
[21580dd]390 }else{
391 // signal the accepted socket
392 fibril_condvar_signal( & socket->accept_signal );
393 }
394 fibril_mutex_unlock( & socket->accept_lock );
[ede63e4]395 break;
396 default:
397 ERROR_CODE = ENOTSUP;
398 }
399 if(( SOCKET_GET_DATA_FRAGMENT_SIZE( call ) > 0 )
400 && ( SOCKET_GET_DATA_FRAGMENT_SIZE( call ) != socket->data_fragment_size )){
401 fibril_rwlock_write_lock( & socket->sending_lock );
402 // set the data fragment size
403 socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( call );
404 fibril_rwlock_write_unlock( & socket->sending_lock );
[21580dd]405 }
406 }
407 fibril_rwlock_read_unlock( & socket_globals.lock );
408 default:
409 ERROR_CODE = ENOTSUP;
410 }
411 ipc_answer_0( callid, ( ipcarg_t ) ERROR_CODE );
412 }
413}
414
415int socket( int domain, int type, int protocol ){
416 ERROR_DECLARE;
417
418 socket_ref socket;
419 int phone;
420 int socket_id;
421 services_t service;
[ede63e4]422 int count;
[21580dd]423
424 // find the appropriate service
425 switch( domain ){
426 case PF_INET:
427 switch( type ){
428 case SOCK_STREAM:
429 if( ! protocol ) protocol = IPPROTO_TCP;
430 switch( protocol ){
431 case IPPROTO_TCP:
432 phone = socket_get_tcp_phone();
433 service = SERVICE_TCP;
434 break;
435 default:
436 return EPROTONOSUPPORT;
437 }
438 break;
439 case SOCK_DGRAM:
440 if( ! protocol ) protocol = IPPROTO_UDP;
441 switch( protocol ){
442 case IPPROTO_UDP:
443 phone = socket_get_udp_phone();
444 service = SERVICE_UDP;
445 break;
446 default:
447 return EPROTONOSUPPORT;
448 }
449 break;
450 case SOCK_RAW:
451 default:
452 return ESOCKTNOSUPPORT;
453 }
454 break;
455 // TODO IPv6
456 default:
457 return EPFNOSUPPORT;
458 }
[1a0fb3f8]459 if( phone < 0 ) return phone;
[21580dd]460 // create a new socket structure
461 socket = ( socket_ref ) malloc( sizeof( socket_t ));
462 if( ! socket ) return ENOMEM;
463 bzero( socket, sizeof( * socket ));
[ede63e4]464 count = 0;
465 fibril_rwlock_write_lock( & socket_globals.lock );
[21580dd]466 // request a new socket
[ede63e4]467 socket_id = socket_generate_new_id();
468 if( socket_id <= 0 ){
469 fibril_rwlock_write_unlock( & socket_globals.lock );
470 free( socket );
471 return socket_id;
472 }
473 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 ))){
474 fibril_rwlock_write_unlock( & socket_globals.lock );
[21580dd]475 free( socket );
476 return ERROR_CODE;
477 }
478 // finish the new socket initialization
479 socket_initialize( socket, socket_id, phone, service );
480 // store the new socket
481 ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket );
482 fibril_rwlock_write_unlock( & socket_globals.lock );
483 if( ERROR_CODE < 0 ){
484 dyn_fifo_destroy( & socket->received );
485 dyn_fifo_destroy( & socket->accepted );
486 free( socket );
487 async_msg_3( phone, NET_SOCKET_CLOSE, ( ipcarg_t ) socket_id, 0, service );
488 return ERROR_CODE;
489 }
490
491 return socket_id;
492}
493
494int socket_send_data( int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength ){
495 socket_ref socket;
496 aid_t message_id;
497 ipcarg_t result;
498
499 if( ! data ) return EBADMEM;
500 if( ! datalength ) return NO_DATA;
501
502 fibril_rwlock_read_lock( & socket_globals.lock );
503 // find the socket
504 socket = sockets_find( socket_get_sockets(), socket_id );
505 if( ! socket ){
506 fibril_rwlock_read_unlock( & socket_globals.lock );
507 return ENOTSOCK;
508 }
509 // request the message
510 message_id = async_send_3( socket->phone, message, ( ipcarg_t ) socket->socket_id, arg2, socket->service, NULL );
511 // send the address
512 async_data_write_start( socket->phone, data, datalength );
513 fibril_rwlock_read_unlock( & socket_globals.lock );
514 async_wait_for( message_id, & result );
515 return ( int ) result;
516}
517
518int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){
519 if( addrlen <= 0 ) return EINVAL;
520 // send the address
521 return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, ( size_t ) addrlen );
522}
523
524int listen( int socket_id, int backlog ){
525 socket_ref socket;
526 int result;
527
528 if( backlog <= 0 ) return EINVAL;
529 fibril_rwlock_read_lock( & socket_globals.lock );
530 // find the socket
531 socket = sockets_find( socket_get_sockets(), socket_id );
532 if( ! socket ){
533 fibril_rwlock_read_unlock( & socket_globals.lock );
534 return ENOTSOCK;
535 }
536 // request listen backlog change
537 result = ( int ) async_req_3_0( socket->phone, NET_SOCKET_LISTEN, ( ipcarg_t ) socket->socket_id, ( ipcarg_t ) backlog, socket->service );
538 fibril_rwlock_read_unlock( & socket_globals.lock );
539 return result;
540}
541
542int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
543 socket_ref socket;
[ede63e4]544 socket_ref new_socket;
[21580dd]545 aid_t message_id;
546 int result;
547 ipc_call_t answer;
548
549 if(( ! cliaddr ) || ( ! addrlen )) return EBADMEM;
550
[ede63e4]551 fibril_rwlock_write_lock( & socket_globals.lock );
[21580dd]552 // find the socket
553 socket = sockets_find( socket_get_sockets(), socket_id );
554 if( ! socket ){
[ede63e4]555 fibril_rwlock_write_unlock( & socket_globals.lock );
[21580dd]556 return ENOTSOCK;
557 }
558 fibril_mutex_lock( & socket->accept_lock );
559 // wait for an accepted socket
560 ++ socket->blocked;
561 while( dyn_fifo_value( & socket->accepted ) <= 0 ){
[ede63e4]562 fibril_rwlock_write_unlock( & socket_globals.lock );
[21580dd]563 fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock );
[ede63e4]564 fibril_rwlock_write_lock( & socket_globals.lock );
[21580dd]565 }
566 -- socket->blocked;
[ede63e4]567
568 // create a new scoket
569 new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
570 if( ! new_socket ){
571 fibril_mutex_unlock( & socket->accept_lock );
572 fibril_rwlock_write_unlock( & socket_globals.lock );
573 return ENOMEM;
574 }
575 bzero( new_socket, sizeof( * new_socket ));
576 socket_id = socket_generate_new_id();
577 if( socket_id <= 0 ){
578 fibril_mutex_unlock( & socket->accept_lock );
579 fibril_rwlock_write_unlock( & socket_globals.lock );
580 free( new_socket );
581 return socket_id;
582 }
583 socket_initialize( new_socket, socket_id, socket->phone, socket->service );
584 result = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket );
585 if( result < 0 ){
586 fibril_mutex_unlock( & socket->accept_lock );
587 fibril_rwlock_write_unlock( & socket_globals.lock );
588 free( new_socket );
589 return result;
590 }
591
[21580dd]592 // request accept
[ede63e4]593 message_id = async_send_5( socket->phone, NET_SOCKET_ACCEPT, ( ipcarg_t ) socket->socket_id, 0, socket->service, 0, new_socket->socket_id, & answer );
[21580dd]594 // read address
[ede63e4]595 ipc_data_read_start( socket->phone, cliaddr, * addrlen );
596 fibril_rwlock_write_unlock( & socket_globals.lock );
[21580dd]597 async_wait_for( message_id, ( ipcarg_t * ) & result );
598 if( result > 0 ){
[ede63e4]599 if( result != socket_id ){
600 result = EINVAL;
601 }
[21580dd]602 // dequeue the accepted socket if successful
603 dyn_fifo_pop( & socket->accepted );
604 // set address length
605 * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer );
[ede63e4]606 new_socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( answer );
[21580dd]607 }else if( result == ENOTSOCK ){
608 // empty the queue if no accepted sockets
609 while( dyn_fifo_pop( & socket->accepted ) > 0 );
610 }
611 fibril_mutex_unlock( & socket->accept_lock );
612 return result;
613}
614
615int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){
616 if( ! serv_addr ) return EDESTADDRREQ;
617 if( ! addrlen ) return EDESTADDRREQ;
618 // send the address
619 return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen );
620}
621
622int closesocket( int socket_id ){
623 ERROR_DECLARE;
624
625 socket_ref socket;
626
627 fibril_rwlock_write_lock( & socket_globals.lock );
628 socket = sockets_find( socket_get_sockets(), socket_id );
629 if( ! socket ){
630 fibril_rwlock_write_unlock( & socket_globals.lock );
631 return ENOTSOCK;
632 }
633 if( socket->blocked ){
634 fibril_rwlock_write_unlock( & socket_globals.lock );
635 return EINPROGRESS;
636 }
637 // request close
638 ERROR_PROPAGATE(( int ) async_req_3_0( socket->phone, NET_SOCKET_CLOSE, ( ipcarg_t ) socket->socket_id, 0, socket->service ));
639 // free the socket structure
640 socket_destroy( socket );
641 fibril_rwlock_write_unlock( & socket_globals.lock );
642 return EOK;
643}
644
645void socket_destroy( socket_ref socket ){
646 int accepted_id;
647
648 // destroy all accepted sockets
649 while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){
650 socket_destroy( sockets_find( socket_get_sockets(), accepted_id ));
651 }
652 dyn_fifo_destroy( & socket->received );
653 dyn_fifo_destroy( & socket->accepted );
654 sockets_exclude( socket_get_sockets(), socket->socket_id );
655}
656
657int send( int socket_id, void * data, size_t datalength, int flags ){
658 // without the address
659 return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 );
660}
661
662int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
663 if( ! toaddr ) return EDESTADDRREQ;
664 if( ! addrlen ) return EDESTADDRREQ;
665 // with the address
666 return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen );
667}
668
669int sendto_core( ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
670 socket_ref socket;
671 aid_t message_id;
672 ipcarg_t result;
673 size_t fragments;
[ede63e4]674 ipc_call_t answer;
[21580dd]675
676 if( ! data ) return EBADMEM;
677 if( ! datalength ) return NO_DATA;
678 fibril_rwlock_read_lock( & socket_globals.lock );
679 // find socket
680 socket = sockets_find( socket_get_sockets(), socket_id );
681 if( ! socket ){
682 fibril_rwlock_read_unlock( & socket_globals.lock );
683 return ENOTSOCK;
684 }
685 fibril_rwlock_read_lock( & socket->sending_lock );
686 // compute data fragment count
[ede63e4]687 if( socket->data_fragment_size > 0 ){
688 fragments = ( datalength + socket->header_size ) / socket->data_fragment_size;
689 if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments;
690 }else{
691 fragments = 1;
692 }
[21580dd]693 // request send
[ede63e4]694 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 );
[21580dd]695 // send the address if given
696 if(( ! toaddr ) || ( async_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){
697 if( fragments == 1 ){
698 // send all if only one fragment
699 async_data_write_start( socket->phone, data, datalength );
700 }else{
701 // send the first fragment
702 async_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size );
703 data = (( const uint8_t * ) data ) + socket->data_fragment_size - socket->header_size;
704 // send the middle fragments
705 while(( -- fragments ) > 1 ){
706 async_data_write_start( socket->phone, data, socket->data_fragment_size );
707 data = (( const uint8_t * ) data ) + socket->data_fragment_size;
708 }
709 // send the last fragment
710 async_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size );
711 }
712 }
[ede63e4]713 async_wait_for( message_id, & result );
714 if(( SOCKET_GET_DATA_FRAGMENT_SIZE( answer ) > 0 )
715 && ( SOCKET_GET_DATA_FRAGMENT_SIZE( answer ) != socket->data_fragment_size )){
716 // set the data fragment size
717 socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( answer );
718 }
[21580dd]719 fibril_rwlock_read_unlock( & socket->sending_lock );
720 fibril_rwlock_read_unlock( & socket_globals.lock );
721 return ( int ) result;
722}
723
724int recv( int socket_id, void * data, size_t datalength, int flags ){
725 // without the address
726 return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL );
727}
728
729int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
730 if( ! fromaddr ) return EBADMEM;
731 if( ! addrlen ) return NO_DATA;
732 // with the address
733 return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen );
734}
735
736int recvfrom_core( ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
737 socket_ref socket;
738 aid_t message_id;
739 int result;
740 size_t fragments;
741 size_t * lengths;
742 size_t index;
743 ipc_call_t answer;
744
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 );
749 // find the socket
750 socket = sockets_find( socket_get_sockets(), socket_id );
751 if( ! socket ){
752 fibril_rwlock_read_unlock( & socket_globals.lock );
753 return ENOTSOCK;
754 }
755 fibril_mutex_lock( & socket->receive_lock );
756 // wait for a received packet
757 ++ socket->blocked;
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 );
762 }
763 -- socket->blocked;
764 fragments = ( size_t ) result;
765 // prepare lengths if more fragments
766 if( fragments > 1 ){
767 lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t ));
768 if( ! lengths ){
769 fibril_mutex_unlock( & socket->receive_lock );
770 fibril_rwlock_read_unlock( & socket_globals.lock );
771 return ENOMEM;
772 }
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 ];
784 }
785 }
786 }
787 }
788 free( lengths );
789 }else{
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 );
796 }
797 }
798 async_wait_for( message_id, ( ipcarg_t * ) & result );
799 // if successful
800 if( result == EOK ){
801 // dequeue the received packet
802 dyn_fifo_pop( & socket->received );
803 // return read data length
804 result = SOCKET_GET_READ_DATA_LENGTH( answer );
805 // set address length
806 if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer );
807 }
808 fibril_mutex_unlock( & socket->receive_lock );
809 fibril_rwlock_read_unlock( & socket_globals.lock );
810 return result;
811}
812
813int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){
814 socket_ref socket;
815 aid_t message_id;
816 ipcarg_t result;
817
818 if( !( value && optlen )) return EBADMEM;
819 if( !( * optlen )) return NO_DATA;
820 fibril_rwlock_read_lock( & socket_globals.lock );
821 // find the socket
822 socket = sockets_find( socket_get_sockets(), socket_id );
823 if( ! socket ){
824 fibril_rwlock_read_unlock( & socket_globals.lock );
825 return ENOTSOCK;
826 }
827 // request option value
828 message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, ( ipcarg_t ) socket->socket_id, ( ipcarg_t ) optname, socket->service, NULL );
829 // read the length
830 if( async_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){
831 // read the value
832 async_data_read_start( socket->phone, value, * optlen );
833 }
834 fibril_rwlock_read_unlock( & socket_globals.lock );
835 async_wait_for( message_id, & result );
836 return ( int ) result;
837}
838
839int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){
840 // send the value
841 return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, ( ipcarg_t ) optname, value, optlen );
842
843}
844
845/** @}
846 */
Note: See TracBrowser for help on using the repository browser.