Subversion Repositories HelenOS

Rev

Rev 4578 | Rev 4603 | 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.  *  Socket application program interface (API) implementation.
  35.  *  @see socket.h for more information.
  36.  *  This is a part of the network application library.
  37.  */
  38.  
  39. #include <assert.h>
  40. #include <async.h>
  41. #include <fibril_sync.h>
  42.  
  43. #include <ipc/services.h>
  44.  
  45. #include "../err.h"
  46. #include "../modules.h"
  47.  
  48. #include "../include/in.h"
  49. #include "../include/socket.h"
  50. #include "../include/socket_errno.h"
  51.  
  52. #include "../structures/int_map.h"
  53.  
  54. #include "socket_messages.h"
  55.  
  56. typedef struct socket   socket_t;
  57. typedef socket_t *      socket_ref;
  58.  
  59. struct socket{
  60.     int                 socket_id;
  61.     int                 phone;
  62.     services_t          service;
  63.     int                 max_content;
  64.     int                 received;
  65.     fibril_mutex_t      receive_lock;
  66.     fibril_condvar_t    receive_signal;
  67.     int                 accepted;
  68.     fibril_mutex_t      accept_lock;
  69.     fibril_condvar_t    accept_signal;
  70. };
  71.  
  72. INT_MAP_DECLARE( sockets, socket_t );
  73.  
  74. static struct{
  75.     int tcp_phone;
  76.     int udp_phone;
  77.     sockets_ref sockets;
  78. } socket_globals = { -1, -1, NULL };
  79.  
  80. INT_MAP_IMPLEMENT( sockets, socket_t );
  81.  
  82. static int  socket_get_tcp_phone();
  83. static int  socket_get_tcp_phone();
  84. static sockets_ref  socket_get_sockets();
  85. void    socket_connection( ipc_callid_t iid, ipc_call_t * icall );
  86. int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength );
  87. void    socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
  88.  
  89. static int socket_get_tcp_phone(){
  90.     if( socket_globals.tcp_phone < 0 ){
  91.         socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection );
  92.     }
  93.     return socket_globals.tcp_phone;
  94. }
  95.  
  96. static int socket_get_udp_phone(){
  97.     if( socket_globals.udp_phone < 0 ){
  98.         socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection );
  99.     }
  100.     return socket_globals.udp_phone;
  101. }
  102.  
  103. static sockets_ref socket_get_sockets(){
  104.     if( ! socket_globals.sockets ){
  105.         socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t ));
  106.         if( ! socket_globals.sockets ) return NULL;
  107.         if( sockets_initialize( socket_globals.sockets ) != EOK ){
  108.             free( socket_globals.sockets );
  109.             socket_globals.sockets = NULL;
  110.         }
  111.     }
  112.     return socket_globals.sockets;
  113. }
  114.  
  115. void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){
  116.     socket->socket_id = socket_id;
  117.     socket->phone = phone;
  118.     socket->service = service;
  119.     socket->received = 0;
  120.     socket->accepted = 0;
  121.     fibril_mutex_initialize( & socket->receive_lock );
  122.     fibril_condvar_initialize( & socket->receive_signal );
  123.     fibril_mutex_initialize( & socket->accept_lock );
  124.     fibril_condvar_initialize( & socket->accept_signal );
  125. }
  126.  
  127. void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){
  128.     ERROR_DECLARE;
  129.  
  130.     ipc_callid_t    callid;
  131.     ipc_call_t      call;
  132.     socket_ref      socket;
  133.     socket_ref      new_socket;
  134.  
  135.     while( true ){
  136.  
  137.         callid = async_get_call( & call );
  138.         switch( IPC_GET_METHOD( call )){
  139.             case NET_SOCKET_RECEIVED:
  140.                 socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
  141.                 if( ! socket ){
  142.                     ERROR_CODE = ENOTSOCK;
  143.                     break;
  144.                 }
  145.                 fibril_mutex_lock( & socket->receive_lock );
  146.                 ++ socket->received;
  147.                 fibril_condvar_signal( & socket->receive_signal );
  148.                 fibril_mutex_unlock( & socket->receive_lock );
  149.                 ERROR_CODE = EOK;
  150.                 break;
  151.             case NET_SOCKET_ACCEPTED:
  152.                 socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
  153.                 if( ! socket ){
  154.                     ERROR_CODE = ENOTSOCK;
  155.                     break;
  156.                 }
  157.                 fibril_mutex_lock( & socket->accept_lock );
  158.                 new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
  159.                 if( ! new_socket ){
  160.                     ERROR_CODE = ENOMEM;
  161.                     break;
  162.                 }
  163.                 socket_initialize( new_socket, SOCKET_GET_NEW_SOCKET_ID( & call ), socket->phone, socket->service );
  164.                 if( ERROR_OCCURRED( sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket ))){
  165.                     break;
  166.                 }
  167.                 ++ socket->accepted;
  168.                 fibril_condvar_signal( & socket->accept_signal );
  169.                 fibril_mutex_unlock( & socket->accept_lock );
  170.                 break;
  171. /*          case NET_SOCKET_MTU:
  172.                 socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
  173.                 if( ! socket ){
  174.                     ERROR_CODE = ENOTSOCK;
  175.                     break;
  176.                 }
  177.                 socket->mtu =
  178.                 ERROR_CODE = EOK;
  179.                 break;
  180. */          default:
  181.                 ERROR_CODE = ENOTSUP;
  182.         }
  183.         ipc_answer_0( callid, ERROR_CODE );
  184.     }
  185. }
  186.  
  187. int socket( int domain, int type, int protocol ){
  188.     socket_ref  socket;
  189.     int         phone;
  190.     int         socket_id;
  191.     services_t  service;
  192.  
  193.     switch( domain ){
  194.         case PF_INET:
  195.             switch( type ){
  196.                 case SOCK_STREAM:
  197.                     if( ! protocol ) protocol = IPPROTO_TCP;
  198.                     switch( protocol ){
  199.                         case IPPROTO_TCP:
  200.                             phone = socket_get_tcp_phone();
  201.                             service = SERVICE_TCP;
  202.                             break;
  203.                         default:
  204.                             return EPROTONOSUPPORT;
  205.                     }
  206.                     break;
  207.                 case SOCK_DGRAM:
  208.                     if( ! protocol ) protocol = IPPROTO_UDP;
  209.                     switch( protocol ){
  210.                         case IPPROTO_UDP:
  211.                             phone = socket_get_udp_phone();
  212.                             service = SERVICE_UDP;
  213.                             break;
  214.                         default:
  215.                             return EPROTONOSUPPORT;
  216.                     }
  217.                     break;
  218.                 case SOCK_RAW:
  219.                 default:
  220.                     return ESOCKTNOSUPPORT;
  221.             }
  222.             break;
  223.         // TODO IPv6
  224.         default:
  225.             return EPFNOSUPPORT;
  226.     }
  227.     assert( phone );
  228.     socket = ( socket_ref ) malloc( sizeof( socket_t ));
  229.     if( ! socket ) return ENOMEM;
  230.     socket_id = async_req_3_0( phone, NET_SOCKET, 0, 0, service );
  231.     if( socket_id > 0 ){
  232.         socket_initialize( socket, socket_id, phone, service );
  233.         if( sockets_add( socket_get_sockets(), socket_id, socket ) != EOK ){
  234.             free( socket );
  235.             async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service );
  236.         }
  237.     }else{
  238.         free( socket );
  239.     }
  240.     return socket_id;
  241. }
  242.  
  243. int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ){
  244.     socket_ref      socket;
  245.     aid_t           message_id;
  246.     ipcarg_t        result;
  247.  
  248.     if( ! data ) return EBADMEM;
  249.     if( ! datalength ) return NO_DATA;
  250.     socket = sockets_find( socket_get_sockets(), socket_id );
  251.     if( ! socket ) return ENOTSOCK;
  252.     message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL );
  253.     ipc_data_write_start( socket->phone, data, datalength );
  254.     async_wait_for( message_id, & result );
  255.     return ( int ) result;
  256. }
  257.  
  258. int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){
  259.     return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen );
  260. }
  261.  
  262. int listen( int socket_id, int backlog ){
  263.     socket_ref      socket;
  264.  
  265.     if( backlog <= 0 ) return EINVAL;
  266.     socket = sockets_find( socket_get_sockets(), socket_id );
  267.     if( ! socket ) return ENOTSOCK;
  268.     return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service );
  269. }
  270.  
  271. int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
  272.     socket_ref      socket;
  273.     aid_t           message_id;
  274.     ipcarg_t        result;
  275.  
  276.     if( ! cliaddr ) return EBADMEM;
  277.     if( ! addrlen ) return NO_DATA;
  278.     socket = sockets_find( socket_get_sockets(), socket_id );
  279.     if( ! socket ) return ENOTSOCK;
  280.     fibril_mutex_lock( & socket->accept_lock );
  281.     while( socket->accepted <= 0 ){
  282.         fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock );
  283.     }
  284.     message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, 0, socket->service, NULL );
  285.     ipc_data_read_start( socket->phone, cliaddr, * addrlen );
  286.     async_wait_for( message_id, & result );
  287.     if( result > 0 ){
  288.         -- socket->accepted;
  289.     }
  290.     fibril_mutex_unlock( & socket->accept_lock );
  291.     return ( int ) result;
  292. }
  293.  
  294. int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){
  295.     return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen );
  296. }
  297.  
  298. int closesocket( int socket_id ){
  299.     socket_ref      socket;
  300.  
  301.     socket = sockets_find( socket_get_sockets(), socket_id );
  302.     if( ! socket ) return ENOTSOCK;
  303.     return async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service );
  304. }
  305.  
  306. int send( int socket_id, void * data, size_t datalength, int flags ){
  307.     return socket_send_data( socket_id, NET_SOCKET_SEND, flags, data, datalength );
  308. }
  309.  
  310. int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
  311.     socket_ref      socket;
  312.     aid_t           message_id;
  313.     ipcarg_t        result;
  314.  
  315.     if( ! toaddr ) return EBADMEM;
  316.     if( ! addrlen ) return NO_DATA;
  317.     if( ! data ) return EBADMEM;
  318.     if( ! datalength ) return NO_DATA;
  319.     socket = sockets_find( socket_get_sockets(), socket_id );
  320.     if( ! socket ) return ENOTSOCK;
  321.     message_id = async_send_3( socket->phone, NET_SOCKET_SENDTO, socket->socket_id, flags, socket->service, NULL );
  322.     if( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK ){
  323.         ipc_data_write_start( socket->phone, data, datalength );
  324.     }
  325.     async_wait_for( message_id, & result );
  326.     return ( int ) result;
  327. }
  328.  
  329. int recv( int socket_id, void * data, size_t datalength, int flags ){
  330.     socket_ref      socket;
  331.     aid_t           message_id;
  332.     ipcarg_t        result;
  333.  
  334.     if( ! data ) return EBADMEM;
  335.     if( ! datalength ) return NO_DATA;
  336.     socket = sockets_find( socket_get_sockets(), socket_id );
  337.     if( ! socket ) return ENOTSOCK;
  338.     fibril_mutex_lock( & socket->receive_lock );
  339.     while( socket->received <= 0 ){
  340.         fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
  341.     }
  342.     message_id = async_send_3( socket->phone, NET_SOCKET_RECV, socket->socket_id, flags, socket->service, NULL );
  343.     ipc_data_read_start( socket->phone, data, datalength );
  344.     async_wait_for( message_id, & result );
  345.     if( result > 0 ){
  346.         -- socket->received;
  347.     }
  348.     fibril_mutex_unlock( & socket->receive_lock );
  349.     return ( int ) result;
  350. }
  351.  
  352. int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
  353.     socket_ref      socket;
  354.     aid_t           message_id;
  355.     ipcarg_t        result;
  356.  
  357.     if( ! fromaddr ) return EBADMEM;
  358.     if( ! addrlen ) return NO_DATA;
  359.     if( ! data ) return EBADMEM;
  360.     if( ! datalength ) return NO_DATA;
  361.     socket = sockets_find( socket_get_sockets(), socket_id );
  362.     if( ! socket ) return ENOTSOCK;
  363.     fibril_mutex_lock( & socket->receive_lock );
  364.     while( socket->received <= 0 ){
  365.         fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
  366.     }
  367.     message_id = async_send_3( socket->phone, NET_SOCKET_RECVFROM, socket->socket_id, flags, socket->service, NULL );
  368.     if( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK ){
  369.         ipc_data_read_start( socket->phone, data, datalength );
  370.     }
  371.     async_wait_for( message_id, & result );
  372.     if( result > 0 ){
  373.         -- socket->received;
  374.     }
  375.     fibril_mutex_unlock( & socket->receive_lock );
  376.     return ( int ) result;
  377. }
  378.  
  379. int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){
  380.     socket_ref      socket;
  381.     aid_t           message_id;
  382.     ipcarg_t        result;
  383.  
  384.     if( ! value ) return EBADMEM;
  385.     if( ! optlen ) return NO_DATA;
  386.     socket = sockets_find( socket_get_sockets(), socket_id );
  387.     if( ! socket ) return ENOTSOCK;
  388.     message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL );
  389.     ipc_data_read_start( socket->phone, value, * optlen );
  390.     async_wait_for( message_id, & result );
  391.     return ( int ) result;
  392. }
  393.  
  394. int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){
  395.     return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen );
  396. }
  397.  
  398. /** @}
  399.  */
  400.