source: mainline/uspace/srv/net/socket/socket_client.c@ 936835e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 936835e was 936835e, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago

Merge mainline changes, revision 311

  • Property mode set to 100644
File size: 27.3 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 */
[aadf01e]77#define SOCKET_CONNECT_TIMEOUT (1 * 1000 * 1000)
[1a0fb3f8]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 */
[aadf01e]99 int socket_id;
[21580dd]100 /** Parent module phone.
101 */
[aadf01e]102 int phone;
[21580dd]103 /** Parent module service.
104 */
[aadf01e]105 services_t service;
[21580dd]106 /** Underlying protocol header size.
107 * Sending and receiving optimalization.
108 */
[aadf01e]109 size_t header_size;
[21580dd]110 /** Packet data fragment size.
111 * Sending optimalization.
112 */
[aadf01e]113 size_t data_fragment_size;
[21580dd]114 /** Sending safety lock.
115 * Locks the header_size and data_fragment_size attributes.
116 */
[aadf01e]117 fibril_rwlock_t sending_lock;
[21580dd]118 /** Received packets queue.
119 */
[aadf01e]120 dyn_fifo_t received;
[21580dd]121 /** Received packets safety lock.
122 * Used for receiving and receive notifications.
123 * Locks the received attribute.
124 */
[aadf01e]125 fibril_mutex_t receive_lock;
[21580dd]126 /** Received packets signaling.
127 * Signaled upon receive notification.
128 */
[aadf01e]129 fibril_condvar_t receive_signal;
[21580dd]130 /** Waiting sockets queue.
131 */
[aadf01e]132 dyn_fifo_t accepted;
[21580dd]133 /** Waiting sockets safety lock.
134 * Used for accepting and accept notifications.
135 * Locks the accepted attribute.
136 */
[aadf01e]137 fibril_mutex_t accept_lock;
[21580dd]138 /** Waiting sockets signaling.
139 * Signaled upon accept notification.
140 */
[aadf01e]141 fibril_condvar_t accept_signal;
[21580dd]142 /** The number of blocked functions called.
143 * Used while waiting for the received packets or accepted sockets.
144 */
[aadf01e]145 int blocked;
[21580dd]146};
147
148/** Sockets map.
149 * Maps socket identifiers to the socket specific data.
150 * @see int_map.h
151 */
[aadf01e]152INT_MAP_DECLARE(sockets, socket_t);
[21580dd]153
154/** Socket client library global data.
155 */
156static struct socket_client_globals {
157 /** TCP module phone.
158 */
[aadf01e]159 int tcp_phone;
[21580dd]160 /** UDP module phone.
161 */
[aadf01e]162 int udp_phone;
[ede63e4]163// /** The last socket identifier.
164// */
165// int last_id;
[21580dd]166 /** Active sockets.
167 */
[aadf01e]168 sockets_ref sockets;
[21580dd]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 */
[aadf01e]175 fibril_rwlock_t lock;
[21580dd]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 = {
[aadf01e]185 .prev = &socket_globals.lock.waiters,
186 .next = &socket_globals.lock.waiters
[21580dd]187 }
188 }
189};
190
[aadf01e]191INT_MAP_IMPLEMENT(sockets, socket_t);
[21580dd]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 */
[aadf01e]198static int socket_get_tcp_phone(void);
[21580dd]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 */
[aadf01e]205static int socket_get_udp_phone(void);
[21580dd]206
207/** Returns the active sockets.
208 * @returns The active sockets.
209 */
[aadf01e]210static sockets_ref socket_get_sockets(void);
[21580dd]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 */
[aadf01e]216static int socket_generate_new_id(void);
[ede63e4]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 */
[aadf01e]222void socket_connection(ipc_callid_t iid, ipc_call_t * icall);
[21580dd]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 */
[aadf01e]236int socket_send_data(int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength);
[21580dd]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 */
[aadf01e]244void socket_initialize(socket_ref socket, int socket_id, int phone, services_t service);
[21580dd]245
246/** Clears and destroys the socket.
247 * @param[in] socket The socket to be destroyed.
248 */
[aadf01e]249void socket_destroy(socket_ref socket);
[21580dd]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 */
[aadf01e]265int recvfrom_core(ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen);
[21580dd]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 */
[aadf01e]282int sendto_core(ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen);
[21580dd]283
[aadf01e]284static 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);
[21580dd]287 }
288 return socket_globals.tcp_phone;
289}
290
[aadf01e]291static 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);
[21580dd]294 }
295 return socket_globals.udp_phone;
296}
297
[aadf01e]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){
302 return NULL;
303 }
304 if(sockets_initialize(socket_globals.sockets) != EOK){
305 free(socket_globals.sockets);
[21580dd]306 socket_globals.sockets = NULL;
307 }
[aadf01e]308 srand(task_get_id());
[21580dd]309 }
310 return socket_globals.sockets;
311}
312
[aadf01e]313static int socket_generate_new_id(void){
314 sockets_ref sockets;
315 int socket_id;
316 int count;
[ede63e4]317
318 sockets = socket_get_sockets();
319 count = 0;
320// socket_id = socket_globals.last_id;
321 do{
[aadf01e]322 if(count < SOCKET_ID_TRIES){
[ede63e4]323 socket_id = rand() % INT_MAX;
324 ++ count;
[aadf01e]325 }else if(count == SOCKET_ID_TRIES){
[ede63e4]326 socket_id = 1;
327 ++ count;
328 // only this branch for last_id
329 }else{
[aadf01e]330 if(socket_id < INT_MAX){
[ede63e4]331 ++ socket_id;
[aadf01e]332/* }else if(socket_globals.last_id){
[ede63e4]333* socket_globals.last_id = 0;
334* socket_id = 1;
335*/ }else{
336 return ELIMIT;
337 }
338 }
[aadf01e]339 }while(sockets_find(sockets, socket_id));
[ede63e4]340// last_id = socket_id
341 return socket_id;
342}
343
[aadf01e]344void socket_initialize(socket_ref socket, int socket_id, int phone, services_t service){
[21580dd]345 socket->socket_id = socket_id;
346 socket->phone = phone;
347 socket->service = service;
[aadf01e]348 dyn_fifo_initialize(&socket->received, SOCKET_INITIAL_RECEIVED_SIZE);
349 dyn_fifo_initialize(&socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE);
350 fibril_mutex_initialize(&socket->receive_lock);
351 fibril_condvar_initialize(&socket->receive_signal);
352 fibril_mutex_initialize(&socket->accept_lock);
353 fibril_condvar_initialize(&socket->accept_signal);
354 fibril_rwlock_initialize(&socket->sending_lock);
[21580dd]355}
356
[aadf01e]357void socket_connection(ipc_callid_t iid, ipc_call_t * icall){
[21580dd]358 ERROR_DECLARE;
359
[aadf01e]360 ipc_callid_t callid;
361 ipc_call_t call;
362 socket_ref socket;
[21580dd]363
[aadf01e]364 while(true){
[21580dd]365
[aadf01e]366 callid = async_get_call(&call);
367 switch(IPC_GET_METHOD(call)){
[21580dd]368 case NET_SOCKET_RECEIVED:
369 case NET_SOCKET_ACCEPTED:
[ede63e4]370 case NET_SOCKET_DATA_FRAGMENT_SIZE:
[aadf01e]371 fibril_rwlock_read_lock(&socket_globals.lock);
[21580dd]372 // find the socket
[aadf01e]373 socket = sockets_find(socket_get_sockets(), SOCKET_GET_SOCKET_ID(call));
374 if(! socket){
[21580dd]375 ERROR_CODE = ENOTSOCK;
376 }else{
[aadf01e]377 switch(IPC_GET_METHOD(call)){
[ede63e4]378 case NET_SOCKET_RECEIVED:
[aadf01e]379 fibril_mutex_lock(&socket->receive_lock);
[ede63e4]380 // push the number of received packet fragments
[aadf01e]381 if(! ERROR_OCCURRED(dyn_fifo_push(&socket->received, SOCKET_GET_DATA_FRAGMENTS(call), SOCKET_MAX_RECEIVED_SIZE))){
[ede63e4]382 // signal the received packet
[aadf01e]383 fibril_condvar_signal(&socket->receive_signal);
[ede63e4]384 }
[aadf01e]385 fibril_mutex_unlock(&socket->receive_lock);
[ede63e4]386 break;
387 case NET_SOCKET_ACCEPTED:
[21580dd]388 // push the new socket identifier
[aadf01e]389 fibril_mutex_lock(&socket->accept_lock);
390 if(! ERROR_OCCURRED(dyn_fifo_push(&socket->accepted, 1, SOCKET_MAX_ACCEPTED_SIZE))){
[21580dd]391 // signal the accepted socket
[aadf01e]392 fibril_condvar_signal(&socket->accept_signal);
[21580dd]393 }
[aadf01e]394 fibril_mutex_unlock(&socket->accept_lock);
[ede63e4]395 break;
396 default:
397 ERROR_CODE = ENOTSUP;
398 }
[aadf01e]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);
[ede63e4]402 // set the data fragment size
[aadf01e]403 socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE(call);
404 fibril_rwlock_write_unlock(&socket->sending_lock);
[21580dd]405 }
406 }
[aadf01e]407 fibril_rwlock_read_unlock(&socket_globals.lock);
[d510c0fe]408 break;
[21580dd]409 default:
410 ERROR_CODE = ENOTSUP;
411 }
[aadf01e]412 ipc_answer_0(callid, (ipcarg_t) ERROR_CODE);
[21580dd]413 }
414}
415
[aadf01e]416int socket(int domain, int type, int protocol){
[21580dd]417 ERROR_DECLARE;
418
[aadf01e]419 socket_ref socket;
420 int phone;
421 int socket_id;
422 services_t service;
[21580dd]423
424 // find the appropriate service
[aadf01e]425 switch(domain){
[21580dd]426 case PF_INET:
[aadf01e]427 switch(type){
[21580dd]428 case SOCK_STREAM:
[aadf01e]429 if(! protocol){
430 protocol = IPPROTO_TCP;
431 }
432 switch(protocol){
[21580dd]433 case IPPROTO_TCP:
434 phone = socket_get_tcp_phone();
435 service = SERVICE_TCP;
436 break;
437 default:
438 return EPROTONOSUPPORT;
439 }
440 break;
441 case SOCK_DGRAM:
[aadf01e]442 if(! protocol){
443 protocol = IPPROTO_UDP;
444 }
445 switch(protocol){
[21580dd]446 case IPPROTO_UDP:
447 phone = socket_get_udp_phone();
448 service = SERVICE_UDP;
449 break;
450 default:
451 return EPROTONOSUPPORT;
452 }
453 break;
454 case SOCK_RAW:
455 default:
456 return ESOCKTNOSUPPORT;
457 }
458 break;
459 // TODO IPv6
460 default:
461 return EPFNOSUPPORT;
462 }
[aadf01e]463 if(phone < 0){
464 return phone;
465 }
[21580dd]466 // create a new socket structure
[aadf01e]467 socket = (socket_ref) malloc(sizeof(socket_t));
468 if(! socket){
469 return ENOMEM;
470 }
471 bzero(socket, sizeof(*socket));
472 fibril_rwlock_write_lock(&socket_globals.lock);
[21580dd]473 // request a new socket
[ede63e4]474 socket_id = socket_generate_new_id();
[aadf01e]475 if(socket_id <= 0){
476 fibril_rwlock_write_unlock(&socket_globals.lock);
477 free(socket);
[ede63e4]478 return socket_id;
479 }
[aadf01e]480 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))){
481 fibril_rwlock_write_unlock(&socket_globals.lock);
482 free(socket);
[21580dd]483 return ERROR_CODE;
484 }
485 // finish the new socket initialization
[aadf01e]486 socket_initialize(socket, socket_id, phone, service);
[21580dd]487 // store the new socket
[aadf01e]488 ERROR_CODE = sockets_add(socket_get_sockets(), socket_id, socket);
489 fibril_rwlock_write_unlock(&socket_globals.lock);
490 if(ERROR_CODE < 0){
491 dyn_fifo_destroy(&socket->received);
492 dyn_fifo_destroy(&socket->accepted);
493 free(socket);
494 async_msg_3(phone, NET_SOCKET_CLOSE, (ipcarg_t) socket_id, 0, service);
[21580dd]495 return ERROR_CODE;
496 }
497
498 return socket_id;
499}
500
[aadf01e]501int socket_send_data(int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength){
502 socket_ref socket;
503 aid_t message_id;
504 ipcarg_t result;
[21580dd]505
[aadf01e]506 if(! data){
507 return EBADMEM;
508 }
509 if(! datalength){
510 return NO_DATA;
511 }
[21580dd]512
[aadf01e]513 fibril_rwlock_read_lock(&socket_globals.lock);
[21580dd]514 // find the socket
[aadf01e]515 socket = sockets_find(socket_get_sockets(), socket_id);
516 if(! socket){
517 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]518 return ENOTSOCK;
519 }
520 // request the message
[aadf01e]521 message_id = async_send_3(socket->phone, message, (ipcarg_t) socket->socket_id, arg2, socket->service, NULL);
[21580dd]522 // send the address
[aadf01e]523 async_data_write_start(socket->phone, data, datalength);
524 fibril_rwlock_read_unlock(&socket_globals.lock);
525 async_wait_for(message_id, &result);
526 return (int) result;
[21580dd]527}
528
[aadf01e]529int bind(int socket_id, const struct sockaddr * my_addr, socklen_t addrlen){
530 if(addrlen <= 0){
531 return EINVAL;
532 }
[21580dd]533 // send the address
[aadf01e]534 return socket_send_data(socket_id, NET_SOCKET_BIND, 0, my_addr, (size_t) addrlen);
[21580dd]535}
536
[aadf01e]537int listen(int socket_id, int backlog){
538 socket_ref socket;
539 int result;
[21580dd]540
[aadf01e]541 if(backlog <= 0){
542 return EINVAL;
543 }
544 fibril_rwlock_read_lock(&socket_globals.lock);
[21580dd]545 // find the socket
[aadf01e]546 socket = sockets_find(socket_get_sockets(), socket_id);
547 if(! socket){
548 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]549 return ENOTSOCK;
550 }
551 // request listen backlog change
[aadf01e]552 result = (int) async_req_3_0(socket->phone, NET_SOCKET_LISTEN, (ipcarg_t) socket->socket_id, (ipcarg_t) backlog, socket->service);
553 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]554 return result;
555}
556
[aadf01e]557int accept(int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen){
558 socket_ref socket;
559 socket_ref new_socket;
560 aid_t message_id;
561 ipcarg_t ipc_result;
562 int result;
563 ipc_call_t answer;
[21580dd]564
[aadf01e]565 if((! cliaddr) || (! addrlen)){
566 return EBADMEM;
567 }
[21580dd]568
[aadf01e]569 fibril_rwlock_write_lock(&socket_globals.lock);
[21580dd]570 // find the socket
[aadf01e]571 socket = sockets_find(socket_get_sockets(), socket_id);
572 if(! socket){
573 fibril_rwlock_write_unlock(&socket_globals.lock);
[21580dd]574 return ENOTSOCK;
575 }
[aadf01e]576 fibril_mutex_lock(&socket->accept_lock);
[21580dd]577 // wait for an accepted socket
578 ++ socket->blocked;
[aadf01e]579 while(dyn_fifo_value(&socket->accepted) <= 0){
580 fibril_rwlock_write_unlock(&socket_globals.lock);
581 fibril_condvar_wait(&socket->accept_signal, &socket->accept_lock);
[11485d0c]582 // drop the accept lock to avoid deadlock
[936835e]583 fibril_mutex_unlock(&socket->accept_lock);
[aadf01e]584 fibril_rwlock_write_lock(&socket_globals.lock);
[936835e]585 fibril_mutex_lock(&socket->accept_lock);
[21580dd]586 }
587 -- socket->blocked;
[ede63e4]588
589 // create a new scoket
[aadf01e]590 new_socket = (socket_ref) malloc(sizeof(socket_t));
591 if(! new_socket){
592 fibril_mutex_unlock(&socket->accept_lock);
593 fibril_rwlock_write_unlock(&socket_globals.lock);
[ede63e4]594 return ENOMEM;
595 }
[aadf01e]596 bzero(new_socket, sizeof(*new_socket));
[ede63e4]597 socket_id = socket_generate_new_id();
[aadf01e]598 if(socket_id <= 0){
599 fibril_mutex_unlock(&socket->accept_lock);
600 fibril_rwlock_write_unlock(&socket_globals.lock);
601 free(new_socket);
[ede63e4]602 return socket_id;
603 }
[aadf01e]604 socket_initialize(new_socket, socket_id, socket->phone, socket->service);
605 result = sockets_add(socket_get_sockets(), new_socket->socket_id, new_socket);
606 if(result < 0){
607 fibril_mutex_unlock(&socket->accept_lock);
608 fibril_rwlock_write_unlock(&socket_globals.lock);
609 free(new_socket);
[ede63e4]610 return result;
611 }
612
[21580dd]613 // request accept
[aadf01e]614 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]615 // read address
[aadf01e]616 ipc_data_read_start(socket->phone, cliaddr, * addrlen);
617 fibril_rwlock_write_unlock(&socket_globals.lock);
618 async_wait_for(message_id, &ipc_result);
[7fb2ce3]619 result = (int) ipc_result;
[aadf01e]620 if(result > 0){
621 if(result != socket_id){
[ede63e4]622 result = EINVAL;
623 }
[21580dd]624 // dequeue the accepted socket if successful
[aadf01e]625 dyn_fifo_pop(&socket->accepted);
[21580dd]626 // set address length
[aadf01e]627 *addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
628 new_socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
629 }else if(result == ENOTSOCK){
[21580dd]630 // empty the queue if no accepted sockets
[aadf01e]631 while(dyn_fifo_pop(&socket->accepted) > 0);
[21580dd]632 }
[aadf01e]633 fibril_mutex_unlock(&socket->accept_lock);
[21580dd]634 return result;
635}
636
[aadf01e]637int connect(int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen){
638 if(! serv_addr){
639 return EDESTADDRREQ;
640 }
641 if(! addrlen){
642 return EDESTADDRREQ;
643 }
[21580dd]644 // send the address
[aadf01e]645 return socket_send_data(socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen);
[21580dd]646}
647
[aadf01e]648int closesocket(int socket_id){
[21580dd]649 ERROR_DECLARE;
650
[aadf01e]651 socket_ref socket;
[21580dd]652
[aadf01e]653 fibril_rwlock_write_lock(&socket_globals.lock);
654 socket = sockets_find(socket_get_sockets(), socket_id);
655 if(! socket){
656 fibril_rwlock_write_unlock(&socket_globals.lock);
[21580dd]657 return ENOTSOCK;
658 }
[aadf01e]659 if(socket->blocked){
660 fibril_rwlock_write_unlock(&socket_globals.lock);
[21580dd]661 return EINPROGRESS;
662 }
663 // request close
[aadf01e]664 ERROR_PROPAGATE((int) async_req_3_0(socket->phone, NET_SOCKET_CLOSE, (ipcarg_t) socket->socket_id, 0, socket->service));
[21580dd]665 // free the socket structure
[aadf01e]666 socket_destroy(socket);
667 fibril_rwlock_write_unlock(&socket_globals.lock);
[21580dd]668 return EOK;
669}
670
[aadf01e]671void socket_destroy(socket_ref socket){
672 int accepted_id;
[21580dd]673
674 // destroy all accepted sockets
[aadf01e]675 while((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0){
676 socket_destroy(sockets_find(socket_get_sockets(), accepted_id));
[21580dd]677 }
[aadf01e]678 dyn_fifo_destroy(&socket->received);
679 dyn_fifo_destroy(&socket->accepted);
680 sockets_exclude(socket_get_sockets(), socket->socket_id);
[21580dd]681}
682
[aadf01e]683int send(int socket_id, void * data, size_t datalength, int flags){
[21580dd]684 // without the address
[aadf01e]685 return sendto_core(NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0);
[21580dd]686}
687
[aadf01e]688int sendto(int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen){
689 if(! toaddr){
690 return EDESTADDRREQ;
691 }
692 if(! addrlen){
693 return EDESTADDRREQ;
694 }
[21580dd]695 // with the address
[aadf01e]696 return sendto_core(NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen);
[21580dd]697}
698
[aadf01e]699int sendto_core(ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen){
700 socket_ref socket;
701 aid_t message_id;
702 ipcarg_t result;
703 size_t fragments;
704 ipc_call_t answer;
[21580dd]705
[aadf01e]706 if(! data){
707 return EBADMEM;
708 }
709 if(! datalength){
710 return NO_DATA;
711 }
712 fibril_rwlock_read_lock(&socket_globals.lock);
[21580dd]713 // find socket
[aadf01e]714 socket = sockets_find(socket_get_sockets(), socket_id);
715 if(! socket){
716 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]717 return ENOTSOCK;
718 }
[aadf01e]719 fibril_rwlock_read_lock(&socket->sending_lock);
[21580dd]720 // compute data fragment count
[aadf01e]721 if(socket->data_fragment_size > 0){
722 fragments = (datalength + socket->header_size) / socket->data_fragment_size;
723 if((datalength + socket->header_size) % socket->data_fragment_size) ++ fragments;
[ede63e4]724 }else{
725 fragments = 1;
726 }
[21580dd]727 // request send
[aadf01e]728 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]729 // send the address if given
[aadf01e]730 if((! toaddr) || (async_data_write_start(socket->phone, toaddr, addrlen) == EOK)){
731 if(fragments == 1){
[21580dd]732 // send all if only one fragment
[aadf01e]733 async_data_write_start(socket->phone, data, datalength);
[21580dd]734 }else{
735 // send the first fragment
[aadf01e]736 async_data_write_start(socket->phone, data, socket->data_fragment_size - socket->header_size);
737 data = ((const uint8_t *) data) + socket->data_fragment_size - socket->header_size;
[21580dd]738 // send the middle fragments
[aadf01e]739 while((-- fragments) > 1){
740 async_data_write_start(socket->phone, data, socket->data_fragment_size);
741 data = ((const uint8_t *) data) + socket->data_fragment_size;
[21580dd]742 }
743 // send the last fragment
[aadf01e]744 async_data_write_start(socket->phone, data, (datalength + socket->header_size) % socket->data_fragment_size);
[21580dd]745 }
746 }
[aadf01e]747 async_wait_for(message_id, &result);
748 if((SOCKET_GET_DATA_FRAGMENT_SIZE(answer) > 0)
749 && (SOCKET_GET_DATA_FRAGMENT_SIZE(answer) != socket->data_fragment_size)){
[ede63e4]750 // set the data fragment size
[aadf01e]751 socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
[ede63e4]752 }
[aadf01e]753 fibril_rwlock_read_unlock(&socket->sending_lock);
754 fibril_rwlock_read_unlock(&socket_globals.lock);
755 return (int) result;
[21580dd]756}
757
[aadf01e]758int recv(int socket_id, void * data, size_t datalength, int flags){
[21580dd]759 // without the address
[aadf01e]760 return recvfrom_core(NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL);
[21580dd]761}
762
[aadf01e]763int recvfrom(int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen){
764 if(! fromaddr){
765 return EBADMEM;
766 }
767 if(! addrlen){
768 return NO_DATA;
769 }
[21580dd]770 // with the address
[aadf01e]771 return recvfrom_core(NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen);
[21580dd]772}
773
[aadf01e]774int recvfrom_core(ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen){
775 socket_ref socket;
776 aid_t message_id;
777 ipcarg_t ipc_result;
778 int result;
779 size_t fragments;
780 size_t * lengths;
781 size_t index;
782 ipc_call_t answer;
783
784 if(! data){
785 return EBADMEM;
786 }
787 if(! datalength){
788 return NO_DATA;
789 }
790 if(fromaddr && (! addrlen)){
791 return EINVAL;
792 }
793 fibril_rwlock_read_lock(&socket_globals.lock);
[21580dd]794 // find the socket
[aadf01e]795 socket = sockets_find(socket_get_sockets(), socket_id);
796 if(! socket){
797 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]798 return ENOTSOCK;
799 }
[aadf01e]800 fibril_mutex_lock(&socket->receive_lock);
[21580dd]801 // wait for a received packet
802 ++ socket->blocked;
[aadf01e]803 while((result = dyn_fifo_value(&socket->received)) <= 0){
804 fibril_rwlock_read_unlock(&socket_globals.lock);
805 fibril_condvar_wait(&socket->receive_signal, &socket->receive_lock);
[8ab2074]806 // drop the receive lock to avoid deadlock
[936835e]807 fibril_mutex_unlock(&socket->receive_lock);
[aadf01e]808 fibril_rwlock_read_lock(&socket_globals.lock);
[936835e]809 fibril_mutex_lock(&socket->receive_lock);
[21580dd]810 }
811 -- socket->blocked;
[aadf01e]812 fragments = (size_t) result;
[21580dd]813 // prepare lengths if more fragments
[aadf01e]814 if(fragments > 1){
815 lengths = (size_t *) malloc(sizeof(size_t) * fragments + sizeof(size_t));
816 if(! lengths){
817 fibril_mutex_unlock(&socket->receive_lock);
818 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]819 return ENOMEM;
820 }
821 // request packet data
[aadf01e]822 message_id = async_send_4(socket->phone, message, (ipcarg_t) socket->socket_id, 0, socket->service, (ipcarg_t) flags, &answer);
[21580dd]823 // read the address if desired
[aadf01e]824 if((! fromaddr) || (async_data_read_start(socket->phone, fromaddr, * addrlen) == EOK)){
[21580dd]825 // read the fragment lengths
[aadf01e]826 if(async_data_read_start(socket->phone, lengths, sizeof(int) * (fragments + 1)) == EOK){
827 if(lengths[fragments] <= datalength){
[21580dd]828 // read all fragments if long enough
[aadf01e]829 for(index = 0; index < fragments; ++ index){
830 async_data_read_start(socket->phone, data, lengths[index]);
831 data = ((uint8_t *) data) + lengths[index];
[21580dd]832 }
833 }
834 }
835 }
[aadf01e]836 free(lengths);
[21580dd]837 }else{
838 // request packet data
[aadf01e]839 message_id = async_send_4(socket->phone, message, (ipcarg_t) socket->socket_id, 0, socket->service, (ipcarg_t) flags, &answer);
[21580dd]840 // read the address if desired
[aadf01e]841 if((! fromaddr) || (async_data_read_start(socket->phone, fromaddr, * addrlen) == EOK)){
[21580dd]842 // read all if only one fragment
[aadf01e]843 async_data_read_start(socket->phone, data, datalength);
[21580dd]844 }
845 }
[aadf01e]846 async_wait_for(message_id, &ipc_result);
[7fb2ce3]847 result = (int) ipc_result;
[21580dd]848 // if successful
[aadf01e]849 if(result == EOK){
[21580dd]850 // dequeue the received packet
[aadf01e]851 dyn_fifo_pop(&socket->received);
[21580dd]852 // return read data length
[aadf01e]853 result = SOCKET_GET_READ_DATA_LENGTH(answer);
[21580dd]854 // set address length
[aadf01e]855 if(fromaddr && addrlen){
856 *addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
857 }
[21580dd]858 }
[aadf01e]859 fibril_mutex_unlock(&socket->receive_lock);
860 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]861 return result;
862}
863
[aadf01e]864int getsockopt(int socket_id, int level, int optname, void * value, size_t * optlen){
865 socket_ref socket;
866 aid_t message_id;
867 ipcarg_t result;
[21580dd]868
[aadf01e]869 if(!(value && optlen)){
870 return EBADMEM;
871 }
872 if(!(*optlen)){
873 return NO_DATA;
874 }
875 fibril_rwlock_read_lock(&socket_globals.lock);
[21580dd]876 // find the socket
[aadf01e]877 socket = sockets_find(socket_get_sockets(), socket_id);
878 if(! socket){
879 fibril_rwlock_read_unlock(&socket_globals.lock);
[21580dd]880 return ENOTSOCK;
881 }
882 // request option value
[aadf01e]883 message_id = async_send_3(socket->phone, NET_SOCKET_GETSOCKOPT, (ipcarg_t) socket->socket_id, (ipcarg_t) optname, socket->service, NULL);
[21580dd]884 // read the length
[aadf01e]885 if(async_data_read_start(socket->phone, optlen, sizeof(*optlen)) == EOK){
[21580dd]886 // read the value
[aadf01e]887 async_data_read_start(socket->phone, value, * optlen);
[21580dd]888 }
[aadf01e]889 fibril_rwlock_read_unlock(&socket_globals.lock);
890 async_wait_for(message_id, &result);
891 return (int) result;
[21580dd]892}
893
[aadf01e]894int setsockopt(int socket_id, int level, int optname, const void * value, size_t optlen){
[21580dd]895 // send the value
[aadf01e]896 return socket_send_data(socket_id, NET_SOCKET_SETSOCKOPT, (ipcarg_t) optname, value, optlen);
[21580dd]897
898}
899
900/** @}
901 */
Note: See TracBrowser for help on using the repository browser.