socket_core.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 
00037 #include <socket_core.h>
00038 #include <packet_client.h>
00039 #include <packet_remote.h>
00040 
00041 #include <net/socket_codes.h>
00042 #include <net/in.h>
00043 #include <net/inet.h>
00044 #include <net/packet.h>
00045 #include <net/modules.h>
00046 
00047 #include <stdint.h>
00048 #include <stdlib.h>
00049 #include <errno.h>
00050 
00051 #include <adt/dynamic_fifo.h>
00052 #include <adt/int_map.h>
00053 
00058 #define SOCKET_ID_TRIES 100
00059 
00061 struct socket_port {
00063         socket_port_map_t map;
00065         int count;
00066 };
00067 
00068 INT_MAP_IMPLEMENT(socket_cores, socket_core_t);
00069 
00070 GENERIC_CHAR_MAP_IMPLEMENT(socket_port_map, socket_core_t *);
00071 
00072 INT_MAP_IMPLEMENT(socket_ports, socket_port_t);
00073 
00086 static void
00087 socket_destroy_core(int packet_phone, socket_core_t *socket,
00088     socket_cores_t *local_sockets, socket_ports_t *global_sockets,
00089     void (* socket_release)(socket_core_t *socket))
00090 {
00091         int packet_id;
00092 
00093         /* If bound */
00094         if (socket->port) {
00095                 /* Release the port */
00096                 socket_port_release(global_sockets, socket);
00097         }
00098         
00099         /* Release all received packets */
00100         while ((packet_id = dyn_fifo_pop(&socket->received)) >= 0)
00101                 pq_release_remote(packet_phone, packet_id);
00102 
00103         dyn_fifo_destroy(&socket->received);
00104         dyn_fifo_destroy(&socket->accepted);
00105 
00106         if (socket_release)
00107                 socket_release(socket);
00108 
00109         socket_cores_exclude(local_sockets, socket->socket_id, free);
00110 }
00111 
00122 void
00123 socket_cores_release(int packet_phone, socket_cores_t *local_sockets,
00124     socket_ports_t *global_sockets,
00125     void (* socket_release)(socket_core_t *socket))
00126 {
00127         int index;
00128 
00129         if (!socket_cores_is_valid(local_sockets))
00130                 return;
00131 
00132         local_sockets->magic = 0;
00133 
00134         for (index = 0; index < local_sockets->next; ++index) {
00135                 if (socket_cores_item_is_valid(&local_sockets->items[index])) {
00136                         local_sockets->items[index].magic = 0;
00137 
00138                         if (local_sockets->items[index].value) {
00139                                 socket_destroy_core(packet_phone,
00140                                     local_sockets->items[index].value,
00141                                     local_sockets, global_sockets,
00142                                     socket_release);
00143                                 free(local_sockets->items[index].value);
00144                                 local_sockets->items[index].value = NULL;
00145                         }
00146                 }
00147         }
00148 
00149         free(local_sockets->items);
00150 }
00151 
00161 static int
00162 socket_port_add_core(socket_port_t *socket_port, socket_core_t *socket,
00163     const uint8_t *key, size_t key_length)
00164 {
00165         socket_core_t **socket_ref;
00166         int rc;
00167 
00168         /* Create a wrapper */
00169         socket_ref = malloc(sizeof(*socket_ref));
00170         if (!socket_ref)
00171                 return ENOMEM;
00172 
00173         *socket_ref = socket;
00174         /* Add the wrapper */
00175         rc = socket_port_map_add(&socket_port->map, key, key_length,
00176             socket_ref);
00177         if (rc != EOK) {
00178                 free(socket_ref);
00179                 return rc;
00180         }
00181         
00182         ++socket_port->count;
00183         socket->key = key;
00184         socket->key_length = key_length;
00185         
00186         return EOK;
00187 }
00188 
00201 static int
00202 socket_bind_insert(socket_ports_t *global_sockets, socket_core_t *socket,
00203     int port)
00204 {
00205         socket_port_t *socket_port;
00206         int rc;
00207 
00208         /* Create a wrapper */
00209         socket_port = malloc(sizeof(*socket_port));
00210         if (!socket_port)
00211                 return ENOMEM;
00212 
00213         socket_port->count = 0;
00214         rc = socket_port_map_initialize(&socket_port->map);
00215         if (rc != EOK)
00216                 goto fail;
00217         
00218         rc = socket_port_add_core(socket_port, socket,
00219             (const uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
00220         if (rc != EOK)
00221                 goto fail;
00222         
00223         /* Register the incoming port */
00224         rc = socket_ports_add(global_sockets, port, socket_port);
00225         if (rc < 0)
00226                 goto fail;
00227         
00228         socket->port = port;
00229         return EOK;
00230 
00231 fail:
00232         socket_port_map_destroy(&socket_port->map, free);
00233         free(socket_port);
00234         return rc;
00235         
00236 }
00237 
00259 int
00260 socket_bind(socket_cores_t *local_sockets, socket_ports_t *global_sockets,
00261     int socket_id, void *addr, size_t addrlen, int free_ports_start,
00262     int free_ports_end, int last_used_port)
00263 {
00264         socket_core_t *socket;
00265         socket_port_t *socket_port;
00266         struct sockaddr *address;
00267         struct sockaddr_in *address_in;
00268 
00269         if (addrlen < sizeof(struct sockaddr))
00270                 return EINVAL;
00271 
00272         address = (struct sockaddr *) addr;
00273         switch (address->sa_family) {
00274         case AF_INET:
00275                 if (addrlen != sizeof(struct sockaddr_in))
00276                         return EINVAL;
00277                 
00278                 address_in = (struct sockaddr_in *) addr;
00279                 /* Find the socket */
00280                 socket = socket_cores_find(local_sockets, socket_id);
00281                 if (!socket)
00282                         return ENOTSOCK;
00283                 
00284                 /* Bind a free port? */
00285                 if (address_in->sin_port <= 0)
00286                         return socket_bind_free_port(global_sockets, socket,
00287                              free_ports_start, free_ports_end, last_used_port);
00288                 
00289                 /* Try to find the port */
00290                 socket_port = socket_ports_find(global_sockets,
00291                     ntohs(address_in->sin_port));
00292                 if (socket_port) {
00293                         /* Already used */
00294                         return EADDRINUSE;
00295                 }
00296                 
00297                 /* If bound */
00298                 if (socket->port) {
00299                         /* Release the port */
00300                         socket_port_release(global_sockets, socket);
00301                 }
00302                 socket->port = -1;
00303                 
00304                 return socket_bind_insert(global_sockets, socket,
00305                     ntohs(address_in->sin_port));
00306                 
00307         case AF_INET6:
00308                 // TODO IPv6
00309                 break;
00310         }
00311         
00312         return EAFNOSUPPORT;
00313 }
00314 
00329 int
00330 socket_bind_free_port(socket_ports_t *global_sockets, socket_core_t *socket,
00331     int free_ports_start, int free_ports_end, int last_used_port)
00332 {
00333         int index;
00334 
00335         /* From the last used one */
00336         index = last_used_port;
00337         
00338         do {
00339                 ++index;
00340                 
00341                 /* Till the range end */
00342                 if (index >= free_ports_end) {
00343                         /* Start from the range beginning */
00344                         index = free_ports_start - 1;
00345                         do {
00346                                 ++index;
00347                                 /* Till the last used one */
00348                                 if (index >= last_used_port) {
00349                                         /* None found */
00350                                         return ENOTCONN;
00351                                 }
00352                         } while (socket_ports_find(global_sockets, index));
00353                         
00354                         /* Found, break immediately */
00355                         break;
00356                 }
00357                 
00358         } while (socket_ports_find(global_sockets, index));
00359         
00360         return socket_bind_insert(global_sockets, socket, index);
00361 }
00362 
00372 static int socket_generate_new_id(socket_cores_t *local_sockets, int positive)
00373 {
00374         int socket_id;
00375         int count;
00376 
00377         count = 0;
00378 #if 0
00379         socket_id = socket_globals.last_id;
00380 #endif
00381         do {
00382                 if (count < SOCKET_ID_TRIES) {
00383                         socket_id = rand() % INT_MAX;
00384                         ++count;
00385                 } else if (count == SOCKET_ID_TRIES) {
00386                         socket_id = 1;
00387                         ++count;
00388                 /* Only this branch for last_id */
00389                 } else {
00390                         if (socket_id < INT_MAX) {
00391                                 ++ socket_id;
00392 #if 0
00393                         } else if(socket_globals.last_id) {
00394                                 socket_globals.last_id = 0;
00395                                 socket_id = 1;
00396 #endif
00397                         } else {
00398                                 return ELIMIT;
00399                         }
00400                 }
00401         } while (socket_cores_find(local_sockets,
00402             ((positive ? 1 : -1) * socket_id)));
00403         
00404 //      last_id = socket_id
00405         return socket_id;
00406 }
00407 
00420 int
00421 socket_create(socket_cores_t *local_sockets, int app_phone,
00422     void *specific_data, int *socket_id)
00423 {
00424         socket_core_t *socket;
00425         int positive;
00426         int rc;
00427 
00428         if (!socket_id)
00429                 return EINVAL;
00430         
00431         /* Store the socket */
00432         if (*socket_id <= 0) {
00433                 positive = (*socket_id == 0);
00434                 *socket_id = socket_generate_new_id(local_sockets, positive);
00435                 if (*socket_id <= 0)
00436                         return *socket_id;
00437                 if (!positive)
00438                         *socket_id *= -1;
00439         } else if(socket_cores_find(local_sockets, *socket_id)) {
00440                 return EEXIST;
00441         }
00442         
00443         socket = (socket_core_t *) malloc(sizeof(*socket));
00444         if (!socket)
00445                 return ENOMEM;
00446         
00447         /* Initialize */
00448         socket->phone = app_phone;
00449         socket->port = -1;
00450         socket->key = NULL;
00451         socket->key_length = 0;
00452         socket->specific_data = specific_data;
00453         rc = dyn_fifo_initialize(&socket->received, SOCKET_INITIAL_RECEIVED_SIZE);
00454         if (rc != EOK) {
00455                 free(socket);
00456                 return rc;
00457         }
00458         
00459         rc = dyn_fifo_initialize(&socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE);
00460         if (rc != EOK) {
00461                 dyn_fifo_destroy(&socket->received);
00462                 free(socket);
00463                 return rc;
00464         }
00465         socket->socket_id = *socket_id;
00466         rc = socket_cores_add(local_sockets, socket->socket_id, socket);
00467         if (rc < 0) {
00468                 dyn_fifo_destroy(&socket->received);
00469                 dyn_fifo_destroy(&socket->accepted);
00470                 free(socket);
00471                 return rc;
00472         }
00473         
00474         return EOK;
00475 }
00476 
00491 int
00492 socket_destroy(int packet_phone, int socket_id, socket_cores_t *local_sockets,
00493     socket_ports_t *global_sockets,
00494     void (*socket_release)(socket_core_t *socket))
00495 {
00496         socket_core_t *socket;
00497         int accepted_id;
00498 
00499         /* Find the socket */
00500         socket = socket_cores_find(local_sockets, socket_id);
00501         if (!socket)
00502                 return ENOTSOCK;
00503         
00504         /* Destroy all accepted sockets */
00505         while ((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0)
00506                 socket_destroy(packet_phone, accepted_id, local_sockets,
00507                     global_sockets, socket_release);
00508         
00509         socket_destroy_core(packet_phone, socket, local_sockets, global_sockets,
00510             socket_release);
00511         
00512         return EOK;
00513 }
00514 
00528 int socket_reply_packets(packet_t *packet, size_t *length)
00529 {
00530         packet_t *next_packet;
00531         size_t fragments;
00532         size_t *lengths;
00533         size_t index;
00534         int rc;
00535 
00536         if (!length)
00537                 return EBADMEM;
00538 
00539         next_packet = pq_next(packet);
00540         if (!next_packet) {
00541                 /* Write all if only one fragment */
00542                 rc = data_reply(packet_get_data(packet),
00543                     packet_get_data_length(packet));
00544                 if (rc != EOK)
00545                         return rc;
00546                 /* Store the total length */
00547                 *length = packet_get_data_length(packet);
00548         } else {
00549                 /* Count the packet fragments */
00550                 fragments = 1;
00551                 next_packet = pq_next(packet);
00552                 while ((next_packet = pq_next(next_packet)))
00553                         ++fragments;
00554                 
00555                 /* Compute and store the fragment lengths */
00556                 lengths = (size_t *) malloc(sizeof(size_t) * fragments +
00557                     sizeof(size_t));
00558                 if (!lengths)
00559                         return ENOMEM;
00560                 
00561                 lengths[0] = packet_get_data_length(packet);
00562                 lengths[fragments] = lengths[0];
00563                 next_packet = pq_next(packet);
00564                 
00565                 for (index = 1; index < fragments; ++index) {
00566                         lengths[index] = packet_get_data_length(next_packet);
00567                         lengths[fragments] += lengths[index];
00568                         next_packet = pq_next(packet);
00569                 }
00570                 
00571                 /* Write the fragment lengths */
00572                 rc = data_reply(lengths, sizeof(int) * (fragments + 1));
00573                 if (rc != EOK) {
00574                         free(lengths);
00575                         return rc;
00576                 }
00577                 next_packet = packet;
00578                 
00579                 /* Write the fragments */
00580                 for (index = 0; index < fragments; ++index) {
00581                         rc = data_reply(packet_get_data(next_packet),
00582                             lengths[index]);
00583                         if (rc != EOK) {
00584                                 free(lengths);
00585                                 return rc;
00586                         }
00587                         next_packet = pq_next(next_packet);
00588                 }
00589                 
00590                 /* Store the total length */
00591                 *length = lengths[fragments];
00592                 free(lengths);
00593         }
00594         
00595         return EOK;
00596 }
00597 
00607 socket_core_t *
00608 socket_port_find(socket_ports_t *global_sockets, int port, const uint8_t *key,
00609     size_t key_length)
00610 {
00611         socket_port_t *socket_port;
00612         socket_core_t **socket_ref;
00613 
00614         socket_port = socket_ports_find(global_sockets, port);
00615         if (socket_port && (socket_port->count > 0)) {
00616                 socket_ref = socket_port_map_find(&socket_port->map, key,
00617                     key_length);
00618                 if (socket_ref)
00619                         return *socket_ref;
00620         }
00621         
00622         return NULL;
00623 }
00624 
00633 void
00634 socket_port_release(socket_ports_t *global_sockets, socket_core_t *socket)
00635 {
00636         socket_port_t *socket_port;
00637         socket_core_t **socket_ref;
00638 
00639         if (!socket->port)
00640                 return;
00641         
00642         /* Find ports */
00643         socket_port = socket_ports_find(global_sockets, socket->port);
00644         if (socket_port) {
00645                 /* Find the socket */
00646                 socket_ref = socket_port_map_find(&socket_port->map,
00647                     socket->key, socket->key_length);
00648                 
00649                 if (socket_ref) {
00650                         --socket_port->count;
00651                         
00652                         /* Release if empty */
00653                         if (socket_port->count <= 0) {
00654                                 /* Destroy the map */
00655                                 socket_port_map_destroy(&socket_port->map, free);
00656                                 /* Release the port */
00657                                 socket_ports_exclude(global_sockets,
00658                                     socket->port, free);
00659                         } else {
00660                                 /* Remove */
00661                                 socket_port_map_exclude(&socket_port->map,
00662                                     socket->key, socket->key_length, free);
00663                         }
00664                 }
00665         }
00666         
00667         socket->port = 0;
00668         socket->key = NULL;
00669         socket->key_length = 0;
00670 }
00671 
00684 int
00685 socket_port_add(socket_ports_t *global_sockets, int port,
00686     socket_core_t *socket, const uint8_t *key, size_t key_length)
00687 {
00688         socket_port_t *socket_port;
00689         int rc;
00690 
00691         /* Find ports */
00692         socket_port = socket_ports_find(global_sockets, port);
00693         if (!socket_port)
00694                 return ENOENT;
00695         
00696         /* Add the socket */
00697         rc = socket_port_add_core(socket_port, socket, key, key_length);
00698         if (rc != EOK)
00699                 return rc;
00700         
00701         socket->port = port;
00702         return EOK;
00703 }
00704 

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