Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (c) 2008 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 udp
  30.  *  @{
  31.  */
  32.  
  33. /** @file
  34.  */
  35.  
  36. #include <async.h>
  37. #include <malloc.h>
  38. #include <stdio.h>
  39.  
  40. #include <ipc/ipc.h>
  41. #include <ipc/services.h>
  42.  
  43. #include "../../err.h"
  44. #include "../../messages.h"
  45. #include "../../modules.h"
  46. #include "../../structures/packet/packet_client.h"
  47.  
  48. #include "../../include/in.h"
  49. #include "../../include/inet.h"
  50. #include "../../include/ip_client.h"
  51. #include "../../include/ip_interface.h"
  52. #include "../../include/ip_protocols.h"
  53. #include "../../include/socket.h"
  54. #include "../../include/socket_errno.h"
  55. //#include "../../include/udp_interface.h"
  56.  
  57. #include "../../socket/socket_core.h"
  58. #include "../../socket/socket_messages.h"
  59.  
  60. #include "../tl_messages.h"
  61.  
  62. #include "udp.h"
  63. #include "udp_header.h"
  64. #include "udp_module.h"
  65.  
  66. int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver );
  67. int process_client_messages( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count );
  68. int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, void * addr, size_t addrlen, void * data, size_t length, int flags );
  69. int socket_get_data( void ** data, size_t * length );
  70.  
  71. udp_globals_t   udp_globals;
  72.  
  73. /** Initializes the module.
  74.  */
  75. int udp_initialize( async_client_conn_t client_connection ){
  76.     ERROR_DECLARE;
  77.  
  78.     udp_globals.port_search_start = 1025;
  79.     udp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg );
  80.     if( udp_globals.ip_phone < 0 ){
  81.         return udp_globals.ip_phone;
  82.     }
  83.     ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.addr_len, & udp_globals.prefix, & udp_globals.content, & udp_globals.suffix ));
  84.     ERROR_PROPAGATE( socket_ports_initialize( & udp_globals.sockets ));
  85.     udp_globals.prefix += sizeof( udp_header_t );
  86.     udp_globals.content -= sizeof( udp_header_t );
  87.     return EOK;
  88. }
  89.  
  90. int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver ){
  91.     // TODO received
  92.     //  TODO remove debug dump:
  93.     uint8_t *   data;
  94.     data = packet_get_data( packet );
  95.     printf( "Receiving packet:\n\tid\t= %d\n\tlength\t= %d\n\tdata\t= %.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX\n\t\t%.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX:%.2hhX %.2hhX %.2hhX %.2hhX\n", packet_get_id( packet ), packet_get_data_length( packet ), data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ], data[ 8 ], data[ 9 ], data[ 10 ], data[ 11 ], data[ 12 ], data[ 13 ], data[ 14 ], data[ 15 ], data[ 16 ], data[ 17 ], data[ 18 ], data[ 19 ], data[ 20 ], data[ 21 ], data[ 22 ], data[ 23 ], data[ 24 ], data[ 25 ], data[ 26 ], data[ 27 ], data[ 28 ], data[ 29 ], data[ 30 ], data[ 31 ], data[ 32 ], data[ 33 ], data[ 34 ], data[ 35 ], data[ 36 ], data[ 37 ], data[ 38 ], data[ 39 ], data[ 40 ], data[ 41 ], data[ 42 ], data[ 43 ], data[ 44 ], data[ 45 ], data[ 46 ], data[ 47 ], data[ 48 ], data[ 49 ], data[ 50 ], data[ 51 ], data[ 52 ], data[ 53 ], data[ 54 ], data[ 55 ], data[ 56 ], data[ 57 ], data[ 58 ], data[ 59 ] );
  96.     pq_release( udp_globals.net_phone, packet_get_id( packet ));
  97.  
  98.     return EOK;
  99. }
  100.  
  101. int udp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  102.     ERROR_DECLARE;
  103.  
  104.     packet_t    packet;
  105.  
  106.     * answer_count = 0;
  107.     switch( IPC_GET_METHOD( * call )){
  108.         case NET_TL_RECEIVED:
  109.             ERROR_PROPAGATE( packet_translate( udp_globals.net_phone, & packet, IPC_GET_PACKET( call )));
  110.             return udp_received_msg( IPC_GET_DEVICE( call ), packet, 0 );
  111.         case IPC_M_CONNECT_TO_ME:
  112.             return process_client_messages( callid, call, answer, answer_count );
  113.     }
  114.     return ENOTSUP;
  115. }
  116.  
  117. int process_client_messages( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
  118.     ERROR_DECLARE;
  119.  
  120.     int                     res;
  121.     bool                    keep_on_going = true;
  122.     socket_cores_t          local_sockets;
  123.     int                     app_phone = IPC_GET_PHONE( call );
  124.     void *                  addr;
  125.     size_t                  addrlen;
  126.     void *                  data;
  127.     size_t                  length;
  128.  
  129.     /*
  130.      * Accept the connection
  131.      *  - Answer the first IPC_M_CONNECT_ME_TO call.
  132.      */
  133.     ipc_answer_0( callid, EOK );
  134.  
  135.     socket_cores_initialize( & local_sockets );
  136.  
  137.     while( keep_on_going ){
  138.         // refresh data
  139.         * answer_count = 0;
  140.         IPC_SET_RETVAL( * answer, 0 );
  141.         // just to be precize
  142.         IPC_SET_METHOD( * answer, 0 );
  143.         IPC_SET_ARG1( * answer, 0 );
  144.         IPC_SET_ARG2( * answer, 0 );
  145.         IPC_SET_ARG3( * answer, 0 );
  146.         IPC_SET_ARG4( * answer, 0 );
  147.         IPC_SET_ARG5( * answer, 0 );
  148.  
  149.         callid = async_get_call( call );
  150.         printf( "message %d\n", IPC_GET_METHOD( * call ));
  151.  
  152.         switch( IPC_GET_METHOD( * call )){
  153.             case IPC_M_PHONE_HUNGUP:
  154.                 keep_on_going = false;
  155.                 res = EOK;
  156.                 break;
  157.             case NET_SOCKET:
  158.                 res = socket_create( & local_sockets, app_phone );
  159.                 break;
  160.             case NET_SOCKET_BIND:
  161.                 if( ERROR_OCCURRED( socket_get_data( & addr, & addrlen ))){
  162.                     res = ERROR_CODE;
  163.                     break;
  164.                 }
  165.                 res = socket_bind( & local_sockets, & udp_globals.sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen );
  166.                 free( addr );
  167.                 break;
  168.             case NET_SOCKET_SENDTO:
  169.                 if( ERROR_OCCURRED( socket_get_data( & addr, & addrlen ))){
  170.                     res = ERROR_CODE;
  171.                     break;
  172.                 }
  173.                 if( ERROR_OCCURRED( socket_get_data( & data, & length ))){
  174.                     free( addr );
  175.                     res = ERROR_CODE;
  176.                     break;
  177.                 }
  178.                 res = udp_sendto_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, data, length, SOCKET_GET_FLAGS( call ));
  179.                 free( addr );
  180.                 free( data );
  181.                 break;
  182.             case NET_SOCKET_RECVFROM:
  183.                 // TODO read first received packet queue data continuesly
  184.                 res = ENOTSUP;
  185.                 break;
  186.             case NET_SOCKET_CLOSE:
  187.                 res = socket_destroy( udp_globals.net_phone, SOCKET_GET_SOCKET_ID( call ), & local_sockets, & udp_globals.sockets );
  188.                 break;
  189.             case NET_SOCKET_GETSOCKOPT:
  190.             case NET_SOCKET_SETSOCKOPT:
  191.             default:
  192.                 res = ENOTSUP;
  193.                 break;
  194.         }
  195.  
  196.         // TODO debug
  197.         printf( "res = %d\n", res );
  198.  
  199.         switch( * answer_count ){
  200.             case 0:     ipc_answer_0( callid, res );
  201.                     continue;
  202.             case 1:     ipc_answer_1( callid, res, IPC_GET_ARG1( * answer ));
  203.                     continue;
  204.             case 2:     ipc_answer_2( callid, res, IPC_GET_ARG1( * answer ), IPC_GET_ARG2( * answer ));
  205.                     continue;
  206.             case 3:     ipc_answer_3( callid, res, IPC_GET_ARG1( * answer ), IPC_GET_ARG2( * answer ), IPC_GET_ARG3( * answer ));
  207.                     continue;
  208.             case 4:     ipc_answer_4( callid, res, IPC_GET_ARG1( * answer ), IPC_GET_ARG2( * answer ), IPC_GET_ARG3( * answer ), IPC_GET_ARG4( * answer ));
  209.                     continue;
  210.             default:    ipc_answer_5( callid, res, IPC_GET_ARG1( * answer ), IPC_GET_ARG2( * answer ), IPC_GET_ARG3( * answer ), IPC_GET_ARG4( * answer ), IPC_GET_ARG5( * answer ));
  211.                     continue;
  212.         }
  213.     }
  214.  
  215.     socket_cores_destroy( & local_sockets );
  216.  
  217.     return EOK;
  218. }
  219.  
  220. int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, void * addr, size_t addrlen, void * data, size_t length, int flags ){
  221.     ERROR_DECLARE;
  222.  
  223.     socket_core_ref         socket;
  224.     struct sockaddr *       address;
  225.     struct sockaddr_in *    address_in;
  226.     packet_t                packet;
  227.     udp_header_ref          header;
  228.  
  229.     if( addrlen < sizeof( struct sockaddr )) return EINVAL;
  230.     address = ( struct sockaddr * ) addr;
  231.     switch( address->sa_family ){
  232.         case AF_INET:
  233.             if( addrlen != sizeof( struct sockaddr_in )) return EINVAL;
  234.             address_in = ( struct sockaddr_in * ) addr;
  235.             socket = socket_cores_find( local_sockets, socket_id );
  236.             if( ! socket ) return ENOTSOCK;
  237. /*          if( socket->port < 0 ){
  238.                 return ENOTCONN;
  239.                 socket->port = udp_globals.port_search_start;
  240.                 while( socket_ports_find( global_sockets, socket->port ) >= 0 ){
  241.                     socket_port = ( socket->port + 1 ) % ( 65535 - 1025 ) + 1025;
  242.                 }
  243.                 ERROR_PROPAGATE( socket_ports_add( global_sockets, socket->port );
  244.                 udp_globals.port_search_start = socket->port + 1;
  245.             }
  246. */          // TODO create and send fragmented packets
  247.             // TODO do not ask all the time
  248.             ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.addr_len, & udp_globals.prefix, & udp_globals.content, & udp_globals.suffix ));
  249.             packet = packet_get_4( udp_globals.net_phone, length, udp_globals.addr_len, udp_globals.prefix, udp_globals.suffix );
  250.             if( ! packet ) return ENOMEM;
  251.             if( ERROR_OCCURRED( packet_copy_data( packet, data, length ))
  252.             || ERROR_OCCURRED( packet_set_addr( packet, NULL, ( uint8_t * ) & address_in->sin_addr.s_addr, sizeof( address_in->sin_addr.s_addr )))){
  253.                 pq_release( udp_globals.net_phone, packet_get_id( packet ));
  254.                 return ERROR_CODE;
  255.             }
  256.             header = PACKET_PREFIX( packet, udp_header_t );
  257.             if( ! header ){
  258.                 pq_release( udp_globals.net_phone, packet_get_id( packet ));
  259.                 return ENOMEM;
  260.             }
  261.             header->source = ( socket->port < 0 ) ? 0 : htons( socket->port );
  262.             header->dest = htons( address_in->sin_port );
  263.             header->len = htons( length );
  264.             // TODO my ip address for the pseudo header checksum
  265.             header->check = 0;
  266.             if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_UDP, 0, 0, 0, 0 ))){
  267.                 pq_release( udp_globals.net_phone, packet_get_id( packet ));
  268.                 return ERROR_CODE;
  269.             }
  270.             return ip_send_msg( udp_globals.ip_phone, socket->device_id, packet, SERVICE_UDP );
  271.             break;
  272.         // TODO IPv6
  273.         default:
  274.             return EAFNOSUPPORT;
  275.     }
  276.     return EOK;
  277. }
  278.  
  279. int socket_get_data( void ** data, size_t * length ){
  280.     ERROR_DECLARE;
  281.  
  282.     ipc_callid_t    callid;
  283.  
  284.     if( !( data && length )) return EBADMEM;
  285.     if( ! ipc_data_write_receive( & callid, length )) return EINVAL;
  286.     * data = malloc( * length );
  287.     if( ! data ) return ENOMEM;
  288.     if( ERROR_OCCURRED( ipc_data_write_finalize( callid, * data, * length ))){
  289.         free( data );
  290.         return ERROR_CODE;
  291.     }
  292.     return EOK;
  293. }
  294.  
  295. /** @}
  296.  */
  297.