Subversion Repositories HelenOS

Rev

Rev 4582 | Go to most recent revision | Details | 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
34
 *  Socket application program interface (API) implementation.
35
 *  @see socket.h for more information.
36
 *  This is a part of the network application library.
37
 */
38
 
39
#include <assert.h>
40
#include <async.h>
41
//#include <fibril_sync.h>
42
 
43
#include <ipc/services.h>
44
 
45
#include "../err.h"
46
#include "../modules.h"
47
 
48
#include "../include/in.h"
49
#include "../include/socket.h"
50
#include "../include/socket_errno.h"
51
 
52
#include "../structures/int_map.h"
53
 
54
#include "socket_messages.h"
55
 
56
typedef struct socket	socket_t;
57
typedef socket_t *		socket_ref;
58
 
59
struct socket{
60
	int					socket_id;
61
	int					phone;
62
	services_t			service;
63
	int					max_content;
64
	int					received;
65
//	fibril_mutex_t		receive_lock;
66
//	fibril_condvar_t	receive_signal;
67
	int					accepted;
68
//	fibril_mutex_t		accept_lock;
69
//	fibril_condvar_t	accept_signal;
70
};
71
 
72
INT_MAP_DECLARE( sockets, socket_t );
73
 
74
static struct{
75
	int	tcp_phone;
76
	int	udp_phone;
77
	sockets_ref	sockets;
78
} socket_globals = { -1, -1, NULL };
79
 
80
INT_MAP_IMPLEMENT( sockets, socket_t );
81
 
82
static int	socket_get_tcp_phone();
83
static int	socket_get_tcp_phone();
84
static sockets_ref	socket_get_sockets();
85
void	socket_connection( ipc_callid_t iid, ipc_call_t * icall );
86
int	socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength );
87
void	socket_initialize( socket_ref socket, int socket_id, int phone, services_t service );
88
 
89
static int socket_get_tcp_phone(){
90
	if( socket_globals.tcp_phone < 0 ){
91
		socket_globals.tcp_phone = bind_service( SERVICE_TCP, 0, 0, SERVICE_TCP, socket_connection );
92
	}
93
	return socket_globals.tcp_phone;
94
}
95
 
96
static int socket_get_udp_phone(){
97
	if( socket_globals.udp_phone < 0 ){
98
		socket_globals.udp_phone = bind_service( SERVICE_UDP, 0, 0, SERVICE_UDP, socket_connection );
99
	}
100
	return socket_globals.udp_phone;
101
}
102
 
103
static sockets_ref socket_get_sockets(){
104
	if( ! socket_globals.sockets ){
105
		socket_globals.sockets = ( sockets_ref ) malloc( sizeof( sockets_t ));
106
		if( ! socket_globals.sockets ) return NULL;
107
		if( sockets_initialize( socket_globals.sockets ) != EOK ){
108
			free( socket_globals.sockets );
109
			socket_globals.sockets = NULL;
110
		}
111
	}
112
	return socket_globals.sockets;
113
}
114
 
115
void socket_initialize( socket_ref socket, int socket_id, int phone, services_t service ){
116
	socket->socket_id = socket_id;
117
	socket->phone = phone;
118
	socket->service = service;
119
	socket->received = 0;
120
	socket->accepted = 0;
121
//	fibril_mutex_initialize( & socket->receive_lock );
122
//	fibril_condvar_initialize( & socket->receive_signal );
123
//	fibril_mutex_initialize( & socket->accept_lock );
124
//	fibril_condvar_initialize( & socket->accept_signal );
125
}
126
 
127
void socket_connection( ipc_callid_t iid, ipc_call_t * icall ){
128
	ERROR_DECLARE;
129
 
130
	ipc_callid_t	callid;
131
	ipc_call_t		call;
132
	socket_ref		socket;
133
	socket_ref		new_socket;
134
 
135
	while( true ){
136
 
137
		callid = async_get_call( & call );
138
		switch( IPC_GET_METHOD( call )){
139
			case NET_SOCKET_RECEIVED:
140
				socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
141
				if( ! socket ){
142
					ERROR_CODE = ENOTSOCK;
143
					break;
144
				}
145
//				fibril_mutex_lock( & socket->receive_lock );
146
				++ socket->received;
147
//				fibril_condvar_signal( & socket->receive_signal );
148
//				fibril_mutex_unlock( & socket->receive_lock );
149
				ERROR_CODE = EOK;
150
				break;
151
			case NET_SOCKET_ACCEPTED:
152
				socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
153
				if( ! socket ){
154
					ERROR_CODE = ENOTSOCK;
155
					break;
156
				}
157
//				fibril_mutex_lock( & socket->accept_lock );
158
				new_socket = ( socket_ref ) malloc( sizeof( socket_t ));
159
				if( ! new_socket ){
160
					ERROR_CODE = ENOMEM;
161
					break;
162
				}
163
				socket_initialize( new_socket, SOCKET_GET_NEW_SOCKET_ID( & call ), socket->phone, socket->service );
164
				if( ERROR_OCCURRED( sockets_add( socket_get_sockets(), new_socket->socket_id, new_socket ))){
165
					break;
166
				}
167
				++ socket->accepted;
168
//				fibril_condvar_signal( & socket->accept_signal );
169
//				fibril_mutex_unlock( & socket->accept_lock );
170
				break;
171
/*			case NET_SOCKET_MTU:
172
				socket = sockets_find( socket_get_sockets(), SOCKET_GET_SOCKET_ID( & call ));
173
				if( ! socket ){
174
					ERROR_CODE = ENOTSOCK;
175
					break;
176
				}
177
				socket->mtu = 
178
				ERROR_CODE = EOK;
179
				break;
180
*/			default:
181
				ERROR_CODE = ENOTSUP;
182
		}
183
		ipc_answer_0( callid, ERROR_CODE );
184
	}
185
}
186
 
187
int socket( int domain, int type, int protocol ){
188
	socket_ref	socket;
189
	int			phone;
190
	int			socket_id;
191
	services_t	service;
192
 
193
	switch( domain ){
194
		case PF_INET:
195
			switch( type ){
196
				case SOCK_STREAM:
197
					if( ! protocol ) protocol = IPPROTO_TCP;
198
					switch( protocol ){
199
						case IPPROTO_TCP:
200
							phone = socket_get_tcp_phone();
201
							service = SERVICE_TCP;
202
							break;
203
						default:
204
							return EPROTONOSUPPORT;
205
					}
206
					break;
207
				case SOCK_DGRAM:
208
					if( ! protocol ) protocol = IPPROTO_UDP;
209
					switch( protocol ){
210
						case IPPROTO_UDP:
211
							phone = socket_get_udp_phone();
212
							service = SERVICE_UDP;
213
							break;
214
						default:
215
							return EPROTONOSUPPORT;
216
					}
217
					break;
218
				case SOCK_RAW:
219
				default:
220
					return ESOCKTNOSUPPORT;
221
			}
222
			break;
223
		// TODO IPv6
224
		default:
225
			return EPFNOSUPPORT;
226
	}
227
	assert( phone );
228
	socket = ( socket_ref ) malloc( sizeof( socket_t ));
229
	if( ! socket ) return ENOMEM;
230
	socket_id = async_req_3_0( phone, NET_SOCKET, 0, 0, service );
231
	if( socket_id > 0 ){
232
		socket_initialize( socket, socket_id, phone, service );
233
		if( sockets_add( socket_get_sockets(), socket_id, socket ) != EOK ){
234
			free( socket );
235
			async_msg_3( phone, NET_SOCKET_CLOSE, socket_id, 0, service );
236
		}
237
	}else{
238
		free( socket );
239
	}
240
	return socket_id;
241
}
242
 
243
int socket_send_data( int socket_id, int message, ipcarg_t arg2, const void * data, size_t datalength ){
244
	socket_ref		socket;
245
	aid_t			message_id;
246
	ipcarg_t		result;
247
 
248
	if( ! data ) return EBADMEM;
249
	if( ! datalength ) return NO_DATA;
250
	socket = sockets_find( socket_get_sockets(), socket_id );
251
	if( ! socket ) return ENOTSOCK;
252
	message_id = async_send_3( socket->phone, message, socket->socket_id, arg2, socket->service, NULL );
253
	ipc_data_write_start( socket->phone, data, datalength );
254
	async_wait_for( message_id, & result );
255
	return ( int ) result;
256
}
257
 
258
int bind( int socket_id, const struct sockaddr * my_addr, socklen_t addrlen ){
259
	return socket_send_data( socket_id, NET_SOCKET_BIND, 0, my_addr, addrlen );
260
}
261
 
262
int listen( int socket_id, int backlog ){
263
	socket_ref		socket;
264
 
265
	if( backlog <= 0 ) return EINVAL;
266
	socket = sockets_find( socket_get_sockets(), socket_id );
267
	if( ! socket ) return ENOTSOCK;
268
	return async_req_3_0( socket->phone, NET_SOCKET_LISTEN, socket->socket_id, backlog, socket->service );
269
}
270
 
271
int accept( int socket_id, struct sockaddr * cliaddr, socklen_t * addrlen ){
272
	socket_ref		socket;
273
	aid_t			message_id;
274
	ipcarg_t		result;
275
 
276
	if( ! cliaddr ) return EBADMEM;
277
	if( ! addrlen ) return NO_DATA;
278
	socket = sockets_find( socket_get_sockets(), socket_id );
279
	if( ! socket ) return ENOTSOCK;
280
//	fibril_mutex_lock( & socket->accept_lock );
281
	while( socket->accepted <= 0 ){
282
//		fibril_condvar_wait( & socket->accept_signal, & socket->accept_lock );
283
	}
284
	message_id = async_send_3( socket->phone, NET_SOCKET_ACCEPT, socket->socket_id, 0, socket->service, NULL );
285
	ipc_data_read_start( socket->phone, cliaddr, * addrlen );
286
	async_wait_for( message_id, & result );
287
	if( result > 0 ){
288
		-- socket->accepted;
289
	}
290
//	fibril_mutex_unlock( & socket->accept_lock );
291
	return ( int ) result;
292
}
293
 
294
int connect( int socket_id, const struct sockaddr * serv_addr, socklen_t addrlen ){
295
	return socket_send_data( socket_id, NET_SOCKET_CONNECT, 0, serv_addr, addrlen );
296
}
297
 
298
int closesocket( int socket_id ){
299
	socket_ref		socket;
300
 
301
	socket = sockets_find( socket_get_sockets(), socket_id );
302
	if( ! socket ) return ENOTSOCK;
303
	return async_req_3_0( socket->phone, NET_SOCKET_CLOSE, socket->socket_id, 0, socket->service );
304
}
305
 
306
int send( int socket_id, void * data, size_t datalength, int flags ){
307
	return socket_send_data( socket_id, NET_SOCKET_SEND, flags, data, datalength );
308
}
309
 
310
int sendto( int socket_id, const void * data, size_t datalength, int flags, const struct sockaddr * toaddr, socklen_t addrlen ){
311
	socket_ref		socket;
312
	aid_t			message_id;
313
	ipcarg_t		result;
314
 
315
	if( ! toaddr ) return EBADMEM;
316
	if( ! addrlen ) return NO_DATA;
317
	if( ! data ) return EBADMEM;
318
	if( ! datalength ) return NO_DATA;
319
	socket = sockets_find( socket_get_sockets(), socket_id );
320
	if( ! socket ) return ENOTSOCK;
321
	message_id = async_send_3( socket->phone, NET_SOCKET_SENDTO, socket->socket_id, flags, socket->service, NULL );
322
	if( ipc_data_write_start( socket->phone, toaddr, addrlen ) == EOK ){
323
		ipc_data_write_start( socket->phone, data, datalength );
324
	}
325
	async_wait_for( message_id, & result );
326
	return ( int ) result;
327
}
328
 
329
int recv( int socket_id, void * data, size_t datalength, int flags ){
330
	socket_ref		socket;
331
	aid_t			message_id;
332
	ipcarg_t		result;
333
 
334
	if( ! data ) return EBADMEM;
335
	if( ! datalength ) return NO_DATA;
336
	socket = sockets_find( socket_get_sockets(), socket_id );
337
	if( ! socket ) return ENOTSOCK;
338
//	fibril_mutex_lock( & socket->receive_lock );
339
	while( socket->received <= 0 ){
340
//		fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
341
	}
342
	message_id = async_send_3( socket->phone, NET_SOCKET_RECV, socket->socket_id, flags, socket->service, NULL );
343
	ipc_data_read_start( socket->phone, data, datalength );
344
	async_wait_for( message_id, & result );
345
	if( result > 0 ){
346
		-- socket->received;
347
	}
348
//	fibril_mutex_unlock( & socket->receive_lock );
349
	return ( int ) result;
350
}
351
 
352
int recvfrom( int socket_id, void * data, size_t datalength, int flags, struct sockaddr * fromaddr, socklen_t * addrlen ){
353
	socket_ref		socket;
354
	aid_t			message_id;
355
	ipcarg_t		result;
356
 
357
	if( ! fromaddr ) return EBADMEM;
358
	if( ! addrlen ) return NO_DATA;
359
	if( ! data ) return EBADMEM;
360
	if( ! datalength ) return NO_DATA;
361
	socket = sockets_find( socket_get_sockets(), socket_id );
362
	if( ! socket ) return ENOTSOCK;
363
//	fibril_mutex_lock( & socket->receive_lock );
364
	while( socket->received <= 0 ){
365
//		fibril_condvar_wait( & socket->receive_signal, & socket->receive_lock );
366
	}
367
	message_id = async_send_3( socket->phone, NET_SOCKET_RECVFROM, socket->socket_id, flags, socket->service, NULL );
368
	if( ipc_data_read_start( socket->phone, fromaddr, * addrlen ) == EOK ){
369
		ipc_data_read_start( socket->phone, data, datalength );
370
	}
371
	async_wait_for( message_id, & result );
372
	if( result > 0 ){
373
		-- socket->received;
374
	}
375
//	fibril_mutex_unlock( & socket->receive_lock );
376
	return ( int ) result;
377
}
378
 
379
int getsockopt( int socket_id, int level, int optname, void * value, size_t * optlen ){
380
	socket_ref		socket;
381
	aid_t			message_id;
382
	ipcarg_t		result;
383
 
384
	if( ! value ) return EBADMEM;
385
	if( ! optlen ) return NO_DATA;
386
	socket = sockets_find( socket_get_sockets(), socket_id );
387
	if( ! socket ) return ENOTSOCK;
388
	message_id = async_send_3( socket->phone, NET_SOCKET_GETSOCKOPT, socket->socket_id, optname, socket->service, NULL );
389
	ipc_data_read_start( socket->phone, value, * optlen );
390
	async_wait_for( message_id, & result );
391
	return ( int ) result;
392
}
393
 
394
int setsockopt( int socket_id, int level, int optname, const void * value, size_t optlen ){
395
	return socket_send_data( socket_id, NET_SOCKET_SETSOCKOPT, optname, value, optlen );
396
}
397
 
398
/** @}
399
 */