device_info.c

Go to the documentation of this file.
00001 /* $Id: device_info.c,v 1.12 2001/09/08 14:29:40 jm Exp $
00002  * Device information daemon in a unix domain socket
00003  *
00004  * Dynamic hierarchial IP tunnel
00005  * Copyright (C) 1998-2001, 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 /*
00014  * Device info daemon can be used to query device priorities. It uses
00015  * configuration file by default in /etc/device_info.conf. The file
00016  * contains MAC addresses of devices and priorities to them. 
00017  */
00018 
00019 #ifndef _GNU_SOURCE
00020 #define _GNU_SOURCE
00021 #endif
00022 
00023 #include <stdio.h>
00024 #include <stdarg.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <time.h>
00029 #include <getopt.h>
00030 #include <unistd.h>
00031 #include <signal.h>
00032 #include <arpa/inet.h>
00033 #include <sys/types.h>
00034 #include <sys/socket.h>
00035 #include <sys/un.h>
00036 #include <sys/param.h>
00037 #include <sys/ioctl.h>
00038 #include <linux/if.h>
00039 
00040 #include "util.h"
00041 #include "dyn_mnlib.h"
00042 #include "agentapi.h"
00043 #include "fixed_fd_zero.h"
00044 #include "device_info.h"
00045 #include "dyn_ip.h"
00046 
00047 #define PID_FILE "/var/run/device_info.pid"
00048 #define MAXLINE 100
00049 
00050 static char *default_socket_path = DEFAULT_DEVICE_INFO_PATH;
00051 static char *default_config_file_path = "/etc/device_info.conf";
00052 static char *config_file_path = NULL;
00053 static char *socket_path = NULL;
00054 static fd_set set;
00055 static int debug = 0;
00056 
00057 static struct device_info_config *config = NULL;
00058 
00059 struct device_info_config {
00060         unsigned char hw[ETH_ALEN];
00061         int priority;
00062         int line;
00063         struct device_info_config *next;
00064 };
00065 
00066 
00067 void DEBUG(char *format, ...)
00068 {
00069         va_list ap;
00070 
00071         if (!debug)
00072                 return;
00073 
00074         va_start(ap, format);
00075         vfprintf(stdout, format, ap);
00076         fflush(stdout);
00077         va_end(ap);
00078 }
00079 
00080 
00081 static int open_socket(char *path)
00082 {
00083         if (!path) {
00084                 fprintf(stderr, "open_socket: path is NULL\n");
00085                 return -1;
00086         }
00087         return api_open_socket(path, NULL, NULL, (int)0666);
00088 }
00089 
00090 
00091 static void clean_up(int sig)
00092 {
00093         unlink(PID_FILE);
00094         exit(sig);
00095 }
00096 
00097 
00098 static struct device_info_config *find_entry(char *hw)
00099 {
00100         struct device_info_config *conf = config;
00101 
00102         if (hw == NULL)
00103                 return NULL;
00104 
00105         while (conf != NULL) {
00106                 if (!memcmp(hw, conf->hw, ETH_ALEN))
00107                         return conf;
00108                 conf = conf->next;
00109         }
00110 
00111         return NULL;
00112 } 
00113 
00114 
00115 static int send_reply(int sock, struct sockaddr_un *addr,
00116                       struct device_info_query *query)
00117 {
00118         int r;
00119         if (addr == NULL || query == NULL) {
00120                 fprintf(stderr, "send_reply: NULL argument\n");
00121                 return -1;
00122         }
00123 
00124         DEBUG("\tsending reply: index = %d, prio %d\n",
00125               query->device_index, query->priority);
00126 
00127         r = sendto(sock, query, sizeof(struct device_info_query), 0,
00128                    (struct sockaddr *)addr, sizeof(struct sockaddr_un));
00129         if (r != sizeof(struct device_info_query)) {
00130                 fprintf(stderr, "send_reply: sendto %d/%d bytes: %s\n",
00131                         r, sizeof(query), strerror(errno));
00132                 return -1;
00133         }
00134         
00135         return r;
00136 }
00137 
00138 
00139 static int handle_request(int sock)
00140 {
00141         struct sockaddr_un addr;
00142         struct device_info_query query;
00143         struct device_info_config *config;
00144         struct idxmap *idxmap, *idx;
00145         struct ifreq ifr;
00146         int n, len, found = 0, s;
00147 
00148         len = sizeof(addr);
00149         n = recvfrom(sock, &query, sizeof(query), 0, (struct sockaddr *) &addr,
00150                      (unsigned int *)&len);
00151         if (n != sizeof(query)) {
00152                 fprintf(stderr, "handle_request: couldn't receive whole "
00153                         "message %d/%d\n", n, sizeof(query));
00154                 return -1;
00155         }
00156         
00157 
00158         DEBUG("received query\n\tquery.device_index = %d\n", 
00159               query.device_index);
00160         memset(&ifr, 0, sizeof(ifr));
00161 
00162         /* find interface name for the index */
00163         idxmap = dyn_ip_get_interface_map();
00164         idx = idxmap;
00165         while (idx != NULL) {
00166                 if (idx->index == query.device_index) {
00167                         memcpy(ifr.ifr_name, idx->name, sizeof(ifr.ifr_name));
00168                         DEBUG("\tdevice name: %s\n", ifr.ifr_name);
00169                         found = 1;
00170                         break;
00171                 }
00172                 idx = idx->next;
00173         }
00174         dyn_ip_free_interface_map(idxmap);
00175         if (!found) {
00176                 fprintf(stderr, "handle_request: Couldn't find ifname\n");
00177                 return -1;
00178         }
00179 
00180         ifr.ifr_ifindex = query.device_index;
00181         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
00182         if (s < 0) {
00183                 fprintf(stderr, "handle_request: socket failed: %s\n",
00184                       strerror(errno));
00185                 return -1;
00186         }
00187         if (ioctl(s, SIOCGIFHWADDR, &ifr) != 0) {
00188                 fprintf(stderr, "handle_request: SIOCGIFHWADDR ioctl: %s\n",
00189                         strerror(errno));
00190                 return -1;
00191         }
00192         config = find_entry(ifr.ifr_hwaddr.sa_data);
00193         found = 1;
00194         if (!config) {
00195                 DEBUG("handle_request: entry not found (%s)\n", 
00196                        ether_hwtoa((unsigned char *)&ifr.ifr_hwaddr.sa_data));
00197                 found = 0;
00198                 query.priority = -2; /* entry not found */
00199         } else {
00200                 query.priority = config->priority;
00201                 DEBUG("\tquery.priority = %d\n", query.priority);
00202         }
00203         
00204         /* reply */
00205         n = send_reply(sock, &addr, &query);
00206         if (n < 0) {
00207                 fprintf(stderr, "handle_request: Couldn't send reply\n");
00208                 return -1;
00209         }
00210 
00211         return 0;
00212 }
00213 
00214 
00215 static void parse_config(int sig)
00216 {
00217         FILE *file;
00218         char buffer[MAXLINE];
00219         struct device_info_config *conf = config, *first = config;
00220         int line = 0, n;
00221         unsigned int hw[6];
00222 
00223 
00224         if (debug && sig == SIGHUP)
00225                 DEBUG("HUP signal received. Rereading config file\n");
00226 
00227         if (config_file_path == NULL) {
00228                 fprintf(stderr, "parse_config: path is NULL\n");
00229                 return;
00230         }
00231         file = fopen(config_file_path, "r");
00232         if (file == NULL) {
00233                 fprintf(stderr, "parse_config: Can't open file %s\n",
00234                         strerror(errno));
00235                 return;
00236         }
00237         
00238         while (fgets(buffer, MAXLINE, file) != NULL) {
00239                 buffer[strlen(buffer)-1]='\0';
00240                 ++line;
00241                 if (buffer[0] == '#' || 
00242                     buffer[0] == '\n' || 
00243                     buffer[0] == '\t' ||
00244                     buffer[0] == ' ' ||
00245                     strlen(buffer) == 0) {
00246                         continue;
00247                 }
00248 
00249                 if (conf == NULL) {
00250                         DEBUG("Reading first time the configuration file\n");
00251                         conf = malloc(sizeof(struct device_info_config));
00252                         first = conf;
00253                 }
00254                 else {
00255                         conf->next = malloc(sizeof(struct device_info_config));
00256                         conf = conf->next;
00257                 }
00258                 if (conf == NULL) {
00259                         fprintf(stderr, "parse_config: Memory allocation "
00260                                 "failed\n");
00261                         fclose(file);
00262                         return;
00263                 }
00264                 n = sscanf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x %d", 
00265                            &hw[0], &hw[1], &hw[2], &hw[3], &hw[4], &hw[5], 
00266                            &conf->priority);
00267                 if (n != 7) {
00268                         fprintf(stderr, "parse_config: Couldn't parse "
00269                                 "line %d '%s'\n", line, buffer);
00270                         fclose(file);
00271                         return;
00272                 }
00273                 conf->line = line;
00274                 conf->hw[0] = (unsigned char)hw[0];
00275                 conf->hw[1] = (unsigned char)hw[1];
00276                 conf->hw[2] = (unsigned char)hw[2];
00277                 conf->hw[3] = (unsigned char)hw[3];
00278                 conf->hw[4] = (unsigned char)hw[4];
00279                 conf->hw[5] = (unsigned char)hw[5];
00280                 DEBUG("%s prio %d (line %d)\n", 
00281                       ether_hwtoa((unsigned char *)conf->hw), 
00282                       conf->priority, conf->line);
00283         }
00284 
00285         fclose(file);
00286         config = first;
00287 
00288         return;
00289 }
00290 
00291 
00292 int main(int argc, char *argv[])
00293 {
00294         int s, foreground = 0, c, n;
00295 
00296         socket_path = default_socket_path;
00297         config_file_path = default_config_file_path;
00298         while (1) {
00299                 int option_index = 0;
00300                 static struct option long_options[] = {
00301                         {"fg", no_argument, NULL, 'f'},
00302                         {"debug", no_argument, NULL, 'd'},
00303                         {0, 0, 0, 0}
00304                 };
00305                 
00306                 c = getopt_long (argc, argv, "fdc:s:",
00307                                  long_options, &option_index);
00308                 if (c == -1)
00309                         break;
00310                 
00311                 switch (c) {
00312                 case 'f':
00313                         switch (option_index) {
00314                         case 0:
00315                                 fprintf(stderr,"Option: %s\n",
00316                                       long_options[option_index].name);
00317                                 foreground = 1;
00318                         }
00319                         break;
00320                 case 'c':
00321                         config_file_path = malloc(MAXPATHLEN);
00322                         if (config_file_path == NULL) {
00323                                 fprintf(stderr, "malloc for config: %s\n",
00324                                         strerror(errno));
00325                                 exit(1);
00326                         }
00327                         dynamics_strlcpy(config_file_path, optarg, MAXPATHLEN);
00328                         break;
00329                 case 's':
00330                         socket_path = malloc(MAXPATHLEN);
00331                         if (socket_path == NULL) {
00332                                 fprintf(stderr, "malloc for path: %s\n",
00333                                         strerror(errno));
00334                                 exit(1);
00335                         }
00336                         dynamics_strlcpy(socket_path, optarg, MAXPATHLEN);
00337                         break;
00338                 case 'd':
00339                         debug = 1;
00340                         break;
00341                 case '?':
00342                         fprintf(stderr, "device_info -c <configuration file> "
00343                                 "[-s <API socket>] [--fg]\n");
00344                         exit(1);
00345                 default:
00346                         fprintf(stderr, "?? getopt returned character code "
00347                                 "0%o ??\n", c);
00348                 }
00349         }
00350 
00351         parse_config(0);
00352         if (config == NULL) {
00353                 fprintf(stderr, "Configuration file parsing failed\n");
00354                 exit(1);
00355         }
00356 
00357         s = open_socket(socket_path);
00358         if (s < 0) {
00359                 fprintf(stderr, "Open socket failed\n");
00360                 exit(1);
00361         }
00362 
00363         DEBUG("Initializing mn admin socket path\n");
00364         c = dynamics_mn_init(NULL);
00365         if (c == API_FAILED || c == API_ERROR) {
00366                 fprintf(stderr, "MN admin socket path initialization "
00367                         "failed\n");
00368                 exit(1);
00369         }
00370         DEBUG("Registering device info socket path\n");
00371 
00372         if (dynamics_mn_register_dev_info_socket(socket_path, 3) 
00373             != API_SUCCESS) {
00374                 fprintf(stderr, "API device info socket initialization "
00375                         "failed\n");
00376                 exit(1);
00377         }
00378         DEBUG("\tregistered\n");
00379 
00380         if (!foreground && dynamics_fork_daemon() < 0) {
00381                 fprintf(stderr, "fork failed\n");
00382                 exit(1);
00383         }
00384         dynamics_write_pid_file(PID_FILE);
00385 
00386         signal(SIGHUP, parse_config);
00387         signal(SIGTERM, clean_up);
00388         signal(SIGINT, clean_up);
00389 
00390         for (;;) {
00391                 FD_ZERO(&set);
00392                 FD_SET(s, &set);
00393 
00394                 n = select(FD_SETSIZE, &set, NULL, NULL, NULL);
00395                 if (n < 0 && errno != EINTR)
00396                         fprintf(stderr, "select: %s\n",
00397                                 strerror(errno));
00398           
00399                 if (n == 1 && FD_ISSET(s, &set))
00400                         handle_request(s);
00401         }
00402 
00403         return 0;
00404 }

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