source: mainline/uspace/srv/net/tl/udp/udp.c@ a63ff7d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a63ff7d was a63ff7d, checked in by Jakub Jermar <jakub@…>, 15 years ago

Do not leak the packet on error in udp_recvfrom_message().

If we don't make it to copying the user data to the client application, do not
forget to release the packet so that it can be used for something else. Also,
pop the packet ID from the socket received queue immediately or else the queue
would become inconsitent on error.

Another approach could be to keep the packet ID in the socket received queue
until the data is successfully copied to the client (just as it was done until
now) and not release the packet in case of error (just as it was done until now,
but for all cases).

The second approach could work better for transient errors as packets would not
be dropped needlessly, but for permanent errors this would render the client
unable to receive any further data.

Rather than complicate the matter, we behave conservatively and drop the packet
whenever we can't deliver it to the client.

  • Property mode set to 100644
File size: 25.0 KB
Line 
1/*
2 * Copyright (c) 2008 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 udp
30 * @{
31 */
32
33/** @file
34 * UDP module implementation.
35 * @see udp.h
36 */
37
38#include "udp.h"
39#include "udp_header.h"
40#include "udp_module.h"
41
42#include <async.h>
43#include <fibril_synch.h>
44#include <malloc.h>
45#include <stdio.h>
46#include <ipc/ipc.h>
47#include <ipc/services.h>
48#include <ipc/net.h>
49#include <ipc/tl.h>
50#include <ipc/socket.h>
51#include <adt/dynamic_fifo.h>
52#include <errno.h>
53
54#include <net/socket_codes.h>
55#include <net/ip_protocols.h>
56#include <net/in.h>
57#include <net/in6.h>
58#include <net/inet.h>
59#include <net/modules.h>
60
61#include <packet_client.h>
62#include <packet_remote.h>
63#include <net_checksum.h>
64#include <ip_client.h>
65#include <ip_interface.h>
66#include <icmp_client.h>
67#include <icmp_interface.h>
68#include <net_interface.h>
69#include <socket_core.h>
70#include <tl_common.h>
71#include <tl_local.h>
72#include <tl_interface.h>
73
74/** UDP module name. */
75#define NAME "UDP protocol"
76
77/** Default UDP checksum computing. */
78#define NET_DEFAULT_UDP_CHECKSUM_COMPUTING true
79
80/** Default UDP autobind when sending via unbound sockets. */
81#define NET_DEFAULT_UDP_AUTOBINDING true
82
83/** Maximum UDP fragment size. */
84#define MAX_UDP_FRAGMENT_SIZE 65535
85
86/** Free ports pool start. */
87#define UDP_FREE_PORTS_START 1025
88
89/** Free ports pool end. */
90#define UDP_FREE_PORTS_END 65535
91
92/** UDP global data. */
93udp_globals_t udp_globals;
94
95/** Initializes the UDP module.
96 *
97 * @param[in] client_connection The client connection processing function. The
98 * module skeleton propagates its own one.
99 * @returns EOK on success.
100 * @returns ENOMEM if there is not enough memory left.
101 */
102int udp_initialize(async_client_conn_t client_connection)
103{
104 measured_string_t names[] = {
105 {
106 (char *) "UDP_CHECKSUM_COMPUTING",
107 22
108 },
109 {
110 (char *) "UDP_AUTOBINDING",
111 15
112 }
113 };
114 measured_string_ref configuration;
115 size_t count = sizeof(names) / sizeof(measured_string_t);
116 char *data;
117 int rc;
118
119 fibril_rwlock_initialize(&udp_globals.lock);
120 fibril_rwlock_write_lock(&udp_globals.lock);
121
122 udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP,
123 ICMP_CONNECT_TIMEOUT);
124
125 udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP,
126 SERVICE_UDP, client_connection);
127 if (udp_globals.ip_phone < 0) {
128 fibril_rwlock_write_unlock(&udp_globals.lock);
129 return udp_globals.ip_phone;
130 }
131
132 // read default packet dimensions
133 rc = ip_packet_size_req(udp_globals.ip_phone, -1,
134 &udp_globals.packet_dimension);
135 if (rc != EOK) {
136 fibril_rwlock_write_unlock(&udp_globals.lock);
137 return rc;
138 }
139
140 rc = socket_ports_initialize(&udp_globals.sockets);
141 if (rc != EOK) {
142 fibril_rwlock_write_unlock(&udp_globals.lock);
143 return rc;
144 }
145
146 rc = packet_dimensions_initialize(&udp_globals.dimensions);
147 if (rc != EOK) {
148 socket_ports_destroy(&udp_globals.sockets);
149 fibril_rwlock_write_unlock(&udp_globals.lock);
150 return rc;
151 }
152
153 udp_globals.packet_dimension.prefix += sizeof(udp_header_t);
154 udp_globals.packet_dimension.content -= sizeof(udp_header_t);
155 udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
156
157 udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
158 udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
159
160 // get configuration
161 configuration = &names[0];
162 rc = net_get_conf_req(udp_globals.net_phone, &configuration, count,
163 &data);
164 if (rc != EOK) {
165 socket_ports_destroy(&udp_globals.sockets);
166 fibril_rwlock_write_unlock(&udp_globals.lock);
167 return rc;
168 }
169
170 if (configuration) {
171 if (configuration[0].value)
172 udp_globals.checksum_computing =
173 (configuration[0].value[0] == 'y');
174
175 if (configuration[1].value)
176 udp_globals.autobinding =
177 (configuration[1].value[0] == 'y');
178
179 net_free_settings(configuration, data);
180 }
181
182 fibril_rwlock_write_unlock(&udp_globals.lock);
183 return EOK;
184}
185
186/** Releases the packet and returns the result.
187 *
188 * @param[in] packet The packet queue to be released.
189 * @param[in] result The result to be returned.
190 * @return The result parameter.
191 */
192static int udp_release_and_return(packet_t packet, int result)
193{
194 pq_release_remote(udp_globals.net_phone, packet_get_id(packet));
195 return result;
196}
197
198/** Processes the received UDP packet queue.
199 *
200 * Notifies the destination socket application.
201 * Releases the packet on error or sends an ICMP error notification.
202 *
203 * @param[in] device_id The receiving device identifier.
204 * @param[in,out] packet The received packet queue.
205 * @param[in] error The packet error reporting service. Prefixes the
206 * received packet.
207 * @returns EOK on success.
208 * @returns EINVAL if the packet is not valid.
209 * @returns EINVAL if the stored packet address is not the
210 * an_addr_t.
211 * @returns EINVAL if the packet does not contain any data.
212 * @returns NO_DATA if the packet content is shorter than the user
213 * datagram header.
214 * @returns ENOMEM if there is not enough memory left.
215 * @returns EADDRNOTAVAIL if the destination socket does not exist.
216 * @returns Other error codes as defined for the
217 * ip_client_process_packet() function.
218 */
219static int
220udp_process_packet(device_id_t device_id, packet_t packet, services_t error)
221{
222 size_t length;
223 size_t offset;
224 int result;
225 udp_header_ref header;
226 socket_core_ref socket;
227 packet_t next_packet;
228 size_t total_length;
229 uint32_t checksum;
230 int fragments;
231 packet_t tmp_packet;
232 icmp_type_t type;
233 icmp_code_t code;
234 void *ip_header;
235 struct sockaddr *src;
236 struct sockaddr *dest;
237 packet_dimension_ref packet_dimension;
238 int rc;
239
240 switch (error) {
241 case SERVICE_NONE:
242 break;
243 case SERVICE_ICMP:
244 // ignore error
245 // length = icmp_client_header_length(packet);
246 // process error
247 result = icmp_client_process_packet(packet, &type,
248 &code, NULL, NULL);
249 if (result < 0)
250 return udp_release_and_return(packet, result);
251 length = (size_t) result;
252 rc = packet_trim(packet, length, 0);
253 if (rc != EOK)
254 return udp_release_and_return(packet, rc);
255 break;
256 default:
257 return udp_release_and_return(packet, ENOTSUP);
258 }
259
260 // TODO process received ipopts?
261 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
262 if (result < 0)
263 return udp_release_and_return(packet, result);
264 offset = (size_t) result;
265
266 length = packet_get_data_length(packet);
267 if (length <= 0)
268 return udp_release_and_return(packet, EINVAL);
269 if (length < UDP_HEADER_SIZE + offset)
270 return udp_release_and_return(packet, NO_DATA);
271
272 // trim all but UDP header
273 rc = packet_trim(packet, offset, 0);
274 if (rc != EOK)
275 return udp_release_and_return(packet, rc);
276
277 // get udp header
278 header = (udp_header_ref) packet_get_data(packet);
279 if (!header)
280 return udp_release_and_return(packet, NO_DATA);
281
282 // find the destination socket
283 socket = socket_port_find(&udp_globals.sockets,
284 ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING, 0);
285 if (!socket) {
286 if (tl_prepare_icmp_packet(udp_globals.net_phone,
287 udp_globals.icmp_phone, packet, error) == EOK) {
288 icmp_destination_unreachable_msg(udp_globals.icmp_phone,
289 ICMP_PORT_UNREACH, 0, packet);
290 }
291 return EADDRNOTAVAIL;
292 }
293
294 // count the received packet fragments
295 next_packet = packet;
296 fragments = 0;
297 total_length = ntohs(header->total_length);
298
299 // compute header checksum if set
300 if (header->checksum && !error) {
301 result = packet_get_addr(packet, (uint8_t **) &src,
302 (uint8_t **) &dest);
303 if (result <= 0)
304 return udp_release_and_return(packet, result);
305
306 rc = ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest,
307 result, total_length, &ip_header, &length);
308 if (rc != EOK) {
309 return udp_release_and_return(packet, rc);
310 } else {
311 checksum = compute_checksum(0, ip_header, length);
312 // the udp header checksum will be added with the first
313 // fragment later
314 free(ip_header);
315 }
316 } else {
317 header->checksum = 0;
318 checksum = 0;
319 }
320
321 do {
322 fragments++;
323 length = packet_get_data_length(next_packet);
324 if (length <= 0)
325 return udp_release_and_return(packet, NO_DATA);
326
327 if (total_length < length) {
328 rc = packet_trim(next_packet, 0, length - total_length);
329 if (rc != EOK)
330 return udp_release_and_return(packet, rc);
331
332 // add partial checksum if set
333 if (header->checksum) {
334 checksum = compute_checksum(checksum,
335 packet_get_data(packet),
336 packet_get_data_length(packet));
337 }
338
339 // relese the rest of the packet fragments
340 tmp_packet = pq_next(next_packet);
341 while (tmp_packet) {
342 next_packet = pq_detach(tmp_packet);
343 pq_release_remote(udp_globals.net_phone,
344 packet_get_id(tmp_packet));
345 tmp_packet = next_packet;
346 }
347
348 // exit the loop
349 break;
350 }
351 total_length -= length;
352
353 // add partial checksum if set
354 if (header->checksum) {
355 checksum = compute_checksum(checksum,
356 packet_get_data(packet),
357 packet_get_data_length(packet));
358 }
359
360 } while ((next_packet = pq_next(next_packet)) && (total_length > 0));
361
362 // check checksum
363 if (header->checksum) {
364 if (flip_checksum(compact_checksum(checksum)) !=
365 IP_CHECKSUM_ZERO) {
366 if (tl_prepare_icmp_packet(udp_globals.net_phone,
367 udp_globals.icmp_phone, packet, error) == EOK) {
368 // checksum error ICMP
369 icmp_parameter_problem_msg(
370 udp_globals.icmp_phone, ICMP_PARAM_POINTER,
371 ((size_t) ((void *) &header->checksum)) -
372 ((size_t) ((void *) header)), packet);
373 }
374 return EINVAL;
375 }
376 }
377
378 // queue the received packet
379 rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
380 SOCKET_MAX_RECEIVED_SIZE);
381 if (rc != EOK)
382 return udp_release_and_return(packet, rc);
383
384 rc = tl_get_ip_packet_dimension(udp_globals.ip_phone,
385 &udp_globals.dimensions, device_id, &packet_dimension);
386 if (rc != EOK)
387 return udp_release_and_return(packet, rc);
388
389 // notify the destination socket
390 fibril_rwlock_write_unlock(&udp_globals.lock);
391 async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
392 (ipcarg_t) socket->socket_id, packet_dimension->content, 0, 0,
393 (ipcarg_t) fragments);
394
395 return EOK;
396}
397
398/** Processes the received UDP packet queue.
399 *
400 * Is used as an entry point from the underlying IP module.
401 * Locks the global lock and calls udp_process_packet() function.
402 *
403 * @param[in] device_id The receiving device identifier.
404 * @param[in,out] packet The received packet queue.
405 * @param receiver The target service. Ignored parameter.
406 * @param[in] error The packet error reporting service. Prefixes the
407 * received packet.
408 * @returns EOK on success.
409 * @returns Other error codes as defined for the
410 * udp_process_packet() function.
411 */
412static int
413udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver,
414 services_t error)
415{
416 int result;
417
418 fibril_rwlock_write_lock(&udp_globals.lock);
419 result = udp_process_packet(device_id, packet, error);
420 if (result != EOK)
421 fibril_rwlock_write_unlock(&udp_globals.lock);
422
423 return result;
424}
425
426/** Sends data from the socket to the remote address.
427 *
428 * Binds the socket to a free port if not already connected/bound.
429 * Handles the NET_SOCKET_SENDTO message.
430 * Supports AF_INET and AF_INET6 address families.
431 *
432 * @param[in,out] local_sockets The application local sockets.
433 * @param[in] socket_id Socket identifier.
434 * @param[in] addr The destination address.
435 * @param[in] addrlen The address length.
436 * @param[in] fragments The number of data fragments.
437 * @param[out] data_fragment_size The data fragment size in bytes.
438 * @param[in] flags Various send flags.
439 * @returns EOK on success.
440 * @returns EAFNOTSUPPORT if the address family is not supported.
441 * @returns ENOTSOCK if the socket is not found.
442 * @returns EINVAL if the address is invalid.
443 * @returns ENOTCONN if the sending socket is not and cannot be
444 * bound.
445 * @returns ENOMEM if there is not enough memory left.
446 * @returns Other error codes as defined for the
447 * socket_read_packet_data() function.
448 * @returns Other error codes as defined for the
449 * ip_client_prepare_packet() function.
450 * @returns Other error codes as defined for the ip_send_msg()
451 * function.
452 */
453static int
454udp_sendto_message(socket_cores_ref local_sockets, int socket_id,
455 const struct sockaddr *addr, socklen_t addrlen, int fragments,
456 size_t *data_fragment_size, int flags)
457{
458 socket_core_ref socket;
459 packet_t packet;
460 packet_t next_packet;
461 udp_header_ref header;
462 int index;
463 size_t total_length;
464 int result;
465 uint16_t dest_port;
466 uint32_t checksum;
467 void *ip_header;
468 size_t headerlen;
469 device_id_t device_id;
470 packet_dimension_ref packet_dimension;
471 int rc;
472
473 rc = tl_get_address_port(addr, addrlen, &dest_port);
474 if (rc != EOK)
475 return rc;
476
477 socket = socket_cores_find(local_sockets, socket_id);
478 if (!socket)
479 return ENOTSOCK;
480
481 if ((socket->port <= 0) && udp_globals.autobinding) {
482 // bind the socket to a random free port if not bound
483 rc = socket_bind_free_port(&udp_globals.sockets, socket,
484 UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
485 udp_globals.last_used_port);
486 if (rc != EOK)
487 return rc;
488 // set the next port as the search starting port number
489 udp_globals.last_used_port = socket->port;
490 }
491
492 if (udp_globals.checksum_computing) {
493 rc = ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr,
494 addrlen, &device_id, &ip_header, &headerlen);
495 if (rc != EOK)
496 return rc;
497 // get the device packet dimension
498// rc = tl_get_ip_packet_dimension(udp_globals.ip_phone,
499// &udp_globals.dimensions, device_id, &packet_dimension);
500// if (rc != EOK)
501// return rc;
502 }
503// } else {
504 // do not ask all the time
505 rc = ip_packet_size_req(udp_globals.ip_phone, -1,
506 &udp_globals.packet_dimension);
507 if (rc != EOK)
508 return rc;
509 packet_dimension = &udp_globals.packet_dimension;
510// }
511
512 // read the first packet fragment
513 result = tl_socket_read_packet_data(udp_globals.net_phone, &packet,
514 UDP_HEADER_SIZE, packet_dimension, addr, addrlen);
515 if (result < 0)
516 return result;
517
518 total_length = (size_t) result;
519 if (udp_globals.checksum_computing)
520 checksum = compute_checksum(0, packet_get_data(packet),
521 packet_get_data_length(packet));
522 else
523 checksum = 0;
524
525 // prefix the udp header
526 header = PACKET_PREFIX(packet, udp_header_t);
527 if (!header)
528 return udp_release_and_return(packet, ENOMEM);
529
530 bzero(header, sizeof(*header));
531 // read the rest of the packet fragments
532 for (index = 1; index < fragments; index++) {
533 result = tl_socket_read_packet_data(udp_globals.net_phone,
534 &next_packet, 0, packet_dimension, addr, addrlen);
535 if (result < 0)
536 return udp_release_and_return(packet, result);
537
538 rc = pq_add(&packet, next_packet, index, 0);
539 if (rc != EOK)
540 return udp_release_and_return(packet, rc);
541
542 total_length += (size_t) result;
543 if (udp_globals.checksum_computing) {
544 checksum = compute_checksum(checksum,
545 packet_get_data(next_packet),
546 packet_get_data_length(next_packet));
547 }
548 }
549
550 // set the udp header
551 header->source_port = htons((socket->port > 0) ? socket->port : 0);
552 header->destination_port = htons(dest_port);
553 header->total_length = htons(total_length + sizeof(*header));
554 header->checksum = 0;
555 if (udp_globals.checksum_computing) {
556 // update the pseudo header
557 rc = ip_client_set_pseudo_header_data_length(ip_header,
558 headerlen, total_length + UDP_HEADER_SIZE);
559 if (rc != EOK) {
560 free(ip_header);
561 return udp_release_and_return(packet, rc);
562 }
563
564 // finish the checksum computation
565 checksum = compute_checksum(checksum, ip_header, headerlen);
566 checksum = compute_checksum(checksum, (uint8_t *) header,
567 sizeof(*header));
568 header->checksum =
569 htons(flip_checksum(compact_checksum(checksum)));
570 free(ip_header);
571 } else {
572 device_id = DEVICE_INVALID_ID;
573 }
574
575 // prepare the first packet fragment
576 rc = ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0);
577 if (rc != EOK)
578 return udp_release_and_return(packet, rc);
579
580 /* Release the UDP global lock on success. */
581 fibril_rwlock_write_unlock(&udp_globals.lock);
582
583 // send the packet
584 ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0);
585
586 return EOK;
587}
588
589/** Receives data to the socket.
590 *
591 * Handles the NET_SOCKET_RECVFROM message.
592 * Replies the source address as well.
593 *
594 * @param[in] local_sockets The application local sockets.
595 * @param[in] socket_id Socket identifier.
596 * @param[in] flags Various receive flags.
597 * @param[out] addrlen The source address length.
598 * @returns The number of bytes received.
599 * @returns ENOTSOCK if the socket is not found.
600 * @returns NO_DATA if there are no received packets or data.
601 * @returns ENOMEM if there is not enough memory left.
602 * @returns EINVAL if the received address is not an IP address.
603 * @returns Other error codes as defined for the packet_translate()
604 * function.
605 * @returns Other error codes as defined for the data_reply()
606 * function.
607 */
608static int
609udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags,
610 size_t *addrlen)
611{
612 socket_core_ref socket;
613 int packet_id;
614 packet_t packet;
615 udp_header_ref header;
616 struct sockaddr *addr;
617 size_t length;
618 uint8_t *data;
619 int result;
620 int rc;
621
622 // find the socket
623 socket = socket_cores_find(local_sockets, socket_id);
624 if (!socket)
625 return ENOTSOCK;
626
627 // get the next received packet
628 packet_id = dyn_fifo_pop(&socket->received);
629 if (packet_id < 0)
630 return NO_DATA;
631
632 rc = packet_translate_remote(udp_globals.net_phone, &packet, packet_id);
633 if (rc != EOK)
634 return rc;
635
636 // get udp header
637 data = packet_get_data(packet);
638 if (!data)
639 return udp_release_and_return(packet, NO_DATA);
640 header = (udp_header_ref) data;
641
642 // set the source address port
643 result = packet_get_addr(packet, (uint8_t **) &addr, NULL);
644 rc = tl_set_address_port(addr, result, ntohs(header->source_port));
645 if (rc != EOK)
646 return udp_release_and_return(packet, rc);
647 *addrlen = (size_t) result;
648
649 // send the source address
650 rc = data_reply(addr, *addrlen);
651 if (rc != EOK)
652 return udp_release_and_return(packet, rc);
653
654 // trim the header
655 rc = packet_trim(packet, UDP_HEADER_SIZE, 0);
656 if (rc != EOK)
657 return udp_release_and_return(packet, rc);
658
659 // reply the packets
660 rc = socket_reply_packets(packet, &length);
661 if (rc != EOK)
662 return udp_release_and_return(packet, rc);
663
664 // release the packet and return the total length
665 return udp_release_and_return(packet, (int) length);
666}
667
668/** Processes the socket client messages.
669 *
670 * Runs until the client module disconnects.
671 *
672 * @param[in] callid The message identifier.
673 * @param[in] call The message parameters.
674 * @returns EOK on success.
675 *
676 * @see socket.h
677 */
678static int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
679{
680 int res;
681 bool keep_on_going = true;
682 socket_cores_t local_sockets;
683 int app_phone = IPC_GET_PHONE(&call);
684 struct sockaddr *addr;
685 int socket_id;
686 size_t addrlen;
687 size_t size;
688 ipc_call_t answer;
689 int answer_count;
690 packet_dimension_ref packet_dimension;
691
692 /*
693 * Accept the connection
694 * - Answer the first IPC_M_CONNECT_TO_ME call.
695 */
696 res = EOK;
697 answer_count = 0;
698
699 // The client connection is only in one fibril and therefore no
700 // additional locks are needed.
701
702 socket_cores_initialize(&local_sockets);
703
704 while (keep_on_going) {
705
706 // answer the call
707 answer_call(callid, res, &answer, answer_count);
708
709 // refresh data
710 refresh_answer(&answer, &answer_count);
711
712 // get the next call
713 callid = async_get_call(&call);
714
715 // process the call
716 switch (IPC_GET_METHOD(call)) {
717 case IPC_M_PHONE_HUNGUP:
718 keep_on_going = false;
719 res = EHANGUP;
720 break;
721
722 case NET_SOCKET:
723 socket_id = SOCKET_GET_SOCKET_ID(call);
724 res = socket_create(&local_sockets, app_phone, NULL,
725 &socket_id);
726 SOCKET_SET_SOCKET_ID(answer, socket_id);
727
728 if (res != EOK)
729 break;
730
731 if (tl_get_ip_packet_dimension(udp_globals.ip_phone,
732 &udp_globals.dimensions, DEVICE_INVALID_ID,
733 &packet_dimension) == EOK) {
734 SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
735 packet_dimension->content);
736 }
737
738// SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
739// MAX_UDP_FRAGMENT_SIZE);
740 SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE);
741 answer_count = 3;
742 break;
743
744 case NET_SOCKET_BIND:
745 res = data_receive((void **) &addr, &addrlen);
746 if (res != EOK)
747 break;
748 fibril_rwlock_write_lock(&udp_globals.lock);
749 res = socket_bind(&local_sockets, &udp_globals.sockets,
750 SOCKET_GET_SOCKET_ID(call), addr, addrlen,
751 UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
752 udp_globals.last_used_port);
753 fibril_rwlock_write_unlock(&udp_globals.lock);
754 free(addr);
755 break;
756
757 case NET_SOCKET_SENDTO:
758 res = data_receive((void **) &addr, &addrlen);
759 if (res != EOK)
760 break;
761
762 fibril_rwlock_write_lock(&udp_globals.lock);
763 res = udp_sendto_message(&local_sockets,
764 SOCKET_GET_SOCKET_ID(call), addr, addrlen,
765 SOCKET_GET_DATA_FRAGMENTS(call), &size,
766 SOCKET_GET_FLAGS(call));
767 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
768
769 if (res != EOK)
770 fibril_rwlock_write_unlock(&udp_globals.lock);
771 else
772 answer_count = 2;
773
774 free(addr);
775 break;
776
777 case NET_SOCKET_RECVFROM:
778 fibril_rwlock_write_lock(&udp_globals.lock);
779 res = udp_recvfrom_message(&local_sockets,
780 SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
781 &addrlen);
782 fibril_rwlock_write_unlock(&udp_globals.lock);
783
784 if (res <= 0)
785 break;
786
787 SOCKET_SET_READ_DATA_LENGTH(answer, res);
788 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
789 answer_count = 3;
790 res = EOK;
791 break;
792
793 case NET_SOCKET_CLOSE:
794 fibril_rwlock_write_lock(&udp_globals.lock);
795 res = socket_destroy(udp_globals.net_phone,
796 SOCKET_GET_SOCKET_ID(call), &local_sockets,
797 &udp_globals.sockets, NULL);
798 fibril_rwlock_write_unlock(&udp_globals.lock);
799 break;
800
801 case NET_SOCKET_GETSOCKOPT:
802 case NET_SOCKET_SETSOCKOPT:
803 default:
804 res = ENOTSUP;
805 break;
806 }
807 }
808
809 // release the application phone
810 ipc_hangup(app_phone);
811
812 // release all local sockets
813 socket_cores_release(udp_globals.net_phone, &local_sockets,
814 &udp_globals.sockets, NULL);
815
816 return res;
817}
818
819/** Processes the UDP message.
820 *
821 * @param[in] callid The message identifier.
822 * @param[in] call The message parameters.
823 * @param[out] answer The message answer parameters.
824 * @param[out] answer_count The last parameter for the actual answer in the
825 * answer parameter.
826 * @returns EOK on success.
827 * @returns ENOTSUP if the message is not known.
828 *
829 * @see udp_interface.h
830 * @see IS_NET_UDP_MESSAGE()
831 */
832int
833udp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
834 ipc_call_t *answer, int *answer_count)
835{
836 packet_t packet;
837 int rc;
838
839 *answer_count = 0;
840
841 switch (IPC_GET_METHOD(*call)) {
842 case NET_TL_RECEIVED:
843 rc = packet_translate_remote(udp_globals.net_phone, &packet,
844 IPC_GET_PACKET(call));
845 if (rc != EOK)
846 return rc;
847 return udp_received_msg(IPC_GET_DEVICE(call), packet,
848 SERVICE_UDP, IPC_GET_ERROR(call));
849 case IPC_M_CONNECT_TO_ME:
850 return udp_process_client_messages(callid, * call);
851 }
852
853 return ENOTSUP;
854}
855
856/** Default thread for new connections.
857 *
858 * @param[in] iid The initial message identifier.
859 * @param[in] icall The initial message call structure.
860 */
861static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall)
862{
863 /*
864 * Accept the connection
865 * - Answer the first IPC_M_CONNECT_ME_TO call.
866 */
867 ipc_answer_0(iid, EOK);
868
869 while (true) {
870 ipc_call_t answer;
871 int answer_count;
872
873 /* Clear the answer structure */
874 refresh_answer(&answer, &answer_count);
875
876 /* Fetch the next message */
877 ipc_call_t call;
878 ipc_callid_t callid = async_get_call(&call);
879
880 /* Process the message */
881 int res = tl_module_message_standalone(callid, &call, &answer,
882 &answer_count);
883
884 /*
885 * End if told to either by the message or the processing
886 * result.
887 */
888 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
889 (res == EHANGUP))
890 return;
891
892 /* Answer the message */
893 answer_call(callid, res, &answer, answer_count);
894 }
895}
896
897/** Starts the module.
898 *
899 * @returns EOK on success.
900 * @returns Other error codes as defined for each specific module
901 * start function.
902 */
903int main(int argc, char *argv[])
904{
905 int rc;
906
907 /* Start the module */
908 rc = tl_module_start_standalone(tl_client_connection);
909 return rc;
910}
911
912/** @}
913 */
Note: See TracBrowser for help on using the repository browser.