Subversion Repositories HelenOS

Rev

Rev 4589 | Rev 4701 | 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/dynamic_fifo.h"
  53. #include "../structures/int_map.h"
  54.  
  55. #include "socket_messages.h"
  56.  
  57. #define SOCKET_INITIAL_RECEIVED_SIZE    4
  58. #define SOCKET_MAX_RECEIVED_SIZE        64
  59.  
  60. #define SOCKET_INITIAL_ACCEPTED_SIZE    1
  61. #define SOCKET_MAX_ACCEPTED_SIZE        64
  62.  
  63. typedef struct socket   socket_t;
  64. typedef socket_t *      socket_ref;
  65.  
  66. struct socket{
  67.     int                 socket_id;
  68.     int                 phone;
  69.     services_t          service;
  70.     int                 header_size;
  71.     int                 data_fragment_size;
  72.     dyn_fifo_t          received;
  73.     fibril_mutex_t      receive_lock;
  74.     fibril_condvar_t    receive_signal;
  75.     dyn_fifo_t          accepted;
  76.     fibril_mutex_t      accept_lock;
  77.     fibril_condvar_t    accept_signal;
  78. };
  79.  
  80. INT_MAP_DECLARE( sockets, socket_t );
  81.  
  82. static struct{
  83.     int tcp_phone;
  84.     int udp_phone;
  85.     sockets_ref sockets;
  86. } socket_globals = { -1, -1, NULL };
  87.  
  88. INT_MAP_IMPLEMENT( sockets, socket_t );
  89.  
  90. static int  socket_get_tcp_phone();
  91. static int  socket_get_tcp_phone();
  92. static sockets_ref  socket_get_sockets();
  93. void    socket_connection( ipc_callid_t iid, ipc_call_t * icall );
  94. int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength );
  95. void    socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
  96. void    socket_destroy( socket_ref socket );
  97. int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen );
  98. int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen );
  99.  
  100. static int socket_get_tcp_phone(){
  101.     if( socket_globals.tcp_phone < 0 ){
  102.         socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection );
  103.     }
  104.     return socket_globals.tcp_phone;
  105. }
  106.  
  107. static int socket_get_udp_phone(){
  108.     if( socket_globals.udp_phone < 0 ){
  109.         socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection );
  110.     }
  111.     return socket_globals.udp_phone;
  112. }
  113.  
  114. static sockets_ref socket_get_sockets(){
  115.     if( ! socket_globals.sockets ){
  116.         socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t ));
  117.         if( ! socket_globals.sockets ) return NULL;
  118.         if( sockets_initialize( socket_globals.sockets ) != EOK ){
  119.             free( socket_globals.sockets );
  120.             socket_globals.sockets = NULL;
  121.         }
  122.     }
  123.     return socket_globals.sockets;
  124. }
  125.  
  126. void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){
  127.     socket->socket_id = socket_id;
  128.     socket->phone = phone;
  129.     socket->service = service;
  130.     dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE );
  131.     dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE );
  132.     fibril_mutex_initialize( & socket->receive_lock );
  133.     fibril_condvar_initialize( & socket->receive_signal );
  134.     fibril_mutex_initialize( & socket->accept_lock );
  135.     fibril_condvar_initialize( & socket->accept_signal );
  136. }
  137.  
  138. void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){
  139.     ERROR_DECLARE;
  140.  
  141.     ipc_callid_t    callid;
  142.     ipc_call_t      call;
  143.     socket_ref      socket;
  144.     socket_ref      new_socket;
  145.  
  146.     while( true ){
  147.  
  148.         callid = async_get_call( & call );
  149.         switch( IPC_GET_METHOD( call )){
  150.             case NET_SOCKET_RECEIVED:
  151.                 // find the socket
  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->receive_lock );
  158.                 // push the number of received packet fragments
  159.                 if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( & call ), SOCKET_MAX_RECEIVED_SIZE ))){
  160.                     // signal the received packet
  161.                     fibril_condvar_signal( & socket->receive_signal );
  162.                 }
  163.                 fibril_mutex_unlock( & socket->receive_lock );
  164.                 break;
  165.             case NET_SOCKET_ACCEPTED:
  166.                 // find the socket
  167.                 socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
  168.                 if( ! socket ){
  169.                     ERROR_CODE = ENOTSOCK;
  170.                     break;
  171.                 }
  172.                 // create a new scoket
  173.                 new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
  174.                 if( ! new_socket ){
  175.                     ERROR_CODE = ENOMEM;
  176.                     break;
  177.                 }
  178.                 socket_initialize( new_socket, SOCKET_GET_SOCKET_ID( & call ), socket->phone, socket->service );
  179.                 ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket );
  180.                 if( ERROR_CODE < 0 ){
  181.                     free( new_socket );
  182.                 }else{
  183.                     // push the new socket identifier
  184.                     fibril_mutex_lock( & socket->accept_lock );
  185.                     if( ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, new_socket->socket_id, SOCKET_MAX_ACCEPTED_SIZE ))){
  186.                         sockets_exclude( socket_get_sockets(), new_socket->socket_id );
  187.                         free( new_socket );
  188.                     }else{
  189.                         // signal the accepted socket
  190.                         fibril_condvar_signal( & socket->accept_signal );
  191.                     }
  192.                     fibril_mutex_unlock( & socket->accept_lock );
  193.                     ERROR_CODE = EOK;
  194.                 }
  195.                 break;
  196.             case NET_SOCKET_DATA_FRAGMENT_SIZE:
  197.                 // find the socket
  198.                 socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
  199.                 if( ! socket ){
  200.                     ERROR_CODE = ENOTSOCK;
  201.                     break;
  202.                 }
  203.                 // set the data fragment size
  204.                 socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( & call );
  205.                 ERROR_CODE = EOK;
  206.                 break;
  207.             default:
  208.                 ERROR_CODE = ENOTSUP;
  209.         }
  210.         ipc_answer_0( callid, ERROR_CODE );
  211.     }
  212. }
  213.  
  214. int socket( int domain, int type, int protocol ){
  215.     ERROR_DECLARE;
  216.  
  217.     socket_ref  socket;
  218.     int         phone;
  219.     int         socket_id;
  220.     services_t  service;
  221.  
  222.     // find the appropriate service
  223.     switch( domain ){
  224.         case PF_INET:
  225.             switch( type ){
  226.                 case SOCK_STREAM:
  227.                     if( ! protocol ) protocol = IPPROTO_TCP;
  228.                     switch( protocol ){
  229.                         case IPPROTO_TCP:
  230.                             phone = socket_get_tcp_phone();
  231.                             service = SERVICE_TCP;
  232.                             break;
  233.                         default:
  234.                             return EPROTONOSUPPORT;
  235.                     }
  236.                     break;
  237.                 case SOCK_DGRAM:
  238.                     if( ! protocol ) protocol = IPPROTO_UDP;
  239.                     switch( protocol ){
  240.                         case IPPROTO_UDP:
  241.                             phone = socket_get_udp_phone();
  242.                             service = SERVICE_UDP;
  243.                             break;
  244.                         default:
  245.                             return EPROTONOSUPPORT;
  246.                     }
  247.                     break;
  248.                 case SOCK_RAW:
  249.                 default:
  250.                     return ESOCKTNOSUPPORT;
  251.             }
  252.             break;
  253.         // TODO IPv6
  254.         default:
  255.             return EPFNOSUPPORT;
  256.     }
  257.     // create a new socket structure
  258.     socket = ( socket_ref ) malloc( sizeof( socket_t ));
  259.     if( ! socket ) return ENOMEM;
  260.     if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){
  261.         free( socket );
  262.         return ERROR_CODE;
  263.     }
  264.     if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){
  265.         dyn_fifo_destroy( & socket->received );
  266.         free( socket );
  267.         return ERROR_CODE;
  268.     }
  269.     // request a new socket
  270.     if( ERROR_OCCURRED( async_req_3_3( phone, NET_SOCKET, 0, 0, service, ( ipcarg_t * ) & socket_id, ( ipcarg_t * ) & socket->header_size, ( ipcarg_t * ) & socket->data_fragment_size ))){
  271.         dyn_fifo_destroy( & socket->received );
  272.         dyn_fifo_destroy( & socket->accepted );
  273.         free( socket );
  274.         return ERROR_CODE;
  275.     }
  276.     // finish the new socket initialization
  277.     socket_initialize( socket, socket_id, phone, service );
  278.     // store the new socket
  279.     ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket );
  280.     if( ERROR_CODE < 0 ){
  281.         dyn_fifo_destroy( & socket->received );
  282.         dyn_fifo_destroy( & socket->accepted );
  283.         free( socket );
  284.         async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service );
  285.         return ERROR_CODE;
  286.     }
  287.  
  288.     return socket_id;
  289. }
  290.  
  291. int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ){
  292.     socket_ref      socket;
  293.     aid_t           message_id;
  294.     ipcarg_t        result;
  295.  
  296.     if( ! data ) return EBADMEM;
  297.     if( ! datalength ) return NO_DATA;
  298.     // find the socket
  299.     socket = sockets_find( socket_get_sockets(), socket_id );
  300.     if( ! socket ) return ENOTSOCK;
  301.     // request the message
  302.     message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL );
  303.     // send the address
  304.     ipc_data_write_start( socket->phone, data, datalength );
  305.     async_wait_for( message_id, & result );
  306.     return ( int ) result;
  307. }
  308.  
  309. int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){
  310.     // send the address
  311.     return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen );
  312. }
  313.  
  314. int listen( int socket_id, int backlog ){
  315.     socket_ref      socket;
  316.  
  317.     if( backlog <= 0 ) return EINVAL;
  318.     // find the socket
  319.     socket = sockets_find( socket_get_sockets(), socket_id );
  320.     if( ! socket ) return ENOTSOCK;
  321.     // request listen backlog change
  322.     return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service );
  323. }
  324.  
  325. int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
  326.     socket_ref      socket;
  327.     aid_t           message_id;
  328.     int             result;
  329.  
  330.     if( ! cliaddr ) return EBADMEM;
  331.     if( ! addrlen ) return NO_DATA;
  332.     // find the socket
  333.     socket = sockets_find( socket_get_sockets(), socket_id );
  334.     if( ! socket ) return ENOTSOCK;
  335.     fibril_mutex_lock( & socket->accept_lock );
  336.     // wait for an accepted socket
  337.     while( dyn_fifo_value( & socket->accepted ) <= 0 ){
  338.         fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock );
  339.     }
  340.     // request accept
  341.     message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, dyn_fifo_value( & socket->accepted ), socket->service, NULL );
  342.     // read address
  343.     ipc_data_read_start( socket->phone, cliaddr, * addrlen );
  344.     async_wait_for( message_id, ( ipcarg_t * ) & result );
  345.     if( result > 0 ){
  346.         // dequeue the accepted apcket if successful
  347.         dyn_fifo_pop( & socket->accepted );
  348.     }
  349.     fibril_mutex_unlock( & socket->accept_lock );
  350.     return result;
  351. }
  352.  
  353. int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){
  354.     // send the address
  355.     return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen );
  356. }
  357.  
  358. int closesocket( int socket_id ){
  359.     ERROR_DECLARE;
  360.  
  361.     socket_ref      socket;
  362.  
  363.     socket = sockets_find( socket_get_sockets(), socket_id );
  364.     if( ! socket ) return ENOTSOCK;
  365.     // request close
  366.     ERROR_PROPAGATE( async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service ));
  367.     // free the socket structure
  368.     socket_destroy( socket );
  369.     return EOK;
  370. }
  371.  
  372. void socket_destroy( socket_ref socket ){
  373.     int accepted_id;
  374.  
  375.     // destroy all accepted sockets
  376.     while(( accepted_id = dyn_fifo_pop( & socket->accepted ))){
  377.         socket_destroy( sockets_find( socket_get_sockets(), accepted_id ));
  378.     }
  379.     dyn_fifo_destroy( & socket->received );
  380.     dyn_fifo_destroy( & socket->accepted );
  381.     sockets_exclude( socket_get_sockets(), socket->socket_id );
  382. }
  383.  
  384. int send( int socket_id, void * data, size_t datalength, int flags ){
  385.     // without the address
  386.     return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 );
  387. }
  388.  
  389. int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
  390.     if( ! toaddr ) return EBADMEM;
  391.     if( ! addrlen ) return NO_DATA;
  392.     // with the address
  393.     return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen );
  394. }
  395.  
  396. int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
  397.     socket_ref      socket;
  398.     aid_t           message_id;
  399.     ipcarg_t        result;
  400.     int             fragments;
  401.  
  402.     if( ! data ) return EBADMEM;
  403.     if( ! datalength ) return NO_DATA;
  404.     // find socket
  405.     socket = sockets_find( socket_get_sockets(), socket_id );
  406.     if( ! socket ) return ENOTSOCK;
  407.     // compute data fragment count
  408.     fragments = ( datalength + socket->header_size ) / socket->data_fragment_size;
  409.     if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments;
  410.     // request send
  411.     message_id = async_send_4( socket->phone, message, socket->socket_id, fragments, socket->service, flags, NULL );
  412.     // send the address if given
  413.     if(( ! toaddr ) || ( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){
  414.         if( fragments == 1 ){
  415.             // send all if only one fragment
  416.             ipc_data_write_start( socket->phone, data, datalength );
  417.         }else{
  418.             // send the first fragment
  419.             ipc_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size );
  420.             data += socket->data_fragment_size - socket->header_size;
  421.             // send the middle fragments
  422.             while(( -- fragments ) > 1 ){
  423.                 ipc_data_write_start( socket->phone, data, socket->data_fragment_size );
  424.                 data += socket->data_fragment_size;
  425.             }
  426.             // send the last fragment
  427.             ipc_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size );
  428.         }
  429.     }
  430.     async_wait_for( message_id, & result );
  431.     return ( int ) result;
  432. }
  433.  
  434. int recv( int socket_id, void * data, size_t datalength, int flags ){
  435.     // without the address
  436.     return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL );
  437. }
  438.  
  439. int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
  440.     if( ! fromaddr ) return EBADMEM;
  441.     if( ! addrlen ) return NO_DATA;
  442.     // with the address
  443.     return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen );
  444. }
  445.  
  446. int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
  447.     socket_ref      socket;
  448.     aid_t           message_id;
  449.     int             result;
  450.     int             fragments;
  451.     int *           lengths;
  452.     int             index;
  453.     ipc_call_t      answer;
  454.  
  455.     if( ! data ) return EBADMEM;
  456.     if( ! datalength ) return NO_DATA;
  457.     if( fromaddr && (( ! addrlen ) || ( * addrlen < sizeof( struct sockaddr_in )))) return EINVAL;
  458.     // find the socket
  459.     socket = sockets_find( socket_get_sockets(), socket_id );
  460.     if( ! socket ) return ENOTSOCK;
  461.     fibril_mutex_lock( & socket->receive_lock );
  462.     // wait for a received packet
  463.     while(( fragments = dyn_fifo_value( & socket->received )) <= 0 ){
  464.         fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
  465.     }
  466.     // prepare lengths if more fragments
  467.     if( fragments > 1 ){
  468.         lengths = ( int * ) malloc( sizeof( int ) * ( fragments + 1 ));
  469.         if( ! lengths ){
  470.             fibril_mutex_unlock( & socket->receive_lock );
  471.             return ENOMEM;
  472.         }
  473.     }
  474.     // request packet data
  475.     message_id = async_send_4( socket->phone, message, socket->socket_id, 0, socket->service, flags, & answer );
  476.     // read the address if desired
  477.     if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){
  478.         if( fragments == 1 ){
  479.             // read all if only one fragment
  480.             ipc_data_read_start( socket->phone, data, datalength );
  481.         }else{
  482.         // read the fragment lengths
  483.             if( ipc_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){
  484.                 if( lengths[ fragments ] <= datalength ){
  485.                 // read all fragments if long enough
  486.                     for( index = 0; index < fragments; ++ index ){
  487.                         ipc_data_read_start( socket->phone, data, lengths[ index ] );
  488.                         data += lengths[ index ];
  489.                     }
  490.                 }
  491.             }
  492.             free( lengths );
  493.         }
  494.     }else if( fragments > 1 ){
  495.         free( lengths );
  496.     }
  497.     async_wait_for( message_id, ( ipcarg_t * ) & result );
  498.     // if successful
  499.     if( result == EOK ){
  500.         // dequeue the received packet
  501.         dyn_fifo_pop( & socket->received );
  502.         // return read data length
  503.         result = SOCKET_GET_READ_DATA_LENGTH( & answer );
  504.         // set address length
  505.         if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( & answer );
  506.     }
  507.     fibril_mutex_unlock( & socket->receive_lock );
  508.     return result;
  509. }
  510.  
  511. int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){
  512.     socket_ref      socket;
  513.     aid_t           message_id;
  514.     ipcarg_t        result;
  515.  
  516.     if( !( value && optlen )) return EBADMEM;
  517.     if( !( * optlen )) return NO_DATA;
  518.     // find the socket
  519.     socket = sockets_find( socket_get_sockets(), socket_id );
  520.     if( ! socket ) return ENOTSOCK;
  521.     // request option value
  522.     message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL );
  523.     // read the length
  524.     if( ipc_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){
  525.         // read the value
  526.         ipc_data_read_start( socket->phone, value, * optlen );
  527.     }
  528.     async_wait_for( message_id, & result );
  529.     return ( int ) result;
  530. }
  531.  
  532. int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){
  533.     // send the value
  534.     return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen );
  535.  
  536. }
  537.  
  538. /** @}
  539.  */
  540.