Hi,

I am trying to develop PHP binding for Libvirt API. As discussed previously on the list the best way is to create a ZEND extension. There is a great tutorial on the net ( http://devzone.zend.com/tag/Extension ) and PHP provides a lot of macros and functions to make extension writing easier. I've implemented functions for connecting, listing domains, getting info about domains and node, dumping domain XML, some basic domain life-cycle actions and very basic error reporting. Before moving to other functions I need to solve a few issues :-)

The biggest issue is that PHP used from webserver can (and usually does) run multithread. One thread can process more than one request and the threads can run in parallel. PHP/ZEND provides "tools" to solve this. It provides "request-global" variables, resources (containers for objects like file handles or connection pointers) and much more. In single threaded environment (like calling from command line) all these fallback to usual behavior. In addition ZEND has its own memory manager to be able to better manage the memory on per request basis (functions are called emalloc(), efree(),...). One can still use malloc() and free() but this is bypassing the ZEND memory manager. Free()ing emalloced memory or vice versa leads to crash.

So one thing is that every memory allocated by libvirt (using malloc()) I need to copy to memory allocated using emalloc(). Also every memory, that would be free()ed by libvirt I need to malloc() and copy from emmaloc()ed memory. The first one is done by simple macro:

#define RECREATE_STRING_WITH_E(str_out, str_in) \       
         str_out = estrndup(str_in, strlen(str_in)); \
         free(str_in);  

The second case I encountered only on authentication callback and I use simple strndup() to copy it for libvirt.

When running from command line everything seems to work fine. This is of course singlethreaded and potential resource leaks need not to cause a problem. However when running from webserver, the result is much more interesting. When connecting to qemu:///system (via local socket) using
<?
libvirt_connect($uri,true);
?>
I can crash the libvirt daemon after cca 10 page reloads - sometimes with message Apr 13 15:32:44 kvmtest kernel: libvirtd[8263]: segfault at 4 ip 00000039d7223fc0 sp 00007fa6fbc29a88 error 6 in libdbus-1.so.3.4.0[39d7200000+3c000]
in system log, sometimes without any message.
(When running the same script from command line it worked for 1000 executions without noticing a problem).

When connecting to qemu+tcp:///system using credentials (explained later):
<?
libvirt_connect($uri,true,Array(VIR_CRED_AUTHNAME=>"fred",VIR_CRED_PASSPHRASE=>"fred"));
?>

It works but httpd processes open a lot pipes and after a few hours with page refreshing every 10 sec I even ran into error: [Mon Apr 13 02:40:26 2009] [error] [client 10.38.25.152] PHP Warning: libvirt_connect() unable to make pipe: Too many open files

Next issue I am not sure about is callbacks. I need them mainly for authentication. As PHP is intended to run the whole script non-interactively at most times, I've created this solution. When calling the libvirt_connect() PHP function you can provide list of credentials in form of an array Array(VIR_CRED_AUTHNAME=>"fred",VIR_CRED_PASSPHRASE=>"fred"). This PHP array is parsed to C array and this prepopulated array is passed to my authentication callback function. That function receives the requested credential, looks it up in the provided array and returns it. I think this suits more the PHP nature but in future I may provide real callback solution. Little trouble is that libvirt free()s the values returned by callback so I need to copy them to malloc()ed memory. I am not sure about multithread safety of callback functions but I think that if the function only obtains the parameters via cbdata and operates only with them then it should be safe. However sometimes I get error: [Mon Apr 13 14:19:48 2009] [error] [client 10.38.25.152] PHP Warning: libvirt_connect(): Failed to collect auth credentials
and I need to restart http daemon for a few times to make it work again.

The last trouble is with error callback, where I am not sure whether it is thread safe. I need to call PHP function for reporting error, storing the error in "global" variable for next use and the PHP may even terminate the whole processing of the request...

And if you are still reading then I can point you to http://phplibvirt.cybersales.cz/ where you can download the source code and browse the documentation - you can find there list of implemented functions and brief instructions how to install the extension. But be warned it really can crash your libvirt and maybe apache! For completeness: I use Fedora 10 with some rawhide updates:
httpd-2.2.11-6.x86_64
php-5.2.9-1.fc11.x86_64
php-devel-5.2.9-1.fc11.x86_64
libvirt-0.6.0-2.fc11.x86_64
qemu-0.9.1-12.fc11.x86_64
libvirt-devel-0.6.0-2.fc11.x86_64
php-cli-5.2.9-1.fc11.x86_64
kvm-83-5.fc10.x86_64
php-common-5.2.9-1.fc11.x86_64


Radek

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to