00001
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define _minisoap_impl_
00036 #define _GNU_SOURCE
00037
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <ctype.h>
00042 #include <errno.h>
00043 #include <string.h>
00044 #include <netdb.h>
00045 #include <sys/time.h>
00046 #include <sys/types.h>
00047 #include <sys/socket.h>
00048 #include <sys/select.h>
00049 #include <math.h>
00050 #include <netinet/in.h>
00051 #include <arpa/inet.h>
00052 #include <netinet/ether.h>
00053 #include <net/if.h>
00054 #include <sys/ioctl.h>
00055 #include <asm/types.h>
00056 #include <linux/netlink.h>
00057 #include <linux/rtnetlink.h>
00058 #include <pthread.h>
00059 #include <errno.h>
00060 #include <zlib.h>
00061 #include "minisoap.h"
00062 #include "sensor_ipc.h"
00063
00064
00065 #define CONN_BACKLOG 10
00066 #define ESOAPCLIENT 8359
00067 #define MAX_NEIGHBORS 128
00068 #define DISCOVERY_PORT 8359
00069
00070
00071 char my_ip_addr[NET_ADDR_LEN];
00072 pthread_t soap_thread, local_thread;
00073
00074 static pthread_mutex_t xml_mutex;
00075 static unsigned int initialized;
00076
00077
00078
00079
00080
00081
00082 #define BUFSIZE 8192
00083
00084 struct route_info {
00085 unsigned int dest;
00086 unsigned int src;
00087 unsigned int gateway;
00088 char if_name[IF_NAMESIZE];
00089 };
00090
00091
00092 static int read_nl_sock(int sock, char *buf, int seq_num, int pid){
00093 struct nlmsghdr *nl_hdr;
00094 int read_len = 0, msg_len = 0;
00095
00096
00097 do{
00098 if ((read_len = recv(sock, buf, BUFSIZE - msg_len, 0)) < 0){
00099 perror("recv");
00100 return -1;
00101 }
00102
00103 nl_hdr = (struct nlmsghdr*)buf;
00104
00105 if ((NLMSG_OK(nl_hdr, read_len) == 0) ||
00106 (nl_hdr->nlmsg_type == NLMSG_ERROR)) {
00107 perror("netlink msg error");
00108 return -1;
00109 }
00110 if (nl_hdr->nlmsg_type == NLMSG_DONE)
00111 break;
00112
00113 buf += read_len;
00114 msg_len += read_len;
00115
00116 if ((nl_hdr->nlmsg_flags & NLM_F_MULTI) == 0)
00117 break;
00118 } while ((nl_hdr->nlmsg_seq != seq_num) || (nl_hdr->nlmsg_pid != pid));
00119 return msg_len;
00120 }
00121
00122
00123 static void parse_routes(struct nlmsghdr *nl_hdr, struct route_info *rt_info,
00124 ip_addr_t gateway)
00125 {
00126 int rt_len;
00127 struct in_addr dest, gw;
00128 struct rtattr *rt_attr;
00129 struct rtmsg *rt_msg = (struct rtmsg*)NLMSG_DATA(nl_hdr);
00130
00131 if (rt_msg->rtm_family != AF_INET ||
00132 rt_msg->rtm_table != RT_TABLE_MAIN)
00133 return;
00134
00135 rt_attr = (struct rtattr*)RTM_RTA(rt_msg);
00136 rt_len = RTM_PAYLOAD(nl_hdr);
00137 for ( ; RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len)) {
00138 switch(rt_attr->rta_type) {
00139 case RTA_OIF:
00140 if_indextoname(*(int*)RTA_DATA(rt_attr),
00141 rt_info->if_name);
00142 break;
00143 case RTA_GATEWAY:
00144 rt_info->gateway = *(unsigned int*)RTA_DATA(rt_attr);
00145 break;
00146 case RTA_PREFSRC:
00147 rt_info->src = *(unsigned int*)RTA_DATA(rt_attr);
00148 break;
00149 case RTA_DST:
00150 rt_info->dest = *(unsigned int*)RTA_DATA(rt_attr);
00151 break;
00152 }
00153 }
00154
00155 dest.s_addr = rt_info->dest;
00156 gw.s_addr = rt_info->gateway;
00157 if (strstr(inet_ntoa(dest), "0.0.0.0") != NULL)
00158 sprintf(gateway.addr, inet_ntoa(gw));
00159
00160 return;
00161 }
00162
00163
00164 int get_gateways(ip_addr_t gateways[], unsigned int size)
00165 {
00166 int i = 0, error = 0;
00167 struct nlmsghdr *nl_msg;
00168 struct rtmsg *rt_msg;
00169 struct route_info rt_info;
00170 char msg[BUFSIZE];
00171 int sock, len, msg_seq = 0;
00172
00173 memset(gateways, '\0', sizeof(ip_addr_t) * size);
00174
00175 if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
00176 perror("socket");
00177
00178 memset(msg, 0, BUFSIZE);
00179 nl_msg = (struct nlmsghdr *)msg;
00180 rt_msg = (struct rtmsg *)NLMSG_DATA(nl_msg);
00181
00182 nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
00183 nl_msg->nlmsg_type = RTM_GETROUTE;
00184 nl_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
00185 nl_msg->nlmsg_seq = msg_seq++;
00186 nl_msg->nlmsg_pid = getpid();
00187
00188 if ((error = send(sock, nl_msg, nl_msg->nlmsg_len, 0)) < 0){
00189 perror("send");
00190 return error;
00191 }
00192
00193 if ((len = read_nl_sock(sock, msg, msg_seq, getpid())) < 0) {
00194 printf("Read From Socket Failed...\n");
00195 return -1;
00196 }
00197
00198 for (i = 0; NLMSG_OK(nl_msg, len) && i < size;
00199 nl_msg = NLMSG_NEXT(nl_msg, len)){
00200 memset(&rt_info, 0, sizeof(struct route_info));
00201 parse_routes(nl_msg, &rt_info, gateways[i]);
00202 if (strcmp(gateways[i].addr, "") != 0)
00203 i++;
00204 }
00205
00206 close(sock);
00207 return 0;
00208 }
00209
00210
00211
00212
00213 static int parse_soap_event(SoapEvent *evt, char *msg, int msg_len)
00214 {
00215 long string_len;
00216 int error = 0;
00217 char *token, *end, *string;
00218 char content_type[128], content_encoding[128] = "";
00219
00220
00221 if (msg == NULL || evt == NULL)
00222 return -ESOAPCLIENT;
00223
00224
00225 if ((token = strcasestr(msg, "Content-Type")) == NULL)
00226 return -ESOAPCLIENT;
00227 token += 12;
00228 if (sscanf(token, ": %s", content_type) < 1)
00229 return -ESOAPCLIENT;
00230
00231 if ((token = strcasestr(msg, "Content-Length")) == NULL)
00232 return -ESOAPCLIENT;
00233 token += 14;
00234 if (sscanf(token, ": %ld", &string_len) < 1)
00235 return -ESOAPCLIENT;
00236
00237 if ((token = strcasestr(msg, "Content-Encoding")) != NULL) {
00238 token += 16;
00239 sscanf(token, ": %s", content_encoding);
00240 }
00241
00242 if ((end = strstr(msg, "\n\n")) == NULL)
00243 return -ESOAPCLIENT;
00244 end += 2;
00245 msg_len -= end - msg;
00246
00247 if ((strncmp(content_type, "application/soap+xml", 20) == 0 &&
00248 (strncmp(content_encoding, "gzip", 4) ||
00249 strncmp(content_encoding, "x-gzip", 6))) ||
00250 strncmp(content_type, "application/x-gzip", 18) == 0 ||
00251 strncmp(content_type, "application/gzip", 16) == 0 ||
00252 strncmp(content_type, "application/octet-stream", 24) == 0) {
00253 string_len++;
00254 string = (char*) malloc(string_len);
00255 if ((error = uncompress(string, &string_len, end,
00256 (long)msg_len)) < 0)
00257 return error;
00258 string[string_len] = '\0';
00259 } else
00260 string = end;
00261
00262 error = string_SoapEvent(string, evt);
00263
00264 #ifdef DEBUG
00265 if (error >= 0)
00266 fprintf(stderr, "constructed evt:\n\tfrom: %s\n\tto: %s\n"
00267 "\ttype: %d\n\tapp: %s\n\ttime: %ls %ls\n"
00268 "\tbody: %s\n\n",
00269 evt->from, evt->to, evt->type, evt->app,
00270 evt->time.sec, evt->time.usec evt->msg);
00271 #endif
00272 return error;
00273 }
00274
00275
00276 static void *soap_server(void *command_callback)
00277 {
00278 int listen_fd, handle_fd, yes = 1;
00279 struct sockaddr_in my_addr, their_addr;
00280 socklen_t sin_size = sizeof(struct sockaddr_in);
00281
00282 listen_socket:
00283 if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
00284 perror("minisoap: listening socket");
00285 exit(-1);
00286 }
00287
00288 if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
00289 &yes, sizeof(int)) == -1) {
00290 perror("minisoap: setsockopt (REUSEADDR)");
00291 exit(-1);
00292 }
00293
00294 my_addr.sin_family = AF_INET;
00295 my_addr.sin_port = htons(DEFAULT_MINISOAP_PORT);
00296 my_addr.sin_addr.s_addr = INADDR_ANY;
00297 memset(&(my_addr.sin_zero), '\0', 8);
00298
00299 if (bind(listen_fd, (struct sockaddr *) &my_addr,
00300 sizeof(struct sockaddr)) == -1) {
00301 perror("minisoap: bind");
00302 exit(-1);
00303 }
00304
00305 if (listen(listen_fd, CONN_BACKLOG) == -1) {
00306 perror("minisoap: listen");
00307 exit(-1);
00308 }
00309
00310 while (!quitting()) {
00311 SoapEvent evt;
00312 int error = 0;
00313 int num_bytes = 0;
00314 unsigned int req_len = MAX_EVENT_LEN;
00315 unsigned int cur_len = 0;
00316 char last = '\0';
00317 char request[req_len + 1];
00318 char *response = "HTTP/1.1 200 OK\n\n";
00319 char *server_error = "HTTP/1.1 500 Server Error\n\n";
00320 char *client_error = "HTTP/1.1 400 Bad Request\n\n";
00321
00322 if ((handle_fd = accept(listen_fd,
00323 (struct sockaddr *) &their_addr,
00324 &sin_size)) == -1) {
00325 perror("minisoap: accept");
00326 close(listen_fd);
00327 sleep(15);
00328 goto listen_socket;
00329 }
00330
00331 #ifdef DEBUG
00332 fprintf(stderr, "minisoap: Server connection opened...\n");
00333 #endif
00334
00335 do {
00336 char buf = 0;
00337 if ((num_bytes = recv(handle_fd, &buf, 1, 0)) == -1) {
00338 perror("minisoap: recv");
00339 send(handle_fd, server_error,
00340 strlen(server_error), 0);
00341 close(handle_fd);
00342 error = 1;
00343 break;
00344 }
00345 if (buf == 0 && last == 64) {
00346 request[cur_len-1] = '\0';
00347 break;
00348 }
00349 if ((isprint(buf) || buf == '\n') &&
00350 cur_len < req_len) {
00351 request[cur_len] = buf;
00352 cur_len ++;
00353 }
00354 last = buf;
00355 } while (num_bytes != 0);
00356 if (error)
00357 continue;
00358
00359 error = parse_soap_event(&evt, request, cur_len);
00360 if (error == -ESOAPCLIENT) {
00361 send(handle_fd, client_error, strlen(client_error), 0);
00362 close(handle_fd);
00363 continue;
00364 } else {
00365 fprintf(stderr, "minisoap: Error in SoapEvent: %s\n",
00366 strerror(error));
00367 send(handle_fd, server_error, strlen(server_error), 0);
00368 close(handle_fd);
00369 continue;
00370 }
00371
00372 if (send(handle_fd, response, strlen(response), 0) == -1) {
00373 perror("minisoap: send");
00374 close(handle_fd);
00375 continue;
00376 }
00377 close(handle_fd);
00378
00379 pthread_mutex_lock(&xml_mutex);
00380 ((cmd_callback_t)command_callback)(&evt);
00381 pthread_mutex_unlock(&xml_mutex);
00382 }
00383 close(listen_fd);
00384 pthread_exit(NULL);
00385 }
00386
00387
00388
00389
00390
00391 static void *local_server(void *unused)
00392 {
00393 int fd, port_in;
00394 struct sockaddr_in their_addr;
00395 socklen_t addr_len = sizeof(struct sockaddr);
00396
00397 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
00398 perror("minisoap: socket");
00399 return NULL;
00400 }
00401
00402 while (!quitting()) {
00403 if (recvfrom(fd, &port_in, sizeof(port_in), 0,
00404 (struct sockaddr*)&their_addr, &addr_len) < 0) {
00405 perror("minisoap: recvfrom");
00406 continue;
00407 }
00408 if (port_in > 0) {
00409 if (sendto(fd, &port_in, sizeof(port_in), 0,
00410 (struct sockaddr*)&their_addr,
00411 addr_len) < 0)
00412 perror("minisoap:sendto");
00413 }
00414 }
00415 return NULL;
00416 }
00417
00418
00419 int register_soap_handler(cmd_callback_t handler)
00420 {
00421 int error = 0;
00422
00423 if (!initialized) {
00424
00425
00426
00427 pthread_mutex_init(&xml_mutex, NULL);
00428 if ((error = pthread_create(&soap_thread, NULL, &soap_server,
00429 (void*)handler)) < 0)
00430 return error;
00431 if ((error = pthread_create(&local_thread, NULL, &local_server,
00432 NULL)) < 0)
00433 return error;
00434 initialized++;
00435 }
00436 return error;
00437 }
00438
00439
00440 int raise_soap_event(SoapEvent *evt, char *server, int port)
00441 {
00442 int error = 0;
00443 int connect_fd, yes = 1;
00444 struct hostent *he;
00445 struct sockaddr_in their_addr;
00446 long body_z_len = MAX_EVENT_LEN + (MAX_EVENT_LEN * .02) + 13;
00447 int msg_size = 150 + strlen(server) + body_z_len;
00448 char body[MAX_EVENT_LEN + 1];
00449 char body_z[body_z_len];
00450 char msg[msg_size + 1];
00451
00452 gettimeofday(&evt->time, NULL);
00453 if ((error = SoapEvent_string(evt, body, MAX_EVENT_LEN)) < 0)
00454 return error;
00455
00456 if ((he = gethostbyname(server)) == NULL) {
00457 char err[128];
00458 sprintf(err, "minisoap: gethostbyname (%s)", server);
00459 herror(err);
00460 return -1;
00461 }
00462
00463 if ((connect_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
00464 perror("minisoap: socket");
00465 return connect_fd;
00466 }
00467
00468 if ((error = setsockopt(connect_fd, SOL_SOCKET, SO_REUSEADDR,
00469 &yes, sizeof(int))) == -1) {
00470 perror("minisoap: setsockopt (REUSEADDR)");
00471 close(connect_fd);
00472 return error;
00473 }
00474
00475 their_addr.sin_family = AF_INET;
00476 their_addr.sin_port = htons(port);
00477 their_addr.sin_addr = *((struct in_addr *)he->h_addr);
00478 memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));
00479
00480 if ((error = connect(connect_fd, (struct sockaddr *)&their_addr,
00481 sizeof(struct sockaddr))) == -1) {
00482 perror("minisoap: connect");
00483 close(connect_fd);
00484 return error;
00485 }
00486
00487 if ((error = compress(body_z, &body_z_len, body,
00488 (long)(strlen(body) + 1))) < 0)
00489 return error;
00490
00491 snprintf(msg, msg_size,
00492 "POST /miniSoap.cgi HTTP/1.1\n"
00493 "Host: %s\n"
00494 "Content-Type: application/soap+xml\n"
00495 "Content-Encoding: gzip\n"
00496 "Content-Length: %ld\n\n%s",
00497 server, body_z_len, body_z);
00498
00499 #ifdef DEBUG
00500 fprintf(stderr, "minisoap: transmitting \"%s\"\n", msg);
00501 #endif
00502
00503 if ((error = send(connect_fd, msg, strlen(msg), 0)) < 0) {
00504 perror("minisoap: send");
00505 }
00506 close(connect_fd);
00507 return error;
00508 }
00509
00510
00511 static int discover_neighbors(ip_addr_t list[], int list_size)
00512 {
00513 int fd, error, i = 0;
00514 int yes = 1, ttl = 1, port = 1;
00515 fd_set recv_fd;
00516 struct timeval timeout;
00517 struct sockaddr_in their_addr;
00518
00519 memset(list, '\0', sizeof(ip_addr_t) * list_size);
00520
00521 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
00522 perror("minisoap: socket");
00523 return fd;
00524 }
00525
00526 if ((error = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
00527 &yes, sizeof(int))) == -1) {
00528 perror("minisoap: setsockopt (BROADCAST)");
00529 close(fd);
00530 return error;
00531 }
00532
00533 if ((error = setsockopt(fd, IPPROTO_IP, IP_TTL,
00534 &ttl, sizeof(int))) == -1) {
00535 perror("minisoap: setsockopt (IP_TTL)");
00536 close(fd);
00537 return error;
00538 }
00539
00540 their_addr.sin_family = AF_INET;
00541 their_addr.sin_port = htons(DISCOVERY_PORT);
00542 their_addr.sin_addr.s_addr = inet_addr("255.255.255.255");
00543 memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));
00544
00545 if ((error = sendto(fd, &port, sizeof(port), 0,
00546 (struct sockaddr*)&their_addr,
00547 sizeof(struct sockaddr))) < 0) {
00548 perror("minisoap: sendto");
00549 close(fd);
00550 return error;
00551 }
00552
00553
00554 timeout.tv_sec = 3;
00555 timeout.tv_usec = 0;
00556 FD_ZERO(&recv_fd);
00557 FD_SET(fd, &recv_fd);
00558
00559 for (i = 0; i < list_size;) {
00560 int port_in = -1;
00561 socklen_t addr_len = sizeof(struct sockaddr);
00562 memset(&their_addr, '\0', sizeof(their_addr));
00563
00564 select(fd+1, &recv_fd, NULL, NULL, &timeout);
00565 if (FD_ISSET(fd, &recv_fd)) {
00566 if (recvfrom(fd, &port_in, sizeof(port_in), 0,
00567 (struct sockaddr*)&their_addr,
00568 &addr_len) < 0) {
00569 if (errno == EAGAIN)
00570 break;
00571 else
00572 perror("minisoap: recvfrom");
00573 } else {
00574 if (port_in == port)
00575 strncpy(list[i++].addr,
00576 inet_ntoa(their_addr.sin_addr),
00577 NET_ADDR_LEN);
00578 }
00579 }
00580 }
00581 close(fd);
00582 return i;
00583 }
00584
00585
00586 int raise_local_query(SoapEvent *evt, int port)
00587 {
00588 ip_addr_t neighbor_list[MAX_NEIGHBORS];
00589 int i, num_neighbors = discover_neighbors(neighbor_list, MAX_NEIGHBORS);
00590
00591 for (i = 0; i < num_neighbors; i++)
00592 raise_soap_event(evt, neighbor_list[i].addr, port);
00593
00594 return 0;
00595 }