2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
3 * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
14 * the documentation and/or other materials provided with the
16 * * Neither the name of olsr.org, olsrd nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 * Visit http://www.olsr.org for more information.
35 * If you find this software useful feel free to make a donation
36 * to the project. For more information see the website or contact
37 * the copyright holders.
53 #include "olsr_logging.h"
55 #include "scheduler.h"
56 #include "olsr_cookie.h"
57 #include "common/autobuf.h"
58 #include "common/avl.h"
59 #include "common/list.h"
62 #include "olsr_comport_http.h"
63 #include "olsr_comport_txt.h"
64 #include "olsr_comport.h"
67 #define HTTP_TIMEOUT 30000
68 #define TXT_TIMEOUT 60000
70 #define COMPORT_MAX_INPUTBUFFER 65536
72 #define OLSR_FOR_ALL_COMPORT_ENTRIES(comport, iterator) list_for_each_element_safe(&olsr_comport_head, comport, node, iterator)
74 struct list_entity olsr_comport_head;
77 static int comsocket_http = 0;
78 static int comsocket_txt = 0;
80 static struct olsr_cookie_info *connection_cookie;
81 static struct olsr_timer_info *connection_timeout;
83 /* counter for open connections */
84 static int connection_http_count;
85 static int connection_txt_count;
87 static int olsr_com_openport(int port);
89 static void olsr_com_parse_request(int fd, void *data, unsigned int flags);
90 static void olsr_com_parse_connection(int fd, void *data, unsigned int flags);
91 static void olsr_com_cleanup_session(struct comport_connection *con);
93 static void olsr_com_timeout_handler(void *);
96 olsr_com_init(bool failfast) {
98 olsr_create_memcookie("comport connections", sizeof(struct comport_connection));
100 connection_timeout = olsr_alloc_timerinfo("comport timout",
101 &olsr_com_timeout_handler, false);
103 connection_http_count = 0;
104 connection_txt_count = 0;
106 list_init_head(&olsr_comport_head);
108 olsr_com_init_http();
111 if (olsr_cnf->comport_http > 0) {
112 if ((comsocket_http = olsr_com_openport(olsr_cnf->comport_http)) == -1) {
118 add_olsr_socket(comsocket_http, &olsr_com_parse_request, NULL, NULL,
122 if (olsr_cnf->comport_txt > 0) {
123 if ((comsocket_txt = olsr_com_openport(olsr_cnf->comport_txt)) == -1) {
129 add_olsr_socket(comsocket_txt, &olsr_com_parse_request, NULL, NULL,
136 olsr_com_destroy(void) {
137 struct comport_connection *con, *iterator;
138 OLSR_FOR_ALL_COMPORT_ENTRIES(con, iterator) {
139 olsr_com_cleanup_session(con);
142 olsr_com_destroy_http();
143 olsr_com_destroy_txt();
147 olsr_com_activate_output(struct comport_connection *con) {
148 enable_olsr_socket(con->fd, &olsr_com_parse_connection, NULL, SP_PR_WRITE);
152 olsr_com_openport(int port) {
153 struct sockaddr_storage sst;
157 #if !defined REMOVE_LOG_WARN
158 char ipchar = olsr_cnf->ip_version == AF_INET ? '4' : '6';
161 /* Init ipc socket */
162 int s = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
164 OLSR_WARN(LOG_COMPORT, "Cannot open %d com-socket for IPv%c: %s\n", port, ipchar, strerror(errno));
168 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof(yes)) < 0) {
169 OLSR_WARN(LOG_COMPORT, "Com-port %d SO_REUSEADDR for IPv%c failed: %s\n", port, ipchar, strerror(errno));
174 /* Bind the socket */
176 /* complete the socket structure */
177 memset(&sst, 0, sizeof(sst));
178 if (olsr_cnf->ip_version == AF_INET) {
179 struct sockaddr_in *addr4 = (struct sockaddr_in *) &sst;
180 addr4->sin_family = AF_INET;
181 addrlen = sizeof(*addr4);
183 addr4->sin_len = addrlen;
185 addr4->sin_addr.s_addr = INADDR_ANY;
186 addr4->sin_port = htons(port);
188 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &sst;
189 addr6->sin6_family = AF_INET6;
190 addrlen = sizeof(*addr6);
192 addr6->sin6_len = addrlen;
194 addr6->sin6_addr = in6addr_any;
195 addr6->sin6_port = htons(port);
198 /* bind the socket to the port number */
199 if (bind(s, (struct sockaddr *) &sst, addrlen) == -1) {
200 OLSR_WARN(LOG_COMPORT, "Com-port %d bind failed for IPv%c: %s\n", port, ipchar, strerror(errno));
205 /* show that we are willing to listen */
206 if (listen(s, 1) == -1) {
207 OLSR_WARN(LOG_COMPORT, "Com-port %d listen for IPv%c failed %s\n", port, ipchar, strerror(errno));
216 olsr_com_parse_request(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
217 struct comport_connection *con;
218 struct sockaddr_storage addr;
221 #if !defined REMOVE_LOG_DEBUG
222 struct ipaddr_str buf;
225 addrlen = sizeof(addr);
226 sock = accept(fd, (struct sockaddr *) &addr, &addrlen);
231 con = olsr_cookie_malloc(connection_cookie);
232 abuf_init(&con->in, 1024);
233 abuf_init(&con->out, 0);
235 con->is_http = fd == comsocket_http;
238 if (olsr_cnf->ip_version == AF_INET6) {
239 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr;
240 con->addr.v6 = addr6->sin6_addr;
242 struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr;
243 con->addr.v4 = addr4->sin_addr;
247 if (connection_http_count < olsr_cnf->comport_http_limit) {
248 connection_http_count++;
249 con->state = HTTP_LOGIN;
250 con->send_as = PLAIN;
251 con->timeout_value = HTTP_TIMEOUT;
253 con->state = SEND_AND_QUIT;
254 con->send_as = HTTP_503_SERVICE_UNAVAILABLE;
256 } else { /* !con->is_http */
257 if (connection_txt_count < olsr_cnf->comport_txt_limit) {
258 connection_txt_count++;
259 con->state = INTERACTIVE;
260 con->send_as = PLAIN;
261 con->timeout_value = TXT_TIMEOUT;
263 abuf_puts(&con->out, "Too many txt connections, sorry...\n");
264 con->state = SEND_AND_QUIT;
265 con->send_as = PLAIN;
269 OLSR_DEBUG(LOG_COMPORT, "Got connection through socket %d from %s.\n",
270 sock, olsr_ip_to_string(&buf, &con->addr));
272 con->timeout = olsr_start_timer(con->timeout_value, 0, con, connection_timeout);
274 add_olsr_socket(sock, &olsr_com_parse_connection, NULL, con, SP_PR_READ
277 list_add_after(&olsr_comport_head, &con->node);
281 olsr_com_cleanup_session(struct comport_connection *con) {
283 connection_http_count--;
285 connection_txt_count--;
288 list_remove(&con->node);
290 if (con->stop_handler) {
291 con->stop_handler(con);
293 remove_olsr_socket(con->fd, &olsr_com_parse_connection, NULL);
297 abuf_free(&con->out);
299 olsr_cookie_free(connection_cookie, con);
303 olsr_com_timeout_handler(void *data) {
304 struct comport_connection *con = data;
305 olsr_com_cleanup_session(con);
309 olsr_com_parse_connection(int fd, void *data, unsigned int flags) {
310 struct comport_connection *con = data;
311 #if !defined(REMOVE_LOG_WARN)
312 struct ipaddr_str buf;
315 OLSR_DEBUG(LOG_COMPORT, "Parsing connection of socket %d\n", fd);
316 /* read data if necessary */
317 if (flags & SP_PR_READ) {
321 len = recv(fd, buffer, sizeof(buffer), 0);
323 OLSR_DEBUG(LOG_COMPORT, " recv returned %d\n", len);
324 if (con->state != SEND_AND_QUIT) {
325 abuf_memcpy(&con->in, buffer, len);
328 if (con->in.len > COMPORT_MAX_INPUTBUFFER) {
329 if (con->state == INTERACTIVE) {
330 abuf_puts(&con->out, "Sorry, input buffer overflow...\n");
331 } else if (con->state == HTTP_LOGIN) {
332 con->send_as = HTTP_413_REQUEST_TOO_LARGE;
334 con->state = SEND_AND_QUIT;
336 } else if (len < 0) {
337 OLSR_WARN(LOG_COMPORT, "Error while reading from communication stream with %s: %s\n",
338 olsr_ip_to_string(&buf, &con->addr), strerror(errno));
339 con->state = CLEANUP;
342 con->state = SEND_AND_QUIT;
346 switch (con->state) {
348 olsr_com_parse_http(con, flags);
351 olsr_com_parse_txt(con, flags);
357 /* maybe we have to create an error message */
358 if (con->out.len == 0 && con->state == SEND_AND_QUIT && con->send_as != PLAIN
359 && con->send_as != HTTP_PLAIN && con->send_as != HTTP_200_OK) {
360 olsr_com_create_httperror(con);
363 /* send data if necessary */
364 if (con->out.len > 0) {
365 if (con->state == SEND_AND_QUIT && con->send_as != PLAIN) {
367 olsr_com_build_httpheader(con);
368 con->send_as = PLAIN;
371 if (flags & SP_PR_WRITE) {
374 len = send(fd, con->out.buf, con->out.len, 0);
376 OLSR_DEBUG(LOG_COMPORT, " send returned %d\n", len);
377 abuf_pull(&con->out, len);
378 } else if (len < 0) {
379 OLSR_WARN(LOG_COMPORT, "Error while writing to communication stream with %s: %s\n",
380 olsr_ip_to_string(&buf, &con->addr), strerror(errno));
381 con->state = CLEANUP;
384 OLSR_DEBUG(LOG_COMPORT, " activating output in scheduler\n");
385 enable_olsr_socket(fd, &olsr_com_parse_connection, NULL, SP_PR_WRITE);
388 if (con->out.len == 0) {
389 OLSR_DEBUG(LOG_COMPORT, " deactivating output in scheduler\n");
390 disable_olsr_socket(fd, &olsr_com_parse_connection, NULL, SP_PR_WRITE);
391 if (con->state == SEND_AND_QUIT) {
392 con->state = CLEANUP;
396 /* end of connection ? */
397 if (con->state == CLEANUP) {
398 OLSR_DEBUG(LOG_COMPORT, " cleanup\n");
399 /* clean up connection by calling timeout directly */
400 olsr_stop_timer(con->timeout);
402 olsr_com_cleanup_session(con);