Subversion Repositories HelenOS

Rev

Rev 4738 | Details | Compare with Previous | Last modification | View Log | RSS feed

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