source: mainline/uspace/lib/socket/generic/socket_client.c@ caad59a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since caad59a was caad59a, checked in by Martin Decky <martin@…>, 15 years ago

move to GCC 4.5.0
fix two cases of uninitialized variable suspicion (hopefully in a conservative and harmless way)

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