source: mainline/uspace/srv/net/udp/sock.c@ db81577

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

Fix calloc() argument order.

  • Property mode set to 100644
File size: 16.7 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/socket.h>
46#include <ns.h>
47
48#include "sock.h"
49#include "std.h"
50#include "udp_type.h"
51#include "ucall.h"
52
53/** Free ports pool start. */
54#define UDP_FREE_PORTS_START 1025
55
56/** Free ports pool end. */
57#define UDP_FREE_PORTS_END 65535
58
59static int last_used_port = UDP_FREE_PORTS_START - 1;
60static socket_ports_t gsock;
61
62static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
63static int udp_sock_recv_fibril(void *arg);
64
65int udp_sock_init(void)
66{
67 socket_ports_initialize(&gsock);
68
69 async_set_client_connection(udp_sock_connection);
70
71 int rc = service_register(SERVICE_UDP);
72 if (rc != EOK)
73 return EEXIST;
74
75 return EOK;
76}
77
78static void udp_free_sock_data(socket_core_t *sock_core)
79{
80 udp_sockdata_t *socket;
81
82 socket = (udp_sockdata_t *)sock_core->specific_data;
83 (void)socket;
84
85 /* XXX We need to force the receive fibril to quit */
86}
87
88static void udp_sock_notify_data(socket_core_t *sock_core)
89{
90 log_msg(LVL_DEBUG, "udp_sock_notify_data(%d)", sock_core->socket_id);
91 async_exch_t *exch = async_exchange_begin(sock_core->sess);
92 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
93 UDP_FRAGMENT_SIZE, 0, 0, 1);
94 async_exchange_end(exch);
95}
96
97static void udp_sock_socket(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
98{
99 udp_sockdata_t *sock;
100 socket_core_t *sock_core;
101 int sock_id;
102 int rc;
103 ipc_call_t answer;
104
105 log_msg(LVL_DEBUG, "udp_sock_socket()");
106 sock = calloc(1, sizeof(udp_sockdata_t));
107 if (sock == NULL) {
108 async_answer_0(callid, ENOMEM);
109 return;
110 }
111
112 fibril_mutex_initialize(&sock->lock);
113 sock->client = client;
114
115 sock->recv_buffer_used = 0;
116 sock->recv_error = UDP_EOK;
117 fibril_mutex_initialize(&sock->recv_buffer_lock);
118 fibril_condvar_initialize(&sock->recv_buffer_cv);
119
120 rc = udp_uc_create(&sock->assoc);
121 if (rc != EOK) {
122 free(sock);
123 async_answer_0(callid, rc);
124 return;
125 }
126
127 sock->recv_fibril = fibril_create(udp_sock_recv_fibril, sock);
128 if (sock->recv_fibril == 0) {
129 udp_uc_destroy(sock->assoc);
130 free(sock);
131 async_answer_0(callid, ENOMEM);
132 return;
133 }
134
135 sock_id = SOCKET_GET_SOCKET_ID(call);
136 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
137 if (rc != EOK) {
138 fibril_destroy(sock->recv_fibril);
139 udp_uc_destroy(sock->assoc);
140 free(sock);
141 async_answer_0(callid, rc);
142 return;
143 }
144
145 fibril_add_ready(sock->recv_fibril);
146
147 sock_core = socket_cores_find(&client->sockets, sock_id);
148 assert(sock_core != NULL);
149 sock->sock_core = sock_core;
150
151 SOCKET_SET_SOCKET_ID(answer, sock_id);
152
153 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
154 SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
155 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
156 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
157}
158
159static void udp_sock_bind(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
160{
161 int rc;
162 struct sockaddr_in *addr;
163 size_t addr_size;
164 socket_core_t *sock_core;
165 udp_sockdata_t *socket;
166 udp_sock_t fsock;
167 udp_error_t urc;
168
169 log_msg(LVL_DEBUG, "udp_sock_bind()");
170 log_msg(LVL_DEBUG, " - async_data_write_accept");
171
172 addr = NULL;
173
174 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_size);
175 if (rc != EOK) {
176 async_answer_0(callid, rc);
177 goto out;
178 }
179
180 log_msg(LVL_DEBUG, " - call socket_bind");
181 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
182 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
183 last_used_port);
184 if (rc != EOK) {
185 async_answer_0(callid, rc);
186 goto out;
187 }
188
189 if (addr_size != sizeof(struct sockaddr_in)) {
190 async_answer_0(callid, EINVAL);
191 goto out;
192 }
193
194 log_msg(LVL_DEBUG, " - call socket_cores_find");
195 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
196 if (sock_core == NULL) {
197 async_answer_0(callid, ENOENT);
198 goto out;
199 }
200
201 socket = (udp_sockdata_t *)sock_core->specific_data;
202
203 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
204 fsock.port = sock_core->port;
205 urc = udp_uc_set_local(socket->assoc, &fsock);
206
207 switch (urc) {
208 case UDP_EOK:
209 rc = EOK;
210 break;
211/* case TCP_ENOTEXIST:
212 rc = ENOTCONN;
213 break;
214 case TCP_ECLOSING:
215 rc = ENOTCONN;
216 break;
217 case TCP_ERESET:
218 rc = ECONNABORTED;
219 break;*/
220 default:
221 assert(false);
222 }
223
224 log_msg(LVL_DEBUG, " - success");
225 async_answer_0(callid, rc);
226out:
227 if (addr != NULL)
228 free(addr);
229}
230
231static void udp_sock_listen(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
232{
233 log_msg(LVL_DEBUG, "udp_sock_listen()");
234 async_answer_0(callid, ENOTSUP);
235}
236
237static void udp_sock_connect(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
238{
239 log_msg(LVL_DEBUG, "udp_sock_connect()");
240 async_answer_0(callid, ENOTSUP);
241}
242
243static void udp_sock_accept(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
244{
245 log_msg(LVL_DEBUG, "udp_sock_accept()");
246 async_answer_0(callid, ENOTSUP);
247}
248
249static void udp_sock_sendto(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
250{
251 int socket_id;
252 int fragments;
253 int index;
254 struct sockaddr_in *addr;
255 size_t addr_size;
256 socket_core_t *sock_core;
257 udp_sockdata_t *socket;
258 udp_sock_t fsock, *fsockp;
259 ipc_call_t answer;
260 ipc_callid_t wcallid;
261 size_t length;
262 uint8_t buffer[UDP_FRAGMENT_SIZE];
263 udp_error_t urc;
264 int rc;
265
266 log_msg(LVL_DEBUG, "udp_sock_send()");
267
268 addr = NULL;
269
270 if (IPC_GET_IMETHOD(call) == NET_SOCKET_SENDTO) {
271 rc = async_data_write_accept((void **) &addr, false,
272 0, 0, 0, &addr_size);
273 if (rc != EOK) {
274 async_answer_0(callid, rc);
275 goto out;
276 }
277
278 if (addr_size != sizeof(struct sockaddr_in)) {
279 async_answer_0(callid, EINVAL);
280 goto out;
281 }
282
283 fsock.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
284 fsock.port = uint16_t_be2host(addr->sin_port);
285 fsockp = &fsock;
286 } else {
287 fsockp = NULL;
288 }
289
290 socket_id = SOCKET_GET_SOCKET_ID(call);
291 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
292 SOCKET_GET_FLAGS(call);
293
294 sock_core = socket_cores_find(&client->sockets, socket_id);
295 if (sock_core == NULL) {
296 async_answer_0(callid, ENOTSOCK);
297 goto out;
298 }
299
300 if (sock_core->port == 0) {
301 /* Implicitly bind socket to port */
302 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
303 addr, addr_size, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END,
304 last_used_port);
305 if (rc != EOK) {
306 async_answer_0(callid, rc);
307 goto out;
308 }
309 }
310
311 socket = (udp_sockdata_t *)sock_core->specific_data;
312 fibril_mutex_lock(&socket->lock);
313
314 if (socket->assoc->ident.local.addr.ipv4 == UDP_IPV4_ANY) {
315 /* Determine local IP address */
316 inet_addr_t loc_addr, rem_addr;
317
318 rem_addr.ipv4 = fsockp ? fsock.addr.ipv4 :
319 socket->assoc->ident.foreign.addr.ipv4;
320
321 rc = inet_get_srcaddr(&rem_addr, 0, &loc_addr);
322 if (rc != EOK) {
323 fibril_mutex_unlock(&socket->lock);
324 async_answer_0(callid, rc);
325 log_msg(LVL_DEBUG, "udp_sock_sendto: Failed to "
326 "determine local address.");
327 return;
328 }
329
330 socket->assoc->ident.local.addr.ipv4 = loc_addr.ipv4;
331 log_msg(LVL_DEBUG, "Local IP address is %x",
332 socket->assoc->ident.local.addr.ipv4);
333 }
334
335
336 assert(socket->assoc != NULL);
337
338 for (index = 0; index < fragments; index++) {
339 if (!async_data_write_receive(&wcallid, &length)) {
340 fibril_mutex_unlock(&socket->lock);
341 async_answer_0(callid, EINVAL);
342 goto out;
343 }
344
345 if (length > UDP_FRAGMENT_SIZE)
346 length = UDP_FRAGMENT_SIZE;
347
348 rc = async_data_write_finalize(wcallid, buffer, length);
349 if (rc != EOK) {
350 fibril_mutex_unlock(&socket->lock);
351 async_answer_0(callid, rc);
352 goto out;
353 }
354
355 urc = udp_uc_send(socket->assoc, fsockp, buffer, length, 0);
356
357 switch (urc) {
358 case UDP_EOK:
359 rc = EOK;
360 break;
361/* case TCP_ENOTEXIST:
362 rc = ENOTCONN;
363 break;
364 case TCP_ECLOSING:
365 rc = ENOTCONN;
366 break;
367 case TCP_ERESET:
368 rc = ECONNABORTED;
369 break;*/
370 default:
371 assert(false);
372 }
373
374 if (rc != EOK) {
375 fibril_mutex_unlock(&socket->lock);
376 async_answer_0(callid, rc);
377 goto out;
378 }
379 }
380
381 IPC_SET_ARG1(answer, 0);
382 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
383 async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
384 IPC_GET_ARG2(answer));
385 fibril_mutex_unlock(&socket->lock);
386
387out:
388 if (addr != NULL)
389 free(addr);
390}
391
392static void udp_sock_recvfrom(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
393{
394 int socket_id;
395 int flags;
396 size_t addr_length, length;
397 socket_core_t *sock_core;
398 udp_sockdata_t *socket;
399 ipc_call_t answer;
400 ipc_callid_t rcallid;
401 size_t data_len;
402 udp_error_t urc;
403 udp_sock_t rsock;
404 struct sockaddr_in addr;
405 int rc;
406
407 log_msg(LVL_DEBUG, "%p: udp_sock_recv[from]()", client);
408
409 socket_id = SOCKET_GET_SOCKET_ID(call);
410 flags = SOCKET_GET_FLAGS(call);
411
412 sock_core = socket_cores_find(&client->sockets, socket_id);
413 if (sock_core == NULL) {
414 async_answer_0(callid, ENOTSOCK);
415 return;
416 }
417
418 socket = (udp_sockdata_t *)sock_core->specific_data;
419 fibril_mutex_lock(&socket->lock);
420
421 if (socket->assoc == NULL) {
422 fibril_mutex_unlock(&socket->lock);
423 async_answer_0(callid, ENOTCONN);
424 return;
425 }
426
427 (void)flags;
428
429 log_msg(LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
430 fibril_mutex_lock(&socket->recv_buffer_lock);
431 while (socket->recv_buffer_used == 0 && socket->recv_error == UDP_EOK) {
432 log_msg(LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
433 fibril_condvar_wait(&socket->recv_buffer_cv,
434 &socket->recv_buffer_lock);
435 }
436
437 log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
438
439 rsock = socket->recv_fsock;
440 data_len = socket->recv_buffer_used;
441 urc = socket->recv_error;
442
443 log_msg(LVL_DEBUG, "**** recv data_len=%zu", data_len);
444
445 switch (urc) {
446 case UDP_EOK:
447 rc = EOK;
448 break;
449/* case TCP_ENOTEXIST:
450 case TCP_ECLOSING:
451 rc = ENOTCONN;
452 break;
453 case TCP_ERESET:
454 rc = ECONNABORTED;
455 break;*/
456 default:
457 assert(false);
458 }
459
460 log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
461 if (rc != EOK) {
462 fibril_mutex_unlock(&socket->recv_buffer_lock);
463 fibril_mutex_unlock(&socket->lock);
464 async_answer_0(callid, rc);
465 return;
466 }
467
468 if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
469 /* Fill addr */
470 addr.sin_family = AF_INET;
471 addr.sin_addr.s_addr = host2uint32_t_be(rsock.addr.ipv4);
472 addr.sin_port = host2uint16_t_be(rsock.port);
473
474 log_msg(LVL_DEBUG, "addr read receive");
475 if (!async_data_read_receive(&rcallid, &addr_length)) {
476 fibril_mutex_unlock(&socket->recv_buffer_lock);
477 fibril_mutex_unlock(&socket->lock);
478 async_answer_0(callid, EINVAL);
479 return;
480 }
481
482 if (addr_length > sizeof(addr))
483 addr_length = sizeof(addr);
484
485 log_msg(LVL_DEBUG, "addr read finalize");
486 rc = async_data_read_finalize(rcallid, &addr, addr_length);
487 if (rc != EOK) {
488 fibril_mutex_unlock(&socket->recv_buffer_lock);
489 fibril_mutex_unlock(&socket->lock);
490 async_answer_0(callid, EINVAL);
491 return;
492 }
493 }
494
495 log_msg(LVL_DEBUG, "data read receive");
496 if (!async_data_read_receive(&rcallid, &length)) {
497 fibril_mutex_unlock(&socket->recv_buffer_lock);
498 fibril_mutex_unlock(&socket->lock);
499 async_answer_0(callid, EINVAL);
500 return;
501 }
502
503 if (length > data_len)
504 length = data_len;
505
506 log_msg(LVL_DEBUG, "data read finalize");
507 rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
508
509 if (length < data_len && rc == EOK)
510 rc = EOVERFLOW;
511
512 log_msg(LVL_DEBUG, "read_data_length <- %zu", length);
513 IPC_SET_ARG2(answer, 0);
514 SOCKET_SET_READ_DATA_LENGTH(answer, length);
515 SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(addr));
516 async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
517 IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
518
519 socket->recv_buffer_used = 0;
520
521 fibril_condvar_broadcast(&socket->recv_buffer_cv);
522 fibril_mutex_unlock(&socket->recv_buffer_lock);
523 fibril_mutex_unlock(&socket->lock);
524}
525
526static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
527{
528 int socket_id;
529 socket_core_t *sock_core;
530 udp_sockdata_t *socket;
531 int rc;
532
533 log_msg(LVL_DEBUG, "tcp_sock_close()");
534 socket_id = SOCKET_GET_SOCKET_ID(call);
535
536 sock_core = socket_cores_find(&client->sockets, socket_id);
537 if (sock_core == NULL) {
538 async_answer_0(callid, ENOTSOCK);
539 return;
540 }
541
542 socket = (udp_sockdata_t *)sock_core->specific_data;
543 fibril_mutex_lock(&socket->lock);
544
545 rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock,
546 udp_free_sock_data);
547 if (rc != EOK) {
548 fibril_mutex_unlock(&socket->lock);
549 async_answer_0(callid, rc);
550 return;
551 }
552
553 fibril_mutex_unlock(&socket->lock);
554 async_answer_0(callid, EOK);
555}
556
557static void udp_sock_getsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
558{
559 log_msg(LVL_DEBUG, "udp_sock_getsockopt()");
560 async_answer_0(callid, ENOTSUP);
561}
562
563static void udp_sock_setsockopt(udp_client_t *client, ipc_callid_t callid, ipc_call_t call)
564{
565 log_msg(LVL_DEBUG, "udp_sock_setsockopt()");
566 async_answer_0(callid, ENOTSUP);
567}
568
569static int udp_sock_recv_fibril(void *arg)
570{
571 udp_sockdata_t *sock = (udp_sockdata_t *)arg;
572 udp_error_t urc;
573 xflags_t xflags;
574 size_t rcvd;
575
576 log_msg(LVL_DEBUG, "udp_sock_recv_fibril()");
577
578 while (true) {
579 log_msg(LVL_DEBUG, "[] wait for rcv buffer empty()");
580 fibril_mutex_lock(&sock->recv_buffer_lock);
581 while (sock->recv_buffer_used != 0) {
582 fibril_condvar_wait(&sock->recv_buffer_cv,
583 &sock->recv_buffer_lock);
584 }
585
586 log_msg(LVL_DEBUG, "[] call udp_uc_receive()");
587 urc = udp_uc_receive(sock->assoc, sock->recv_buffer,
588 UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock);
589 sock->recv_error = urc;
590
591 udp_sock_notify_data(sock->sock_core);
592
593 if (urc != UDP_EOK) {
594 fibril_condvar_broadcast(&sock->recv_buffer_cv);
595 fibril_mutex_unlock(&sock->recv_buffer_lock);
596 break;
597 }
598
599 log_msg(LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
600
601 sock->recv_buffer_used = rcvd;
602 fibril_mutex_unlock(&sock->recv_buffer_lock);
603 fibril_condvar_broadcast(&sock->recv_buffer_cv);
604 }
605
606 udp_uc_destroy(sock->assoc);
607
608 return 0;
609}
610
611static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
612{
613 ipc_callid_t callid;
614 ipc_call_t call;
615 udp_client_t client;
616
617 /* Accept the connection */
618 async_answer_0(iid, EOK);
619
620 client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
621 socket_cores_initialize(&client.sockets);
622
623 while (true) {
624 log_msg(LVL_DEBUG, "udp_sock_connection: wait");
625 callid = async_get_call(&call);
626 if (!IPC_GET_IMETHOD(call))
627 break;
628
629 log_msg(LVL_DEBUG, "udp_sock_connection: METHOD=%d",
630 (int)IPC_GET_IMETHOD(call));
631
632 switch (IPC_GET_IMETHOD(call)) {
633 case NET_SOCKET:
634 udp_sock_socket(&client, callid, call);
635 break;
636 case NET_SOCKET_BIND:
637 udp_sock_bind(&client, callid, call);
638 break;
639 case NET_SOCKET_LISTEN:
640 udp_sock_listen(&client, callid, call);
641 break;
642 case NET_SOCKET_CONNECT:
643 udp_sock_connect(&client, callid, call);
644 break;
645 case NET_SOCKET_ACCEPT:
646 udp_sock_accept(&client, callid, call);
647 break;
648 case NET_SOCKET_SEND:
649 case NET_SOCKET_SENDTO:
650 udp_sock_sendto(&client, callid, call);
651 break;
652 case NET_SOCKET_RECV:
653 case NET_SOCKET_RECVFROM:
654 udp_sock_recvfrom(&client, callid, call);
655 break;
656 case NET_SOCKET_CLOSE:
657 udp_sock_close(&client, callid, call);
658 break;
659 case NET_SOCKET_GETSOCKOPT:
660 udp_sock_getsockopt(&client, callid, call);
661 break;
662 case NET_SOCKET_SETSOCKOPT:
663 udp_sock_setsockopt(&client, callid, call);
664 break;
665 default:
666 async_answer_0(callid, ENOTSUP);
667 break;
668 }
669 }
670
671 /* Clean up */
672 log_msg(LVL_DEBUG, "udp_sock_connection: Clean up");
673 async_hangup(client.sess);
674 socket_cores_release(NULL, &client.sockets, &gsock, udp_free_sock_data);
675}
676
677/**
678 * @}
679 */
Note: See TracBrowser for help on using the repository browser.