Remove memory allocation in olsr_timer_add()
[oonf.git] / src / core / olsr_packet_socket.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <errno.h>
43 #include <fcntl.h>
44
45 #include "common/common_types.h"
46 #include "common/list.h"
47 #include "common/autobuf.h"
48 #include "common/netaddr.h"
49 #include "olsr_logging.h"
50 #include "os_net.h"
51 #include "olsr_packet_socket.h"
52 #include "olsr.h"
53
54 static struct list_entity packet_sockets = { NULL, NULL };
55 static char input_buffer[65536];
56
57 /* remember if initialized or not */
58 OLSR_SUBSYSTEM_STATE(_packet_state);
59
60 static void _cb_packet_event(int fd, void *data, bool r, bool w);
61
62 /**
63  * Initialize packet socket handler
64  */
65 void
66 olsr_packet_init(void) {
67   if (olsr_subsystem_init(&_packet_state))
68     return;
69
70   list_init_head(&packet_sockets);
71 }
72
73 /**
74  * Cleanup all resources allocated by packet socket handler
75  */
76 void
77 olsr_packet_cleanup(void) {
78   struct olsr_packet_socket *skt;
79
80   if (olsr_subsystem_cleanup(&_packet_state))
81     return;
82
83   while (!list_is_empty(&packet_sockets)) {
84     skt = list_first_element(&packet_sockets, skt, node);
85
86     olsr_packet_remove(skt);
87   }
88 }
89
90 /**
91  * Add a new packet socket handler
92  * @param pktsocket pointer to uninitialized packet socket struct
93  * @param local pointer local IP address of packet socket
94  * @return -1 if an error happened, 0 otherwise
95  */
96 int
97 olsr_packet_add(struct olsr_packet_socket *pktsocket,
98     union netaddr_socket *local) {
99   int s = -1;
100
101   memset(pktsocket, 0, sizeof(*pktsocket));
102
103   /* Init socket */
104   s = os_net_getsocket(local, OS_SOCKET_UDP | OS_SOCKET_MULTICAST, 0, LOG_SOCKET_PACKET);
105   if (s < 0) {
106     return -1;
107   }
108
109   pktsocket->scheduler_entry.fd = s;
110   pktsocket->scheduler_entry.process = _cb_packet_event;
111   pktsocket->scheduler_entry.event_read = true;
112   pktsocket->scheduler_entry.event_write = true;
113   pktsocket->scheduler_entry.data = pktsocket;
114
115   olsr_socket_add(&pktsocket->scheduler_entry);
116
117   abuf_init(&pktsocket->out);
118   list_add_tail(&packet_sockets, &pktsocket->node);
119   memcpy(&pktsocket->local_socket, local, sizeof(pktsocket->local_socket));
120
121   pktsocket->input_buffer = input_buffer;
122   pktsocket->input_buffer_length = sizeof(input_buffer);
123   return 0;
124 }
125
126 /**
127  * Remove a packet socket from the global scheduler
128  * @param pktsocket pointer to packet socket
129  */
130 void
131 olsr_packet_remove(struct olsr_packet_socket *pktsocket) {
132   if (list_is_node_added(&pktsocket->node)) {
133     olsr_socket_remove(&pktsocket->scheduler_entry);
134     os_close(pktsocket->scheduler_entry.fd);
135     list_remove(&pktsocket->node);
136
137     abuf_free(&pktsocket->out);
138   }
139 }
140
141 /**
142  * Send a data packet through a packet socket. The transmission might not
143  * be happen synchronously if the socket would block.
144  * @param pktsocket pointer to packet socket
145  * @param remote ip/address to send packet to
146  * @param data pointer to data to be sent
147  * @param length length of data
148  * @return -1 if an error happened, 0 otherwise
149  */
150 int
151 olsr_packet_send(struct olsr_packet_socket *pktsocket, union netaddr_socket *remote,
152     const void *data, size_t length) {
153   int result;
154 #if !defined(REMOVE_LOG_WARN)
155   struct netaddr_str buf;
156 #endif
157
158   if (abuf_getlen(&pktsocket->out) == 0) {
159     /* no backlog of outgoing packets, try to send directly */
160     result = os_sendto(pktsocket->scheduler_entry.fd, data, length, remote);
161     if (result > 0) {
162       /* successful */
163       return 0;
164     }
165
166     if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
167       OLSR_WARN(LOG_SOCKET_PACKET, "Cannot send UDP packet to %s: %s (%d)",
168           netaddr_socket_to_string(&buf, remote), strerror(errno), errno);
169       return -1;
170     }
171   }
172
173   /* append destination */
174   abuf_memcpy(&pktsocket->out, remote, sizeof(*remote));
175
176   /* append data length */
177   abuf_append_uint16(&pktsocket->out, length);
178
179   /* append data */
180   abuf_memcpy(&pktsocket->out, data, length);
181
182   /* activate outgoing socket scheduler */
183   olsr_socket_set_write(&pktsocket->scheduler_entry, true);
184   return 0;
185 }
186
187 /**
188  * Callback to handle data from the olsr socket scheduler
189  * @param fd filedescriptor to read data from
190  * @param data custom data pointer
191  * @param event_read true if read-event is incoming
192  * @param event_write true if write-event is incoming
193  */
194 static void
195 _cb_packet_event(int fd, void *data, bool event_read, bool event_write) {
196   struct olsr_packet_socket *pktsocket = data;
197   union netaddr_socket *skt, sock;
198   uint16_t length;
199   char *pkt;
200   int result;
201 #if !defined(REMOVE_LOG_WARN)
202   struct netaddr_str buf;
203 #endif
204
205   if (event_read) {
206     /* handle incoming data */
207     result = os_recvfrom(fd, pktsocket->input_buffer, pktsocket->input_buffer_length-1, &sock);
208     if (result > 0 && pktsocket->receive_data != NULL) {
209       /* null terminate it */
210       pktsocket->input_buffer[pktsocket->input_buffer_length-1] = 0;
211
212       /* received valid packet */
213       pktsocket->receive_data(pktsocket, &sock, result);
214     }
215     else if (result < 0 && (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)) {
216       OLSR_WARN(LOG_SOCKET_PACKET, "Cannot read packet from socket %s: %s (%d)",
217           netaddr_socket_to_string(&buf, &pktsocket->local_socket), strerror(errno), errno);
218     }
219   }
220
221   if (event_write && abuf_getlen(&pktsocket->out) > 0) {
222     /* handle outgoing data */
223
224     /* pointer to remote socket */
225     skt = data;
226
227     /* data area */
228     pkt = data;
229     pkt += sizeof(*skt);
230
231     memcpy(&length, pkt, 2);
232     pkt += 2;
233
234     /* try to send packet */
235     result = sendto(fd, data, length, 0, &skt->std, sizeof(*skt));
236     if (result < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
237       /* try again later */
238       return;
239     }
240
241     if (result < 0) {
242       /* display error message */
243       OLSR_WARN(LOG_SOCKET_PACKET, "Cannot send UDP packet to %s: %s (%d)",
244           netaddr_socket_to_string(&buf, skt), strerror(errno), errno);
245     }
246
247     /* remove data from outgoing buffer (both for success and for final error */
248     abuf_pull(&pktsocket->out, sizeof(*skt) + 2 + length);
249   }
250
251   if (abuf_getlen(&pktsocket->out) == 0) {
252     /* nothing left to send, disable outgoing events */
253     olsr_socket_set_write(&pktsocket->scheduler_entry, false);
254   }
255 }