snmpSTDDomain.c

00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #include <stdio.h>
00004 #include <sys/types.h>
00005 #include <signal.h>
00006 #include <errno.h>
00007 
00008 #if HAVE_STRING_H
00009 #include <string.h>
00010 #else
00011 #include <strings.h>
00012 #endif
00013 #if HAVE_STDLIB_H
00014 #include <stdlib.h>
00015 #endif
00016 #if HAVE_UNISTD_H
00017 #include <unistd.h>
00018 #endif
00019 
00020 #if HAVE_DMALLOC_H
00021 #include <dmalloc.h>
00022 #endif
00023 
00024 #include <net-snmp/types.h>
00025 #include <net-snmp/output_api.h>
00026 
00027 #include <net-snmp/library/snmp_transport.h>
00028 #include <net-snmp/library/snmpSTDDomain.h>
00029 #include <net-snmp/library/tools.h>
00030 
00031 oid netsnmp_snmpSTDDomain[] = { TRANSPORT_DOMAIN_STD_IP };
00032 static netsnmp_tdomain stdDomain;
00033 
00034 /*
00035  * Return a string representing the address in data, or else the "far end"
00036  * address if data is NULL.  
00037  */
00038 
00039 static char *
00040 netsnmp_std_fmtaddr(netsnmp_transport *t, void *data, int len)
00041 {
00042     char *buf;
00043     DEBUGMSGTL(("domain:std","formatting addr.  data=%x\n",t->data));
00044     if (t->data) {
00045         netsnmp_std_data *data = t->data;
00046         buf = malloc(SNMP_MAXBUF_MEDIUM);
00047         if (!buf)
00048             return strdup("STDInOut");
00049         snprintf(buf, SNMP_MAXBUF_MEDIUM, "STD:%s", data->prog);
00050         DEBUGMSGTL(("domain:std","  formatted:=%s\n",buf));
00051         return buf;
00052     }
00053     return strdup("STDInOut");
00054 }
00055 
00056 
00057 
00058 /*
00059  * You can write something into opaque that will subsequently get passed back 
00060  * to your send function if you like.  For instance, you might want to
00061  * remember where a PDU came from, so that you can send a reply there...  
00062  */
00063 
00064 static int
00065 netsnmp_std_recv(netsnmp_transport *t, void *buf, int size,
00066                  void **opaque, int *olength)
00067 {
00068     int rc = -1;
00069 
00070     DEBUGMSGTL(("domain:std","recv on sock %d.  data=%x\n",t->sock, t->data));
00071     while (rc < 0) {
00072         rc = read(t->sock, buf, size);
00073         DEBUGMSGTL(("domain:std","  bytes: %d.\n", rc));
00074         if (rc < 0 && errno != EINTR) {
00075             DEBUGMSGTL(("netsnmp_std", " read on fd %d failed: %d (\"%s\")\n",
00076                         t->sock, errno, strerror(errno)));
00077             break;
00078         }
00079         if (rc == 0) {
00080             /* 0 input is probably bad since we selected on it */
00081             return -1;
00082         }
00083         DEBUGMSGTL(("netsnmp_std", "read on stdin got %d bytes\n", rc));
00084     }
00085 
00086     return rc;
00087 }
00088 
00089 
00090 
00091 static int
00092 netsnmp_std_send(netsnmp_transport *t, void *buf, int size,
00093                  void **opaque, int *olength)
00094 {
00095     int rc = -1;
00096 
00097     DEBUGMSGTL(("domain:std","send on sock.  data=%x\n", t->data));
00098     while (rc < 0) {
00099         if (t->data) {
00100             netsnmp_std_data *data = t->data;
00101             rc = write(data->outfd, buf, size);
00102         } else {
00103             /* straight to stdout */
00104             rc = write(1, buf, size);
00105         }
00106         if (rc < 0 && errno != EINTR) {
00107             break;
00108         }
00109     }
00110     return rc;
00111 }
00112 
00113 static int
00114 netsnmp_std_close(netsnmp_transport *t)
00115 {
00116     DEBUGMSGTL(("domain:std","close.  data=%x\n", t->data));
00117     if (t->data) {
00118         netsnmp_std_data *data = t->data;
00119         close(data->outfd);
00120         close(t->sock);
00121 
00122         /* kill the child too */
00123         DEBUGMSGTL(("domain:std"," killing %d\n", data->childpid));
00124         kill(data->childpid, SIGTERM);
00125         sleep(1);
00126         kill(data->childpid, SIGKILL);
00127         /* XXX: set an alarm to kill harder the child */
00128     } else {
00129         /* close stdout/in */
00130         close(1);
00131         close(0);
00132     }
00133     return 0;
00134 }
00135 
00136 
00137 
00138 static int
00139 netsnmp_std_accept(netsnmp_transport *t)
00140 {
00141     DEBUGMSGTL(("domain:std"," accept data=%x\n", t->data));
00142     /* nothing to do here */
00143     return 0;
00144 }
00145 
00146 /*
00147  * Open a STDIN/STDOUT -based transport for SNMP.
00148  */
00149 
00150 netsnmp_transport *
00151 netsnmp_std_transport(const char *instring, size_t instring_len)
00152 {
00153     netsnmp_transport *t;
00154 
00155     t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00156     if (t == NULL) {
00157         return NULL;
00158     }
00159     memset(t, 0, sizeof(netsnmp_transport));
00160 
00161     t->domain = netsnmp_snmpSTDDomain;
00162     t->domain_length =
00163         sizeof(netsnmp_snmpSTDDomain) / sizeof(netsnmp_snmpSTDDomain[0]);
00164 
00165     t->sock = 0;
00166     t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED;
00167 
00168     /*
00169      * Message size is not limited by this transport (hence msgMaxSize
00170      * is equal to the maximum legal size of an SNMP message).  
00171      */
00172 
00173     t->msgMaxSize = 0x7fffffff;
00174     t->f_recv     = netsnmp_std_recv;
00175     t->f_send     = netsnmp_std_send;
00176     t->f_close    = netsnmp_std_close;
00177     t->f_accept   = netsnmp_std_accept;
00178     t->f_fmtaddr  = netsnmp_std_fmtaddr;
00179 
00180     /*
00181      * if instring is not null length, it specifies a path to a prog
00182      * XXX: plus args
00183      */
00184     if (instring_len != 0) {
00185         int infd[2], outfd[2];  /* sockets to and from the client */
00186         int childpid;
00187 
00188         if (pipe(infd) || pipe(outfd)) {
00189             snmp_log(LOG_ERR,
00190                      "Failed to create needed pipes for a STD transport");
00191             netsnmp_transport_free(t);
00192             return NULL;
00193         }
00194 
00195         childpid = fork();
00196         /* parentpid => childpid */
00197         /* infd[1]   => infd[0] */
00198         /* outfd[0]  <= outfd[1] */
00199 
00200         if (childpid) {
00201             netsnmp_std_data *data;
00202             
00203             /* we're in the parent */
00204             close(infd[0]);
00205             close(outfd[1]);
00206 
00207             data = SNMP_MALLOC_TYPEDEF(netsnmp_std_data);
00208             if (!data) {
00209                 snmp_log(LOG_ERR, "snmpSTDDomain: memdup failed");
00210                 netsnmp_transport_free(t);
00211                 return NULL;
00212             }
00213             t->data = data;
00214             t->data_length = sizeof(netsnmp_transport_free);
00215             t->sock = outfd[0];
00216             data->prog = strdup(instring);
00217             data->outfd = infd[1];
00218             data->childpid = childpid;
00219             DEBUGMSGTL(("domain:std","parent.  data=%x\n", t->data));
00220         } else {
00221             /* we're in the child */
00222 
00223             /* close stdin */
00224             close(0);
00225             /* copy pipe output to stdout */
00226             dup(infd[0]);
00227 
00228             /* close stdout */
00229             close(1);
00230             /* copy pipe output to stdin */
00231             dup(outfd[1]);
00232             
00233             /* close all the pipes themselves */
00234             close(infd[0]);
00235             close(infd[1]);
00236             close(outfd[0]);
00237             close(outfd[1]);
00238 
00239             /* call exec */
00240             system(instring);
00241             /* XXX: TODO: use exec form instead; needs args */
00242             /* execv(instring, NULL); */
00243             exit(0);
00244 
00245             /* ack...  we should never ever get here */
00246             snmp_log(LOG_ERR, "STD transport returned after execv()\n");
00247         }
00248     }            
00249 
00250     return t;
00251 }
00252 
00253 netsnmp_transport *
00254 netsnmp_std_create_tstring(const char *instring, int local)
00255 {
00256     return netsnmp_std_transport(instring, strlen(instring));
00257 }
00258 
00259 netsnmp_transport *
00260 netsnmp_std_create_ostring(const u_char * o, size_t o_len, int local)
00261 {
00262     return netsnmp_std_transport(o, o_len);
00263 }
00264 
00265 void
00266 netsnmp_std_ctor(void)
00267 {
00268     stdDomain.name = netsnmp_snmpSTDDomain;
00269     stdDomain.name_length = sizeof(netsnmp_snmpSTDDomain) / sizeof(oid);
00270     stdDomain.prefix = calloc(2, sizeof(char *));
00271     stdDomain.prefix[0] = "std";
00272 
00273     stdDomain.f_create_from_tstring = netsnmp_std_create_tstring;
00274     stdDomain.f_create_from_ostring = netsnmp_std_create_ostring;
00275 
00276     netsnmp_tdomain_register(&stdDomain);
00277 }

net-snmpに対してSat Sep 5 13:14:26 2009に生成されました。  doxygen 1.4.7