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