root/src/noit_capabilities_listener.c

Revision 068f02cf3f9a4c2da07d38a1554f02352ba4fa11, 4.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

refs #115, split version into its own field

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7 #include "eventer/eventer.h"
8 #include "noit_listener.h"
9 #include "utils/noit_hash.h"
10 #include "utils/noit_log.h"
11 #include "utils/noit_sem.h"
12 #include "noit_capabilities_listener.h"
13 #include "noit_module.h"
14 #include "noit_check.h"
15
16 #include <unistd.h>
17 #include <sys/ioctl.h>
18 #include <errno.h>
19
20 #include <libxml/xmlsave.h>
21 #include <libxml/tree.h>
22
23 typedef struct noit_capsvc_closure {
24   char *buff;
25   size_t written;
26   size_t towrite;
27 } noit_capsvc_closure_t;
28
29 void
30 noit_capabilities_listener_init() {
31   eventer_name_callback("capabilities_transit/1.0", noit_capabilities_handler);
32   noit_control_dispatch_delegate(noit_control_dispatch,
33                                  NOIT_CAPABILITIES_SERVICE,
34                                  noit_capabilities_handler);
35 }
36
37 int
38 noit_capabilities_handler(eventer_t e, int mask, void *closure,
39                           struct timeval *now) {
40   int newmask = EVENTER_WRITE | EVENTER_EXCEPTION;
41   acceptor_closure_t *ac = closure;
42   noit_capsvc_closure_t *cl = ac->service_ctx;
43
44   if(mask & EVENTER_EXCEPTION) {
45 socket_error:
46     /* Exceptions cause us to simply snip the connection */
47 cleanup_shutdown:
48     eventer_remove_fd(e->fd);
49     e->opset->close(e->fd, &newmask, e);
50     if(cl) {
51       if(cl->buff) free(cl->buff);
52       free(cl);
53     }
54     if(ac) acceptor_closure_free(ac);
55     return 0;
56   }
57
58   if(!ac->service_ctx) {
59     char vbuff[128];
60     noit_hash_table *lc;
61     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
62     const char *k;
63     int klen;
64     void *data;
65
66     xmlDocPtr xmldoc;
67     xmlNodePtr root, cmds;
68     xmlBufferPtr xmlbuffer;
69     xmlSaveCtxtPtr savectx;
70
71     cl = ac->service_ctx = calloc(1, sizeof(*cl));
72     /* fill out capabilities */
73     noit_build_version(vbuff, sizeof(vbuff));
74
75     /* Create an XML Document */
76     xmldoc = xmlNewDoc((xmlChar *)"1.0");
77     root = xmlNewDocNode(xmldoc, NULL, (xmlChar *)"noitd_capabilities", NULL);
78     xmlDocSetRootElement(xmldoc, root);
79
80     /* Fill in the document */
81     xmlNewTextChild(root, NULL, (xmlChar *)"version", (xmlChar *)vbuff);
82
83     cmds = xmlNewNode(NULL, (xmlChar *)"services");
84     xmlAddChild(root, cmds);
85     lc = noit_listener_commands();
86     while(noit_hash_next(lc, &iter, &k, &klen, &data)) {
87       xmlNodePtr cnode;
88       char hexcode[10];
89       const char *name;
90       eventer_func_t *f = (eventer_func_t *)k;
91       noit_hash_table *sc = (noit_hash_table *)data;
92       noit_hash_iter sc_iter = NOIT_HASH_ITER_ZERO;
93       const char *sc_k;
94       int sc_klen;
95       void *sc_data;
96
97       name = eventer_name_for_callback(*f);
98       cnode = xmlNewNode(NULL, (xmlChar *)"service");
99       xmlSetProp(cnode, (xmlChar *)"name", name ? (xmlChar *)name : NULL);
100       if(*f == ac->dispatch)
101         xmlSetProp(cnode, (xmlChar *)"connected", (xmlChar *)"true");
102       xmlAddChild(cmds, cnode);
103       while(noit_hash_next(sc, &sc_iter, &sc_k, &sc_klen, &sc_data)) {
104         xmlNodePtr scnode;
105         char *name_copy, *version = NULL;
106         eventer_func_t *f = (eventer_func_t *)sc_data;
107
108         snprintf(hexcode, sizeof(hexcode), "0x%08x", *((u_int32_t *)sc_k));
109         name = eventer_name_for_callback(*f);
110         name_copy = strdup(name ? name : "[[unknown]]");
111         version = strchr(name_copy, '/');
112         if(version) *version++ = '\0';
113
114         scnode = xmlNewNode(NULL, (xmlChar *)"command");
115         xmlSetProp(scnode, (xmlChar *)"name", (xmlChar *)name_copy);
116         if(version)
117           xmlSetProp(scnode, (xmlChar *)"version", (xmlChar *)version);
118         xmlSetProp(scnode, (xmlChar *)"code", (xmlChar *)hexcode);
119         xmlAddChild(cnode, scnode);
120         free(name_copy);
121       }
122     }
123
124     /* Write it out to a buffer and copy it for writing */
125     xmlbuffer = xmlBufferCreate();
126     savectx = xmlSaveToBuffer(xmlbuffer, "utf8", 1);
127     xmlSaveDoc(savectx, xmldoc);
128     xmlSaveClose(savectx);
129     cl->buff = strdup((const char *)xmlBufferContent(xmlbuffer));
130     cl->towrite = xmlBufferLength(xmlbuffer);
131
132     /* Clean up after ourselves */
133     xmlBufferFree(xmlbuffer);
134     xmlFreeDoc(xmldoc);
135   }
136
137   while(cl->towrite > cl->written) {
138     int len;
139     while((len = e->opset->write(e->fd, cl->buff + cl->written,
140                                  cl->towrite - cl->written,
141                                  &newmask, e)) == -1 && errno == EINTR);
142     if(len < 0) {
143       if(errno == EAGAIN) return newmask | EVENTER_EXCEPTION;
144       goto socket_error;
145     }
146     cl->written += len;
147   }
148   goto cleanup_shutdown;
149
150   return 0;
151 }
Note: See TracBrowser for help on using the browser.