dyn_iwspy_rec.c

Go to the documentation of this file.
00001 /* $Id: dyn_iwspy_rec.c,v 1.13 2000/04/06 07:26:52 jm Exp $
00002  * Dynamics iwspy recorder module
00003  *
00004  * Dynamic hierarchial IP tunnel
00005  * Copyright (C) 1998-2000, Dynamics group
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License version 2 as
00009  * published by the Free Software Foundation. See README and COPYING for
00010  * more details.
00011  */
00012 
00013 #include <stdlib.h>
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <assert.h>
00017 #include <asm/types.h>
00018 #include <sys/types.h>
00019 #include <sys/socket.h>
00020 #include <sys/ioctl.h>
00021 #include <sys/socket.h>
00022 #include <arpa/inet.h>
00023 #include <netinet/in.h>
00024 #include <linux/wireless.h>
00025 
00026 #include "util.h"
00027 #include "hashtable.h"
00028 #include "dyn_iwspy_rec.h"
00029 #include "debug.h"
00030 
00031 #ifndef TRUE
00032 #define TRUE 1
00033 #endif
00034 
00035 #ifndef FALSE
00036 #define FALSE 0
00037 #endif
00038 
00039 #define DEBUG_FLAG '5'
00040 
00041 /* gnuplot headers */
00042 #define IMG_X 1000   /* single node image */
00043 #define IMG_Y 300
00044 #define G_IMG_X 1500 /* group node image */
00045 #define G_IMG_Y 400
00046 #define Q_RANGE 100  /* quality range: 0 - Q_RANGE */
00047 
00048 static struct hashtable *rec_hash;
00049 static int rec_num;
00050 struct timeval start_time;
00051 int new_dump = 1;
00052 
00053 
00054 static int hashfunc(void *key, const int hashsize)
00055 {
00056         __u8 hash;
00057         __u32 data;
00058 
00059         data = *((__u32 *) key); /* 32 least significant bytes 
00060                                    of the mac address */
00061 
00062         hash = (__u8)((data & 0xff000000) >> 24) ^
00063                 (__u8)((data & 0x00ff0000) >> 16) ^
00064                 (__u8)((data & 0x0000ff00) >> 8) ^
00065                 (__u8)(data & 0x000000ff);
00066 
00067         return ((int) hash);
00068 }
00069 
00070 
00071 /*
00072  * Comparison function for hashtable
00073  *
00074  * Arguments:
00075  *  key        First data structure
00076  *  cmprd      Second data structure
00077  *
00078  * Return:
00079  *  0          Not equal
00080  *  1          Equal
00081  */
00082 static int cmpfunc(void *key, struct node *cmprd)
00083 {
00084         __u32 data1;
00085         struct hw_record *data2;
00086 
00087         if (key == NULL) {
00088                 DEBUG(DEBUG_FLAG, "rec, cmpfunc:\n"
00089                       "value for argument 'key' was NULL !\n"
00090                       "Illegal value, returning 0 ! \n");
00091                 return 0;
00092         }
00093         if (cmprd == NULL) {
00094                 DEBUG(DEBUG_FLAG, "rec, cmpfunc:\n"
00095                       "value for argument 'cmpd' was NULL !\n"
00096                       "Illegal value, returning 0 ! \n");
00097                 return 0;
00098         }
00099 
00100         data1 = *((__u32 *)key);
00101         data2 = (struct hw_record *) cmprd;
00102 
00103         /* Compare the 32 least significant bits of the mac address */
00104         if (!memcmp(&data1, &data2->hw[2], sizeof(__u32)))
00105                 return 1;
00106 
00107         return 0;
00108 }
00109 
00110 
00111 int rec_init(void)
00112 {
00113         /* initialize hash */
00114         rec_num = 0;
00115         rec_hash = NULL;
00116         rec_hash = hashtable_init(REC_HASH_SIZE);
00117         if (rec_hash == NULL)
00118                 return -1;
00119         
00120         return 0;
00121 }
00122 
00123 
00124 int rec_clean(struct node *node, void *data)
00125 {
00126         struct hw_record *entry = (struct hw_record *) node;
00127         struct qual_entry *list = entry->quals;
00128         struct qual_entry *tmp;
00129 
00130         DEBUG(DEBUG_FLAG, "rec_clean\n");
00131         while (list != NULL) {
00132                 tmp = list;
00133                 list = list->next;
00134                 free(tmp);
00135         }
00136         hashtable_remove(node);
00137         free(entry);
00138         new_dump = 1;
00139         
00140         return 1;
00141 }
00142 
00143 
00144 void rec_clean_up(void)
00145 {
00146         DEBUG(DEBUG_FLAG, "rec_clean_up\n");
00147         if (rec_hash == NULL)
00148                 return;
00149         hashtable_iterator(rec_hash, rec_clean, NULL);
00150         hashtable_destroy(rec_hash);
00151         rec_hash = NULL;
00152 }
00153 
00154 
00155 static struct qual_entry *alloc_qual_entry(void)
00156 {
00157         struct qual_entry *qual;
00158 
00159         qual = (struct qual_entry *)
00160                 malloc(sizeof(struct qual_entry));
00161         if (!qual) {
00162                 DEBUG(DEBUG_FLAG, "alloc_qual_entry: malloc failed\n");
00163                 return NULL;
00164         }
00165         memset(qual, 0, sizeof(struct qual_entry));
00166 
00167         return qual;
00168 }
00169 
00170 
00171 /* Add new quals node to old mac entry */
00172 static int qual_add(struct hw_record *rec, 
00173                     struct iw_quality *qual,
00174                     struct timeval *t)
00175 {
00176         struct qual_entry *entry;
00177         unsigned int c;
00178 
00179         if (!rec->quals) {      /* first qual entry? */
00180                 rec->quals = alloc_qual_entry();
00181                 if (!rec->quals) {
00182                         DEBUG(DEBUG_FLAG, "qual_add:"
00183                               "alloc_qual_entry failed\n");
00184                         return -1;
00185                 }
00186                 rec->tail = rec->quals;
00187         } else if (rec->tail->current >= REC_NODE_CHUNK) {
00188                 DEBUG(DEBUG_FLAG, "qual_add: New CHUNK\n");
00189                 /* time to allocate one chunk more */
00190                 rec->tail->next = (struct qual_entry *)
00191                         malloc(sizeof(struct qual_entry));
00192                 if (!rec->tail->next) {
00193                         DEBUG(DEBUG_FLAG, "qual_add:"
00194                               " malloc failed\n");
00195                         return -1;
00196                 }
00197                 rec->tail = rec->tail->next;
00198                 memset(rec->tail, 0, sizeof(struct qual_entry));
00199         }
00200 
00201         entry = rec->tail;
00202         c = entry->current;
00203 
00204         assert(c >= 0 && c <= REC_NODE_CHUNK);
00205         /* vector structure */
00206         if (qual->qual > 200)
00207                 entry->qual[c].qual = 0;
00208         else
00209                 entry->qual[c].qual = qual->qual;
00210         entry->qual[c].level = qual->level;
00211         entry->qual[c].noise = qual->noise;
00212         entry->tstamp[c].tv_sec = t->tv_sec;
00213         entry->tstamp[c].tv_usec = t->tv_usec;
00214         entry->current++;
00215         
00216         DEBUG(DEBUG_FLAG, "qual_add: %s - %d\n", 
00217               inet_ntoa(rec->ip_addr), entry->current);
00218 
00219         return 0;
00220 }
00221 
00222 
00223 int rec_add_qual(char *hw, struct iw_quality *qual, struct timeval *tstamp)
00224 {
00225         struct hw_record *recs;
00226         int ret;
00227 
00228         assert(rec_hash != NULL);
00229         recs = (struct hw_record *) 
00230                 hashtable_fetch(rec_hash, hashfunc, &hw[2], cmpfunc);
00231 
00232         if (!recs) {
00233                 DEBUG(DEBUG_FLAG, "rec_add_qual: record not found!\n");
00234                 return 1;
00235         }
00236 
00237         ret = qual_add(recs, qual, tstamp);
00238         if (ret < 0)
00239                 DEBUG(DEBUG_FLAG, "rec_add_qual: qual entry add failed\n");
00240 
00241         return ret;
00242 }
00243 
00244 
00245 int rec_add(char *hw, struct iw_quality *qual, struct timeval *t,
00246             struct in_addr addr) 
00247 {
00248         struct hw_record *recs;
00249         int ret;
00250 
00251         if (new_dump) {
00252                 new_dump = 0;
00253                 start_time.tv_sec = t->tv_sec;
00254                 start_time.tv_usec = t->tv_usec;
00255                 DEBUG(DEBUG_FLAG, "rec_add: start time %ld\n",
00256                       start_time.tv_sec);
00257         }
00258 
00259         assert(rec_hash != NULL);
00260         recs = (struct hw_record *) 
00261                 hashtable_fetch(rec_hash, hashfunc, &hw[2], 
00262                                 cmpfunc);
00263 
00264         if (recs) {
00265                 /* old mac found. Add to that */
00266                 ret = qual_add(recs, qual, t);
00267                 if (ret < 0)
00268                         DEBUG(DEBUG_FLAG, "rec_add: qual entry add failed "
00269                               "(old mac)\n");
00270                 return ret;
00271         }
00272 
00273         /* mac not found. Add new one */
00274         recs = (struct hw_record *) malloc(sizeof(struct hw_record));
00275         if (!recs) {
00276                 DEBUG(DEBUG_FLAG, "rec_add: malloc failed\n");
00277                 /* FIX: Add record dumping into files and free
00278                    memory. Then initialize new list and continue
00279                    recording. */
00280                 return -1;
00281         }
00282         memcpy(recs->hw, hw, ETH_ALEN);
00283         recs->ip_addr.s_addr = addr.s_addr;
00284         recs->quals = NULL;
00285         recs->tail = recs->quals;
00286 
00287         /* Add mac entry */
00288         list_init_node(&recs->hashnode);
00289         ret = hashtable_add(rec_hash, hashfunc, &hw[2], &recs->hashnode);
00290         if (ret != TRUE) {
00291                 DEBUG(DEBUG_FLAG, "rec_add: hashtable_add failed\n");
00292                 return -1;
00293         }
00294         rec_num++;
00295 
00296         /* Add new qual node to the mac entry */
00297         ret = qual_add(recs, qual, t);
00298         if (ret < 0) {
00299                 DEBUG(DEBUG_FLAG, "rec_add: qual entry add "
00300                       "failed (new mac)\n");
00301                 return -1;
00302         }
00303 
00304         return ret;
00305 }
00306 
00307 
00308 int rec_add_long(struct sockaddr *hwa, unsigned char *hw,
00309                  struct in_addr addr, struct iw_quality *qual, 
00310                  struct timeval *t, int monitored)
00311 {
00312         int index = -1, i;
00313         
00314 
00315         DEBUG(DEBUG_FLAG, "rec_add_long (%s)\n",
00316               inet_ntoa(addr));
00317 
00318         for (i = 0 ; i < monitored; i++) {
00319                 if (!(memcmp(hwa[i].sa_data, hw, ETH_ALEN)))
00320                         index = i;
00321         }
00322         if (index < 0) {
00323                 DEBUG(DEBUG_FLAG, "rec_add: MAC address not found\n");
00324                 return -1;
00325         }
00326 
00327         return (rec_add((char *)&(hwa[index].sa_data), &qual[index], t, addr));
00328 }
00329 
00330 /**********************/
00331 /* Dump data to files */
00332 /**********************/
00333 
00334 
00335 static int dump_fa(struct node *node, void *data)
00336 {
00337         struct hw_record *rec = (struct hw_record *) node;
00338         struct qual_entry *qual = rec->quals;
00339         FILE *fd, *header;
00340         char name[FILENAME_MAX];
00341         unsigned int i, len;
00342         unsigned long range_sec = 0, range_dmsec = 0;
00343 #ifdef TEST
00344         unsigned long diff;
00345 #endif
00346         long range_usec = 0;
00347         struct dump *info = (struct dump *)data;
00348         
00349         /* open file */
00350         snprintf(name, FILENAME_MAX, "FA-%s-dump.dat",
00351                  inet_ntoa(rec->ip_addr));
00352         fd = fopen(name, "w");
00353         if (!fd) {
00354                 DEBUG(DEBUG_FLAG, "dump_fa: fopen: %s\n",
00355                       strerror(errno));
00356                 return -1;
00357         }
00358         
00359         /* Print filetype info */
00360         fprintf(fd, "# %d %d\n", info->interval, info->output_type);
00361         /* Printf addresses */
00362         fprintf(fd, "# %s %s\n", inet_ntoa(rec->ip_addr), 
00363                 ether_hwtoa((unsigned char *)rec->hw));
00364         i = 0;
00365         while (qual != NULL && i <= qual->current-1) {
00366                 /* write entry */
00367                 range_sec = qual->tstamp[i].tv_sec - start_time.tv_sec;
00368                 if (info->output_type == 1) { /* timestamp, seconds */
00369                         fprintf(fd, "%lu %u\n", range_sec, qual->qual[i].qual);
00370                 } else if (info->output_type == 2) { /* timestamp, 
00371                                                         dmsec, difference */
00372                         range_usec = qual->tstamp[i].tv_usec -
00373                                 start_time.tv_usec;
00374                         if (range_usec < 0) {
00375                                 range_sec--;
00376                                 range_usec += 1000000;
00377                         }
00378                         range_dmsec = range_sec * 100 + range_usec/10000;
00379 #ifdef TEST
00380                         if (i > 0) {
00381                                 diff = (qual->tstamp[i].tv_sec - 
00382                                         qual->tstamp[i-1].tv_sec) * 1000000 -
00383                                         qual->tstamp[i-1].tv_usec +
00384                                         qual->tstamp[i].tv_usec;
00385                         }
00386                         fprintf(fd, "%lu.%lu %u (%lu)\n", range_sec, 
00387                                 range_usec, qual->qual[i].qual, diff);
00388 #else
00389                         fprintf(fd, "%lu %u\n", range_dmsec, 
00390                                 qual->qual[i].qual);
00391 #endif
00392                 } else if (info->output_type == 3) { /* timestamp, msec */
00393                         fprintf(fd, "%lu %u\n", qual->tstamp[i].tv_sec*1000+
00394                                 qual->tstamp[i].tv_usec/1000 -
00395                                 (start_time.tv_sec*1000-
00396                                  start_time.tv_usec/1000), 
00397                                 qual->qual[i].qual);
00398                 } else if (info->output_type == 4) { /* timestamp, realtime,
00399                                                         dmsec */
00400                         fprintf(fd, "%lu %u\n", qual->tstamp[i].tv_sec*100+
00401                                 qual->tstamp[i].tv_usec/10000, 
00402                                 qual->qual[i].qual);
00403                 } else if (info->output_type == 0) { /* plain quality */
00404                         fprintf(fd, "%d", qual->qual[i].qual);
00405                 } else {
00406                         fprintf(stderr, "Unknown output type! (%d)\n",
00407                                 info->output_type);
00408                         fclose(fd);
00409                         return -1;
00410                 }
00411                 
00412                 if (qual->current >= REC_NODE_CHUNK && 
00413                     i >= (qual->current-1) && qual->next != NULL) {
00414                         qual = qual->next;
00415                         i = 0;
00416                         DEBUG(DEBUG_FLAG, "dump_fa: Next qual node\n");
00417                 } else
00418                         i++;
00419         }
00420         
00421         if (info->output_type > 0 && range_sec > 0) {
00422                 /* generate gnuplot header file */
00423                 snprintf(name, FILENAME_MAX, "FA-%s-dump.plot",
00424                          inet_ntoa(rec->ip_addr));
00425                 header = fopen(name, "w");
00426                 if (!header) {
00427                         DEBUG(DEBUG_FLAG, "dump_fa: fopen: %s\n",
00428                               strerror(errno));
00429                         fclose(fd);
00430                         return -1;
00431                 }
00432                 fprintf(header, "set output \"%s.gif\"\n", 
00433                         inet_ntoa(rec->ip_addr));
00434                 if (info->output_type == 1)
00435                         fprintf(header, "set terminal gif small size %d,%d\n"
00436                                 "set xlabel \"Time t/s\"\n"
00437                                 "set ylabel \"Quality\"\n"
00438                                 "plot [0:%ld] [0:%d] 'FA-%s-dump.dat' title "
00439                                 "\"FA (%s)\" with lines lt 3 \n",
00440                                 IMG_X, IMG_Y, range_sec, Q_RANGE,
00441                                 inet_ntoa(rec->ip_addr),
00442                                 inet_ntoa(rec->ip_addr));
00443                 else if (info->output_type == 2)
00444                         fprintf(header, "set terminal gif small size %d,%d\n"
00445                                 "set xlabel \"Time t/10msec\"\n"
00446                                 "set ylabel \"Quality\"\n"
00447                                 "plot [%ld:%ld] [0:%d] 'FA-%s-dump.dat' "
00448                                 "title \"FA (%s)\" with lines lt 3 \n",
00449                                 IMG_X, IMG_Y, start_time.tv_sec*100, 
00450                                 start_time.tv_sec*100+range_sec*100, Q_RANGE,
00451                                 inet_ntoa(rec->ip_addr),
00452                                 inet_ntoa(rec->ip_addr));
00453                 else if (info->output_type == 3)
00454                         fprintf(header, "set terminal gif small size %d,%d\n"
00455                                 "set xlabel \"Time t/ms\"\n"
00456                                 "set ylabel \"Quality\"\n"
00457                                 "plot [0:%ld] [0:%d] 'FA-%s-dump.dat' title "
00458                                 "\"FA (%s)\" with lines lt 3 \n",
00459                                 IMG_X, IMG_Y, range_sec*1000, Q_RANGE,
00460                                 inet_ntoa(rec->ip_addr),
00461                                 inet_ntoa(rec->ip_addr));
00462                 else if (info->output_type == 4)
00463                         fprintf(header, "set terminal gif small size %d,%d\n"
00464                                 "set xlabel \"Time t/ms\"\n"
00465                                 "set ylabel \"Quality\"\n"
00466                                 "plot [%ld:%ld] [0:%d] 'FA-%s-dump.dat' title "
00467                                 "\"FA (%s)\" with lines lt 3 \n",
00468                                 IMG_X, IMG_Y, start_time.tv_sec*1000, 
00469                                 start_time.tv_sec*1000+range_sec, Q_RANGE,
00470                                 inet_ntoa(rec->ip_addr),
00471                                 inet_ntoa(rec->ip_addr));
00472                 /* print entry into combined plot */
00473                 len = strlen(info->plot_str);
00474                 if (len + 100 < PLOT_STR_SIZE)
00475                         snprintf(&info->plot_str[len], 100, 
00476                                  "'FA-%s-dump.dat' title \"FA %s\" "
00477                                  "with lines, ", inet_ntoa(rec->ip_addr),
00478                                  inet_ntoa(rec->ip_addr));
00479                 fclose(header);
00480         }
00481 
00482         fclose(fd);
00483         return 1;
00484 }
00485 
00486 
00487 int rec_dump(int type, int interval)
00488 {
00489         struct dump info;
00490         char name[FILENAME_MAX];
00491         long range;
00492         int len;
00493         FILE *header;
00494         struct timeval stop_time;
00495 
00496         DEBUG(DEBUG_FLAG, "rec_dump\n");
00497         /* dump the data in specified format (type) */
00498         if (rec_hash == NULL) {
00499                 DEBUG(DEBUG_FLAG, "rec_dump: hashtable NULL\n");
00500                 return -1;
00501         }
00502         memset(&info, 0, sizeof(info));
00503         info.output_type = type;
00504         info.interval = interval;
00505         hashtable_iterator(rec_hash, dump_fa, &info);
00506         len = strlen(info.plot_str);
00507 
00508         if (len <= 0) {
00509                 DEBUG(DEBUG_FLAG, "rec_dump: info plot string < 0\n");
00510                 return 0;
00511         }
00512 
00513         /* Make special group gnuplot file */
00514         snprintf(name, FILENAME_MAX, "group.plot");
00515         header = fopen(name, "w");
00516         if (header == NULL) {
00517                 DEBUG(DEBUG_FLAG, "rec_dump: fopen: %s\n",
00518                       strerror(errno));
00519                 return -1;
00520         }
00521         gettimeofday(&stop_time, NULL);
00522         range = stop_time.tv_sec - start_time.tv_sec;
00523         fprintf(header, "set output \"group.gif\"\n"); 
00524         if (type == 1)
00525                 fprintf(header, "set terminal gif large size %d,%d\n"
00526                         "set xlabel \"Time t/s\"\n"
00527                         "set ylabel \"Quality\"\n"
00528                         "plot [0:%ld] [0:%d] ", G_IMG_X, G_IMG_Y, range,
00529                         Q_RANGE);
00530         else if (type == 2 || type == 4)
00531                 fprintf(header, "set terminal gif large size %d,%d\n"
00532                         "set xlabel \"Time t/10msec\"\n"
00533                         "set ylabel \"Quality\"\n"
00534                         "plot [0:%ld] [0:%d] ", G_IMG_X, G_IMG_Y, range*100,
00535                         Q_RANGE);
00536         
00537         else if (type == 3)
00538                 fprintf(header, "set terminal gif large size %d,%d\n"
00539                         "set xlabel \"Time t/ms\"\n"
00540                         "set ylabel \"Quality\"\n"
00541                         "plot [0:%ld] [0:%d] ", G_IMG_X, G_IMG_Y, range*1000,
00542                         Q_RANGE);
00543         info.plot_str[len - 2] = '\n';
00544         info.plot_str[len - 1] = '\0';
00545         fprintf(header, info.plot_str);
00546         if (fclose(header))
00547                 DEBUG(DEBUG_FLAG, "rec_dump: fclose: %s\n", 
00548                       strerror(errno));
00549 
00550         return 0;
00551 }

Generated on Tue Jan 15 08:50:43 2008 for Virtual foreign agent generator version 0.1 by  doxygen 1.5.1