Rev 4603 | Rev 4708 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4603 | Rev 4701 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2009 Lukas Mejdrech |
2 | * Copyright (c) 2009 Lukas Mejdrech |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
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 |
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. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
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 |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
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 |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
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 |
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. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup socket |
29 | /** @addtogroup socket |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | 32 | ||
33 | /** @file |
33 | /** @file |
34 | * Socket application program interface (API) implementation. |
34 | * Socket application program interface (API) implementation. |
35 | * @see socket.h for more information. |
35 | * @see socket.h for more information. |
36 | * This is a part of the network application library. |
36 | * This is a part of the network application library. |
37 | */ |
37 | */ |
38 | 38 | ||
39 | #include <assert.h> |
39 | #include <assert.h> |
40 | #include <async.h> |
40 | #include <async.h> |
41 | #include <fibril_sync.h> |
41 | #include <fibril_sync.h> |
42 | 42 | ||
43 | #include <ipc/services.h> |
43 | #include <ipc/services.h> |
44 | 44 | ||
45 | #include "../err.h" |
45 | #include "../err.h" |
46 | #include "../modules.h" |
46 | #include "../modules.h" |
47 | 47 | ||
48 | #include "../include/in.h" |
48 | #include "../include/in.h" |
49 | #include "../include/socket.h" |
49 | #include "../include/socket.h" |
50 | #include "../include/socket_errno.h" |
50 | #include "../include/socket_errno.h" |
51 | 51 | ||
52 | #include "../structures/dynamic_fifo.h" |
52 | #include "../structures/dynamic_fifo.h" |
53 | #include "../structures/int_map.h" |
53 | #include "../structures/int_map.h" |
54 | 54 | ||
55 | #include "socket_messages.h" |
55 | #include "socket_messages.h" |
56 | 56 | ||
- | 57 | /** Initial received packet queue size. |
|
- | 58 | */ |
|
57 | #define SOCKET_INITIAL_RECEIVED_SIZE 4 |
59 | #define SOCKET_INITIAL_RECEIVED_SIZE 4 |
- | 60 | ||
- | 61 | /** Maximum received packet queue size. |
|
- | 62 | */ |
|
58 | #define SOCKET_MAX_RECEIVED_SIZE 64 |
63 | #define SOCKET_MAX_RECEIVED_SIZE 64 |
59 | 64 | ||
- | 65 | /** Initial waiting sockets queue size. |
|
- | 66 | */ |
|
60 | #define SOCKET_INITIAL_ACCEPTED_SIZE 1 |
67 | #define SOCKET_INITIAL_ACCEPTED_SIZE 1 |
- | 68 | ||
- | 69 | /** Maximum waiting sockets queue size. |
|
- | 70 | */ |
|
61 | #define SOCKET_MAX_ACCEPTED_SIZE 64 |
71 | #define SOCKET_MAX_ACCEPTED_SIZE 64 |
62 | 72 | ||
- | 73 | /** Type definition of the socket specific data. |
|
- | 74 | * @see socket |
|
- | 75 | */ |
|
63 | typedef struct socket socket_t; |
76 | typedef struct socket socket_t; |
64 | typedef socket_t * socket_ref; |
- | |
65 | 77 | ||
- | 78 | /** Type definition of the socket specific data pointer. |
|
- | 79 | * @see socket |
|
- | 80 | */ |
|
- | 81 | typedef socket_t * socket_ref; |
|
- | 82 | ||
- | 83 | /** Socket specific data. |
|
- | 84 | */ |
|
66 | struct socket{ |
85 | struct socket{ |
- | 86 | /** Socket identifier. |
|
- | 87 | */ |
|
67 | int socket_id; |
88 | int socket_id; |
- | 89 | /** Parent module phone. |
|
- | 90 | */ |
|
68 | int phone; |
91 | int phone; |
- | 92 | /** Parent module service. |
|
- | 93 | */ |
|
69 | services_t service; |
94 | services_t service; |
- | 95 | /** Underlying protocol header size. |
|
- | 96 | * Sending and receiving optimalization. |
|
- | 97 | */ |
|
70 | int header_size; |
98 | int header_size; |
- | 99 | /** Packet data fragment size. |
|
- | 100 | * Sending and receiving optimalization. |
|
- | 101 | */ |
|
71 | int data_fragment_size; |
102 | int data_fragment_size; |
- | 103 | /** Received packets queue. |
|
- | 104 | */ |
|
72 | dyn_fifo_t received; |
105 | dyn_fifo_t received; |
- | 106 | /** Received packets safety lock. |
|
- | 107 | */ |
|
73 | fibril_mutex_t receive_lock; |
108 | fibril_mutex_t receive_lock; |
- | 109 | /** Received packets signaling. |
|
- | 110 | */ |
|
74 | fibril_condvar_t receive_signal; |
111 | fibril_condvar_t receive_signal; |
- | 112 | /** Waiting sockets queue. |
|
- | 113 | */ |
|
75 | dyn_fifo_t accepted; |
114 | dyn_fifo_t accepted; |
- | 115 | /** Waiting sockets safety lock. |
|
- | 116 | */ |
|
76 | fibril_mutex_t accept_lock; |
117 | fibril_mutex_t accept_lock; |
- | 118 | /** Waiting sockets signaling. |
|
- | 119 | */ |
|
77 | fibril_condvar_t accept_signal; |
120 | fibril_condvar_t accept_signal; |
78 | }; |
121 | }; |
79 | 122 | ||
- | 123 | /** Sockets map. |
|
- | 124 | * Maps socket identifiers to the socket specific data. |
|
- | 125 | * @see int_map.h |
|
- | 126 | */ |
|
80 | INT_MAP_DECLARE( sockets, socket_t ); |
127 | INT_MAP_DECLARE( sockets, socket_t ); |
81 | 128 | ||
- | 129 | /** Socket client library global data. |
|
- | 130 | */ |
|
82 | static struct{ |
131 | static struct{ |
- | 132 | /** TCP module phone. |
|
- | 133 | */ |
|
83 | int tcp_phone; |
134 | int tcp_phone; |
- | 135 | /** UDP module phone. |
|
- | 136 | */ |
|
84 | int udp_phone; |
137 | int udp_phone; |
- | 138 | /** Active sockets. |
|
- | 139 | */ |
|
85 | sockets_ref sockets; |
140 | sockets_ref sockets; |
86 | } socket_globals = { -1, -1, NULL }; |
141 | } socket_globals = { -1, -1, NULL }; |
87 | 142 | ||
88 | INT_MAP_IMPLEMENT( sockets, socket_t ); |
143 | INT_MAP_IMPLEMENT( sockets, socket_t ); |
89 | 144 | ||
- | 145 | /** Returns the TCP module phone. |
|
- | 146 | * Connects to the TCP module if necessary. |
|
- | 147 | * @returns The TCP module phone. |
|
- | 148 | */ |
|
90 | static int socket_get_tcp_phone(); |
149 | static int socket_get_tcp_phone(); |
- | 150 | ||
- | 151 | /** Returns the UDP module phone. |
|
- | 152 | * Connects to the UDP module if necessary. |
|
- | 153 | * @returns The UDP module phone. |
|
- | 154 | */ |
|
91 | static int socket_get_tcp_phone(); |
155 | static int socket_get_tcp_phone(); |
- | 156 | ||
- | 157 | /** Returns the active sockets. |
|
- | 158 | * @returns The active sockets. |
|
- | 159 | */ |
|
92 | static sockets_ref socket_get_sockets(); |
160 | static sockets_ref socket_get_sockets(); |
- | 161 | ||
- | 162 | /** Default thread for new connections. |
|
- | 163 | * @param iid The initial message identifier. Input parameter. |
|
- | 164 | * @param icall The initial message call structure. Input parameter. |
|
- | 165 | */ |
|
93 | void socket_connection( ipc_callid_t iid, ipc_call_t * icall ); |
166 | void socket_connection( ipc_callid_t iid, ipc_call_t * icall ); |
- | 167 | ||
- | 168 | /** Sends message to the socket parent module with specified data. |
|
- | 169 | * @param socket_id Socket identifier. Input parameter. |
|
- | 170 | * @param message The action message. Input parameter. |
|
- | 171 | * @param arg2 The second message parameter. Input parameter. |
|
- | 172 | * @param data The data to be sent. Input parameter. |
|
- | 173 | * @param datalength The data length. Input parameter. |
|
- | 174 | * @returns EOK on success. |
|
- | 175 | * @returns ENOTSOCK if the socket is not found. |
|
- | 176 | * @returns EBADMEM if the data parameter is NULL. |
|
- | 177 | * @returns NO_DATA if the datalength parameter is zero (0). |
|
- | 178 | * @returns Other error codes as defined for the spcific message. |
|
- | 179 | */ |
|
94 | int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ); |
180 | int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ); |
- | 181 | ||
- | 182 | /** Initializes a new socket specific data. |
|
- | 183 | * @param socket The socket to be initialized. Input/output parameter. |
|
- | 184 | * @param socket_id The new socket identifier. Input parameter. |
|
- | 185 | * @param phone The parent module phone. Input parameter. |
|
- | 186 | * @param service The parent module service. Input parameter. |
|
- | 187 | */ |
|
95 | void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ); |
188 | void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ); |
- | 189 | ||
- | 190 | /** Clears and destroys the socket. |
|
- | 191 | * @param socket The socket to be destroyed. Input parameter. |
|
- | 192 | */ |
|
96 | void socket_destroy( socket_ref socket ); |
193 | void socket_destroy( socket_ref socket ); |
- | 194 | ||
- | 195 | /** Receives data via the socket. |
|
- | 196 | * @param message The action message. Input parameter. |
|
- | 197 | * @param socket_id Socket identifier. Input parameter. |
|
- | 198 | * @param data The data buffer to be filled. Output parameter. |
|
- | 199 | * @param datalength The data length. Input parameter. |
|
- | 200 | * @param flags Various receive flags. Input parameter. |
|
- | 201 | * @param fromaddr The source address. May be NULL for connected sockets. Output parameter. |
|
- | 202 | * @param addrlen The address length. The maximum address length is read. The actual address length is set. Used only if fromaddr is not NULL. Input/output parameter. |
|
- | 203 | * @returns EOK on success. |
|
- | 204 | * @returns ENOTSOCK if the socket is not found. |
|
- | 205 | * @returns EBADMEM if the data parameter is NULL. |
|
- | 206 | * @returns NO_DATA if the datalength or addrlen parameter is zero (0). |
|
- | 207 | * @returns Other error codes as defined for the spcific message. |
|
- | 208 | */ |
|
97 | int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ); |
209 | int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ); |
- | 210 | ||
- | 211 | /** Sends data via the socket to the remote address. |
|
- | 212 | * Binds the socket to a free port if not already connected/bound. |
|
- | 213 | * @param message The action message. Input parameter. |
|
- | 214 | * @param socket_id Socket identifier. Input parameter. |
|
- | 215 | * @param data The data to be sent. Input parameter. |
|
- | 216 | * @param datalength The data length. Input parameter. |
|
- | 217 | * @param flags Various send flags. Input parameter. |
|
- | 218 | * @param toaddr The destination address. May be NULL for connected sockets. Input parameter. |
|
- | 219 | * @param addrlen The address length. Used only if toaddr is not NULL. Input parameter. |
|
- | 220 | * @returns EOK on success. |
|
- | 221 | * @returns ENOTSOCK if the socket is not found. |
|
- | 222 | * @returns EBADMEM if the data or toaddr parameter is NULL. |
|
- | 223 | * @returns NO_DATA if the datalength or the addrlen parameter is zero (0). |
|
- | 224 | * @returns Other error codes as defined for the NET_SOCKET_SENDTO message. |
|
- | 225 | */ |
|
98 | int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ); |
226 | int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ); |
99 | 227 | ||
100 | static int socket_get_tcp_phone(){ |
228 | static int socket_get_tcp_phone(){ |
101 | if( socket_globals.tcp_phone < 0 ){ |
229 | if( socket_globals.tcp_phone < 0 ){ |
102 | socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection ); |
230 | socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection ); |
103 | } |
231 | } |
104 | return socket_globals.tcp_phone; |
232 | return socket_globals.tcp_phone; |
105 | } |
233 | } |
106 | 234 | ||
107 | static int socket_get_udp_phone(){ |
235 | static int socket_get_udp_phone(){ |
108 | if( socket_globals.udp_phone < 0 ){ |
236 | if( socket_globals.udp_phone < 0 ){ |
109 | socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection ); |
237 | socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection ); |
110 | } |
238 | } |
111 | return socket_globals.udp_phone; |
239 | return socket_globals.udp_phone; |
112 | } |
240 | } |
113 | 241 | ||
114 | static sockets_ref socket_get_sockets(){ |
242 | static sockets_ref socket_get_sockets(){ |
115 | if( ! socket_globals.sockets ){ |
243 | if( ! socket_globals.sockets ){ |
116 | socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t )); |
244 | socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t )); |
117 | if( ! socket_globals.sockets ) return NULL; |
245 | if( ! socket_globals.sockets ) return NULL; |
118 | if( sockets_initialize( socket_globals.sockets ) != EOK ){ |
246 | if( sockets_initialize( socket_globals.sockets ) != EOK ){ |
119 | free( socket_globals.sockets ); |
247 | free( socket_globals.sockets ); |
120 | socket_globals.sockets = NULL; |
248 | socket_globals.sockets = NULL; |
121 | } |
249 | } |
122 | } |
250 | } |
123 | return socket_globals.sockets; |
251 | return socket_globals.sockets; |
124 | } |
252 | } |
125 | 253 | ||
126 | void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){ |
254 | void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){ |
127 | socket->socket_id = socket_id; |
255 | socket->socket_id = socket_id; |
128 | socket->phone = phone; |
256 | socket->phone = phone; |
129 | socket->service = service; |
257 | socket->service = service; |
130 | dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ); |
258 | dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ); |
131 | dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ); |
259 | dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ); |
132 | fibril_mutex_initialize( & socket->receive_lock ); |
260 | fibril_mutex_initialize( & socket->receive_lock ); |
133 | fibril_condvar_initialize( & socket->receive_signal ); |
261 | fibril_condvar_initialize( & socket->receive_signal ); |
134 | fibril_mutex_initialize( & socket->accept_lock ); |
262 | fibril_mutex_initialize( & socket->accept_lock ); |
135 | fibril_condvar_initialize( & socket->accept_signal ); |
263 | fibril_condvar_initialize( & socket->accept_signal ); |
136 | } |
264 | } |
137 | 265 | ||
138 | void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){ |
266 | void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){ |
139 | ERROR_DECLARE; |
267 | ERROR_DECLARE; |
140 | 268 | ||
141 | ipc_callid_t callid; |
269 | ipc_callid_t callid; |
142 | ipc_call_t call; |
270 | ipc_call_t call; |
143 | socket_ref socket; |
271 | socket_ref socket; |
144 | socket_ref new_socket; |
272 | socket_ref new_socket; |
145 | 273 | ||
146 | while( true ){ |
274 | while( true ){ |
147 | 275 | ||
148 | callid = async_get_call( & call ); |
276 | callid = async_get_call( & call ); |
149 | switch( IPC_GET_METHOD( call )){ |
277 | switch( IPC_GET_METHOD( call )){ |
150 | case NET_SOCKET_RECEIVED: |
278 | case NET_SOCKET_RECEIVED: |
151 | // find the socket |
279 | // find the socket |
152 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call )); |
280 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call )); |
153 | if( ! socket ){ |
281 | if( ! socket ){ |
154 | ERROR_CODE = ENOTSOCK; |
282 | ERROR_CODE = ENOTSOCK; |
155 | break; |
283 | break; |
156 | } |
284 | } |
157 | fibril_mutex_lock( & socket->receive_lock ); |
285 | fibril_mutex_lock( & socket->receive_lock ); |
158 | // push the number of received packet fragments |
286 | // 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 ))){ |
287 | if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_MAX_RECEIVED_SIZE ))){ |
160 | // signal the received packet |
288 | // signal the received packet |
161 | fibril_condvar_signal( & socket->receive_signal ); |
289 | fibril_condvar_signal( & socket->receive_signal ); |
162 | } |
290 | } |
163 | fibril_mutex_unlock( & socket->receive_lock ); |
291 | fibril_mutex_unlock( & socket->receive_lock ); |
164 | break; |
292 | break; |
165 | case NET_SOCKET_ACCEPTED: |
293 | case NET_SOCKET_ACCEPTED: |
166 | // find the socket |
294 | // find the socket |
167 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call )); |
295 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call )); |
168 | if( ! socket ){ |
296 | if( ! socket ){ |
169 | ERROR_CODE = ENOTSOCK; |
297 | ERROR_CODE = ENOTSOCK; |
170 | break; |
298 | break; |
171 | } |
299 | } |
172 | // create a new scoket |
300 | // create a new scoket |
173 | new_socket = ( socket_ref ) malloc( sizeof( socket_t )); |
301 | new_socket = ( socket_ref ) malloc( sizeof( socket_t )); |
174 | if( ! new_socket ){ |
302 | if( ! new_socket ){ |
175 | ERROR_CODE = ENOMEM; |
303 | ERROR_CODE = ENOMEM; |
176 | break; |
304 | break; |
177 | } |
305 | } |
178 | socket_initialize( new_socket, SOCKET_GET_SOCKET_ID( & call ), socket->phone, socket->service ); |
306 | 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 ); |
307 | ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket ); |
180 | if( ERROR_CODE < 0 ){ |
308 | if( ERROR_CODE < 0 ){ |
181 | free( new_socket ); |
309 | free( new_socket ); |
182 | }else{ |
310 | }else{ |
183 | // push the new socket identifier |
311 | // push the new socket identifier |
184 | fibril_mutex_lock( & socket->accept_lock ); |
312 | fibril_mutex_lock( & socket->accept_lock ); |
185 | if( ERROR_OCCURRED( dyn_fifo_push( & socket->accepted, new_socket->socket_id, SOCKET_MAX_ACCEPTED_SIZE ))){ |
313 | 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 ); |
314 | sockets_exclude( socket_get_sockets(), new_socket->socket_id ); |
187 | free( new_socket ); |
315 | free( new_socket ); |
188 | }else{ |
316 | }else{ |
189 | // signal the accepted socket |
317 | // signal the accepted socket |
190 | fibril_condvar_signal( & socket->accept_signal ); |
318 | fibril_condvar_signal( & socket->accept_signal ); |
191 | } |
319 | } |
192 | fibril_mutex_unlock( & socket->accept_lock ); |
320 | fibril_mutex_unlock( & socket->accept_lock ); |
193 | ERROR_CODE = EOK; |
321 | ERROR_CODE = EOK; |
194 | } |
322 | } |
195 | break; |
323 | break; |
196 | case NET_SOCKET_DATA_FRAGMENT_SIZE: |
324 | case NET_SOCKET_DATA_FRAGMENT_SIZE: |
197 | // find the socket |
325 | // find the socket |
198 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call )); |
326 | socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call )); |
199 | if( ! socket ){ |
327 | if( ! socket ){ |
200 | ERROR_CODE = ENOTSOCK; |
328 | ERROR_CODE = ENOTSOCK; |
201 | break; |
329 | break; |
202 | } |
330 | } |
203 | // set the data fragment size |
331 | // set the data fragment size |
204 | socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( & call ); |
332 | socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( call ); |
205 | ERROR_CODE = EOK; |
333 | ERROR_CODE = EOK; |
206 | break; |
334 | break; |
207 | default: |
335 | default: |
208 | ERROR_CODE = ENOTSUP; |
336 | ERROR_CODE = ENOTSUP; |
209 | } |
337 | } |
210 | ipc_answer_0( callid, ERROR_CODE ); |
338 | ipc_answer_0( callid, ERROR_CODE ); |
211 | } |
339 | } |
212 | } |
340 | } |
213 | 341 | ||
214 | int socket( int domain, int type, int protocol ){ |
342 | int socket( int domain, int type, int protocol ){ |
215 | ERROR_DECLARE; |
343 | ERROR_DECLARE; |
216 | 344 | ||
217 | socket_ref socket; |
345 | socket_ref socket; |
218 | int phone; |
346 | int phone; |
219 | int socket_id; |
347 | int socket_id; |
220 | services_t service; |
348 | services_t service; |
221 | 349 | ||
222 | // find the appropriate service |
350 | // find the appropriate service |
223 | switch( domain ){ |
351 | switch( domain ){ |
224 | case PF_INET: |
352 | case PF_INET: |
225 | switch( type ){ |
353 | switch( type ){ |
226 | case SOCK_STREAM: |
354 | case SOCK_STREAM: |
227 | if( ! protocol ) protocol = IPPROTO_TCP; |
355 | if( ! protocol ) protocol = IPPROTO_TCP; |
228 | switch( protocol ){ |
356 | switch( protocol ){ |
229 | case IPPROTO_TCP: |
357 | case IPPROTO_TCP: |
230 | phone = socket_get_tcp_phone(); |
358 | phone = socket_get_tcp_phone(); |
231 | service = SERVICE_TCP; |
359 | service = SERVICE_TCP; |
232 | break; |
360 | break; |
233 | default: |
361 | default: |
234 | return EPROTONOSUPPORT; |
362 | return EPROTONOSUPPORT; |
235 | } |
363 | } |
236 | break; |
364 | break; |
237 | case SOCK_DGRAM: |
365 | case SOCK_DGRAM: |
238 | if( ! protocol ) protocol = IPPROTO_UDP; |
366 | if( ! protocol ) protocol = IPPROTO_UDP; |
239 | switch( protocol ){ |
367 | switch( protocol ){ |
240 | case IPPROTO_UDP: |
368 | case IPPROTO_UDP: |
241 | phone = socket_get_udp_phone(); |
369 | phone = socket_get_udp_phone(); |
242 | service = SERVICE_UDP; |
370 | service = SERVICE_UDP; |
243 | break; |
371 | break; |
244 | default: |
372 | default: |
245 | return EPROTONOSUPPORT; |
373 | return EPROTONOSUPPORT; |
246 | } |
374 | } |
247 | break; |
375 | break; |
248 | case SOCK_RAW: |
376 | case SOCK_RAW: |
249 | default: |
377 | default: |
250 | return ESOCKTNOSUPPORT; |
378 | return ESOCKTNOSUPPORT; |
251 | } |
379 | } |
252 | break; |
380 | break; |
253 | // TODO IPv6 |
381 | // TODO IPv6 |
254 | default: |
382 | default: |
255 | return EPFNOSUPPORT; |
383 | return EPFNOSUPPORT; |
256 | } |
384 | } |
257 | // create a new socket structure |
385 | // create a new socket structure |
258 | socket = ( socket_ref ) malloc( sizeof( socket_t )); |
386 | socket = ( socket_ref ) malloc( sizeof( socket_t )); |
259 | if( ! socket ) return ENOMEM; |
387 | if( ! socket ) return ENOMEM; |
260 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){ |
388 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){ |
261 | free( socket ); |
389 | free( socket ); |
262 | return ERROR_CODE; |
390 | return ERROR_CODE; |
263 | } |
391 | } |
264 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){ |
392 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){ |
265 | dyn_fifo_destroy( & socket->received ); |
393 | dyn_fifo_destroy( & socket->received ); |
266 | free( socket ); |
394 | free( socket ); |
267 | return ERROR_CODE; |
395 | return ERROR_CODE; |
268 | } |
396 | } |
269 | // request a new socket |
397 | // 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 ))){ |
398 | 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 ); |
399 | dyn_fifo_destroy( & socket->received ); |
272 | dyn_fifo_destroy( & socket->accepted ); |
400 | dyn_fifo_destroy( & socket->accepted ); |
273 | free( socket ); |
401 | free( socket ); |
274 | return ERROR_CODE; |
402 | return ERROR_CODE; |
275 | } |
403 | } |
276 | // finish the new socket initialization |
404 | // finish the new socket initialization |
277 | socket_initialize( socket, socket_id, phone, service ); |
405 | socket_initialize( socket, socket_id, phone, service ); |
278 | // store the new socket |
406 | // store the new socket |
279 | ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket ); |
407 | ERROR_CODE = sockets_add( socket_get_sockets(), socket_id, socket ); |
280 | if( ERROR_CODE < 0 ){ |
408 | if( ERROR_CODE < 0 ){ |
281 | dyn_fifo_destroy( & socket->received ); |
409 | dyn_fifo_destroy( & socket->received ); |
282 | dyn_fifo_destroy( & socket->accepted ); |
410 | dyn_fifo_destroy( & socket->accepted ); |
283 | free( socket ); |
411 | free( socket ); |
284 | async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service ); |
412 | async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service ); |
285 | return ERROR_CODE; |
413 | return ERROR_CODE; |
286 | } |
414 | } |
287 | 415 | ||
288 | return socket_id; |
416 | return socket_id; |
289 | } |
417 | } |
290 | 418 | ||
291 | int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ){ |
419 | int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ){ |
292 | socket_ref socket; |
420 | socket_ref socket; |
293 | aid_t message_id; |
421 | aid_t message_id; |
294 | ipcarg_t result; |
422 | ipcarg_t result; |
295 | 423 | ||
296 | if( ! data ) return EBADMEM; |
424 | if( ! data ) return EBADMEM; |
297 | if( ! datalength ) return NO_DATA; |
425 | if( ! datalength ) return NO_DATA; |
298 | // find the socket |
426 | // find the socket |
299 | socket = sockets_find( socket_get_sockets(), socket_id ); |
427 | socket = sockets_find( socket_get_sockets(), socket_id ); |
300 | if( ! socket ) return ENOTSOCK; |
428 | if( ! socket ) return ENOTSOCK; |
301 | // request the message |
429 | // request the message |
302 | message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL ); |
430 | message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL ); |
303 | // send the address |
431 | // send the address |
304 | ipc_data_write_start( socket->phone, data, datalength ); |
432 | ipc_data_write_start( socket->phone, data, datalength ); |
305 | async_wait_for( message_id, & result ); |
433 | async_wait_for( message_id, & result ); |
306 | return ( int ) result; |
434 | return ( int ) result; |
307 | } |
435 | } |
308 | 436 | ||
309 | int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){ |
437 | int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){ |
310 | // send the address |
438 | // send the address |
311 | return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen ); |
439 | return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen ); |
312 | } |
440 | } |
313 | 441 | ||
314 | int listen( int socket_id, int backlog ){ |
442 | int listen( int socket_id, int backlog ){ |
315 | socket_ref socket; |
443 | socket_ref socket; |
316 | 444 | ||
317 | if( backlog <= 0 ) return EINVAL; |
445 | if( backlog <= 0 ) return EINVAL; |
318 | // find the socket |
446 | // find the socket |
319 | socket = sockets_find( socket_get_sockets(), socket_id ); |
447 | socket = sockets_find( socket_get_sockets(), socket_id ); |
320 | if( ! socket ) return ENOTSOCK; |
448 | if( ! socket ) return ENOTSOCK; |
321 | // request listen backlog change |
449 | // request listen backlog change |
322 | return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service ); |
450 | return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service ); |
323 | } |
451 | } |
324 | 452 | ||
325 | int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){ |
453 | int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){ |
326 | socket_ref socket; |
454 | socket_ref socket; |
327 | aid_t message_id; |
455 | aid_t message_id; |
328 | int result; |
456 | int result; |
329 | 457 | ||
330 | if( ! cliaddr ) return EBADMEM; |
458 | if(( ! cliaddr ) || ( ! addrlen )) return EBADMEM; |
331 | if( ! addrlen ) return NO_DATA; |
- | |
332 | // find the socket |
459 | // find the socket |
333 | socket = sockets_find( socket_get_sockets(), socket_id ); |
460 | socket = sockets_find( socket_get_sockets(), socket_id ); |
334 | if( ! socket ) return ENOTSOCK; |
461 | if( ! socket ) return ENOTSOCK; |
335 | fibril_mutex_lock( & socket->accept_lock ); |
462 | fibril_mutex_lock( & socket->accept_lock ); |
336 | // wait for an accepted socket |
463 | // wait for an accepted socket |
337 | while( dyn_fifo_value( & socket->accepted ) <= 0 ){ |
464 | while( dyn_fifo_value( & socket->accepted ) <= 0 ){ |
338 | fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock ); |
465 | fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock ); |
339 | } |
466 | } |
340 | // request accept |
467 | // request accept |
341 | message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, dyn_fifo_value( & socket->accepted ), socket->service, NULL ); |
468 | message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, dyn_fifo_value( & socket->accepted ), socket->service, NULL ); |
342 | // read address |
469 | // read address |
343 | ipc_data_read_start( socket->phone, cliaddr, * addrlen ); |
470 | ipc_data_read_start( socket->phone, cliaddr, * addrlen ); |
344 | async_wait_for( message_id, ( ipcarg_t * ) & result ); |
471 | async_wait_for( message_id, ( ipcarg_t * ) & result ); |
345 | if( result > 0 ){ |
472 | if( result > 0 ){ |
346 | // dequeue the accepted apcket if successful |
473 | // dequeue the accepted apcket if successful |
347 | dyn_fifo_pop( & socket->accepted ); |
474 | dyn_fifo_pop( & socket->accepted ); |
348 | } |
475 | } |
349 | fibril_mutex_unlock( & socket->accept_lock ); |
476 | fibril_mutex_unlock( & socket->accept_lock ); |
350 | return result; |
477 | return result; |
351 | } |
478 | } |
352 | 479 | ||
353 | int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){ |
480 | int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){ |
354 | // send the address |
481 | // send the address |
355 | return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen ); |
482 | return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen ); |
356 | } |
483 | } |
357 | 484 | ||
358 | int closesocket( int socket_id ){ |
485 | int closesocket( int socket_id ){ |
359 | ERROR_DECLARE; |
486 | ERROR_DECLARE; |
360 | 487 | ||
361 | socket_ref socket; |
488 | socket_ref socket; |
362 | 489 | ||
363 | socket = sockets_find( socket_get_sockets(), socket_id ); |
490 | socket = sockets_find( socket_get_sockets(), socket_id ); |
364 | if( ! socket ) return ENOTSOCK; |
491 | if( ! socket ) return ENOTSOCK; |
365 | // request close |
492 | // request close |
366 | ERROR_PROPAGATE( async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service )); |
493 | ERROR_PROPAGATE( async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service )); |
367 | // free the socket structure |
494 | // free the socket structure |
368 | socket_destroy( socket ); |
495 | socket_destroy( socket ); |
369 | return EOK; |
496 | return EOK; |
370 | } |
497 | } |
371 | 498 | ||
372 | void socket_destroy( socket_ref socket ){ |
499 | void socket_destroy( socket_ref socket ){ |
373 | int accepted_id; |
500 | int accepted_id; |
374 | 501 | ||
375 | // destroy all accepted sockets |
502 | // destroy all accepted sockets |
376 | while(( accepted_id = dyn_fifo_pop( & socket->accepted ))){ |
503 | while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){ |
377 | socket_destroy( sockets_find( socket_get_sockets(), accepted_id )); |
504 | socket_destroy( sockets_find( socket_get_sockets(), accepted_id )); |
378 | } |
505 | } |
379 | dyn_fifo_destroy( & socket->received ); |
506 | dyn_fifo_destroy( & socket->received ); |
380 | dyn_fifo_destroy( & socket->accepted ); |
507 | dyn_fifo_destroy( & socket->accepted ); |
381 | sockets_exclude( socket_get_sockets(), socket->socket_id ); |
508 | sockets_exclude( socket_get_sockets(), socket->socket_id ); |
382 | } |
509 | } |
383 | 510 | ||
384 | int send( int socket_id, void * data, size_t datalength, int flags ){ |
511 | int send( int socket_id, void * data, size_t datalength, int flags ){ |
385 | // without the address |
512 | // without the address |
386 | return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 ); |
513 | return sendto_core( NET_SOCKET_SEND, socket_id, data, datalength, flags, NULL, 0 ); |
387 | } |
514 | } |
388 | 515 | ||
389 | int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){ |
516 | 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; |
517 | if( ! toaddr ) return EBADMEM; |
391 | if( ! addrlen ) return NO_DATA; |
518 | if( ! addrlen ) return NO_DATA; |
392 | // with the address |
519 | // with the address |
393 | return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen ); |
520 | return sendto_core( NET_SOCKET_SENDTO, socket_id, data, datalength, flags, toaddr, addrlen ); |
394 | } |
521 | } |
395 | 522 | ||
396 | int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){ |
523 | 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; |
524 | socket_ref socket; |
398 | aid_t message_id; |
525 | aid_t message_id; |
399 | ipcarg_t result; |
526 | ipcarg_t result; |
400 | int fragments; |
527 | int fragments; |
401 | 528 | ||
402 | if( ! data ) return EBADMEM; |
529 | if( ! data ) return EBADMEM; |
403 | if( ! datalength ) return NO_DATA; |
530 | if( ! datalength ) return NO_DATA; |
404 | // find socket |
531 | // find socket |
405 | socket = sockets_find( socket_get_sockets(), socket_id ); |
532 | socket = sockets_find( socket_get_sockets(), socket_id ); |
406 | if( ! socket ) return ENOTSOCK; |
533 | if( ! socket ) return ENOTSOCK; |
407 | // compute data fragment count |
534 | // compute data fragment count |
408 | fragments = ( datalength + socket->header_size ) / socket->data_fragment_size; |
535 | fragments = ( datalength + socket->header_size ) / socket->data_fragment_size; |
409 | if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments; |
536 | if(( datalength + socket->header_size ) % socket->data_fragment_size ) ++ fragments; |
410 | // request send |
537 | // request send |
411 | message_id = async_send_4( socket->phone, message, socket->socket_id, fragments, socket->service, flags, NULL ); |
538 | message_id = async_send_4( socket->phone, message, socket->socket_id, fragments, socket->service, flags, NULL ); |
412 | // send the address if given |
539 | // send the address if given |
413 | if(( ! toaddr ) || ( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){ |
540 | if(( ! toaddr ) || ( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK )){ |
414 | if( fragments == 1 ){ |
541 | if( fragments == 1 ){ |
415 | // send all if only one fragment |
542 | // send all if only one fragment |
416 | ipc_data_write_start( socket->phone, data, datalength ); |
543 | ipc_data_write_start( socket->phone, data, datalength ); |
417 | }else{ |
544 | }else{ |
418 | // send the first fragment |
545 | // send the first fragment |
419 | ipc_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size ); |
546 | ipc_data_write_start( socket->phone, data, socket->data_fragment_size - socket->header_size ); |
420 | data += socket->data_fragment_size - socket->header_size; |
547 | data += socket->data_fragment_size - socket->header_size; |
421 | // send the middle fragments |
548 | // send the middle fragments |
422 | while(( -- fragments ) > 1 ){ |
549 | while(( -- fragments ) > 1 ){ |
423 | ipc_data_write_start( socket->phone, data, socket->data_fragment_size ); |
550 | ipc_data_write_start( socket->phone, data, socket->data_fragment_size ); |
424 | data += socket->data_fragment_size; |
551 | data += socket->data_fragment_size; |
425 | } |
552 | } |
426 | // send the last fragment |
553 | // send the last fragment |
427 | ipc_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size ); |
554 | ipc_data_write_start( socket->phone, data, ( datalength + socket->header_size ) % socket->data_fragment_size ); |
428 | } |
555 | } |
429 | } |
556 | } |
430 | async_wait_for( message_id, & result ); |
557 | async_wait_for( message_id, & result ); |
431 | return ( int ) result; |
558 | return ( int ) result; |
432 | } |
559 | } |
433 | 560 | ||
434 | int recv( int socket_id, void * data, size_t datalength, int flags ){ |
561 | int recv( int socket_id, void * data, size_t datalength, int flags ){ |
435 | // without the address |
562 | // without the address |
436 | return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL ); |
563 | return recvfrom_core( NET_SOCKET_RECV, socket_id, data, datalength, flags, NULL, NULL ); |
437 | } |
564 | } |
438 | 565 | ||
439 | int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
566 | int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
440 | if( ! fromaddr ) return EBADMEM; |
567 | if( ! fromaddr ) return EBADMEM; |
441 | if( ! addrlen ) return NO_DATA; |
568 | if( ! addrlen ) return NO_DATA; |
442 | // with the address |
569 | // with the address |
443 | return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen ); |
570 | return recvfrom_core( NET_SOCKET_RECVFROM, socket_id, data, datalength, flags, fromaddr, addrlen ); |
444 | } |
571 | } |
445 | 572 | ||
446 | int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){ |
573 | 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; |
574 | socket_ref socket; |
448 | aid_t message_id; |
575 | aid_t message_id; |
449 | int result; |
576 | int result; |
450 | int fragments; |
577 | int fragments; |
451 | int * lengths; |
578 | int * lengths; |
452 | int index; |
579 | int index; |
453 | ipc_call_t answer; |
580 | ipc_call_t answer; |
454 | 581 | ||
455 | if( ! data ) return EBADMEM; |
582 | if( ! data ) return EBADMEM; |
456 | if( ! datalength ) return NO_DATA; |
583 | if( ! datalength ) return NO_DATA; |
457 | if( fromaddr && (( ! addrlen ) || ( * addrlen < sizeof( struct sockaddr_in )))) return EINVAL; |
584 | if( fromaddr && ( ! addrlen )) return EINVAL; |
458 | // find the socket |
585 | // find the socket |
459 | socket = sockets_find( socket_get_sockets(), socket_id ); |
586 | socket = sockets_find( socket_get_sockets(), socket_id ); |
460 | if( ! socket ) return ENOTSOCK; |
587 | if( ! socket ) return ENOTSOCK; |
461 | fibril_mutex_lock( & socket->receive_lock ); |
588 | fibril_mutex_lock( & socket->receive_lock ); |
462 | // wait for a received packet |
589 | // wait for a received packet |
463 | while(( fragments = dyn_fifo_value( & socket->received )) <= 0 ){ |
590 | while(( fragments = dyn_fifo_value( & socket->received )) <= 0 ){ |
464 | fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock ); |
591 | fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock ); |
465 | } |
592 | } |
466 | // prepare lengths if more fragments |
593 | // prepare lengths if more fragments |
467 | if( fragments > 1 ){ |
594 | if( fragments > 1 ){ |
468 | lengths = ( int * ) malloc( sizeof( int ) * ( fragments + 1 )); |
595 | lengths = ( int * ) malloc( sizeof( int ) * ( fragments + 1 )); |
469 | if( ! lengths ){ |
596 | if( ! lengths ){ |
470 | fibril_mutex_unlock( & socket->receive_lock ); |
597 | fibril_mutex_unlock( & socket->receive_lock ); |
471 | return ENOMEM; |
598 | return ENOMEM; |
472 | } |
599 | } |
473 | } |
600 | } |
474 | // request packet data |
601 | // request packet data |
475 | message_id = async_send_4( socket->phone, message, socket->socket_id, 0, socket->service, flags, & answer ); |
602 | message_id = async_send_4( socket->phone, message, socket->socket_id, 0, socket->service, flags, & answer ); |
476 | // read the address if desired |
603 | // read the address if desired |
477 | if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){ |
604 | if(( ! fromaddr ) || ( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK )){ |
478 | if( fragments == 1 ){ |
605 | if( fragments == 1 ){ |
479 | // read all if only one fragment |
606 | // read all if only one fragment |
480 | ipc_data_read_start( socket->phone, data, datalength ); |
607 | ipc_data_read_start( socket->phone, data, datalength ); |
481 | }else{ |
608 | }else{ |
482 | // read the fragment lengths |
609 | // read the fragment lengths |
483 | if( ipc_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){ |
610 | if( ipc_data_read_start( socket->phone, lengths, sizeof( int ) * ( fragments + 1 )) == EOK ){ |
484 | if( lengths[ fragments ] <= datalength ){ |
611 | if( lengths[ fragments ] <= datalength ){ |
485 | // read all fragments if long enough |
612 | // read all fragments if long enough |
486 | for( index = 0; index < fragments; ++ index ){ |
613 | for( index = 0; index < fragments; ++ index ){ |
487 | ipc_data_read_start( socket->phone, data, lengths[ index ] ); |
614 | ipc_data_read_start( socket->phone, data, lengths[ index ] ); |
488 | data += lengths[ index ]; |
615 | data += lengths[ index ]; |
489 | } |
616 | } |
490 | } |
617 | } |
491 | } |
618 | } |
492 | free( lengths ); |
619 | free( lengths ); |
493 | } |
620 | } |
494 | }else if( fragments > 1 ){ |
621 | }else if( fragments > 1 ){ |
495 | free( lengths ); |
622 | free( lengths ); |
496 | } |
623 | } |
497 | async_wait_for( message_id, ( ipcarg_t * ) & result ); |
624 | async_wait_for( message_id, ( ipcarg_t * ) & result ); |
498 | // if successful |
625 | // if successful |
499 | if( result == EOK ){ |
626 | if( result == EOK ){ |
500 | // dequeue the received packet |
627 | // dequeue the received packet |
501 | dyn_fifo_pop( & socket->received ); |
628 | dyn_fifo_pop( & socket->received ); |
502 | // return read data length |
629 | // return read data length |
503 | result = SOCKET_GET_READ_DATA_LENGTH( & answer ); |
630 | result = SOCKET_GET_READ_DATA_LENGTH( answer ); |
504 | // set address length |
631 | // set address length |
505 | if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( & answer ); |
632 | if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer ); |
506 | } |
633 | } |
507 | fibril_mutex_unlock( & socket->receive_lock ); |
634 | fibril_mutex_unlock( & socket->receive_lock ); |
508 | return result; |
635 | return result; |
509 | } |
636 | } |
510 | 637 | ||
511 | int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){ |
638 | int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){ |
512 | socket_ref socket; |
639 | socket_ref socket; |
513 | aid_t message_id; |
640 | aid_t message_id; |
514 | ipcarg_t result; |
641 | ipcarg_t result; |
515 | 642 | ||
516 | if( !( value && optlen )) return EBADMEM; |
643 | if( !( value && optlen )) return EBADMEM; |
517 | if( !( * optlen )) return NO_DATA; |
644 | if( !( * optlen )) return NO_DATA; |
518 | // find the socket |
645 | // find the socket |
519 | socket = sockets_find( socket_get_sockets(), socket_id ); |
646 | socket = sockets_find( socket_get_sockets(), socket_id ); |
520 | if( ! socket ) return ENOTSOCK; |
647 | if( ! socket ) return ENOTSOCK; |
521 | // request option value |
648 | // request option value |
522 | message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL ); |
649 | message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL ); |
523 | // read the length |
650 | // read the length |
524 | if( ipc_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){ |
651 | if( ipc_data_read_start( socket->phone, optlen, sizeof( * optlen )) == EOK ){ |
525 | // read the value |
652 | // read the value |
526 | ipc_data_read_start( socket->phone, value, * optlen ); |
653 | ipc_data_read_start( socket->phone, value, * optlen ); |
527 | } |
654 | } |
528 | async_wait_for( message_id, & result ); |
655 | async_wait_for( message_id, & result ); |
529 | return ( int ) result; |
656 | return ( int ) result; |
530 | } |
657 | } |
531 | 658 | ||
532 | int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){ |
659 | int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){ |
533 | // send the value |
660 | // send the value |
534 | return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen ); |
661 | return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen ); |
535 | 662 | ||
536 | } |
663 | } |
537 | 664 | ||
538 | /** @} |
665 | /** @} |
539 | */ |
666 | */ |
540 | 667 |