OpenSM: Add socket support to OpenSM console

Signed-off-by: Ira Weiny <[EMAIL PROTECTED]>
Signed-off-by: Hal Rosenstock <[EMAIL PROTECTED]>

diff --git a/osm/include/opensm/osm_console.h b/osm/include/opensm/osm_console.h
index 705f918..2d212f2 100644
--- a/osm/include/opensm/osm_console.h
+++ b/osm/include/opensm/osm_console.h
@@ -38,6 +38,11 @@
 #include <opensm/osm_subnet.h>
 #include <opensm/osm_opensm.h>
 
+#define OSM_COMMAND_LINE_LEN    120
+#define OSM_COMMAND_PROMPT      "$ "
+#define OSM_DEFAULT_CONSOLE_PORT 10000
+#define OSM_DAEMON_NAME          "opensm"
+
 #ifdef __cplusplus
 #  define BEGIN_C_DECLS extern "C" {
 #  define END_C_DECLS   }
@@ -48,8 +53,10 @@
 
 BEGIN_C_DECLS
 
+void osm_console_init(osm_subn_opt_t *opt, osm_opensm_t *p_osm);
 void osm_console(osm_opensm_t *p_osm);
-void osm_console_prompt(void);
+void osm_console_prompt(FILE *out);
+void osm_console_close_socket(osm_opensm_t *p_osm);
 
 END_C_DECLS
 
diff --git a/osm/include/opensm/osm_opensm.h b/osm/include/opensm/osm_opensm.h
index 16fef37..482de28 100644
--- a/osm/include/opensm/osm_opensm.h
+++ b/osm/include/opensm/osm_opensm.h
@@ -48,6 +48,7 @@
 #ifndef _OSM_OPENSM_H_
 #define _OSM_OPENSM_H_
 
+#include <stdio.h>
 #include <signal.h>
 #include <complib/cl_dispatcher.h>
 #include <complib/cl_passivelock.h>
@@ -130,6 +131,15 @@ struct osm_routing_engine {
 *              internals cleanup.
 */
 
+typedef struct _osm_console_t
+{
+  int   socket;
+  int   in_fd;
+  int   out_fd;
+  FILE *in;
+  FILE *out;
+} osm_console_t;
+
 /****s* OpenSM: OpenSM/osm_opensm_t
 * NAME
 *      osm_opensm_t
@@ -156,6 +166,7 @@ typedef struct _osm_opensm_t
   cl_plock_t           lock;
   struct osm_routing_engine routing_engine;
   osm_stats_t          stats;
+  osm_console_t                console;
 } osm_opensm_t;
 /*
 * FIELDS
diff --git a/osm/include/opensm/osm_subnet.h b/osm/include/opensm/osm_subnet.h
index 79796e5..c9b04eb 100644
--- a/osm/include/opensm/osm_subnet.h
+++ b/osm/include/opensm/osm_subnet.h
@@ -266,6 +266,7 @@ typedef struct _osm_subn_opt
   boolean_t                no_qos;
   boolean_t                accum_log_file;
   boolean_t                console;
+  uint16_t                 console_port;
   cl_map_t                 port_prof_ignore_guids;
   boolean_t                port_profile_switch_nodes;
   osm_pfn_ui_extension_t   pfn_ui_pre_lid_assign;
diff --git a/osm/opensm/configure.in b/osm/opensm/configure.in
index 1ccf5c6..2d52675 100644
--- a/osm/opensm/configure.in
+++ b/osm/opensm/configure.in
@@ -62,6 +62,22 @@ AC_ARG_ENABLE(debug,
 esac],[debug=false])
 AM_CONDITIONAL(DEBUG, test x$debug = xtrue)
 
+dnl Console over a socket connection
+AC_ARG_ENABLE(console-socket,
+[  --enable-console-socket Enable a console socket, requires tcp_wrappers 
(default yes)],
+[case $enableval in
+     yes) console_socket=yes ;;
+     no)  console_socket=no ;;
+   esac],
+   console_socket=yes)
+if test $console_socket = yes; then
+  AC_CHECK_LIB(wrap, request_init, [],
+       AC_MSG_ERROR([request_init() not found. console-socket requires 
libwrap.]))
+  AC_DEFINE(ENABLE_OSM_CONSOLE_SOCKET,
+           1,
+           [Define as 1 if you want to enable a console on a socket 
connection])
+fi
+
 dnl Provide user option to select vendor
 OPENIB_APP_OSMV_SEL
 
diff --git a/osm/opensm/main.c b/osm/opensm/main.c
index 374d323..90432be 100644
--- a/osm/opensm/main.c
+++ b/osm/opensm/main.c
@@ -217,6 +217,11 @@ show_usage(void)
           "          4 outstanding SMPs.\n\n" );
   printf( "-console\n"
           "          This option brings up the OpenSM console.\n\n" );
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+  printf( "--console_port <port>\n"
+          "          Specify an alternate telnet port for the console (default 
%d).\n\n",
+         OSM_DEFAULT_CONSOLE_PORT);
+#endif
   printf( "-i <equalize-ignore-guids-file>\n"
           "-ignore-guids <equalize-ignore-guids-file>\n"
           "          This option provides the means to define a set of ports\n"
@@ -578,6 +583,9 @@ main(
       {  "cache-options", 0, NULL, 'c'},
       {  "stay_on_fatal", 0, NULL, 'y'},
       {  "honor_guid2lid", 0, NULL, 'x'},
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+      {  "console_port",  1, NULL, 'C'},
+#endif
       {  NULL,            0, NULL,  0 }  /* Required at the end of the array */
     };
 
@@ -679,6 +687,12 @@ main(
       printf(" Enabling OpenSM interactive console\n");
       break;
 
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+    case 'C':
+      opt.console_port = strtol(optarg, NULL, 0);
+      break;
+#endif
+
     case 'd':
       dbg_lvl = strtol(optarg, NULL, 0);
       printf(" d level = 0x%x\n", dbg_lvl);
@@ -931,15 +945,11 @@ main(
   }
   else
   {
+    osm_console_init(&opt, &osm);
+
     /*
       Sit here forever
-      In the future, some sort of console interactivity could
-      be implemented in this loop.
     */
-    if (opt.console) {
-      printf("\nOpenSM Console\n\n");
-      osm_console_prompt();
-    }
     while( !osm_exit_flag ) {
       if (opt.console)
         osm_console(&osm);
@@ -953,6 +963,7 @@ main(
         osm_opensm_sweep( &osm );
       }
     }
+    osm_console_close_socket(&osm);
   }
 
 #if 0
diff --git a/osm/opensm/osm_console.c b/osm/opensm/osm_console.c
index a1a5eec..420acc2 100644
--- a/osm/opensm/osm_console.c
+++ b/osm/opensm/osm_console.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -39,78 +39,91 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+#include <tcpd.h>
+#endif
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <errno.h>
 #include <opensm/osm_console.h>
 
-#define OSM_COMMAND_LINE_LEN   120
-#define OSM_COMMAND_PROMPT     "$ "
-
 struct command {
        char *name;
-       void (*help_function)(void);
-       void (*parse_function)(char **p_last, osm_opensm_t *p_osm);
+       void (*help_function)(FILE *out, int detail);
+       void (*parse_function)(char **p_last, osm_opensm_t *p_osm, FILE *out);
 };
 
 static const struct command console_cmds[];
 
 static inline char *next_token(char **p_last)
 {
-       return strtok_r(NULL, " \t\n", p_last);
+       return strtok_r(NULL, " \t\n\r", p_last);
 }
 
-static void help_command()
+static void help_command(FILE *out, int detail)
 {
        int i;
 
-       printf("Supported commands and syntax:\n");
-       printf("help [<command>]\n");
+       fprintf(out, "Supported commands and syntax:\n");
+       fprintf(out, "help [<command>]\n");
        /* skip help command */
        for (i = 1; console_cmds[i].name; i++)
-               console_cmds[i].help_function();
+               console_cmds[i].help_function(out, 0);
+}
+
+static void help_quit(FILE *out, int detail)
+{
+       fprintf(out, "quit\n");
 }
 
-static void help_loglevel()
+
+static void help_loglevel(FILE *out, int detail)
 {
-       printf("loglevel [<log-level>]\n");
+       fprintf(out, "loglevel [<log-level>]\n");
 }
 
-static void help_priority()
+static void help_priority(FILE *out, int detail)
 {
-       printf("priority [<sm-priority>]\n");
+       fprintf(out, "priority [<sm-priority>]\n");
 }
 
 /* more help routines go here */
 
-static void help_parse(char **p_last, osm_opensm_t *p_osm)
+static void help_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
 {
        char *p_cmd;
        int i, found = 0;
 
        p_cmd = next_token(p_last);
        if (!p_cmd)
-               help_command();
+               help_command(out, 0);
        else {
                for (i = 1; console_cmds[i].name; i++) {
                        if (!strcmp(p_cmd, console_cmds[i].name)) {
                                found = 1;
-                               console_cmds[i].help_function();
+                               console_cmds[i].help_function(out, 1);
                                break;
                        }
                }
                if (!found) {
-                       printf("Command %s not found\n\n", p_cmd);
-                       help_command();
+                       fprintf(out, "%s : Command not found\n\n", p_cmd);
+                       help_command(out, 0);
                }
        }
 }
 
-static void loglevel_parse(char **p_last, osm_opensm_t *p_osm)
+static void loglevel_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
 {
        char *p_cmd;
        int level;
 
        p_cmd = next_token(p_last);
        if (!p_cmd)
-               printf("Current log level is 0x%x\n", 
osm_log_get_level(&p_osm->log));
+               fprintf(out, "Current log level is 0x%x\n", 
osm_log_get_level(&p_osm->log));
        else {
                /* Handle x, 0x, and decimal specification of log level */
                if (!strncmp(p_cmd, "x", 1)) { 
@@ -124,38 +137,57 @@ static void loglevel_parse(char **p_last
                                level = strtol(p_cmd, NULL, 10);
                }
                if ((level >= 0) && (level < 256)) {
-                       printf("Setting log level to 0x%x\n", level);
+                       fprintf(out, "Setting log level to 0x%x\n", level);
                        osm_log_set_level(&p_osm->log, level);
                } else
-                       printf("Invalid log level 0x%x\n", level);
+                       fprintf(out, "Invalid log level 0x%x\n", level);
        }
 }
 
-static void priority_parse(char **p_last, osm_opensm_t *p_osm)
+static void priority_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
 {
        char *p_cmd;
        int priority;
 
        p_cmd = next_token(p_last);
        if (!p_cmd)
-               printf("Current sm-priority is %d\n", 
p_osm->subn.opt.sm_priority);
+               fprintf(out, "Current sm-priority is %d\n", 
p_osm->subn.opt.sm_priority);
        else {
                priority = strtol(p_cmd, NULL, 0);
                if (0 > priority || 15 < priority)
-                       printf("Invalid sm-priority %d; must be between 0 and 
15\n", priority);
+                       fprintf(out, "Invalid sm-priority %d; must be between 0 
and 15\n", priority);
                else {
-                       printf("Setting sm-priority to %d\n", priority);
+                       fprintf(out, "Setting sm-priority to %d\n", priority);
                        p_osm->subn.opt.sm_priority = (uint8_t)priority;
                        /* Does the SM state machine need a kick now ? */
                }
        }
 }
 
+/* This is public to be able to close it on exit */
+void osm_console_close_socket(osm_opensm_t *p_osm)
+{
+       if (p_osm->console.socket > 0) {
+               close(p_osm->console.in_fd);
+               p_osm->console.in_fd = -1;
+               p_osm->console.out_fd = -1;
+               p_osm->console.in = NULL;
+               p_osm->console.out = NULL;
+       }
+}
+
+static void quit_parse(char **p_last, osm_opensm_t *p_osm, FILE *out)
+{
+       osm_console_close_socket(p_osm);
+}
+
+
 /* more parse routines go here */
 
 static const struct command console_cmds[] =
 {
        { "help",       &help_command,          &help_parse},
+       { "quit",       &help_quit,             &quit_parse},
        { "loglevel",   &help_loglevel,         &loglevel_parse},       
        { "priority",   &help_priority,         &priority_parse},
        { NULL,         NULL,                   NULL}   /* end of array */
@@ -165,60 +197,196 @@ static void parse_cmd_line(char *line, o
 {
        char *p_cmd, *p_last;
        int i, found = 0;
+       FILE *out = p_osm->console.out;
+
 
        /* find first token which is the command */
-       p_cmd = strtok_r(line, " \t\n", &p_last);
+       p_cmd = strtok_r(line, " \t\n\r", &p_last);
        if (p_cmd) {
                for (i = 0; console_cmds[i].name; i++) {
                        if (!strcmp(p_cmd, console_cmds[i].name)) {
                                found = 1;
-                               console_cmds[i].parse_function(&p_last, p_osm);
+                               console_cmds[i].parse_function(&p_last, p_osm, 
out);
                                break;
                        }
                }
                if (!found) {
-                       printf("Command %s not found\n\n", p_cmd);
-                       help_command();
+                       fprintf(out, "%s : Command not found\n\n", p_cmd);
+                       help_command(out, 0);
                }
        } else {
-               printf("Error parsing command line: %s\n", line);
+               fprintf(out, "Error parsing command line: %s\n", line);
                return;
        }
 }
 
-void osm_console_prompt(void)
+void osm_console_prompt(FILE *out)
 {
-       printf("%s", OSM_COMMAND_PROMPT);
-       fflush(stdout);
+       if (out) {
+               fprintf(out, "OpenSM %s", OSM_COMMAND_PROMPT);
+               fflush(out);
+       }
 }
 
+void osm_console_init(osm_subn_opt_t *opt, osm_opensm_t *p_osm)
+{
+       p_osm->console.socket = -1;
+       /* set up the file descriptors for the console */
+       if (opt->console) {
+               p_osm->console.in = stdin;
+               p_osm->console.out = stdout;
+               p_osm->console.in_fd = fileno(stdin);
+               p_osm->console.out_fd = fileno(stdout);
+
+               osm_console_prompt(p_osm->console.out);
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+       } else {
+               struct sockaddr_in  sin;
+               int optval = 1;
+
+               if ((p_osm->console.socket = socket(AF_INET, SOCK_STREAM, 0)) < 
0)
+               {
+                       osm_log(&(p_osm->log), OSM_LOG_ERROR,
+                               "osm_console_init: Failed to open console 
socket : %s\n",
+                               strerror(errno));
+                       return;
+               }
+               setsockopt(p_osm->console.socket, SOL_SOCKET, SO_REUSEADDR, 
&optval, sizeof(optval));
+               sin.sin_family = AF_INET;
+               sin.sin_port = htons(opt->console_port);
+               sin.sin_addr.s_addr = htonl(INADDR_ANY);
+               if (bind(p_osm->console.socket, &sin, sizeof(sin)) < 0)
+               {
+                       osm_log(&(p_osm->log), OSM_LOG_ERROR,
+                               "osm_console_init: Failed to bind console 
socket : %s\n",
+                               strerror(errno));
+                       return;
+               }
+               if (listen(p_osm->console.socket, 1) < 0)
+               {
+                       osm_log(&(p_osm->log), OSM_LOG_ERROR,
+                               "osm_console_init: Failed to listen on socket : 
%s\n",
+                               strerror(errno));
+                       return;
+               }
+
+               p_osm->console.in = NULL;
+               p_osm->console.out = NULL;
+               p_osm->console.in_fd = -1;
+               p_osm->console.out_fd = -1;
+               opt->console = 1;
+               osm_log(&(p_osm->log), OSM_LOG_INFO,
+                               "osm_console_init: Console listening on port 
%d\n", opt->console_port);
+#endif
+       }
+}
+
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+static void handle_osm_connection(osm_opensm_t *p_osm, int new_fd,
+                               char *client_ip, char *client_hn)
+{
+       char          *p_line;
+       size_t         len;
+       ssize_t        n;
+
+       if (p_osm->console.in_fd >= 0)
+       {
+               FILE *file = fdopen(new_fd, "w+");
+               fprintf(file, "OpenSM Console connection already in use\n"
+                               "   kill other session (y/n)? ");
+               fflush(file);
+               p_line = NULL;
+               n = getline(&p_line, &len, file);
+               if (n > 0 && (p_line[0] == 'y' || p_line[0] == 'Y'))
+               {
+                       osm_console_close_socket(p_osm);
+               } else {
+                       close(new_fd);
+                       return;
+               }
+       }
+       p_osm->console.in_fd = new_fd;
+       p_osm->console.out_fd = p_osm->console.in_fd;
+       p_osm->console.in = fdopen(p_osm->console.in_fd, "w+");
+       p_osm->console.out = p_osm->console.in;
+       osm_console_prompt(p_osm->console.out);
+       osm_log(&(p_osm->log), OSM_LOG_INFO,
+                       "osm_console_init: Console connection accepted : %s 
(%s)\n",
+                       client_hn, client_ip);
+}
+
+static int connection_ok(char *client_ip, char *client_hn)
+{
+       return (hosts_ctl(OSM_DAEMON_NAME, client_hn, client_ip, 
"STRING_UNKNOWN"));
+}
+#endif
+
 void osm_console(osm_opensm_t *p_osm)
 {
-       struct pollfd pollfd;
-       char *p_line;
-       size_t len;
-       ssize_t n;
+       struct pollfd  pollfd[2];
+       char          *p_line;
+       size_t         len;
+       ssize_t        n;
 
-       pollfd.fd = 0;
-       pollfd.events = POLLIN;
-       pollfd.revents = 0;
+       pollfd[0].fd = p_osm->console.socket;
+       pollfd[0].events = POLLIN|POLLOUT;
+       pollfd[0].revents = 0;
 
-       if (poll(&pollfd, 1, 10000) <= 0)
+       pollfd[1].fd = p_osm->console.in_fd;
+       pollfd[1].events = POLLIN|POLLOUT;
+       pollfd[1].revents = 0;
+
+       if (poll(pollfd, 2, 10000) <= 0)
                return;
 
-       if (pollfd.revents|POLLIN) {
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+       if (pollfd[0].revents & POLLIN) {
+               int new_fd = 0;
+               struct sockaddr_in  sin;
+               socklen_t len = sizeof(sin);
+               char client_ip[64];
+               char client_hn[128];
+               struct hostent *hent;
+               if ((new_fd = accept(p_osm->console.socket, &sin, &len)) < 0) {
+                       osm_log(&(p_osm->log), OSM_LOG_ERROR,
+                               "osm_console: Failed to accept console socket : 
%s\n",
+                               strerror(errno));
+                       p_osm->console.in_fd = -1;
+                       return;
+               }
+               if (inet_ntop(AF_INET, &sin.sin_addr, client_ip, 
sizeof(client_ip)) == NULL) {
+                       snprintf(client_ip, 64, "STRING_UNKNOWN");
+               }
+               if ((hent = gethostbyaddr((const char *) &sin.sin_addr,
+                              sizeof(struct in_addr), AF_INET)) == NULL) {
+                       snprintf(client_hn, 128, "STRING_UNKNOWN");
+               } else {
+                       snprintf(client_hn, 128, "%s", hent->h_name);
+               }
+               if (connection_ok(client_ip, client_hn)) {
+                       handle_osm_connection(p_osm, new_fd, client_ip, 
client_hn);
+               } else {
+                       osm_log(&(p_osm->log), OSM_LOG_ERROR,
+                               "osm_console: Console connection denied : %s 
(%s)\n",
+                               client_hn, client_ip);
+                       close(new_fd);
+               }
+               return;
+       }
+#endif
+
+       if (pollfd[1].revents & POLLIN) {
                p_line = NULL;
                /* Get input line */
-               n = getline(&p_line, &len, stdin);
+               n = getline(&p_line, &len, p_osm->console.in);
                if (n > 0) {
                        /* Parse and act on input */
                        parse_cmd_line(p_line, p_osm);
                        free(p_line);
                } else {
-                       printf("Input error\n");
-                       fflush(stdin);
+                       fprintf(p_osm->console.out, "Input error\n");
+                       fflush(p_osm->console.out);
                }
-               osm_console_prompt();
+               osm_console_prompt(p_osm->console.out);
        }
 }
-
diff --git a/osm/opensm/osm_subnet.c b/osm/opensm/osm_subnet.c
index aec4ff2..aff2130 100644
--- a/osm/opensm/osm_subnet.c
+++ b/osm/opensm/osm_subnet.c
@@ -63,6 +63,7 @@
 #include <opensm/osm_node.h>
 #include <opensm/osm_multicast.h>
 #include <opensm/osm_inform.h>
+#include <opensm/osm_console.h>
 
 /**********************************************************************
  **********************************************************************/
@@ -444,6 +445,7 @@ osm_subn_set_default_opt(
   p_opt->sweep_interval = OSM_DEFAULT_SWEEP_INTERVAL_SECS;
   p_opt->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE;
   p_opt->console = FALSE;
+  p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT;
   p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;
   /* by default we will consider waiting for 50x transaction timeout normal */
   p_opt->max_msg_fifo_timeout = 50*OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;




_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to