00001
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <sys/time.h>
00040 #include <sys/ioctl.h>
00041 #include <netinet/in.h>
00042 #include <arpa/inet.h>
00043 #include <net/if.h>
00044 #include <syslog.h>
00045
00046 #include "mesh_metrics.h"
00047 #include "mesh_link.h"
00048 #include "mesh_discovery.h"
00049 #include "sensor_self.h"
00050 #include "sensor_mesh.h"
00051
00052
00053 #define MESH_METRICS 3
00054 static const char *mesh_metric_names[MESH_METRICS] =
00055 { "reliability", "goodput", "energy" };
00056
00057
00058 int metric_by_name(char *name)
00059 {
00060 int i;
00061 for (i = 0; i < MESH_METRICS; i++) {
00062 if (strcmp(name, mesh_metric_names[i]) == 0)
00063 break;
00064 }
00065 if (i >= MESH_METRICS)
00066 return -1;
00067 return i;
00068 }
00069
00070
00071
00072 void init_metrics(metric_t *metrics)
00073 {
00074 metrics->reliability = -1.0;
00075 metrics->goodput = -1.0;
00076 metrics->energy = -1.0;
00077 }
00078
00079
00080 double compile_mesh_metrics(protocol_t *proto, enum mesh_metric m,
00081 char *destination)
00082 {
00083 double data = 0.0;
00084 link_entry_t *entry = retrieve_entry(proto, ip_to_id(destination));
00085
00086 if (entry != NULL) {
00087 if (m == RELIABILITY)
00088 data = entry->metrics.reliability;
00089 else if (m == GOODPUT)
00090 data = entry->metrics.goodput;
00091 else if (m == ENERGY)
00092 data = entry->metrics.energy * entry->link.hop_count;
00093 }
00094 return data;
00095 }
00096
00097
00098
00099 int echo_statistics(self_t *self)
00100 {
00101 int sd, error, mtu = 1500;
00102 struct sockaddr_in my_addr, their_addr;
00103 struct ifreq ifr;
00104 socklen_t addr_len = sizeof(struct sockaddr);
00105
00106 if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
00107 syslog(LOG_ERR, "socket: %m");
00108 return sd;
00109 }
00110
00111 strcpy(ifr.ifr_name, self->interface);
00112 ifr.ifr_addr.sa_family = AF_INET;
00113 if (ioctl(sd, SIOCGIFMTU, &ifr) < 0)
00114 syslog(LOG_ERR, "net interface \"%s\" not found (%m)", self->interface);
00115 else
00116 mtu = ifr.ifr_mtu;
00117
00118 my_addr.sin_family = AF_INET;
00119 my_addr.sin_port = htons(MESH_METRICS_PORT+1);
00120 my_addr.sin_addr.s_addr = INADDR_ANY;
00121 memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
00122
00123 if ((error = bind(sd, (struct sockaddr*)&my_addr,
00124 sizeof(struct sockaddr))) < 0) {
00125 syslog(LOG_ERR, "bind: %m");
00126 return error;
00127 }
00128
00129 while (1) {
00130 int i, nbytes, total_bytes = 0;
00131 for (i = 0; i < MESH_METRICS_PACKETS; i++) {
00132 char buf[mtu];
00133
00134 if ((nbytes = timed_recv(sd, buf, mtu, &their_addr,
00135 MESH_METRICS_ROUND)) < 0) {
00136 if (nbytes == -2)
00137 break;
00138 if (nbytes == -1) {
00139 syslog(LOG_ERR, "timed_recv: %m");
00140 continue;
00141 }
00142 }
00143 total_bytes += nbytes;
00144 }
00145 if (i == 0 && nbytes == -2)
00146 continue;
00147 if (strcmp(self->ip_addr, inet_ntoa(their_addr.sin_addr)) == 0)
00148 continue;
00149
00150 #ifdef DEBUG_METRICS
00151 syslog(LOG_INFO, "echoing metrics measurement packets");
00152 #endif
00153 if (sendto(sd, &nbytes, sizeof(int), 0,
00154 (struct sockaddr*)&their_addr, addr_len) < 0)
00155 syslog(LOG_ERR, "sendto: %m");
00156 }
00157 return 0;
00158 }
00159
00160
00161 static void time_difference(struct timeval *ans, struct timeval *larger,
00162 struct timeval *smaller)
00163 {
00164 ans->tv_sec = larger->tv_sec - smaller->tv_sec;
00165 ans->tv_usec = larger->tv_usec - smaller->tv_usec;
00166 if (ans->tv_usec < 0) {
00167 ans->tv_sec--;
00168 ans->tv_usec = 1000000 + ans->tv_usec;
00169 }
00170 }
00171
00172
00173
00174 int gather_statistics(self_t *self)
00175 {
00176 int sd, mtu = 1500;
00177 int error, yes = 1, ttl = 1;
00178 struct ifreq ifr;
00179 struct timeval now;
00180 struct sockaddr_in my_addr;
00181
00182 gettimeofday(&now, NULL);
00183 srand(now.tv_usec);
00184
00185 if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
00186 syslog(LOG_ERR, "socket: %m");
00187 return sd;
00188 }
00189
00190 strcpy(ifr.ifr_name, self->interface);
00191 ifr.ifr_addr.sa_family = AF_INET;
00192 if (ioctl(sd, SIOCGIFMTU, &ifr) < 0)
00193 syslog(LOG_ERR, "net interface \"%s\" not found (%m)", self->interface);
00194 else
00195 mtu = ifr.ifr_mtu;
00196
00197 if ((error = setsockopt(sd, SOL_SOCKET, SO_BROADCAST,
00198 &yes, sizeof(int))) < 0) {
00199 syslog(LOG_ERR, "setsockopt (BROADCAST): %m");
00200 close(sd);
00201 return error;
00202 }
00203
00204 if ((error = setsockopt(sd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int))) < 0) {
00205 syslog(LOG_ERR, "setsockopt (IP_TTL): %m");
00206 close(sd);
00207 return error;
00208 }
00209
00210 my_addr.sin_family = AF_INET;
00211 my_addr.sin_port = htons(MESH_METRICS_PORT);
00212 my_addr.sin_addr.s_addr = INADDR_ANY;
00213 memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
00214
00215 if ((error = bind(sd, (struct sockaddr*)&my_addr,
00216 sizeof(struct sockaddr))) < 0) {
00217 syslog(LOG_ERR, "bind: %m");
00218 return error;
00219 }
00220
00221 while (1) {
00222 struct timeval begin, middle, end, offset, elapsed;
00223 int i, nbytes = 0, bytes_sent = 0, bytes_thru = 0;
00224 double amps_begin = 0.0, amps_end = 0.0, seconds_passed;
00225 int rand_offset = (int) ((double)(MESH_METRICS_INTERVAL / 2) *
00226 (rand() / (double)RAND_MAX));
00227 link_entry_t *entry;
00228 char packet[mtu];
00229 struct sockaddr_in their_addr;
00230 socklen_t addr_len = sizeof(struct sockaddr);
00231 protocol_t *proto = self->protocols;
00232
00233 memset(&begin, 0, sizeof(struct timeval));
00234 memset(&middle, 0, sizeof(struct timeval));
00235 memset(&end, 0, sizeof(struct timeval));
00236 memset(&offset, 0, sizeof(struct timeval));
00237 memset(&elapsed, 0, sizeof(struct timeval));
00238
00239 their_addr.sin_family = AF_INET;
00240 their_addr.sin_port = htons(MESH_METRICS_PORT+1);
00241 their_addr.sin_addr.s_addr = INADDR_ANY;
00242 memset(their_addr.sin_zero, 0, sizeof(their_addr.sin_zero));
00243
00244 #ifdef DEBUG_METRICS
00245 syslog(LOG_INFO, "metrics interval: %d (%d)",
00246 MESH_METRICS_INTERVAL + rand_offset,
00247 (MESH_METRICS_INTERVAL / 2) - rand_offset);
00248 #endif
00249 sleep(MESH_METRICS_INTERVAL + rand_offset);
00250
00251 while (proto != NULL) {
00252 #ifdef DEBUG_METRICS
00253 syslog(LOG_INFO, "sending metrics measurement packets");
00254 #endif
00255 gettimeofday(&begin, NULL);
00256 if (self->battery_enabled)
00257 amps_begin = get_discharge_rate(self);
00258 for (i = 0; i < MESH_METRICS_PACKETS; i++) {
00259 if ((nbytes = sendto(sd, packet, mtu, 0,
00260 (struct sockaddr*)&their_addr, addr_len)) < 0) {
00261 syslog(LOG_ERR, "sendto: %m");
00262 continue;
00263 }
00264 bytes_sent += nbytes;
00265 }
00266 if (self->battery_enabled)
00267 amps_end = get_discharge_rate(self);
00268
00269 #ifdef DEBUG_METRICS
00270 syslog(LOG_INFO, "recving metrics packet ACKs");
00271 #endif
00272 while (1) {
00273 if ((nbytes = timed_recv(sd, &bytes_thru, sizeof(int), &their_addr,
00274 MESH_METRICS_ROUND)) < 0) {
00275 if (nbytes == -2)
00276 break;
00277 if (nbytes == -1) {
00278 syslog(LOG_ERR, "timed_recv: %m");
00279 continue;
00280 }
00281 }
00282
00283 gettimeofday(&middle, NULL);
00284 entry = retrieve_entry(proto,
00285 ip_to_id(inet_ntoa(their_addr.sin_addr)));
00286 if (entry == NULL)
00287 continue;
00288
00289 if (entry->metrics.reliability < 0.0)
00290 entry->metrics.reliability = (double)bytes_thru / (double)bytes_sent;
00291 else
00292 entry->metrics.reliability = (((double)bytes_thru / (double)bytes_sent)
00293 + entry->metrics.reliability) / 2;
00294 time_difference(&offset, &middle, &end);
00295 time_difference(&elapsed, &middle, &begin);
00296 time_difference(&elapsed, &elapsed, &offset);
00297 seconds_passed = (double) elapsed.tv_sec;
00298 seconds_passed += elapsed.tv_usec / 1000000.0;
00299 if (entry->metrics.goodput < 0.0)
00300 entry->metrics.goodput = (double)bytes_thru / seconds_passed;
00301 else
00302 entry->metrics.goodput = (((double)bytes_thru / seconds_passed)
00303 + entry->metrics.goodput) / 2;
00304 if (entry->metrics.energy < 0.0)
00305 entry->metrics.energy = amps_end - amps_begin;
00306 else
00307 entry->metrics.energy = (amps_end - amps_begin +
00308 entry->metrics.energy) / 2;
00309 gettimeofday(&end, NULL);
00310 }
00311 proto = proto->next;
00312 }
00313 sleep((MESH_METRICS_INTERVAL / 2) - rand_offset);
00314 }
00315 return 0;
00316 }