source: mainline/uspace/lib/c/generic/net/socket_client.c@ 77ad86c

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

cstyle (no change in functionality)

  • Property mode set to 100644
File size: 33.7 KB
RevLine 
[d9e2e0e]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
[db6c332]29/** @addtogroup libc
[d9e2e0e]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>
42#include <stdint.h>
43#include <stdlib.h>
44#include <errno.h>
[64d2b10]45#include <task.h>
[b1bd89ea]46#include <ns.h>
[d9e2e0e]47#include <ipc/services.h>
48#include <ipc/socket.h>
49#include <net/in.h>
50#include <net/socket.h>
51#include <adt/dynamic_fifo.h>
52#include <adt/int_map.h>
53
54/** Initial received packet queue size. */
55#define SOCKET_INITIAL_RECEIVED_SIZE 4
56
57/** Maximum received packet queue size. */
58#define SOCKET_MAX_RECEIVED_SIZE 0
59
60/** Initial waiting sockets queue size. */
61#define SOCKET_INITIAL_ACCEPTED_SIZE 1
62
63/** Maximum waiting sockets queue size. */
64#define SOCKET_MAX_ACCEPTED_SIZE 0
65
66/**
67 * Maximum number of random attempts to find a new socket identifier before
68 * switching to the sequence.
69 */
70#define SOCKET_ID_TRIES 100
71
72/** Type definition of the socket specific data.
73 * @see socket
74 */
75typedef struct socket socket_t;
76
77/** Socket specific data.
78 *
79 * Each socket lock locks only its structure part and any number of them may be
80 * locked simultaneously.
81 */
82struct socket {
83 /** Socket identifier. */
84 int socket_id;
[6b82009]85 /** Parent module session. */
86 async_sess_t *sess;
[d9e2e0e]87 /** Parent module service. */
88 services_t service;
89
90 /**
91 * Underlying protocol header size.
92 * Sending and receiving optimalization.
93 */
94 size_t header_size;
95
96 /** Packet data fragment size. Sending optimization. */
97 size_t data_fragment_size;
98
99 /**
100 * Sending safety lock.
101 * Locks the header_size and data_fragment_size attributes.
102 */
103 fibril_rwlock_t sending_lock;
104
105 /** Received packets queue. */
106 dyn_fifo_t received;
107
108 /**
109 * Received packets safety lock.
110 * Used for receiving and receive notifications.
111 * Locks the received attribute.
112 */
113 fibril_mutex_t receive_lock;
114
115 /** Received packets signaling. Signaled upon receive notification. */
116 fibril_condvar_t receive_signal;
117 /** Waiting sockets queue. */
118 dyn_fifo_t accepted;
119
120 /**
121 * Waiting sockets safety lock.
122 * Used for accepting and accept notifications.
123 * Locks the accepted attribute.
124 */
125 fibril_mutex_t accept_lock;
126
127 /** Waiting sockets signaling. Signaled upon accept notification. */
128 fibril_condvar_t accept_signal;
129
130 /**
131 * The number of blocked functions called.
132 * Used while waiting for the received packets or accepted sockets.
133 */
134 int blocked;
135};
136
137/** Sockets map.
138 * Maps socket identifiers to the socket specific data.
139 * @see int_map.h
140 */
141INT_MAP_DECLARE(sockets, socket_t);
142
143/** Socket client library global data. */
144static struct socket_client_globals {
[6b82009]145 /** TCP module session. */
146 async_sess_t *tcp_sess;
147 /** UDP module session. */
148 async_sess_t *udp_sess;
[d9e2e0e]149
150 /** Active sockets. */
[aaa3f33a]151 sockets_t *sockets;
[d9e2e0e]152
153 /** Safety lock.
154 * Write lock is used only for adding or removing sockets.
155 * When locked for writing, no other socket locks need to be locked.
156 * When locked for reading, any other socket locks may be locked.
157 * No socket lock may be locked if this lock is unlocked.
158 */
159 fibril_rwlock_t lock;
160} socket_globals = {
[6b82009]161 .tcp_sess = NULL,
162 .udp_sess = NULL,
[d9e2e0e]163 .sockets = NULL,
[e721462]164 .lock = FIBRIL_RWLOCK_INITIALIZER(socket_globals.lock)
[d9e2e0e]165};
166
167INT_MAP_IMPLEMENT(sockets, socket_t);
168
169/** Returns the active sockets.
170 *
[1bfd3d3]171 * @return The active sockets.
[d9e2e0e]172 */
[aaa3f33a]173static sockets_t *socket_get_sockets(void)
[d9e2e0e]174{
175 if (!socket_globals.sockets) {
176 socket_globals.sockets =
[aaa3f33a]177 (sockets_t *) malloc(sizeof(sockets_t));
[d9e2e0e]178 if (!socket_globals.sockets)
179 return NULL;
180
181 if (sockets_initialize(socket_globals.sockets) != EOK) {
182 free(socket_globals.sockets);
183 socket_globals.sockets = NULL;
184 }
185
186 srand(task_get_id());
187 }
188
189 return socket_globals.sockets;
190}
191
192/** Default thread for new connections.
193 *
194 * @param[in] iid The initial message identifier.
195 * @param[in] icall The initial message call structure.
[9934f7d]196 * @param[in] arg Local argument.
[d9e2e0e]197 */
[9934f7d]198static void socket_connection(ipc_callid_t iid, ipc_call_t * icall, void *arg)
[d9e2e0e]199{
200 ipc_callid_t callid;
201 ipc_call_t call;
[88a1bb9]202 socket_t *socket;
[16ac756]203 int rc;
[d9e2e0e]204
205loop:
206 callid = async_get_call(&call);
207
[228e490]208 switch (IPC_GET_IMETHOD(call)) {
[d9e2e0e]209 case NET_SOCKET_RECEIVED:
210 case NET_SOCKET_ACCEPTED:
211 case NET_SOCKET_DATA_FRAGMENT_SIZE:
212 fibril_rwlock_read_lock(&socket_globals.lock);
213
[45bb1d2]214 /* Find the socket */
[d9e2e0e]215 socket = sockets_find(socket_get_sockets(),
216 SOCKET_GET_SOCKET_ID(call));
217 if (!socket) {
[16ac756]218 rc = ENOTSOCK;
[d9e2e0e]219 fibril_rwlock_read_unlock(&socket_globals.lock);
220 break;
221 }
222
[228e490]223 switch (IPC_GET_IMETHOD(call)) {
[d9e2e0e]224 case NET_SOCKET_RECEIVED:
225 fibril_mutex_lock(&socket->receive_lock);
[45bb1d2]226 /* Push the number of received packet fragments */
[16ac756]227 rc = dyn_fifo_push(&socket->received,
[d9e2e0e]228 SOCKET_GET_DATA_FRAGMENTS(call),
[16ac756]229 SOCKET_MAX_RECEIVED_SIZE);
230 if (rc == EOK) {
[45bb1d2]231 /* Signal the received packet */
[d9e2e0e]232 fibril_condvar_signal(&socket->receive_signal);
233 }
234 fibril_mutex_unlock(&socket->receive_lock);
235 break;
236
237 case NET_SOCKET_ACCEPTED:
[45bb1d2]238 /* Push the new socket identifier */
[d9e2e0e]239 fibril_mutex_lock(&socket->accept_lock);
[16ac756]240 rc = dyn_fifo_push(&socket->accepted, 1,
241 SOCKET_MAX_ACCEPTED_SIZE);
[b4c9c61]242 if (rc == EOK) {
[45bb1d2]243 /* Signal the accepted socket */
[d9e2e0e]244 fibril_condvar_signal(&socket->accept_signal);
245 }
246 fibril_mutex_unlock(&socket->accept_lock);
247 break;
248
249 default:
[16ac756]250 rc = ENOTSUP;
[d9e2e0e]251 }
252
253 if ((SOCKET_GET_DATA_FRAGMENT_SIZE(call) > 0) &&
254 (SOCKET_GET_DATA_FRAGMENT_SIZE(call) !=
255 socket->data_fragment_size)) {
256 fibril_rwlock_write_lock(&socket->sending_lock);
257
[45bb1d2]258 /* Set the data fragment size */
[d9e2e0e]259 socket->data_fragment_size =
260 SOCKET_GET_DATA_FRAGMENT_SIZE(call);
261
262 fibril_rwlock_write_unlock(&socket->sending_lock);
263 }
264
265 fibril_rwlock_read_unlock(&socket_globals.lock);
266 break;
267
268 default:
[16ac756]269 rc = ENOTSUP;
[d9e2e0e]270 }
271
[64d2b10]272 async_answer_0(callid, (sysarg_t) rc);
[d9e2e0e]273 goto loop;
274}
275
[6b82009]276/** Return the TCP module session.
[d9e2e0e]277 *
[6b82009]278 * Connect to the TCP module if necessary.
279 *
280 * @return The TCP module session.
[d9e2e0e]281 *
282 */
[6b82009]283static async_sess_t *socket_get_tcp_sess(void)
[d9e2e0e]284{
[77ad86c]285 if (socket_globals.tcp_sess == NULL)
[b1bd89ea]286 socket_globals.tcp_sess = service_bind(SERVICE_TCP,
[bf172825]287 0, 0, SERVICE_TCP, socket_connection);
[77ad86c]288
[6b82009]289 return socket_globals.tcp_sess;
[d9e2e0e]290}
291
[6b82009]292/** Return the UDP module session.
[d9e2e0e]293 *
[6b82009]294 * Connect to the UDP module if necessary.
295 *
296 * @return The UDP module session.
[d9e2e0e]297 *
298 */
[6b82009]299static async_sess_t *socket_get_udp_sess(void)
[d9e2e0e]300{
[77ad86c]301 if (socket_globals.udp_sess == NULL)
[b1bd89ea]302 socket_globals.udp_sess = service_bind(SERVICE_UDP,
[bf172825]303 0, 0, SERVICE_UDP, socket_connection);
[77ad86c]304
[6b82009]305 return socket_globals.udp_sess;
[d9e2e0e]306}
307
308/** Tries to find a new free socket identifier.
309 *
[1bfd3d3]310 * @return The new socket identifier.
311 * @return ELIMIT if there is no socket identifier available.
[d9e2e0e]312 */
313static int socket_generate_new_id(void)
314{
[aaa3f33a]315 sockets_t *sockets;
[d9e2e0e]316 int socket_id = 0;
317 int count;
318
319 sockets = socket_get_sockets();
320 count = 0;
321
322 do {
323 if (count < SOCKET_ID_TRIES) {
324 socket_id = rand() % INT_MAX;
325 ++count;
326 } else if (count == SOCKET_ID_TRIES) {
327 socket_id = 1;
328 ++count;
[45bb1d2]329 /* Only this branch for last_id */
[d9e2e0e]330 } else {
331 if (socket_id < INT_MAX) {
332 ++socket_id;
[6b82009]333 } else {
[d9e2e0e]334 return ELIMIT;
335 }
336 }
337 } while (sockets_find(sockets, socket_id));
[6b82009]338
[d9e2e0e]339 return socket_id;
340}
341
342/** Initializes a new socket specific data.
343 *
344 * @param[in,out] socket The socket to be initialized.
[6b82009]345 * @param[in] socket_id The new socket identifier.
346 * @param[in] sess The parent module session.
347 * @param[in] service The parent module service.
[d9e2e0e]348 */
[6b82009]349static void socket_initialize(socket_t *socket, int socket_id,
350 async_sess_t *sess, services_t service)
[d9e2e0e]351{
352 socket->socket_id = socket_id;
[6b82009]353 socket->sess = sess;
[d9e2e0e]354 socket->service = service;
355 dyn_fifo_initialize(&socket->received, SOCKET_INITIAL_RECEIVED_SIZE);
356 dyn_fifo_initialize(&socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE);
357 fibril_mutex_initialize(&socket->receive_lock);
358 fibril_condvar_initialize(&socket->receive_signal);
359 fibril_mutex_initialize(&socket->accept_lock);
360 fibril_condvar_initialize(&socket->accept_signal);
361 fibril_rwlock_initialize(&socket->sending_lock);
362}
363
364/** Creates a new socket.
365 *
366 * @param[in] domain The socket protocol family.
367 * @param[in] type Socket type.
368 * @param[in] protocol Socket protocol.
[1bfd3d3]369 * @return The socket identifier on success.
370 * @return EPFNOTSUPPORT if the protocol family is not supported.
371 * @return ESOCKNOTSUPPORT if the socket type is not supported.
372 * @return EPROTONOSUPPORT if the protocol is not supported.
373 * @return ENOMEM if there is not enough memory left.
374 * @return ELIMIT if there was not a free socket identifier found
[d9e2e0e]375 * this time.
[1bfd3d3]376 * @return Other error codes as defined for the NET_SOCKET message.
377 * @return Other error codes as defined for the
[b1bd89ea]378 * service_bind() function.
[d9e2e0e]379 */
380int socket(int domain, int type, int protocol)
381{
[88a1bb9]382 socket_t *socket;
[6b82009]383 async_sess_t *sess;
[d9e2e0e]384 int socket_id;
385 services_t service;
[96b02eb9]386 sysarg_t fragment_size;
387 sysarg_t header_size;
[16ac756]388 int rc;
[d9e2e0e]389
[45bb1d2]390 /* Find the appropriate service */
[d9e2e0e]391 switch (domain) {
392 case PF_INET:
393 switch (type) {
394 case SOCK_STREAM:
395 if (!protocol)
396 protocol = IPPROTO_TCP;
397
398 switch (protocol) {
399 case IPPROTO_TCP:
[6b82009]400 sess = socket_get_tcp_sess();
[d9e2e0e]401 service = SERVICE_TCP;
402 break;
403 default:
404 return EPROTONOSUPPORT;
405 }
406
407 break;
408
409 case SOCK_DGRAM:
410 if (!protocol)
411 protocol = IPPROTO_UDP;
412
413 switch (protocol) {
414 case IPPROTO_UDP:
[6b82009]415 sess = socket_get_udp_sess();
[d9e2e0e]416 service = SERVICE_UDP;
417 break;
418 default:
419 return EPROTONOSUPPORT;
420 }
421
422 break;
423
424 case SOCK_RAW:
425 default:
426 return ESOCKTNOSUPPORT;
427 }
428
429 break;
430
431 case PF_INET6:
432 default:
433 return EPFNOSUPPORT;
434 }
435
[6b82009]436 if (sess == NULL)
437 return ENOENT;
[d9e2e0e]438
[45bb1d2]439 /* Create a new socket structure */
[88a1bb9]440 socket = (socket_t *) malloc(sizeof(socket_t));
[d9e2e0e]441 if (!socket)
442 return ENOMEM;
443
444 bzero(socket, sizeof(*socket));
445 fibril_rwlock_write_lock(&socket_globals.lock);
446
[45bb1d2]447 /* Request a new socket */
[d9e2e0e]448 socket_id = socket_generate_new_id();
449 if (socket_id <= 0) {
450 fibril_rwlock_write_unlock(&socket_globals.lock);
451 free(socket);
452 return socket_id;
453 }
[6b82009]454
455 async_exch_t *exch = async_exchange_begin(sess);
456 rc = (int) async_req_3_3(exch, NET_SOCKET, socket_id, 0, service, NULL,
[16ac756]457 &fragment_size, &header_size);
[6b82009]458 async_exchange_end(exch);
459
[16ac756]460 if (rc != EOK) {
[d9e2e0e]461 fibril_rwlock_write_unlock(&socket_globals.lock);
462 free(socket);
[16ac756]463 return rc;
[d9e2e0e]464 }
465
466 socket->data_fragment_size = (size_t) fragment_size;
467 socket->header_size = (size_t) header_size;
468
[45bb1d2]469 /* Finish the new socket initialization */
[6b82009]470 socket_initialize(socket, socket_id, sess, service);
[45bb1d2]471 /* Store the new socket */
[16ac756]472 rc = sockets_add(socket_get_sockets(), socket_id, socket);
[d9e2e0e]473
474 fibril_rwlock_write_unlock(&socket_globals.lock);
[16ac756]475 if (rc < 0) {
[d9e2e0e]476 dyn_fifo_destroy(&socket->received);
477 dyn_fifo_destroy(&socket->accepted);
478 free(socket);
[6b82009]479
480 exch = async_exchange_begin(sess);
481 async_msg_3(exch, NET_SOCKET_CLOSE, (sysarg_t) socket_id, 0,
[d9e2e0e]482 service);
[6b82009]483 async_exchange_end(exch);
484
[16ac756]485 return rc;
[d9e2e0e]486 }
487
488 return socket_id;
489}
490
491/** Sends message to the socket parent module with specified data.
492 *
[db6c332]493 * @param[in] socket_id Socket identifier.
494 * @param[in] message The action message.
495 * @param[in] arg2 The second message parameter.
496 * @param[in] data The data to be sent.
497 * @param[in] datalength The data length.
[1bfd3d3]498 * @return EOK on success.
499 * @return ENOTSOCK if the socket is not found.
500 * @return EBADMEM if the data parameter is NULL.
501 * @return NO_DATA if the datalength parameter is zero (0).
502 * @return Other error codes as defined for the spcific message.
[d9e2e0e]503 */
504static int
[96b02eb9]505socket_send_data(int socket_id, sysarg_t message, sysarg_t arg2,
[d9e2e0e]506 const void *data, size_t datalength)
507{
[88a1bb9]508 socket_t *socket;
[d9e2e0e]509 aid_t message_id;
[96b02eb9]510 sysarg_t result;
[d9e2e0e]511
512 if (!data)
513 return EBADMEM;
514
515 if (!datalength)
516 return NO_DATA;
517
518 fibril_rwlock_read_lock(&socket_globals.lock);
519
[45bb1d2]520 /* Find the socket */
[d9e2e0e]521 socket = sockets_find(socket_get_sockets(), socket_id);
522 if (!socket) {
523 fibril_rwlock_read_unlock(&socket_globals.lock);
524 return ENOTSOCK;
525 }
526
[45bb1d2]527 /* Request the message */
[6b82009]528 async_exch_t *exch = async_exchange_begin(socket->sess);
529 message_id = async_send_3(exch, message,
[96b02eb9]530 (sysarg_t) socket->socket_id, arg2, socket->service, NULL);
[45bb1d2]531 /* Send the address */
[6b82009]532 async_data_write_start(exch, data, datalength);
533 async_exchange_end(exch);
[d9e2e0e]534
535 fibril_rwlock_read_unlock(&socket_globals.lock);
536 async_wait_for(message_id, &result);
537 return (int) result;
538}
539
540/** Binds the socket to a port address.
541 *
542 * @param[in] socket_id Socket identifier.
543 * @param[in] my_addr The port address.
544 * @param[in] addrlen The address length.
[1bfd3d3]545 * @return EOK on success.
546 * @return ENOTSOCK if the socket is not found.
547 * @return EBADMEM if the my_addr parameter is NULL.
548 * @return NO_DATA if the addlen parameter is zero.
549 * @return Other error codes as defined for the NET_SOCKET_BIND
[d9e2e0e]550 * message.
551 */
552int bind(int socket_id, const struct sockaddr * my_addr, socklen_t addrlen)
553{
554 if (addrlen <= 0)
555 return EINVAL;
556
[45bb1d2]557 /* Send the address */
[d9e2e0e]558 return socket_send_data(socket_id, NET_SOCKET_BIND, 0, my_addr,
559 (size_t) addrlen);
560}
561
562/** Sets the number of connections waiting to be accepted.
563 *
564 * @param[in] socket_id Socket identifier.
565 * @param[in] backlog The maximum number of waiting sockets to be accepted.
[1bfd3d3]566 * @return EOK on success.
567 * @return EINVAL if the backlog parameter is not positive (<=0).
568 * @return ENOTSOCK if the socket is not found.
569 * @return Other error codes as defined for the NET_SOCKET_LISTEN
[d9e2e0e]570 * message.
571 */
572int listen(int socket_id, int backlog)
573{
[88a1bb9]574 socket_t *socket;
[d9e2e0e]575 int result;
576
577 if (backlog <= 0)
578 return EINVAL;
579
580 fibril_rwlock_read_lock(&socket_globals.lock);
581
[45bb1d2]582 /* Find the socket */
[d9e2e0e]583 socket = sockets_find(socket_get_sockets(), socket_id);
584 if (!socket) {
585 fibril_rwlock_read_unlock(&socket_globals.lock);
586 return ENOTSOCK;
587 }
588
[45bb1d2]589 /* Request listen backlog change */
[6b82009]590 async_exch_t *exch = async_exchange_begin(socket->sess);
591 result = (int) async_req_3_0(exch, NET_SOCKET_LISTEN,
[96b02eb9]592 (sysarg_t) socket->socket_id, (sysarg_t) backlog, socket->service);
[6b82009]593 async_exchange_end(exch);
[d9e2e0e]594
595 fibril_rwlock_read_unlock(&socket_globals.lock);
596 return result;
597}
598
599/** Accepts waiting socket.
600 *
601 * Blocks until such a socket exists.
602 *
603 * @param[in] socket_id Socket identifier.
604 * @param[out] cliaddr The remote client address.
605 * @param[in] addrlen The address length.
[1bfd3d3]606 * @return EOK on success.
607 * @return EBADMEM if the cliaddr or addrlen parameter is NULL.
608 * @return EINVAL if the backlog parameter is not positive (<=0).
609 * @return ENOTSOCK if the socket is not found.
610 * @return Other error codes as defined for the NET_SOCKET_ACCEPT
[d9e2e0e]611 * message.
612 */
613int accept(int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen)
614{
[88a1bb9]615 socket_t *socket;
616 socket_t *new_socket;
[d9e2e0e]617 aid_t message_id;
[96b02eb9]618 sysarg_t ipc_result;
[d9e2e0e]619 int result;
620 ipc_call_t answer;
621
622 if (!cliaddr || !addrlen)
623 return EBADMEM;
624
625 fibril_rwlock_write_lock(&socket_globals.lock);
626
[45bb1d2]627 /* Find the socket */
[d9e2e0e]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
634 fibril_mutex_lock(&socket->accept_lock);
635
[45bb1d2]636 /* Wait for an accepted socket */
[d9e2e0e]637 ++ socket->blocked;
638 while (dyn_fifo_value(&socket->accepted) <= 0) {
639 fibril_rwlock_write_unlock(&socket_globals.lock);
640 fibril_condvar_wait(&socket->accept_signal, &socket->accept_lock);
[45bb1d2]641 /* Drop the accept lock to avoid deadlock */
[d9e2e0e]642 fibril_mutex_unlock(&socket->accept_lock);
643 fibril_rwlock_write_lock(&socket_globals.lock);
644 fibril_mutex_lock(&socket->accept_lock);
645 }
646 -- socket->blocked;
647
[45bb1d2]648 /* Create a new socket */
[88a1bb9]649 new_socket = (socket_t *) malloc(sizeof(socket_t));
[d9e2e0e]650 if (!new_socket) {
651 fibril_mutex_unlock(&socket->accept_lock);
652 fibril_rwlock_write_unlock(&socket_globals.lock);
653 return ENOMEM;
654 }
655 bzero(new_socket, sizeof(*new_socket));
656 socket_id = socket_generate_new_id();
657 if (socket_id <= 0) {
658 fibril_mutex_unlock(&socket->accept_lock);
659 fibril_rwlock_write_unlock(&socket_globals.lock);
660 free(new_socket);
661 return socket_id;
662 }
[6b82009]663 socket_initialize(new_socket, socket_id, socket->sess,
[d9e2e0e]664 socket->service);
665 result = sockets_add(socket_get_sockets(), new_socket->socket_id,
666 new_socket);
667 if (result < 0) {
668 fibril_mutex_unlock(&socket->accept_lock);
669 fibril_rwlock_write_unlock(&socket_globals.lock);
670 free(new_socket);
671 return result;
672 }
673
[45bb1d2]674 /* Request accept */
[6b82009]675 async_exch_t *exch = async_exchange_begin(socket->sess);
676 message_id = async_send_5(exch, NET_SOCKET_ACCEPT,
[96b02eb9]677 (sysarg_t) socket->socket_id, 0, socket->service, 0,
[d9e2e0e]678 new_socket->socket_id, &answer);
679
[45bb1d2]680 /* Read address */
[6b82009]681 async_data_read_start(exch, cliaddr, *addrlen);
682 async_exchange_end(exch);
683
[d9e2e0e]684 fibril_rwlock_write_unlock(&socket_globals.lock);
685 async_wait_for(message_id, &ipc_result);
686 result = (int) ipc_result;
687 if (result > 0) {
688 if (result != socket_id)
689 result = EINVAL;
690
[45bb1d2]691 /* Dequeue the accepted socket if successful */
[d9e2e0e]692 dyn_fifo_pop(&socket->accepted);
[45bb1d2]693 /* Set address length */
[d9e2e0e]694 *addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
695 new_socket->data_fragment_size =
696 SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
697 } else if (result == ENOTSOCK) {
[45bb1d2]698 /* Empty the queue if no accepted sockets */
[d9e2e0e]699 while (dyn_fifo_pop(&socket->accepted) > 0)
700 ;
701 }
702
703 fibril_mutex_unlock(&socket->accept_lock);
704 return result;
705}
706
707/** Connects socket to the remote server.
708 *
709 * @param[in] socket_id Socket identifier.
710 * @param[in] serv_addr The remote server address.
711 * @param[in] addrlen The address length.
[1bfd3d3]712 * @return EOK on success.
713 * @return EBADMEM if the serv_addr parameter is NULL.
714 * @return NO_DATA if the addlen parameter is zero.
715 * @return ENOTSOCK if the socket is not found.
716 * @return Other error codes as defined for the NET_SOCKET_CONNECT
[d9e2e0e]717 * message.
718 */
719int connect(int socket_id, const struct sockaddr *serv_addr, socklen_t addrlen)
720{
721 if (!serv_addr)
722 return EDESTADDRREQ;
723
724 if (!addrlen)
725 return EDESTADDRREQ;
726
[45bb1d2]727 /* Send the address */
[d9e2e0e]728 return socket_send_data(socket_id, NET_SOCKET_CONNECT, 0, serv_addr,
729 addrlen);
730}
731
732/** Clears and destroys the socket.
733 *
734 * @param[in] socket The socket to be destroyed.
735 */
[88a1bb9]736static void socket_destroy(socket_t *socket)
[d9e2e0e]737{
738 int accepted_id;
739
[45bb1d2]740 /* Destroy all accepted sockets */
[d9e2e0e]741 while ((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0)
742 socket_destroy(sockets_find(socket_get_sockets(), accepted_id));
743
744 dyn_fifo_destroy(&socket->received);
745 dyn_fifo_destroy(&socket->accepted);
[5fe7692]746 sockets_exclude(socket_get_sockets(), socket->socket_id, free);
[d9e2e0e]747}
748
749/** Closes the socket.
750 *
751 * @param[in] socket_id Socket identifier.
[1bfd3d3]752 * @return EOK on success.
753 * @return ENOTSOCK if the socket is not found.
754 * @return EINPROGRESS if there is another blocking function in
[d9e2e0e]755 * progress.
[1bfd3d3]756 * @return Other error codes as defined for the NET_SOCKET_CLOSE
[d9e2e0e]757 * message.
758 */
759int closesocket(int socket_id)
760{
[88a1bb9]761 socket_t *socket;
[16ac756]762 int rc;
[d9e2e0e]763
764 fibril_rwlock_write_lock(&socket_globals.lock);
765
766 socket = sockets_find(socket_get_sockets(), socket_id);
767 if (!socket) {
768 fibril_rwlock_write_unlock(&socket_globals.lock);
769 return ENOTSOCK;
770 }
771 if (socket->blocked) {
772 fibril_rwlock_write_unlock(&socket_globals.lock);
773 return EINPROGRESS;
774 }
775
[45bb1d2]776 /* Request close */
[6b82009]777 async_exch_t *exch = async_exchange_begin(socket->sess);
778 rc = (int) async_req_3_0(exch, NET_SOCKET_CLOSE,
[96b02eb9]779 (sysarg_t) socket->socket_id, 0, socket->service);
[6b82009]780 async_exchange_end(exch);
781
[16ac756]782 if (rc != EOK) {
783 fibril_rwlock_write_unlock(&socket_globals.lock);
784 return rc;
785 }
[45bb1d2]786 /* Free the socket structure */
[d9e2e0e]787 socket_destroy(socket);
788
789 fibril_rwlock_write_unlock(&socket_globals.lock);
790 return EOK;
791}
792
793/** Sends data via the socket to the remote address.
794 *
[db6c332]795 * Binds the socket to a free port if not already connected/bound.
[d9e2e0e]796 *
[db6c332]797 * @param[in] message The action message.
798 * @param[in] socket_id Socket identifier.
799 * @param[in] data The data to be sent.
800 * @param[in] datalength The data length.
801 * @param[in] flags Various send flags.
802 * @param[in] toaddr The destination address. May be NULL for connected
[d9e2e0e]803 * sockets.
[db6c332]804 * @param[in] addrlen The address length. Used only if toaddr is not NULL.
[1bfd3d3]805 * @return EOK on success.
806 * @return ENOTSOCK if the socket is not found.
807 * @return EBADMEM if the data or toaddr parameter is NULL.
808 * @return NO_DATA if the datalength or the addrlen parameter is
[d9e2e0e]809 * zero (0).
[1bfd3d3]810 * @return Other error codes as defined for the NET_SOCKET_SENDTO
[d9e2e0e]811 * message.
812 */
813static int
[96b02eb9]814sendto_core(sysarg_t message, int socket_id, const void *data,
[d9e2e0e]815 size_t datalength, int flags, const struct sockaddr *toaddr,
816 socklen_t addrlen)
817{
[88a1bb9]818 socket_t *socket;
[d9e2e0e]819 aid_t message_id;
[96b02eb9]820 sysarg_t result;
[d9e2e0e]821 size_t fragments;
822 ipc_call_t answer;
823
824 if (!data)
825 return EBADMEM;
826
827 if (!datalength)
828 return NO_DATA;
829
830 fibril_rwlock_read_lock(&socket_globals.lock);
831
[45bb1d2]832 /* Find socket */
[d9e2e0e]833 socket = sockets_find(socket_get_sockets(), socket_id);
834 if (!socket) {
835 fibril_rwlock_read_unlock(&socket_globals.lock);
836 return ENOTSOCK;
837 }
838
839 fibril_rwlock_read_lock(&socket->sending_lock);
840
[45bb1d2]841 /* Compute data fragment count */
[d9e2e0e]842 if (socket->data_fragment_size > 0) {
843 fragments = (datalength + socket->header_size) /
844 socket->data_fragment_size;
845 if ((datalength + socket->header_size) %
846 socket->data_fragment_size)
847 ++fragments;
848 } else {
849 fragments = 1;
850 }
851
[45bb1d2]852 /* Request send */
[6b82009]853 async_exch_t *exch = async_exchange_begin(socket->sess);
854
855 message_id = async_send_5(exch, message,
[96b02eb9]856 (sysarg_t) socket->socket_id,
[d9e2e0e]857 (fragments == 1 ? datalength : socket->data_fragment_size),
[96b02eb9]858 socket->service, (sysarg_t) flags, fragments, &answer);
[d9e2e0e]859
[45bb1d2]860 /* Send the address if given */
[d9e2e0e]861 if (!toaddr ||
[6b82009]862 (async_data_write_start(exch, toaddr, addrlen) == EOK)) {
[d9e2e0e]863 if (fragments == 1) {
[45bb1d2]864 /* Send all if only one fragment */
[6b82009]865 async_data_write_start(exch, data, datalength);
[d9e2e0e]866 } else {
[45bb1d2]867 /* Send the first fragment */
[6b82009]868 async_data_write_start(exch, data,
[d9e2e0e]869 socket->data_fragment_size - socket->header_size);
870 data = ((const uint8_t *) data) +
871 socket->data_fragment_size - socket->header_size;
872
[45bb1d2]873 /* Send the middle fragments */
[d9e2e0e]874 while (--fragments > 1) {
[6b82009]875 async_data_write_start(exch, data,
[d9e2e0e]876 socket->data_fragment_size);
877 data = ((const uint8_t *) data) +
878 socket->data_fragment_size;
879 }
880
[45bb1d2]881 /* Send the last fragment */
[6b82009]882 async_data_write_start(exch, data,
[d9e2e0e]883 (datalength + socket->header_size) %
884 socket->data_fragment_size);
885 }
886 }
[6b82009]887
888 async_exchange_end(exch);
[d9e2e0e]889
890 async_wait_for(message_id, &result);
891
892 if ((SOCKET_GET_DATA_FRAGMENT_SIZE(answer) > 0) &&
893 (SOCKET_GET_DATA_FRAGMENT_SIZE(answer) !=
894 socket->data_fragment_size)) {
[45bb1d2]895 /* Set the data fragment size */
[d9e2e0e]896 socket->data_fragment_size =
897 SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
898 }
899
900 fibril_rwlock_read_unlock(&socket->sending_lock);
901 fibril_rwlock_read_unlock(&socket_globals.lock);
902 return (int) result;
903}
904
905/** Sends data via the socket.
906 *
907 * @param[in] socket_id Socket identifier.
908 * @param[in] data The data to be sent.
909 * @param[in] datalength The data length.
910 * @param[in] flags Various send flags.
[1bfd3d3]911 * @return EOK on success.
912 * @return ENOTSOCK if the socket is not found.
913 * @return EBADMEM if the data parameter is NULL.
914 * @return NO_DATA if the datalength parameter is zero.
915 * @return Other error codes as defined for the NET_SOCKET_SEND
[d9e2e0e]916 * message.
917 */
918int send(int socket_id, void *data, size_t datalength, int flags)
919{
[45bb1d2]920 /* Without the address */
[d9e2e0e]921 return sendto_core(NET_SOCKET_SEND, socket_id, data, datalength, flags,
922 NULL, 0);
923}
924
925/** Sends data via the socket to the remote address.
926 *
927 * Binds the socket to a free port if not already connected/bound.
928 *
929 * @param[in] socket_id Socket identifier.
930 * @param[in] data The data to be sent.
931 * @param[in] datalength The data length.
932 * @param[in] flags Various send flags.
933 * @param[in] toaddr The destination address.
934 * @param[in] addrlen The address length.
[1bfd3d3]935 * @return EOK on success.
936 * @return ENOTSOCK if the socket is not found.
937 * @return EBADMEM if the data or toaddr parameter is NULL.
938 * @return NO_DATA if the datalength or the addrlen parameter is
[d9e2e0e]939 * zero.
[1bfd3d3]940 * @return Other error codes as defined for the NET_SOCKET_SENDTO
[d9e2e0e]941 * message.
942 */
943int
944sendto(int socket_id, const void *data, size_t datalength, int flags,
945 const struct sockaddr *toaddr, socklen_t addrlen)
946{
947 if (!toaddr)
948 return EDESTADDRREQ;
949
950 if (!addrlen)
951 return EDESTADDRREQ;
952
[45bb1d2]953 /* With the address */
[d9e2e0e]954 return sendto_core(NET_SOCKET_SENDTO, socket_id, data, datalength,
955 flags, toaddr, addrlen);
956}
957
958/** Receives data via the socket.
959 *
[db6c332]960 * @param[in] message The action message.
961 * @param[in] socket_id Socket identifier.
962 * @param[out] data The data buffer to be filled.
963 * @param[in] datalength The data length.
964 * @param[in] flags Various receive flags.
965 * @param[out] fromaddr The source address. May be NULL for connected sockets.
966 * @param[in,out] addrlen The address length. The maximum address length is
[d9e2e0e]967 * read. The actual address length is set. Used only if
968 * fromaddr is not NULL.
[727f04f]969 * @return Positive received message size in bytes on success.
970 * @return Zero if no more data (other side closed the connection).
[1bfd3d3]971 * @return ENOTSOCK if the socket is not found.
972 * @return EBADMEM if the data parameter is NULL.
973 * @return NO_DATA if the datalength or addrlen parameter is zero.
974 * @return Other error codes as defined for the spcific message.
[d9e2e0e]975 */
[727f04f]976static ssize_t
[96b02eb9]977recvfrom_core(sysarg_t message, int socket_id, void *data, size_t datalength,
[d9e2e0e]978 int flags, struct sockaddr *fromaddr, socklen_t *addrlen)
979{
[88a1bb9]980 socket_t *socket;
[d9e2e0e]981 aid_t message_id;
[96b02eb9]982 sysarg_t ipc_result;
[d9e2e0e]983 int result;
984 size_t fragments;
985 size_t *lengths;
986 size_t index;
987 ipc_call_t answer;
[727f04f]988 ssize_t retval;
[d9e2e0e]989
990 if (!data)
991 return EBADMEM;
992
993 if (!datalength)
994 return NO_DATA;
995
996 if (fromaddr && !addrlen)
997 return EINVAL;
998
999 fibril_rwlock_read_lock(&socket_globals.lock);
1000
[45bb1d2]1001 /* Find the socket */
[d9e2e0e]1002 socket = sockets_find(socket_get_sockets(), socket_id);
1003 if (!socket) {
1004 fibril_rwlock_read_unlock(&socket_globals.lock);
1005 return ENOTSOCK;
1006 }
1007
1008 fibril_mutex_lock(&socket->receive_lock);
[45bb1d2]1009 /* Wait for a received packet */
[d9e2e0e]1010 ++socket->blocked;
[d493830e]1011 while ((result = dyn_fifo_value(&socket->received)) < 0) {
[d9e2e0e]1012 fibril_rwlock_read_unlock(&socket_globals.lock);
1013 fibril_condvar_wait(&socket->receive_signal,
1014 &socket->receive_lock);
1015
[45bb1d2]1016 /* Drop the receive lock to avoid deadlock */
[d9e2e0e]1017 fibril_mutex_unlock(&socket->receive_lock);
1018 fibril_rwlock_read_lock(&socket_globals.lock);
1019 fibril_mutex_lock(&socket->receive_lock);
1020 }
1021 --socket->blocked;
1022 fragments = (size_t) result;
1023
[d493830e]1024 if (fragments == 0) {
1025 /* No more data, other side has closed the connection. */
[b35fea3]1026 fibril_mutex_unlock(&socket->receive_lock);
1027 fibril_rwlock_read_unlock(&socket_globals.lock);
[d493830e]1028 return 0;
1029 }
[6b82009]1030
1031 async_exch_t *exch = async_exchange_begin(socket->sess);
[d493830e]1032
[45bb1d2]1033 /* Prepare lengths if more fragments */
[d9e2e0e]1034 if (fragments > 1) {
1035 lengths = (size_t *) malloc(sizeof(size_t) * fragments +
1036 sizeof(size_t));
1037 if (!lengths) {
1038 fibril_mutex_unlock(&socket->receive_lock);
1039 fibril_rwlock_read_unlock(&socket_globals.lock);
1040 return ENOMEM;
1041 }
1042
[45bb1d2]1043 /* Request packet data */
[6b82009]1044 message_id = async_send_4(exch, message,
[96b02eb9]1045 (sysarg_t) socket->socket_id, 0, socket->service,
1046 (sysarg_t) flags, &answer);
[d9e2e0e]1047
[45bb1d2]1048 /* Read the address if desired */
[d9e2e0e]1049 if(!fromaddr ||
[6b82009]1050 (async_data_read_start(exch, fromaddr,
[d9e2e0e]1051 *addrlen) == EOK)) {
[45bb1d2]1052 /* Read the fragment lengths */
[6b82009]1053 if (async_data_read_start(exch, lengths,
[d9e2e0e]1054 sizeof(int) * (fragments + 1)) == EOK) {
1055 if (lengths[fragments] <= datalength) {
1056
[45bb1d2]1057 /* Read all fragments if long enough */
[d9e2e0e]1058 for (index = 0; index < fragments;
1059 ++index) {
[6b82009]1060 async_data_read_start(exch, data,
[d9e2e0e]1061 lengths[index]);
1062 data = ((uint8_t *) data) +
1063 lengths[index];
1064 }
1065 }
1066 }
1067 }
1068
1069 free(lengths);
[d493830e]1070 } else { /* fragments == 1 */
[45bb1d2]1071 /* Request packet data */
[6b82009]1072 message_id = async_send_4(exch, message,
[96b02eb9]1073 (sysarg_t) socket->socket_id, 0, socket->service,
1074 (sysarg_t) flags, &answer);
[d9e2e0e]1075
[45bb1d2]1076 /* Read the address if desired */
[d9e2e0e]1077 if (!fromaddr ||
[6b82009]1078 (async_data_read_start(exch, fromaddr, *addrlen) == EOK)) {
[45bb1d2]1079 /* Read all if only one fragment */
[6b82009]1080 async_data_read_start(exch, data, datalength);
[d9e2e0e]1081 }
1082 }
[6b82009]1083
1084 async_exchange_end(exch);
[d9e2e0e]1085
1086 async_wait_for(message_id, &ipc_result);
1087 result = (int) ipc_result;
1088 if (result == EOK) {
[45bb1d2]1089 /* Dequeue the received packet */
[d9e2e0e]1090 dyn_fifo_pop(&socket->received);
[45bb1d2]1091 /* Return read data length */
[727f04f]1092 retval = SOCKET_GET_READ_DATA_LENGTH(answer);
[45bb1d2]1093 /* Set address length */
[d9e2e0e]1094 if (fromaddr && addrlen)
1095 *addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
[727f04f]1096 } else {
1097 retval = (ssize_t) result;
[d9e2e0e]1098 }
1099
1100 fibril_mutex_unlock(&socket->receive_lock);
1101 fibril_rwlock_read_unlock(&socket_globals.lock);
[727f04f]1102 return retval;
[d9e2e0e]1103}
1104
1105/** Receives data via the socket.
1106 *
1107 * @param[in] socket_id Socket identifier.
1108 * @param[out] data The data buffer to be filled.
1109 * @param[in] datalength The data length.
1110 * @param[in] flags Various receive flags.
[727f04f]1111 * @return Positive received message size in bytes on success.
1112 * @return Zero if no more data (other side closed the connection).
[1bfd3d3]1113 * @return ENOTSOCK if the socket is not found.
1114 * @return EBADMEM if the data parameter is NULL.
1115 * @return NO_DATA if the datalength parameter is zero.
1116 * @return Other error codes as defined for the NET_SOCKET_RECV
[d9e2e0e]1117 * message.
1118 */
[727f04f]1119ssize_t recv(int socket_id, void *data, size_t datalength, int flags)
[d9e2e0e]1120{
[45bb1d2]1121 /* Without the address */
[d9e2e0e]1122 return recvfrom_core(NET_SOCKET_RECV, socket_id, data, datalength,
1123 flags, NULL, NULL);
1124}
1125
1126/** Receives data via the socket.
1127 *
1128 * @param[in] socket_id Socket identifier.
1129 * @param[out] data The data buffer to be filled.
1130 * @param[in] datalength The data length.
1131 * @param[in] flags Various receive flags.
1132 * @param[out] fromaddr The source address.
1133 * @param[in,out] addrlen The address length. The maximum address length is
1134 * read. The actual address length is set.
[727f04f]1135 * @return Positive received message size in bytes on success.
1136 * @return Zero if no more data (other side closed the connection).
[1bfd3d3]1137 * @return ENOTSOCK if the socket is not found.
1138 * @return EBADMEM if the data or fromaddr parameter is NULL.
1139 * @return NO_DATA if the datalength or addrlen parameter is zero.
1140 * @return Other error codes as defined for the NET_SOCKET_RECVFROM
[d9e2e0e]1141 * message.
1142 */
[727f04f]1143ssize_t
[d9e2e0e]1144recvfrom(int socket_id, void *data, size_t datalength, int flags,
1145 struct sockaddr *fromaddr, socklen_t *addrlen)
1146{
1147 if (!fromaddr)
1148 return EBADMEM;
1149
1150 if (!addrlen)
1151 return NO_DATA;
1152
[45bb1d2]1153 /* With the address */
[d9e2e0e]1154 return recvfrom_core(NET_SOCKET_RECVFROM, socket_id, data, datalength,
1155 flags, fromaddr, addrlen);
1156}
1157
1158/** Gets socket option.
1159 *
1160 * @param[in] socket_id Socket identifier.
1161 * @param[in] level The socket options level.
1162 * @param[in] optname The socket option to be get.
1163 * @param[out] value The value buffer to be filled.
1164 * @param[in,out] optlen The value buffer length. The maximum length is read.
1165 * The actual length is set.
[1bfd3d3]1166 * @return EOK on success.
1167 * @return ENOTSOCK if the socket is not found.
1168 * @return EBADMEM if the value or optlen parameter is NULL.
1169 * @return NO_DATA if the optlen parameter is zero.
1170 * @return Other error codes as defined for the
[d9e2e0e]1171 * NET_SOCKET_GETSOCKOPT message.
1172 */
1173int
1174getsockopt(int socket_id, int level, int optname, void *value, size_t *optlen)
1175{
[88a1bb9]1176 socket_t *socket;
[d9e2e0e]1177 aid_t message_id;
[96b02eb9]1178 sysarg_t result;
[d9e2e0e]1179
1180 if (!value || !optlen)
1181 return EBADMEM;
1182
1183 if (!*optlen)
1184 return NO_DATA;
1185
1186 fibril_rwlock_read_lock(&socket_globals.lock);
1187
[45bb1d2]1188 /* Find the socket */
[d9e2e0e]1189 socket = sockets_find(socket_get_sockets(), socket_id);
1190 if (!socket) {
1191 fibril_rwlock_read_unlock(&socket_globals.lock);
1192 return ENOTSOCK;
1193 }
1194
[45bb1d2]1195 /* Request option value */
[6b82009]1196 async_exch_t *exch = async_exchange_begin(socket->sess);
1197
1198 message_id = async_send_3(exch, NET_SOCKET_GETSOCKOPT,
[96b02eb9]1199 (sysarg_t) socket->socket_id, (sysarg_t) optname, socket->service,
[d9e2e0e]1200 NULL);
1201
[45bb1d2]1202 /* Read the length */
[6b82009]1203 if (async_data_read_start(exch, optlen,
[d9e2e0e]1204 sizeof(*optlen)) == EOK) {
[45bb1d2]1205 /* Read the value */
[6b82009]1206 async_data_read_start(exch, value, *optlen);
[d9e2e0e]1207 }
[6b82009]1208
1209 async_exchange_end(exch);
[d9e2e0e]1210
1211 fibril_rwlock_read_unlock(&socket_globals.lock);
1212 async_wait_for(message_id, &result);
1213 return (int) result;
1214}
1215
1216/** Sets socket option.
1217 *
1218 * @param[in] socket_id Socket identifier.
1219 * @param[in] level The socket options level.
1220 * @param[in] optname The socket option to be set.
1221 * @param[in] value The value to be set.
1222 * @param[in] optlen The value length.
[1bfd3d3]1223 * @return EOK on success.
1224 * @return ENOTSOCK if the socket is not found.
1225 * @return EBADMEM if the value parameter is NULL.
1226 * @return NO_DATA if the optlen parameter is zero.
1227 * @return Other error codes as defined for the
[d9e2e0e]1228 * NET_SOCKET_SETSOCKOPT message.
1229 */
1230int
1231setsockopt(int socket_id, int level, int optname, const void *value,
1232 size_t optlen)
1233{
[45bb1d2]1234 /* Send the value */
[d9e2e0e]1235 return socket_send_data(socket_id, NET_SOCKET_SETSOCKOPT,
[96b02eb9]1236 (sysarg_t) optname, value, optlen);
[d9e2e0e]1237}
1238
1239/** @}
1240 */
Note: See TracBrowser for help on using the repository browser.