1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Alvaro Lopez Ortega <alvaro@alobbs.com>
7 * Stefan de Konink <stefan@konink.de>
9 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include "handler_virt.h"
27 #include "handler_avahi.h"
28 #include <cherokee/cherokee.h>
30 /* Plug-in initialization
32 * In this function you can use any of these:
33 * http_delete | http_get | http_post | http_put
35 * For a full list: cherokee_http_method_t
37 * It is what your handler to be implements.
40 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt
, http_get
| http_post
);
43 /* Methods implementation
46 props_free (cherokee_handler_virt_props_t
*props
)
48 return cherokee_module_props_free_base (MODULE_PROPS(props
));
53 cherokee_handler_virt_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
56 cherokee_handler_virt_props_t
*props
;
58 /* Instance a new property object
61 if (*_props
== NULL
) {
62 CHEROKEE_NEW_STRUCT (n
, handler_virt_props
);
64 cherokee_handler_avahi_props_init_base (PROP_AVAHI(n
), MODULE_PROPS_FREE(props_free
));
66 /* Look at handler_virt.h
67 * This is an virt of configuration.
69 n
->authenticate
= true; /* by default we are secure! */
70 n
->read_only
= true; /* by default we are secure! */
71 cherokee_buffer_init (&n
->xsl
); /* we support a custom header */
73 *_props
= MODULE_PROPS(n
);
76 props
= PROP_VIRT(*_props
);
78 cherokee_config_node_foreach (i
, conf
) {
79 cherokee_config_node_t
*subconf
= CONFIG_NODE(i
);
81 if (equal_buf_str (&subconf
->key
, "authenticate")) {
82 props
->authenticate
= atoi(subconf
->val
.buf
);
84 else if (equal_buf_str (&subconf
->key
, "read_only")) {
85 props
->read_only
= atoi(subconf
->val
.buf
);
87 else if (equal_buf_str (&subconf
->key
, "xsl")) {
88 cherokee_buffer_add_buffer (&props
->xsl
, &subconf
->val
);
95 return cherokee_handler_avahi_configure (conf
, srv
, _props
);
100 cherokee_handler_virt_init (cherokee_handler_virt_t
*hdl
)
106 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
107 cherokee_buffer_init(&hdl
->user
);
108 cherokee_buffer_init(&hdl
->vm
);
110 hdl
->action
= nothing
;
112 cherokee_buffer_add (&conn
->pathinfo
,
113 conn
->request
.buf
+ conn
->web_directory
.len
,
114 conn
->request
.len
- conn
->web_directory
.len
);
116 this = conn
->pathinfo
.buf
+ 1;
117 next
= strchr(this, '/');
120 if ((!next
&& (this && (len
= strlen(this)) == 0)) || (next
&& ((len
= next
- this) == 0)) )
121 hdl
->action
= showall
;
123 cherokee_buffer_add (&hdl
->user
, this, len
);
126 if (HDL_VIRT_PROPS(hdl
)->authenticate
) {
127 if (!conn
->validator
||
129 (!cherokee_buffer_cmp_buf(&conn
->validator
->user
, &hdl
->user
) &&
130 !(isroot
= cherokee_buffer_cmp (&conn
->validator
->user
, "root", 4))))) {
131 hdl
->action
= nothing
; /* just in case */
132 conn
->error_code
= http_unauthorized
;
139 if (hdl
->action
== showall
) {
141 hdl
->action
= nothing
;
142 conn
->error_code
= http_unauthorized
;
145 return virt_build_page(hdl
);
151 hdl
->action
= showuservms
;
152 return virt_build_page(hdl
);
155 next
= strchr(this, '/');
157 if (!next
&& (this && (len
= strlen(this)) == 0) || (next
&& ((len
= next
- this) == 0)) ) {
158 hdl
->action
= showuservms
;
159 return virt_build_page(hdl
);
163 cherokee_buffer_add (&hdl
->vm
, this, len
);
166 hdl
->action
= domainGetXMLDesc
;
167 return virt_build_page(hdl
);
170 next
= strchr(this, '/');
172 if (!next
&& (this && (len
= strlen(this)) == 0) || (next
&& ((len
= next
- this) == 0)) ) {
173 hdl
->action
= domainGetXMLDesc
;
174 return virt_build_page(hdl
);
178 hdl
->action
= not_implemented
;
179 switch (conn
->header
.method
) {
181 if (strncmp(this, "virDomain", 9) == 0) {
182 if (strncmp(this+9, "Get", 3) == 0) {
183 if (strcmp(this+12, "ID") == 0) hdl
->action
= domainGetID
;
184 else if (strcmp(this+12, "Name") == 0) hdl
->action
= domainGetName
;
185 else if (strcmp(this+12, "MaxMemory") == 0) hdl
->action
= domainGetMaxMemory
;
186 else if (strcmp(this+12, "MaxVcpus") == 0) hdl
->action
= domainGetMaxVcpus
;
187 else if (strcmp(this+12, "OSType") == 0) hdl
->action
= domainGetOSType
;
188 else if (strcmp(this+12, "UUID") == 0) hdl
->action
= domainGetUUID
;
189 else if (strcmp(this+12, "UUIDString") == 0) hdl
->action
= domainGetUUIDString
;
190 else if (strcmp(this+12, "XMLDesc") == 0) hdl
->action
= domainGetXMLDesc
;
192 else if (strcmp(this+9, "Reboot") == 0) hdl
->action
= domainReboot
;
193 else if (strcmp(this+9, "Shutdown") == 0) hdl
->action
= domainShutdown
;
199 cherokee_post_get_len (&conn
->post
, &postl
);
201 if (postl
<= 0 || postl
>= (INT_MAX
-1)) {
202 conn
->error_code
= http_bad_request
;
206 if (strncmp(this, "virDomain", 9) == 0) {
207 if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice
;
208 if (strcmp(this+9, "DetachDevice") == 0) hdl
->action
= domainDetachDevice
;
217 if (hdl
->action
<= 0) {
218 conn
->error_code
= http_bad_request
;
223 return virt_build_page(hdl
);
227 cherokee_handler_virt_free (cherokee_handler_virt_t
*hdl
)
229 cherokee_buffer_mrproper (&hdl
->buffer
);
230 cherokee_buffer_mrproper (&hdl
->user
);
231 cherokee_buffer_mrproper (&hdl
->vm
);
237 cherokee_handler_virt_step (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
239 cherokee_buffer_add_buffer (buffer
, &hdl
->buffer
);
240 return ret_eof_have_data
;
244 cherokee_handler_virt_add_headers (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
246 cherokee_buffer_add_va (buffer
, "Content-Length: %d"CRLF
, hdl
->buffer
.len
);
248 if (hdl
->action
> xml
)
249 cherokee_buffer_add_str (buffer
, "Content-Type: application/xml"CRLF
);
251 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
258 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
259 virConnectPtr conn = NULL;
260 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
261 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
263 cherokee_buffer_add_va (&uri, "xen://%s/", value);
265 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
266 if (!(conn = virConnectOpen (uri.buf))) {
271 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
275 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
278 char *xml = virDomainGetXMLDesc(dom, 0);
279 cherokee_buffer_add(buf, xml, strlen(xml));
281 virConnectClose(conn);
284 cherokee_buffer_mrproper(&uri);
290 virt_virt_function(cherokee_handler_virt_t
*hdl
, virDomainPtr dom
) {
291 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
292 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
294 switch (hdl
->action
) {
295 case domainAttachDevice
: {
298 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
299 cherokee_post_get_len (&conn
->post
, &postl
);
300 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
301 if ((result
= virDomainAttachDevice(dom
, (const char *) post
.buf
)) != 0)
302 conn
->error_code
= http_internal_error
;
304 cherokee_buffer_mrproper(&post
);
305 cherokee_buffer_add_long10(buf
, result
);
309 case domainDetachDevice
: {
312 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
313 cherokee_post_get_len (&conn
->post
, &postl
);
314 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
315 if ((result
= virDomainDetachDevice(dom
, (const char *) post
.buf
)) != 0) {
316 conn
->error_code
= http_internal_error
;
318 cherokee_buffer_mrproper(&post
);
319 cherokee_buffer_add_long10(buf
, result
);
324 cherokee_buffer_add_ulong10(buf
, virDomainGetID(dom
));
327 case domainGetMaxMemory
: {
328 cherokee_buffer_add_ulong10(buf
, virDomainGetMaxMemory (dom
));
331 case domainGetMaxVcpus
: {
332 cherokee_buffer_add_long10(buf
, virDomainGetMaxVcpus (dom
));
335 case domainGetName
: {
336 const char *name
= virDomainGetName (dom
);
337 cherokee_buffer_add(buf
, name
, strlen(name
));
340 case domainGetUUID
: {
341 unsigned char uuid
[VIR_UUID_BUFLEN
];
342 if (virDomainGetUUID(dom
, uuid
) == 0) {
343 cherokee_buffer_add_str(buf
, uuid
);
345 conn
->error_code
= http_internal_error
;
350 case domainGetUUIDString
: {
351 unsigned char uuid
[VIR_UUID_STRING_BUFLEN
];
352 if (virDomainGetUUIDString(dom
, uuid
) == 0) {
353 cherokee_buffer_add_str(buf
, uuid
);
355 conn
->error_code
= http_internal_error
;
362 cherokee_buffer_add_long10(buf
, virDomainReboot (dom
, 0));
366 case domainShutdown
: {
367 cherokee_buffer_add_long10(buf
, virDomainShutdown (dom
));
372 case domainGetOSType
: {
373 char *ostype
= virDomainGetOSType(dom
);
374 cherokee_buffer_add(buf
, ostype
, strlen(ostype
));
379 case domainGetXMLDesc
: {
380 char *xml
= virDomainGetXMLDesc(dom
, 0);
381 cherokee_buffer_add(buf
, xml
, strlen(xml
));
391 virt_virt_do(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*domu
, cherokee_buffer_t
*uri
)
393 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
395 ret_t ret
= ret_error
;
396 virConnectPtr virConn
= NULL
;
399 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
400 virConn
= virConnectOpen (uri
->buf
);
402 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
->buf
))) {
403 conn
->error_code
= http_service_unavailable
;
408 if (!(dom
= virDomainLookupByName(virConn
, domu
->buf
))) {
409 conn
->error_code
= http_not_found
;
411 ret
= virt_virt_function(hdl
, dom
);
413 virConnectClose(virConn
);
419 virt_while (cherokee_buffer_t
*key
, void *value
, void *param
) {
420 cherokee_handler_virt_t
* hdl
= param
;
421 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
422 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
423 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
424 // cherokee_buffer_mrproper(&uri);
426 cherokee_buffer_add_va (&hdl
->buffer
, "<domain><name>%s</name></domain>", key
->buf
);
432 virt_while_user (cherokee_buffer_t
*key
, void *value
, void *param
) {
433 cherokee_handler_virt_t
*hdl
= param
;
434 if (key
->len
> hdl
->user
.len
&& key
->buf
[hdl
->user
.len
] == '_' && strncmp(key
->buf
, hdl
->user
.buf
, hdl
->user
.len
) == 0)
435 return virt_while (key
, value
, param
);
441 virt_build_page (cherokee_handler_virt_t
*hdl
)
444 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
446 if (hdl
->action
> xml
&& HDL_VIRT_PROPS(hdl
)->xsl
.len
> 0)
447 cherokee_buffer_add_va (&hdl
->buffer
, "<?xml version=\"1.0\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n", HDL_VIRT_PROPS(hdl
)->xsl
.buf
);
450 /* First, block the event loop */
451 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
452 switch (hdl
->action
) {
454 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
455 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while
, hdl
, NULL
, NULL
);
456 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
461 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
462 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while_user
, hdl
, NULL
, NULL
);
463 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
468 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
469 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
470 cherokee_buffer_t
*hostname
= NULL
;
471 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
472 if ((ret
= cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl
)->entries
, domu
.buf
, (void **) &hostname
)) == ret_error
) {
473 hdl
->action
= nothing
;
474 conn
->error_code
= http_not_found
;
477 cherokee_buffer_add_va (&uri
, "xen://%s/", hostname
->buf
);
478 ret
= virt_virt_do(hdl
, &domu
, &uri
);
479 cherokee_buffer_mrproper(&domu
);
480 cherokee_buffer_mrproper(&uri
);
484 /* Finally, unblock the event loop */
485 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
492 cherokee_handler_virt_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
495 CHEROKEE_NEW_STRUCT (n
, handler_virt
);
497 /* Init the base class
500 cherokee_handler_init_base(HANDLER(n
), cnt
, HANDLER_PROPS(props
), PLUGIN_INFO_HANDLER_PTR(virt
));
502 MODULE(n
)->init
= (handler_func_init_t
) cherokee_handler_virt_init
;
503 MODULE(n
)->free
= (module_func_free_t
) cherokee_handler_virt_free
;
504 HANDLER(n
)->step
= (handler_func_step_t
) cherokee_handler_virt_step
;
505 HANDLER(n
)->add_headers
= (handler_func_add_headers_t
) cherokee_handler_virt_add_headers
;
507 HANDLER(n
)->support
= hsupport_length
| hsupport_range
;
509 ret
= cherokee_buffer_init (&n
->buffer
);
510 if (unlikely(ret
!= ret_ok
))
513 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
514 if (unlikely(ret
!= ret_ok
))