N-sim
Emulation and simulation of
Wireless Sensor Networks



   Home


   Project Page


   Download


   CVS



   Installation


   Configuration


   Plug-ins




 Hosted by
SourceForge.net Logo

/home/brennan/n-sim/Vaike/linux/system-addons/system/soap/minisoap.c

Go to the documentation of this file.
00001 
00014 /*
00015  * Copyright 2007. Los Alamos National Security, LLC. This material
00016  * was produced under U.S. Government contract DE-AC52-06NA25396 for
00017  * Los Alamos National Laboratory (LANL), which is operated by Los
00018  * Alamos National Security, LLC, for the Department of Energy. The
00019  * U.S. Government has rights to use, reproduce, and distribute this
00020  * software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY,
00021  * LLC, MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL
00022  * LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to
00023  * produce derivative works, such modified software should be clearly
00024  * marked, so as not to confuse it with the version available from LANL.
00025  *
00026  * Additionally, this program is free software; you can redistribute
00027  * it and/or modify it under the terms of the GNU General Public
00028  * License as published by the Free Software Foundation; version 2 of
00029  * the License. Accordingly, this program is distributed in the hope
00030  * it will be useful, but WITHOUT ANY WARRANTY; without even the
00031  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00032  * PURPOSE. See the GNU General Public License for more details.
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 /* find gateway */
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         /* increment through netlink messages to find desired data */
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         /* extract header */
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);  /* allow bind to timeout */
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) {  /* weird windows EOF */
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);  /* EOF */
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                 /* my_ip_addr initialized elsewhere */
00425 
00426                 // FIXME: error handling
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;  // FIXME: what do we send ?
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         /* set timeout */
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 }


© 2007, Los Alamos National Security, LLC.