Subversion Repositories HelenOS

Rev

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