00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00039 #include <assert.h>
00040 #include <async.h>
00041 #include <fibril_synch.h>
00042 #include <stdint.h>
00043 #include <stdlib.h>
00044 #include <errno.h>
00045 #include <task.h>
00046 #include <ipc/services.h>
00047 #include <ipc/socket.h>
00048 #include <net/modules.h>
00049 #include <net/in.h>
00050 #include <net/socket.h>
00051 #include <adt/dynamic_fifo.h>
00052 #include <adt/int_map.h>
00053
00055 #define SOCKET_INITIAL_RECEIVED_SIZE 4
00056
00058 #define SOCKET_MAX_RECEIVED_SIZE 0
00059
00061 #define SOCKET_INITIAL_ACCEPTED_SIZE 1
00062
00064 #define SOCKET_MAX_ACCEPTED_SIZE 0
00065
00067 #define SOCKET_CONNECT_TIMEOUT (1 * 1000 * 1000)
00068
00073 #define SOCKET_ID_TRIES 100
00074
00078 typedef struct socket socket_t;
00079
00085 struct socket {
00087 int socket_id;
00089 int phone;
00091 services_t service;
00092
00097 size_t header_size;
00098
00100 size_t data_fragment_size;
00101
00106 fibril_rwlock_t sending_lock;
00107
00109 dyn_fifo_t received;
00110
00116 fibril_mutex_t receive_lock;
00117
00119 fibril_condvar_t receive_signal;
00121 dyn_fifo_t accepted;
00122
00128 fibril_mutex_t accept_lock;
00129
00131 fibril_condvar_t accept_signal;
00132
00137 int blocked;
00138 };
00139
00144 INT_MAP_DECLARE(sockets, socket_t);
00145
00147 static struct socket_client_globals {
00149 int tcp_phone;
00151 int udp_phone;
00152
00153
00154
00155
00156
00158 sockets_t *sockets;
00159
00166 fibril_rwlock_t lock;
00167 } socket_globals = {
00168 .tcp_phone = -1,
00169 .udp_phone = -1,
00170
00171 .sockets = NULL,
00172 .lock = FIBRIL_RWLOCK_INITIALIZER(socket_globals.lock)
00173 };
00174
00175 INT_MAP_IMPLEMENT(sockets, socket_t);
00176
00181 static sockets_t *socket_get_sockets(void)
00182 {
00183 if (!socket_globals.sockets) {
00184 socket_globals.sockets =
00185 (sockets_t *) malloc(sizeof(sockets_t));
00186 if (!socket_globals.sockets)
00187 return NULL;
00188
00189 if (sockets_initialize(socket_globals.sockets) != EOK) {
00190 free(socket_globals.sockets);
00191 socket_globals.sockets = NULL;
00192 }
00193
00194 srand(task_get_id());
00195 }
00196
00197 return socket_globals.sockets;
00198 }
00199
00205 static void socket_connection(ipc_callid_t iid, ipc_call_t * icall)
00206 {
00207 ipc_callid_t callid;
00208 ipc_call_t call;
00209 socket_t *socket;
00210 int rc;
00211
00212 loop:
00213 callid = async_get_call(&call);
00214
00215 switch (IPC_GET_IMETHOD(call)) {
00216 case NET_SOCKET_RECEIVED:
00217 case NET_SOCKET_ACCEPTED:
00218 case NET_SOCKET_DATA_FRAGMENT_SIZE:
00219 fibril_rwlock_read_lock(&socket_globals.lock);
00220
00221
00222 socket = sockets_find(socket_get_sockets(),
00223 SOCKET_GET_SOCKET_ID(call));
00224 if (!socket) {
00225 rc = ENOTSOCK;
00226 fibril_rwlock_read_unlock(&socket_globals.lock);
00227 break;
00228 }
00229
00230 switch (IPC_GET_IMETHOD(call)) {
00231 case NET_SOCKET_RECEIVED:
00232 fibril_mutex_lock(&socket->receive_lock);
00233
00234 rc = dyn_fifo_push(&socket->received,
00235 SOCKET_GET_DATA_FRAGMENTS(call),
00236 SOCKET_MAX_RECEIVED_SIZE);
00237 if (rc == EOK) {
00238
00239 fibril_condvar_signal(&socket->receive_signal);
00240 }
00241 fibril_mutex_unlock(&socket->receive_lock);
00242 break;
00243
00244 case NET_SOCKET_ACCEPTED:
00245
00246 fibril_mutex_lock(&socket->accept_lock);
00247 rc = dyn_fifo_push(&socket->accepted, 1,
00248 SOCKET_MAX_ACCEPTED_SIZE);
00249 if (rc == EOK) {
00250
00251 fibril_condvar_signal(&socket->accept_signal);
00252 }
00253 fibril_mutex_unlock(&socket->accept_lock);
00254 break;
00255
00256 default:
00257 rc = ENOTSUP;
00258 }
00259
00260 if ((SOCKET_GET_DATA_FRAGMENT_SIZE(call) > 0) &&
00261 (SOCKET_GET_DATA_FRAGMENT_SIZE(call) !=
00262 socket->data_fragment_size)) {
00263 fibril_rwlock_write_lock(&socket->sending_lock);
00264
00265
00266 socket->data_fragment_size =
00267 SOCKET_GET_DATA_FRAGMENT_SIZE(call);
00268
00269 fibril_rwlock_write_unlock(&socket->sending_lock);
00270 }
00271
00272 fibril_rwlock_read_unlock(&socket_globals.lock);
00273 break;
00274
00275 default:
00276 rc = ENOTSUP;
00277 }
00278
00279 async_answer_0(callid, (sysarg_t) rc);
00280 goto loop;
00281 }
00282
00291 static int socket_get_tcp_phone(void)
00292 {
00293 if (socket_globals.tcp_phone < 0) {
00294 socket_globals.tcp_phone = bind_service_timeout(SERVICE_TCP,
00295 0, 0, SERVICE_TCP, socket_connection,
00296 SOCKET_CONNECT_TIMEOUT);
00297 }
00298
00299 return socket_globals.tcp_phone;
00300 }
00301
00310 static int socket_get_udp_phone(void)
00311 {
00312 if (socket_globals.udp_phone < 0) {
00313 socket_globals.udp_phone = bind_service_timeout(SERVICE_UDP,
00314 0, 0, SERVICE_UDP, socket_connection,
00315 SOCKET_CONNECT_TIMEOUT);
00316 }
00317
00318 return socket_globals.udp_phone;
00319 }
00320
00326 static int socket_generate_new_id(void)
00327 {
00328 sockets_t *sockets;
00329 int socket_id = 0;
00330 int count;
00331
00332 sockets = socket_get_sockets();
00333 count = 0;
00334
00335
00336 do {
00337 if (count < SOCKET_ID_TRIES) {
00338 socket_id = rand() % INT_MAX;
00339 ++count;
00340 } else if (count == SOCKET_ID_TRIES) {
00341 socket_id = 1;
00342 ++count;
00343
00344 } else {
00345 if (socket_id < INT_MAX) {
00346 ++socket_id;
00347
00348
00349
00350 } else {
00351 return ELIMIT;
00352 }
00353 }
00354 } while (sockets_find(sockets, socket_id));
00355
00356
00357 return socket_id;
00358 }
00359
00367 static void
00368 socket_initialize(socket_t *socket, int socket_id, int phone,
00369 services_t service)
00370 {
00371 socket->socket_id = socket_id;
00372 socket->phone = phone;
00373 socket->service = service;
00374 dyn_fifo_initialize(&socket->received, SOCKET_INITIAL_RECEIVED_SIZE);
00375 dyn_fifo_initialize(&socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE);
00376 fibril_mutex_initialize(&socket->receive_lock);
00377 fibril_condvar_initialize(&socket->receive_signal);
00378 fibril_mutex_initialize(&socket->accept_lock);
00379 fibril_condvar_initialize(&socket->accept_signal);
00380 fibril_rwlock_initialize(&socket->sending_lock);
00381 }
00382
00399 int socket(int domain, int type, int protocol)
00400 {
00401 socket_t *socket;
00402 int phone;
00403 int socket_id;
00404 services_t service;
00405 sysarg_t fragment_size;
00406 sysarg_t header_size;
00407 int rc;
00408
00409
00410 switch (domain) {
00411 case PF_INET:
00412 switch (type) {
00413 case SOCK_STREAM:
00414 if (!protocol)
00415 protocol = IPPROTO_TCP;
00416
00417 switch (protocol) {
00418 case IPPROTO_TCP:
00419 phone = socket_get_tcp_phone();
00420 service = SERVICE_TCP;
00421 break;
00422 default:
00423 return EPROTONOSUPPORT;
00424 }
00425
00426 break;
00427
00428 case SOCK_DGRAM:
00429 if (!protocol)
00430 protocol = IPPROTO_UDP;
00431
00432 switch (protocol) {
00433 case IPPROTO_UDP:
00434 phone = socket_get_udp_phone();
00435 service = SERVICE_UDP;
00436 break;
00437 default:
00438 return EPROTONOSUPPORT;
00439 }
00440
00441 break;
00442
00443 case SOCK_RAW:
00444 default:
00445 return ESOCKTNOSUPPORT;
00446 }
00447
00448 break;
00449
00450 case PF_INET6:
00451 default:
00452 return EPFNOSUPPORT;
00453 }
00454
00455 if (phone < 0)
00456 return phone;
00457
00458
00459 socket = (socket_t *) malloc(sizeof(socket_t));
00460 if (!socket)
00461 return ENOMEM;
00462
00463 bzero(socket, sizeof(*socket));
00464 fibril_rwlock_write_lock(&socket_globals.lock);
00465
00466
00467 socket_id = socket_generate_new_id();
00468 if (socket_id <= 0) {
00469 fibril_rwlock_write_unlock(&socket_globals.lock);
00470 free(socket);
00471 return socket_id;
00472 }
00473
00474 rc = (int) async_req_3_3(phone, NET_SOCKET, socket_id, 0, service, NULL,
00475 &fragment_size, &header_size);
00476 if (rc != EOK) {
00477 fibril_rwlock_write_unlock(&socket_globals.lock);
00478 free(socket);
00479 return rc;
00480 }
00481
00482 socket->data_fragment_size = (size_t) fragment_size;
00483 socket->header_size = (size_t) header_size;
00484
00485
00486 socket_initialize(socket, socket_id, phone, service);
00487
00488 rc = sockets_add(socket_get_sockets(), socket_id, socket);
00489
00490 fibril_rwlock_write_unlock(&socket_globals.lock);
00491 if (rc < 0) {
00492 dyn_fifo_destroy(&socket->received);
00493 dyn_fifo_destroy(&socket->accepted);
00494 free(socket);
00495 async_msg_3(phone, NET_SOCKET_CLOSE, (sysarg_t) socket_id, 0,
00496 service);
00497 return rc;
00498 }
00499
00500 return socket_id;
00501 }
00502
00516 static int
00517 socket_send_data(int socket_id, sysarg_t message, sysarg_t arg2,
00518 const void *data, size_t datalength)
00519 {
00520 socket_t *socket;
00521 aid_t message_id;
00522 sysarg_t result;
00523
00524 if (!data)
00525 return EBADMEM;
00526
00527 if (!datalength)
00528 return NO_DATA;
00529
00530 fibril_rwlock_read_lock(&socket_globals.lock);
00531
00532
00533 socket = sockets_find(socket_get_sockets(), socket_id);
00534 if (!socket) {
00535 fibril_rwlock_read_unlock(&socket_globals.lock);
00536 return ENOTSOCK;
00537 }
00538
00539
00540 message_id = async_send_3(socket->phone, message,
00541 (sysarg_t) socket->socket_id, arg2, socket->service, NULL);
00542
00543 async_data_write_start(socket->phone, data, datalength);
00544
00545 fibril_rwlock_read_unlock(&socket_globals.lock);
00546 async_wait_for(message_id, &result);
00547 return (int) result;
00548 }
00549
00562 int bind(int socket_id, const struct sockaddr * my_addr, socklen_t addrlen)
00563 {
00564 if (addrlen <= 0)
00565 return EINVAL;
00566
00567
00568 return socket_send_data(socket_id, NET_SOCKET_BIND, 0, my_addr,
00569 (size_t) addrlen);
00570 }
00571
00582 int listen(int socket_id, int backlog)
00583 {
00584 socket_t *socket;
00585 int result;
00586
00587 if (backlog <= 0)
00588 return EINVAL;
00589
00590 fibril_rwlock_read_lock(&socket_globals.lock);
00591
00592
00593 socket = sockets_find(socket_get_sockets(), socket_id);
00594 if (!socket) {
00595 fibril_rwlock_read_unlock(&socket_globals.lock);
00596 return ENOTSOCK;
00597 }
00598
00599
00600 result = (int) async_req_3_0(socket->phone, NET_SOCKET_LISTEN,
00601 (sysarg_t) socket->socket_id, (sysarg_t) backlog, socket->service);
00602
00603 fibril_rwlock_read_unlock(&socket_globals.lock);
00604 return result;
00605 }
00606
00621 int accept(int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen)
00622 {
00623 socket_t *socket;
00624 socket_t *new_socket;
00625 aid_t message_id;
00626 sysarg_t ipc_result;
00627 int result;
00628 ipc_call_t answer;
00629
00630 if (!cliaddr || !addrlen)
00631 return EBADMEM;
00632
00633 fibril_rwlock_write_lock(&socket_globals.lock);
00634
00635
00636 socket = sockets_find(socket_get_sockets(), socket_id);
00637 if (!socket) {
00638 fibril_rwlock_write_unlock(&socket_globals.lock);
00639 return ENOTSOCK;
00640 }
00641
00642 fibril_mutex_lock(&socket->accept_lock);
00643
00644
00645 ++ socket->blocked;
00646 while (dyn_fifo_value(&socket->accepted) <= 0) {
00647 fibril_rwlock_write_unlock(&socket_globals.lock);
00648 fibril_condvar_wait(&socket->accept_signal, &socket->accept_lock);
00649
00650 fibril_mutex_unlock(&socket->accept_lock);
00651 fibril_rwlock_write_lock(&socket_globals.lock);
00652 fibril_mutex_lock(&socket->accept_lock);
00653 }
00654 -- socket->blocked;
00655
00656
00657 new_socket = (socket_t *) malloc(sizeof(socket_t));
00658 if (!new_socket) {
00659 fibril_mutex_unlock(&socket->accept_lock);
00660 fibril_rwlock_write_unlock(&socket_globals.lock);
00661 return ENOMEM;
00662 }
00663 bzero(new_socket, sizeof(*new_socket));
00664 socket_id = socket_generate_new_id();
00665 if (socket_id <= 0) {
00666 fibril_mutex_unlock(&socket->accept_lock);
00667 fibril_rwlock_write_unlock(&socket_globals.lock);
00668 free(new_socket);
00669 return socket_id;
00670 }
00671 socket_initialize(new_socket, socket_id, socket->phone,
00672 socket->service);
00673 result = sockets_add(socket_get_sockets(), new_socket->socket_id,
00674 new_socket);
00675 if (result < 0) {
00676 fibril_mutex_unlock(&socket->accept_lock);
00677 fibril_rwlock_write_unlock(&socket_globals.lock);
00678 free(new_socket);
00679 return result;
00680 }
00681
00682
00683 message_id = async_send_5(socket->phone, NET_SOCKET_ACCEPT,
00684 (sysarg_t) socket->socket_id, 0, socket->service, 0,
00685 new_socket->socket_id, &answer);
00686
00687
00688 async_data_read_start(socket->phone, cliaddr, *addrlen);
00689 fibril_rwlock_write_unlock(&socket_globals.lock);
00690 async_wait_for(message_id, &ipc_result);
00691 result = (int) ipc_result;
00692 if (result > 0) {
00693 if (result != socket_id)
00694 result = EINVAL;
00695
00696
00697 dyn_fifo_pop(&socket->accepted);
00698
00699 *addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
00700 new_socket->data_fragment_size =
00701 SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
00702 } else if (result == ENOTSOCK) {
00703
00704 while (dyn_fifo_pop(&socket->accepted) > 0)
00705 ;
00706 }
00707
00708 fibril_mutex_unlock(&socket->accept_lock);
00709 return result;
00710 }
00711
00724 int connect(int socket_id, const struct sockaddr *serv_addr, socklen_t addrlen)
00725 {
00726 if (!serv_addr)
00727 return EDESTADDRREQ;
00728
00729 if (!addrlen)
00730 return EDESTADDRREQ;
00731
00732
00733 return socket_send_data(socket_id, NET_SOCKET_CONNECT, 0, serv_addr,
00734 addrlen);
00735 }
00736
00741 static void socket_destroy(socket_t *socket)
00742 {
00743 int accepted_id;
00744
00745
00746 while ((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0)
00747 socket_destroy(sockets_find(socket_get_sockets(), accepted_id));
00748
00749 dyn_fifo_destroy(&socket->received);
00750 dyn_fifo_destroy(&socket->accepted);
00751 sockets_exclude(socket_get_sockets(), socket->socket_id, free);
00752 }
00753
00764 int closesocket(int socket_id)
00765 {
00766 socket_t *socket;
00767 int rc;
00768
00769 fibril_rwlock_write_lock(&socket_globals.lock);
00770
00771 socket = sockets_find(socket_get_sockets(), socket_id);
00772 if (!socket) {
00773 fibril_rwlock_write_unlock(&socket_globals.lock);
00774 return ENOTSOCK;
00775 }
00776 if (socket->blocked) {
00777 fibril_rwlock_write_unlock(&socket_globals.lock);
00778 return EINPROGRESS;
00779 }
00780
00781
00782 rc = (int) async_req_3_0(socket->phone, NET_SOCKET_CLOSE,
00783 (sysarg_t) socket->socket_id, 0, socket->service);
00784 if (rc != EOK) {
00785 fibril_rwlock_write_unlock(&socket_globals.lock);
00786 return rc;
00787 }
00788
00789 socket_destroy(socket);
00790
00791 fibril_rwlock_write_unlock(&socket_globals.lock);
00792 return EOK;
00793 }
00794
00815 static int
00816 sendto_core(sysarg_t message, int socket_id, const void *data,
00817 size_t datalength, int flags, const struct sockaddr *toaddr,
00818 socklen_t addrlen)
00819 {
00820 socket_t *socket;
00821 aid_t message_id;
00822 sysarg_t result;
00823 size_t fragments;
00824 ipc_call_t answer;
00825
00826 if (!data)
00827 return EBADMEM;
00828
00829 if (!datalength)
00830 return NO_DATA;
00831
00832 fibril_rwlock_read_lock(&socket_globals.lock);
00833
00834
00835 socket = sockets_find(socket_get_sockets(), socket_id);
00836 if (!socket) {
00837 fibril_rwlock_read_unlock(&socket_globals.lock);
00838 return ENOTSOCK;
00839 }
00840
00841 fibril_rwlock_read_lock(&socket->sending_lock);
00842
00843
00844 if (socket->data_fragment_size > 0) {
00845 fragments = (datalength + socket->header_size) /
00846 socket->data_fragment_size;
00847 if ((datalength + socket->header_size) %
00848 socket->data_fragment_size)
00849 ++fragments;
00850 } else {
00851 fragments = 1;
00852 }
00853
00854
00855 message_id = async_send_5(socket->phone, message,
00856 (sysarg_t) socket->socket_id,
00857 (fragments == 1 ? datalength : socket->data_fragment_size),
00858 socket->service, (sysarg_t) flags, fragments, &answer);
00859
00860
00861 if (!toaddr ||
00862 (async_data_write_start(socket->phone, toaddr, addrlen) == EOK)) {
00863 if (fragments == 1) {
00864
00865 async_data_write_start(socket->phone, data, datalength);
00866 } else {
00867
00868 async_data_write_start(socket->phone, data,
00869 socket->data_fragment_size - socket->header_size);
00870 data = ((const uint8_t *) data) +
00871 socket->data_fragment_size - socket->header_size;
00872
00873
00874 while (--fragments > 1) {
00875 async_data_write_start(socket->phone, data,
00876 socket->data_fragment_size);
00877 data = ((const uint8_t *) data) +
00878 socket->data_fragment_size;
00879 }
00880
00881
00882 async_data_write_start(socket->phone, data,
00883 (datalength + socket->header_size) %
00884 socket->data_fragment_size);
00885 }
00886 }
00887
00888 async_wait_for(message_id, &result);
00889
00890 if ((SOCKET_GET_DATA_FRAGMENT_SIZE(answer) > 0) &&
00891 (SOCKET_GET_DATA_FRAGMENT_SIZE(answer) !=
00892 socket->data_fragment_size)) {
00893
00894 socket->data_fragment_size =
00895 SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
00896 }
00897
00898 fibril_rwlock_read_unlock(&socket->sending_lock);
00899 fibril_rwlock_read_unlock(&socket_globals.lock);
00900 return (int) result;
00901 }
00902
00916 int send(int socket_id, void *data, size_t datalength, int flags)
00917 {
00918
00919 return sendto_core(NET_SOCKET_SEND, socket_id, data, datalength, flags,
00920 NULL, 0);
00921 }
00922
00941 int
00942 sendto(int socket_id, const void *data, size_t datalength, int flags,
00943 const struct sockaddr *toaddr, socklen_t addrlen)
00944 {
00945 if (!toaddr)
00946 return EDESTADDRREQ;
00947
00948 if (!addrlen)
00949 return EDESTADDRREQ;
00950
00951
00952 return sendto_core(NET_SOCKET_SENDTO, socket_id, data, datalength,
00953 flags, toaddr, addrlen);
00954 }
00955
00974 static ssize_t
00975 recvfrom_core(sysarg_t message, int socket_id, void *data, size_t datalength,
00976 int flags, struct sockaddr *fromaddr, socklen_t *addrlen)
00977 {
00978 socket_t *socket;
00979 aid_t message_id;
00980 sysarg_t ipc_result;
00981 int result;
00982 size_t fragments;
00983 size_t *lengths;
00984 size_t index;
00985 ipc_call_t answer;
00986 ssize_t retval;
00987
00988 if (!data)
00989 return EBADMEM;
00990
00991 if (!datalength)
00992 return NO_DATA;
00993
00994 if (fromaddr && !addrlen)
00995 return EINVAL;
00996
00997 fibril_rwlock_read_lock(&socket_globals.lock);
00998
00999
01000 socket = sockets_find(socket_get_sockets(), socket_id);
01001 if (!socket) {
01002 fibril_rwlock_read_unlock(&socket_globals.lock);
01003 return ENOTSOCK;
01004 }
01005
01006 fibril_mutex_lock(&socket->receive_lock);
01007
01008 ++socket->blocked;
01009 while ((result = dyn_fifo_value(&socket->received)) < 0) {
01010 fibril_rwlock_read_unlock(&socket_globals.lock);
01011 fibril_condvar_wait(&socket->receive_signal,
01012 &socket->receive_lock);
01013
01014
01015 fibril_mutex_unlock(&socket->receive_lock);
01016 fibril_rwlock_read_lock(&socket_globals.lock);
01017 fibril_mutex_lock(&socket->receive_lock);
01018 }
01019 --socket->blocked;
01020 fragments = (size_t) result;
01021
01022 if (fragments == 0) {
01023
01024 fibril_mutex_unlock(&socket->receive_lock);
01025 fibril_rwlock_read_unlock(&socket_globals.lock);
01026 return 0;
01027 }
01028
01029
01030 if (fragments > 1) {
01031 lengths = (size_t *) malloc(sizeof(size_t) * fragments +
01032 sizeof(size_t));
01033 if (!lengths) {
01034 fibril_mutex_unlock(&socket->receive_lock);
01035 fibril_rwlock_read_unlock(&socket_globals.lock);
01036 return ENOMEM;
01037 }
01038
01039
01040 message_id = async_send_4(socket->phone, message,
01041 (sysarg_t) socket->socket_id, 0, socket->service,
01042 (sysarg_t) flags, &answer);
01043
01044
01045 if(!fromaddr ||
01046 (async_data_read_start(socket->phone, fromaddr,
01047 *addrlen) == EOK)) {
01048
01049 if (async_data_read_start(socket->phone, lengths,
01050 sizeof(int) * (fragments + 1)) == EOK) {
01051 if (lengths[fragments] <= datalength) {
01052
01053
01054 for (index = 0; index < fragments;
01055 ++index) {
01056 async_data_read_start(
01057 socket->phone, data,
01058 lengths[index]);
01059 data = ((uint8_t *) data) +
01060 lengths[index];
01061 }
01062 }
01063 }
01064 }
01065
01066 free(lengths);
01067 } else {
01068
01069 message_id = async_send_4(socket->phone, message,
01070 (sysarg_t) socket->socket_id, 0, socket->service,
01071 (sysarg_t) flags, &answer);
01072
01073
01074 if (!fromaddr ||
01075 (async_data_read_start(socket->phone, fromaddr,
01076 *addrlen) == EOK)) {
01077
01078 async_data_read_start(socket->phone, data, datalength);
01079 }
01080 }
01081
01082 async_wait_for(message_id, &ipc_result);
01083 result = (int) ipc_result;
01084 if (result == EOK) {
01085
01086 dyn_fifo_pop(&socket->received);
01087
01088 retval = SOCKET_GET_READ_DATA_LENGTH(answer);
01089
01090 if (fromaddr && addrlen)
01091 *addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
01092 } else {
01093 retval = (ssize_t) result;
01094 }
01095
01096 fibril_mutex_unlock(&socket->receive_lock);
01097 fibril_rwlock_read_unlock(&socket_globals.lock);
01098 return retval;
01099 }
01100
01115 ssize_t recv(int socket_id, void *data, size_t datalength, int flags)
01116 {
01117
01118 return recvfrom_core(NET_SOCKET_RECV, socket_id, data, datalength,
01119 flags, NULL, NULL);
01120 }
01121
01139 ssize_t
01140 recvfrom(int socket_id, void *data, size_t datalength, int flags,
01141 struct sockaddr *fromaddr, socklen_t *addrlen)
01142 {
01143 if (!fromaddr)
01144 return EBADMEM;
01145
01146 if (!addrlen)
01147 return NO_DATA;
01148
01149
01150 return recvfrom_core(NET_SOCKET_RECVFROM, socket_id, data, datalength,
01151 flags, fromaddr, addrlen);
01152 }
01153
01169 int
01170 getsockopt(int socket_id, int level, int optname, void *value, size_t *optlen)
01171 {
01172 socket_t *socket;
01173 aid_t message_id;
01174 sysarg_t result;
01175
01176 if (!value || !optlen)
01177 return EBADMEM;
01178
01179 if (!*optlen)
01180 return NO_DATA;
01181
01182 fibril_rwlock_read_lock(&socket_globals.lock);
01183
01184
01185 socket = sockets_find(socket_get_sockets(), socket_id);
01186 if (!socket) {
01187 fibril_rwlock_read_unlock(&socket_globals.lock);
01188 return ENOTSOCK;
01189 }
01190
01191
01192 message_id = async_send_3(socket->phone, NET_SOCKET_GETSOCKOPT,
01193 (sysarg_t) socket->socket_id, (sysarg_t) optname, socket->service,
01194 NULL);
01195
01196
01197 if (async_data_read_start(socket->phone, optlen,
01198 sizeof(*optlen)) == EOK) {
01199
01200 async_data_read_start(socket->phone, value, *optlen);
01201 }
01202
01203 fibril_rwlock_read_unlock(&socket_globals.lock);
01204 async_wait_for(message_id, &result);
01205 return (int) result;
01206 }
01207
01222 int
01223 setsockopt(int socket_id, int level, int optname, const void *value,
01224 size_t optlen)
01225 {
01226
01227 return socket_send_data(socket_id, NET_SOCKET_SETSOCKOPT,
01228 (sysarg_t) optname, value, optlen);
01229 }
01230