Subversion Repositories HelenOS

Rev

Rev 4603 | Rev 4708 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4603 Rev 4701
Line 52... Line 52...
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.
-
 
58
 */
57
#define SOCKET_INITIAL_RECEIVED_SIZE    4
59
#define SOCKET_INITIAL_RECEIVED_SIZE    4
-
 
60
 
-
 
61
/** Maximum received packet queue size.
-
 
62
 */
58
#define SOCKET_MAX_RECEIVED_SIZE        64
63
#define SOCKET_MAX_RECEIVED_SIZE        64
59
 
64
 
-
 
65
/** Initial waiting sockets queue size.
-
 
66
 */
60
#define SOCKET_INITIAL_ACCEPTED_SIZE    1
67
#define SOCKET_INITIAL_ACCEPTED_SIZE    1
-
 
68
 
-
 
69
/** Maximum waiting sockets queue size.
-
 
70
 */
61
#define SOCKET_MAX_ACCEPTED_SIZE        64
71
#define SOCKET_MAX_ACCEPTED_SIZE        64
62
 
72
 
-
 
73
/** Type definition of the socket specific data.
-
 
74
 *  @see socket
-
 
75
 */
63
typedef struct socket   socket_t;
76
typedef struct socket   socket_t;
64
typedef socket_t *      socket_ref;
-
 
65
 
77
 
-
 
78
/** Type definition of the socket specific data pointer.
-
 
79
 *  @see socket
-
 
80
 */
-
 
81
typedef socket_t *  socket_ref;
-
 
82
 
-
 
83
/** Socket specific data.
-
 
84
 */
66
struct socket{
85
struct socket{
-
 
86
    /** Socket identifier.
-
 
87
     */
67
    int                 socket_id;
88
    int                 socket_id;
-
 
89
    /** Parent module phone.
-
 
90
     */
68
    int                 phone;
91
    int                 phone;
-
 
92
    /** Parent module service.
-
 
93
     */
69
    services_t          service;
94
    services_t          service;
-
 
95
    /** Underlying protocol header size.
-
 
96
     *  Sending and receiving optimalization.
-
 
97
     */
70
    int                 header_size;
98
    int                 header_size;
-
 
99
    /** Packet data fragment size.
-
 
100
     *  Sending and receiving optimalization.
-
 
101
     */
71
    int                 data_fragment_size;
102
    int                 data_fragment_size;
-
 
103
    /** Received packets queue.
-
 
104
     */
72
    dyn_fifo_t          received;
105
    dyn_fifo_t          received;
-
 
106
    /** Received packets safety lock.
-
 
107
     */
73
    fibril_mutex_t      receive_lock;
108
    fibril_mutex_t      receive_lock;
-
 
109
    /** Received packets signaling.
-
 
110
     */
74
    fibril_condvar_t    receive_signal;
111
    fibril_condvar_t    receive_signal;
-
 
112
    /** Waiting sockets queue.
-
 
113
     */
75
    dyn_fifo_t          accepted;
114
    dyn_fifo_t          accepted;
-
 
115
    /** Waiting sockets safety lock.
-
 
116
     */
76
    fibril_mutex_t      accept_lock;
117
    fibril_mutex_t      accept_lock;
-
 
118
    /** Waiting sockets signaling.
-
 
119
     */
77
    fibril_condvar_t    accept_signal;
120
    fibril_condvar_t    accept_signal;
78
};
121
};
79
 
122
 
-
 
123
/** Sockets map.
-
 
124
 *  Maps socket identifiers to the socket specific data.
-
 
125
 *  @see int_map.h
-
 
126
 */
80
INT_MAP_DECLARE( sockets, socket_t );
127
INT_MAP_DECLARE( sockets, socket_t );
81
 
128
 
-
 
129
/** Socket client library global data.
-
 
130
 */
82
static struct{
131
static struct{
-
 
132
    /** TCP module phone.
-
 
133
     */
83
    int tcp_phone;
134
    int tcp_phone;
-
 
135
    /** UDP module phone.
-
 
136
     */
84
    int udp_phone;
137
    int udp_phone;
-
 
138
    /** Active sockets.
-
 
139
     */
85
    sockets_ref sockets;
140
    sockets_ref sockets;
86
} socket_globals = { -1, -1, NULL };
141
} socket_globals = { -1, -1, NULL };
87
 
142
 
88
INT_MAP_IMPLEMENT( sockets, socket_t );
143
INT_MAP_IMPLEMENT( sockets, socket_t );
89
 
144
 
-
 
145
/** Returns the TCP module phone.
-
 
146
 *  Connects to the TCP module if necessary.
-
 
147
 *  @returns The TCP module phone.
-
 
148
 */
90
static int  socket_get_tcp_phone();
149
static int  socket_get_tcp_phone();
-
 
150
 
-
 
151
/** Returns the UDP module phone.
-
 
152
 *  Connects to the UDP module if necessary.
-
 
153
 *  @returns The UDP module phone.
-
 
154
 */
91
static int  socket_get_tcp_phone();
155
static int  socket_get_tcp_phone();
-
 
156
 
-
 
157
/** Returns the active sockets.
-
 
158
 *  @returns The active sockets.
-
 
159
 */
92
static sockets_ref  socket_get_sockets();
160
static sockets_ref  socket_get_sockets();
-
 
161
 
-
 
162
/** Default thread for new connections.
-
 
163
 *  @param iid The initial message identifier. Input parameter.
-
 
164
 *  @param icall The initial message call structure. Input parameter.
-
 
165
 */
93
void    socket_connection( ipc_callid_t iid, ipc_call_t * icall );
166
void    socket_connection( ipc_callid_t iid, ipc_call_t * icall );
-
 
167
 
-
 
168
/** Sends message to the socket parent module with specified data.
-
 
169
 *  @param socket_id Socket identifier. Input parameter.
-
 
170
 *  @param message The action message. Input parameter.
-
 
171
 *  @param arg2 The second message parameter. Input parameter.
-
 
172
 *  @param data The data to be sent. Input parameter.
-
 
173
 *  @param datalength The data length. Input parameter.
-
 
174
 *  @returns EOK on success.
-
 
175
 *  @returns ENOTSOCK if the socket is not found.
-
 
176
 *  @returns EBADMEM if the data parameter is NULL.
-
 
177
 *  @returns NO_DATA if the datalength parameter is zero (0).
-
 
178
 *  @returns Other error codes as defined for the spcific message.
-
 
179
 */
94
int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength );
180
int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength );
-
 
181
 
-
 
182
/** Initializes a new socket specific data.
-
 
183
 *  @param socket The socket to be initialized. Input/output parameter.
-
 
184
 *  @param socket_id The new socket identifier. Input parameter.
-
 
185
 *  @param phone The parent module phone. Input parameter.
-
 
186
 *  @param service The parent module service. Input parameter.
-
 
187
 */
95
void    socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
188
void    socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
-
 
189
 
-
 
190
/** Clears and destroys the socket.
-
 
191
 *  @param socket The socket to be destroyed. Input parameter.
-
 
192
 */
96
void    socket_destroy( socket_ref socket );
193
void    socket_destroy( socket_ref socket );
-
 
194
 
-
 
195
/** Receives data via the socket.
-
 
196
 *  @param message The action message. Input parameter.
-
 
197
 *  @param socket_id Socket identifier. Input parameter.
-
 
198
 *  @param data The data buffer to be filled. Output parameter.
-
 
199
 *  @param datalength The data length. Input parameter.
-
 
200
 *  @param flags Various receive flags. Input parameter.
-
 
201
 *  @param fromaddr The source address. May be NULL for connected sockets. Output parameter.
-
 
202
 *  @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.
-
 
203
 *  @returns EOK on success.
-
 
204
 *  @returns ENOTSOCK if the socket is not found.
-
 
205
 *  @returns EBADMEM if the data parameter is NULL.
-
 
206
 *  @returns NO_DATA if the datalength or addrlen parameter is zero (0).
-
 
207
 *  @returns Other error codes as defined for the spcific message.
-
 
208
 */
97
int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen );
209
int recvfrom_core( int message, int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen );
-
 
210
 
-
 
211
/** Sends data via the socket to the remote address.
-
 
212
 *  Binds the socket to a free port if not already connected/bound.
-
 
213
 *  @param message The action message. Input parameter.
-
 
214
 *  @param socket_id Socket identifier. Input parameter.
-
 
215
 *  @param data The data to be sent. Input parameter.
-
 
216
 *  @param datalength The data length. Input parameter.
-
 
217
 *  @param flags Various send flags. Input parameter.
-
 
218
 *  @param toaddr The destination address. May be NULL for connected sockets. Input parameter.
-
 
219
 *  @param addrlen The address length. Used only if toaddr is not NULL. Input parameter.
-
 
220
 *  @returns EOK on success.
-
 
221
 *  @returns ENOTSOCK if the socket is not found.
-
 
222
 *  @returns EBADMEM if the data or toaddr parameter is NULL.
-
 
223
 *  @returns NO_DATA if the datalength or the addrlen parameter is zero (0).
-
 
224
 *  @returns Other error codes as defined for the NET_SOCKET_SENDTO message.
-
 
225
 */
98
int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen );
226
int sendto_core( int message, int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen );
99
 
227
 
100
static int socket_get_tcp_phone(){
228
static int socket_get_tcp_phone(){
101
    if( socket_globals.tcp_phone < 0 ){
229
    if( socket_globals.tcp_phone < 0 ){
102
        socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection );
230
        socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection );
Line 147... Line 275...
147
 
275
 
148
        callid = async_get_call( & call );
276
        callid = async_get_call( & call );
149
        switch( IPC_GET_METHOD( call )){
277
        switch( IPC_GET_METHOD( call )){
150
            case NET_SOCKET_RECEIVED:
278
            case NET_SOCKET_RECEIVED:
151
                // find the socket
279
                // find the socket
152
                socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
280
                socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call ));
153
                if( ! socket ){
281
                if( ! socket ){
154
                    ERROR_CODE = ENOTSOCK;
282
                    ERROR_CODE = ENOTSOCK;
155
                    break;
283
                    break;
156
                }
284
                }
157
                fibril_mutex_lock( & socket->receive_lock );
285
                fibril_mutex_lock( & socket->receive_lock );
158
                // push the number of received packet fragments
286
                // push the number of received packet fragments
159
                if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( & call ), SOCKET_MAX_RECEIVED_SIZE ))){
287
                if( ! ERROR_OCCURRED( dyn_fifo_push( & socket->received, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_MAX_RECEIVED_SIZE ))){
160
                    // signal the received packet
288
                    // signal the received packet
161
                    fibril_condvar_signal( & socket->receive_signal );
289
                    fibril_condvar_signal( & socket->receive_signal );
162
                }
290
                }
163
                fibril_mutex_unlock( & socket->receive_lock );
291
                fibril_mutex_unlock( & socket->receive_lock );
164
                break;
292
                break;
165
            case NET_SOCKET_ACCEPTED:
293
            case NET_SOCKET_ACCEPTED:
166
                // find the socket
294
                // find the socket
167
                socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
295
                socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call ));
168
                if( ! socket ){
296
                if( ! socket ){
169
                    ERROR_CODE = ENOTSOCK;
297
                    ERROR_CODE = ENOTSOCK;
170
                    break;
298
                    break;
171
                }
299
                }
172
                // create a new scoket
300
                // create a new scoket
173
                new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
301
                new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
174
                if( ! new_socket ){
302
                if( ! new_socket ){
175
                    ERROR_CODE = ENOMEM;
303
                    ERROR_CODE = ENOMEM;
176
                    break;
304
                    break;
177
                }
305
                }
178
                socket_initialize( new_socket, SOCKET_GET_SOCKET_ID( & call ), socket->phone, socket->service );
306
                socket_initialize( new_socket, SOCKET_GET_SOCKET_ID( call ), socket->phone, socket->service );
179
                ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket );
307
                ERROR_CODE = sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket );
180
                if( ERROR_CODE < 0 ){
308
                if( ERROR_CODE < 0 ){
181
                    free( new_socket );
309
                    free( new_socket );
182
                }else{
310
                }else{
183
                    // push the new socket identifier
311
                    // push the new socket identifier
Line 193... Line 321...
193
                    ERROR_CODE = EOK;
321
                    ERROR_CODE = EOK;
194
                }
322
                }
195
                break;
323
                break;
196
            case NET_SOCKET_DATA_FRAGMENT_SIZE:
324
            case NET_SOCKET_DATA_FRAGMENT_SIZE:
197
                // find the socket
325
                // find the socket
198
                socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
326
                socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( call ));
199
                if( ! socket ){
327
                if( ! socket ){
200
                    ERROR_CODE = ENOTSOCK;
328
                    ERROR_CODE = ENOTSOCK;
201
                    break;
329
                    break;
202
                }
330
                }
203
                // set the data fragment size
331
                // set the data fragment size
204
                socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( & call );
332
                socket->data_fragment_size = SOCKET_GET_DATA_FRAGMENT_SIZE( call );
205
                ERROR_CODE = EOK;
333
                ERROR_CODE = EOK;
206
                break;
334
                break;
207
            default:
335
            default:
208
                ERROR_CODE = ENOTSUP;
336
                ERROR_CODE = ENOTSUP;
209
        }
337
        }
Line 325... Line 453...
325
int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
453
int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
326
    socket_ref      socket;
454
    socket_ref      socket;
327
    aid_t           message_id;
455
    aid_t           message_id;
328
    int             result;
456
    int             result;
329
 
457
 
330
    if( ! cliaddr ) return EBADMEM;
458
    if(( ! cliaddr ) || ( ! addrlen )) return EBADMEM;
331
    if( ! addrlen ) return NO_DATA;
-
 
332
    // find the socket
459
    // find the socket
333
    socket = sockets_find( socket_get_sockets(), socket_id );
460
    socket = sockets_find( socket_get_sockets(), socket_id );
334
    if( ! socket ) return ENOTSOCK;
461
    if( ! socket ) return ENOTSOCK;
335
    fibril_mutex_lock( & socket->accept_lock );
462
    fibril_mutex_lock( & socket->accept_lock );
336
    // wait for an accepted socket
463
    // wait for an accepted socket
Line 371... Line 498...
371
 
498
 
372
void socket_destroy( socket_ref socket ){
499
void socket_destroy( socket_ref socket ){
373
    int accepted_id;
500
    int accepted_id;
374
 
501
 
375
    // destroy all accepted sockets
502
    // destroy all accepted sockets
376
    while(( accepted_id = dyn_fifo_pop( & socket->accepted ))){
503
    while(( accepted_id = dyn_fifo_pop( & socket->accepted )) >= 0 ){
377
        socket_destroy( sockets_find( socket_get_sockets(), accepted_id ));
504
        socket_destroy( sockets_find( socket_get_sockets(), accepted_id ));
378
    }
505
    }
379
    dyn_fifo_destroy( & socket->received );
506
    dyn_fifo_destroy( & socket->received );
380
    dyn_fifo_destroy( & socket->accepted );
507
    dyn_fifo_destroy( & socket->accepted );
381
    sockets_exclude( socket_get_sockets(), socket->socket_id );
508
    sockets_exclude( socket_get_sockets(), socket->socket_id );
Line 452... Line 579...
452
    int             index;
579
    int             index;
453
    ipc_call_t      answer;
580
    ipc_call_t      answer;
454
 
581
 
455
    if( ! data ) return EBADMEM;
582
    if( ! data ) return EBADMEM;
456
    if( ! datalength ) return NO_DATA;
583
    if( ! datalength ) return NO_DATA;
457
    if( fromaddr && (( ! addrlen ) || ( * addrlen < sizeof( struct sockaddr_in )))) return EINVAL;
584
    if( fromaddr && ( ! addrlen )) return EINVAL;
458
    // find the socket
585
    // find the socket
459
    socket = sockets_find( socket_get_sockets(), socket_id );
586
    socket = sockets_find( socket_get_sockets(), socket_id );
460
    if( ! socket ) return ENOTSOCK;
587
    if( ! socket ) return ENOTSOCK;
461
    fibril_mutex_lock( & socket->receive_lock );
588
    fibril_mutex_lock( & socket->receive_lock );
462
    // wait for a received packet
589
    // wait for a received packet
Line 498... Line 625...
498
    // if successful
625
    // if successful
499
    if( result == EOK ){
626
    if( result == EOK ){
500
        // dequeue the received packet
627
        // dequeue the received packet
501
        dyn_fifo_pop( & socket->received );
628
        dyn_fifo_pop( & socket->received );
502
        // return read data length
629
        // return read data length
503
        result = SOCKET_GET_READ_DATA_LENGTH( & answer );
630
        result = SOCKET_GET_READ_DATA_LENGTH( answer );
504
        // set address length
631
        // set address length
505
        if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( & answer );
632
        if( fromaddr && addrlen ) * addrlen = SOCKET_GET_ADDRESS_LENGTH( answer );
506
    }
633
    }
507
    fibril_mutex_unlock( & socket->receive_lock );
634
    fibril_mutex_unlock( & socket->receive_lock );
508
    return result;
635
    return result;
509
}
636
}
510
 
637