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

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

make the socket connection fibril more robust (handle hangup)

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