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

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

use new network address infrastructure (towards IPv6 support)

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