socket_client.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 //      /** The last socket identifier.
00154 //       */
00155 //      int last_id;
00156 
00158         sockets_t *sockets;
00159 
00166         fibril_rwlock_t lock;
00167 } socket_globals = {
00168         .tcp_phone = -1,
00169         .udp_phone = -1,
00170 //      .last_id = 0,
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                 /* Find the socket */
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                         /* Push the number of received packet fragments */
00234                         rc = dyn_fifo_push(&socket->received,
00235                             SOCKET_GET_DATA_FRAGMENTS(call),
00236                             SOCKET_MAX_RECEIVED_SIZE);
00237                         if (rc == EOK) {
00238                                 /* Signal the received packet */
00239                                 fibril_condvar_signal(&socket->receive_signal);
00240                         }
00241                         fibril_mutex_unlock(&socket->receive_lock);
00242                         break;
00243 
00244                 case NET_SOCKET_ACCEPTED:
00245                         /* Push the new socket identifier */
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                                 /* Signal the accepted socket */
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                         /* Set the data fragment size */
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 //      socket_id = socket_globals.last_id;
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                 /* Only this branch for last_id */
00344                 } else {
00345                         if (socket_id < INT_MAX) {
00346                                 ++socket_id;
00347 /*                      } else if(socket_globals.last_id) {
00348  *                              socket_globals.last_id = 0;
00349  *                              socket_id = 1;
00350  */                     } else {
00351                                 return ELIMIT;
00352                         }
00353                 }
00354         } while (sockets_find(sockets, socket_id));
00355 
00356 //      last_id = socket_id
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         /* Find the appropriate service */
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         /* Create a new socket structure */
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         /* Request a new socket */
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         /* Finish the new socket initialization */
00486         socket_initialize(socket, socket_id, phone, service);
00487         /* Store the new socket */
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         /* Find the socket */
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         /* Request the message */
00540         message_id = async_send_3(socket->phone, message,
00541             (sysarg_t) socket->socket_id, arg2, socket->service, NULL);
00542         /* Send the address */
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         /* Send the address */
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         /* Find the socket */
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         /* Request listen backlog change */
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         /* Find the socket */
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         /* Wait for an accepted socket */
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                 /* Drop the accept lock to avoid deadlock */
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         /* Create a new socket */
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         /* Request accept */
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         /* Read address */
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                 /* Dequeue the accepted socket if successful */
00697                 dyn_fifo_pop(&socket->accepted);
00698                 /* Set address length */
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                 /* Empty the queue if no accepted sockets */
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         /* Send the address */
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         /* Destroy all accepted sockets */
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         /* Request close */
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         /* Free the socket structure */
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         /* Find socket */
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         /* Compute data fragment count */
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         /* Request send */
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         /* Send the address if given */
00861         if (!toaddr ||
00862             (async_data_write_start(socket->phone, toaddr, addrlen) == EOK)) {
00863                 if (fragments == 1) {
00864                         /* Send all if only one fragment */
00865                         async_data_write_start(socket->phone, data, datalength);
00866                 } else {
00867                         /* Send the first fragment */
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                         /* Send the middle fragments */
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                         /* Send the last fragment */
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                 /* Set the data fragment size */
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         /* Without the address */
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         /* With the address */
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         /* Find the socket */
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         /* Wait for a received packet */
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                 /* Drop the receive lock to avoid deadlock */
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                 /* No more data, other side has closed the connection. */
01024                 fibril_mutex_unlock(&socket->receive_lock);
01025                 fibril_rwlock_read_unlock(&socket_globals.lock);
01026                 return 0;
01027         }
01028 
01029         /* Prepare lengths if more fragments */
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                 /* Request packet data */
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                 /* Read the address if desired */
01045                 if(!fromaddr ||
01046                     (async_data_read_start(socket->phone, fromaddr,
01047                     *addrlen) == EOK)) {
01048                         /* Read the fragment lengths */
01049                         if (async_data_read_start(socket->phone, lengths,
01050                             sizeof(int) * (fragments + 1)) == EOK) {
01051                                 if (lengths[fragments] <= datalength) {
01052 
01053                                         /* Read all fragments if long enough */
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 { /* fragments == 1 */
01068                 /* Request packet data */
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                 /* Read the address if desired */
01074                 if (!fromaddr ||
01075                     (async_data_read_start(socket->phone, fromaddr,
01076                         *addrlen) == EOK)) {
01077                         /* Read all if only one fragment */
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                 /* Dequeue the received packet */
01086                 dyn_fifo_pop(&socket->received);
01087                 /* Return read data length */
01088                 retval = SOCKET_GET_READ_DATA_LENGTH(answer);
01089                 /* Set address length */
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         /* Without the address */
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         /* With the address */
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         /* Find the socket */
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         /* Request option value */
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         /* Read the length */
01197         if (async_data_read_start(socket->phone, optlen,
01198             sizeof(*optlen)) == EOK) {
01199                 /* Read the value */
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         /* Send the value */
01227         return socket_send_data(socket_id, NET_SOCKET_SETSOCKOPT,
01228             (sysarg_t) optname, value, optlen);
01229 }
01230 

Generated on Thu Jun 2 07:45:46 2011 for HelenOS/USB by  doxygen 1.4.7