Rev 4747 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 4578 | mejdrech | 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> |
||
| 4582 | mejdrech | 41 | #include <fibril_sync.h> |
| 4578 | mejdrech | 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 | |||
| 4589 | mejdrech | 52 | #include "../structures/dynamic_fifo.h" |
| 4578 | mejdrech | 53 | #include "../structures/int_map.h" |
| 54 | |||
| 55 | #include "socket_messages.h" |
||
| 56 | |||
| 4701 | mejdrech | 57 | /** Initial received packet queue size. |
| 58 | */ |
||
| 4589 | mejdrech | 59 | #define SOCKET_INITIAL_RECEIVED_SIZE 4 |
| 4701 | mejdrech | 60 | |
| 61 | /** Maximum received packet queue size. |
||
| 62 | */ |
||
| 4747 | mejdrech | 63 | #define SOCKET_MAX_RECEIVED_SIZE 0 |
| 4589 | mejdrech | 64 | |
| 4701 | mejdrech | 65 | /** Initial waiting sockets queue size. |
| 66 | */ |
||
| 4589 | mejdrech | 67 | #define SOCKET_INITIAL_ACCEPTED_SIZE 1 |
| 4701 | mejdrech | 68 | |
| 69 | /** Maximum waiting sockets queue size. |
||
| 70 | */ |
||
| 4747 | mejdrech | 71 | #define SOCKET_MAX_ACCEPTED_SIZE 0 |
| 4589 | mejdrech | 72 | |
| 4701 | mejdrech | 73 | /** Type definition of the socket specific data. |
| 74 | * @see socket |
||
| 75 | */ |
||
| 4578 | mejdrech | 76 | typedef struct socket socket_t; |
| 77 | |||
| 4701 | mejdrech | 78 | /** Type definition of the socket specific data pointer. |
| 79 | * @see socket |
||
| 80 | */ |
||
| 81 | typedef socket_t * socket_ref; |
||
| 82 | |||
| 83 | /** Socket specific data. |
||
| 4726 | mejdrech | 84 | * Each socket lock locks only its structure part and any number of them may be locked simultaneously. |
| 4701 | mejdrech | 85 | */ |
| 4578 | mejdrech | 86 | struct socket{ |
| 4701 | mejdrech | 87 | /** Socket identifier. |
| 88 | */ |
||
| 4578 | mejdrech | 89 | int socket_id; |
| 4701 | mejdrech | 90 | /** Parent module phone. |
| 91 | */ |
||
| 4578 | mejdrech | 92 | int phone; |
| 4701 | mejdrech | 93 | /** Parent module service. |
| 94 | */ |
||
| 4578 | mejdrech | 95 | services_t service; |
| 4701 | mejdrech | 96 | /** Underlying protocol header size. |
| 97 | * Sending and receiving optimalization. |
||
| 98 | */ |
||
| 4708 | mejdrech | 99 | size_t header_size; |
| 4701 | mejdrech | 100 | /** Packet data fragment size. |
| 4726 | mejdrech | 101 | * Sending optimalization. |
| 4701 | mejdrech | 102 | */ |
| 4708 | mejdrech | 103 | size_t data_fragment_size; |
| 4726 | mejdrech | 104 | /** Sending safety lock. |
| 105 | * Locks the header_size and data_fragment_size attributes. |
||
| 106 | */ |
||
| 107 | fibril_rwlock_t sending_lock; |
||
| 4701 | mejdrech | 108 | /** Received packets queue. |
| 109 | */ |
||
| 4589 | mejdrech | 110 | dyn_fifo_t received; |
| 4701 | mejdrech | 111 | /** Received packets safety lock. |
| 4726 | mejdrech | 112 | * Used for receiving and receive notifications. |
| 113 | * Locks the received attribute. |
||
| 4701 | mejdrech | 114 | */ |
| 4582 | mejdrech | 115 | fibril_mutex_t receive_lock; |
| 4701 | mejdrech | 116 | /** Received packets signaling. |
| 4726 | mejdrech | 117 | * Signaled upon receive notification. |
| 4701 | mejdrech | 118 | */ |
| 4582 | mejdrech | 119 | fibril_condvar_t receive_signal; |
| 4701 | mejdrech | 120 | /** Waiting sockets queue. |
| 121 | */ |
||
| 4589 | mejdrech | 122 | dyn_fifo_t accepted; |
| 4701 | mejdrech | 123 | /** Waiting sockets safety lock. |
| 4726 | mejdrech | 124 | * Used for accepting and accept notifications. |
| 125 | * Locks the accepted attribute. |
||
| 4701 | mejdrech | 126 | */ |
| 4582 | mejdrech | 127 | fibril_mutex_t accept_lock; |
| 4701 | mejdrech | 128 | /** Waiting sockets signaling. |
| 4726 | mejdrech | 129 | * Signaled upon accept notification. |
| 4701 | mejdrech | 130 | */ |
| 4582 | mejdrech | 131 | fibril_condvar_t accept_signal; |
| 4726 | mejdrech | 132 | /** The number of blocked functions called. |
| 133 | * Used while waiting for the received packets or accepted sockets. |
||
| 134 | */ |
||
| 135 | int blocked; |
||
| 4578 | mejdrech | 136 | }; |
| 137 | |||
| 4701 | mejdrech | 138 | /** Sockets map. |
| 139 | * Maps socket identifiers to the socket specific data. |
||
| 140 | * @see int_map.h |
||
| 141 | */ |
||
| 4578 | mejdrech | 142 | INT_MAP_DECLARE( sockets, socket_t ); |
| 143 | |||
| 4701 | mejdrech | 144 | /** Socket client library global data. |
| 145 | */ |
||
| 4726 | mejdrech | 146 | static struct socket_client_globals { |
| 4701 | mejdrech | 147 | /** TCP module phone. |
| 148 | */ |
||
| 4578 | mejdrech | 149 | int tcp_phone; |
| 4701 | mejdrech | 150 | /** UDP module phone. |
| 151 | */ |
||
| 4578 | mejdrech | 152 | int udp_phone; |
| 4701 | mejdrech | 153 | /** Active sockets. |
| 154 | */ |
||
| 4578 | mejdrech | 155 | sockets_ref sockets; |
| 4726 | mejdrech | 156 | /** Safety lock. |
| 157 | * Write lock is used only for adding or removing sockets. |
||
| 158 | * When locked for writing, no other socket locks need to be locked. |
||
| 159 | * When locked for reading, any other socket locks may be locked. |
||
| 160 | * No socket lock may be locked if this lock is unlocked. |
||
| 161 | */ |
||
| 162 | fibril_rwlock_t lock; |
||
| 163 | } socket_globals = { |
||
| 164 | .tcp_phone = -1, |
||
| 165 | .udp_phone = -1, |
||
| 166 | .sockets = NULL, |
||
| 167 | .lock = { |
||
| 168 | .readers = 0, |
||
| 169 | .writers = 0, |
||
| 170 | .waiters = { |
||
| 171 | .prev = & socket_globals.lock.waiters, |
||
| 172 | .next = & socket_globals.lock.waiters |
||
| 173 | } |
||
| 174 | } |
||
| 175 | }; |
||
| 4578 | mejdrech | 176 | |
| 177 | INT_MAP_IMPLEMENT( sockets, socket_t ); |
||
| 178 | |||
| 4701 | mejdrech | 179 | /** Returns the TCP module phone. |
| 180 | * Connects to the TCP module if necessary. |
||
| 181 | * @returns The TCP module phone. |
||
| 182 | */ |
||
| 4708 | mejdrech | 183 | static int socket_get_tcp_phone( void ); |
| 4701 | mejdrech | 184 | |
| 185 | /** Returns the UDP module phone. |
||
| 186 | * Connects to the UDP module if necessary. |
||
| 187 | * @returns The UDP module phone. |
||
| 188 | */ |
||
| 4708 | mejdrech | 189 | static int socket_get_udp_phone( void ); |
| 4701 | mejdrech | 190 | |
| 191 | /** Returns the active sockets. |
||
| 192 | * @returns The active sockets. |
||
| 193 | */ |
||
| 4708 | mejdrech | 194 | static sockets_ref socket_get_sockets( void ); |
| 4701 | mejdrech | 195 | |
| 196 | /** Default thread for new connections. |
||
| 4756 | mejdrech | 197 | * @param[in] iid The initial message identifier. |
| 198 | * @param[in] icall The initial message call structure. |
||
| 4701 | mejdrech | 199 | */ |
| 4578 | mejdrech | 200 | void socket_connection( ipc_callid_t iid, ipc_call_t * icall ); |
| 4701 | mejdrech | 201 | |
| 202 | /** Sends message to the socket parent module with specified data. |
||
| 4756 | mejdrech | 203 | * @param[in] socket_id Socket identifier. |
| 204 | * @param[in] message The action message. |
||
| 205 | * @param[in] arg2 The second message parameter. |
||
| 206 | * @param[in] data The data to be sent. |
||
| 207 | * @param[in] datalength The data length. |
||
| 4701 | mejdrech | 208 | * @returns EOK on success. |
| 209 | * @returns ENOTSOCK if the socket is not found. |
||
| 210 | * @returns EBADMEM if the data parameter is NULL. |
||
| 211 | * @returns NO_DATA if the datalength parameter is zero (0). |
||
| 212 | * @returns Other error codes as defined for the spcific message. |
||
| 213 | */ |
||
| 4708 | mejdrech | 214 | int socket_send_data( int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength ); |
| 4701 | mejdrech | 215 | |
| 216 | /** Initializes a new socket specific data. |
||
| 4756 | mejdrech | 217 | * @param[in,out] socket The socket to be initialized. |
| 218 | * @param[in] socket_id The new socket identifier. |
||
| 219 | * @param[in] phone The parent module phone. |
||
| 220 | * @param[in] service The parent module service. |
||
| 4701 | mejdrech | 221 | */ |
| 4578 | mejdrech | 222 | void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ); |
| 4701 | mejdrech | 223 | |
| 224 | /** Clears and destroys the socket. |
||
| 4756 | mejdrech | 225 | * @param[in] socket The socket to be destroyed. |
| 4701 | mejdrech | 226 | */ |
| 4589 | mejdrech | 227 | void socket_destroy( socket_ref socket ); |
| 4701 | mejdrech | 228 | |
| 229 | /** Receives data via the socket. |
||
| 4756 | mejdrech | 230 | * @param[in] message The action message. |
| 231 | * @param[in] socket_id Socket identifier. |
||
| 232 | * @param[out] data The data buffer to be filled. |
||
| 233 | * @param[in] datalength The data length. |
||
| 234 | * @param[in] flags Various receive flags. |
||
| 235 | * @param[out] fromaddr The source address. May be NULL for connected sockets. |
||
| 236 | * @param[in,out] addrlen The address length. The maximum address length is read. The actual address length is set. Used only if fromaddr is not NULL. |
||
| 4701 | mejdrech | 237 | * @returns EOK on success. |
| 238 | * @returns ENOTSOCK if the socket is not found. |
||
| 239 | * @returns EBADMEM if the data parameter is NULL. |
||
| 240 | * @returns NO_DATA if the datalength or addrlen parameter is zero (0). |
||
| 241 | * @returns Other error codes as defined for the spcific message. |
||
| 242 | */ |
||
| 4708 | mejdrech | 243 | int recvfrom_core( ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ); |
| 4701 | mejdrech | 244 | |
| 245 | /** Sends data via the socket to the remote address. |
||
| 246 | * Binds the socket to a free port if not already connected/bound. |
||
| 4756 | mejdrech | 247 | * @param[in] message The action message. |
| 248 | * @param[in] socket_id Socket identifier. |
||
| 249 | * @param[in] data The data to be sent. |
||
| 250 | * @param[in] datalength The data length. |
||
| 251 | * @param[in] flags Various send flags. |
||
| 252 | * @param[in] toaddr The destination address. May be NULL for connected sockets. |
||
| 253 | * @param[in] addrlen The address length. Used only if toaddr is not NULL. |
||
| 4701 | mejdrech | 254 | * @returns EOK on success. |
| 255 | * @returns ENOTSOCK if the socket is not found. |
||
| 256 | * @returns EBADMEM if the data or toaddr parameter is NULL. |
||
| 257 | * @returns NO_DATA if the datalength or the addrlen parameter is zero (0). |
||
| 258 | * @returns Other error codes as defined for the NET_SOCKET_SENDTO message. |
||
| 259 | */ |
||
| 4708 | mejdrech | 260 | int sendto_core( ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ); |
| 4578 | mejdrech | 261 | |
| 4708 | mejdrech | 262 | static int socket_get_tcp_phone( void ){ |
| 4578 | mejdrech | 263 | if( socket_globals.tcp_phone < 0 ){ |
| 264 | socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection ); |
||
| 265 | } |
||
| 266 | return socket_globals.tcp_phone; |
||
| 267 | } |
||
| 268 | |||
| 4708 | mejdrech | 269 | static int socket_get_udp_phone( void ){ |
| 4578 | mejdrech | 270 | if( socket_globals.udp_phone < 0 ){ |
| 271 | socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection ); |
||
| 272 | } |
||
| 273 | return socket_globals.udp_phone; |
||
| 274 | } |
||
| 275 | |||
| 4708 | mejdrech | 276 | static sockets_ref socket_get_sockets( void ){ |
| 4578 | mejdrech | 277 | if( ! socket_globals.sockets ){ |
| 278 | socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t )); |
||
| 279 | if( ! socket_globals.sockets ) return NULL; |
||
| 280 | if( sockets_initialize( socket_globals.sockets ) != EOK ){ |
||
| 281 | free( socket_globals.sockets ); |
||
| 282 | socket_globals.sockets = NULL; |
||
| 283 | } |
||
| 284 | } |
||
| 285 | return socket_globals.sockets; |
||
| 286 | } |
||
| 287 | |||
| 288 | void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){ |
||
| 289 | socket->socket_id = socket_id; |
||
| 290 | socket->phone = phone; |
||
| 291 | socket->service = service; |
||
| 4589 | mejdrech | 292 | dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ); |
| 293 | dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ); |
||
| 4582 | mejdrech | 294 | fibril_mutex_initialize( & socket->receive_lock ); |
| 295 | fibril_condvar_initialize( & socket->receive_signal ); |
||
| 296 | fibril_mutex_initialize( & socket->accept_lock ); |
||
| 297 | fibril_condvar_initialize( & socket->accept_signal ); |
||
| 4726 | mejdrech | 298 | fibril_rwlock_initialize( & socket->sending_lock ); |
| 4578 | mejdrech | 299 | } |
| 300 | |||
| 301 | void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){ |
||
| 302 | ERROR_DECLARE; |
||
| 303 | |||
| 304 | ipc_callid_t callid; |
||
| 305 | ipc_call_t call; |
||
| 306 | socket_ref socket; |
||
| 307 | socket_ref new_socket; |
||
| 308 | |||
| 309 | while( true ){ |
||
| 310 | |||
| 311 | callid = async_get_call( & call ); |
||
| 312 | switch( IPC_GET_METHOD( call )){ |
||
| 313 | case NET_SOCKET_RECEIVED: |
||
| 4726 | mejdrech | 314 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 315 | // find the socket |
| 4701 | mejdrech | 316 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call )); |
| 4578 | mejdrech | 317 | if( ! socket ){ |
| 318 | ERROR_CODE = ENOTSOCK; |
||
| 4726 | mejdrech | 319 | }else{ |
| 320 | fibril_mutex_lock( & socket->receive_lock ); |
||
| 321 | // push the number of received packet fragments |
||
| 322 | if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_MAX_RECEIVED_SIZE ))){ |
||
| 323 | // signal the received packet |
||
| 324 | fibril_condvar_signal( & socket->receive_signal ); |
||
| 325 | } |
||
| 326 | fibril_mutex_unlock( & socket->receive_lock ); |
||
| 4578 | mejdrech | 327 | } |
| 4726 | mejdrech | 328 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4578 | mejdrech | 329 | break; |
| 330 | case NET_SOCKET_ACCEPTED: |
||
| 4726 | mejdrech | 331 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 332 | // find the socket |
| 4701 | mejdrech | 333 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call )); |
| 4578 | mejdrech | 334 | if( ! socket ){ |
| 335 | ERROR_CODE = ENOTSOCK; |
||
| 4589 | mejdrech | 336 | }else{ |
| 4726 | mejdrech | 337 | // create a new scoket |
| 338 | new_socket = ( socket_ref ) malloc( sizeof( socket_t )); |
||
| 339 | if( ! new_socket ){ |
||
| 340 | ERROR_CODE = ENOMEM; |
||
| 4589 | mejdrech | 341 | }else{ |
| 4743 | mejdrech | 342 | bzero( new_socket, sizeof( * new_socket )); |
| 343 | socket_initialize( new_socket, SOCKET_GET_NEW_SOCKET_ID( call ), socket->phone, socket->service ); |
||
| 4726 | mejdrech | 344 | ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket ); |
| 345 | if( ERROR_CODE < 0 ){ |
||
| 346 | free( new_socket ); |
||
| 347 | }else{ |
||
| 348 | // push the new socket identifier |
||
| 349 | fibril_mutex_lock( & socket->accept_lock ); |
||
| 350 | if( ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, new_socket->socket_id, SOCKET_MAX_ACCEPTED_SIZE ))){ |
||
| 351 | sockets_exclude( socket_get_sockets(), new_socket->socket_id ); |
||
| 352 | }else{ |
||
| 353 | // signal the accepted socket |
||
| 354 | fibril_condvar_signal( & socket->accept_signal ); |
||
| 355 | } |
||
| 356 | fibril_mutex_unlock( & socket->accept_lock ); |
||
| 357 | ERROR_CODE = EOK; |
||
| 358 | } |
||
| 4589 | mejdrech | 359 | } |
| 4578 | mejdrech | 360 | } |
| 4726 | mejdrech | 361 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4578 | mejdrech | 362 | break; |
| 4589 | mejdrech | 363 | case NET_SOCKET_DATA_FRAGMENT_SIZE: |
| 4726 | mejdrech | 364 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 365 | // find the socket |
| 4701 | mejdrech | 366 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call )); |
| 4578 | mejdrech | 367 | if( ! socket ){ |
| 368 | ERROR_CODE = ENOTSOCK; |
||
| 4726 | mejdrech | 369 | }else{ |
| 370 | fibril_rwlock_write_lock( & socket->sending_lock ); |
||
| 371 | // set the data fragment size |
||
| 372 | socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( call ); |
||
| 373 | fibril_rwlock_write_unlock( & socket->sending_lock ); |
||
| 374 | ERROR_CODE = EOK; |
||
| 4578 | mejdrech | 375 | } |
| 4726 | mejdrech | 376 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4578 | mejdrech | 377 | break; |
| 4589 | mejdrech | 378 | default: |
| 4578 | mejdrech | 379 | ERROR_CODE = ENOTSUP; |
| 380 | } |
||
| 4708 | mejdrech | 381 | ipc_answer_0( callid, ( ipcarg_t ) ERROR_CODE ); |
| 4578 | mejdrech | 382 | } |
| 383 | } |
||
| 384 | |||
| 385 | int socket( int domain, int type, int protocol ){ |
||
| 4589 | mejdrech | 386 | ERROR_DECLARE; |
| 387 | |||
| 4578 | mejdrech | 388 | socket_ref socket; |
| 389 | int phone; |
||
| 390 | int socket_id; |
||
| 391 | services_t service; |
||
| 392 | |||
| 4589 | mejdrech | 393 | // find the appropriate service |
| 4578 | mejdrech | 394 | switch( domain ){ |
| 395 | case PF_INET: |
||
| 396 | switch( type ){ |
||
| 397 | case SOCK_STREAM: |
||
| 398 | if( ! protocol ) protocol = IPPROTO_TCP; |
||
| 399 | switch( protocol ){ |
||
| 400 | case IPPROTO_TCP: |
||
| 401 | phone = socket_get_tcp_phone(); |
||
| 402 | service = SERVICE_TCP; |
||
| 403 | break; |
||
| 404 | default: |
||
| 405 | return EPROTONOSUPPORT; |
||
| 406 | } |
||
| 407 | break; |
||
| 408 | case SOCK_DGRAM: |
||
| 409 | if( ! protocol ) protocol = IPPROTO_UDP; |
||
| 410 | switch( protocol ){ |
||
| 411 | case IPPROTO_UDP: |
||
| 412 | phone = socket_get_udp_phone(); |
||
| 413 | service = SERVICE_UDP; |
||
| 414 | break; |
||
| 415 | default: |
||
| 416 | return EPROTONOSUPPORT; |
||
| 417 | } |
||
| 418 | break; |
||
| 419 | case SOCK_RAW: |
||
| 420 | default: |
||
| 421 | return ESOCKTNOSUPPORT; |
||
| 422 | } |
||
| 423 | break; |
||
| 424 | // TODO IPv6 |
||
| 425 | default: |
||
| 426 | return EPFNOSUPPORT; |
||
| 427 | } |
||
| 4589 | mejdrech | 428 | // create a new socket structure |
| 4578 | mejdrech | 429 | socket = ( socket_ref ) malloc( sizeof( socket_t )); |
| 430 | if( ! socket ) return ENOMEM; |
||
| 4736 | mejdrech | 431 | bzero( socket, sizeof( * socket )); |
| 4589 | mejdrech | 432 | // request a new socket |
| 4726 | mejdrech | 433 | if( ERROR_OCCURRED(( int ) async_req_3_3( phone, NET_SOCKET, 0, 0, service, ( ipcarg_t * ) & socket_id, ( ipcarg_t * ) & socket->data_fragment_size, ( ipcarg_t * ) & socket->header_size ))){ |
| 4589 | mejdrech | 434 | free( socket ); |
| 435 | return ERROR_CODE; |
||
| 436 | } |
||
| 437 | // finish the new socket initialization |
||
| 438 | socket_initialize( socket, socket_id, phone, service ); |
||
| 439 | // store the new socket |
||
| 4726 | mejdrech | 440 | fibril_rwlock_write_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 441 | ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket ); |
| 4726 | mejdrech | 442 | fibril_rwlock_write_unlock( & socket_globals.lock ); |
| 4589 | mejdrech | 443 | if( ERROR_CODE < 0 ){ |
| 444 | dyn_fifo_destroy( & socket->received ); |
||
| 445 | dyn_fifo_destroy( & socket->accepted ); |
||
| 446 | free( socket ); |
||
| 4708 | mejdrech | 447 | async_msg_3( phone, NET_SOCKET_CLOSE, ( ipcarg_t ) socket_id, 0, service ); |
| 4589 | mejdrech | 448 | return ERROR_CODE; |
| 449 | } |
||
| 450 | |||
| 4578 | mejdrech | 451 | return socket_id; |
| 452 | } |
||
| 453 | |||
| 4708 | mejdrech | 454 | int socket_send_data( int socket_id, ipcarg_t message, ipcarg_t arg2, const void * data, size_t datalength ){ |
| 4578 | mejdrech | 455 | socket_ref socket; |
| 456 | aid_t message_id; |
||
| 457 | ipcarg_t result; |
||
| 458 | |||
| 459 | if( ! data ) return EBADMEM; |
||
| 460 | if( ! datalength ) return NO_DATA; |
||
| 4726 | mejdrech | 461 | |
| 462 | fibril_rwlock_read_lock( & socket_globals.lock ); |
||
| 4589 | mejdrech | 463 | // find the socket |
| 4578 | mejdrech | 464 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 465 | if( ! socket ){ |
| 466 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 467 | return ENOTSOCK; |
||
| 468 | } |
||
| 4589 | mejdrech | 469 | // request the message |
| 4708 | mejdrech | 470 | message_id = async_send_3( socket->phone, message, ( ipcarg_t ) socket->socket_id, arg2, socket->service, NULL ); |
| 4589 | mejdrech | 471 | // send the address |
| 4578 | mejdrech | 472 | ipc_data_write_start( socket->phone, data, datalength ); |
| 4726 | mejdrech | 473 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4578 | mejdrech | 474 | async_wait_for( message_id, & result ); |
| 475 | return ( int ) result; |
||
| 476 | } |
||
| 477 | |||
| 478 | int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){ |
||
| 4708 | mejdrech | 479 | if( addrlen <= 0 ) return EINVAL; |
| 4589 | mejdrech | 480 | // send the address |
| 4708 | mejdrech | 481 | return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, ( size_t ) addrlen ); |
| 4578 | mejdrech | 482 | } |
| 483 | |||
| 484 | int listen( int socket_id, int backlog ){ |
||
| 4726 | mejdrech | 485 | socket_ref socket; |
| 486 | int result; |
||
| 4578 | mejdrech | 487 | |
| 488 | if( backlog <= 0 ) return EINVAL; |
||
| 4726 | mejdrech | 489 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 490 | // find the socket |
| 4578 | mejdrech | 491 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 492 | if( ! socket ){ |
| 493 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 494 | return ENOTSOCK; |
||
| 495 | } |
||
| 4589 | mejdrech | 496 | // request listen backlog change |
| 4726 | mejdrech | 497 | result = ( int ) async_req_3_0( socket->phone, NET_SOCKET_LISTEN, ( ipcarg_t ) socket->socket_id, ( ipcarg_t ) backlog, socket->service ); |
| 498 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 499 | return result; |
||
| 4578 | mejdrech | 500 | } |
| 501 | |||
| 502 | int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){ |
||
| 503 | socket_ref socket; |
||
| 504 | aid_t message_id; |
||
| 4589 | mejdrech | 505 | int result; |
| 4743 | mejdrech | 506 | ipc_call_t answer; |
| 4578 | mejdrech | 507 | |
| 4701 | mejdrech | 508 | if(( ! cliaddr ) || ( ! addrlen )) return EBADMEM; |
| 4726 | mejdrech | 509 | |
| 510 | fibril_rwlock_read_lock( & socket_globals.lock ); |
||
| 4589 | mejdrech | 511 | // find the socket |
| 4578 | mejdrech | 512 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 513 | if( ! socket ){ |
| 514 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 515 | return ENOTSOCK; |
||
| 516 | } |
||
| 4582 | mejdrech | 517 | fibril_mutex_lock( & socket->accept_lock ); |
| 4589 | mejdrech | 518 | // wait for an accepted socket |
| 4726 | mejdrech | 519 | ++ socket->blocked; |
| 4589 | mejdrech | 520 | while( dyn_fifo_value( & socket->accepted ) <= 0 ){ |
| 4726 | mejdrech | 521 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4582 | mejdrech | 522 | fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock ); |
| 4726 | mejdrech | 523 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4578 | mejdrech | 524 | } |
| 4726 | mejdrech | 525 | -- socket->blocked; |
| 4589 | mejdrech | 526 | // request accept |
| 4743 | mejdrech | 527 | message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, ( ipcarg_t ) socket->socket_id, 0, socket->service, & answer ); |
| 4589 | mejdrech | 528 | // read address |
| 4578 | mejdrech | 529 | ipc_data_read_start( socket->phone, cliaddr, * addrlen ); |
| 4726 | mejdrech | 530 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4589 | mejdrech | 531 | async_wait_for( message_id, ( ipcarg_t * ) & result ); |
| 4578 | mejdrech | 532 | if( result > 0 ){ |
| 4743 | mejdrech | 533 | // dequeue the accepted socket if successful |
| 4589 | mejdrech | 534 | dyn_fifo_pop( & socket->accepted ); |
| 4743 | mejdrech | 535 | // set address length |
| 536 | * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer ); |
||
| 537 | }else if( result == ENOTSOCK ){ |
||
| 538 | // empty the queue if no accepted sockets |
||
| 539 | while( dyn_fifo_pop( & socket->accepted ) > 0 ); |
||
| 4578 | mejdrech | 540 | } |
| 4582 | mejdrech | 541 | fibril_mutex_unlock( & socket->accept_lock ); |
| 4589 | mejdrech | 542 | return result; |
| 4578 | mejdrech | 543 | } |
| 544 | |||
| 545 | int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){ |
||
| 4736 | mejdrech | 546 | if( ! serv_addr ) return EDESTADDRREQ; |
| 547 | if( ! addrlen ) return EDESTADDRREQ; |
||
| 4589 | mejdrech | 548 | // send the address |
| 4578 | mejdrech | 549 | return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen ); |
| 550 | } |
||
| 551 | |||
| 552 | int closesocket( int socket_id ){ |
||
| 4589 | mejdrech | 553 | ERROR_DECLARE; |
| 554 | |||
| 4578 | mejdrech | 555 | socket_ref socket; |
| 556 | |||
| 4729 | mejdrech | 557 | fibril_rwlock_write_lock( & socket_globals.lock ); |
| 4578 | mejdrech | 558 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 559 | if( ! socket ){ |
| 560 | fibril_rwlock_write_unlock( & socket_globals.lock ); |
||
| 561 | return ENOTSOCK; |
||
| 562 | } |
||
| 563 | if( socket->blocked ){ |
||
| 564 | fibril_rwlock_write_unlock( & socket_globals.lock ); |
||
| 565 | return EINPROGRESS; |
||
| 566 | } |
||
| 4589 | mejdrech | 567 | // request close |
| 4708 | mejdrech | 568 | ERROR_PROPAGATE(( int ) async_req_3_0( socket->phone, NET_SOCKET_CLOSE, ( ipcarg_t ) socket->socket_id, 0, socket->service )); |
| 4589 | mejdrech | 569 | // free the socket structure |
| 570 | socket_destroy( socket ); |
||
| 4726 | mejdrech | 571 | fibril_rwlock_write_unlock( & socket_globals.lock ); |
| 4589 | mejdrech | 572 | return EOK; |
| 4578 | mejdrech | 573 | } |
| 574 | |||
| 4589 | mejdrech | 575 | void socket_destroy( socket_ref socket ){ |
| 576 | int accepted_id; |
||
| 577 | |||
| 578 | // destroy all accepted sockets |
||
| 4701 | mejdrech | 579 | while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){ |
| 4589 | mejdrech | 580 | socket_destroy( sockets_find( socket_get_sockets(), accepted_id )); |
| 581 | } |
||
| 582 | dyn_fifo_destroy( & socket->received ); |
||
| 583 | dyn_fifo_destroy( & socket->accepted ); |
||
| 584 | sockets_exclude( socket_get_sockets(), socket->socket_id ); |
||
| 585 | } |
||
| 586 | |||
| 4578 | mejdrech | 587 | int send( int socket_id, void * data, size_t datalength, int flags ){ |
| 4589 | mejdrech | 588 | // without the address |
| 589 | return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 ); |
||
| 4578 | mejdrech | 590 | } |
| 591 | |||
| 592 | int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){ |
||
| 4736 | mejdrech | 593 | if( ! toaddr ) return EDESTADDRREQ; |
| 594 | if( ! addrlen ) return EDESTADDRREQ; |
||
| 4589 | mejdrech | 595 | // with the address |
| 596 | return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen ); |
||
| 4578 | mejdrech | 597 | } |
| 598 | |||
| 4708 | mejdrech | 599 | int sendto_core( ipcarg_t message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){ |
| 4578 | mejdrech | 600 | socket_ref socket; |
| 601 | aid_t message_id; |
||
| 602 | ipcarg_t result; |
||
| 4708 | mejdrech | 603 | size_t fragments; |
| 4578 | mejdrech | 604 | |
| 605 | if( ! data ) return EBADMEM; |
||
| 606 | if( ! datalength ) return NO_DATA; |
||
| 4726 | mejdrech | 607 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 608 | // find socket |
| 4578 | mejdrech | 609 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 610 | if( ! socket ){ |
| 611 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 612 | return ENOTSOCK; |
||
| 613 | } |
||
| 614 | fibril_rwlock_read_lock( & socket->sending_lock ); |
||
| 4589 | mejdrech | 615 | // compute data fragment count |
| 616 | fragments = ( datalength + socket->header_size ) / socket->data_fragment_size; |
||
| 617 | if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments; |
||
| 618 | // request send |
||
| 4726 | mejdrech | 619 | message_id = async_send_5( socket->phone, message, ( ipcarg_t ) socket->socket_id, socket->data_fragment_size, socket->service, ( ipcarg_t ) flags, fragments, NULL ); |
| 4589 | mejdrech | 620 | // send the address if given |
| 621 | if(( ! toaddr ) || ( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){ |
||
| 622 | if( fragments == 1 ){ |
||
| 623 | // send all if only one fragment |
||
| 624 | ipc_data_write_start( socket->phone, data, datalength ); |
||
| 625 | }else{ |
||
| 626 | // send the first fragment |
||
| 627 | ipc_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size ); |
||
| 4708 | mejdrech | 628 | data = (( const uint8_t * ) data ) + socket->data_fragment_size - socket->header_size; |
| 4589 | mejdrech | 629 | // send the middle fragments |
| 630 | while(( -- fragments ) > 1 ){ |
||
| 631 | ipc_data_write_start( socket->phone, data, socket->data_fragment_size ); |
||
| 4708 | mejdrech | 632 | data = (( const uint8_t * ) data ) + socket->data_fragment_size; |
| 4589 | mejdrech | 633 | } |
| 634 | // send the last fragment |
||
| 635 | ipc_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size ); |
||
| 636 | } |
||
| 4578 | mejdrech | 637 | } |
| 4726 | mejdrech | 638 | fibril_rwlock_read_unlock( & socket->sending_lock ); |
| 639 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 4578 | mejdrech | 640 | async_wait_for( message_id, & result ); |
| 641 | return ( int ) result; |
||
| 642 | } |
||
| 643 | |||
| 4589 | mejdrech | 644 | int recv( int socket_id, void * data, size_t datalength, int flags ){ |
| 645 | // without the address |
||
| 646 | return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL ); |
||
| 647 | } |
||
| 648 | |||
| 4578 | mejdrech | 649 | int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
| 4589 | mejdrech | 650 | if( ! fromaddr ) return EBADMEM; |
| 651 | if( ! addrlen ) return NO_DATA; |
||
| 652 | // with the address |
||
| 653 | return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen ); |
||
| 654 | } |
||
| 655 | |||
| 4708 | mejdrech | 656 | int recvfrom_core( ipcarg_t message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
| 4578 | mejdrech | 657 | socket_ref socket; |
| 658 | aid_t message_id; |
||
| 4589 | mejdrech | 659 | int result; |
| 4708 | mejdrech | 660 | size_t fragments; |
| 661 | size_t * lengths; |
||
| 662 | size_t index; |
||
| 4589 | mejdrech | 663 | ipc_call_t answer; |
| 4578 | mejdrech | 664 | |
| 665 | if( ! data ) return EBADMEM; |
||
| 666 | if( ! datalength ) return NO_DATA; |
||
| 4701 | mejdrech | 667 | if( fromaddr && ( ! addrlen )) return EINVAL; |
| 4726 | mejdrech | 668 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 669 | // find the socket |
| 4578 | mejdrech | 670 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 671 | if( ! socket ){ |
| 672 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 673 | return ENOTSOCK; |
||
| 674 | } |
||
| 4582 | mejdrech | 675 | fibril_mutex_lock( & socket->receive_lock ); |
| 4589 | mejdrech | 676 | // wait for a received packet |
| 4726 | mejdrech | 677 | ++ socket->blocked; |
| 4708 | mejdrech | 678 | while(( result = dyn_fifo_value( & socket->received )) <= 0 ){ |
| 4726 | mejdrech | 679 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4582 | mejdrech | 680 | fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock ); |
| 4726 | mejdrech | 681 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4578 | mejdrech | 682 | } |
| 4726 | mejdrech | 683 | -- socket->blocked; |
| 4708 | mejdrech | 684 | fragments = ( size_t ) result; |
| 4589 | mejdrech | 685 | // prepare lengths if more fragments |
| 686 | if( fragments > 1 ){ |
||
| 4708 | mejdrech | 687 | lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t )); |
| 4589 | mejdrech | 688 | if( ! lengths ){ |
| 689 | fibril_mutex_unlock( & socket->receive_lock ); |
||
| 4726 | mejdrech | 690 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4589 | mejdrech | 691 | return ENOMEM; |
| 692 | } |
||
| 4708 | mejdrech | 693 | // request packet data |
| 694 | message_id = async_send_4( socket->phone, message, ( ipcarg_t ) socket->socket_id, 0, socket->service, ( ipcarg_t ) flags, & answer ); |
||
| 695 | // read the address if desired |
||
| 696 | if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){ |
||
| 4589 | mejdrech | 697 | // read the fragment lengths |
| 698 | if( ipc_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){ |
||
| 699 | if( lengths[ fragments ] <= datalength ){ |
||
| 4708 | mejdrech | 700 | // read all fragments if long enough |
| 4589 | mejdrech | 701 | for( index = 0; index < fragments; ++ index ){ |
| 702 | ipc_data_read_start( socket->phone, data, lengths[ index ] ); |
||
| 4708 | mejdrech | 703 | data = (( uint8_t * ) data ) + lengths[ index ]; |
| 4589 | mejdrech | 704 | } |
| 705 | } |
||
| 706 | } |
||
| 707 | } |
||
| 708 | free( lengths ); |
||
| 4708 | mejdrech | 709 | }else{ |
| 710 | // request packet data |
||
| 711 | message_id = async_send_4( socket->phone, message, ( ipcarg_t ) socket->socket_id, 0, socket->service, ( ipcarg_t ) flags, & answer ); |
||
| 712 | // read the address if desired |
||
| 713 | if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){ |
||
| 714 | // read all if only one fragment |
||
| 715 | ipc_data_read_start( socket->phone, data, datalength ); |
||
| 716 | } |
||
| 4589 | mejdrech | 717 | } |
| 718 | async_wait_for( message_id, ( ipcarg_t * ) & result ); |
||
| 719 | // if successful |
||
| 720 | if( result == EOK ){ |
||
| 721 | // dequeue the received packet |
||
| 722 | dyn_fifo_pop( & socket->received ); |
||
| 723 | // return read data length |
||
| 4701 | mejdrech | 724 | result = SOCKET_GET_READ_DATA_LENGTH( answer ); |
| 4603 | mejdrech | 725 | // set address length |
| 4701 | mejdrech | 726 | if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer ); |
| 4589 | mejdrech | 727 | } |
| 4582 | mejdrech | 728 | fibril_mutex_unlock( & socket->receive_lock ); |
| 4726 | mejdrech | 729 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4589 | mejdrech | 730 | return result; |
| 4578 | mejdrech | 731 | } |
| 732 | |||
| 733 | int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){ |
||
| 734 | socket_ref socket; |
||
| 735 | aid_t message_id; |
||
| 736 | ipcarg_t result; |
||
| 737 | |||
| 4589 | mejdrech | 738 | if( !( value && optlen )) return EBADMEM; |
| 739 | if( !( * optlen )) return NO_DATA; |
||
| 4726 | mejdrech | 740 | fibril_rwlock_read_lock( & socket_globals.lock ); |
| 4589 | mejdrech | 741 | // find the socket |
| 4578 | mejdrech | 742 | socket = sockets_find( socket_get_sockets(), socket_id ); |
| 4726 | mejdrech | 743 | if( ! socket ){ |
| 744 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
||
| 745 | return ENOTSOCK; |
||
| 746 | } |
||
| 4589 | mejdrech | 747 | // request option value |
| 4708 | mejdrech | 748 | message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, ( ipcarg_t ) socket->socket_id, ( ipcarg_t ) optname, socket->service, NULL ); |
| 4589 | mejdrech | 749 | // read the length |
| 750 | if( ipc_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){ |
||
| 751 | // read the value |
||
| 752 | ipc_data_read_start( socket->phone, value, * optlen ); |
||
| 753 | } |
||
| 4726 | mejdrech | 754 | fibril_rwlock_read_unlock( & socket_globals.lock ); |
| 4578 | mejdrech | 755 | async_wait_for( message_id, & result ); |
| 756 | return ( int ) result; |
||
| 757 | } |
||
| 758 | |||
| 759 | int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){ |
||
| 4589 | mejdrech | 760 | // send the value |
| 4708 | mejdrech | 761 | return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, ( ipcarg_t ) optname, value, optlen ); |
| 4589 | mejdrech | 762 | |
| 4578 | mejdrech | 763 | } |
| 764 | |||
| 765 | /** @} |
||
| 766 | */ |