Subversion Repositories HelenOS

Rev

Rev 4730 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.  
  29. /** @addtogroup socket
  30.  *  @{
  31.  */
  32.  
  33. /** @file
  34.  *  \todo
  35.  */
  36.  
  37. #include "../err.h"
  38.  
  39. #include "../include/in.h"
  40. #include "../include/inet.h"
  41.  
  42. #include "../include/socket_codes.h"
  43. #include "../include/socket_errno.h"
  44.  
  45. #include "../structures/dynamic_fifo.h"
  46. #include "../structures/int_map.h"
  47. #include "../structures/packet/packet.h"
  48. #include "../structures/packet/packet_client.h"
  49.  
  50. #include "../modules.h"
  51.  
  52. #include "socket_core.h"
  53.  
  54. /** \todo
  55.  */
  56. struct socket_port{
  57.     socket_port_map_t   map;
  58.     int                 count;
  59. };
  60.  
  61. /** \todo
  62.  */
  63. int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port );
  64.  
  65. /** \todo
  66.  */
  67. void    socket_destroy_core( int packet_phone, socket_core_ref socket, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket ));
  68.  
  69. /** \todo
  70.  */
  71. int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length );
  72.  
  73. INT_MAP_IMPLEMENT( socket_cores, socket_core_t );
  74.  
  75. GENERIC_CHAR_MAP_IMPLEMENT( socket_port_map, socket_core_ref );
  76.  
  77. INT_MAP_IMPLEMENT( socket_ports, socket_port_t );
  78.  
  79. void socket_cores_release( int packet_phone, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){
  80.     if( socket_cores_is_valid( local_sockets )){
  81.         int index;
  82.  
  83.         local_sockets->magic = 0;
  84.         for( index = 0; index < local_sockets->next; ++ index ){
  85.             if( socket_cores_item_is_valid( &( local_sockets->items[ index ] ))){
  86.                 local_sockets->items[ index ].magic = 0;
  87.                 if( local_sockets->items[ index ].value ){
  88.                     socket_destroy_core( packet_phone, local_sockets->items[ index ].value, local_sockets, global_sockets, socket_release );
  89.                     free( local_sockets->items[ index ].value );
  90.                     local_sockets->items[ index ].value = NULL;
  91.                 }
  92.             }
  93.         }
  94.         free( local_sockets->items );
  95.     }
  96. }
  97.  
  98. void socket_destroy_core( int packet_phone, socket_core_ref socket, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){
  99.     int packet_id;
  100.  
  101.     // if bound
  102.     if( socket->port ){
  103.         // release the port
  104.         socket_port_release( global_sockets, socket );
  105.     }
  106.     // release all received packets
  107.     while(( packet_id = dyn_fifo_pop( & socket->received )) >= 0 ){
  108.         pq_release( packet_phone, packet_id );
  109.     }
  110.     dyn_fifo_destroy( & socket->received );
  111.     dyn_fifo_destroy( & socket->accepted );
  112.     if( socket_release ){
  113.         socket_release( socket );
  114.     }
  115.     socket_cores_exclude( local_sockets, socket->socket_id );
  116. }
  117.  
  118. int socket_bind( socket_cores_ref local_sockets, socket_ports_ref global_sockets, int socket_id, void * addr, size_t addrlen, int free_ports_start, int free_ports_end, int last_used_port ){
  119.     socket_core_ref         socket;
  120.     socket_port_ref         socket_port;
  121.     struct sockaddr *       address;
  122.     struct sockaddr_in *    address_in;
  123.  
  124.     if( addrlen < sizeof( struct sockaddr )) return EINVAL;
  125.     address = ( struct sockaddr * ) addr;
  126.     switch( address->sa_family ){
  127.         case AF_INET:
  128.             if( addrlen != sizeof( struct sockaddr_in )) return EINVAL;
  129.             address_in = ( struct sockaddr_in * ) addr;
  130.             // find the socket
  131.             socket = socket_cores_find( local_sockets, socket_id );
  132.             if( ! socket ) return ENOTSOCK;
  133.             // bind a free port?
  134.             if( address_in->sin_port <= 0 ){
  135.                 return socket_bind_free_port( global_sockets, socket, free_ports_start, free_ports_end, last_used_port );
  136.             }
  137.             // try to find the port
  138.             socket_port = socket_ports_find( global_sockets, ntohs( address_in->sin_port ));
  139.             if( socket_port ){
  140.                 // already used
  141.                 return EADDRINUSE;
  142.             }
  143.             // if bound
  144.             if( socket->port ){
  145.                 // release the port
  146.                 socket_port_release( global_sockets, socket );
  147.             }
  148.             socket->port = -1;
  149.             return socket_bind_insert( global_sockets, socket, ntohs( address_in->sin_port ));
  150.             break;
  151.         // TODO IPv6
  152.     }
  153.     return EAFNOSUPPORT;
  154. }
  155.  
  156. int socket_bind_free_port( socket_ports_ref global_sockets, socket_core_ref socket, int free_ports_start, int free_ports_end, int last_used_port ){
  157.     int index;
  158.  
  159.     // from the last used one
  160.     index = last_used_port;
  161.     do{
  162.         ++ index;
  163.         // til the range end
  164.         if( index >= free_ports_end ){
  165.             // start from the range beginning
  166.             index = free_ports_start - 1;
  167.             do{
  168.                 ++ index;
  169.                 // til the last used one
  170.                 if( index >= last_used_port ){
  171.                     // none found
  172.                     return ENOTCONN;
  173.                 }
  174.             }while( socket_ports_find( global_sockets, index ) != NULL );
  175.             // found, break immediately
  176.             break;
  177.         }
  178.     }while( socket_ports_find( global_sockets, index ) != NULL );
  179.     return socket_bind_insert( global_sockets, socket, index );
  180. }
  181.  
  182. int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port ){
  183.     ERROR_DECLARE;
  184.  
  185.     socket_port_ref socket_port;
  186.  
  187.     // create a wrapper
  188.     socket_port = malloc( sizeof( * socket_port ));
  189.     if( ! socket_port ) return ENOMEM;
  190.     socket_port->count = 0;
  191.     if( ERROR_OCCURRED( socket_port_map_initialize( & socket_port->map ))
  192.     || ERROR_OCCURRED( socket_port_add_core( socket_port, socket, SOCKET_MAP_KEY_LISTENING, 0 ))){
  193.         socket_port_map_destroy( & socket_port->map );
  194.         free( socket_port );
  195.         return ERROR_CODE;
  196.     }
  197.     // register the incomming port
  198.     ERROR_CODE = socket_ports_add( global_sockets, port, socket_port );
  199.     if( ERROR_CODE < 0 ){
  200.         socket_port_map_destroy( & socket_port->map );
  201.         free( socket_port );
  202.         return ERROR_CODE;
  203.     }
  204.     socket->port = port;
  205.     return EOK;
  206. }
  207.  
  208. int socket_create( socket_cores_ref local_sockets, int app_phone, void * specific_data, int * socket_id ){
  209.     ERROR_DECLARE;
  210.  
  211.     socket_core_ref socket;
  212.     int             res;
  213.  
  214.     if( ! socket_id ) return EBADMEM;
  215.     socket = ( socket_core_ref ) malloc( sizeof( * socket ));
  216.     if( ! socket ) return ENOMEM;
  217.     // initialize
  218.     socket->phone = app_phone;
  219.     socket->port = -1;
  220.     socket->key = NULL;
  221.     socket->key_length = 0;
  222.     socket->specific_data = specific_data;
  223.     if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){
  224.         free( socket );
  225.         return ERROR_CODE;
  226.     }
  227.     if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){
  228.         dyn_fifo_destroy( & socket->received );
  229.         free( socket );
  230.         return ERROR_CODE;
  231.     }
  232.     // get a next free socket number
  233.     socket->socket_id = socket_cores_count( local_sockets ) + 1;
  234.     // store the socket
  235.     res = socket_cores_add( local_sockets, socket->socket_id, socket );
  236.     if( res < 0 ){
  237.         dyn_fifo_destroy( & socket->received );
  238.         dyn_fifo_destroy( & socket->accepted );
  239.         free( socket );
  240.         return res;
  241.     }
  242.     // return the socket identifier
  243.     * socket_id = socket->socket_id;
  244.     return EOK;
  245. }
  246.  
  247. int socket_destroy( int packet_phone, int socket_id, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){
  248.     socket_core_ref socket;
  249.     int             accepted_id;
  250.  
  251.     // find the socket
  252.     socket = socket_cores_find( local_sockets, socket_id );
  253.     if( ! socket ) return ENOTSOCK;
  254.     // destroy all accepted sockets
  255.     while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){
  256.         socket_destroy( packet_phone, accepted_id, local_sockets, global_sockets, socket_release );
  257.     }
  258.     socket_destroy_core( packet_phone, socket, local_sockets, global_sockets, socket_release );
  259.     return EOK;
  260. }
  261.  
  262. int socket_reply_packets( packet_t packet, size_t * length ){
  263.     ERROR_DECLARE;
  264.  
  265.     packet_t        next_packet;
  266.     size_t          fragments;
  267.     size_t *        lengths;
  268.     size_t          index;
  269.  
  270.     if( ! length ){
  271.         return EINVAL;
  272.     }
  273.     next_packet = pq_next( packet );
  274.     if( ! next_packet ){
  275.         // write all if only one fragment
  276.         ERROR_PROPAGATE( data_reply( packet_get_data( packet ), packet_get_data_length( packet )));
  277.         // store the total length
  278.         * length = packet_get_data_length( packet );
  279.     }else{
  280.         // count the packet fragments
  281.         fragments = 1;
  282.         next_packet = pq_next( packet );
  283.         while(( next_packet = pq_next( next_packet ))){
  284.             ++ fragments;
  285.         }
  286.         // compute and store the fragment lengths
  287.         lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t ));
  288.         if( ! lengths ) return ENOMEM;
  289.         lengths[ 0 ] = packet_get_data_length( packet );
  290.         lengths[ fragments ] = lengths[ 0 ];
  291.         next_packet = pq_next( packet );
  292.         for( index = 1; index < fragments; ++ index ){
  293.             lengths[ index ] = packet_get_data_length( next_packet );
  294.             lengths[ fragments ] += lengths[ index ];
  295.             next_packet = pq_next( packet );
  296.         }while( next_packet );
  297.         // write the fragment lengths
  298.         ERROR_PROPAGATE( data_reply( lengths, sizeof( int ) * ( fragments + 1 )));
  299.         next_packet = packet;
  300.         // write the fragments
  301.         for( index = 0; index < fragments; ++ index ){
  302.             ERROR_PROPAGATE( data_reply( packet_get_data( next_packet ), lengths[ index ] ));
  303.             next_packet = pq_next( next_packet );
  304.         }while( next_packet );
  305.         // store the total length
  306.         * length = lengths[ fragments ];
  307.         free( lengths );
  308.     }
  309.     return EOK;
  310. }
  311.  
  312. socket_core_ref socket_port_find( socket_ports_ref global_sockets, int port, const char * key, size_t key_length ){
  313.     socket_port_ref     socket_port;
  314.     socket_core_ref *   socket_ref;
  315.  
  316.     socket_port = socket_ports_find( global_sockets, port );
  317.     if( socket_port && ( socket_port->count > 0 )){
  318.         socket_ref = socket_port_map_find( & socket_port->map, key, key_length );
  319.         if( socket_ref ){
  320.             return * socket_ref;
  321.         }
  322.     }
  323.     return NULL;
  324. }
  325.  
  326. void socket_port_release( socket_ports_ref global_sockets, socket_core_ref socket ){
  327.     socket_port_ref socket_port;
  328.     socket_core_ref *   socket_ref;
  329.  
  330.     if( socket->port ){
  331.         // find ports
  332.         socket_port = socket_ports_find( global_sockets, socket->port );
  333.         if( socket_port ){
  334.             // find the socket
  335.             socket_ref = socket_port_map_find( & socket_port->map, socket->key, socket->key_length );
  336.             if( socket_ref ){
  337.                 -- socket_port->count;
  338.                 // release if empty
  339.                 if( socket_port->count <= 0 ){
  340.                     // destroy the map
  341.                     socket_port_map_destroy( & socket_port->map );
  342.                     // release the port
  343.                     socket_ports_exclude( global_sockets, socket->port );
  344.                 }else{
  345.                     // remove
  346.                     socket_port_map_exclude( & socket_port->map, socket->key, socket->key_length );
  347.                 }
  348.             }
  349.         }
  350.         socket->port = 0;
  351.         socket->key = NULL;
  352.         socket->key_length = 0;
  353.     }
  354. }
  355.  
  356. int socket_port_add( socket_ports_ref global_sockets, int port, socket_core_ref socket, const char * key, size_t key_length ){
  357.     ERROR_DECLARE;
  358.  
  359.     socket_port_ref     socket_port;
  360.  
  361.     // find ports
  362.     socket_port = socket_ports_find( global_sockets, port );
  363.     if( ! socket_port ) return ENOENT;
  364.     // add the socket
  365.     ERROR_PROPAGATE( socket_port_add_core( socket_port, socket, key, key_length ));
  366.     socket->port = port;
  367.     return EOK;
  368. }
  369.  
  370. int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length ){
  371.     ERROR_DECLARE;
  372.  
  373.     socket_core_ref *   socket_ref;
  374.  
  375.     // create a wrapper
  376.     socket_ref = malloc( sizeof( * socket_ref ));
  377.     if( ! socket_ref ) return ENOMEM;
  378.     * socket_ref = socket;
  379.     // add the wrapper
  380.     if( ERROR_OCCURRED( socket_port_map_add( & socket_port->map, key, key_length, socket_ref ))){
  381.         free( socket_ref );
  382.         return ERROR_CODE;
  383.     }
  384.     ++ socket_port->count;
  385.     socket->key = key;
  386.     socket->key_length = key_length;
  387.     return EOK;
  388. }
  389.  
  390. /** @}
  391.  */
  392.