root/src/noit_capabilities_listener.c

Revision 9bfe1c2d8a658e59c3518c84d0ecb0e22117e3fc, 7.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 2 months ago)

to help with debugging expose system info over capabilities

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34 #include "noit_version.h"
35 #include "eventer/eventer.h"
36 #include "noit_listener.h"
37 #include "utils/noit_hash.h"
38 #include "utils/noit_log.h"
39 #include "utils/noit_sem.h"
40 #include "noit_capabilities_listener.h"
41 #include "noit_module.h"
42 #include "noit_check.h"
43 #include "noit_xml.h"
44
45 #include <unistd.h>
46 #include <sys/ioctl.h>
47 #include <errno.h>
48 #include <sys/utsname.h>
49
50 #include <libxml/xmlsave.h>
51 #include <libxml/tree.h>
52
53 typedef struct noit_capsvc_closure {
54   char *buff;
55   size_t written;
56   size_t towrite;
57 } noit_capsvc_closure_t;
58
59 void
60 noit_capabilities_listener_init() {
61   eventer_name_callback("capabilities_transit/1.0", noit_capabilities_handler);
62   noit_control_dispatch_delegate(noit_control_dispatch,
63                                  NOIT_CAPABILITIES_SERVICE,
64                                  noit_capabilities_handler);
65 }
66
67 static void
68 noit_capabilities_tobuff(noit_capsvc_closure_t *cl, eventer_func_t curr) {
69     struct utsname utsn;
70     char vbuff[128], bwstr[4];
71     noit_hash_table *lc;
72     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
73     const char *k;
74     int klen;
75     void *data;
76     struct timeval now;
77
78     xmlDocPtr xmldoc;
79     xmlNodePtr root, cmds, bi, ri;
80
81     /* fill out capabilities */
82
83     /* Create an XML Document */
84     xmldoc = xmlNewDoc((xmlChar *)"1.0");
85     root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)"noit_capabilities", NULL);
86     xmlDocSetRootElement(xmldoc, root);
87
88     /* Fill in the document */
89     noit_build_version(vbuff, sizeof(vbuff));
90     xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff);
91
92     snprintf(bwstr, sizeof(bwstr), "%d", (int)sizeof(void *)*8);
93     /* Build info */
94     bi = xmlNewNode(NULL, (xmlChar *)"unameBuild");
95     xmlSetProp(bi, (xmlChar *)"bitwidth", (xmlChar *)bwstr);
96     xmlAddChild(root, bi);
97     xmlNewTextChild(bi, NULL, (xmlChar *)"sysname", (xmlChar *)UNAME_S);
98     xmlNewTextChild(bi, NULL, (xmlChar *)"nodename", (xmlChar *)UNAME_N);
99     xmlNewTextChild(bi, NULL, (xmlChar *)"release", (xmlChar *)UNAME_R);
100     xmlNewTextChild(bi, NULL, (xmlChar *)"version", (xmlChar *)UNAME_V);
101     xmlNewTextChild(bi, NULL, (xmlChar *)"machine", (xmlChar *)UNAME_M);
102
103     /* Run info */
104     ri = xmlNewNode(NULL, (xmlChar *)"unameRun");
105     xmlSetProp(ri, (xmlChar *)"bitwidth", (xmlChar *)bwstr);
106     xmlAddChild(root, ri);
107     if(uname(&utsn)) {
108       xmlNewTextChild(ri, NULL, (xmlChar *)"error", (xmlChar *)strerror(errno));
109     } else {
110       xmlNewTextChild(ri, NULL, (xmlChar *)"sysname", (xmlChar *)utsn.sysname);
111       xmlNewTextChild(ri, NULL, (xmlChar *)"nodename", (xmlChar *)utsn.nodename);
112       xmlNewTextChild(ri, NULL, (xmlChar *)"release", (xmlChar *)utsn.release);
113       xmlNewTextChild(ri, NULL, (xmlChar *)"version", (xmlChar *)utsn.version);
114       xmlNewTextChild(ri, NULL, (xmlChar *)"machine", (xmlChar *)utsn.machine);
115     }
116
117     /* time (poor man's time check) */
118     gettimeofday(&now, NULL);
119     snprintf(vbuff, sizeof(vbuff), "%llu.%03d", (unsigned long long)now.tv_sec,
120              (int)(now.tv_usec / 1000));
121     xmlNewTextChild(root, NULL, (xmlChar *)"current_time", (xmlChar *)vbuff);
122
123     cmds = xmlNewNode(NULL, (xmlChar *)"services");
124     xmlAddChild(root, cmds);
125     lc = noit_listener_commands();
126     while(noit_hash_next(lc, &iter, &k, &klen, &data)) {
127       xmlNodePtr cnode;
128       char hexcode[11];
129       const char *name;
130       eventer_func_t *f = (eventer_func_t *)k;
131       noit_hash_table *sc = (noit_hash_table *)data;
132       noit_hash_iter sc_iter = NOIT_HASH_ITER_ZERO;
133       const char *sc_k;
134       int sc_klen;
135       void *sc_data;
136
137       name = eventer_name_for_callback(*f);
138       cnode = xmlNewNode(NULL, (xmlChar *)"service");
139       xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL);
140       if(*f == curr)
141         xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true");
142       xmlAddChild(cmds, cnode);
143       while(noit_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) {
144         xmlNodePtr scnode;
145         char *name_copy, *version = NULL;
146         eventer_func_t *f = (eventer_func_t *)sc_data;
147
148         snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k));
149         name = eventer_name_for_callback(*f);
150         name_copy = strdup(name ? name : "[[unknown]]");
151         version = strchr(name_copy, '/');
152         if(version) *version++ = '\0';
153
154         scnode = xmlNewNode(NULL, (xmlChar *)"command");
155         xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy);
156         if(version)
157           xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version);
158         xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode);
159         xmlAddChild(cnode, scnode);
160         free(name_copy);
161       }
162     }
163
164     /* Write it out to a buffer and copy it for writing */
165     cl->buff = noit_xmlSaveToBuffer(xmldoc);
166     cl->towrite = strlen(cl->buff);
167
168     /* Clean up after ourselves */
169     xmlFreeDoc(xmldoc);
170 }
171
172 int
173 noit_capabilities_handler(eventer_t e, int mask, void *closure,
174                           struct timeval *now) {
175   int newmask = EVENTER_WRITE | EVENTER_EXCEPTION;
176   acceptor_closure_t *ac = closure;
177   noit_capsvc_closure_t *cl = ac->service_ctx;
178
179   if(mask & EVENTER_EXCEPTION) {
180 socket_error:
181     /* Exceptions cause us to simply snip the connection */
182 cleanup_shutdown:
183     eventer_remove_fd(e->fd);
184     e->opset->close(e->fd, &newmask, e);
185     if(cl) {
186       if(cl->buff) free(cl->buff);
187       free(cl);
188     }
189     if(ac) acceptor_closure_free(ac);
190     return 0;
191   }
192
193   if(!ac->service_ctx) {
194     cl = ac->service_ctx = calloc(1, sizeof(*cl));
195     noit_capabilities_tobuff(cl, ac->dispatch);
196   }
197
198   while(cl->towrite > cl->written) {
199     int len;
200     while((len = e->opset->write(e->fd, cl->buff + cl->written,
201                                  cl->towrite - cl->written,
202                                  &newmask, e)) == -1 && errno == EINTR);
203     if(len < 0) {
204       if(errno == EAGAIN) return newmask | EVENTER_EXCEPTION;
205       goto socket_error;
206     }
207     cl->written += len;
208   }
209   goto cleanup_shutdown;
210 }
211
212
Note: See TracBrowser for help on using the browser.