source: mainline/uspace/srv/net/socket/socket_core.c@ 6092b56e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6092b56e was aadf01e, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago

Coding style (no functional change)

  • Property mode set to 100644
File size: 14.6 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup socket
30 * @{
31 */
32
33/** @file
34 * Socket common core implementation.
35 */
36
37#include <limits.h>
38#include <stdlib.h>
39
40#include "../err.h"
41
42#include "../include/in.h"
43#include "../include/inet.h"
44
45#include "../include/socket_codes.h"
46#include "../include/socket_errno.h"
47
48#include "../structures/dynamic_fifo.h"
49#include "../structures/int_map.h"
50#include "../structures/packet/packet.h"
51#include "../structures/packet/packet_client.h"
52
53#include "../modules.h"
54
55#include "socket_core.h"
56
57/** Maximum number of random attempts to find a new socket identifier before switching to the sequence.
58 */
59#define SOCKET_ID_TRIES 100
60
61/** Bound port sockets.
62 */
63struct socket_port{
64 /** The bound sockets map.
65 */
66 socket_port_map_t map;
67 /** The bound sockets count.
68 */
69 int count;
70};
71
72/** Binds the socket to the port.
73 * The SOCKET_MAP_KEY_LISTENING key identifier is used.
74 * @param[in] global_sockets The global sockets to be updated.
75 * @param[in] socket The socket to be added.
76 * @param[in] port The port number to be bound to.
77 * @returns EOK on success.
78 * @returns ENOMEM if there is not enough memory left.
79 * @returns Other error codes as defined for the socket_ports_add() function.
80 */
81int socket_bind_insert(socket_ports_ref global_sockets, socket_core_ref socket, int port);
82
83/** Destroys the socket.
84 * If the socket is bound, the port is released.
85 * Releases all buffered packets, calls the release function and removes the socket from the local sockets.
86 * @param[in] packet_phone The packet server phone to release buffered packets.
87 * @param[in] socket The socket to be destroyed.
88 * @param[in,out] local_sockets The local sockets to be updated.
89 * @param[in,out] global_sockets The global sockets to be updated.
90 * @param[in] socket_release The client release callback function.
91 */
92void 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));
93
94/** Adds the socket to a socket port.
95 * @param[in,out] socket_port The socket port structure.
96 * @param[in] socket The socket to be added.
97 * @param[in] key The socket key identifier.
98 * @param[in] key_length The socket key length.
99 * @returns EOK on success.
100 * @returns ENOMEM if there is not enough memory left.
101 */
102int socket_port_add_core(socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length);
103
104/** Tries to find a new free socket identifier.
105 * @param[in] local_sockets The local sockets to be searched.
106 * @param[in] positive A value indicating whether a positive identifier is requested. A negative identifier is requested if set to false.
107 * @returns The new socket identifier.
108 * @returns ELIMIT if there is no socket identifier available.
109 */
110static int socket_generate_new_id(socket_cores_ref local_sockets, int positive);
111
112INT_MAP_IMPLEMENT(socket_cores, socket_core_t);
113
114GENERIC_CHAR_MAP_IMPLEMENT(socket_port_map, socket_core_ref);
115
116INT_MAP_IMPLEMENT(socket_ports, socket_port_t);
117
118void socket_cores_release(int packet_phone, socket_cores_ref local_sockets, socket_ports_ref global_sockets, void (*socket_release)(socket_core_ref socket)){
119 if(socket_cores_is_valid(local_sockets)){
120 int index;
121
122 local_sockets->magic = 0;
123 for(index = 0; index < local_sockets->next; ++ index){
124 if(socket_cores_item_is_valid(&(local_sockets->items[index]))){
125 local_sockets->items[index].magic = 0;
126 if(local_sockets->items[index].value){
127 socket_destroy_core(packet_phone, local_sockets->items[index].value, local_sockets, global_sockets, socket_release);
128 free(local_sockets->items[index].value);
129 local_sockets->items[index].value = NULL;
130 }
131 }
132 }
133 free(local_sockets->items);
134 }
135}
136
137void 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)){
138 int packet_id;
139
140 // if bound
141 if(socket->port){
142 // release the port
143 socket_port_release(global_sockets, socket);
144 }
145 // release all received packets
146 while((packet_id = dyn_fifo_pop(&socket->received)) >= 0){
147 pq_release(packet_phone, packet_id);
148 }
149 dyn_fifo_destroy(&socket->received);
150 dyn_fifo_destroy(&socket->accepted);
151 if(socket_release){
152 socket_release(socket);
153 }
154 socket_cores_exclude(local_sockets, socket->socket_id);
155}
156
157int 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){
158 socket_core_ref socket;
159 socket_port_ref socket_port;
160 struct sockaddr * address;
161 struct sockaddr_in * address_in;
162
163 if(addrlen < sizeof(struct sockaddr)){
164 return EINVAL;
165 }
166 address = (struct sockaddr *) addr;
167 switch(address->sa_family){
168 case AF_INET:
169 if(addrlen != sizeof(struct sockaddr_in)){
170 return EINVAL;
171 }
172 address_in = (struct sockaddr_in *) addr;
173 // find the socket
174 socket = socket_cores_find(local_sockets, socket_id);
175 if(! socket){
176 return ENOTSOCK;
177 }
178 // bind a free port?
179 if(address_in->sin_port <= 0){
180 return socket_bind_free_port(global_sockets, socket, free_ports_start, free_ports_end, last_used_port);
181 }
182 // try to find the port
183 socket_port = socket_ports_find(global_sockets, ntohs(address_in->sin_port));
184 if(socket_port){
185 // already used
186 return EADDRINUSE;
187 }
188 // if bound
189 if(socket->port){
190 // release the port
191 socket_port_release(global_sockets, socket);
192 }
193 socket->port = -1;
194 return socket_bind_insert(global_sockets, socket, ntohs(address_in->sin_port));
195 break;
196 // TODO IPv6
197 }
198 return EAFNOSUPPORT;
199}
200
201int 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){
202 int index;
203
204 // from the last used one
205 index = last_used_port;
206 do{
207 ++ index;
208 // til the range end
209 if(index >= free_ports_end){
210 // start from the range beginning
211 index = free_ports_start - 1;
212 do{
213 ++ index;
214 // til the last used one
215 if(index >= last_used_port){
216 // none found
217 return ENOTCONN;
218 }
219 }while(socket_ports_find(global_sockets, index) != NULL);
220 // found, break immediately
221 break;
222 }
223 }while(socket_ports_find(global_sockets, index) != NULL);
224 return socket_bind_insert(global_sockets, socket, index);
225}
226
227int socket_bind_insert(socket_ports_ref global_sockets, socket_core_ref socket, int port){
228 ERROR_DECLARE;
229
230 socket_port_ref socket_port;
231
232 // create a wrapper
233 socket_port = malloc(sizeof(*socket_port));
234 if(! socket_port){
235 return ENOMEM;
236 }
237 socket_port->count = 0;
238 if(ERROR_OCCURRED(socket_port_map_initialize(&socket_port->map))
239 || ERROR_OCCURRED(socket_port_add_core(socket_port, socket, SOCKET_MAP_KEY_LISTENING, 0))){
240 socket_port_map_destroy(&socket_port->map);
241 free(socket_port);
242 return ERROR_CODE;
243 }
244 // register the incomming port
245 ERROR_CODE = socket_ports_add(global_sockets, port, socket_port);
246 if(ERROR_CODE < 0){
247 socket_port_map_destroy(&socket_port->map);
248 free(socket_port);
249 return ERROR_CODE;
250 }
251 socket->port = port;
252 return EOK;
253}
254
255
256static int socket_generate_new_id(socket_cores_ref local_sockets, int positive){
257 int socket_id;
258 int count;
259
260 count = 0;
261// socket_id = socket_globals.last_id;
262 do{
263 if(count < SOCKET_ID_TRIES){
264 socket_id = rand() % INT_MAX;
265 ++ count;
266 }else if(count == SOCKET_ID_TRIES){
267 socket_id = 1;
268 ++ count;
269 // only this branch for last_id
270 }else{
271 if(socket_id < INT_MAX){
272 ++ socket_id;
273/* }else if(socket_globals.last_id){
274* socket_globals.last_id = 0;
275* socket_id = 1;
276*/ }else{
277 return ELIMIT;
278 }
279 }
280 }while(socket_cores_find(local_sockets, ((positive ? 1 : -1) * socket_id)));
281// last_id = socket_id
282 return socket_id;
283}
284
285int socket_create(socket_cores_ref local_sockets, int app_phone, void * specific_data, int * socket_id){
286 ERROR_DECLARE;
287
288 socket_core_ref socket;
289 int res;
290 int positive;
291
292 if(! socket_id){
293 return EINVAL;
294 }
295 // store the socket
296 if(*socket_id <= 0){
297 positive = (*socket_id == 0);
298 *socket_id = socket_generate_new_id(local_sockets, positive);
299 if(*socket_id <= 0){
300 return * socket_id;
301 }
302 if(! positive){
303 *socket_id *= -1;
304 }
305 }else if(socket_cores_find(local_sockets, * socket_id)){
306 return EEXIST;
307 }
308 socket = (socket_core_ref) malloc(sizeof(*socket));
309 if(! socket){
310 return ENOMEM;
311 }
312 // initialize
313 socket->phone = app_phone;
314 socket->port = -1;
315 socket->key = NULL;
316 socket->key_length = 0;
317 socket->specific_data = specific_data;
318 if(ERROR_OCCURRED(dyn_fifo_initialize(&socket->received, SOCKET_INITIAL_RECEIVED_SIZE))){
319 free(socket);
320 return ERROR_CODE;
321 }
322 if(ERROR_OCCURRED(dyn_fifo_initialize(&socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE))){
323 dyn_fifo_destroy(&socket->received);
324 free(socket);
325 return ERROR_CODE;
326 }
327 socket->socket_id = * socket_id;
328 res = socket_cores_add(local_sockets, socket->socket_id, socket);
329 if(res < 0){
330 dyn_fifo_destroy(&socket->received);
331 dyn_fifo_destroy(&socket->accepted);
332 free(socket);
333 return res;
334 }
335 return EOK;
336}
337
338int 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)){
339 socket_core_ref socket;
340 int accepted_id;
341
342 // find the socket
343 socket = socket_cores_find(local_sockets, socket_id);
344 if(! socket){
345 return ENOTSOCK;
346 }
347 // destroy all accepted sockets
348 while((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0){
349 socket_destroy(packet_phone, accepted_id, local_sockets, global_sockets, socket_release);
350 }
351 socket_destroy_core(packet_phone, socket, local_sockets, global_sockets, socket_release);
352 return EOK;
353}
354
355int socket_reply_packets(packet_t packet, size_t * length){
356 ERROR_DECLARE;
357
358 packet_t next_packet;
359 size_t fragments;
360 size_t * lengths;
361 size_t index;
362
363 if(! length){
364 return EBADMEM;
365 }
366 next_packet = pq_next(packet);
367 if(! next_packet){
368 // write all if only one fragment
369 ERROR_PROPAGATE(data_reply(packet_get_data(packet), packet_get_data_length(packet)));
370 // store the total length
371 *length = packet_get_data_length(packet);
372 }else{
373 // count the packet fragments
374 fragments = 1;
375 next_packet = pq_next(packet);
376 while((next_packet = pq_next(next_packet))){
377 ++ fragments;
378 }
379 // compute and store the fragment lengths
380 lengths = (size_t *) malloc(sizeof(size_t) * fragments + sizeof(size_t));
381 if(! lengths){
382 return ENOMEM;
383 }
384 lengths[0] = packet_get_data_length(packet);
385 lengths[fragments] = lengths[0];
386 next_packet = pq_next(packet);
387 for(index = 1; index < fragments; ++ index){
388 lengths[index] = packet_get_data_length(next_packet);
389 lengths[fragments] += lengths[index];
390 next_packet = pq_next(packet);
391 }while(next_packet);
392 // write the fragment lengths
393 ERROR_PROPAGATE(data_reply(lengths, sizeof(int) * (fragments + 1)));
394 next_packet = packet;
395 // write the fragments
396 for(index = 0; index < fragments; ++ index){
397 ERROR_PROPAGATE(data_reply(packet_get_data(next_packet), lengths[index]));
398 next_packet = pq_next(next_packet);
399 }while(next_packet);
400 // store the total length
401 *length = lengths[fragments];
402 free(lengths);
403 }
404 return EOK;
405}
406
407socket_core_ref socket_port_find(socket_ports_ref global_sockets, int port, const char * key, size_t key_length){
408 socket_port_ref socket_port;
409 socket_core_ref * socket_ref;
410
411 socket_port = socket_ports_find(global_sockets, port);
412 if(socket_port && (socket_port->count > 0)){
413 socket_ref = socket_port_map_find(&socket_port->map, key, key_length);
414 if(socket_ref){
415 return * socket_ref;
416 }
417 }
418 return NULL;
419}
420
421void socket_port_release(socket_ports_ref global_sockets, socket_core_ref socket){
422 socket_port_ref socket_port;
423 socket_core_ref * socket_ref;
424
425 if(socket->port){
426 // find ports
427 socket_port = socket_ports_find(global_sockets, socket->port);
428 if(socket_port){
429 // find the socket
430 socket_ref = socket_port_map_find(&socket_port->map, socket->key, socket->key_length);
431 if(socket_ref){
432 -- socket_port->count;
433 // release if empty
434 if(socket_port->count <= 0){
435 // destroy the map
436 socket_port_map_destroy(&socket_port->map);
437 // release the port
438 socket_ports_exclude(global_sockets, socket->port);
439 }else{
440 // remove
441 socket_port_map_exclude(&socket_port->map, socket->key, socket->key_length);
442 }
443 }
444 }
445 socket->port = 0;
446 socket->key = NULL;
447 socket->key_length = 0;
448 }
449}
450
451int socket_port_add(socket_ports_ref global_sockets, int port, socket_core_ref socket, const char * key, size_t key_length){
452 ERROR_DECLARE;
453
454 socket_port_ref socket_port;
455
456 // find ports
457 socket_port = socket_ports_find(global_sockets, port);
458 if(! socket_port){
459 return ENOENT;
460 }
461 // add the socket
462 ERROR_PROPAGATE(socket_port_add_core(socket_port, socket, key, key_length));
463 socket->port = port;
464 return EOK;
465}
466
467int socket_port_add_core(socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length){
468 ERROR_DECLARE;
469
470 socket_core_ref * socket_ref;
471
472 // create a wrapper
473 socket_ref = malloc(sizeof(*socket_ref));
474 if(! socket_ref){
475 return ENOMEM;
476 }
477 *socket_ref = socket;
478 // add the wrapper
479 if(ERROR_OCCURRED(socket_port_map_add(&socket_port->map, key, key_length, socket_ref))){
480 free(socket_ref);
481 return ERROR_CODE;
482 }
483 ++ socket_port->count;
484 socket->key = key;
485 socket->key_length = key_length;
486 return EOK;
487}
488
489/** @}
490 */
Note: See TracBrowser for help on using the repository browser.