ff68a666aaf65ce78b12cf9e5bfd9882028b0ec6
[oonf.git] / src-plugins / generic / dlep / router / dlep_router_session.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, 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 /**
43  * @file
44  */
45
46 #include <errno.h>
47 #include <unistd.h>
48
49 #include "common/avl.h"
50 #include "common/avl_comp.h"
51 #include "common/common_types.h"
52 #include "common/netaddr.h"
53
54 #include "subsystems/oonf_class.h"
55 #include "subsystems/oonf_layer2.h"
56 #include "subsystems/oonf_stream_socket.h"
57 #include "subsystems/oonf_timer.h"
58
59 #include "dlep/dlep_iana.h"
60 #include "dlep/dlep_session.h"
61 #include "dlep/dlep_writer.h"
62 #include "dlep/router/dlep_router.h"
63 #include "dlep/router/dlep_router_interface.h"
64 #include "dlep/router/dlep_router_internal.h"
65 #include "dlep/router/dlep_router_session.h"
66
67 static void _cb_socket_terminated(struct oonf_stream_socket *stream_socket);
68 static void _cb_tcp_lost(struct oonf_stream_session *);
69 static enum oonf_stream_session_state _cb_tcp_receive_data(struct oonf_stream_session *);
70 static void _cb_send_buffer(struct dlep_session *session, int af_family);
71 static void _cb_end_session(struct dlep_session *session);
72
73 /* session objects */
74 static struct oonf_class _router_session_class = {
75   .name = "DLEP router stream",
76   .size = sizeof(struct dlep_router_session),
77 };
78
79 /**
80  * Initialize dlep router session framework
81  */
82 void
83 dlep_router_session_init(void) {
84   oonf_class_add(&_router_session_class);
85 }
86
87 /**
88  * Cleanup dlep router session framework
89  */
90 void
91 dlep_router_session_cleanup(void) {
92   oonf_class_remove(&_router_session_class);
93 }
94
95 /**
96  * Get dlep router session based on interface and remote socket
97  * @param interf dlep router interface
98  * @param remote remote IP socket
99  * @return dlep router session, NULL if not found
100  */
101 struct dlep_router_session *
102 dlep_router_get_session(struct dlep_router_if *interf, union netaddr_socket *remote) {
103   struct dlep_router_session *session;
104
105   return avl_find_element(&interf->interf.session_tree, remote, session, _node);
106 }
107
108 /**
109  * Add new dlep router session or return existing one
110  * @param interf dlep router interface
111  * @param local local IP socket
112  * @param remote remote IP socket
113  * @return dlep router session, NULL if not found
114  */
115 struct dlep_router_session *
116 dlep_router_add_session(struct dlep_router_if *interf, union netaddr_socket *local, union netaddr_socket *remote) {
117   struct dlep_router_session *router_session;
118   struct dlep_extension *ext;
119   struct netaddr_str nbuf1, nbuf2;
120
121   router_session = dlep_router_get_session(interf, remote);
122   if (router_session) {
123     OONF_DEBUG(LOG_DLEP_ROUTER,
124       "use existing instance on"
125       " %s for %s",
126       interf->interf.l2_ifname, netaddr_socket_to_string(&nbuf1, remote));
127     return router_session;
128   }
129
130   /* initialize tcp session instance */
131   router_session = oonf_class_malloc(&_router_session_class);
132   if (!router_session) {
133     return NULL;
134   }
135
136   /* initialize tree node */
137   memcpy(&router_session->session.remote_socket, remote, sizeof(*remote));
138   router_session->_node.key = &router_session->session.remote_socket;
139
140   /* configure and open TCP session */
141   router_session->tcp.config.session_timeout = 120000; /* 120 seconds */
142   router_session->tcp.config.maximum_input_buffer = 4096;
143   router_session->tcp.config.allowed_sessions = 3;
144   router_session->tcp.config.cleanup_session = _cb_tcp_lost;
145   router_session->tcp.config.cleanup_socket = _cb_socket_terminated;
146   router_session->tcp.config.receive_data = _cb_tcp_receive_data;
147
148   OONF_DEBUG(LOG_DLEP_ROUTER, "Connect DLEP session from %s to %s", netaddr_socket_to_string(&nbuf1, local),
149     netaddr_socket_to_string(&nbuf2, remote));
150
151   if (oonf_stream_add(&router_session->tcp, local)) {
152     OONF_WARN(
153       LOG_DLEP_ROUTER, "Could not open TCP client for local address %s", netaddr_socket_to_string(&nbuf1, local));
154     dlep_router_remove_session(router_session);
155     return NULL;
156   }
157
158   /* open stream */
159   router_session->stream = oonf_stream_connect_to(&router_session->tcp, remote);
160   if (!router_session->stream) {
161     OONF_WARN(LOG_DLEP_ROUTER, "Could not open TCP client on from %s to %s", netaddr_socket_to_string(&nbuf1, local),
162       netaddr_socket_to_string(&nbuf2, remote));
163     dlep_router_remove_session(router_session);
164     return NULL;
165   }
166
167   if (dlep_session_add(&router_session->session, interf->interf.l2_ifname, interf->interf.session.l2_origin,
168         interf->interf.session.l2_default_origin, &router_session->stream->out, false, LOG_DLEP_ROUTER)) {
169     dlep_router_remove_session(router_session);
170     return NULL;
171   }
172   router_session->session.restrict_signal = DLEP_SESSION_INITIALIZATION_ACK;
173   router_session->session.cb_send_buffer = _cb_send_buffer;
174   router_session->session.cb_end_session = _cb_end_session;
175   memcpy(&router_session->session.cfg, &interf->interf.session.cfg, sizeof(router_session->session.cfg));
176
177   /* initialize back pointer */
178   router_session->interface = interf;
179
180   /* add session to interface */
181   avl_insert(&interf->interf.session_tree, &router_session->_node);
182
183   /* inform all extensions */
184   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
185     if (ext->cb_session_init_router) {
186       ext->cb_session_init_router(&router_session->session);
187     }
188   }
189
190   return router_session;
191 }
192
193 /**
194  * Remove existing dlep router session
195  * @param router_session dlep router session
196  */
197 void
198 dlep_router_remove_session(struct dlep_router_session *router_session) {
199   if (router_session->stream) {
200     oonf_stream_close(router_session->stream);
201     router_session->stream = NULL;
202   }
203   oonf_stream_remove(&router_session->tcp, false);
204 }
205
206 /**
207  * Callback triggered when tcp socket (not session) has been terminated
208  * @param stream_socket terminated socket
209  */
210 static void
211 _cb_socket_terminated(struct oonf_stream_socket *stream_socket) {
212   struct dlep_router_session *router_session;
213
214   router_session = container_of(stream_socket, struct dlep_router_session, tcp);
215
216   oonf_class_free(&_router_session_class, router_session);
217 }
218 /**
219  * Callback triggered when tcp session was lost and will be removed
220  * @param tcp_session tcp session
221  */
222 static void
223 _cb_tcp_lost(struct oonf_stream_session *tcp_session) {
224   struct dlep_extension *ext;
225   struct dlep_router_session *router_session;
226 #ifdef OONF_LOG_DEBUG_INFO
227   struct netaddr_str nbuf;
228 #endif
229
230   router_session = container_of(tcp_session->stream_socket, struct dlep_router_session, tcp);
231
232   OONF_DEBUG(LOG_DLEP_ROUTER, "Lost tcp session to %s", netaddr_socket_to_string(&nbuf, &tcp_session->remote_socket));
233
234   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
235     if (ext->cb_session_cleanup_router) {
236       ext->cb_session_cleanup_router(&router_session->session);
237     }
238   }
239
240   /* kill embedded session object */
241   dlep_session_remove(&router_session->session);
242
243   /* remove from session tree of interface */
244   if (avl_is_node_added(&router_session->_node)) {
245     avl_remove(&router_session->interface->interf.session_tree, &router_session->_node);
246   }
247 }
248
249 /**
250  * Receive tcp data via oonf_stream_socket
251  * @param tcp_session tcp session to DLEP partner
252  * @return new state of TCP session
253  */
254 static enum oonf_stream_session_state
255 _cb_tcp_receive_data(struct oonf_stream_session *tcp_session) {
256   struct dlep_router_session *router_session;
257
258   router_session = container_of(tcp_session->stream_socket, struct dlep_router_session, tcp);
259
260   return dlep_session_process_tcp(tcp_session, &router_session->session);
261 }
262
263 /**
264  * Callback triggered to send current buffer to the network
265  * @param session dlep session
266  * @param af_family address family
267  */
268 static void
269 _cb_send_buffer(struct dlep_session *session, int af_family __attribute((unused))) {
270   struct dlep_router_session *router_session;
271
272   if (!abuf_getlen(session->writer.out)) {
273     return;
274   }
275
276   OONF_DEBUG(session->log_source, "Send buffer %" PRINTF_SIZE_T_SPECIFIER " bytes", abuf_getlen(session->writer.out));
277
278   /* get pointer to radio interface */
279   router_session = container_of(session, struct dlep_router_session, session);
280
281   oonf_stream_flush(router_session->stream);
282 }
283
284 /**
285  * Callback triggered when session is terminated
286  * @param session dlep session
287  */
288 static void
289 _cb_end_session(struct dlep_session *session) {
290   struct dlep_router_session *router_session;
291
292   /* get pointer to radio interface */
293   router_session = container_of(session, struct dlep_router_session, session);
294
295   dlep_router_remove_session(router_session);
296 }