source: mainline/uspace/srv/udp/sock.c@ ee603c4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ee603c4 was e33bceb, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Implement socket provider interface in UDP to UDP user calls.

  • Property mode set to 100644
File size: 13.6 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * Copyright (c) 2012 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup udp
31 * @{
32 */
33
34/**
35 * @file Socket provider
36 */
37
38#include <async.h>
39#include <byteorder.h>
40#include <errno.h>
41#include <inet/inet.h>
42#include <io/log.h>
43#include <ipc/services.h>
44#include <ipc/socket.h>
45#include <net/modules.h>
46#include <net/socket.h>
47#include <ns.h>
48
49#include "sock.h"
50#include "std.h"
51#include "udp_type.h"
52#include "ucall.h"
53
54#define FRAGMENT_SIZE 1024
55
56/** Free ports pool start. */
57#define UDP_FREE_PORTS_START 1025
58
59/** Free ports pool end. */
60#define UDP_FREE_PORTS_END 65535
61
62static int last_used_port = UDP_FREE_PORTS_START - 1;
63static socket_ports_t gsock;
64
65static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
66
67int udp_sock_init(void)
68{
69 int rc;
70
71 socket_ports_initialize(&gsock);
72
73 async_set_client_connection(udp_sock_connection);
74
75 rc = service_register(SERVICE_UDP);
76 if (rc != EOK)
77 return EEXIST;
78
79 return EOK;
80}
81
82static void udp_free_sock_data(socket_core_t *sock_core)
83{
84 udp_sockdata_t *socket;
85
86 socket = (udp_sockdata_t *)sock_core->specific_data;
87 (void)socket;
88}
89
90static void udp_sock_notify_data(socket_core_t *sock_core)
91{
92 log_msg(LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
93 async_exch_t *exch = async_exchange_begin(sock_core->sess);
94 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
95 FRAGMENT_SIZE, 0, 0, 1);
96 async_exchange_end(exch);
97}
98
99static void udp_sock_socket(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
100{
101 udp_sockdata_t *sock;
102 socket_core_t *sock_core;
103 int sock_id;
104 int rc;
105 ipc_call_t answer;
106
107 log_msg(LVL_DEBUG, "udp_sock_socket()");
108 sock = calloc(sizeof(udp_sockdata_t), 1);
109 if (sock == NULL) {
110 async_answer_0(callid, ENOMEM);
111 return;
112 }
113
114 fibril_mutex_initialize(&sock->lock);
115 sock->client = client;
116 sock->laddr.ipv4 = UDP_IPV4_ANY;
117
118 rc = udp_uc_create(&sock->assoc);
119 if (rc != EOK) {
120 udp_uc_destroy(sock->assoc);
121 free(sock);
122 async_answer_0(callid, rc);
123 return;
124 }
125
126 sock_id = SOCKET_GET_SOCKET_ID(call);
127 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
128 if (rc != EOK) {
129 async_answer_0(callid, rc);
130 return;
131 }
132
133 sock_core = socket_cores_find(&client->sockets, sock_id);
134 assert(sock_core != NULL);
135 sock->sock_core = sock_core;
136
137
138 refresh_answer(&answer, NULL);
139 SOCKET_SET_SOCKET_ID(answer, sock_id);
140
141 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
142 SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
143 answer_call(callid, EOK, &answer, 3);
144}
145
146static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
147{
148 int rc;
149 struct sockaddr_in *addr;
150 size_t addr_size;
151 socket_core_t *sock_core;
152 udp_sockdata_t *socket;
153 udp_sock_t fsock;
154 udp_error_t urc;
155
156 log_msg(LVL_DEBUG, "udp_sock_bind()");
157 log_msg(LVL_DEBUG, " - async_data_write_accept");
158
159 addr = NULL;
160
161 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_size);
162 if (rc != EOK) {
163 async_answer_0(callid, rc);
164 goto out;
165 }
166
167 log_msg(LVL_DEBUG, " - call socket_bind");
168 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
169 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
170 last_used_port);
171 if (rc != EOK) {
172 async_answer_0(callid, rc);
173 goto out;
174 }
175
176 if (addr_size != sizeof(struct sockaddr_in)) {
177 async_answer_0(callid, EINVAL);
178 goto out;
179 }
180
181 log_msg(LVL_DEBUG, " - call socket_cores_find");
182 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
183 if (sock_core == NULL) {
184 async_answer_0(callid, ENOENT);
185 goto out;
186 }
187
188 socket = (udp_sockdata_t *)sock_core->specific_data;
189
190 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
191 fsock.port = uint16_t_be2host(sock_core->port);
192 urc = udp_uc_set_local(socket->assoc, &fsock);
193
194 switch (urc) {
195 case UDP_EOK:
196 rc = EOK;
197 break;
198/* case TCP_ENOTEXIST:
199 rc = ENOTCONN;
200 break;
201 case TCP_ECLOSING:
202 rc = ENOTCONN;
203 break;
204 case TCP_ERESET:
205 rc = ECONNABORTED;
206 break;*/
207 default:
208 assert(false);
209 }
210
211 log_msg(LVL_DEBUG, " - success");
212 async_answer_0(callid, rc);
213out:
214 if (addr != NULL)
215 free(addr);
216}
217
218static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
219{
220 log_msg(LVL_DEBUG, "udp_sock_listen()");
221 async_answer_0(callid, ENOTSUP);
222}
223
224static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
225{
226 log_msg(LVL_DEBUG, "udp_sock_connect()");
227 async_answer_0(callid, ENOTSUP);
228}
229
230static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
231{
232 log_msg(LVL_DEBUG, "udp_sock_accept()");
233 async_answer_0(callid, ENOTSUP);
234}
235
236static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
237{
238 int socket_id;
239 int fragments;
240 int index;
241 struct sockaddr_in *addr;
242 size_t addr_size;
243 socket_core_t *sock_core;
244 udp_sockdata_t *socket;
245 udp_sock_t fsock, *fsockp;
246 ipc_call_t answer;
247 ipc_callid_t wcallid;
248 size_t length;
249 uint8_t buffer[FRAGMENT_SIZE];
250 udp_error_t urc;
251 int rc;
252
253 log_msg(LVL_DEBUG, "udp_sock_send()");
254
255 addr = NULL;
256
257 if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
258 rc = async_data_write_accept((void **) &addr, false,
259 0, 0, 0, &addr_size);
260 if (rc != EOK) {
261 async_answer_0(callid, rc);
262 goto out;
263 }
264
265 if (addr_size != sizeof(struct sockaddr_in)) {
266 async_answer_0(callid, EINVAL);
267 goto out;
268 }
269
270 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
271 fsock.port = uint16_t_be2host(addr->sin_port);
272 fsockp = &fsock;
273 } else {
274 fsockp = NULL;
275 }
276
277 socket_id = SOCKET_GET_SOCKET_ID(call);
278 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
279 SOCKET_GET_FLAGS(call);
280
281 sock_core = socket_cores_find(&client->sockets, socket_id);
282 if (sock_core == NULL) {
283 async_answer_0(callid, ENOTSOCK);
284 goto out;
285 }
286
287 if (sock_core->port == 0) {
288 /* Implicitly bind socket */
289 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
290 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
291 last_used_port);
292 if (rc != EOK) {
293 async_answer_0(callid, rc);
294 goto out;
295 }
296 }
297
298 socket = (udp_sockdata_t *)sock_core->specific_data;
299 fibril_mutex_lock(&socket->lock);
300
301 assert(socket->assoc != NULL);
302
303 for (index = 0; index < fragments; index++) {
304 if (!async_data_write_receive(&wcallid, &length)) {
305 fibril_mutex_unlock(&socket->lock);
306 async_answer_0(callid, EINVAL);
307 goto out;
308 }
309
310 if (length > FRAGMENT_SIZE)
311 length = FRAGMENT_SIZE;
312
313 rc = async_data_write_finalize(wcallid, buffer, length);
314 if (rc != EOK) {
315 fibril_mutex_unlock(&socket->lock);
316 async_answer_0(callid, rc);
317 goto out;
318 }
319
320 urc = udp_uc_send(socket->assoc, fsockp, buffer, length, 0);
321
322 switch (urc) {
323 case UDP_EOK:
324 rc = EOK;
325 break;
326/* case TCP_ENOTEXIST:
327 rc = ENOTCONN;
328 break;
329 case TCP_ECLOSING:
330 rc = ENOTCONN;
331 break;
332 case TCP_ERESET:
333 rc = ECONNABORTED;
334 break;*/
335 default:
336 assert(false);
337 }
338
339 if (rc != EOK) {
340 fibril_mutex_unlock(&socket->lock);
341 async_answer_0(callid, rc);
342 goto out;
343 }
344 }
345
346 refresh_answer(&answer, NULL);
347 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
348 answer_call(callid, EOK, &answer, 2);
349 fibril_mutex_unlock(&socket->lock);
350out:
351 if (addr != NULL)
352 free(addr);
353}
354
355static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
356{
357 int socket_id;
358 int flags;
359 size_t addr_length, length;
360 socket_core_t *sock_core;
361 udp_sockdata_t *socket;
362 ipc_call_t answer;
363 ipc_callid_t rcallid;
364 uint8_t buffer[FRAGMENT_SIZE];
365 size_t data_len;
366 xflags_t xflags;
367 udp_error_t urc;
368 struct sockaddr_in addr;
369 udp_sock_t rsock;
370 int rc;
371
372 log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
373
374 socket_id = SOCKET_GET_SOCKET_ID(call);
375 flags = SOCKET_GET_FLAGS(call);
376
377 sock_core = socket_cores_find(&client->sockets, socket_id);
378 if (sock_core == NULL) {
379 async_answer_0(callid, ENOTSOCK);
380 return;
381 }
382
383 socket = (udp_sockdata_t *)sock_core->specific_data;
384 fibril_mutex_lock(&socket->lock);
385
386 if (socket->assoc == NULL) {
387 fibril_mutex_unlock(&socket->lock);
388 async_answer_0(callid, ENOTCONN);
389 return;
390 }
391
392 (void)flags;
393
394 urc = udp_uc_receive(socket->assoc, buffer, FRAGMENT_SIZE, &data_len,
395 &xflags, &rsock);
396 log_msg(LVL_DEBUG, "**** udp_uc_receive done");
397
398 switch (urc) {
399 case UDP_EOK:
400 rc = EOK;
401 break;
402/* case TCP_ENOTEXIST:
403 case TCP_ECLOSING:
404 rc = ENOTCONN;
405 break;
406 case TCP_ERESET:
407 rc = ECONNABORTED;
408 break;*/
409 default:
410 assert(false);
411 }
412
413 log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
414 if (rc != EOK) {
415 fibril_mutex_unlock(&socket->lock);
416 async_answer_0(callid, rc);
417 return;
418 }
419
420 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
421 /* Fill addr */
422 addr.sin_family = AF_INET;
423 addr.sin_addr.s_addr = host2uint32_t_be(rsock.addr.ipv4);
424 addr.sin_port = host2uint16_t_be(rsock.port);
425
426 log_msg(LVL_DEBUG, "addr read receive");
427 if (!async_data_read_receive(&rcallid, &addr_length)) {
428 fibril_mutex_unlock(&socket->lock);
429 async_answer_0(callid, EINVAL);
430 return;
431 }
432
433 if (addr_length > sizeof(addr))
434 addr_length = sizeof(addr);
435
436 log_msg(LVL_DEBUG, "addr read finalize");
437 rc = async_data_read_finalize(rcallid, &addr, addr_length);
438 if (rc != EOK) {
439 fibril_mutex_unlock(&socket->lock);
440 async_answer_0(callid, EINVAL);
441 return;
442 }
443 }
444
445 log_msg(LVL_DEBUG, "data read receive");
446 if (!async_data_read_receive(&rcallid, &length)) {
447 fibril_mutex_unlock(&socket->lock);
448 async_answer_0(callid, EINVAL);
449 return;
450 }
451
452 if (length > data_len)
453 length = data_len;
454
455 log_msg(LVL_DEBUG, "data read finalize");
456 rc = async_data_read_finalize(rcallid, buffer, length);
457
458 if (length < data_len && rc == EOK)
459 rc = EOVERFLOW;
460
461 SOCKET_SET_READ_DATA_LENGTH(answer, length);
462 answer_call(callid, EOK, &answer, 1);
463
464 /* Push one fragment notification to client's queue */
465 udp_sock_notify_data(sock_core);
466 fibril_mutex_unlock(&socket->lock);
467}
468
469static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
470{
471 int socket_id;
472 socket_core_t *sock_core;
473 udp_sockdata_t *socket;
474 int rc;
475
476 log_msg(LVL_DEBUG, "tcp_sock_close()");
477 socket_id = SOCKET_GET_SOCKET_ID(call);
478
479 sock_core = socket_cores_find(&client->sockets, socket_id);
480 if (sock_core == NULL) {
481 async_answer_0(callid, ENOTSOCK);
482 return;
483 }
484
485 socket = (udp_sockdata_t *)sock_core->specific_data;
486 fibril_mutex_lock(&socket->lock);
487
488 assert(socket->assoc != NULL);
489 udp_uc_destroy(socket->assoc);
490
491 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
492 udp_free_sock_data);
493 if (rc != EOK) {
494 fibril_mutex_unlock(&socket->lock);
495 async_answer_0(callid, rc);
496 return;
497 }
498
499 fibril_mutex_unlock(&socket->lock);
500 async_answer_0(callid, EOK);
501}
502
503static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
504{
505 log_msg(LVL_DEBUG, "udp_sock_getsockopt()");
506 async_answer_0(callid, ENOTSUP);
507}
508
509static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
510{
511 log_msg(LVL_DEBUG, "udp_sock_setsockopt()");
512 async_answer_0(callid, ENOTSUP);
513}
514
515static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
516{
517 ipc_callid_t callid;
518 ipc_call_t call;
519 udp_client_t client;
520
521 /* Accept the connection */
522 async_answer_0(iid, EOK);
523
524 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
525 socket_cores_initialize(&client.sockets);
526
527 while (true) {
528 callid = async_get_call(&call);
529 if (!IPC_GET_IMETHOD(call))
530 break;
531
532 log_msg(LVL_DEBUG, "udp_sock_connection: METHOD=%d\n",
533 (int)IPC_GET_IMETHOD(call));
534
535 switch (IPC_GET_IMETHOD(call)) {
536 case NET_SOCKET:
537 udp_sock_socket(&client, callid, call);
538 break;
539 case NET_SOCKET_BIND:
540 udp_sock_bind(&client, callid, call);
541 break;
542 case NET_SOCKET_LISTEN:
543 udp_sock_listen(&client, callid, call);
544 break;
545 case NET_SOCKET_CONNECT:
546 udp_sock_connect(&client, callid, call);
547 break;
548 case NET_SOCKET_ACCEPT:
549 udp_sock_accept(&client, callid, call);
550 break;
551 case NET_SOCKET_SEND:
552 case NET_SOCKET_SENDTO:
553 udp_sock_sendto(&client, callid, call);
554 break;
555 case NET_SOCKET_RECV:
556 case NET_SOCKET_RECVFROM:
557 udp_sock_recvfrom(&client, callid, call);
558 break;
559 case NET_SOCKET_CLOSE:
560 udp_sock_close(&client, callid, call);
561 break;
562 case NET_SOCKET_GETSOCKOPT:
563 udp_sock_getsockopt(&client, callid, call);
564 break;
565 case NET_SOCKET_SETSOCKOPT:
566 udp_sock_setsockopt(&client, callid, call);
567 break;
568 default:
569 async_answer_0(callid, ENOTSUP);
570 break;
571 }
572 }
573}
574
575/**
576 * @}
577 */
Note: See TracBrowser for help on using the repository browser.