Rev 4738 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4738 | 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 | * \todo |
34 | * Socket common core implementation. |
35 | */ |
35 | */ |
36 | 36 | ||
37 | #include "../err.h" |
37 | #include "../err.h" |
38 | 38 | ||
39 | #include "../include/in.h" |
39 | #include "../include/in.h" |
40 | #include "../include/inet.h" |
40 | #include "../include/inet.h" |
41 | 41 | ||
42 | #include "../include/socket_codes.h" |
42 | #include "../include/socket_codes.h" |
43 | #include "../include/socket_errno.h" |
43 | #include "../include/socket_errno.h" |
44 | 44 | ||
45 | #include "../structures/dynamic_fifo.h" |
45 | #include "../structures/dynamic_fifo.h" |
46 | #include "../structures/int_map.h" |
46 | #include "../structures/int_map.h" |
47 | #include "../structures/packet/packet.h" |
47 | #include "../structures/packet/packet.h" |
48 | #include "../structures/packet/packet_client.h" |
48 | #include "../structures/packet/packet_client.h" |
49 | 49 | ||
50 | #include "../modules.h" |
50 | #include "../modules.h" |
51 | 51 | ||
52 | #include "socket_core.h" |
52 | #include "socket_core.h" |
53 | 53 | ||
54 | /** \todo |
54 | /** Bound port sockets. |
55 | */ |
55 | */ |
56 | struct socket_port{ |
56 | struct socket_port{ |
- | 57 | /** The bound sockets map. |
|
- | 58 | */ |
|
57 | socket_port_map_t map; |
59 | socket_port_map_t map; |
- | 60 | /** The bound sockets count. |
|
- | 61 | */ |
|
58 | int count; |
62 | int count; |
59 | }; |
63 | }; |
60 | 64 | ||
61 | /** \todo |
65 | /** Binds the socket to the port. |
- | 66 | * The SOCKET_MAP_KEY_LISTENING key identifier is used. |
|
- | 67 | * @param[in] global_sockets The global sockets to be updated. |
|
- | 68 | * @param[in] socket The socket to be added. |
|
- | 69 | * @param[in] port The port number to be bound to. |
|
- | 70 | * @returns EOK on success. |
|
- | 71 | * @returns ENOMEM if there is not enough memory left. |
|
- | 72 | * @returns Other error codes as defined for the socket_ports_add() function. |
|
62 | */ |
73 | */ |
63 | int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port ); |
74 | int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port ); |
64 | 75 | ||
65 | /** \todo |
76 | /** Destroys the socket. |
- | 77 | * If the socket is bound, the port is released. |
|
- | 78 | * Releases all buffered packets, calls the release function and removes the socket from the local sockets. |
|
- | 79 | * @param[in] packet_phone The packet server phone to release buffered packets. |
|
- | 80 | * @param[in] socket The socket to be destroyed. |
|
- | 81 | * @param[in,out] local_sockets The local sockets to be updated. |
|
- | 82 | * @param[in,out] global_sockets The global sockets to be updated. |
|
- | 83 | * @param[in] socket_release The client release callback function. |
|
66 | */ |
84 | */ |
67 | void socket_destroy_core( int packet_phone, socket_core_ref socket, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )); |
85 | void socket_destroy_core( int packet_phone, socket_core_ref socket, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )); |
68 | 86 | ||
- | 87 | /** Adds the socket to a socket port. |
|
- | 88 | * @param[in,out] socket_port The socket port structure. |
|
- | 89 | * @param[in] socket The socket to be added. |
|
- | 90 | * @param[in] key The socket key identifier. |
|
- | 91 | * @param[in] key_length The socket key length. |
|
69 | /** \todo |
92 | * @returns EOK on success. |
- | 93 | * @returns ENOMEM if there is not enough memory left. |
|
70 | */ |
94 | */ |
71 | int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length ); |
95 | int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length ); |
72 | 96 | ||
73 | INT_MAP_IMPLEMENT( socket_cores, socket_core_t ); |
97 | INT_MAP_IMPLEMENT( socket_cores, socket_core_t ); |
74 | 98 | ||
75 | GENERIC_CHAR_MAP_IMPLEMENT( socket_port_map, socket_core_ref ); |
99 | GENERIC_CHAR_MAP_IMPLEMENT( socket_port_map, socket_core_ref ); |
76 | 100 | ||
77 | INT_MAP_IMPLEMENT( socket_ports, socket_port_t ); |
101 | INT_MAP_IMPLEMENT( socket_ports, socket_port_t ); |
78 | 102 | ||
79 | void socket_cores_release( int packet_phone, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){ |
103 | void socket_cores_release( int packet_phone, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){ |
80 | if( socket_cores_is_valid( local_sockets )){ |
104 | if( socket_cores_is_valid( local_sockets )){ |
81 | int index; |
105 | int index; |
82 | 106 | ||
83 | local_sockets->magic = 0; |
107 | local_sockets->magic = 0; |
84 | for( index = 0; index < local_sockets->next; ++ index ){ |
108 | for( index = 0; index < local_sockets->next; ++ index ){ |
85 | if( socket_cores_item_is_valid( &( local_sockets->items[ index ] ))){ |
109 | if( socket_cores_item_is_valid( &( local_sockets->items[ index ] ))){ |
86 | local_sockets->items[ index ].magic = 0; |
110 | local_sockets->items[ index ].magic = 0; |
87 | if( local_sockets->items[ index ].value ){ |
111 | if( local_sockets->items[ index ].value ){ |
88 | socket_destroy_core( packet_phone, local_sockets->items[ index ].value, local_sockets, global_sockets, socket_release ); |
112 | socket_destroy_core( packet_phone, local_sockets->items[ index ].value, local_sockets, global_sockets, socket_release ); |
89 | free( local_sockets->items[ index ].value ); |
113 | free( local_sockets->items[ index ].value ); |
90 | local_sockets->items[ index ].value = NULL; |
114 | local_sockets->items[ index ].value = NULL; |
91 | } |
115 | } |
92 | } |
116 | } |
93 | } |
117 | } |
94 | free( local_sockets->items ); |
118 | free( local_sockets->items ); |
95 | } |
119 | } |
96 | } |
120 | } |
97 | 121 | ||
98 | void socket_destroy_core( int packet_phone, socket_core_ref socket, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){ |
122 | void socket_destroy_core( int packet_phone, socket_core_ref socket, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){ |
99 | int packet_id; |
123 | int packet_id; |
100 | 124 | ||
101 | // if bound |
125 | // if bound |
102 | if( socket->port ){ |
126 | if( socket->port ){ |
103 | // release the port |
127 | // release the port |
104 | socket_port_release( global_sockets, socket ); |
128 | socket_port_release( global_sockets, socket ); |
105 | } |
129 | } |
106 | // release all received packets |
130 | // release all received packets |
107 | while(( packet_id = dyn_fifo_pop( & socket->received )) >= 0 ){ |
131 | while(( packet_id = dyn_fifo_pop( & socket->received )) >= 0 ){ |
108 | pq_release( packet_phone, packet_id ); |
132 | pq_release( packet_phone, packet_id ); |
109 | } |
133 | } |
110 | dyn_fifo_destroy( & socket->received ); |
134 | dyn_fifo_destroy( & socket->received ); |
111 | dyn_fifo_destroy( & socket->accepted ); |
135 | dyn_fifo_destroy( & socket->accepted ); |
112 | if( socket_release ){ |
136 | if( socket_release ){ |
113 | socket_release( socket ); |
137 | socket_release( socket ); |
114 | } |
138 | } |
115 | socket_cores_exclude( local_sockets, socket->socket_id ); |
139 | socket_cores_exclude( local_sockets, socket->socket_id ); |
116 | } |
140 | } |
117 | 141 | ||
118 | int socket_bind( socket_cores_ref local_sockets, socket_ports_ref global_sockets, int socket_id, void * addr, size_t addrlen, int free_ports_start, int free_ports_end, int last_used_port ){ |
142 | int socket_bind( socket_cores_ref local_sockets, socket_ports_ref global_sockets, int socket_id, void * addr, size_t addrlen, int free_ports_start, int free_ports_end, int last_used_port ){ |
119 | socket_core_ref socket; |
143 | socket_core_ref socket; |
120 | socket_port_ref socket_port; |
144 | socket_port_ref socket_port; |
121 | struct sockaddr * address; |
145 | struct sockaddr * address; |
122 | struct sockaddr_in * address_in; |
146 | struct sockaddr_in * address_in; |
123 | 147 | ||
124 | if( addrlen < sizeof( struct sockaddr )) return EINVAL; |
148 | if( addrlen < sizeof( struct sockaddr )) return EINVAL; |
125 | address = ( struct sockaddr * ) addr; |
149 | address = ( struct sockaddr * ) addr; |
126 | switch( address->sa_family ){ |
150 | switch( address->sa_family ){ |
127 | case AF_INET: |
151 | case AF_INET: |
128 | if( addrlen != sizeof( struct sockaddr_in )) return EINVAL; |
152 | if( addrlen != sizeof( struct sockaddr_in )) return EINVAL; |
129 | address_in = ( struct sockaddr_in * ) addr; |
153 | address_in = ( struct sockaddr_in * ) addr; |
130 | // find the socket |
154 | // find the socket |
131 | socket = socket_cores_find( local_sockets, socket_id ); |
155 | socket = socket_cores_find( local_sockets, socket_id ); |
132 | if( ! socket ) return ENOTSOCK; |
156 | if( ! socket ) return ENOTSOCK; |
133 | // bind a free port? |
157 | // bind a free port? |
134 | if( address_in->sin_port <= 0 ){ |
158 | if( address_in->sin_port <= 0 ){ |
135 | return socket_bind_free_port( global_sockets, socket, free_ports_start, free_ports_end, last_used_port ); |
159 | return socket_bind_free_port( global_sockets, socket, free_ports_start, free_ports_end, last_used_port ); |
136 | } |
160 | } |
137 | // try to find the port |
161 | // try to find the port |
138 | socket_port = socket_ports_find( global_sockets, ntohs( address_in->sin_port )); |
162 | socket_port = socket_ports_find( global_sockets, ntohs( address_in->sin_port )); |
139 | if( socket_port ){ |
163 | if( socket_port ){ |
140 | // already used |
164 | // already used |
141 | return EADDRINUSE; |
165 | return EADDRINUSE; |
142 | } |
166 | } |
143 | // if bound |
167 | // if bound |
144 | if( socket->port ){ |
168 | if( socket->port ){ |
145 | // release the port |
169 | // release the port |
146 | socket_port_release( global_sockets, socket ); |
170 | socket_port_release( global_sockets, socket ); |
147 | } |
171 | } |
148 | socket->port = -1; |
172 | socket->port = -1; |
149 | return socket_bind_insert( global_sockets, socket, ntohs( address_in->sin_port )); |
173 | return socket_bind_insert( global_sockets, socket, ntohs( address_in->sin_port )); |
150 | break; |
174 | break; |
151 | // TODO IPv6 |
175 | // TODO IPv6 |
152 | } |
176 | } |
153 | return EAFNOSUPPORT; |
177 | return EAFNOSUPPORT; |
154 | } |
178 | } |
155 | 179 | ||
156 | int socket_bind_free_port( socket_ports_ref global_sockets, socket_core_ref socket, int free_ports_start, int free_ports_end, int last_used_port ){ |
180 | int socket_bind_free_port( socket_ports_ref global_sockets, socket_core_ref socket, int free_ports_start, int free_ports_end, int last_used_port ){ |
157 | int index; |
181 | int index; |
158 | 182 | ||
159 | // from the last used one |
183 | // from the last used one |
160 | index = last_used_port; |
184 | index = last_used_port; |
161 | do{ |
185 | do{ |
162 | ++ index; |
186 | ++ index; |
163 | // til the range end |
187 | // til the range end |
164 | if( index >= free_ports_end ){ |
188 | if( index >= free_ports_end ){ |
165 | // start from the range beginning |
189 | // start from the range beginning |
166 | index = free_ports_start - 1; |
190 | index = free_ports_start - 1; |
167 | do{ |
191 | do{ |
168 | ++ index; |
192 | ++ index; |
169 | // til the last used one |
193 | // til the last used one |
170 | if( index >= last_used_port ){ |
194 | if( index >= last_used_port ){ |
171 | // none found |
195 | // none found |
172 | return ENOTCONN; |
196 | return ENOTCONN; |
173 | } |
197 | } |
174 | }while( socket_ports_find( global_sockets, index ) != NULL ); |
198 | }while( socket_ports_find( global_sockets, index ) != NULL ); |
175 | // found, break immediately |
199 | // found, break immediately |
176 | break; |
200 | break; |
177 | } |
201 | } |
178 | }while( socket_ports_find( global_sockets, index ) != NULL ); |
202 | }while( socket_ports_find( global_sockets, index ) != NULL ); |
179 | return socket_bind_insert( global_sockets, socket, index ); |
203 | return socket_bind_insert( global_sockets, socket, index ); |
180 | } |
204 | } |
181 | 205 | ||
182 | int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port ){ |
206 | int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port ){ |
183 | ERROR_DECLARE; |
207 | ERROR_DECLARE; |
184 | 208 | ||
185 | socket_port_ref socket_port; |
209 | socket_port_ref socket_port; |
186 | 210 | ||
187 | // create a wrapper |
211 | // create a wrapper |
188 | socket_port = malloc( sizeof( * socket_port )); |
212 | socket_port = malloc( sizeof( * socket_port )); |
189 | if( ! socket_port ) return ENOMEM; |
213 | if( ! socket_port ) return ENOMEM; |
190 | socket_port->count = 0; |
214 | socket_port->count = 0; |
191 | if( ERROR_OCCURRED( socket_port_map_initialize( & socket_port->map )) |
215 | if( ERROR_OCCURRED( socket_port_map_initialize( & socket_port->map )) |
192 | || ERROR_OCCURRED( socket_port_add_core( socket_port, socket, SOCKET_MAP_KEY_LISTENING, 0 ))){ |
216 | || ERROR_OCCURRED( socket_port_add_core( socket_port, socket, SOCKET_MAP_KEY_LISTENING, 0 ))){ |
193 | socket_port_map_destroy( & socket_port->map ); |
217 | socket_port_map_destroy( & socket_port->map ); |
194 | free( socket_port ); |
218 | free( socket_port ); |
195 | return ERROR_CODE; |
219 | return ERROR_CODE; |
196 | } |
220 | } |
197 | // register the incomming port |
221 | // register the incomming port |
198 | ERROR_CODE = socket_ports_add( global_sockets, port, socket_port ); |
222 | ERROR_CODE = socket_ports_add( global_sockets, port, socket_port ); |
199 | if( ERROR_CODE < 0 ){ |
223 | if( ERROR_CODE < 0 ){ |
200 | socket_port_map_destroy( & socket_port->map ); |
224 | socket_port_map_destroy( & socket_port->map ); |
201 | free( socket_port ); |
225 | free( socket_port ); |
202 | return ERROR_CODE; |
226 | return ERROR_CODE; |
203 | } |
227 | } |
204 | socket->port = port; |
228 | socket->port = port; |
205 | return EOK; |
229 | return EOK; |
206 | } |
230 | } |
207 | 231 | ||
208 | int socket_create( socket_cores_ref local_sockets, int app_phone, void * specific_data, int * socket_id ){ |
232 | int socket_create( socket_cores_ref local_sockets, int app_phone, void * specific_data, int * socket_id ){ |
209 | ERROR_DECLARE; |
233 | ERROR_DECLARE; |
210 | 234 | ||
211 | socket_core_ref socket; |
235 | socket_core_ref socket; |
212 | int res; |
236 | int res; |
213 | 237 | ||
214 | if( ! socket_id ) return EBADMEM; |
238 | if( ! socket_id ) return EBADMEM; |
215 | socket = ( socket_core_ref ) malloc( sizeof( * socket )); |
239 | socket = ( socket_core_ref ) malloc( sizeof( * socket )); |
216 | if( ! socket ) return ENOMEM; |
240 | if( ! socket ) return ENOMEM; |
217 | // initialize |
241 | // initialize |
218 | socket->phone = app_phone; |
242 | socket->phone = app_phone; |
219 | socket->port = -1; |
243 | socket->port = -1; |
220 | socket->key = NULL; |
244 | socket->key = NULL; |
221 | socket->key_length = 0; |
245 | socket->key_length = 0; |
222 | socket->specific_data = specific_data; |
246 | socket->specific_data = specific_data; |
223 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){ |
247 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){ |
224 | free( socket ); |
248 | free( socket ); |
225 | return ERROR_CODE; |
249 | return ERROR_CODE; |
226 | } |
250 | } |
227 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){ |
251 | if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){ |
228 | dyn_fifo_destroy( & socket->received ); |
252 | dyn_fifo_destroy( & socket->received ); |
229 | free( socket ); |
253 | free( socket ); |
230 | return ERROR_CODE; |
254 | return ERROR_CODE; |
231 | } |
255 | } |
232 | // get a next free socket number |
256 | // get a next free socket number |
233 | socket->socket_id = socket_cores_count( local_sockets ) + 1; |
257 | socket->socket_id = socket_cores_count( local_sockets ) + 1; |
234 | // store the socket |
258 | // store the socket |
235 | res = socket_cores_add( local_sockets, socket->socket_id, socket ); |
259 | res = socket_cores_add( local_sockets, socket->socket_id, socket ); |
236 | if( res < 0 ){ |
260 | if( res < 0 ){ |
237 | dyn_fifo_destroy( & socket->received ); |
261 | dyn_fifo_destroy( & socket->received ); |
238 | dyn_fifo_destroy( & socket->accepted ); |
262 | dyn_fifo_destroy( & socket->accepted ); |
239 | free( socket ); |
263 | free( socket ); |
240 | return res; |
264 | return res; |
241 | } |
265 | } |
242 | // return the socket identifier |
266 | // return the socket identifier |
243 | * socket_id = socket->socket_id; |
267 | * socket_id = socket->socket_id; |
244 | return EOK; |
268 | return EOK; |
245 | } |
269 | } |
246 | 270 | ||
247 | int socket_destroy( int packet_phone, int socket_id, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){ |
271 | int socket_destroy( int packet_phone, int socket_id, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void ( * socket_release )( socket_core_ref socket )){ |
248 | socket_core_ref socket; |
272 | socket_core_ref socket; |
249 | int accepted_id; |
273 | int accepted_id; |
250 | 274 | ||
251 | // find the socket |
275 | // find the socket |
252 | socket = socket_cores_find( local_sockets, socket_id ); |
276 | socket = socket_cores_find( local_sockets, socket_id ); |
253 | if( ! socket ) return ENOTSOCK; |
277 | if( ! socket ) return ENOTSOCK; |
254 | // destroy all accepted sockets |
278 | // destroy all accepted sockets |
255 | while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){ |
279 | while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){ |
256 | socket_destroy( packet_phone, accepted_id, local_sockets, global_sockets, socket_release ); |
280 | socket_destroy( packet_phone, accepted_id, local_sockets, global_sockets, socket_release ); |
257 | } |
281 | } |
258 | socket_destroy_core( packet_phone, socket, local_sockets, global_sockets, socket_release ); |
282 | socket_destroy_core( packet_phone, socket, local_sockets, global_sockets, socket_release ); |
259 | return EOK; |
283 | return EOK; |
260 | } |
284 | } |
261 | 285 | ||
262 | int socket_reply_packets( packet_t packet, size_t * length ){ |
286 | int socket_reply_packets( packet_t packet, size_t * length ){ |
263 | ERROR_DECLARE; |
287 | ERROR_DECLARE; |
264 | 288 | ||
265 | packet_t next_packet; |
289 | packet_t next_packet; |
266 | size_t fragments; |
290 | size_t fragments; |
267 | size_t * lengths; |
291 | size_t * lengths; |
268 | size_t index; |
292 | size_t index; |
269 | 293 | ||
270 | if( ! length ){ |
294 | if( ! length ) return EBADMEM; |
271 | return EINVAL; |
- | |
272 | } |
- | |
273 | next_packet = pq_next( packet ); |
295 | next_packet = pq_next( packet ); |
274 | if( ! next_packet ){ |
296 | if( ! next_packet ){ |
275 | // write all if only one fragment |
297 | // write all if only one fragment |
276 | ERROR_PROPAGATE( data_reply( packet_get_data( packet ), packet_get_data_length( packet ))); |
298 | ERROR_PROPAGATE( data_reply( packet_get_data( packet ), packet_get_data_length( packet ))); |
277 | // store the total length |
299 | // store the total length |
278 | * length = packet_get_data_length( packet ); |
300 | * length = packet_get_data_length( packet ); |
279 | }else{ |
301 | }else{ |
280 | // count the packet fragments |
302 | // count the packet fragments |
281 | fragments = 1; |
303 | fragments = 1; |
282 | next_packet = pq_next( packet ); |
304 | next_packet = pq_next( packet ); |
283 | while(( next_packet = pq_next( next_packet ))){ |
305 | while(( next_packet = pq_next( next_packet ))){ |
284 | ++ fragments; |
306 | ++ fragments; |
285 | } |
307 | } |
286 | // compute and store the fragment lengths |
308 | // compute and store the fragment lengths |
287 | lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t )); |
309 | lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t )); |
288 | if( ! lengths ) return ENOMEM; |
310 | if( ! lengths ) return ENOMEM; |
289 | lengths[ 0 ] = packet_get_data_length( packet ); |
311 | lengths[ 0 ] = packet_get_data_length( packet ); |
290 | lengths[ fragments ] = lengths[ 0 ]; |
312 | lengths[ fragments ] = lengths[ 0 ]; |
291 | next_packet = pq_next( packet ); |
313 | next_packet = pq_next( packet ); |
292 | for( index = 1; index < fragments; ++ index ){ |
314 | for( index = 1; index < fragments; ++ index ){ |
293 | lengths[ index ] = packet_get_data_length( next_packet ); |
315 | lengths[ index ] = packet_get_data_length( next_packet ); |
294 | lengths[ fragments ] += lengths[ index ]; |
316 | lengths[ fragments ] += lengths[ index ]; |
295 | next_packet = pq_next( packet ); |
317 | next_packet = pq_next( packet ); |
296 | }while( next_packet ); |
318 | }while( next_packet ); |
297 | // write the fragment lengths |
319 | // write the fragment lengths |
298 | ERROR_PROPAGATE( data_reply( lengths, sizeof( int ) * ( fragments + 1 ))); |
320 | ERROR_PROPAGATE( data_reply( lengths, sizeof( int ) * ( fragments + 1 ))); |
299 | next_packet = packet; |
321 | next_packet = packet; |
300 | // write the fragments |
322 | // write the fragments |
301 | for( index = 0; index < fragments; ++ index ){ |
323 | for( index = 0; index < fragments; ++ index ){ |
302 | ERROR_PROPAGATE( data_reply( packet_get_data( next_packet ), lengths[ index ] )); |
324 | ERROR_PROPAGATE( data_reply( packet_get_data( next_packet ), lengths[ index ] )); |
303 | next_packet = pq_next( next_packet ); |
325 | next_packet = pq_next( next_packet ); |
304 | }while( next_packet ); |
326 | }while( next_packet ); |
305 | // store the total length |
327 | // store the total length |
306 | * length = lengths[ fragments ]; |
328 | * length = lengths[ fragments ]; |
307 | free( lengths ); |
329 | free( lengths ); |
308 | } |
330 | } |
309 | return EOK; |
331 | return EOK; |
310 | } |
332 | } |
311 | 333 | ||
312 | socket_core_ref socket_port_find( socket_ports_ref global_sockets, int port, const char * key, size_t key_length ){ |
334 | socket_core_ref socket_port_find( socket_ports_ref global_sockets, int port, const char * key, size_t key_length ){ |
313 | socket_port_ref socket_port; |
335 | socket_port_ref socket_port; |
314 | socket_core_ref * socket_ref; |
336 | socket_core_ref * socket_ref; |
315 | 337 | ||
316 | socket_port = socket_ports_find( global_sockets, port ); |
338 | socket_port = socket_ports_find( global_sockets, port ); |
317 | if( socket_port && ( socket_port->count > 0 )){ |
339 | if( socket_port && ( socket_port->count > 0 )){ |
318 | socket_ref = socket_port_map_find( & socket_port->map, key, key_length ); |
340 | socket_ref = socket_port_map_find( & socket_port->map, key, key_length ); |
319 | if( socket_ref ){ |
341 | if( socket_ref ){ |
320 | return * socket_ref; |
342 | return * socket_ref; |
321 | } |
343 | } |
322 | } |
344 | } |
323 | return NULL; |
345 | return NULL; |
324 | } |
346 | } |
325 | 347 | ||
326 | void socket_port_release( socket_ports_ref global_sockets, socket_core_ref socket ){ |
348 | void socket_port_release( socket_ports_ref global_sockets, socket_core_ref socket ){ |
327 | socket_port_ref socket_port; |
349 | socket_port_ref socket_port; |
328 | socket_core_ref * socket_ref; |
350 | socket_core_ref * socket_ref; |
329 | 351 | ||
330 | if( socket->port ){ |
352 | if( socket->port ){ |
331 | // find ports |
353 | // find ports |
332 | socket_port = socket_ports_find( global_sockets, socket->port ); |
354 | socket_port = socket_ports_find( global_sockets, socket->port ); |
333 | if( socket_port ){ |
355 | if( socket_port ){ |
334 | // find the socket |
356 | // find the socket |
335 | socket_ref = socket_port_map_find( & socket_port->map, socket->key, socket->key_length ); |
357 | socket_ref = socket_port_map_find( & socket_port->map, socket->key, socket->key_length ); |
336 | if( socket_ref ){ |
358 | if( socket_ref ){ |
337 | -- socket_port->count; |
359 | -- socket_port->count; |
338 | // release if empty |
360 | // release if empty |
339 | if( socket_port->count <= 0 ){ |
361 | if( socket_port->count <= 0 ){ |
340 | // destroy the map |
362 | // destroy the map |
341 | socket_port_map_destroy( & socket_port->map ); |
363 | socket_port_map_destroy( & socket_port->map ); |
342 | // release the port |
364 | // release the port |
343 | socket_ports_exclude( global_sockets, socket->port ); |
365 | socket_ports_exclude( global_sockets, socket->port ); |
344 | }else{ |
366 | }else{ |
345 | // remove |
367 | // remove |
346 | socket_port_map_exclude( & socket_port->map, socket->key, socket->key_length ); |
368 | socket_port_map_exclude( & socket_port->map, socket->key, socket->key_length ); |
347 | } |
369 | } |
348 | } |
370 | } |
349 | } |
371 | } |
350 | socket->port = 0; |
372 | socket->port = 0; |
351 | socket->key = NULL; |
373 | socket->key = NULL; |
352 | socket->key_length = 0; |
374 | socket->key_length = 0; |
353 | } |
375 | } |
354 | } |
376 | } |
355 | 377 | ||
356 | int socket_port_add( socket_ports_ref global_sockets, int port, socket_core_ref socket, const char * key, size_t key_length ){ |
378 | int socket_port_add( socket_ports_ref global_sockets, int port, socket_core_ref socket, const char * key, size_t key_length ){ |
357 | ERROR_DECLARE; |
379 | ERROR_DECLARE; |
358 | 380 | ||
359 | socket_port_ref socket_port; |
381 | socket_port_ref socket_port; |
360 | 382 | ||
361 | // find ports |
383 | // find ports |
362 | socket_port = socket_ports_find( global_sockets, port ); |
384 | socket_port = socket_ports_find( global_sockets, port ); |
363 | if( ! socket_port ) return ENOENT; |
385 | if( ! socket_port ) return ENOENT; |
364 | // add the socket |
386 | // add the socket |
365 | ERROR_PROPAGATE( socket_port_add_core( socket_port, socket, key, key_length )); |
387 | ERROR_PROPAGATE( socket_port_add_core( socket_port, socket, key, key_length )); |
366 | socket->port = port; |
388 | socket->port = port; |
367 | return EOK; |
389 | return EOK; |
368 | } |
390 | } |
369 | 391 | ||
370 | int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length ){ |
392 | int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length ){ |
371 | ERROR_DECLARE; |
393 | ERROR_DECLARE; |
372 | 394 | ||
373 | socket_core_ref * socket_ref; |
395 | socket_core_ref * socket_ref; |
374 | 396 | ||
375 | // create a wrapper |
397 | // create a wrapper |
376 | socket_ref = malloc( sizeof( * socket_ref )); |
398 | socket_ref = malloc( sizeof( * socket_ref )); |
377 | if( ! socket_ref ) return ENOMEM; |
399 | if( ! socket_ref ) return ENOMEM; |
378 | * socket_ref = socket; |
400 | * socket_ref = socket; |
379 | // add the wrapper |
401 | // add the wrapper |
380 | if( ERROR_OCCURRED( socket_port_map_add( & socket_port->map, key, key_length, socket_ref ))){ |
402 | if( ERROR_OCCURRED( socket_port_map_add( & socket_port->map, key, key_length, socket_ref ))){ |
381 | free( socket_ref ); |
403 | free( socket_ref ); |
382 | return ERROR_CODE; |
404 | return ERROR_CODE; |
383 | } |
405 | } |
384 | ++ socket_port->count; |
406 | ++ socket_port->count; |
385 | socket->key = key; |
407 | socket->key = key; |
386 | socket->key_length = key_length; |
408 | socket->key_length = key_length; |
387 | return EOK; |
409 | return EOK; |
388 | } |
410 | } |
389 | 411 | ||
390 | /** @} |
412 | /** @} |
391 | */ |
413 | */ |
392 | 414 |