2
* Copyright (c) 2009 Lukas Mejdrech
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
29
/** @addtogroup socket
34
* Socket common core implementation.
42
#include "../include/in.h"
43
#include "../include/inet.h"
45
#include "../include/socket_codes.h"
46
#include "../include/socket_errno.h"
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"
53
#include "../modules.h"
55
#include "socket_core.h"
57
/** Maximum number of random attempts to find a new socket identifier before switching to the sequence.
59
#define SOCKET_ID_TRIES 100
61
/** Bound port sockets.
64
/** The bound sockets map.
66
socket_port_map_t map;
67
/** The bound sockets count.
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.
81
int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port );
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.
92
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 ));
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.
102
int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length );
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.
110
static int socket_generate_new_id( socket_cores_ref local_sockets, int positive );
112
INT_MAP_IMPLEMENT( socket_cores, socket_core_t );
114
GENERIC_CHAR_MAP_IMPLEMENT( socket_port_map, socket_core_ref );
116
INT_MAP_IMPLEMENT( socket_ports, socket_port_t );
118
void 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 )){
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;
133
free( local_sockets->items );
137
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 )){
143
socket_port_release( global_sockets, socket );
145
// release all received packets
146
while(( packet_id = dyn_fifo_pop( & socket->received )) >= 0 ){
147
pq_release( packet_phone, packet_id );
149
dyn_fifo_destroy( & socket->received );
150
dyn_fifo_destroy( & socket->accepted );
151
if( socket_release ){
152
socket_release( socket );
154
socket_cores_exclude( local_sockets, socket->socket_id );
157
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 ){
158
socket_core_ref socket;
159
socket_port_ref socket_port;
160
struct sockaddr * address;
161
struct sockaddr_in * address_in;
163
if( addrlen < sizeof( struct sockaddr )) return EINVAL;
164
address = ( struct sockaddr * ) addr;
165
switch( address->sa_family ){
167
if( addrlen != sizeof( struct sockaddr_in )) return EINVAL;
168
address_in = ( struct sockaddr_in * ) addr;
170
socket = socket_cores_find( local_sockets, socket_id );
171
if( ! socket ) return ENOTSOCK;
173
if( address_in->sin_port <= 0 ){
174
return socket_bind_free_port( global_sockets, socket, free_ports_start, free_ports_end, last_used_port );
176
// try to find the port
177
socket_port = socket_ports_find( global_sockets, ntohs( address_in->sin_port ));
185
socket_port_release( global_sockets, socket );
188
return socket_bind_insert( global_sockets, socket, ntohs( address_in->sin_port ));
195
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 ){
198
// from the last used one
199
index = last_used_port;
203
if( index >= free_ports_end ){
204
// start from the range beginning
205
index = free_ports_start - 1;
208
// til the last used one
209
if( index >= last_used_port ){
213
}while( socket_ports_find( global_sockets, index ) != NULL );
214
// found, break immediately
217
}while( socket_ports_find( global_sockets, index ) != NULL );
218
return socket_bind_insert( global_sockets, socket, index );
221
int socket_bind_insert( socket_ports_ref global_sockets, socket_core_ref socket, int port ){
224
socket_port_ref socket_port;
227
socket_port = malloc( sizeof( * socket_port ));
228
if( ! socket_port ) return ENOMEM;
229
socket_port->count = 0;
230
if( ERROR_OCCURRED( socket_port_map_initialize( & socket_port->map ))
231
|| ERROR_OCCURRED( socket_port_add_core( socket_port, socket, SOCKET_MAP_KEY_LISTENING, 0 ))){
232
socket_port_map_destroy( & socket_port->map );
236
// register the incomming port
237
ERROR_CODE = socket_ports_add( global_sockets, port, socket_port );
238
if( ERROR_CODE < 0 ){
239
socket_port_map_destroy( & socket_port->map );
248
static int socket_generate_new_id( socket_cores_ref local_sockets, int positive ){
253
// socket_id = socket_globals.last_id;
255
if( count < SOCKET_ID_TRIES ){
256
socket_id = rand() % INT_MAX;
258
}else if( count == SOCKET_ID_TRIES ){
261
// only this branch for last_id
263
if( socket_id < INT_MAX ){
265
/* }else if( socket_globals.last_id ){
266
* socket_globals.last_id = 0;
272
}while( socket_cores_find( local_sockets, (( positive ? 1 : -1 ) * socket_id )));
273
// last_id = socket_id
277
int socket_create( socket_cores_ref local_sockets, int app_phone, void * specific_data, int * socket_id ){
280
socket_core_ref socket;
284
if( ! socket_id ) return EINVAL;
286
if( * socket_id <= 0 ){
287
positive = ( * socket_id == 0 );
288
* socket_id = socket_generate_new_id( local_sockets, positive );
289
if( * socket_id <= 0 ){
295
}else if( socket_cores_find( local_sockets, * socket_id )){
298
socket = ( socket_core_ref ) malloc( sizeof( * socket ));
299
if( ! socket ) return ENOMEM;
301
socket->phone = app_phone;
304
socket->key_length = 0;
305
socket->specific_data = specific_data;
306
if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->received, SOCKET_INITIAL_RECEIVED_SIZE ))){
310
if( ERROR_OCCURRED( dyn_fifo_initialize( & socket->accepted, SOCKET_INITIAL_ACCEPTED_SIZE ))){
311
dyn_fifo_destroy( & socket->received );
315
socket->socket_id = * socket_id;
316
res = socket_cores_add( local_sockets, socket->socket_id, socket );
318
dyn_fifo_destroy( & socket->received );
319
dyn_fifo_destroy( & socket->accepted );
326
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 )){
327
socket_core_ref socket;
331
socket = socket_cores_find( local_sockets, socket_id );
332
if( ! socket ) return ENOTSOCK;
333
// destroy all accepted sockets
334
while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){
335
socket_destroy( packet_phone, accepted_id, local_sockets, global_sockets, socket_release );
337
socket_destroy_core( packet_phone, socket, local_sockets, global_sockets, socket_release );
341
int socket_reply_packets( packet_t packet, size_t * length ){
344
packet_t next_packet;
349
if( ! length ) return EBADMEM;
350
next_packet = pq_next( packet );
352
// write all if only one fragment
353
ERROR_PROPAGATE( data_reply( packet_get_data( packet ), packet_get_data_length( packet )));
354
// store the total length
355
* length = packet_get_data_length( packet );
357
// count the packet fragments
359
next_packet = pq_next( packet );
360
while(( next_packet = pq_next( next_packet ))){
363
// compute and store the fragment lengths
364
lengths = ( size_t * ) malloc( sizeof( size_t ) * fragments + sizeof( size_t ));
365
if( ! lengths ) return ENOMEM;
366
lengths[ 0 ] = packet_get_data_length( packet );
367
lengths[ fragments ] = lengths[ 0 ];
368
next_packet = pq_next( packet );
369
for( index = 1; index < fragments; ++ index ){
370
lengths[ index ] = packet_get_data_length( next_packet );
371
lengths[ fragments ] += lengths[ index ];
372
next_packet = pq_next( packet );
373
}while( next_packet );
374
// write the fragment lengths
375
ERROR_PROPAGATE( data_reply( lengths, sizeof( int ) * ( fragments + 1 )));
376
next_packet = packet;
377
// write the fragments
378
for( index = 0; index < fragments; ++ index ){
379
ERROR_PROPAGATE( data_reply( packet_get_data( next_packet ), lengths[ index ] ));
380
next_packet = pq_next( next_packet );
381
}while( next_packet );
382
// store the total length
383
* length = lengths[ fragments ];
389
socket_core_ref socket_port_find( socket_ports_ref global_sockets, int port, const char * key, size_t key_length ){
390
socket_port_ref socket_port;
391
socket_core_ref * socket_ref;
393
socket_port = socket_ports_find( global_sockets, port );
394
if( socket_port && ( socket_port->count > 0 )){
395
socket_ref = socket_port_map_find( & socket_port->map, key, key_length );
403
void socket_port_release( socket_ports_ref global_sockets, socket_core_ref socket ){
404
socket_port_ref socket_port;
405
socket_core_ref * socket_ref;
409
socket_port = socket_ports_find( global_sockets, socket->port );
412
socket_ref = socket_port_map_find( & socket_port->map, socket->key, socket->key_length );
414
-- socket_port->count;
416
if( socket_port->count <= 0 ){
418
socket_port_map_destroy( & socket_port->map );
420
socket_ports_exclude( global_sockets, socket->port );
423
socket_port_map_exclude( & socket_port->map, socket->key, socket->key_length );
429
socket->key_length = 0;
433
int socket_port_add( socket_ports_ref global_sockets, int port, socket_core_ref socket, const char * key, size_t key_length ){
436
socket_port_ref socket_port;
439
socket_port = socket_ports_find( global_sockets, port );
440
if( ! socket_port ) return ENOENT;
442
ERROR_PROPAGATE( socket_port_add_core( socket_port, socket, key, key_length ));
447
int socket_port_add_core( socket_port_ref socket_port, socket_core_ref socket, const char * key, size_t key_length ){
450
socket_core_ref * socket_ref;
453
socket_ref = malloc( sizeof( * socket_ref ));
454
if( ! socket_ref ) return ENOMEM;
455
* socket_ref = socket;
457
if( ERROR_OCCURRED( socket_port_map_add( & socket_port->map, key, key_length, socket_ref ))){
461
++ socket_port->count;
463
socket->key_length = key_length;