ia64/xen-unstable

changeset 4676:16efdf7bbd57

bitkeeper revision 1.1390 (4270bf1dDv9UZF9rYSk8GFK5ZxP09Q)

Merge http://xen.bkbits.net:8080/xeno-unstable.bk
into gandalf.hpl.hp.com:/var/bk/xeno-unstable.bk
author xenbk@gandalf.hpl.hp.com
date Thu Apr 28 10:46:53 2005 +0000 (2005-04-28)
parents 3000c660f103 7719c5e6954d
children f85eb51dc313
files .rootkeys tools/python/setup.py tools/python/xen/lowlevel/xu/xu.c tools/python/xen/util/console_client.py tools/python/xen/web/SrvBase.py tools/python/xen/web/SrvDir.py tools/python/xen/web/__init__.py tools/python/xen/web/connection.py tools/python/xen/web/http.py tools/python/xen/web/httpserver.py tools/python/xen/web/protocol.py tools/python/xen/web/reactor.py tools/python/xen/web/resource.py tools/python/xen/web/static.py tools/python/xen/web/tcp.py tools/python/xen/web/unix.py tools/python/xen/xend/EventServer.py tools/python/xen/xend/EventTypes.py tools/python/xen/xend/XendAsynchProtocol.py tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendConsole.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainConfig.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendMigrate.py tools/python/xen/xend/XendProtocol.py tools/python/xen/xend/XendRoot.py tools/python/xen/xend/scheduler.py tools/python/xen/xend/server/SrvBase.py tools/python/xen/xend/server/SrvConsole.py tools/python/xen/xend/server/SrvConsoleDir.py tools/python/xen/xend/server/SrvDaemon.py tools/python/xen/xend/server/SrvDeviceDir.py tools/python/xen/xend/server/SrvDir.py tools/python/xen/xend/server/SrvDmesg.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/SrvDomainDir.py tools/python/xen/xend/server/SrvEventDir.py tools/python/xen/xend/server/SrvNode.py tools/python/xen/xend/server/SrvRoot.py tools/python/xen/xend/server/SrvServer.py tools/python/xen/xend/server/SrvUsbif.py tools/python/xen/xend/server/SrvVnetDir.py tools/python/xen/xend/server/SrvXendLog.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/channel.py tools/python/xen/xend/server/console.py tools/python/xen/xend/server/controller.py tools/python/xen/xend/server/domain.py tools/python/xen/xend/server/event.py tools/python/xen/xend/server/messages.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/server/pciif.py tools/python/xen/xend/server/usbif.py tools/python/xen/xend/util.py tools/python/xen/xm/create.py tools/python/xen/xm/main.py
line diff
     1.1 --- a/.rootkeys	Thu Apr 28 08:56:40 2005 +0000
     1.2 +++ b/.rootkeys	Thu Apr 28 10:46:53 2005 +0000
     1.3 @@ -883,19 +883,28 @@ 4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/pyt
     1.4  40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py
     1.5  41dde8b0yuJX-S79w4xJKxBQ-Mhp1A tools/python/xen/util/memmap.py
     1.6  4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py
     1.7 +4267a9b16u4IEPhjRryesk6A17sobA tools/python/xen/web/SrvBase.py
     1.8 +4267a9b1FfCUjW7m9anLERcx9lwhJg tools/python/xen/web/SrvDir.py
     1.9 +4267a9b1uMXIfzB6-81ZLqMCyTgJmw tools/python/xen/web/__init__.py
    1.10 +4267a9b1i_zVq36tt2iQejVuR6DGFw tools/python/xen/web/connection.py
    1.11 +4267a9b1KzSWZwWKYrGRc9bUhow_7Q tools/python/xen/web/http.py
    1.12 +4267a9b1KWNZhhmZnySe_nLASwO47g tools/python/xen/web/httpserver.py
    1.13 +4267a9b21miObgEJLAgtLTAKRBK8uQ tools/python/xen/web/protocol.py
    1.14 +4267a9b2pA22-lF37dB7XfapMNroGw tools/python/xen/web/reactor.py
    1.15 +4267a9b2AbH-azu7SXIUETXC39tu-A tools/python/xen/web/resource.py
    1.16 +4267a9b21XhDCpkVXtgea3ko8uS16g tools/python/xen/web/static.py
    1.17 +4267a9b2q7UA0cU5-KATCWX6O-TKsA tools/python/xen/web/tcp.py
    1.18 +4267a9b2XqvzKDWxfAdV22c3mO6NHA tools/python/xen/web/unix.py
    1.19  40c9c468SNuObE_YWARyS0hzTPSzKg tools/python/xen/xend/Args.py
    1.20  41597996WNvJA-DVCBmc0xU9w_XmoA tools/python/xen/xend/Blkctl.py
    1.21  40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py
    1.22 -40c9c468U8EVl0d3G--8YXVg6VJD3g tools/python/xen/xend/EventTypes.py
    1.23  40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py
    1.24  40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/python/xen/xend/Vifctl.py
    1.25 -4151594bBq8h-bwTfEt8dbBuojMtcA tools/python/xen/xend/XendAsynchProtocol.py
    1.26  40c9c4688m3eqnC8fhLu1APm36VOVA tools/python/xen/xend/XendClient.py
    1.27  40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/python/xen/xend/XendConsole.py
    1.28  40c9c468WnXs6eOUSff23IIGI4kMfQ tools/python/xen/xend/XendDB.py
    1.29  40eee3a0sPO-WUu34uHUXOC7HliDGw tools/python/xen/xend/XendDmesg.py
    1.30  40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/python/xen/xend/XendDomain.py
    1.31 -40c9c468bbKq3uC7_fuNUkiMMjArdw tools/python/xen/xend/XendDomainConfig.py
    1.32  40c9c4685ykq87_n1kVUbMr9flx9fg tools/python/xen/xend/XendDomainInfo.py
    1.33  40f50d99YiiaMI1fZBh1VCDFLD57qg tools/python/xen/xend/XendError.py
    1.34  40ffc44eGsgTEY355E3nN4mPLZHhMQ tools/python/xen/xend/XendLogging.py
    1.35 @@ -906,20 +915,16 @@ 40c9c4686jruMyZIqiaZRMiMoqMJtg tools/pyt
    1.36  40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py
    1.37  40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py
    1.38  40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py
    1.39 -40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py
    1.40 +4266169ezWIlXSfY50n6HSoVFbosmw tools/python/xen/xend/scheduler.py
    1.41  40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py
    1.42  40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py
    1.43  40c9c468woSmBByfeXA4o_jGf2gCgA tools/python/xen/xend/server/SrvDaemon.py
    1.44 -40c9c468kACsmkqjxBWKHRo071L26w tools/python/xen/xend/server/SrvDeviceDir.py
    1.45 -40c9c468EQZJVkCLds-OhesJVVyZbQ tools/python/xen/xend/server/SrvDir.py
    1.46  40eee3a0m38EwYXfCSFIjWNwG6jx_A tools/python/xen/xend/server/SrvDmesg.py
    1.47  40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/python/xen/xend/server/SrvDomain.py
    1.48  40c9c469WzajDjutou3X7FmL9hMf3g tools/python/xen/xend/server/SrvDomainDir.py
    1.49 -40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/python/xen/xend/server/SrvEventDir.py
    1.50  40c9c4694eu5759Dehr4Uhakei0EMg tools/python/xen/xend/server/SrvNode.py
    1.51  40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py
    1.52  40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py
    1.53 -41ee5e8cFlODpYxhBMZqo9ZgGtcHbg tools/python/xen/xend/server/SrvUsbif.py
    1.54  40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py
    1.55  4108f181GtRoD1U9TBuJXMfBbGJwdQ tools/python/xen/xend/server/SrvXendLog.py
    1.56  40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py
    1.57 @@ -927,13 +932,13 @@ 40c9c4692hckPol_EK0EGB16ZyDsyQ tools/pyt
    1.58  40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py
    1.59  40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py
    1.60  40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py
    1.61 -40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py
    1.62 +4266169exkN9o3hA8vxe8Er0BZv1Xw tools/python/xen/xend/server/event.py
    1.63  40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
    1.64  40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
    1.65  40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py
    1.66 +4266169eI_oX3YBjwaeC0V-THBRnjg tools/python/xen/xend/server/pciif.py
    1.67  41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py
    1.68  40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
    1.69 -4189125cL90jKSOcBJ3Vx4nWGiXXvA tools/python/xen/xend/util.py
    1.70  40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
    1.71  40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
    1.72  40f552eariuUSB9TWqCPnDLz5zvxMw tools/python/xen/xm/destroy.py
     2.1 --- a/tools/python/setup.py	Thu Apr 28 08:56:40 2005 +0000
     2.2 +++ b/tools/python/setup.py	Thu Apr 28 10:46:53 2005 +0000
     2.3 @@ -43,6 +43,7 @@ setup(name            = 'xen',
     2.4                           'xen.xend.server',
     2.5                           'xen.sv',
     2.6                           'xen.xm',
     2.7 +                         'xen.web',
     2.8                           ],
     2.9        ext_package = "xen.lowlevel",
    2.10        ext_modules = [ xc, xu ]
     3.1 --- a/tools/python/xen/lowlevel/xu/xu.c	Thu Apr 28 08:56:40 2005 +0000
     3.2 +++ b/tools/python/xen/lowlevel/xu/xu.c	Thu Apr 28 10:46:53 2005 +0000
     3.3 @@ -304,20 +304,6 @@ static PyObject *xu_notifier_read(PyObje
     3.4      return Py_None;
     3.5  }
     3.6  
     3.7 -/* this is now a NOOP */
     3.8 -static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
     3.9 -{
    3.10 -    Py_INCREF(Py_None);
    3.11 -    return Py_None;
    3.12 -}
    3.13 -
    3.14 -/* this is now a NOOP */
    3.15 -static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
    3.16 -{
    3.17 -    Py_INCREF(Py_None);
    3.18 -    return Py_None;
    3.19 -}
    3.20 -
    3.21  static PyObject *xu_notifier_bind_virq(PyObject *self, 
    3.22              PyObject *args, PyObject *kwds)
    3.23  {
    3.24 @@ -366,13 +352,6 @@ static PyObject *xu_notifier_virq_send(P
    3.25      return PyInt_FromLong(kmsg.u.virq.port);
    3.26  }
    3.27  
    3.28 -/* this is now a NOOP */
    3.29 -static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
    3.30 -{
    3.31 -    Py_INCREF(Py_None);
    3.32 -    return Py_None;
    3.33 -}
    3.34 -
    3.35  static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
    3.36  {
    3.37      return PyInt_FromLong(xcs_data_fd);
    3.38 @@ -384,21 +363,6 @@ static PyMethodDef xu_notifier_methods[]
    3.39        METH_VARARGS,
    3.40        "Read a @port with pending notifications.\n" },
    3.41  
    3.42 -    { "unmask", 
    3.43 -      (PyCFunction)xu_notifier_unmask,
    3.44 -      METH_VARARGS,
    3.45 -      "Unmask notifications for a @port.\n" },
    3.46 -
    3.47 -    { "bind", 
    3.48 -      (PyCFunction)xu_notifier_bind,
    3.49 -      METH_VARARGS,
    3.50 -      "Get notifications for a @port.\n" },
    3.51 -
    3.52 -    { "unbind", 
    3.53 -      (PyCFunction)xu_notifier_unbind,
    3.54 -      METH_VARARGS,
    3.55 -      "No longer get notifications for a @port.\n" },
    3.56 -      
    3.57      { "bind_virq",
    3.58        (PyCFunction)xu_notifier_bind_virq,
    3.59        METH_VARARGS | METH_KEYWORDS,
    3.60 @@ -1054,13 +1018,6 @@ typedef struct xu_port_object {
    3.61  
    3.62  static PyObject *port_error;
    3.63  
    3.64 -/* now a NOOP */
    3.65 -static PyObject *xu_port_notify(PyObject *self, PyObject *args)
    3.66 -{
    3.67 -    Py_INCREF(Py_None);
    3.68 -    return Py_None;
    3.69 -}
    3.70 -
    3.71  static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
    3.72  {
    3.73      xu_port_object    *xup = (xu_port_object *)self;
    3.74 @@ -1212,14 +1169,6 @@ static PyObject *xu_port_request_to_read
    3.75      return PyInt_FromLong(found);
    3.76  }
    3.77  
    3.78 -static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
    3.79 -{
    3.80 -    if ( !PyArg_ParseTuple(args, "") )
    3.81 -        return NULL;
    3.82 -
    3.83 -    return PyInt_FromLong(1);
    3.84 -}
    3.85 -
    3.86  static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
    3.87  {
    3.88      xu_port_object   *xup = (xu_port_object *)self;
    3.89 @@ -1243,25 +1192,27 @@ static PyObject *xu_port_response_to_rea
    3.90      return PyInt_FromLong(found);
    3.91  }
    3.92  
    3.93 -static PyObject *xu_port_space_to_write_response(
    3.94 -    PyObject *self, PyObject *args)
    3.95 +static void _xu_port_close(xu_port_object *xup )
    3.96  {
    3.97 -    if ( !PyArg_ParseTuple(args, "") )
    3.98 -        return NULL;
    3.99 -
   3.100 -    return PyInt_FromLong(1);
   3.101 +    if ( xup->connected && xup->remote_dom != 0 )
   3.102 +    {  
   3.103 +        xcs_msg_t kmsg;
   3.104 +        kmsg.type = XCS_CIF_FREE_CC;
   3.105 +        kmsg.u.interface.dom         = xup->remote_dom;
   3.106 +        kmsg.u.interface.local_port  = xup->local_port; 
   3.107 +        kmsg.u.interface.remote_port = xup->remote_port;
   3.108 +        xcs_ctrl_send(&kmsg);
   3.109 +        xcs_ctrl_read(&kmsg);
   3.110 +        xup->connected = 0;
   3.111 +    }
   3.112  }
   3.113  
   3.114 -/* NOOP */
   3.115 -static PyObject *xu_port_connect(PyObject *self, PyObject *args)
   3.116 +static PyObject *xu_port_close(PyObject *self, PyObject *args)
   3.117  {
   3.118 -    Py_INCREF(Py_None);
   3.119 -    return Py_None;
   3.120 -}
   3.121 +    xu_port_object *xup = (xu_port_object *)self;
   3.122  
   3.123 -/* NOOP */
   3.124 -static PyObject *xu_port_disconnect(PyObject *self, PyObject *args)
   3.125 -{
   3.126 +    _xu_port_close(xup);
   3.127 +
   3.128      Py_INCREF(Py_None);
   3.129      return Py_None;
   3.130  }
   3.131 @@ -1278,6 +1229,11 @@ static PyObject *xu_port_register(PyObje
   3.132                                        &type) )
   3.133          return NULL;
   3.134      
   3.135 +    if (!xup->connected)
   3.136 +    {
   3.137 +        return PyInt_FromLong(0);
   3.138 +    }
   3.139 +    
   3.140      msg.type = XCS_MSG_BIND;
   3.141      msg.u.bind.port = xup->local_port;
   3.142      msg.u.bind.type = type;
   3.143 @@ -1303,6 +1259,11 @@ static PyObject *xu_port_deregister(PyOb
   3.144      if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
   3.145                                        &type) )
   3.146          return NULL;
   3.147 +
   3.148 +    if (!xup->connected)
   3.149 +    {
   3.150 +        return PyInt_FromLong(0);
   3.151 +    }
   3.152      
   3.153      msg.type = XCS_MSG_UNBIND;
   3.154      msg.u.bind.port = xup->local_port;
   3.155 @@ -1319,10 +1280,6 @@ static PyObject *xu_port_deregister(PyOb
   3.156  }
   3.157  
   3.158  static PyMethodDef xu_port_methods[] = {
   3.159 -    { "notify",
   3.160 -      (PyCFunction)xu_port_notify,
   3.161 -      METH_VARARGS,
   3.162 -      "Send a notification to the remote end.\n" },
   3.163  
   3.164      { "read_request",
   3.165        (PyCFunction)xu_port_read_request,
   3.166 @@ -1349,21 +1306,12 @@ static PyMethodDef xu_port_methods[] = {
   3.167        METH_VARARGS,
   3.168        "Returns TRUE if there is a request message to read.\n" },
   3.169  
   3.170 -    { "space_to_write_request",
   3.171 -      (PyCFunction)xu_port_space_to_write_request,
   3.172 -      METH_VARARGS,
   3.173 -      "Returns TRUE if there is space to write a request message.\n" },
   3.174  
   3.175      { "response_to_read",
   3.176        (PyCFunction)xu_port_response_to_read,
   3.177        METH_VARARGS,
   3.178        "Returns TRUE if there is a response message to read.\n" },
   3.179  
   3.180 -    { "space_to_write_response",
   3.181 -      (PyCFunction)xu_port_space_to_write_response,
   3.182 -      METH_VARARGS,
   3.183 -      "Returns TRUE if there is space to write a response message.\n" },
   3.184 -      
   3.185      { "register",
   3.186        (PyCFunction)xu_port_register,
   3.187        METH_VARARGS | METH_KEYWORDS,
   3.188 @@ -1374,15 +1322,10 @@ static PyMethodDef xu_port_methods[] = {
   3.189        METH_VARARGS | METH_KEYWORDS,
   3.190        "Stop receiving a type of message on this port.\n" },
   3.191  
   3.192 -    { "connect",
   3.193 -      (PyCFunction)xu_port_connect,
   3.194 +    { "close",
   3.195 +      (PyCFunction)xu_port_close,
   3.196        METH_VARARGS,
   3.197 -      "Synchronously connect to remote domain.\n" },
   3.198 -
   3.199 -    { "disconnect",
   3.200 -      (PyCFunction)xu_port_disconnect,
   3.201 -      METH_VARARGS,
   3.202 -      "Synchronously disconnect from remote domain.\n" },
   3.203 +      "Close the port.\n" },
   3.204  
   3.205      { NULL, NULL, 0, NULL }
   3.206  };
   3.207 @@ -1431,31 +1374,32 @@ static PyObject *xu_port_new(PyObject *s
   3.208  static PyObject *xu_port_getattr(PyObject *obj, char *name)
   3.209  {
   3.210      xu_port_object *xup = (xu_port_object *)obj;
   3.211 +
   3.212      if ( strcmp(name, "local_port") == 0 )
   3.213 -        return PyInt_FromLong(xup->local_port);
   3.214 +    {
   3.215 +        return PyInt_FromLong(xup->connected ? xup->local_port : -1);
   3.216 +    }
   3.217      if ( strcmp(name, "remote_port") == 0 )
   3.218 -        return PyInt_FromLong(xup->remote_port);
   3.219 +    {
   3.220 +        return PyInt_FromLong(xup->connected ? xup->remote_port : -1);
   3.221 +    }
   3.222      if ( strcmp(name, "remote_dom") == 0 )
   3.223 +    {
   3.224          return PyInt_FromLong(xup->remote_dom);
   3.225 +    }
   3.226 +    if ( strcmp(name, "connected") == 0 )
   3.227 +    {
   3.228 +        return PyInt_FromLong(xup->connected);
   3.229 +    }
   3.230      return Py_FindMethod(xu_port_methods, obj, name);
   3.231  }
   3.232  
   3.233  static void xu_port_dealloc(PyObject *self)
   3.234  {
   3.235 -
   3.236      xu_port_object *xup = (xu_port_object *)self;
   3.237 -    xcs_msg_t kmsg;
   3.238  
   3.239 -    if ( xup->remote_dom != 0 )
   3.240 -    {  
   3.241 -        kmsg.type = XCS_CIF_FREE_CC;
   3.242 -        kmsg.u.interface.dom         = xup->remote_dom;
   3.243 -        kmsg.u.interface.local_port  = xup->local_port; 
   3.244 -        kmsg.u.interface.remote_port = xup->remote_port;
   3.245 -        xcs_ctrl_send(&kmsg);
   3.246 -        xcs_ctrl_read(&kmsg);
   3.247 -    }
   3.248 -            
   3.249 +    _xu_port_close(xup);
   3.250 +
   3.251      PyObject_Del(self);
   3.252  }
   3.253  
   3.254 @@ -1638,6 +1582,26 @@ static PyObject *xu_buffer_full(PyObject
   3.255      return PyInt_FromLong(0);
   3.256  }
   3.257  
   3.258 +static PyObject *xu_buffer_size(PyObject *self, PyObject *args)
   3.259 +{
   3.260 +    xu_buffer_object *xub = (xu_buffer_object *)self;
   3.261 +
   3.262 +    if ( !PyArg_ParseTuple(args, "") )
   3.263 +        return NULL;
   3.264 +
   3.265 +    return PyInt_FromLong(xub->prod - xub->cons);
   3.266 +}
   3.267 +
   3.268 +static PyObject *xu_buffer_space(PyObject *self, PyObject *args)
   3.269 +{
   3.270 +    xu_buffer_object *xub = (xu_buffer_object *)self;
   3.271 +
   3.272 +    if ( !PyArg_ParseTuple(args, "") )
   3.273 +        return NULL;
   3.274 +
   3.275 +    return PyInt_FromLong(BUFSZ - (xub->prod - xub->cons));
   3.276 +}
   3.277 +
   3.278  static PyMethodDef xu_buffer_methods[] = {
   3.279      { "peek", 
   3.280        (PyCFunction)xu_buffer_peek,
   3.281 @@ -1669,6 +1633,16 @@ static PyMethodDef xu_buffer_methods[] =
   3.282        METH_VARARGS,
   3.283        "Return TRUE if the buffer is full.\n" },
   3.284  
   3.285 +    { "size", 
   3.286 +      (PyCFunction)xu_buffer_size,
   3.287 +      METH_VARARGS,
   3.288 +      "Return number of bytes in the buffer.\n" },
   3.289 +
   3.290 +    { "space", 
   3.291 +      (PyCFunction)xu_buffer_space,
   3.292 +      METH_VARARGS,
   3.293 +      "Return space left in the buffer.\n" },
   3.294 +
   3.295      { NULL, NULL, 0, NULL }
   3.296  };
   3.297  
     4.1 --- a/tools/python/xen/util/console_client.py	Thu Apr 28 08:56:40 2005 +0000
     4.2 +++ b/tools/python/xen/util/console_client.py	Thu Apr 28 10:46:53 2005 +0000
     4.3 @@ -57,9 +57,18 @@ def __send_to_sock(sock):
     4.4                      raise
     4.5      sys.exit(0)
     4.6  
     4.7 -def connect(host,port):
     4.8 -    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
     4.9 -    sock.connect((host,port))
    4.10 +def connect(host, port, path=None):
    4.11 +    # Try inet first. If 'path' is given and the error
    4.12 +    # was connection refused, try unix-domain on 'path'.
    4.13 +    try:
    4.14 +        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    4.15 +        sock.connect((host, port))
    4.16 +    except socket.error, err:
    4.17 +        if (path is None) or (err[0] != errno.ECONNREFUSED):
    4.18 +            raise
    4.19 +        # Try unix-domain.
    4.20 +        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    4.21 +        sock.connect(path)
    4.22  
    4.23      oattrs = tcgetattr(0)
    4.24      nattrs = tcgetattr(0)
    4.25 @@ -86,7 +95,14 @@ def connect(host,port):
    4.26          __send_to_sock(sock)
    4.27  
    4.28  if __name__ == '__main__':
    4.29 -    if len(sys.argv) != 3:
    4.30 -        print sys.argv[0] + " <host> <port>"
    4.31 +    argc = len(sys.argv)
    4.32 +    if argc < 3 or argc > 4:
    4.33 +        print >>sys.stderr, sys.argv[0], "<host> <port> [<path>]"
    4.34          sys.exit(1)
    4.35 -    connect(str(sys.argv[1]),int(sys.argv[2]))
    4.36 +    host = sys.argv[1]
    4.37 +    port = int(sys.argv[2])
    4.38 +    if argc > 3:
    4.39 +        path = sys.argv[3]
    4.40 +    else:
    4.41 +        path = None
    4.42 +    connect(host, port, path=path)
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/python/xen/web/SrvBase.py	Thu Apr 28 10:46:53 2005 +0000
     5.3 @@ -0,0 +1,75 @@
     5.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     5.5 +
     5.6 +import types
     5.7 +
     5.8 +
     5.9 +from xen.xend import sxp
    5.10 +from xen.xend import PrettyPrint
    5.11 +from xen.xend.Args import ArgError
    5.12 +from xen.xend.XendError import XendError
    5.13 +from xen.xend.XendLogging import log
    5.14 +
    5.15 +import resource
    5.16 +import http
    5.17 +import httpserver
    5.18 +
    5.19 +def uri_pathlist(p):
    5.20 +    """Split a path into a list.
    5.21 +    p		path
    5.22 +    return list of path elements
    5.23 +    """
    5.24 +    l = []
    5.25 +    for x in p.split('/'):
    5.26 +        if x == '': continue
    5.27 +        l.append(x)
    5.28 +    return l
    5.29 +
    5.30 +class SrvBase(resource.Resource):
    5.31 +    """Base class for services.
    5.32 +    """
    5.33 +
    5.34 +    
    5.35 +    def use_sxp(self, req):
    5.36 +        return req.useSxp()
    5.37 +    
    5.38 +    def get_op_method(self, op):
    5.39 +        """Get the method for an operation.
    5.40 +        For operation 'foo' looks for 'op_foo'.
    5.41 +
    5.42 +        op	operation name
    5.43 +        returns method or None
    5.44 +        """
    5.45 +        op_method_name = 'op_' + op
    5.46 +        return getattr(self, op_method_name, None)
    5.47 +        
    5.48 +    def perform(self, req):
    5.49 +        """General operation handler for posted operations.
    5.50 +        For operation 'foo' looks for a method op_foo and calls
    5.51 +        it with op_foo(op, req). Replies with code 500 if op_foo
    5.52 +        is not found.
    5.53 +
    5.54 +        The method must return a list when req.use_sxp is true
    5.55 +        and an HTML string otherwise (or list).
    5.56 +        Methods may also return a ThreadRequest (for incomplete processing).
    5.57 +
    5.58 +        req	request
    5.59 +        """
    5.60 +        op = req.args.get('op')
    5.61 +        if op is None or len(op) != 1:
    5.62 +            req.setResponseCode(http.NOT_ACCEPTABLE, "Invalid request")
    5.63 +            return ''
    5.64 +        op = op[0]
    5.65 +        op_method = self.get_op_method(op)
    5.66 +        if op_method is None:
    5.67 +            req.setResponseCode(http.NOT_IMPLEMENTED, "Operation not implemented: " + op)
    5.68 +            req.setHeader("Content-Type", "text/plain")
    5.69 +            req.write("Operation not implemented: " + op)
    5.70 +            return ''
    5.71 +        else:
    5.72 +            return op_method(op, req)
    5.73 +
    5.74 +    def print_path(self, req):
    5.75 +        """Print the path with hyperlinks.
    5.76 +        """
    5.77 +        req.printPath()
    5.78 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/python/xen/web/SrvDir.py	Thu Apr 28 10:46:53 2005 +0000
     6.3 @@ -0,0 +1,112 @@
     6.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
     6.5 +
     6.6 +import types
     6.7 +
     6.8 +from xen.xend import sxp
     6.9 +from xen.xend import PrettyPrint
    6.10 +from xen.xend.Args import ArgError
    6.11 +from xen.xend.XendError import XendError
    6.12 +#from xen.xend.XendLogging import log
    6.13 +
    6.14 +import resource
    6.15 +import http
    6.16 +
    6.17 +from xen.web.SrvBase import SrvBase
    6.18 +
    6.19 +class SrvConstructor:
    6.20 +    """Delayed constructor for sub-servers.
    6.21 +    Does not import the sub-server class or create the object until needed.
    6.22 +    """
    6.23 +
    6.24 +    def __init__(self, klass):
    6.25 +        """Create a constructor. It is assumed that the class
    6.26 +        should be imported as 'from xen.xend.server.klass import klass'.
    6.27 +
    6.28 +        klass	name of its class
    6.29 +        """
    6.30 +        self.klass = klass
    6.31 +        self.obj = None
    6.32 +
    6.33 +    def getobj(self):
    6.34 +        """Get the sub-server object, importing its class and instantiating it if
    6.35 +        necessary.
    6.36 +        """
    6.37 +        if not self.obj:
    6.38 +            exec 'from xen.xend.server.%s import %s' % (self.klass, self.klass)
    6.39 +            klassobj = eval(self.klass)
    6.40 +            self.obj = klassobj()
    6.41 +        return self.obj
    6.42 +
    6.43 +class SrvDir(SrvBase):
    6.44 +    """Base class for directory servlets.
    6.45 +    """
    6.46 +    isLeaf = False
    6.47 +    
    6.48 +    def __init__(self):
    6.49 +        SrvBase.__init__(self)
    6.50 +        self.table = {}
    6.51 +        self.order = []
    6.52 +
    6.53 +    def noChild(self, msg):
    6.54 +        return resource.ErrorPage(http.NOT_FOUND, msg=msg)
    6.55 +
    6.56 +    def getChild(self, x, req):
    6.57 +        if x == '': return self
    6.58 +        try:
    6.59 +            val = self.get(x)
    6.60 +        except XendError, ex:
    6.61 +            return self.noChild(str(ex))
    6.62 +        if val is None:
    6.63 +            return self.noChild('Not found: ' + str(x))
    6.64 +        else:
    6.65 +            return val
    6.66 +
    6.67 +    def get(self, x):
    6.68 +        val = self.table.get(x)
    6.69 +        if isinstance(val, SrvConstructor):
    6.70 +            val = val.getobj()
    6.71 +        return val
    6.72 +
    6.73 +    def add(self, x, v=None):
    6.74 +        if v is None:
    6.75 +            v = 'SrvDir'
    6.76 +        if isinstance(v, types.StringType):
    6.77 +            v = SrvConstructor(v)
    6.78 +        self.table[x] = v
    6.79 +        self.order.append(x)
    6.80 +        return v
    6.81 +
    6.82 +    def render_GET(self, req):
    6.83 +        try:
    6.84 +            if self.use_sxp(req):
    6.85 +                req.setHeader("Content-type", sxp.mime_type)
    6.86 +                self.ls(req, 1)
    6.87 +            else:
    6.88 +                req.write('<html><head></head><body>')
    6.89 +                self.print_path(req)
    6.90 +                self.ls(req)
    6.91 +                self.form(req)
    6.92 +                req.write('</body></html>')
    6.93 +            return ''
    6.94 +        except Exception, ex:
    6.95 +            self._perform_err(ex, "GET", req)
    6.96 +            
    6.97 +    def ls(self, req, use_sxp=0):
    6.98 +        url = req.prePathURL()
    6.99 +        if not url.endswith('/'):
   6.100 +            url += '/'
   6.101 +        if use_sxp:
   6.102 +           req.write('(ls ')
   6.103 +           for k in self.order:
   6.104 +               req.write(' ' + k)
   6.105 +           req.write(')')
   6.106 +        else:
   6.107 +            req.write('<ul>')
   6.108 +            for k in self.order:
   6.109 +                v = self.get(k)
   6.110 +                req.write('<li><a href="%s%s">%s</a></li>'
   6.111 +                          % (url, k, k))
   6.112 +            req.write('</ul>')
   6.113 +
   6.114 +    def form(self, req):
   6.115 +        pass
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/python/xen/web/__init__.py	Thu Apr 28 10:46:53 2005 +0000
     7.3 @@ -0,0 +1,1 @@
     7.4 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/python/xen/web/connection.py	Thu Apr 28 10:46:53 2005 +0000
     8.3 @@ -0,0 +1,398 @@
     8.4 +import sys
     8.5 +import threading
     8.6 +import select
     8.7 +import socket
     8.8 +
     8.9 +from errno import EAGAIN, EINTR, EWOULDBLOCK
    8.10 +
    8.11 +"""General classes to support server and client sockets, without
    8.12 +specifying what kind of socket they are. There are subclasses
    8.13 +for TCP and unix-domain sockets (see tcp.py and unix.py).
    8.14 +"""
    8.15 +
    8.16 +"""We make sockets non-blocking so that operations like accept()
    8.17 +don't block. We also select on a timeout. Otherwise we have no way
    8.18 +of getting the threads to shutdown.
    8.19 +"""
    8.20 +SELECT_TIMEOUT = 2.0
    8.21 +
    8.22 +class SocketServerConnection:
    8.23 +    """An accepted connection to a server.
    8.24 +    """
    8.25 +
    8.26 +    def __init__(self, sock, protocol, addr, server):
    8.27 +        self.sock = sock
    8.28 +        self.protocol = protocol
    8.29 +        self.addr = addr
    8.30 +        self.server = server
    8.31 +        self.buffer_n = 1024
    8.32 +        self.thread = None
    8.33 +        self.connected = True
    8.34 +        protocol.setTransport(self)
    8.35 +        protocol.connectionMade(addr)
    8.36 +
    8.37 +    def run(self):
    8.38 +        self.thread = threading.Thread(target=self.main)
    8.39 +        #self.thread.setDaemon(True)
    8.40 +        self.thread.start()
    8.41 +
    8.42 +    def main(self):
    8.43 +        while True:
    8.44 +            if not self.thread: break
    8.45 +            if self.select(): break
    8.46 +            if not self.thread: break
    8.47 +            data = self.read()
    8.48 +            if data is None: continue
    8.49 +            if data is True: break
    8.50 +            if self.dataReceived(data): break
    8.51 +
    8.52 +    def select(self):
    8.53 +        try:
    8.54 +            select.select([self.sock], [], [], SELECT_TIMEOUT)
    8.55 +            return False
    8.56 +        except socket.error, ex:
    8.57 +            if ex.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
    8.58 +                return False
    8.59 +            else:
    8.60 +                self.loseConnection(ex)
    8.61 +                return True
    8.62 +
    8.63 +    def read(self):
    8.64 +        try:
    8.65 +            data = self.sock.recv(self.buffer_n)
    8.66 +            if data == '':
    8.67 +                self.loseConnection()
    8.68 +                return True
    8.69 +            return data
    8.70 +        except socket.error, ex:
    8.71 +            if ex.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
    8.72 +                return None
    8.73 +            else:
    8.74 +                self.loseConnection(ex)
    8.75 +                return True
    8.76 +
    8.77 +    def dataReceived(self, data):
    8.78 +        if not self.connected:
    8.79 +            return True
    8.80 +        if not self.protocol:
    8.81 +            return True
    8.82 +        try:
    8.83 +            self.protocol.dataReceived(data)
    8.84 +        except SystemExit:
    8.85 +            raise
    8.86 +        except Exception, ex:
    8.87 +            self.loseConnection(ex)
    8.88 +            return True
    8.89 +        return False
    8.90 +
    8.91 +    def write(self, data):
    8.92 +        self.sock.send(data)
    8.93 +
    8.94 +    def loseConnection(self, reason=None):
    8.95 +        self.thread = None
    8.96 +        self.closeSocket(reason)
    8.97 +        self.closeProtocol(reason)
    8.98 +
    8.99 +    def closeSocket(self, reason):
   8.100 +        try:
   8.101 +            self.sock.close()
   8.102 +        except SystemExit:
   8.103 +            raise
   8.104 +        except:
   8.105 +            pass
   8.106 +
   8.107 +    def closeProtocol(self, reason):
   8.108 +        try:
   8.109 +            if self.connected:
   8.110 +                self.connected = False
   8.111 +                if self.protocol:
   8.112 +                    self.protocol.connectionLost(reason)
   8.113 +        except SystemExit:
   8.114 +            raise
   8.115 +        except:
   8.116 +            pass
   8.117 +
   8.118 +    def getHost(self):
   8.119 +        return self.sock.getsockname()
   8.120 +
   8.121 +    def getPeer(self):
   8.122 +        return self.addr
   8.123 +
   8.124 +class SocketListener:
   8.125 +    """A server socket, running listen in a thread.
   8.126 +    Accepts connections and runs a thread for each one.
   8.127 +    """
   8.128 +
   8.129 +    def __init__(self, factory, backlog=None):
   8.130 +        if backlog is None:
   8.131 +            backlog = 5
   8.132 +        self.factory = factory
   8.133 +        self.sock = None
   8.134 +        self.backlog = backlog
   8.135 +        self.thread = None
   8.136 +
   8.137 +    def createSocket(self):
   8.138 +        raise NotImplementedError()
   8.139 +
   8.140 +    def acceptConnection(self, sock, protocol, addr):
   8.141 +        return SocketServerConnection(sock, protocol, addr, self)
   8.142 +
   8.143 +    def startListening(self):
   8.144 +        if self.sock or self.thread:
   8.145 +            raise IOError("already listening")
   8.146 +        self.sock = self.createSocket()
   8.147 +        self.sock.setblocking(0)
   8.148 +        self.sock.listen(self.backlog)
   8.149 +        self.run()
   8.150 +
   8.151 +    def stopListening(self, reason=None):
   8.152 +        self.loseConnection(reason)
   8.153 +
   8.154 +    def run(self):
   8.155 +        self.factory.doStart()
   8.156 +        self.thread = threading.Thread(target=self.main)
   8.157 +        #self.thread.setDaemon(True)
   8.158 +        self.thread.start()
   8.159 +
   8.160 +    def main(self):
   8.161 +        while True:
   8.162 +            if not self.thread: break
   8.163 +            if self.select(): break
   8.164 +            if self.accept(): break
   8.165 +
   8.166 +    def select(self):
   8.167 +        try:
   8.168 +            select.select([self.sock], [], [], SELECT_TIMEOUT)
   8.169 +            return False
   8.170 +        except socket.error, ex:
   8.171 +            if ex.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
   8.172 +                return False
   8.173 +            else:
   8.174 +                self.loseConnection(ex)
   8.175 +                return True
   8.176 +
   8.177 +    def accept(self):
   8.178 +        try:
   8.179 +            (sock, addr) = self.sock.accept()
   8.180 +            sock.setblocking(0)
   8.181 +            return self.accepted(sock, addr)
   8.182 +        except socket.error, ex:
   8.183 +            if ex.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
   8.184 +                return False
   8.185 +            else:
   8.186 +                self.loseConnection(ex)
   8.187 +                return True
   8.188 +
   8.189 +    def accepted(self, sock, addr):
   8.190 +        protocol = self.factory.buildProtocol(addr)
   8.191 +        if protocol is None:
   8.192 +            self.loseConnection()
   8.193 +            return True
   8.194 +        connection = self.acceptConnection(sock, protocol, addr)
   8.195 +        connection.run()
   8.196 +        return False
   8.197 +
   8.198 +    def loseConnection(self, reason=None):
   8.199 +        self.thread = None
   8.200 +        self.closeSocket(reason)
   8.201 +        self.closeFactory(reason)
   8.202 +
   8.203 +    def closeSocket(self, reason):
   8.204 +        try:
   8.205 +            self.sock.close()
   8.206 +        except SystemExit:
   8.207 +            raise
   8.208 +        except Exception, ex:
   8.209 +            pass
   8.210 +
   8.211 +    def closeFactory(self, reason):
   8.212 +        try:
   8.213 +            self.factory.doStop()
   8.214 +        except SystemExit:
   8.215 +            raise
   8.216 +        except:
   8.217 +            pass
   8.218 +
   8.219 +class SocketClientConnection:
   8.220 +    """A connection to a server from a client.
   8.221 +
   8.222 +    Call connectionMade() on the protocol in a thread when connected.
   8.223 +    It is completely up to the protocol what to do.
   8.224 +    """
   8.225 +
   8.226 +    def __init__(self, connector):
   8.227 +        self.addr = None
   8.228 +        self.connector = connector
   8.229 +        self.buffer_n = 1024
   8.230 +        self.connected = False
   8.231 +
   8.232 +    def createSocket (self):
   8.233 +        raise NotImplementedError()
   8.234 +
   8.235 +    def write(self, data):
   8.236 +        if self.sock:
   8.237 +            return self.sock.send(data)
   8.238 +        else:
   8.239 +            return 0
   8.240 +
   8.241 +    def connect(self, timeout):
   8.242 +        #todo: run a timer to cancel on timeout?
   8.243 +        try:
   8.244 +            sock = self.createSocket()
   8.245 +            sock.connect(self.addr)
   8.246 +            self.sock = sock
   8.247 +            self.connected = True
   8.248 +            self.protocol = self.connector.buildProtocol(self.addr)
   8.249 +            self.protocol.setTransport(self)
   8.250 +        except SystemExit:
   8.251 +            raise
   8.252 +        except Exception, ex:
   8.253 +            self.connector.connectionFailed(ex)
   8.254 +            return False
   8.255 +
   8.256 +        self.thread = threading.Thread(target=self.main)
   8.257 +        #self.thread.setDaemon(True)
   8.258 +        self.thread.start()
   8.259 +        return True
   8.260 +
   8.261 +    def main(self):
   8.262 +        try:
   8.263 +            # Call the protocol in a thread.
   8.264 +            # Up to it what to do.
   8.265 +            self.protocol.connectionMade(self.addr)
   8.266 +        except SystemExit:
   8.267 +            raise
   8.268 +        except Exception, ex:
   8.269 +            self.loseConnection(ex)
   8.270 +
   8.271 +    def mainLoop(self):
   8.272 +        # Something a protocol could call.
   8.273 +        while True:
   8.274 +            if not self.thread: break
   8.275 +            if self.select(): break
   8.276 +            if not self.thread: break
   8.277 +            data = self.read()
   8.278 +            if data is None: continue
   8.279 +            if data is True: break
   8.280 +            if self.dataReceived(data): break
   8.281 +
   8.282 +    def select(self):
   8.283 +        try:
   8.284 +            select.select([self.sock], [], [], SELECT_TIMEOUT)
   8.285 +            return False
   8.286 +        except socket.error, ex:
   8.287 +            if ex.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
   8.288 +                return False
   8.289 +            else:
   8.290 +                self.loseConnection(ex)
   8.291 +                return True
   8.292 +
   8.293 +    def read(self):
   8.294 +        try:
   8.295 +            data = self.sock.recv(self.buffer_n)
   8.296 +            return data
   8.297 +        except socket.error, ex:
   8.298 +            if ex.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
   8.299 +                return None
   8.300 +            else:
   8.301 +                self.loseConnection(ex)
   8.302 +                return True
   8.303 +        
   8.304 +    def dataReceived(self, data):
   8.305 +        if not self.protocol:
   8.306 +            return True
   8.307 +        try:
   8.308 +            self.protocol.dataReceived(data)
   8.309 +        except SystemExit:
   8.310 +            raise
   8.311 +        except Exception, ex:
   8.312 +            self.loseConnection(ex)
   8.313 +            return True
   8.314 +        return False
   8.315 +
   8.316 +    def loseConnection(self, reason=None):
   8.317 +        self.thread = None
   8.318 +        self.closeSocket(reason)
   8.319 +        self.closeProtocol(reason)
   8.320 +        self.closeConnector(reason)
   8.321 +
   8.322 +    def closeSocket(self, reason):
   8.323 +        try:
   8.324 +            if self.sock:
   8.325 +                self.sock.close()
   8.326 +        except SystemExit:
   8.327 +            raise
   8.328 +        except:
   8.329 +            pass
   8.330 +
   8.331 +    def closeProtocol(self, reason):
   8.332 +        try:
   8.333 +            if self.connected:
   8.334 +                self.connected = False
   8.335 +                if self.protocol:
   8.336 +                    self.protocol.connectionLost(reason)
   8.337 +        except SystemExit:
   8.338 +            raise
   8.339 +        except:
   8.340 +            pass
   8.341 +        self.protocol = None
   8.342 +
   8.343 +    def closeConnector(self, reason):
   8.344 +        try:
   8.345 +            self.connector.connectionLost(reason)
   8.346 +        except SystemExit:
   8.347 +            raise
   8.348 +        except:
   8.349 +            pass
   8.350 +        
   8.351 +class SocketConnector:
   8.352 +    """A client socket. Connects to a server and runs the client protocol
   8.353 +    in a thread.
   8.354 +    """
   8.355 +
   8.356 +    def __init__(self, factory):
   8.357 +        self.factoryStarted = False
   8.358 +        self.clientLost = False
   8.359 +        self.clientFailed = False
   8.360 +        self.factory = factory
   8.361 +        self.state = "disconnected"
   8.362 +        self.transport = None
   8.363 +
   8.364 +    def getDestination(self):
   8.365 +        raise NotImplementedError()
   8.366 +
   8.367 +    def connectTransport(self):
   8.368 +        raise NotImplementedError()
   8.369 +
   8.370 +    def connect(self):
   8.371 +        if self.state != "disconnected":
   8.372 +            raise socket.error(EINVAL, "cannot connect in state " + self.state)
   8.373 +        self.state = "connecting"
   8.374 +        self.clientLost = False
   8.375 +        self.clientFailed = False
   8.376 +        if not self.factoryStarted:
   8.377 +            self.factoryStarted = True
   8.378 +            self.factory.doStart()
   8.379 +        self.factory.startedConnecting(self)
   8.380 +        self.connectTransport()
   8.381 +        self.state = "connected"
   8.382 +
   8.383 +    def stopConnecting(self):
   8.384 +        if self.state != "connecting":
   8.385 +            return
   8.386 +        self.state = "disconnected"
   8.387 +        self.transport.disconnect()
   8.388 +
   8.389 +    def buildProtocol(self, addr):
   8.390 +        return self.factory.buildProtocol(addr)
   8.391 +
   8.392 +    def connectionLost(self, reason=None):
   8.393 +        if not self.clientLost:
   8.394 +            self.clientLost = True
   8.395 +            self.factory.clientConnectionLost(self, reason)
   8.396 +
   8.397 +    def connectionFailed(self, reason=None):
   8.398 +        if not self.clientFailed:
   8.399 +            self.clientFailed = True
   8.400 +            self.factory.clientConnectionFailed(self, reason)
   8.401 +        
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/python/xen/web/http.py	Thu Apr 28 10:46:53 2005 +0000
     9.3 @@ -0,0 +1,514 @@
     9.4 +#============================================================================
     9.5 +# This library is free software; you can redistribute it and/or
     9.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
     9.7 +# License as published by the Free Software Foundation.
     9.8 +#
     9.9 +# This library is distributed in the hope that it will be useful,
    9.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9.12 +# Lesser General Public License for more details.
    9.13 +#
    9.14 +# You should have received a copy of the GNU Lesser General Public
    9.15 +# License along with this library; if not, write to the Free Software
    9.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    9.17 +#
    9.18 +#============================================================================
    9.19 +# Parts of this library are derived from Twisted:
    9.20 +# Copyright (C) 2001 Matthew W. Lefkowitz
    9.21 +#
    9.22 +# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
    9.23 +#============================================================================
    9.24 +
    9.25 +from  mimetools import Message
    9.26 +from cStringIO import StringIO
    9.27 +import math
    9.28 +import time
    9.29 +import cgi
    9.30 +
    9.31 +CONTINUE                        = 100
    9.32 +SWITCHING_PROTOCOLS             = 101
    9.33 +
    9.34 +OK                              = 200
    9.35 +CREATED                         = 201
    9.36 +ACCEPTED                        = 202
    9.37 +NON_AUTHORITATIVE_INFORMATION   = 203
    9.38 +NO_CONTENT                      = 204
    9.39 +RESET_CONTENT                   = 205
    9.40 +PARTIAL_CONTENT                 = 206
    9.41 +MULTI_STATUS                    = 207
    9.42 +
    9.43 +MULTIPLE_CHOICE                 = 300
    9.44 +MOVED_PERMANENTLY               = 301
    9.45 +FOUND                           = 302
    9.46 +SEE_OTHER                       = 303
    9.47 +NOT_MODIFIED                    = 304
    9.48 +USE_PROXY                       = 305
    9.49 +TEMPORARY_REDIRECT              = 307
    9.50 +
    9.51 +BAD_REQUEST                     = 400
    9.52 +UNAUTHORIZED                    = 401
    9.53 +PAYMENT_REQUIRED                = 402
    9.54 +FORBIDDEN                       = 403
    9.55 +NOT_FOUND                       = 404
    9.56 +NOT_ALLOWED                     = 405
    9.57 +NOT_ACCEPTABLE                  = 406
    9.58 +PROXY_AUTH_REQUIRED             = 407
    9.59 +REQUEST_TIMEOUT                 = 408
    9.60 +CONFLICT                        = 409
    9.61 +GONE                            = 410
    9.62 +LENGTH_REQUIRED                 = 411
    9.63 +PRECONDITION_FAILED             = 412
    9.64 +REQUEST_ENTITY_TOO_LARGE        = 413
    9.65 +REQUEST_URI_TOO_LONG            = 414
    9.66 +UNSUPPORTED_MEDIA_TYPE          = 415
    9.67 +REQUESTED_RANGE_NOT_SATISFIABLE = 416
    9.68 +EXPECTATION_FAILED              = 417
    9.69 +
    9.70 +INTERNAL_SERVER_ERROR           = 500
    9.71 +NOT_IMPLEMENTED                 = 501
    9.72 +BAD_GATEWAY                     = 502
    9.73 +SERVICE_UNAVAILABLE             = 503
    9.74 +GATEWAY_TIMEOUT                 = 504
    9.75 +VERSION_NOT_SUPPORTED           = 505
    9.76 +INSUFFICIENT_STORAGE_SPACE      = 507
    9.77 +NOT_EXTENDED                    = 510
    9.78 +
    9.79 +NO_BODY_CODES = [ NO_CONTENT, NOT_MODIFIED ]
    9.80 +    
    9.81 +
    9.82 +STATUS = {
    9.83 +    CONTINUE                        : "Continue",
    9.84 +    SWITCHING_PROTOCOLS             : "Switching protocols",
    9.85 +    
    9.86 +    OK                              : "OK",
    9.87 +    CREATED                         : "Created",
    9.88 +    ACCEPTED                        : "Accepted",
    9.89 +    NON_AUTHORITATIVE_INFORMATION   : "Non-authoritative information",
    9.90 +    NO_CONTENT                      : "No content",
    9.91 +    RESET_CONTENT                   : "Reset content",
    9.92 +    PARTIAL_CONTENT                 : "Partial content",
    9.93 +    MULTI_STATUS                    : "Multi-status",
    9.94 +    
    9.95 +    MULTIPLE_CHOICE                 : "Multiple choice",
    9.96 +    MOVED_PERMANENTLY               : "Moved permanently",
    9.97 +    FOUND                           : "Found",
    9.98 +    SEE_OTHER                       : "See other",
    9.99 +    NOT_MODIFIED                    : "Not modified",
   9.100 +    USE_PROXY                       : "Use proxy",
   9.101 +    TEMPORARY_REDIRECT              : "Temporary redirect",
   9.102 +    
   9.103 +    BAD_REQUEST                     : "Bad request",
   9.104 +    UNAUTHORIZED                    : "Unauthorized",
   9.105 +    PAYMENT_REQUIRED                : "Payment required",
   9.106 +    FORBIDDEN                       : "Forbidden",
   9.107 +    NOT_FOUND                       : "Not found",
   9.108 +    NOT_ALLOWED                     : "Not allowed",
   9.109 +    NOT_ACCEPTABLE                  : "Not acceptable",
   9.110 +    PROXY_AUTH_REQUIRED             : "Proxy authentication required",
   9.111 +    REQUEST_TIMEOUT                 : "Request timeout",
   9.112 +    CONFLICT                        : "Conflict",
   9.113 +    GONE                            : "Gone",
   9.114 +    LENGTH_REQUIRED                 : "Length required",
   9.115 +    PRECONDITION_FAILED             : "Precondition failed",
   9.116 +    REQUEST_ENTITY_TOO_LARGE        : "Request entity too large",
   9.117 +    REQUEST_URI_TOO_LONG            : "Request URI too long",
   9.118 +    UNSUPPORTED_MEDIA_TYPE          : "Unsupported media type",
   9.119 +    REQUESTED_RANGE_NOT_SATISFIABLE : "Requested range not satisfiable",
   9.120 +    EXPECTATION_FAILED              : "Expectation failed",
   9.121 +    
   9.122 +    INTERNAL_SERVER_ERROR           : "Internal server error",
   9.123 +    NOT_IMPLEMENTED                 : "Not implemented",
   9.124 +    BAD_GATEWAY                     : "Bad gateway",
   9.125 +    SERVICE_UNAVAILABLE             : "Service unavailable",
   9.126 +    GATEWAY_TIMEOUT                 : "Gateway timeout",
   9.127 +    VERSION_NOT_SUPPORTED           : "HTTP version not supported",
   9.128 +    INSUFFICIENT_STORAGE_SPACE      : "Insufficient storage space",
   9.129 +    NOT_EXTENDED                    : "Not extended",
   9.130 +    }
   9.131 +
   9.132 +def getStatus(code):
   9.133 +    return STATUS.get(code, "unknown")
   9.134 +
   9.135 +MULTIPART_FORM_DATA = 'multipart/form-data'
   9.136 +URLENCODED = 'application/x-www-form-urlencoded'
   9.137 +
   9.138 +parseQueryArgs = cgi.parse_qs
   9.139 +
   9.140 +def timegm(year, month, day, hour, minute, second):
   9.141 +    """Convert time tuple in GMT to seconds since epoch, GMT"""
   9.142 +    EPOCH = 1970
   9.143 +    assert year >= EPOCH
   9.144 +    assert 1 <= month <= 12
   9.145 +    days = 365*(year-EPOCH) + calendar.leapdays(EPOCH, year)
   9.146 +    for i in range(1, month):
   9.147 +        days = days + calendar.mdays[i]
   9.148 +    if month > 2 and calendar.isleap(year):
   9.149 +        days = days + 1
   9.150 +    days = days + day - 1
   9.151 +    hours = days*24 + hour
   9.152 +    minutes = hours*60 + minute
   9.153 +    seconds = minutes*60 + second
   9.154 +    return seconds
   9.155 +
   9.156 +def stringToDatetime(dateString):
   9.157 +    """Convert an HTTP date string to seconds since epoch."""
   9.158 +    parts = dateString.split(' ')
   9.159 +    day = int(parts[1])
   9.160 +    month = int(monthname.index(parts[2]))
   9.161 +    year = int(parts[3])
   9.162 +    hour, min, sec = map(int, parts[4].split(':'))
   9.163 +    return int(timegm(year, month, day, hour, min, sec))
   9.164 +
   9.165 +class HttpRequest:
   9.166 +
   9.167 +    http_version = (1, 1)
   9.168 +
   9.169 +    http_version_string = ("HTTP/%d.%d" % http_version)
   9.170 +
   9.171 +    max_content_length = 10000
   9.172 +    max_headers = 500
   9.173 +
   9.174 +    request_line = None
   9.175 +    request_method = None
   9.176 +    request_uri = None
   9.177 +    request_path = None
   9.178 +    request_query = None
   9.179 +    request_version = None
   9.180 +    content_length = 0
   9.181 +    content = None
   9.182 +    etag = None
   9.183 +    close_connection = True
   9.184 +    response_code = 200
   9.185 +    response_status = "OK"
   9.186 +    response_sent = False
   9.187 +    cached = False
   9.188 +    last_modified = None
   9.189 +
   9.190 +    forceSSL = False
   9.191 +    
   9.192 +    def __init__(self, host, rin, out):
   9.193 +        self.host = host
   9.194 +        self.rin = rin
   9.195 +        self.out = out
   9.196 +        self.request_args = {}
   9.197 +        self.args = self.request_args
   9.198 +        self.request_headers = {}
   9.199 +        self.request_cookies = {}
   9.200 +        self.response_headers = {}
   9.201 +        self.response_cookies = {}
   9.202 +        self.output = StringIO()
   9.203 +        self.parseRequest()
   9.204 +
   9.205 +    def isSecure(self):
   9.206 +        return self.forceSSL
   9.207 +
   9.208 +    def getRequestMethod(self):
   9.209 +        return self.request_method
   9.210 +
   9.211 +    def trim(self, str, ends):
   9.212 +        for end in ends:
   9.213 +            if str.endswith(end):
   9.214 +                str = str[ : -len(end) ]
   9.215 +                break
   9.216 +        return str
   9.217 +
   9.218 +    def requestError(self, code, msg=None):
   9.219 +        self.sendError(code, msg)
   9.220 +        raise ValueError(self.response_status)
   9.221 +
   9.222 +    def sendError(self, code, msg=None):
   9.223 +        self.setResponseCode(code, msg=msg)
   9.224 +        self.sendResponse()
   9.225 +
   9.226 +    def parseRequestVersion(self, version):
   9.227 +        try:
   9.228 +            if not version.startswith('HTTP/'):
   9.229 +                raise ValueError
   9.230 +            version_string = version.split('/', 1)[1]
   9.231 +            version_codes = version_string.split('.')
   9.232 +            if len(version_codes) != 2:
   9.233 +                raise ValueError
   9.234 +            request_version = (int(version_codes[0]), int(version_codes[1]))
   9.235 +        except (ValueError, IndexError):
   9.236 +            self.requestError(400, "Bad request version (%s)" % `version`)
   9.237 +
   9.238 +    def parseRequestLine(self):
   9.239 +        line = self.trim(self.request_line, ['\r\n', '\n'])
   9.240 +        line_fields = line.split()
   9.241 +        n = len(line_fields)
   9.242 +        if n == 3:
   9.243 +            [method, uri, version] = line_fields
   9.244 +        elif n == 2:
   9.245 +            [method, uri] = line_fields
   9.246 +            version = 'HTTP/0.9'
   9.247 +        else:
   9.248 +            self.requestError(BAD_REQUEST,
   9.249 +                              "Bad request (%s)" % `line`)
   9.250 +
   9.251 +        request_version = self.parseRequestVersion(version)
   9.252 +
   9.253 +        if request_version > (2, 0):
   9.254 +            self.requestError(VERSION_NOT_SUPPORTED,
   9.255 +                              "HTTP version not supported (%s)" % `version`)
   9.256 +        #if request_version >= (1, 1) and self.http_version >= (1, 1):
   9.257 +        #    self.close_connection = False
   9.258 +        #else:
   9.259 +        #    self.close_connection = True
   9.260 +
   9.261 +        self.request_method = method
   9.262 +        self.method = method
   9.263 +        self.request_uri = uri
   9.264 +        self.request_version = version
   9.265 +
   9.266 +        uri_query = uri.split('?')
   9.267 +        if len(uri_query) == 1:
   9.268 +            self.request_path = uri
   9.269 +        else:
   9.270 +            self.request_path = uri_query[0]
   9.271 +            self.request_query = uri_query[1]
   9.272 +            self.request_args = parseQueryArgs(self.request_query)
   9.273 +            self.args = self.request_args
   9.274 +            
   9.275 +
   9.276 +    def parseRequestHeaders(self):
   9.277 +        header_bytes = ""
   9.278 +        header_count = 0
   9.279 +        while True:
   9.280 +            if header_count >= self.max_headers:
   9.281 +                self.requestError(BAD_REQUEST,
   9.282 +                                  "Bad request (too many headers)")
   9.283 +            line = self.rin.readline()
   9.284 +            header_bytes += line
   9.285 +            header_count += 1
   9.286 +            if line == '\r\n' or line == '\n' or line == '':
   9.287 +                break
   9.288 +        header_input = StringIO(header_bytes)
   9.289 +        self.request_headers = Message(header_input)
   9.290 +
   9.291 +    def parseRequestCookies(self):
   9.292 +        cookie_hdr = self.getHeader("cookie")
   9.293 +        if not cookie_hdr: return
   9.294 +        for cookie in cookie_hdr.split(';'):
   9.295 +            try:
   9.296 +                cookie = cookie.lstrip()
   9.297 +                (k, v) = cookie.split('=', 1)
   9.298 +                self.request_cookies[k] = v
   9.299 +            except ValueError:
   9.300 +                pass
   9.301 +
   9.302 +    def parseRequestArgs(self):
   9.303 +        if ((self.content is None) or
   9.304 +            (self.request_method != "POST")):
   9.305 +            return
   9.306 +        content_type = self.getHeader('content-type')
   9.307 +        if not content_type:
   9.308 +            return
   9.309 +        (encoding, params) = cgi.parse_header(content_type)
   9.310 +        if encoding == URLENCODED:
   9.311 +            xargs = cgi.parse_qs(self.content.getvalue(),
   9.312 +                                 keep_blank_values=True)
   9.313 +        elif encoding == MULTIPART_FORM_DATA:
   9.314 +            xargs = cgi.parse_multipart(self.content, params)
   9.315 +        else:
   9.316 +            xargs = {}
   9.317 +        self.request_args.update(xargs)
   9.318 +
   9.319 +    def getCookie(self, k):
   9.320 +        return self.request_cookies[k]
   9.321 +
   9.322 +    def readContent(self):
   9.323 +        try:
   9.324 +            self.content_length = int(self.getHeader("Content-Length"))
   9.325 +        except:
   9.326 +            return
   9.327 +        if self.content_length > self.max_content_length:
   9.328 +            self.requestError(REQUEST_ENTITY_TOO_LARGE)
   9.329 +        self.content = self.rin.read(self.content_length)
   9.330 +        self.content = StringIO(self.content)
   9.331 +        self.content.seek(0,0)
   9.332 +
   9.333 +    def parseRequest(self):
   9.334 +        self.request_line = self.rin.readline()
   9.335 +        self.parseRequestLine()
   9.336 +        self.parseRequestHeaders()
   9.337 +        self.parseRequestCookies()
   9.338 +        connection_mode = self.getHeader('Connection')
   9.339 +        self.setCloseConnection(connection_mode)
   9.340 +        self.readContent()
   9.341 +        self.parseRequestArgs()
   9.342 +
   9.343 +    def setCloseConnection(self, mode):
   9.344 +        if not mode: return
   9.345 +        mode = mode.lower()
   9.346 +        if mode == 'close':
   9.347 +            self.close_connection = True
   9.348 +        elif (mode == 'keep-alive') and (self.http_version >= (1, 1)):
   9.349 +            self.close_connection = False
   9.350 +        
   9.351 +    def getCloseConnection(self):
   9.352 +        return self.close_connection
   9.353 +
   9.354 +    def getHeader(self, k, v=None):
   9.355 +        return self.request_headers.get(k, v)
   9.356 +
   9.357 +    def getRequestMethod(self):
   9.358 +        return self.request_method
   9.359 +
   9.360 +    def getRequestPath(self):
   9.361 +        return self.request_path
   9.362 +
   9.363 +    def setResponseCode(self, code, status=None, msg=None):
   9.364 +        self.response_code = code
   9.365 +        if not status:
   9.366 +            status = getStatus(code)
   9.367 +        self.response_status = status
   9.368 +
   9.369 +    def setResponseHeader(self, k, v):
   9.370 +        k = k.lower()
   9.371 +        self.response_headers[k] = v
   9.372 +        if k == 'connection':
   9.373 +            self.setCloseConnection(v)
   9.374 +
   9.375 +    setHeader = setResponseHeader
   9.376 +
   9.377 +    def setLastModified(self, when):
   9.378 +        # time.time() may be a float, but the HTTP-date strings are
   9.379 +        # only good for whole seconds.
   9.380 +        when = long(math.ceil(when))
   9.381 +        if (not self.last_modified) or (self.last_modified < when):
   9.382 +            self.lastModified = when
   9.383 +
   9.384 +        modified_since = self.getHeader('if-modified-since')
   9.385 +        if modified_since:
   9.386 +            modified_since = stringToDatetime(modified_since)
   9.387 +            if modified_since >= when:
   9.388 +                self.setResponseCode(NOT_MODIFIED)
   9.389 +                self.cached = True
   9.390 +
   9.391 +    def setContentType(self, ty):
   9.392 +        self.setResponseHeader("Content-Type", ty)
   9.393 +
   9.394 +    def setEtag(self, etag):
   9.395 +        if etag:
   9.396 +            self.etag = etag
   9.397 +
   9.398 +        tags = self.getHeader("if-none-match")
   9.399 +        if tags:
   9.400 +            tags = tags.split()
   9.401 +            if (etag in tags) or ('*' in tags):
   9.402 +                if self.request_method in ("HEAD", "GET"):
   9.403 +                    code = NOT_MODIFIED
   9.404 +                else:
   9.405 +                    code = PRECONDITION_FAILED
   9.406 +                self.setResponseCode(code)
   9.407 +                self.cached = True
   9.408 +
   9.409 +    def addCookie(self, k, v, expires=None, domain=None, path=None,
   9.410 +                  max_age=None, comment=None, secure=None):
   9.411 +        cookie = v
   9.412 +        if expires != None:
   9.413 +            cookie += "; Expires=%s" % expires
   9.414 +        if domain != None:
   9.415 +            cookie += "; Domain=%s" % domain
   9.416 +        if path != None:
   9.417 +            cookie += "; Path=%s" % path
   9.418 +        if max_age != None:
   9.419 +            cookie += "; Max-Age=%s" % max_age
   9.420 +        if comment != None:
   9.421 +            cookie += "; Comment=%s" % comment
   9.422 +        if secure:
   9.423 +            cookie += "; Secure"
   9.424 +        self.response_cookies[k] = cookie
   9.425 +
   9.426 +    def sendResponseHeaders(self):
   9.427 +        if self.etag:
   9.428 +            self.setResponseHeader("ETag", self.etag)
   9.429 +        for (k, v) in self.response_headers.items():
   9.430 +            self.send("%s: %s\r\n" % (k.capitalize(), v))
   9.431 +        for (k, v) in self.response_cookies.items():
   9.432 +            self.send("Set-Cookie: %s=%s\r\n" % (k, v))
   9.433 +        self.send("\r\n")
   9.434 +        
   9.435 +    def sendResponse(self):
   9.436 +        if self.response_sent:
   9.437 +            return
   9.438 +        self.response_sent = True
   9.439 +        send_body = self.hasBody()
   9.440 +        if not self.close_connection:
   9.441 +            self.setResponseHeader("Connection", "keep-alive")
   9.442 +        if send_body:
   9.443 +            self.output.seek(0, 0)
   9.444 +            body = self.output.getvalue()
   9.445 +            body_length = len(body)
   9.446 +            self.setResponseHeader("Content-Length", body_length)
   9.447 +        if self.http_version > (0, 9):
   9.448 +            self.send("%s %d %s\r\n" % (self.http_version_string,
   9.449 +                                         self.response_code,
   9.450 +                                         self.response_status))
   9.451 +            self.sendResponseHeaders()
   9.452 +        if send_body:
   9.453 +            self.send(body)
   9.454 +        self.flush()
   9.455 +
   9.456 +    def write(self, data):
   9.457 +        self.output.write(data)
   9.458 +
   9.459 +    def send(self, data):
   9.460 +        #print 'send>', data
   9.461 +        self.out.write(data)
   9.462 +
   9.463 +    def flush(self):
   9.464 +        self.out.flush()
   9.465 +
   9.466 +    def hasNoBody(self):
   9.467 +        return ((self.request_method == "HEAD") or
   9.468 +                (self.response_code in NO_BODY_CODES) or
   9.469 +                self.cached)
   9.470 +
   9.471 +    def hasBody(self):
   9.472 +        return not self.hasNoBody()
   9.473 +
   9.474 +    def process(self):
   9.475 +        pass
   9.476 +        return self.close_connection
   9.477 +
   9.478 +    def getRequestHostname(self):
   9.479 +        """Get the hostname that the user passed in to the request.
   9.480 +
   9.481 +        Uses the 'Host:' header if it is available, and the
   9.482 +        host we are listening on otherwise.
   9.483 +        """
   9.484 +        return (self.getHeader('host') or
   9.485 +                socket.gethostbyaddr(self.getHostAddr())[0]
   9.486 +                ).split(':')[0]
   9.487 +
   9.488 +    def getHost(self):
   9.489 +        return self.host
   9.490 +
   9.491 +    def getHostAddr(self):
   9.492 +        return self.host[0]
   9.493 +    
   9.494 +    def getPort(self):
   9.495 +        return self.host[1]
   9.496 +
   9.497 +    def setHost(self, host, port, ssl=0):
   9.498 +        """Change the host and port the request thinks it's using.
   9.499 +
   9.500 +        This method is useful for working with reverse HTTP proxies (e.g.
   9.501 +        both Squid and Apache's mod_proxy can do this), when the address
   9.502 +        the HTTP client is using is different than the one we're listening on.
   9.503 +
   9.504 +        For example, Apache may be listening on https://www.example.com, and then
   9.505 +        forwarding requests to http://localhost:8080, but we don't want HTML produced
   9.506 +        to say 'http://localhost:8080', they should say 'https://www.example.com',
   9.507 +        so we do::
   9.508 +
   9.509 +           request.setHost('www.example.com', 443, ssl=1)
   9.510 +
   9.511 +        """
   9.512 +        self.forceSSL = ssl
   9.513 +        self.received_headers["host"] = host
   9.514 +        self.host = (host, port)
   9.515 +
   9.516 +        
   9.517 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/python/xen/web/httpserver.py	Thu Apr 28 10:46:53 2005 +0000
    10.3 @@ -0,0 +1,342 @@
    10.4 +import threading
    10.5 +
    10.6 +import string
    10.7 +import socket
    10.8 +import types
    10.9 +from urllib import quote, unquote
   10.10 +import os
   10.11 +import os.path
   10.12 +
   10.13 +from xen.xend import sxp
   10.14 +from xen.xend.Args import ArgError
   10.15 +from xen.xend.XendError import XendError
   10.16 +
   10.17 +import http
   10.18 +from resource import Resource, ErrorPage
   10.19 +from SrvDir import SrvDir
   10.20 +
   10.21 +class ThreadRequest:
   10.22 +    """A request to complete processing using a thread.
   10.23 +    """
   10.24 +    
   10.25 +    def __init__(self, processor, req, fn, args, kwds):
   10.26 +        self.processor = processor
   10.27 +        self.req = req
   10.28 +        self.fn = fn
   10.29 +        self.args = args
   10.30 +        self.kwds = kwds
   10.31 +        
   10.32 +    def run(self):
   10.33 +        self.processor.setInThread()
   10.34 +        thread = threading.Thread(target=self.main)
   10.35 +        thread.setDaemon(True)
   10.36 +        thread.start()
   10.37 +
   10.38 +    def call(self):
   10.39 +        try:
   10.40 +            self.fn(*self.args, **self.kwds)
   10.41 +        except SystemExit:
   10.42 +            raise
   10.43 +        except Exception, ex:
   10.44 +            self.req.resultErr(ex)
   10.45 +        self.req.finish()
   10.46 +
   10.47 +    def main(self):
   10.48 +        self.call()
   10.49 +        self.processor.process()
   10.50 +       
   10.51 +
   10.52 +class RequestProcessor:
   10.53 +    """Processor for requests on a connection to an http server.
   10.54 +    Requests are executed synchonously unless they ask for a thread by returning
   10.55 +    a ThreadRequest.
   10.56 +    """
   10.57 +
   10.58 +    done = False
   10.59 +
   10.60 +    inThread = False
   10.61 +
   10.62 +    def __init__(self, server, sock, addr):
   10.63 +        self.server = server
   10.64 +        self.sock = sock
   10.65 +        self.srd = sock.makefile('rb')
   10.66 +        self.srw = sock.makefile('wb')
   10.67 +        self.srvaddr = server.getServerAddr()
   10.68 +
   10.69 +    def isInThread(self):
   10.70 +        return self.inThread
   10.71 +
   10.72 +    def setInThread(self):
   10.73 +        self.inThread = True
   10.74 +
   10.75 +    def getServer(self):
   10.76 +        return self.server
   10.77 +
   10.78 +    def getRequest(self):
   10.79 +        return HttpServerRequest(self, self.srvaddr, self.srd, self.srw)
   10.80 +
   10.81 +    def close(self):
   10.82 +        try:
   10.83 +            self.sock.close()
   10.84 +        except:
   10.85 +            pass
   10.86 +
   10.87 +    def finish(self):
   10.88 +        self.done = True
   10.89 +        self.close()
   10.90 +
   10.91 +    def process(self):
   10.92 +        while not self.done:
   10.93 +            req = self.getRequest()
   10.94 +            res = req.process()
   10.95 +            if isinstance(res, ThreadRequest):
   10.96 +                if self.isInThread():
   10.97 +                    res.call()
   10.98 +                else:
   10.99 +                    res.run()
  10.100 +                    break
  10.101 +            else:
  10.102 +                req.finish()
  10.103 +                                        
  10.104 +class HttpServerRequest(http.HttpRequest):
  10.105 +    """A single request to an http server.
  10.106 +    """
  10.107 +
  10.108 +    def __init__(self, processor, addr, srd, srw):
  10.109 +        self.processor = processor
  10.110 +        self.prepath = ''
  10.111 +        http.HttpRequest.__init__(self, addr, srd, srw)
  10.112 +
  10.113 +    def getServer(self):
  10.114 +        return self.processor.getServer()
  10.115 +
  10.116 +    def process(self):
  10.117 +        """Process the request. If the return value is a ThreadRequest
  10.118 +        it is evaluated in a thread.
  10.119 +        """
  10.120 +        try:
  10.121 +            self.prepath = []
  10.122 +            self.postpath = map(unquote, string.split(self.request_path[1:], '/'))
  10.123 +            resource = self.getResource()
  10.124 +            return self.render(resource)
  10.125 +        except SystemExit:
  10.126 +            raise
  10.127 +        except Exception, ex:
  10.128 +            self.processError(ex)
  10.129 +
  10.130 +    def processError(self, ex):
  10.131 +        import traceback; traceback.print_exc()
  10.132 +        self.sendError(http.INTERNAL_SERVER_ERROR, msg=str(ex))
  10.133 +        self.setCloseConnection('close')
  10.134 +
  10.135 +    def finish(self):
  10.136 +        self.sendResponse()
  10.137 +        if self.close_connection:
  10.138 +            self.processor.finish()
  10.139 +
  10.140 +    def prePathURL(self):
  10.141 +        url_host = self.getRequestHostname()
  10.142 +        port = self.getPort()
  10.143 +        if self.isSecure():
  10.144 +            url_proto = "https"
  10.145 +            default_port = 443
  10.146 +        else:
  10.147 +            url_proto = "http"
  10.148 +            default_port = 80
  10.149 +        if port != default_port:
  10.150 +            url_host += (':%d' % port)
  10.151 +        url_path = quote(string.join(self.prepath, '/'))
  10.152 +        return ('%s://%s/%s' % (url_proto, url_host, url_path))
  10.153 +
  10.154 +    def getResource(self):
  10.155 +        return self.getServer().getResource(self)
  10.156 +
  10.157 +    def render(self, resource):
  10.158 +        val = None
  10.159 +        if resource is None:
  10.160 +            self.sendError(http.NOT_FOUND)
  10.161 +        else:
  10.162 +            try:
  10.163 +                while True:
  10.164 +                    val = resource.render(self)
  10.165 +                    if not isinstance(val, Resource):
  10.166 +                        break
  10.167 +                val = self.result(val)
  10.168 +            except SystemExit:
  10.169 +                raise
  10.170 +            except Exception, ex:
  10.171 +                self.resultErr(ex)
  10.172 +        return val
  10.173 +
  10.174 +    def threadRequest(self, _fn, *_args, **_kwds):
  10.175 +        """Create a request to finish request processing in a thread.
  10.176 +        Use this to create a ThreadRequest to return from rendering a
  10.177 +        resource if you need a thread to complete processing.
  10.178 +        """
  10.179 +        return ThreadRequest(self.processor, self, _fn, _args, _kwds)
  10.180 +            
  10.181 +    def result(self, val):
  10.182 +        if isinstance(val, Exception):
  10.183 +            return self.resultErr(val)
  10.184 +        else:
  10.185 +            return self.resultVal(val)
  10.186 +
  10.187 +    def resultVal(self, val):
  10.188 +        """Callback to complete the request.
  10.189 +
  10.190 +        @param val: the value
  10.191 +        """
  10.192 +        if val is None:
  10.193 +            return val
  10.194 +        elif isinstance(val, ThreadRequest):
  10.195 +            return val
  10.196 +        elif self.useSxp():
  10.197 +            self.setHeader("Content-Type", sxp.mime_type)
  10.198 +            sxp.show(val, out=self)
  10.199 +        else:
  10.200 +            self.write('<html><head></head><body>')
  10.201 +            self.printPath()
  10.202 +            if isinstance(val, types.ListType):
  10.203 +                self.write('<code><pre>')
  10.204 +                PrettyPrint.prettyprint(val, out=self)
  10.205 +                self.write('</pre></code>')
  10.206 +            else:
  10.207 +                self.write(str(val))
  10.208 +            self.write('</body></html>')
  10.209 +        return None
  10.210 +
  10.211 +    def resultErr(self, err):
  10.212 +        """Error callback to complete a request.
  10.213 +
  10.214 +        @param err: the error
  10.215 +        """
  10.216 +        if not isinstance(err, (ArgError, sxp.ParseError, XendError)):
  10.217 +            raise
  10.218 +        #log.exception("op=%s: %s", op, str(err))
  10.219 +        if self.useSxp():
  10.220 +            self.setHeader("Content-Type", sxp.mime_type)
  10.221 +            sxp.show(['xend.err', str(err)], out=self)
  10.222 +        else:
  10.223 +            self.setHeader("Content-Type", "text/plain")
  10.224 +            self.write('Error ')
  10.225 +            self.write(': ')
  10.226 +            self.write(str(err))
  10.227 +        return None
  10.228 +
  10.229 +    def useSxp(self):
  10.230 +        """Determine whether to send an SXP response to a request.
  10.231 +        Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
  10.232 +
  10.233 +        returns 1 for SXP, 0 otherwise
  10.234 +        """
  10.235 +        ok = 0
  10.236 +        user_agent = self.getHeader('User-Agent')
  10.237 +        accept = self.getHeader('Accept')
  10.238 +        if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
  10.239 +            ok = 1
  10.240 +        return ok
  10.241 +
  10.242 +    def printPath(self):
  10.243 +        pathlist = [x for x in self.prepath if x != '' ]
  10.244 +        s = "/"
  10.245 +        self.write('<h1><a href="/">/</a>')
  10.246 +        for x in pathlist:
  10.247 +            s += x + "/"
  10.248 +            self.write(' <a href="%s">%s</a>/' % (s, x))
  10.249 +        self.write("</h1>")
  10.250 +        
  10.251 +class HttpServer:
  10.252 +
  10.253 +    backlog = 5
  10.254 +
  10.255 +    closed = False
  10.256 +
  10.257 +    def __init__(self, interface='', port=8080, root=None):
  10.258 +        if root is None:
  10.259 +            root = SrvDir()
  10.260 +        self.interface = interface
  10.261 +        self.port = port
  10.262 +        self.root = root
  10.263 +
  10.264 +    def getRoot(self):
  10.265 +        return self.root
  10.266 +
  10.267 +    def getPort(self):
  10.268 +        return self.port
  10.269 +
  10.270 +    def run(self):
  10.271 +        self.bind()
  10.272 +        self.listen()
  10.273 +        self.requestLoop()
  10.274 +
  10.275 +    def stop(self):
  10.276 +        self.close()
  10.277 +
  10.278 +    def bind(self):
  10.279 +        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  10.280 +        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  10.281 +        self.socket.bind((self.interface, self.port))
  10.282 +
  10.283 +    def listen(self):
  10.284 +        self.socket.listen(self.backlog)
  10.285 +
  10.286 +    def accept(self):
  10.287 +        return self.socket.accept()
  10.288 +
  10.289 +    def requestLoop(self):
  10.290 +        while not self.closed:
  10.291 +            self.acceptRequest()
  10.292 +
  10.293 +    def close(self):
  10.294 +        self.closed = True
  10.295 +        try:
  10.296 +            self.socket.close()
  10.297 +        except:
  10.298 +            pass
  10.299 +
  10.300 +    def acceptRequest(self):
  10.301 +        try:
  10.302 +            (sock, addr) = self.accept()
  10.303 +            self.processRequest(sock, addr)
  10.304 +        except socket.error:
  10.305 +            return
  10.306 +
  10.307 +    def processRequest(self, sock, addr):
  10.308 +        try:
  10.309 +            rp = RequestProcessor(self, sock, addr)
  10.310 +            rp.process()
  10.311 +        except SystemExit:
  10.312 +            raise
  10.313 +        except Exception, ex:
  10.314 +            print 'HttpServer>processRequest> exception: ', ex
  10.315 +            try:
  10.316 +                sock.close()
  10.317 +            except:
  10.318 +                pass
  10.319 +
  10.320 +    def getServerAddr(self):
  10.321 +        return (socket.gethostname(), self.port)
  10.322 +
  10.323 +    def getResource(self, req):
  10.324 +        return self.root.getRequestResource(req)
  10.325 +
  10.326 +class UnixHttpServer(HttpServer):
  10.327 +
  10.328 +    def __init__(self, path=None, root=None):
  10.329 +        HttpServer.__init__(self, interface='localhost', root=root)
  10.330 +        self.path = path
  10.331 +        
  10.332 +    def bind(self):
  10.333 +        pathdir = os.path.dirname(self.path)
  10.334 +        if not os.path.exists(pathdir):
  10.335 +            os.makedirs(pathdir)
  10.336 +        else:
  10.337 +            try:
  10.338 +                os.unlink(self.path)
  10.339 +            except SystemExit:
  10.340 +                raise
  10.341 +            except Exception, ex:
  10.342 +                pass
  10.343 +        self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  10.344 +        #self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  10.345 +        self.socket.bind(self.path)
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/python/xen/web/protocol.py	Thu Apr 28 10:46:53 2005 +0000
    11.3 @@ -0,0 +1,126 @@
    11.4 +class Factory:
    11.5 +    """Generic protocol factory.
    11.6 +    """
    11.7 +
    11.8 +    starts = 0
    11.9 +
   11.10 +    def __init__(self):
   11.11 +        pass
   11.12 +
   11.13 +    def doStart(self):
   11.14 +        if self.starts == 0:
   11.15 +            self.startFactory()
   11.16 +        self.starts += 1
   11.17 +
   11.18 +    def doStop(self):
   11.19 +        if self.starts > 0:
   11.20 +            self.starts -= 1
   11.21 +        else:
   11.22 +            return
   11.23 +        if self.starts == 0:
   11.24 +            self.stopFactory()
   11.25 +
   11.26 +    def buildProtocol(self, addr):
   11.27 +        return Protocol(self)
   11.28 +
   11.29 +    def startFactory(self):
   11.30 +        pass
   11.31 +
   11.32 +    def stopFactory(self):
   11.33 +        pass
   11.34 +
   11.35 +class ServerFactory(Factory):
   11.36 +    """Factory for server protocols.
   11.37 +    """
   11.38 +    pass
   11.39 +    
   11.40 +class ClientFactory(Factory):
   11.41 +    """Factory for client protocols.
   11.42 +    """
   11.43 +    
   11.44 +    def startedConnecting(self, connector):
   11.45 +        pass
   11.46 +
   11.47 +    def clientConnectionLost(self, connector, reason):
   11.48 +        pass
   11.49 +
   11.50 +    def clientConnectionFailed(self, connector, reason):
   11.51 +        pass
   11.52 +
   11.53 +
   11.54 +class Protocol:
   11.55 +
   11.56 +    factory = None
   11.57 +    transport = None
   11.58 +    connected = False
   11.59 +
   11.60 +    def __init__(self, factory):
   11.61 +        self.factory = factory
   11.62 +
   11.63 +    def setTransport(self, transport):
   11.64 +        self.transport = transport
   11.65 +        self.connected = bool(transport)
   11.66 +
   11.67 +    def getTransport(self):
   11.68 +        return self.transport
   11.69 +
   11.70 +    def connectionMade(self, addr):
   11.71 +        print 'Protocol>connectionMade>', addr
   11.72 +        pass
   11.73 +
   11.74 +    def connectionLost(self, reason=None):
   11.75 +        print 'Protocol>connectionLost>', reason
   11.76 +        pass
   11.77 +
   11.78 +    def dataReceived(self, data):
   11.79 +        print 'Protocol>dataReceived>'
   11.80 +        pass
   11.81 +
   11.82 +    def write(self, data):
   11.83 +        if self.transport:
   11.84 +            return self.transport.write(data)
   11.85 +        else:
   11.86 +            return 0
   11.87 +
   11.88 +    def read(self):
   11.89 +        if self.transport:
   11.90 +            return self.transport.read()
   11.91 +        else:
   11.92 +            return None
   11.93 +
   11.94 +class TestClientFactory(ClientFactory):
   11.95 +
   11.96 +    def buildProtocol(self, addr):
   11.97 +        print 'TestClientFactory>buildProtocol>', addr
   11.98 +        return TestClientProtocol(self)
   11.99 +    
  11.100 +    def startedConnecting(self, connector):
  11.101 +        print 'TestClientFactory>startedConnecting>', connector
  11.102 +
  11.103 +    def clientConnectionLost(self, connector, reason):
  11.104 +        print 'TestClientFactory>clientConnectionLost>', connector, reason
  11.105 +
  11.106 +    def clientConnectionFailed(self, connector, reason):
  11.107 +        print 'TestClientFactory>clientConnectionFailed>', connector, reason
  11.108 +
  11.109 +class TestClientProtocol(Protocol):
  11.110 +
  11.111 +    def connectionMade(self, addr):
  11.112 +        print 'TestClientProtocol>connectionMade>', addr
  11.113 +        self.write("hello")
  11.114 +        self.write("there")
  11.115 +
  11.116 +class TestServerFactory(Factory):
  11.117 +
  11.118 +    def buildProtocol(self, addr):
  11.119 +        print 'TestServerFactory>buildProtocol>', addr
  11.120 +        return TestServerProtocol(self)
  11.121 +    
  11.122 +class TestServerProtocol(Protocol):
  11.123 +
  11.124 +    def dataReceived(self, data):
  11.125 +        print 'TestServerProtocol>dataReceived>', len(data), data
  11.126 +        #sys.exit(0)
  11.127 +        import os
  11.128 +        os._exit(0)
  11.129 +        
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tools/python/xen/web/reactor.py	Thu Apr 28 10:46:53 2005 +0000
    12.3 @@ -0,0 +1,9 @@
    12.4 +from threading import Timer
    12.5 +
    12.6 +from unix import listenUNIX, connectUNIX
    12.7 +from tcp import listenTCP, connectTCP
    12.8 +
    12.9 +def callLater(_delay, _fn, *args, **kwds):
   12.10 +    timer = Timer(_delay, _fn, args=args, kwargs=kwds)
   12.11 +    timer.start()
   12.12 +    return timer
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tools/python/xen/web/resource.py	Thu Apr 28 10:46:53 2005 +0000
    13.3 @@ -0,0 +1,91 @@
    13.4 +import http
    13.5 +
    13.6 +def findResource(resource, request):
    13.7 +    """Traverse resource tree to find who will handle the request."""
    13.8 +    while request.postpath and not resource.isLeaf:
    13.9 +        #print 'findResource:', resource, request.postpath
   13.10 +        pathElement = request.postpath.pop(0)
   13.11 +        request.prepath.append(pathElement)
   13.12 +        next = resource.getPathResource(pathElement, request)
   13.13 +        if not next: break
   13.14 +        resource = next
   13.15 +    return resource
   13.16 +
   13.17 +class Resource:
   13.18 +
   13.19 +    isLeaf = False
   13.20 +
   13.21 +    def __init__(self):
   13.22 +        self.children = {}
   13.23 +
   13.24 +    def getRequestResource(self, req):
   13.25 +        return findResource(self, req)
   13.26 +
   13.27 +    def getChild(self, path, request):
   13.28 +        return None
   13.29 +
   13.30 +    def getPathResource(self, path, request):
   13.31 +        #print 'getPathResource>', self, path
   13.32 +        if self.children.has_key(path):
   13.33 +            val =  self.children[path]
   13.34 +        else:
   13.35 +            val = self.getChild(path, request)
   13.36 +        #print 'getPathResource<', val
   13.37 +        return val
   13.38 +
   13.39 +    def putChild(self, path, child):
   13.40 +        self.children[path] = child
   13.41 +        #child.server = self.server
   13.42 +
   13.43 +    def render(self, req):
   13.44 +        meth = getattr(self, 'render_' + req.getRequestMethod(), self.unsupported)
   13.45 +        return meth(req)
   13.46 +
   13.47 +    def supportedMethods(self):
   13.48 +        l = []
   13.49 +        s = 'render_'
   13.50 +        for x in dir(self):
   13.51 +            if x.startswith(s):
   13.52 +                l.append(x[len(s):])
   13.53 +        return l
   13.54 +
   13.55 +    def render_HEAD(self, req):
   13.56 +        return self.render_GET(req)
   13.57 +
   13.58 +    def render_GET(self, req):
   13.59 +        req.setContentType("text/plain")
   13.60 +        req.write("GET")
   13.61 +
   13.62 +    def render_POST(self, req):
   13.63 +        req.setContentType("text/plain")
   13.64 +        req.write("POST")
   13.65 +
   13.66 +    def unsupported(self, req):
   13.67 +        req.setHeader("Accept", ",".join(self.supportedMethods()))
   13.68 +        req.setResponseCode(http.NOT_IMPLEMENTED)
   13.69 +        req.setContentType("text/plain")
   13.70 +        req.write("Request method not supported (%s)" % req.getRequestMethod())
   13.71 +
   13.72 +class ErrorPage(Resource):
   13.73 +
   13.74 +    isLeaf = True
   13.75 +    
   13.76 +    def __init__(self, code, status=None, msg=None):
   13.77 +        Resource.__init__(self)
   13.78 +        if status is None:
   13.79 +            status = http.getStatus(code)
   13.80 +        if msg is None:
   13.81 +            msg = status
   13.82 +        self.code = code
   13.83 +        self.status = status
   13.84 +        self.msg = msg
   13.85 +
   13.86 +    def render(self, req):
   13.87 +        req.setResponseCode(self.code, self.status)
   13.88 +        req.setContentType("text/plain")
   13.89 +        req.write(self.msg)
   13.90 +        
   13.91 +
   13.92 +    
   13.93 +    
   13.94 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tools/python/xen/web/static.py	Thu Apr 28 10:46:53 2005 +0000
    14.3 @@ -0,0 +1,45 @@
    14.4 +import os
    14.5 +
    14.6 +from resource import Resource
    14.7 +
    14.8 +class File(Resource):
    14.9 +
   14.10 +    isLeaf = True
   14.11 +
   14.12 +    def __init__(self, filename, defaultType=None):
   14.13 +        if defaultType is None:
   14.14 +            defaultType = "text/plain"
   14.15 +        self.filename = filename
   14.16 +        self.type = defaultType
   14.17 +        self.encoding = None
   14.18 +
   14.19 +    def getFileSize(self):
   14.20 +        try:
   14.21 +            info = os.stat(self.filename)
   14.22 +            return info.st_size
   14.23 +        except:
   14.24 +            return 0
   14.25 +
   14.26 +    def render(self, req):
   14.27 +        if self.type:
   14.28 +            req.setHeader('Content-Type', self.type)
   14.29 +        if self.encoding:
   14.30 +            req.setHeader('Content-Encoding', self.encoding)
   14.31 +        req.setHeader('Content-Length', self.getFileSize())
   14.32 +        try:
   14.33 +            io = file(self.filename, "r")
   14.34 +            while True:
   14.35 +                buf = io.read(1024)
   14.36 +                if not buf:
   14.37 +                    break
   14.38 +                req.write(buf)
   14.39 +        except IOError:
   14.40 +            pass
   14.41 +        try:
   14.42 +            if io:
   14.43 +                io.close()
   14.44 +        except:
   14.45 +            pass
   14.46 +        
   14.47 +
   14.48 +        
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tools/python/xen/web/tcp.py	Thu Apr 28 10:46:53 2005 +0000
    15.3 @@ -0,0 +1,90 @@
    15.4 +import sys
    15.5 +import socket
    15.6 +import types
    15.7 +
    15.8 +from connection import *
    15.9 +from protocol import *
   15.10 +
   15.11 +class TCPServerConnection(SocketServerConnection):
   15.12 +    pass
   15.13 +
   15.14 +class TCPListener(SocketListener):
   15.15 +
   15.16 +    def __init__(self, port, factory, backlog=None, interface=''):
   15.17 +        SocketListener.__init__(self, factory, backlog=backlog)
   15.18 +        self.port = port
   15.19 +        self.interface = interface
   15.20 +        
   15.21 +    def createSocket(self):
   15.22 +        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   15.23 +        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   15.24 +        addr = (self.interface, self.port)
   15.25 +        sock.bind(addr)
   15.26 +        return sock
   15.27 +
   15.28 +    def acceptConnection(self, sock, protocol, addr):
   15.29 +        return TCPServerConnection(sock, protocol, addr, self)
   15.30 +
   15.31 +class TCPClientConnection(SocketClientConnection):
   15.32 +
   15.33 +    def __init__(self, host, port, bindAddress, connector):
   15.34 +        SocketClientConnection.__init__(self, connector)
   15.35 +        self.addr = (host, port)
   15.36 +        self.bindAddress = bindAddress
   15.37 +
   15.38 +    def createSocket(self):
   15.39 +        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   15.40 +        if self.bindAddress is not None:
   15.41 +            sock.bind(self.bindAddress)
   15.42 +        return sock
   15.43 +    
   15.44 +class TCPConnector(SocketConnector):
   15.45 +
   15.46 +    def __init__(self, host, port, factory, timeout=None, bindAddress=None):
   15.47 +        SocketConnector.__init__(self, factory)
   15.48 +        self.host = host
   15.49 +        self.port = self.servicePort(port)
   15.50 +        self.bindAddress = bindAddress
   15.51 +        self.timeout = timeout
   15.52 +
   15.53 +    def servicePort(self, port):
   15.54 +        if isinstance(port, types.StringTypes):
   15.55 +            try:
   15.56 +                port = socket.getservbyname(port, 'tcp')
   15.57 +            except socket.error, ex:
   15.58 +                raise IOError("unknown service: " + ex)
   15.59 +        return port
   15.60 +
   15.61 +    def getDestination(self):
   15.62 +        return (self.host, self.port)
   15.63 +
   15.64 +    def connectTransport(self):
   15.65 +        self.transport = TCPClientConnection(
   15.66 +            self.host, self.port, self.bindAddress, self)
   15.67 +        self.transport.connect(self.timeout)
   15.68 +
   15.69 +def listenTCP(port, factory, interface='', backlog=None):
   15.70 +    l = TCPListener(port, factory, interface=interface, backlog=backlog)
   15.71 +    l.startListening()
   15.72 +    return l
   15.73 +
   15.74 +def connectTCP(host, port, factory, timeout=None, bindAddress=None):
   15.75 +    c = TCPConnector(host, port, factory, timeout=timeout, bindAddress=bindAddress)
   15.76 +    c.connect()
   15.77 +    return c
   15.78 +
   15.79 +def main(argv):
   15.80 +    host = 'localhost'
   15.81 +    port = 8005
   15.82 +    if argv[1] == "client":
   15.83 +        c = connectTCP(host, port, TestClientFactory())
   15.84 +        print 'client:', c
   15.85 +    else:
   15.86 +        s = listenTCP(port, TestServerFactory())
   15.87 +        print 'server:', s
   15.88 +        
   15.89 +if __name__ == "__main__":
   15.90 +    main(sys.argv)
   15.91 +
   15.92 +        
   15.93 +
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/python/xen/web/unix.py	Thu Apr 28 10:46:53 2005 +0000
    16.3 @@ -0,0 +1,81 @@
    16.4 +import sys
    16.5 +import socket
    16.6 +import os
    16.7 +import os.path
    16.8 +
    16.9 +from connection import *
   16.10 +from protocol import *
   16.11 +
   16.12 +class UnixServerConnection(SocketServerConnection):
   16.13 +    pass
   16.14 +
   16.15 +class UnixListener(SocketListener):
   16.16 +
   16.17 +    def __init__(self, path, factory, backlog=None):
   16.18 +        SocketListener.__init__(self, factory, backlog=backlog)
   16.19 +        self.path = path
   16.20 +        
   16.21 +    def createSocket(self):
   16.22 +        pathdir = os.path.dirname(self.path)
   16.23 +        if not os.path.exists(pathdir):
   16.24 +            os.makedirs(pathdir)
   16.25 +        else:
   16.26 +            try:
   16.27 +                os.unlink(self.path)
   16.28 +            except SystemExit:
   16.29 +                raise
   16.30 +            except Exception, ex:
   16.31 +                pass
   16.32 +        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
   16.33 +        sock.bind(self.path)
   16.34 +        return sock
   16.35 +
   16.36 +    def acceptConnection(self, sock, protocol, addr):
   16.37 +        return UnixServerConnection(sock, protocol, self.path, self)
   16.38 +
   16.39 +class UnixClientConnection(SocketClientConnection):
   16.40 +
   16.41 +    def __init__(self, addr, connector):
   16.42 +        SocketClientConnection.__init__(self, connector)
   16.43 +        self.addr = addr
   16.44 +        
   16.45 +    def createSocket(self):
   16.46 +        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
   16.47 +        return sock
   16.48 +    
   16.49 +class UnixConnector(SocketConnector):
   16.50 +
   16.51 +    def __init__(self, path, factory, timeout=None):
   16.52 +        SocketConnector.__init__(self, factory)
   16.53 +        self.addr = path
   16.54 +        self.timeout = timeout
   16.55 +
   16.56 +    def getDestination(self):
   16.57 +        return self.addr
   16.58 +
   16.59 +    def connectTransport(self):
   16.60 +        self.transport = UnixClientConnection(self.addr, self)
   16.61 +        self.transport.connect(self.timeout)
   16.62 +
   16.63 +def listenUNIX(path, factory, backlog=None):
   16.64 +    l = UnixListener(path, factory, backlog=backlog)
   16.65 +    l.startListening()
   16.66 +    return l
   16.67 +
   16.68 +def connectUNIX(path, factory, timeout=None):
   16.69 +    c = UnixConnector(path, factory, timeout=timeout)
   16.70 +    c.connect()
   16.71 +    return c
   16.72 +
   16.73 +def main(argv):
   16.74 +    path = "/tmp/test-foo"
   16.75 +    if argv[1] == "client":
   16.76 +        c = connectUNIX(path, TestClientFactory())
   16.77 +        print "client:", c
   16.78 +    else:
   16.79 +        s = listenUNIX(path, TestServeractory())
   16.80 +        print "server:", s
   16.81 +
   16.82 +if __name__ == "__main__":
   16.83 +    main(sys.argv)
   16.84 +
    17.1 --- a/tools/python/xen/xend/EventServer.py	Thu Apr 28 08:56:40 2005 +0000
    17.2 +++ b/tools/python/xen/xend/EventServer.py	Thu Apr 28 10:46:53 2005 +0000
    17.3 @@ -3,8 +3,10 @@
    17.4  
    17.5  """
    17.6  import string
    17.7 +from threading import Lock
    17.8  
    17.9 -from twisted.internet import reactor
   17.10 +#from twisted.internet import reactor
   17.11 +from xen.web import reactor
   17.12  
   17.13  # subscribe a.b.c h: map a.b.c -> h
   17.14  # subscribe a.b.* h: map a.b.* -> h
   17.15 @@ -38,20 +40,30 @@ class EventServer:
   17.16          self.handlers = {}
   17.17          self.run = run
   17.18          self.queue = []
   17.19 +        self.lock = Lock()
   17.20  
   17.21      def start(self):
   17.22          """Enable event handling. Sends any queued events.
   17.23          """
   17.24 -        self.run = 1
   17.25 -        for (e,v) in self.queue:
   17.26 +        try:
   17.27 +            self.lock.acquire()
   17.28 +            self.run = 1
   17.29 +            queue = self.queue
   17.30 +            self.queue = []
   17.31 +        finally:
   17.32 +            self.lock.release()
   17.33 +        for (e,v) in queue:
   17.34              self.inject(e, v)
   17.35 -        self.queue = []
   17.36  
   17.37      def stop(self):
   17.38          """Suspend event handling. Events injected while suspended
   17.39          are queued until we are started again.
   17.40          """
   17.41 -        self.run = 0
   17.42 +        try:
   17.43 +            self.lock.acquire()
   17.44 +            self.run = 0
   17.45 +        finally:
   17.46 +            self.lock.release()
   17.47  
   17.48      def subscribe(self, event, handler):
   17.49          """Subscribe to an event. For example 'a.b.c.d'.
   17.50 @@ -62,21 +74,29 @@ class EventServer:
   17.51          event	event name
   17.52          handler event handler fn(event, val)
   17.53          """
   17.54 -        hl = self.handlers.get(event)
   17.55 -        if hl is None:
   17.56 -            self.handlers[event] = [handler]
   17.57 -        else:
   17.58 -            hl.append(handler)
   17.59 +        try:
   17.60 +            self.lock.acquire()
   17.61 +            hl = self.handlers.get(event)
   17.62 +            if hl is None:
   17.63 +                self.handlers[event] = [handler]
   17.64 +            else:
   17.65 +                hl.append(handler)
   17.66 +        finally:
   17.67 +            self.lock.release()
   17.68  
   17.69      def unsubscribe_all(self, event=None):
   17.70          """Unsubscribe all handlers for a given event, or all handlers.
   17.71  
   17.72          event	event (optional)
   17.73          """
   17.74 -        if event == None:
   17.75 -            self.handlers.clear()
   17.76 -        elif event in self.handlers:
   17.77 -            del self.handlers[event]
   17.78 +        try:
   17.79 +            self.lock.acquire()
   17.80 +            if event == None:
   17.81 +                self.handlers.clear()
   17.82 +            elif event in self.handlers:
   17.83 +                del self.handlers[event]
   17.84 +        finally:
   17.85 +            self.lock.release()
   17.86          
   17.87      def unsubscribe(self, event, handler):
   17.88          """Unsubscribe a given event and handler.
   17.89 @@ -84,11 +104,15 @@ class EventServer:
   17.90          event	event
   17.91          handler handler
   17.92          """
   17.93 -        hl = self.handlers.get(event)
   17.94 -        if hl is None:
   17.95 -            return
   17.96 -        if handler in hl:
   17.97 -            hl.remove(handler)
   17.98 +        try:
   17.99 +            self.lock.acquire()
  17.100 +            hl = self.handlers.get(event)
  17.101 +            if hl is None:
  17.102 +                return
  17.103 +            if handler in hl:
  17.104 +                hl.remove(handler)
  17.105 +        finally:
  17.106 +            self.lock.release()
  17.107  
  17.108      def inject(self, event, val, async=1):
  17.109          """Inject an event. Handlers for it are called if running, otherwise
  17.110 @@ -97,13 +121,18 @@ class EventServer:
  17.111          event	event type
  17.112          val	event value
  17.113          """
  17.114 -        if self.run:
  17.115 -            if async:
  17.116 -                reactor.callLater(0, self.call_handlers, event, val)
  17.117 -            else:
  17.118 -                self.notify_handlers(event, val)
  17.119 +        try:
  17.120 +            self.lock.acquire()
  17.121 +            if not self.run:
  17.122 +                self.queue.append( (event, val) )
  17.123 +                return
  17.124 +        finally:
  17.125 +            self.lock.release()
  17.126 +            
  17.127 +        if async:
  17.128 +            reactor.callLater(0, self.call_handlers, event, val)
  17.129          else:
  17.130 -            self.queue.append( (event, val) )
  17.131 +            self.call_handlers(event, val)
  17.132  
  17.133      def call_handlers(self, event, val):
  17.134          """Internal method to call event handlers.
  17.135 @@ -121,13 +150,19 @@ class EventServer:
  17.136          event	event type
  17.137          val	event value
  17.138          """
  17.139 -        hl = self.handlers.get(key)
  17.140 -        if hl is None:
  17.141 -            return
  17.142 -        # Copy the handler list so that handlers can call
  17.143 -        # subscribe/unsubscribe safely - python list iteration
  17.144 -        # is not safe against list modification.
  17.145 -        for h in hl[:]:
  17.146 +        try:
  17.147 +            self.lock.acquire()
  17.148 +            hl = self.handlers.get(key)
  17.149 +            if hl is None:
  17.150 +                return
  17.151 +            # Copy the handler list so that handlers can call
  17.152 +            # subscribe/unsubscribe safely - python list iteration
  17.153 +            # is not safe against list modification.
  17.154 +            hl = hl[:]
  17.155 +        finally:
  17.156 +            self.lock.release()
  17.157 +        # Must not hold the lock while calling the handlers.
  17.158 +        for h in hl:
  17.159              try:
  17.160                  h(event, val)
  17.161              except:
    18.1 --- a/tools/python/xen/xend/EventTypes.py	Thu Apr 28 08:56:40 2005 +0000
    18.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3 @@ -1,34 +0,0 @@
    18.4 -#   Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    18.5 -
    18.6 -## XEND_DOMAIN_CREATE = "xend.domain.create": dom
    18.7 -## create: 
    18.8 -## xend.domain.destroy: dom, reason:died/crashed
    18.9 -## xend.domain.up ?
   18.10 -
   18.11 -## xend.domain.unpause: dom
   18.12 -## xend.domain.pause: dom
   18.13 -## xend.domain.shutdown: dom
   18.14 -## xend.domain.destroy: dom
   18.15 -
   18.16 -## xend.domain.migrate.begin: dom, to
   18.17 -## Begin tells: src host, src domain uri, dst host. Dst id known?
   18.18 -## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason
   18.19 -## end: src host, src domain uri, dst host, dst uri
   18.20 -
   18.21 -## Events for both ends of migrate: for exporter and importer?
   18.22 -## Include migrate id so can tie together.
   18.23 -## Have uri /xend/migrate/<id> for migrate info (migrations in progress).
   18.24 -
   18.25 -## (xend.domain.migrate.begin (src <host>) (src.domain <id>)
   18.26 -##                            (dst <host>) (id <migrate id>))
   18.27 - 
   18.28 -## xend.domain.migrate.end:
   18.29 -## (xend.domain.migrate.end (domain <id>) (to <host>)
   18.30 -
   18.31 -## xend.node.up:  xend uri
   18.32 -## xend.node.down: xend uri
   18.33 -
   18.34 -## xend.error ?
   18.35 -
   18.36 -## format:
   18.37 -
    19.1 --- a/tools/python/xen/xend/XendAsynchProtocol.py	Thu Apr 28 08:56:40 2005 +0000
    19.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3 @@ -1,94 +0,0 @@
    19.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    19.5 -
    19.6 -from twisted.protocols import http
    19.7 -from twisted.internet.protocol import ClientCreator
    19.8 -from twisted.internet.defer import Deferred
    19.9 -from twisted.internet import reactor
   19.10 -
   19.11 -from XendProtocol import XendClientProtocol, XendRequest
   19.12 -
   19.13 -class AsynchXendClient(http.HTTPClient):
   19.14 -    """A subclass of twisted's HTTPClient to deal with a connection to xend.
   19.15 -    Makes the request when connected, and delegates handling responses etc.
   19.16 -    to its protocol (usually an AsynchXendClientProtocol instance).
   19.17 -    """
   19.18 -    def __init__(self, protocol, request):
   19.19 -        self.protocol = protocol
   19.20 -        self.request = request
   19.21 -
   19.22 -    def connectionMade(self):
   19.23 -        request = self.request
   19.24 -        url = self.request.url
   19.25 -        self.sendCommand(request.method, url.fullpath())
   19.26 -        self.sendHeader('Host', url.location())
   19.27 -        for (k, v) in request.headers.items():
   19.28 -            self.sendHeader(k, v)
   19.29 -        if request.data:
   19.30 -            self.sendHeader('Content-Length', len(request.data))
   19.31 -        self.endHeaders()
   19.32 -        if request.data:
   19.33 -            self.transport.write(request.data)
   19.34 -
   19.35 -    def handleStatus(self, version, status, message):
   19.36 -        return self.protocol.handleStatus(version, status, message)
   19.37 -
   19.38 -    def handleHeader(self, key, val):
   19.39 -        return self.protocol.handleHeader(key, val)
   19.40 -
   19.41 -    def handleResponse(self, data):
   19.42 -        return self.protocol.handleResponse(data)
   19.43 -
   19.44 -class AsynchXendClientProtocol(XendClientProtocol):
   19.45 -    """An asynchronous xend client. Uses twisted to connect to xend
   19.46 -    and make the request. It does not block waiting for the result,
   19.47 -    but sets up a deferred that is called when the result becomes available.
   19.48 -
   19.49 -    Uses AsynchXendClient to manage the connection.
   19.50 -    """
   19.51 -    def __init__(self):
   19.52 -        self.err = None
   19.53 -        self.headers = {}
   19.54 -
   19.55 -    def xendRequest(self, url, method, args=None):
   19.56 -        """Make a request to xend. The returned deferred is called when
   19.57 -        the result is available.
   19.58 -        
   19.59 -        @param url:    xend request url
   19.60 -        @param method: http method: POST or GET
   19.61 -        @param args:   request arguments (dict)
   19.62 -        @return: deferred
   19.63 -        """
   19.64 -        request = XendRequest(url, method, args)
   19.65 -        self.deferred = Deferred()
   19.66 -        clientCreator = ClientCreator(reactor, AsynchXendClient, self, request)
   19.67 -        clientCreator.connectTCP(url.host, url.port)
   19.68 -        return self.deferred
   19.69 -
   19.70 -    def callErrback(self, err):
   19.71 -        if not self.deferred.called:
   19.72 -            self.err = err
   19.73 -            self.deferred.errback(err)
   19.74 -        return err
   19.75 -
   19.76 -    def callCallback(self, val):
   19.77 -        if not self.deferred.called:
   19.78 -            self.deferred.callback(val)
   19.79 -        return val
   19.80 -
   19.81 -    def handleException(self, err):
   19.82 -        return self.callErrback(err)
   19.83 -
   19.84 -    def handleHeader(self, key, val):
   19.85 -        self.headers[key.lower()] = val
   19.86 -
   19.87 -    def getHeader(self, key):
   19.88 -        return self.headers.get(key.lower())
   19.89 -
   19.90 -    def handleResponse(self, data):
   19.91 -        if self.err: return self.err
   19.92 -        val = XendClientProtocol.handleResponse(self, data)
   19.93 -        if isinstance(val, Exception):
   19.94 -            self.callErrback(val)
   19.95 -        else:
   19.96 -            self.callCallback(val)
   19.97 -        return val
    20.1 --- a/tools/python/xen/xend/XendClient.py	Thu Apr 28 08:56:40 2005 +0000
    20.2 +++ b/tools/python/xen/xend/XendClient.py	Thu Apr 28 10:46:53 2005 +0000
    20.3 @@ -2,7 +2,7 @@
    20.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    20.5  """Client API for the HTTP interface on xend.
    20.6  Callable as a script - see main().
    20.7 -Supports synchronous or asynchronous connection to xend.
    20.8 +Supports inet or unix connection to xend.
    20.9  
   20.10  This API is the 'control-plane' for xend.
   20.11  The 'data-plane' is done separately. For example, consoles
   20.12 @@ -15,7 +15,9 @@ import types
   20.13  
   20.14  import sxp
   20.15  import PrettyPrint
   20.16 -from XendProtocol import XendClientProtocol, SynchXendClientProtocol, XendError
   20.17 +from XendProtocol import HttpXendClientProtocol, \
   20.18 +                         UnixXendClientProtocol, \
   20.19 +                         XendError
   20.20  
   20.21  DEBUG = 0
   20.22  
   20.23 @@ -32,15 +34,6 @@ def fileof(val):
   20.24          return val
   20.25      raise XendError('cannot convert value')
   20.26  
   20.27 -# todo: need to sort of what urls/paths are using for objects.
   20.28 -# e.g. for domains at the moment return '0'.
   20.29 -# should probably return abs path w.r.t. server, e.g. /xend/domain/0.
   20.30 -# As an arg, assume abs path is obj uri, otherwise just id.
   20.31 -
   20.32 -# Function to convert to full url: Xend.uri(path), e.g.
   20.33 -# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
   20.34 -# And should accept urls for ids?
   20.35 -
   20.36  class URL:
   20.37      """A URL.
   20.38      """
   20.39 @@ -115,7 +108,7 @@ class Xend:
   20.40          @param root:    xend root path on the server
   20.41          """
   20.42          if client is None:
   20.43 -            client = SynchXendClientProtocol()
   20.44 +            client = HttpXendClientProtocol()
   20.45          self.client = client
   20.46          self.bind(srv, root)
   20.47  
   20.48 @@ -162,9 +155,6 @@ class Xend:
   20.49      def vneturl(self, id=''):
   20.50          return self.url.relative('vnet/' + str(id))
   20.51  
   20.52 -    def eventurl(self, id=''):
   20.53 -        return self.url.relative('event/' + str(id))
   20.54 -
   20.55      def xend(self):
   20.56          return self.xendGet(self.url)
   20.57  
   20.58 @@ -262,34 +252,33 @@ class Xend:
   20.59  
   20.60      def xend_domain_maxmem_set(self, id, memory):
   20.61          return self.xendPost(self.domainurl(id),
   20.62 -                             { 'op'     : 'maxmem_set',
   20.63 -                               'memory' : memory })
   20.64 +                             { 'op'      : 'maxmem_set',
   20.65 +                               'memory'  : memory })
   20.66 +
   20.67 +    def xend_domain_mem_target_set(self, id, mem_target):
   20.68 +        val = self.xendPost(self.domainurl(id),
   20.69 +                            {'op'        : 'mem_target_set',
   20.70 +                             'target'    : mem_target })
   20.71 +        return val
   20.72  
   20.73      def xend_domain_vif_limit(self, id, vif, credit, period):
   20.74          return self.xendPost(self.domainurl(id),
   20.75 -                            { 'op'      : 'vif_credit_limit',
   20.76 +                            { 'op'      : 'vif_limit_set',
   20.77                                'vif'     : vif,
   20.78                                'credit'  : credit,
   20.79                                'period'  : period })
   20.80  
   20.81 -    def xend_domain_vifs(self, id):
   20.82 +    def xend_domain_devices(self, id, type):
   20.83          return self.xendGet(self.domainurl(id),
   20.84 -                            { 'op'      : 'vifs' })
   20.85 -
   20.86 -    def xend_domain_vif(self, id, vif):
   20.87 -        return self.xendGet(self.domainurl(id),
   20.88 -                            { 'op'      : 'vif',
   20.89 -                              'vif'     : vif })
   20.90 +                             {'op'      : 'devices',
   20.91 +                              'type'    : type })
   20.92  
   20.93 -    def xend_domain_vbds(self, id):
   20.94 +    def xend_domain_device(self, id, type, idx):
   20.95          return self.xendGet(self.domainurl(id),
   20.96 -                            {'op'       : 'vbds'})
   20.97 -
   20.98 -    def xend_domain_vbd(self, id, vbd):
   20.99 -        return self.xendGet(self.domainurl(id),
  20.100 -                            {'op'       : 'vbd',
  20.101 -                             'vbd'      : vbd })
  20.102 -
  20.103 +                             {'op'      : 'device',
  20.104 +                              'type'    : type,
  20.105 +                              'idx'     : idx })
  20.106 +    
  20.107      def xend_domain_device_create(self, id, config):
  20.108          return self.xendPost(self.domainurl(id),
  20.109                               {'op'      : 'device_create',
  20.110 @@ -338,63 +327,29 @@ class Xend:
  20.111          return self.xendPost(self.vneturl(id),
  20.112                                {'op'     : 'delete' })
  20.113  
  20.114 -    def xend_event_inject(self, sxpr):
  20.115 -        val = self.xendPost(self.eventurl(),
  20.116 -                             {'op'      : 'inject',
  20.117 -                              'event'   : fileof(sxpr) })
  20.118 +def getHttpServer(srv=None):
  20.119 +    """Create and return a xend client.
  20.120 +    """
  20.121 +    return Xend(srv=srv, client=XendClientProtocol())
  20.122  
  20.123 -    def xend_domain_mem_target_set(self, id, mem_target):
  20.124 -        val = self.xendPost(self.domainurl(id),
  20.125 -                            {'op'         : 'mem_target_set',
  20.126 -                             'target'     : mem_target })
  20.127 -        return val
  20.128 -
  20.129 -def getAsynchXendClientProtocol():
  20.130 -    """Load AsynchXendClientProtocol on demand to avoid the cost.
  20.131 +def getUnixServer(srv=None):
  20.132 +    """Create and return a unix-domain xend client.
  20.133      """
  20.134 -    global AsynchXendClientProtocol
  20.135 -    try:
  20.136 -       AsynchXendClientProtocol
  20.137 -    except:
  20.138 -        from XendAsynchProtocol import AsynchXendClientProtocol
  20.139 -    return AsynchXendClientProtocol
  20.140 -
  20.141 -def getAsynchServer():
  20.142 -    """Load AsynchXendClientProtocol and create an asynch xend client.
  20.143 +    return Xend(client=UnixXendClientProtocol(srv))
  20.144  
  20.145 -    @return asynch Xend
  20.146 -    """
  20.147 -    getAsynchXendClientProtocol()
  20.148 -    return Xend(AsynchXendClientProtocol())
  20.149 -
  20.150 -def xendmain(srv, asynch, fn, args):
  20.151 -    if asynch:
  20.152 -        getAsynchXendClientProtocol()
  20.153 -        client = AsynchXendClientProtocol() 
  20.154 +def xendmain(srv, fn, args, unix=False):
  20.155 +    if unix:
  20.156 +        xend = getUnixServer(srv)
  20.157      else:
  20.158 -        client = None
  20.159 -    xend = Xend(srv=srv, client=client)
  20.160 +        xend = getHttpServer(srv)
  20.161      xend.rc = 0
  20.162      try:
  20.163          v = getattr(xend, fn)(*args)
  20.164 +        PrettyPrint.prettyprint(v)
  20.165 +        return 0
  20.166      except XendError, err:
  20.167          print 'ERROR:', err
  20.168          return 1
  20.169 -    if asynch:
  20.170 -        def cbok(val):
  20.171 -            PrettyPrint.prettyprint(val)
  20.172 -            reactor.stop()
  20.173 -        def cberr(err):
  20.174 -            print 'ERROR:', err
  20.175 -            xend.rc = 1
  20.176 -            reactor.stop()
  20.177 -        v.addCallback(cbok)
  20.178 -        v.addErrback(cberr)
  20.179 -        reactor.run()
  20.180 -        return xend.rc
  20.181 -    else:
  20.182 -        PrettyPrint.prettyprint(v)
  20.183 -        return 0
  20.184  
  20.185  def main(argv):
  20.186      """Call an API function:
  20.187 @@ -411,16 +366,16 @@ python XendClient.py domain 0
  20.188      """
  20.189      global DEBUG
  20.190      from getopt import getopt
  20.191 -    short_options = 'x:ad'
  20.192 -    long_options = ['xend=', 'asynch', 'debug']
  20.193 +    short_options = 'x:au:d'
  20.194 +    long_options = ['xend=', 'unix=', 'debug']
  20.195      (options, args) = getopt(argv[1:], short_options, long_options)
  20.196      srv = None
  20.197 -    asynch = 0
  20.198 +    unix = 1
  20.199      for k, v in options:
  20.200          if k in ['-x', '--xend']:
  20.201              srv = v
  20.202 -        elif k in ['-a', '--asynch']:
  20.203 -            asynch = 1
  20.204 +        elif k in ['-u', '--unix']:
  20.205 +            unix = int(v)
  20.206          elif k in ['-d', '--debug']:
  20.207              DEBUG = 1
  20.208      if len(args):
  20.209 @@ -431,9 +386,9 @@ python XendClient.py domain 0
  20.210          args = []
  20.211      if not fn.startswith('xend'):
  20.212          fn = 'xend_' + fn
  20.213 -    sys.exit(xendmain(srv, asynch, fn, args))
  20.214 +    sys.exit(xendmain(srv, fn, args, unix=unix))
  20.215  
  20.216  if __name__ == "__main__":
  20.217      main(sys.argv)
  20.218  else:    
  20.219 -    server = Xend()
  20.220 +    server = getUnixServer()
    21.1 --- a/tools/python/xen/xend/XendConsole.py	Thu Apr 28 08:56:40 2005 +0000
    21.2 +++ b/tools/python/xen/xend/XendConsole.py	Thu Apr 28 10:46:53 2005 +0000
    21.3 @@ -1,40 +1,29 @@
    21.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    21.5  
    21.6 -import socket
    21.7  import xen.lowlevel.xc
    21.8  xc = xen.lowlevel.xc.new()
    21.9  
   21.10 -import sxp
   21.11 -import XendRoot
   21.12 -xroot = XendRoot.instance()
   21.13 -import XendDB
   21.14 +import XendRoot; xroot = XendRoot.instance()
   21.15  from XendError import XendError
   21.16  
   21.17 -import EventServer
   21.18 -eserver = EventServer.instance()
   21.19 -
   21.20 -from xen.xend.server import SrvDaemon
   21.21 -daemon = SrvDaemon.instance()
   21.22 -
   21.23  class XendConsole:
   21.24  
   21.25      def  __init__(self):
   21.26          pass
   21.27 -        eserver.subscribe('xend.domain.died', self.onDomainDied)
   21.28 -        eserver.subscribe('xend.domain.destroy', self.onDomainDied)
   21.29 -
   21.30 -    def onDomainDied(self, event, val):
   21.31 -        pass
   21.32  
   21.33      def console_ls(self):
   21.34          return [ c.console_port for c in self.consoles() ]
   21.35  
   21.36      def consoles(self):
   21.37 -        return daemon.get_consoles()
   21.38 -    
   21.39 -    def console_create(self, dom, console_port=None):
   21.40 -        consinfo = daemon.console_create(dom, console_port=console_port)
   21.41 -        return consinfo
   21.42 +        l = []
   21.43 +        xd = XendRoot.get_component('xen.xend.XendDomain')
   21.44 +        for vm in xd.domains():
   21.45 +            ctrl = vm.getDeviceController("console", error=False)
   21.46 +            if (not ctrl): continue
   21.47 +            console = ctrl.getDevice(0)
   21.48 +            if (not console): continue
   21.49 +            l.append(console)
   21.50 +        return l
   21.51      
   21.52      def console_get(self, id):
   21.53          id = int(id)
    22.1 --- a/tools/python/xen/xend/XendDomain.py	Thu Apr 28 08:56:40 2005 +0000
    22.2 +++ b/tools/python/xen/xend/XendDomain.py	Thu Apr 28 10:46:53 2005 +0000
    22.3 @@ -6,30 +6,68 @@
    22.4  """
    22.5  import sys
    22.6  import traceback
    22.7 -
    22.8 -from twisted.internet import defer
    22.9 -#defer.Deferred.debug = 1
   22.10 -from twisted.internet import reactor
   22.11 +import time
   22.12  
   22.13  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
   22.14  
   22.15  import sxp
   22.16 -import XendRoot
   22.17 -xroot = XendRoot.instance()
   22.18 +import XendRoot; xroot = XendRoot.instance()
   22.19  import XendDB
   22.20  import XendDomainInfo
   22.21  import XendMigrate
   22.22 -import EventServer
   22.23 +import EventServer; eserver = EventServer.instance()
   22.24  from XendError import XendError
   22.25  from XendLogging import log
   22.26  
   22.27 +from scheduler import Scheduler
   22.28  
   22.29 -from xen.xend.server import SrvDaemon
   22.30 -xend = SrvDaemon.instance()
   22.31 +from xen.xend.server import channel
   22.32  
   22.33 -eserver = EventServer.instance()
   22.34  
   22.35  __all__ = [ "XendDomain" ]
   22.36 +
   22.37 +SHUTDOWN_TIMEOUT = 30
   22.38 +
   22.39 +class DomainShutdown:
   22.40 +    """A pending domain shutdown. The domain is asked to shut down,
   22.41 +    if it has not terminated or rebooted when the timeout expires it
   22.42 +    is destroyed.
   22.43 +    """
   22.44 +
   22.45 +    def __init__(self, dominfo, reason, key, timeout=None):
   22.46 +        if timeout is None:
   22.47 +            timeout = SHUTDOWN_TIMEOUT
   22.48 +        self.start = time.time()
   22.49 +        self.timeout = timeout
   22.50 +        self.dominfo = dominfo
   22.51 +        self.last_restart_time = dominfo.restart_time
   22.52 +        self.last_restart_count = dominfo.restart_count
   22.53 +        self.reason = reason
   22.54 +        self.key = key
   22.55 +
   22.56 +    def getDomain(self):
   22.57 +        return self.dominfo.id
   22.58 +
   22.59 +    def getDomainName(self):
   22.60 +        return self.dominfo.name
   22.61 +
   22.62 +    def getReason(self):
   22.63 +        return self.reason
   22.64 +
   22.65 +    def getTimeout(self):
   22.66 +        return self.timeout
   22.67 +
   22.68 +    def isTerminated(self):
   22.69 +        return self.dominfo.is_terminated()
   22.70 +
   22.71 +    def isRestarted(self):
   22.72 +        return (self.dominfo.restart_count > self.last_restart_count)
   22.73 +
   22.74 +    def isShutdown(self):
   22.75 +        return self.isTerminated() or self.isRestarted()
   22.76 +
   22.77 +    def isExpired(self):
   22.78 +        return (time.time() - self.start) > self.timeout
   22.79          
   22.80  class XendDomain:
   22.81      """Index of all domains. Singleton.
   22.82 @@ -46,8 +84,11 @@ class XendDomain:
   22.83      restarts_by_id = {}
   22.84      restarts_by_name = {}
   22.85  
   22.86 +    """Table of pending domain shutdowns, indexed by domain id."""
   22.87 +    shutdowns_by_id = {}
   22.88 +
   22.89      """Table of delayed calls."""
   22.90 -    schedule = {}
   22.91 +    scheduler = Scheduler()
   22.92      
   22.93      def __init__(self):
   22.94          # Hack alert. Python does not support mutual imports, but XendDomainInfo
   22.95 @@ -67,7 +108,8 @@ class XendDomain:
   22.96      def onVirq(self, event, val):
   22.97          """Event handler for virq.
   22.98          """
   22.99 -        self.reap()
  22.100 +        print 'onVirq>', val
  22.101 +        self.refresh_schedule(delay=0)
  22.102  
  22.103      def schedule_later(self, _delay, _name, _fn, *args):
  22.104          """Schedule a function to be called later (if not already scheduled).
  22.105 @@ -77,34 +119,16 @@ class XendDomain:
  22.106          @param _fn:    function
  22.107          @param args:   arguments
  22.108          """
  22.109 -        if self.schedule.get(_name): return
  22.110 -        self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
  22.111 +        self.scheduler.later(_delay, _name, _fn, args)
  22.112          
  22.113      def schedule_cancel(self, name):
  22.114          """Cancel a scheduled function call.
  22.115          
  22.116          @param name: schedule name to cancel
  22.117          """
  22.118 -        callid = self.schedule.get(name)
  22.119 -        if not callid:
  22.120 -            return
  22.121 -        if callid.active():
  22.122 -            callid.cancel()
  22.123 -        del self.schedule[name]
  22.124 -
  22.125 -    def reap_schedule(self, delay=0):
  22.126 -        """Schedule reap to be called later.
  22.127 +        self.scheduler.cancel(name)
  22.128  
  22.129 -        @param delay: delay in seconds
  22.130 -        """
  22.131 -        self.schedule_later(delay, 'reap', self.reap)
  22.132 -
  22.133 -    def reap_cancel(self):
  22.134 -        """Cancel any scheduled reap.
  22.135 -        """
  22.136 -        self.schedule_cancel('reap')
  22.137 -
  22.138 -    def refresh_schedule(self, delay=0):
  22.139 +    def refresh_schedule(self, delay=1):
  22.140          """Schedule refresh to be called later.
  22.141          
  22.142          @param delay: delay in seconds
  22.143 @@ -116,7 +140,7 @@ class XendDomain:
  22.144          """
  22.145          self.schedule_cancel('refresh')
  22.146  
  22.147 -    def domain_restarts_schedule(self, delay=0):
  22.148 +    def domain_restarts_schedule(self, delay=1):
  22.149          """Schedule domain_restarts to be called later.
  22.150          
  22.151          @param delay: delay in seconds
  22.152 @@ -132,30 +156,46 @@ class XendDomain:
  22.153          """Remove all domain info. Used after reboot.
  22.154          """
  22.155          for (k, v) in self.domain_db.items():
  22.156 -            self._delete_domain(k, notify=0)
  22.157 -            
  22.158 -    def initial_refresh(self):
  22.159 -        """Refresh initial domain info from domain_db.
  22.160 +            self._delete_domain(k, notify=False)
  22.161 +
  22.162 +    def xen_domains(self):
  22.163 +        """Get table of domains indexed by id from xc.
  22.164          """
  22.165 -            
  22.166 -        def cb_all_ok(val):
  22.167 -            self.refresh()
  22.168 -
  22.169          domlist = xc.domain_getinfo()
  22.170          doms = {}
  22.171          for d in domlist:
  22.172              domid = str(d['dom'])
  22.173              doms[domid] = d
  22.174 -        dlist = []
  22.175 +        return doms
  22.176 +
  22.177 +    def xen_domain(self, dom):
  22.178 +        """Get info about a single domain from xc.
  22.179 +        Returns None if not found.
  22.180 +        """
  22.181 +        dom = int(dom)
  22.182 +        dominfo = xc.domain_getinfo(dom, 1)
  22.183 +        if dominfo == [] or dominfo[0]['dom'] != dom:
  22.184 +            dominfo = None
  22.185 +        else:
  22.186 +            dominfo = dominfo[0]
  22.187 +        return dominfo
  22.188 +            
  22.189 +    def initial_refresh(self):
  22.190 +        """Refresh initial domain info from domain_db.
  22.191 +        """
  22.192 +        doms = self.xen_domains()
  22.193          for config in self.domain_db.values():
  22.194              domid = str(sxp.child_value(config, 'id'))
  22.195              if domid in doms:
  22.196 -                d_dom = self._new_domain(config, doms[domid])
  22.197 -                dlist.append(d_dom)
  22.198 +                try:
  22.199 +                    self._new_domain(config, doms[domid])
  22.200 +                    self.update_domain(domid)
  22.201 +                except Exception, ex:
  22.202 +                    log.exception("Error recreating domain info: id=%s", domid)
  22.203 +                    self._delete_domain(domid)
  22.204              else:
  22.205                  self._delete_domain(domid)
  22.206 -        d_all = defer.DeferredList(dlist, fireOnOneErrback=1)
  22.207 -        d_all.addCallback(cb_all_ok)
  22.208 +        self.refresh()
  22.209  
  22.210      def sync(self):
  22.211          """Sync domain db to disk.
  22.212 @@ -177,35 +217,45 @@ class XendDomain:
  22.213  
  22.214          @param savedinfo: saved info from the db
  22.215          @param info:      domain info from xen
  22.216 -        @return: deferred
  22.217 +        @return: domain
  22.218          """
  22.219 -        def cbok(dominfo):
  22.220 -            self.domain_by_id[dominfo.id] = dominfo
  22.221 -            self.domain_by_name[dominfo.name] = dominfo
  22.222 -            if dominfo.restart_pending():
  22.223 -                self.domain_restart_add(dominfo)
  22.224 -        
  22.225 -        deferred = XendDomainInfo.vm_recreate(savedinfo, info)
  22.226 -        deferred.addCallback(cbok)
  22.227 -        return deferred
  22.228 +        dominfo = XendDomainInfo.vm_recreate(savedinfo, info)
  22.229 +        self.domain_by_id[dominfo.id] = dominfo
  22.230 +        self.domain_by_name[dominfo.name] = dominfo
  22.231 +        if dominfo.restart_pending():
  22.232 +            self.domain_restart_add(dominfo)
  22.233 +        return dominfo
  22.234  
  22.235 -    def _add_domain(self, info, notify=1):
  22.236 +    def _add_domain(self, info, notify=True):
  22.237          """Add a domain entry to the tables.
  22.238  
  22.239          @param info:   domain info object
  22.240          @param notify: send a domain created event if true
  22.241          """
  22.242 +        # Remove entries under the wrong id.
  22.243 +        for i, d in self.domain_by_id.items():
  22.244 +            if i != d.id:
  22.245 +                del self.domain_by_id[i]
  22.246 +                if i in self.domain_db:
  22.247 +                    del self.domain_db[i]
  22.248 +                self.db.delete(i)
  22.249 +        # Remove entries under the wrong name.
  22.250 +        for n, d in self.domain_by_name.items():
  22.251 +            if n != d.name:
  22.252 +                del self.domain_by_name[n]
  22.253 +        # But also need to make sure are indexed under correct name.
  22.254 +        # What about entries under info.name ?
  22.255 +        if info.id in self.domain_by_id:
  22.256 +            notify = False
  22.257          self.domain_by_id[info.id] = info
  22.258          self.domain_db[info.id] = info.sxpr()
  22.259 -        for k, d in self.domain_by_name.items():
  22.260 -            if k != d.name:
  22.261 -                del self.domain_by_name[k]
  22.262          if info.name:
  22.263              self.domain_by_name[info.name] = info
  22.264          self.sync_domain(info.id)
  22.265 -        if notify: eserver.inject('xend.domain.create', [info.name, info.id])
  22.266 +        if notify:
  22.267 +            eserver.inject('xend.domain.create', [info.name, info.id])
  22.268  
  22.269 -    def _delete_domain(self, id, notify=1):
  22.270 +    def _delete_domain(self, id, notify=True):
  22.271          """Remove a domain from the tables.
  22.272  
  22.273          @param id:     domain id
  22.274 @@ -214,10 +264,11 @@ class XendDomain:
  22.275          for (k, info) in self.domain_by_name.items():
  22.276              if info.id == id:
  22.277                  del self.domain_by_name[k]
  22.278 -        if id in self.domain_by_id:
  22.279 -            info = self.domain_by_id[id]
  22.280 +        info = self.domain_by_id.get(id)
  22.281 +        if info:
  22.282              del self.domain_by_id[id]
  22.283 -            if notify: eserver.inject('xend.domain.died', [info.name, info.id])
  22.284 +            if notify:
  22.285 +                eserver.inject('xend.domain.died', [info.name, info.id])
  22.286          if id in self.domain_db:
  22.287              del self.domain_db[id]
  22.288              self.db.delete(id)
  22.289 @@ -226,10 +277,9 @@ class XendDomain:
  22.290          """Look for domains that have crashed or stopped.
  22.291          Tidy them up.
  22.292          """
  22.293 -        self.reap_cancel()
  22.294 -        domlist = xc.domain_getinfo()
  22.295          casualties = []
  22.296 -        for d in domlist:
  22.297 +        doms = self.xen_domains()
  22.298 +        for d in doms.values():
  22.299              dead = 0
  22.300              dead = dead or (d['crashed'] or d['shutdown'])
  22.301              dead = dead or (d['dying'] and
  22.302 @@ -239,12 +289,16 @@ class XendDomain:
  22.303          destroyed = 0
  22.304          for d in casualties:
  22.305              id = str(d['dom'])
  22.306 +            #print 'reap>', id
  22.307              dominfo = self.domain_by_id.get(id)
  22.308              name = (dominfo and dominfo.name) or '??'
  22.309 +            if dominfo and dominfo.is_terminated():
  22.310 +                #print 'reap> already terminated:', id
  22.311 +                continue
  22.312              log.debug('XendDomain>reap> domain died name=%s id=%s', name, id)
  22.313              if d['shutdown']:
  22.314                  reason = XendDomainInfo.shutdown_reason(d['shutdown_reason'])
  22.315 -                log.debug('XendDomain>reap> shutdown id=%s reason=%s', id, reason)
  22.316 +                log.debug('XendDomain>reap> shutdown name=%s id=%s reason=%s', name, id, reason)
  22.317                  if reason in ['suspend']:
  22.318                      if dominfo and dominfo.is_terminated():
  22.319                          log.debug('XendDomain>reap> Suspended domain died id=%s', id)
  22.320 @@ -255,39 +309,39 @@ class XendDomain:
  22.321                      eserver.inject('xend.domain.exit', [name, id, reason])
  22.322                      self.domain_restart_schedule(id, reason)
  22.323              else:
  22.324 -               eserver.inject('xend.domain.exit', [name, id, 'crash']) 
  22.325 +               eserver.inject('xend.domain.exit', [name, id, 'crash'])
  22.326              destroyed += 1
  22.327              self.final_domain_destroy(id)
  22.328          if self.domain_restarts_exist():
  22.329              self.domain_restarts_schedule()
  22.330 -        if destroyed:
  22.331 -            self.refresh_schedule(delay=1)
  22.332  
  22.333      def refresh(self):
  22.334          """Refresh domain list from Xen.
  22.335          """
  22.336          self.refresh_cancel()
  22.337 -        domlist = xc.domain_getinfo()
  22.338 -        # Index the domlist by id.
  22.339 +        self.refresh_schedule(delay=10)
  22.340 +        self.reap()
  22.341 +        doms = self.xen_domains()
  22.342          # Add entries for any domains we don't know about.
  22.343 -        doms = {}
  22.344 -        for d in domlist:
  22.345 -            id = str(d['dom'])
  22.346 -            doms[id] = d
  22.347 +        for (id, d) in doms.items():
  22.348              if id not in self.domain_by_id:
  22.349 +                log.info("Creating entry for unknown domain: id=%s", id)
  22.350                  savedinfo = None
  22.351 -                deferred = XendDomainInfo.vm_recreate(savedinfo, d)
  22.352 -                def cbok(dominfo):
  22.353 +                try:
  22.354 +                    dominfo = XendDomainInfo.vm_recreate(savedinfo, d)
  22.355                      self._add_domain(dominfo)
  22.356 -                deferred.addCallback(cbok)
  22.357 +                except Exception, ex:
  22.358 +                    log.exception("Error creating domain info: id=%s", id)
  22.359          # Remove entries for domains that no longer exist.
  22.360 +        # Update entries for existing domains.
  22.361          for d in self.domain_by_id.values():
  22.362              info = doms.get(d.id)
  22.363              if info:
  22.364                  d.update(info)
  22.365 +            elif d.restart_pending():
  22.366 +                pass
  22.367              else:
  22.368                  self._delete_domain(d.id)
  22.369 -        self.reap_schedule(delay=1)
  22.370  
  22.371      def update_domain(self, id):
  22.372          """Update the saved info for a domain.
  22.373 @@ -304,19 +358,13 @@ class XendDomain:
  22.374  
  22.375          @param id: domain id
  22.376          """
  22.377 -        dom = int(id)
  22.378 -        dominfo = xc.domain_getinfo(dom, 1)
  22.379 -        if dominfo == [] or dominfo[0]['dom'] != dom:
  22.380 -            try:
  22.381 -                self._delete_domain(id)
  22.382 -            except:
  22.383 -                log.exception('refresh_domain> error')
  22.384 -                raise
  22.385 -                pass
  22.386 -        else:
  22.387 +        dominfo = self.xen_domain(id)
  22.388 +        if dominfo:
  22.389              d = self.domain_by_id.get(id)
  22.390              if d:
  22.391 -                d.update(dominfo[0])
  22.392 +                d.update(dominfo)
  22.393 +        else:
  22.394 +            self._delete_domain(id)
  22.395  
  22.396      def domain_ls(self):
  22.397          """Get list of domain names.
  22.398 @@ -346,30 +394,33 @@ class XendDomain:
  22.399          """Create a domain from a configuration.
  22.400  
  22.401          @param config: configuration
  22.402 -        @return: deferred
  22.403 +        @return: domain
  22.404          """
  22.405 -        def cbok(dominfo):
  22.406 -            self._add_domain(dominfo)
  22.407 -            return dominfo
  22.408 -        deferred = XendDomainInfo.vm_create(config)
  22.409 -        deferred.addCallback(cbok)
  22.410 -        return deferred
  22.411 +        dominfo = XendDomainInfo.vm_create(config)
  22.412 +        self._add_domain(dominfo)
  22.413 +        return dominfo
  22.414  
  22.415      def domain_restart(self, dominfo):
  22.416          """Restart a domain.
  22.417  
  22.418          @param dominfo: domain object
  22.419 -        @return: deferred
  22.420          """
  22.421 -        def cbok(dominfo):
  22.422 -            self._add_domain(dominfo)
  22.423 -            return dominfo
  22.424 -        log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name)
  22.425 +        log.info("Restarting domain: name=%s id=%s", dominfo.name, dominfo.id)
  22.426          eserver.inject("xend.domain.restart",
  22.427                         [dominfo.name, dominfo.id, "begin"])
  22.428 -        deferred = dominfo.restart()
  22.429 -        deferred.addCallback(cbok)
  22.430 -        return deferred        
  22.431 +        try:
  22.432 +            dominfo.restart()
  22.433 +            self._add_domain(dominfo)
  22.434 +            log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
  22.435 +            eserver.inject("xend.domain.restart",
  22.436 +                           [dominfo.name, dominfo.id, "success"])
  22.437 +            self.domain_unpause(dominfo.id)
  22.438 +        except Exception, ex:
  22.439 +            log.exception("Exception restarting domain: name=%s id=%s",
  22.440 +                          dominfo.name, dominfo.id)
  22.441 +            eserver.inject("xend.domain.restart",
  22.442 +                           [dominfo.name, dominfo.id, "fail"])
  22.443 +        return dominfo
  22.444  
  22.445      def domain_configure(self, id, vmconfig):
  22.446          """Configure an existing domain. This is intended for internal
  22.447 @@ -377,38 +428,24 @@ class XendDomain:
  22.448  
  22.449          @param id:       domain id
  22.450          @param vmconfig: vm configuration
  22.451 -        @return: deferred
  22.452          """
  22.453          config = sxp.child_value(vmconfig, 'config')
  22.454          dominfo = self.domain_lookup(id)
  22.455          log.debug('domain_configure> id=%s config=%s', str(id), str(config))
  22.456          if dominfo.config:
  22.457              raise XendError("Domain already configured: " + dominfo.id)
  22.458 -        def cbok(dominfo):
  22.459 -            self._add_domain(dominfo)
  22.460 -            return dominfo
  22.461 -        deferred = dominfo.dom_construct(dominfo.dom, config)
  22.462 -        deferred.addCallback(cbok)
  22.463 -        return deferred
  22.464 +        dominfo.dom_construct(dominfo.dom, config)
  22.465 +        self._add_domain(dominfo)
  22.466 +        return dominfo
  22.467      
  22.468 -    def domain_restore(self, src, progress=0):
  22.469 +    def domain_restore(self, src, progress=False):
  22.470          """Restore a domain from file.
  22.471  
  22.472          @param src:      source file
  22.473          @param progress: output progress if true
  22.474 -        @return: deferred
  22.475          """
  22.476 -        
  22.477 -        if 0:
  22.478 -            def cbok(dominfo):
  22.479 -                self._add_domain(dominfo)
  22.480 -                return dominfo
  22.481 -            deferred = XendDomainInfo.vm_restore(src, progress=progress)
  22.482 -            deferred.addCallback(cbok)
  22.483 -        else:
  22.484 -            xmigrate = XendMigrate.instance()
  22.485 -            deferred = xmigrate.restore_begin(src)
  22.486 -        return deferred
  22.487 +        xmigrate = XendMigrate.instance()
  22.488 +        return xmigrate.restore_begin(src)
  22.489      
  22.490      def domain_get(self, id):
  22.491          """Get up-to-date info about a domain.
  22.492 @@ -425,7 +462,7 @@ class XendDomain:
  22.493          dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name)
  22.494          if dominfo:
  22.495              return dominfo
  22.496 -        raise XendError('invalid domain:' + name)
  22.497 +        raise XendError('invalid domain: ' + name)
  22.498  
  22.499      def domain_exists(self, name):
  22.500          name = str(name)
  22.501 @@ -470,15 +507,54 @@ class XendDomain:
  22.502          if reason == 'halt':
  22.503              self.domain_restart_cancel(dominfo.id)
  22.504          else:
  22.505 -            self.domain_restart_schedule(dominfo.id, reason, force=1)
  22.506 +            self.domain_restart_schedule(dominfo.id, reason, force=True)
  22.507          eserver.inject('xend.domain.shutdown', [dominfo.name, dominfo.id, reason])
  22.508          if reason == 'halt':
  22.509              reason = 'poweroff'
  22.510 -        val = xend.domain_shutdown(dominfo.id, reason, key)
  22.511 -        self.refresh_schedule()
  22.512 +        val = dominfo.shutdown(reason, key=key)
  22.513 +        self.add_shutdown(dominfo, reason, key)
  22.514 +        self.refresh_schedule(delay=10)
  22.515          return val
  22.516  
  22.517 -    def domain_restart_schedule(self, id, reason, force=0):
  22.518 +    def add_shutdown(self, dominfo, reason, key):
  22.519 +        """Add a pending shutdown for a domain.
  22.520 +        This will destroy the domain if the shutdown times out.
  22.521 +        """
  22.522 +        if dominfo.id in self.shutdowns_by_id:
  22.523 +            return
  22.524 +        self.shutdowns_by_id[dominfo.id] = DomainShutdown(dominfo, reason, key)
  22.525 +        self.domain_shutdowns()
  22.526 +
  22.527 +    def domain_shutdowns(self):
  22.528 +        """Process pending domain shutdowns.
  22.529 +        Destroys domains whose shutdowns have timed out.
  22.530 +        """
  22.531 +        self.schedule_cancel('domain_shutdowns')
  22.532 +        timeout = SHUTDOWN_TIMEOUT
  22.533 +        for shutdown in self.shutdowns_by_id.values():
  22.534 +            id = shutdown.getDomain()
  22.535 +            if shutdown.isShutdown():
  22.536 +                # Shutdown done - remove.
  22.537 +                print 'domain_shutdowns> done: ', id
  22.538 +                del self.shutdowns_by_id[id]
  22.539 +            elif shutdown.isExpired():
  22.540 +                # Shutdown expired - remove and destroy domain.
  22.541 +                del self.shutdowns_by_id[id]
  22.542 +                try:
  22.543 +                    log.info("Domain shutdown timeout expired: name=%s id=%s",
  22.544 +                             shutdown.getDomainName(), id)
  22.545 +                    self.domain_destroy(id, reason=shutdown.getReason())
  22.546 +                except Exception:
  22.547 +                    pass
  22.548 +            else:
  22.549 +                # Shutdown still pending.
  22.550 +                print 'domain_shutdowns> pending: ', id
  22.551 +                timeout = min(timeout, shutdown.getTimeout())
  22.552 +        if self.shutdowns_by_id:
  22.553 +            # Pending shutdowns remain - reschedule.
  22.554 +            self.schedule_later(timeout, 'domain_shutdowns', self.domain_shutdowns)
  22.555 +
  22.556 +    def domain_restart_schedule(self, id, reason, force=False):
  22.557          """Schedule a restart for a domain if it needs one.
  22.558  
  22.559          @param id:     domain id
  22.560 @@ -510,7 +586,8 @@ class XendDomain:
  22.561          """
  22.562          dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id)
  22.563          if dominfo:
  22.564 -            log.info('Cancelling restart for domain: name=%s id=%s', dominfo.name, dominfo.id)
  22.565 +            log.info('Cancelling restart for domain: name=%s id=%s',
  22.566 +                     dominfo.name, dominfo.id)
  22.567              eserver.inject("xend.domain.restart",
  22.568                             [dominfo.name, dominfo.id, "cancel"])
  22.569              dominfo.restart_cancel()
  22.570 @@ -521,36 +598,22 @@ class XendDomain:
  22.571          """Execute any scheduled domain restarts for domains that have gone.
  22.572          """
  22.573          self.domain_restarts_cancel()
  22.574 +        doms = self.xen_domains()
  22.575          for dominfo in self.restarts_by_id.values():
  22.576 -            if dominfo.id in self.domain_by_id:
  22.577 +            print 'domain_restarts>', dominfo.name, dominfo.id
  22.578 +            info = doms.get(dominfo.id)
  22.579 +            if info:
  22.580                  # Don't execute restart for domains still running.
  22.581 +                print 'domain_restarts> still runnning: ', dominfo.name
  22.582                  continue
  22.583              # Remove it from the restarts.
  22.584              del self.restarts_by_id[dominfo.id]
  22.585              del self.restarts_by_name[dominfo.name]
  22.586 -            try:
  22.587 -                def cbok(dominfo):
  22.588 -                    log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id)
  22.589 -                    eserver.inject("xend.domain.restart",
  22.590 -                                   [dominfo.name, dominfo.id, "success"])
  22.591 -                    self.domain_unpause(dominfo.id)
  22.592 -                def cberr(err):
  22.593 -                    log.exception("Delayed exception restarting domain: name=%s id=%s",
  22.594 -                                  dominfo.name, dominfo.id)
  22.595 -                    eserver.inject("xend.domain.restart",
  22.596 -                                   [dominfo.name, dominfo.id, "fail"])
  22.597 -                    
  22.598 -                deferred = self.domain_restart(dominfo)
  22.599 -                deferred.addCallback(cbok)
  22.600 -                deferred.addErrback(cberr)
  22.601 -            except:
  22.602 -                log.exception("Exception restarting domain: name=%s id=%s",
  22.603 -                              dominfo.name, dominfo.id)
  22.604 -                eserver.inject("xend.domain.restart",
  22.605 -                               [dominfo.name, dominfo.id, "fail"])
  22.606 +            print 'domain_restarts> restarting: ', dominfo.name
  22.607 +            self.domain_restart(dominfo)
  22.608          if self.domain_restarts_exist():
  22.609              # Run again later if any restarts remain.
  22.610 -            self.refresh_schedule(delay=5)
  22.611 +            self.refresh_schedule(delay=10)
  22.612  
  22.613      def domain_restarts_exist(self):
  22.614          return len(self.restarts_by_id)
  22.615 @@ -560,14 +623,17 @@ class XendDomain:
  22.616  
  22.617          @param id: domain id
  22.618          """
  22.619 -        dominfo = self.domain_lookup(id)
  22.620 -        log.info('Destroying domain: name=%s', dominfo.name)
  22.621 -        eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
  22.622 -        if dominfo:
  22.623 +        try:
  22.624 +            dominfo = self.domain_lookup(id)
  22.625 +            log.info('Destroying domain: name=%s', dominfo.name)
  22.626 +            eserver.inject('xend.domain.destroy', [dominfo.name, dominfo.id])
  22.627              val = dominfo.destroy()
  22.628 -        else:
  22.629 +        except:
  22.630              #todo
  22.631 -            val = xc.domain_destroy(dom=dominfo.dom)
  22.632 +            try:
  22.633 +                val = xc.domain_destroy(dom=int(id))
  22.634 +            except Exception, ex:
  22.635 +                raise XendError(str(ex))
  22.636          return val       
  22.637  
  22.638      def domain_destroy(self, id, reason='halt'):
  22.639 @@ -580,31 +646,28 @@ class XendDomain:
  22.640          if reason == 'halt':
  22.641              self.domain_restart_cancel(id)
  22.642          elif reason == 'reboot':
  22.643 -            self.domain_restart_schedule(id, reason, force=1)
  22.644 +            self.domain_restart_schedule(id, reason, force=True)
  22.645          val = self.final_domain_destroy(id)
  22.646          self.refresh_schedule()
  22.647          return val
  22.648  
  22.649 -    def domain_migrate(self, id, dst, live=0, resource=0):
  22.650 +    def domain_migrate(self, id, dst, live=False, resource=0):
  22.651          """Start domain migration.
  22.652  
  22.653          @param id: domain id
  22.654 -        @return: deferred
  22.655          """
  22.656          # Need a cancel too?
  22.657          # Don't forget to cancel restart for it.
  22.658          dominfo = self.domain_lookup(id)
  22.659          xmigrate = XendMigrate.instance()
  22.660 -        val = xmigrate.migrate_begin(dominfo, dst, live=live, resource=resource)
  22.661 -        return val
  22.662 +        return xmigrate.migrate_begin(dominfo, dst, live=live, resource=resource)
  22.663  
  22.664 -    def domain_save(self, id, dst, progress=0):
  22.665 +    def domain_save(self, id, dst, progress=False):
  22.666          """Start saving a domain to file.
  22.667  
  22.668          @param id:       domain id
  22.669          @param dst:      destination file
  22.670          @param progress: output progress if true
  22.671 -        @return: deferred
  22.672          """
  22.673          dominfo = self.domain_lookup(id)
  22.674          xmigrate = XendMigrate.instance()
  22.675 @@ -647,12 +710,11 @@ class XendDomain:
  22.676  
  22.677          @param id:       domain id
  22.678          @param devconfig: device configuration
  22.679 -        @return: deferred
  22.680          """
  22.681          dominfo = self.domain_lookup(id)
  22.682 -        self.refresh_schedule()
  22.683          val = dominfo.device_create(devconfig)
  22.684          self.update_domain(dominfo.id)
  22.685 +        self.refresh_schedule()
  22.686          return val
  22.687  
  22.688      def domain_device_configure(self, id, devconfig, idx):
  22.689 @@ -664,9 +726,9 @@ class XendDomain:
  22.690          @return: updated device configuration
  22.691          """
  22.692          dominfo = self.domain_lookup(id)
  22.693 -        self.refresh_schedule()
  22.694          val = dominfo.device_configure(devconfig, idx)
  22.695          self.update_domain(dominfo.id)
  22.696 +        self.refresh_schedule()
  22.697          return val
  22.698      
  22.699      def domain_device_refresh(self, id, type, idx):
  22.700 @@ -677,9 +739,9 @@ class XendDomain:
  22.701          @param type: device type
  22.702          """
  22.703          dominfo = self.domain_lookup(id)
  22.704 -        self.refresh_schedule()
  22.705          val = dominfo.device_refresh(type, idx)
  22.706          self.update_domain(dominfo.id)
  22.707 +        self.refresh_schedule()
  22.708          return val
  22.709  
  22.710      def domain_device_destroy(self, id, type, idx):
  22.711 @@ -690,9 +752,9 @@ class XendDomain:
  22.712          @param type: device type
  22.713          """
  22.714          dominfo = self.domain_lookup(id)
  22.715 -        self.refresh_schedule()
  22.716          val = dominfo.device_destroy(type, idx)
  22.717          self.update_domain(dominfo.id)
  22.718 +        self.refresh_schedule()
  22.719          return val
  22.720  
  22.721      def domain_devtype_ls(self, id, type):
  22.722 @@ -703,8 +765,7 @@ class XendDomain:
  22.723          @return: device indexes
  22.724          """
  22.725          dominfo = self.domain_lookup(id)
  22.726 -        devs = dominfo.get_devices(type)
  22.727 -        return devs
  22.728 +        return dominfo.getDeviceIndexes(type)
  22.729  
  22.730      def domain_devtype_get(self, id, type, idx):
  22.731          """Get a device from a domain.
  22.732 @@ -715,51 +776,17 @@ class XendDomain:
  22.733          @return: device object (or None)
  22.734          """
  22.735          dominfo = self.domain_lookup(id)
  22.736 -        return dominfo.get_device_by_index(type, idx)
  22.737 +        return dominfo.getDeviceByIndex(type, idx)
  22.738  
  22.739 -    def domain_vif_credit_limit(self, id, vif, credit, period):
  22.740 +    def domain_vif_limit_set(self, id, vif, credit, period):
  22.741          """Limit the vif's transmission rate
  22.742          """
  22.743          dominfo = self.domain_lookup(id)
  22.744 -        try:
  22.745 -            return dominfo.limit_vif(vif, credit, period)
  22.746 -        except Exception, ex:
  22.747 -            raise XendError(str(ex))
  22.748 +        dev = dominfo.getDeviceById('vif', vif)
  22.749 +        if not dev:
  22.750 +            raise XendError("invalid vif")
  22.751 +        return dev.setCreditLimit(credit, period)
  22.752          
  22.753 -    def domain_vif_ls(self, id):
  22.754 -        """Get list of virtual network interface (vif) indexes for a domain.
  22.755 -
  22.756 -        @param id: domain
  22.757 -        @return: vif indexes
  22.758 -        """
  22.759 -        return self.domain_devtype_ls(id, 'vif')
  22.760 -
  22.761 -    def domain_vif_get(self, id, vif):
  22.762 -        """Get a virtual network interface (vif) from a domain.
  22.763 -
  22.764 -        @param id: domain
  22.765 -        @param vif: vif index
  22.766 -        @return: vif device object (or None)
  22.767 -        """
  22.768 -        return self.domain_devtype_get(id, 'vif', vif)
  22.769 -
  22.770 -    def domain_vbd_ls(self, id):
  22.771 -        """Get list of virtual block device (vbd) indexes for a domain.
  22.772 -
  22.773 -        @param id: domain
  22.774 -        @return: vbd indexes
  22.775 -        """
  22.776 -        return self.domain_devtype_ls(id, 'vbd')
  22.777 -
  22.778 -    def domain_vbd_get(self, id, vbd):
  22.779 -        """Get a virtual block device (vbd) from a domain.
  22.780 -
  22.781 -        @param id: domain
  22.782 -        @param vbd: vbd index
  22.783 -        @return: vbd device (or None)
  22.784 -        """
  22.785 -        return self.domain_devtype_get(id, 'vbd', vbd)
  22.786 -
  22.787      def domain_shadow_control(self, id, op):
  22.788          """Shadow page control.
  22.789  
  22.790 @@ -787,7 +814,8 @@ class XendDomain:
  22.791              raise XendError(str(ex))
  22.792  
  22.793      def domain_mem_target_set(self, id, target):
  22.794 -        return xend.domain_mem_target_set(id, target)
  22.795 +        dominfo = self.domain_lookup(id)
  22.796 +        return dominfo.mem_target_set(target)
  22.797          
  22.798  
  22.799  
    23.1 --- a/tools/python/xen/xend/XendDomainConfig.py	Thu Apr 28 08:56:40 2005 +0000
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,44 +0,0 @@
    23.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    23.5 -
    23.6 -"""Handler for persistent domain configs.
    23.7 -
    23.8 -"""
    23.9 -
   23.10 -import sxp
   23.11 -import XendDB
   23.12 -import XendDomain
   23.13 -
   23.14 -__all__ = [ "XendDomainConfig" ]
   23.15 -
   23.16 -class XendDomainConfig:
   23.17 -
   23.18 -    dbpath = 'config'
   23.19 -
   23.20 -    def __init__(self):
   23.21 -        self.db = XendDB.XendDB(self.dbpath)
   23.22 -
   23.23 -    def domain_config_ls(self, path):
   23.24 -        return self.db.ls(path)
   23.25 -
   23.26 -    def domain_config_create(self, path, sxpr):
   23.27 -        self.db.save(path, sxpr)
   23.28 -        pass
   23.29 -
   23.30 -    def domain_config_delete(self, path):
   23.31 -        self.db.delete(path)
   23.32 -
   23.33 -    def domain_config_instance(self, path):
   23.34 -        """Create a domain from a config.
   23.35 -        """
   23.36 -        config = self.db.fetch(path)
   23.37 -        xd = XendDomain.instance()
   23.38 -        newdom = xd.domain_create(config)
   23.39 -        return newdom
   23.40 -
   23.41 -def instance():
   23.42 -    global inst
   23.43 -    try:
   23.44 -        inst
   23.45 -    except:
   23.46 -        inst = XendDomainConfig()
   23.47 -    return inst
    24.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Apr 28 08:56:40 2005 +0000
    24.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Apr 28 10:46:53 2005 +0000
    24.3 @@ -4,41 +4,29 @@
    24.4  Includes support for domain construction, using
    24.5  open-ended configurations.
    24.6  
    24.7 -Author: Mike Wray <mike.wray@hpl.hp.com>
    24.8 +Author: Mike Wray <mike.wray@hp.com>
    24.9  
   24.10  """
   24.11  
   24.12  import string
   24.13 -import types
   24.14 -import re
   24.15 -import sys
   24.16  import os
   24.17  import time
   24.18  
   24.19 -from twisted.internet import defer
   24.20 -
   24.21  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
   24.22  import xen.util.ip
   24.23  from xen.util.ip import _readline, _readlines
   24.24 -from xen.xend.server import channel
   24.25 +from xen.xend.server import channel, controller
   24.26 +
   24.27 +from server.channel import channelFactory
   24.28 +import server.SrvDaemon; xend = server.SrvDaemon.instance()
   24.29 +from server import messages
   24.30  
   24.31  import sxp
   24.32 -
   24.33 -import XendConsole
   24.34 -xendConsole = XendConsole.instance()
   24.35  from XendLogging import log
   24.36 +from XendError import VmError
   24.37  from XendRoot import get_component
   24.38  
   24.39 -import server.SrvDaemon
   24.40 -xend = server.SrvDaemon.instance()
   24.41 -
   24.42 -from XendError import VmError
   24.43 -
   24.44 -"""The length of domain names that Xen can handle.
   24.45 -The names stored in Xen itself are not used for much, and
   24.46 -xend can handle domain names of any length.
   24.47 -"""
   24.48 -MAX_DOMAIN_NAME = 15
   24.49 +from PrettyPrint import prettyprint
   24.50  
   24.51  """Flag for a block device backend domain."""
   24.52  SIF_BLK_BE_DOMAIN = (1<<4)
   24.53 @@ -48,8 +36,10 @@ SIF_NET_BE_DOMAIN = (1<<5)
   24.54  
   24.55  """Shutdown code for poweroff."""
   24.56  DOMAIN_POWEROFF = 0
   24.57 +
   24.58  """Shutdown code for reboot."""
   24.59  DOMAIN_REBOOT   = 1
   24.60 +
   24.61  """Shutdown code for suspend."""
   24.62  DOMAIN_SUSPEND  = 2
   24.63  
   24.64 @@ -59,6 +49,15 @@ shutdown_reasons = {
   24.65      DOMAIN_REBOOT  : "reboot",
   24.66      DOMAIN_SUSPEND : "suspend" }
   24.67  
   24.68 +"""Map shutdown reasons to the message type to use.
   24.69 +"""
   24.70 +shutdown_messages = {
   24.71 +    'poweroff' : 'shutdown_poweroff_t',
   24.72 +    'reboot'   : 'shutdown_reboot_t',
   24.73 +    'suspend'  : 'shutdown_suspend_t',
   24.74 +    'sysrq'    : 'shutdown_sysrq_t',
   24.75 +    }
   24.76 +
   24.77  RESTART_ALWAYS   = 'always'
   24.78  RESTART_ONREBOOT = 'onreboot'
   24.79  RESTART_NEVER    = 'never'
   24.80 @@ -164,21 +163,12 @@ Indexed by device type.
   24.81  """
   24.82  device_handlers = {}
   24.83  
   24.84 -def add_device_handler(name, h):
   24.85 -    """Add a handler for a device type.
   24.86 -
   24.87 -    @param name:     device type
   24.88 -    @param h:        handler: fn(vm, dev)
   24.89 -    """
   24.90 -    device_handlers[name] = h
   24.91 +def add_device_handler(name, type):
   24.92 +    device_handlers[name] = type
   24.93  
   24.94  def get_device_handler(name):
   24.95 -    """Get the handler for a device type.
   24.96 -
   24.97 -    @param name :     device type
   24.98 -    @return; handler or None
   24.99 -    """
  24.100 -    return device_handlers.get(name)
  24.101 +    return device_handlers[name]
  24.102 +    
  24.103  
  24.104  def vm_create(config):
  24.105      """Create a VM from a configuration.
  24.106 @@ -186,11 +176,11 @@ def vm_create(config):
  24.107      is destroyed.
  24.108  
  24.109      @param config    configuration
  24.110 -    @return: Deferred
  24.111      @raise: VmError for invalid configuration
  24.112      """
  24.113      vm = XendDomainInfo()
  24.114 -    return vm.construct(config)
  24.115 +    vm.construct(config)
  24.116 +    return vm
  24.117  
  24.118  def vm_recreate(savedinfo, info):
  24.119      """Create the VM object for an existing domain.
  24.120 @@ -199,37 +189,37 @@ def vm_recreate(savedinfo, info):
  24.121      @type  savedinfo: sxpr
  24.122      @param info:      domain info from xc
  24.123      @type  info:      xc domain dict
  24.124 -    @return: deferred
  24.125      """
  24.126 +    print 'vm_recreate>'
  24.127 +    print 'savedinfo=' ; prettyprint(savedinfo)
  24.128 +    print 'info=', info
  24.129      vm = XendDomainInfo()
  24.130 -    vm.recreate = 1
  24.131 +    vm.recreate = True
  24.132      vm.savedinfo = savedinfo
  24.133      vm.setdom(info['dom'])
  24.134 -    #vm.name = info['name']
  24.135      vm.memory = info['mem_kb']/1024
  24.136      start_time = sxp.child_value(savedinfo, 'start_time')
  24.137      if start_time is not None:
  24.138          vm.start_time = float(start_time)
  24.139      vm.restart_state = sxp.child_value(savedinfo, 'restart_state')
  24.140 +    vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0))
  24.141      restart_time = sxp.child_value(savedinfo, 'restart_time')
  24.142      if restart_time is not None:
  24.143          vm.restart_time = float(restart_time)
  24.144      config = sxp.child_value(savedinfo, 'config')
  24.145      if config:
  24.146 -        d = vm.construct(config)
  24.147 +        vm.construct(config)
  24.148      else:
  24.149          vm.name = sxp.child_value(savedinfo, 'name', "Domain-%d" % info['dom'])
  24.150 -        d = defer.succeed(vm)
  24.151 -    vm.recreate = 0
  24.152 +    vm.recreate = False
  24.153      vm.savedinfo = None
  24.154 -    return d
  24.155 +    return vm
  24.156  
  24.157 -def vm_restore(src, progress=0):
  24.158 +def vm_restore(src, progress=False):
  24.159      """Restore a VM from a disk image.
  24.160  
  24.161      src      saved state to restore
  24.162      progress progress reporting flag
  24.163 -    returns  deferred
  24.164      raises   VmError for invalid configuration
  24.165      """
  24.166      vm = XendDomainInfo()
  24.167 @@ -244,12 +234,9 @@ def vm_restore(src, progress=0):
  24.168          config = sxp.child_value(vmconfig, 'config')
  24.169      except Exception, ex:
  24.170          raise VmError('config error: ' + str(ex))
  24.171 -    deferred = vm.dom_construct(dom, config)
  24.172 -    def vifs_cb(val, vm):
  24.173 -        vif_up(vm.ipaddrs)
  24.174 -        return vm
  24.175 -    deferred.addCallback(vifs_cb, vm)
  24.176 -    return deferred
  24.177 +    vm.dom_construct(dom, config)
  24.178 +    vif_up(vm.ipaddrs)
  24.179 +    return vm
  24.180      
  24.181  def dom_get(dom):
  24.182      """Get info from xen for an existing domain.
  24.183 @@ -262,27 +249,6 @@ def dom_get(dom):
  24.184          return domlist[0]
  24.185      return None
  24.186      
  24.187 -def append_deferred(dlist, v):
  24.188 -    """Append a value to a deferred list if it is a deferred.
  24.189 -
  24.190 -    @param dlist: list of deferreds
  24.191 -    @param v: value to add
  24.192 -    """
  24.193 -    if isinstance(v, defer.Deferred):
  24.194 -        dlist.append(v)
  24.195 -
  24.196 -def dlist_err(val):
  24.197 -    """Error callback suitable for a deferred list.
  24.198 -    In a deferred list the error callback is called with with Failure((error, index)).
  24.199 -    This callback extracts the error and returns it.
  24.200 -
  24.201 -    @param val: Failure containing (error, index)
  24.202 -    @type val: twisted.internet.failure.Failure 
  24.203 -    """
  24.204 -    
  24.205 -    (error, index) = val.value
  24.206 -    return error
  24.207 -
  24.208  class XendDomainInfo:
  24.209      """Virtual machine object."""
  24.210  
  24.211 @@ -303,25 +269,30 @@ class XendDomainInfo:
  24.212          self.image = None
  24.213          self.ramdisk = None
  24.214          self.cmdline = None
  24.215 -        self.console = None
  24.216 -        self.devices = {}
  24.217 -        self.device_index = {}
  24.218 +
  24.219 +        self.channel = None
  24.220 +        self.controllers = {}
  24.221 +        
  24.222          self.configs = []
  24.223 +        
  24.224          self.info = None
  24.225          self.ipaddrs = []
  24.226 -        self.blkif_backend = 0
  24.227 -        self.netif_backend = 0
  24.228 +        self.blkif_backend = False
  24.229 +        self.netif_backend = False
  24.230          #todo: state: running, suspended
  24.231          self.state = STATE_VM_OK
  24.232          #todo: set to migrate info if migrating
  24.233          self.migrate = None
  24.234 +        
  24.235          self.restart_mode = RESTART_ONREBOOT
  24.236          self.restart_state = None
  24.237          self.restart_time = None
  24.238 +        self.restart_count = 0
  24.239 +        
  24.240          self.console_port = None
  24.241          self.savedinfo = None
  24.242          self.image_handler = None
  24.243 -        self.is_vmx = 0
  24.244 +        self.is_vmx = False
  24.245          self.vcpus = 1
  24.246  
  24.247      def setdom(self, dom):
  24.248 @@ -332,6 +303,15 @@ class XendDomainInfo:
  24.249          self.dom = int(dom)
  24.250          self.id = str(dom)
  24.251  
  24.252 +    def getDomain(self):
  24.253 +        return self.dom
  24.254 +
  24.255 +    def getName(self):
  24.256 +        return self.name
  24.257 +
  24.258 +    def getChannel(self):
  24.259 +        return self.channel
  24.260 +
  24.261      def update(self, info):
  24.262          """Update with  info from xc.domain_getinfo().
  24.263          """
  24.264 @@ -343,8 +323,9 @@ class XendDomainInfo:
  24.265          s += " id=" + self.id
  24.266          s += " name=" + self.name
  24.267          s += " memory=" + str(self.memory)
  24.268 -        if self.console:
  24.269 -            s += " console=" + str(self.console.console_port)
  24.270 +        console = self.getConsole()
  24.271 +        if console:
  24.272 +            s += " console=" + str(console.console_port)
  24.273          if self.image:
  24.274              s += " image=" + self.image
  24.275          s += ""
  24.276 @@ -352,6 +333,71 @@ class XendDomainInfo:
  24.277  
  24.278      __repr__ = __str__
  24.279  
  24.280 +    def getDeviceTypes(self):
  24.281 +        return self.controllers.keys()
  24.282 +
  24.283 +    def getDeviceControllers(self):
  24.284 +        return self.controllers.values()
  24.285 +
  24.286 +    def getDeviceController(self, type, error=True):
  24.287 +        ctrl = self.controllers.get(type)
  24.288 +        if not ctrl and error:
  24.289 +            raise XendError("invalid device type:" + type)
  24.290 +        return ctrl
  24.291 +    
  24.292 +    def findDeviceController(self, type):
  24.293 +        return (self.getDeviceController(type, error=False)
  24.294 +                or self.createDeviceController(type))
  24.295 +
  24.296 +    def createDeviceController(self, type):
  24.297 +        ctrl = controller.createDevController(type, self, recreate=self.recreate)
  24.298 +        self.controllers[type] = ctrl
  24.299 +        return ctrl
  24.300 +
  24.301 +    def createDevice(self, type, devconfig, recreate=False):
  24.302 +        ctrl = self.findDeviceController(type)
  24.303 +        return ctrl.createDevice(devconfig, recreate=self.recreate)
  24.304 +
  24.305 +    def configureDevice(self, type, id, devconfig):
  24.306 +        ctrl = self.getDeviceController(type)
  24.307 +        return ctrl.configureDevice(id, devconfig)
  24.308 +
  24.309 +    def destroyDevice(self, type, id, change=False, reboot=False):
  24.310 +        ctrl = self.getDeviceController(type)
  24.311 +        return ctrl.destroyDevice(id, change=change, reboot=reboot)
  24.312 +
  24.313 +    def deleteDevice(self, type, id):
  24.314 +        ctrl = self.getDeviceController(type)
  24.315 +        return ctrl.deleteDevice(id)
  24.316 +
  24.317 +    def getDevice(self, type, id):
  24.318 +        ctrl = self.getDeviceController(type)
  24.319 +        return ctrl.getDevice(id)
  24.320 +        
  24.321 +    def getDeviceByIndex(self, type, idx):
  24.322 +        ctrl = self.getDeviceController(type)
  24.323 +        return ctrl.getDeviceByIndex(idx)
  24.324 +
  24.325 +    def getDeviceConfig(self, type, id):
  24.326 +        ctrl = self.getDeviceController(type)
  24.327 +        return ctrl.getDeviceConfig(id)
  24.328 +
  24.329 +    def getDeviceIds(self, type):
  24.330 +        ctrl = self.getDeviceController(type)
  24.331 +        return ctrl.getDeviceIds()
  24.332 +    
  24.333 +    def getDeviceIndexes(self, type):
  24.334 +        ctrl = self.getDeviceController(type)
  24.335 +        return ctrl.getDeviceIndexes()
  24.336 +    
  24.337 +    def getDeviceConfigs(self, type):
  24.338 +        ctrl = self.getDeviceController(type)
  24.339 +        return ctrl.getDeviceConfigs()
  24.340 +
  24.341 +    def getDeviceSxprs(self, type):
  24.342 +        ctrl = self.getDeviceController(type)
  24.343 +        return ctrl.getDeviceSxprs()
  24.344 +
  24.345      def sxpr(self):
  24.346          sxpr = ['domain',
  24.347                  ['id', self.id],
  24.348 @@ -378,8 +424,13 @@ class XendDomainInfo:
  24.349              sxpr.append(['up_time', str(up_time) ])
  24.350              sxpr.append(['start_time', str(self.start_time) ])
  24.351  
  24.352 -        if self.console:
  24.353 -            sxpr.append(self.console.sxpr())
  24.354 +        if self.channel:
  24.355 +            sxpr.append(self.channel.sxpr())
  24.356 +        console = self.getConsole()
  24.357 +        if console:
  24.358 +            sxpr.append(console.sxpr())
  24.359 +        if self.restart_count:
  24.360 +            sxpr.append(['restart_count', self.restart_count])
  24.361          if self.restart_state:
  24.362              sxpr.append(['restart_state', self.restart_state])
  24.363          if self.restart_time:
  24.364 @@ -392,16 +443,19 @@ class XendDomainInfo:
  24.365          return sxpr
  24.366  
  24.367      def sxpr_devices(self):
  24.368 -        sxpr = ['devices']
  24.369 -        for devs in self.devices.values():
  24.370 -            for dev in devs:
  24.371 -                if hasattr(dev, 'sxpr'):
  24.372 -                    sxpr.append(dev.sxpr())
  24.373 +        sxpr = []
  24.374 +        for ty in self.getDeviceTypes():
  24.375 +            devs = self.getDeviceSxprs(ty)
  24.376 +            sxpr += devs
  24.377 +        if sxpr:
  24.378 +            sxpr.insert(0, 'devices')
  24.379 +        else:
  24.380 +            sxpr = None
  24.381          return sxpr
  24.382  
  24.383      def check_name(self, name):
  24.384 -        """Check if a vm name is valid. Valid names start with a non-digit
  24.385 -        and contain alphabetic characters, digits, or characters in '_-.:/+'.
  24.386 +        """Check if a vm name is valid. Valid names contain alphabetic characters,
  24.387 +        digits, or characters in '_-.:/+'.
  24.388          The same name cannot be used for more than one vm at the same time.
  24.389  
  24.390          @param name: name
  24.391 @@ -410,8 +464,6 @@ class XendDomainInfo:
  24.392          if self.recreate: return
  24.393          if name is None or name == '':
  24.394              raise VmError('missing vm name')
  24.395 -        if name[0] in string.digits:
  24.396 -            raise VmError('invalid vm name')
  24.397          for c in name:
  24.398              if c in string.digits: continue
  24.399              if c in '_-.:/+': continue
  24.400 @@ -432,46 +484,55 @@ class XendDomainInfo:
  24.401          """Construct the vm instance from its configuration.
  24.402  
  24.403          @param config: configuration
  24.404 -        @return: deferred
  24.405          @raise: VmError on error
  24.406          """
  24.407          # todo - add support for scheduling params?
  24.408          self.config = config
  24.409          try:
  24.410 +            # Initial domain create.
  24.411              self.name = sxp.child_value(config, 'name')
  24.412              self.check_name(self.name)
  24.413 -            try:
  24.414 -                self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
  24.415 -            except:
  24.416 -                raise VmError('invalid cpu weight')
  24.417 -            self.memory = int(sxp.child_value(config, 'memory'))
  24.418 -            if self.memory is None:
  24.419 -                raise VmError('missing memory size')
  24.420 -            cpu = sxp.child_value(config, 'cpu')
  24.421 -            if self.recreate and self.dom and cpu is not None:
  24.422 -                xc.domain_pincpu(self.dom, int(cpu))
  24.423 -            try:
  24.424 -                image = sxp.child_value(self.config, 'image')
  24.425 -                self.vcpus = int(sxp.child_value(image, 'vcpus'))
  24.426 -            except:
  24.427 -                raise VmError('invalid vcpus value')
  24.428 -
  24.429 +            self.configure_cpus(config)
  24.430              self.find_image_handler()
  24.431              self.init_domain()
  24.432 -            self.configure_console()
  24.433 +            self.register_domain()
  24.434 +
  24.435 +            # Create domain devices.
  24.436              self.configure_backends()
  24.437 -            self.construct_image()
  24.438 +            self.configure_console()
  24.439              self.configure_restart()
  24.440 -            deferred = self.configure()
  24.441 -            def cberr(err):
  24.442 -                self.destroy()
  24.443 -                return err
  24.444 -            deferred.addErrback(cberr)
  24.445 -        except StandardError, ex:
  24.446 +            self.construct_image()
  24.447 +            self.configure()
  24.448 +        except Exception, ex:
  24.449              # Catch errors, cleanup and re-raise.
  24.450 +            print 'Domain construction error:', ex
  24.451 +            import traceback
  24.452 +            traceback.print_exc()
  24.453              self.destroy()
  24.454              raise
  24.455 -        return deferred
  24.456 +
  24.457 +    def register_domain(self):
  24.458 +        xd = get_component('xen.xend.XendDomain')
  24.459 +        xd._add_domain(self)
  24.460 +
  24.461 +    def configure_cpus(self, config):
  24.462 +        try:
  24.463 +            self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
  24.464 +        except:
  24.465 +            raise VmError('invalid cpu weight')
  24.466 +        self.memory = int(sxp.child_value(config, 'memory'))
  24.467 +        if self.memory is None:
  24.468 +            raise VmError('missing memory size')
  24.469 +        cpu = sxp.child_value(config, 'cpu')
  24.470 +        if self.recreate and self.dom and cpu is not None:
  24.471 +            xc.domain_pincpu(self.dom, int(cpu))
  24.472 +        try:
  24.473 +            image = sxp.child_value(self.config, 'image')
  24.474 +            vcpus = sxp.child_value(image, 'vcpus')
  24.475 +            if vcpus:
  24.476 +                self.vcpus = int(vcpus)
  24.477 +        except:
  24.478 +            raise VmError('invalid vcpus value')
  24.479  
  24.480      def find_image_handler(self):
  24.481          """Construct the boot image for the domain.
  24.482 @@ -485,7 +546,7 @@ class XendDomainInfo:
  24.483          if image_name is None:
  24.484              raise VmError('missing image name')
  24.485          if image_name == "vmx":
  24.486 -            self.is_vmx = 1
  24.487 +            self.is_vmx = True
  24.488          image_handler = get_image_handler(image_name)
  24.489          if image_handler is None:
  24.490              raise VmError('unknown image type: ' + image_name)
  24.491 @@ -513,107 +574,15 @@ class XendDomainInfo:
  24.492                  devices.append(dev)
  24.493          return devices
  24.494  
  24.495 -    def config_device(self, type, idx):
  24.496 -        """Get a device config from the device nodes of a given type
  24.497 -        from the config.
  24.498 -
  24.499 -        @param type: device type
  24.500 -        @type  type: string
  24.501 -        @param idx: index
  24.502 -        @type  idx: int
  24.503 -        @return config or None
  24.504 -        """
  24.505 -        devs = self.config_devices(type)
  24.506 -        if 0 <= idx < len(devs):
  24.507 -            return devs[idx]
  24.508 -        else:
  24.509 -            return None
  24.510 -
  24.511 -    def next_device_index(self, type):
  24.512 -        """Get the next index for a given device type.
  24.513 -
  24.514 -        @param type: device type
  24.515 -        @type  type: string
  24.516 -        @return device index
  24.517 -        @rtype: int
  24.518 -        """
  24.519 -        idx = self.device_index.get(type, 0)
  24.520 -        self.device_index[type] = idx + 1
  24.521 -        return idx
  24.522 -
  24.523 -    def add_device(self, type, dev):
  24.524 -        """Add a device to a virtual machine.
  24.525 -
  24.526 -        @param type: device type
  24.527 -        @param dev:  device to add
  24.528 -        """
  24.529 -        dl = self.devices.get(type, [])
  24.530 -        dl.append(dev)
  24.531 -        self.devices[type] = dl
  24.532 -
  24.533 -    def refresh_device(self, type, dev):
  24.534 -        """Refresh a device to a virtual machine.
  24.535 -
  24.536 -        @param type: device type
  24.537 -        @param dev:  device
  24.538 -        """
  24.539 -        dl = self.devices.get(type, [])
  24.540 -        if dev in dl:
  24.541 -            dl.refresh(dev)
  24.542 -
  24.543 -    def remove_device(self, type, dev):
  24.544 -        """Remove a device from a virtual machine.
  24.545 -
  24.546 -        @param type: device type
  24.547 -        @param dev:  device
  24.548 -        """
  24.549 -        dl = self.devices.get(type, [])
  24.550 -        if dev in dl:
  24.551 -            dl.remove(dev)
  24.552 -
  24.553 -    def get_devices(self, type):
  24.554 -        """Get a list of the devices of a given type.
  24.555 -
  24.556 -        @param type: device type
  24.557 -        @return: devices
  24.558 -        """
  24.559 -        val = self.devices.get(type, [])
  24.560 -        return val
  24.561 -
  24.562 -    def get_device_by_id(self, type, id):
  24.563 -        """Get the device with the given id.
  24.564 -
  24.565 -        @param id:       device id
  24.566 -        @return:  device or None
  24.567 -        """
  24.568 -        dl = self.get_devices(type)
  24.569 -        for d in dl:
  24.570 -            if d.getprop('id') == id:
  24.571 -                return d
  24.572 -        return None
  24.573 -
  24.574 -    def get_device_by_index(self, type, idx):
  24.575 -        """Get the device with the given index.
  24.576 -
  24.577 -        @param idx: device index
  24.578 -        @return:  device or None
  24.579 -        """
  24.580 -        idx = str(idx)
  24.581 -        dl = self.get_devices(type)
  24.582 -        for d in dl:
  24.583 -            if d.getidx() == idx:
  24.584 -                return d
  24.585 -        return None
  24.586 -
  24.587      def get_device_savedinfo(self, type, index):
  24.588          val = None
  24.589          if self.savedinfo is None:
  24.590              return val
  24.591 +        devices = sxp.child(self.savedinfo, 'devices')
  24.592 +        if devices is None:
  24.593 +            return val
  24.594          index = str(index)
  24.595 -        devinfo = sxp.child(self.savedinfo, 'devices')
  24.596 -        if devinfo is None:
  24.597 -            return val
  24.598 -        for d in sxp.children(devinfo, type):
  24.599 +        for d in sxp.children(devices, type):
  24.600              dindex = sxp.child_value(d, 'index')
  24.601              if dindex is None: continue
  24.602              if str(dindex) == index:
  24.603 @@ -624,18 +593,6 @@ class XendDomainInfo:
  24.604      def get_device_recreate(self, type, index):
  24.605          return self.get_device_savedinfo(type, index) or self.recreate
  24.606  
  24.607 -    def limit_vif(self, vif, credit, period):
  24.608 -        """Limit the rate of a virtual interface
  24.609 -        @param vif:       vif
  24.610 -        @param credit:    vif credit in bytes
  24.611 -        @param period:    vif period in uSec
  24.612 -        @return: 0 on success
  24.613 -        """
  24.614 -    
  24.615 -        ctrl = xend.netif_create(self.dom, recreate=self.recreate)
  24.616 -        d = ctrl.limitDevice(vif, credit, period)
  24.617 -        return d
  24.618 -    
  24.619      def add_config(self, val):
  24.620          """Add configuration data to a virtual machine.
  24.621  
  24.622 @@ -654,25 +611,15 @@ class XendDomainInfo:
  24.623          The domain will not finally go away unless all vm
  24.624          devices have been released.
  24.625          """
  24.626 +        if self.channel:
  24.627 +            self.channel.close()
  24.628 +            self.channel = None
  24.629          if self.dom is None: return 0
  24.630 -        self.destroy_console()
  24.631 -        chan = xend.getDomChannel(self.dom)
  24.632 -        if chan:
  24.633 -            log.debug("Closing channel to domain %d", self.dom)
  24.634 -            chan.close()
  24.635          try:
  24.636              return xc.domain_destroy(dom=self.dom)
  24.637          except Exception, err:
  24.638              log.exception("Domain destroy failed: %s", self.name)
  24.639  
  24.640 -    def destroy_console(self):
  24.641 -        if self.console:
  24.642 -            if self.restart_pending():
  24.643 -                self.console.deregisterChannel()
  24.644 -            else:
  24.645 -                log.debug('Closing console, domain %s', self.id)
  24.646 -                self.console.close()
  24.647 -
  24.648      def cleanup(self):
  24.649          """Cleanup vm resources: release devices.
  24.650          """
  24.651 @@ -687,41 +634,13 @@ class XendDomainInfo:
  24.652      def release_devices(self):
  24.653          """Release all vm devices.
  24.654          """
  24.655 -        self.release_vifs()
  24.656 -        self.release_vbds()
  24.657 -        self.release_usbifs()
  24.658 -        
  24.659 -        self.devices = {}
  24.660 -        self.device_index = {}
  24.661 -        self.configs = []
  24.662 -        self.ipaddrs = []
  24.663 -
  24.664 -    def release_vifs(self):
  24.665 -        """Release vm virtual network devices (vifs).
  24.666 -        """
  24.667 -        if self.dom is None: return
  24.668 -        ctrl = xend.netif_get(self.dom)
  24.669 -        if ctrl:
  24.670 -            log.debug("Destroying vifs for domain %d", self.dom)
  24.671 -            ctrl.destroy()
  24.672 -
  24.673 -    def release_vbds(self):
  24.674 -        """Release vm virtual block devices (vbds).
  24.675 -        """
  24.676 -        if self.dom is None: return
  24.677 -        ctrl = xend.blkif_get(self.dom)
  24.678 -        if ctrl:
  24.679 -            log.debug("Destroying vbds for domain %d", self.dom)
  24.680 -            ctrl.destroy()
  24.681 -
  24.682 -    def release_usbifs(self):
  24.683 -        """Release vm virtual USB devices (usbifs).
  24.684 -        """
  24.685 -        if self.dom is None: return
  24.686 -        ctrl = xend.usbif_get(self.dom)
  24.687 -        if ctrl:
  24.688 -            log.debug("Destroying usbifs for domain %d", self.dom)
  24.689 -            ctrl.destroy()
  24.690 +        reboot = self.restart_pending()
  24.691 +        for ctrl in self.getDeviceControllers():
  24.692 +            if ctrl.isDestroyed(): continue
  24.693 +            ctrl.destroyController(reboot=reboot)
  24.694 +        if not reboot:
  24.695 +            self.configs = []
  24.696 +            self.ipaddrs = []
  24.697  
  24.698      def show(self):
  24.699          """Print virtual machine info.
  24.700 @@ -730,11 +649,6 @@ class XendDomainInfo:
  24.701          print "image:"
  24.702          sxp.show(self.image)
  24.703          print
  24.704 -        for dl in self.devices:
  24.705 -            for dev in dl:
  24.706 -                print "device:"
  24.707 -                sxp.show(dev)
  24.708 -                print
  24.709          for val in self.configs:
  24.710              print "config:"
  24.711              sxp.show(val)
  24.712 @@ -752,10 +666,6 @@ class XendDomainInfo:
  24.713              return
  24.714          dom = self.dom or 0
  24.715          memory = self.memory
  24.716 -        name = self.name
  24.717 -        # If the name is over the xen limit, use the end of it.
  24.718 -        if len(name) > MAX_DOMAIN_NAME:
  24.719 -            name = name[-MAX_DOMAIN_NAME:]
  24.720          try:
  24.721              cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
  24.722          except:
  24.723 @@ -766,8 +676,8 @@ class XendDomainInfo:
  24.724                                 cpu= cpu, cpu_weight= cpu_weight)
  24.725          if dom <= 0:
  24.726              raise VmError('Creating domain failed: name=%s memory=%d'
  24.727 -                          % (name, memory))
  24.728 -        log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, name, memory)
  24.729 +                          % (self.name, memory))
  24.730 +        log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, self.name, memory)
  24.731          self.setdom(dom)
  24.732  
  24.733      def build_domain(self, ostype, kernel, ramdisk, cmdline, memmap):
  24.734 @@ -785,28 +695,29 @@ class XendDomainInfo:
  24.735          flags = 0
  24.736          if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
  24.737          if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
  24.738 -	if ostype == "vmx":
  24.739 -        	err = buildfn(dom      = dom,
  24.740 -               	      	image          = kernel,
  24.741 -                      	control_evtchn = 0,
  24.742 -                        memsize        = self.memory,
  24.743 -			memmap	       = memmap,
  24.744 -                      	cmdline        = cmdline,
  24.745 -                      	ramdisk        = ramdisk,
  24.746 -                      	flags          = flags)
  24.747 -	else:
  24.748 -        	log.warning('building dom with %d vcpus', self.vcpus)
  24.749 -        	err = buildfn(dom            = dom,
  24.750 -               	      	image          = kernel,
  24.751 -                      	control_evtchn = self.console.getRemotePort(),
  24.752 -                      	cmdline        = cmdline,
  24.753 -                      	ramdisk        = ramdisk,
  24.754 -                      	flags          = flags,
  24.755 -                      	vcpus          = self.vcpus)
  24.756 -        if err != 0:
  24.757 -            raise VmError('Building domain failed: type=%s dom=%d err=%d'
  24.758 -                          % (ostype, dom, err))
  24.759 -
  24.760 +        #todo generalise this
  24.761 +        if ostype == "vmx":
  24.762 +            err = buildfn(dom            = dom,
  24.763 +                          image          = kernel,
  24.764 +                          control_evtchn = 0,
  24.765 +                          memsize        = self.memory,
  24.766 +                          memmap         = memmap,
  24.767 +                          cmdline        = cmdline,
  24.768 +                          ramdisk        = ramdisk,
  24.769 +                          flags          = flags)
  24.770 +        else:
  24.771 +            log.warning('building dom with %d vcpus', self.vcpus)
  24.772 +            err = buildfn(dom            = dom,
  24.773 +                          image          = kernel,
  24.774 +                          control_evtchn = self.channel.getRemotePort(),
  24.775 +                          cmdline        = cmdline,
  24.776 +                          ramdisk        = ramdisk,
  24.777 +                          flags          = flags,
  24.778 +                          vcpus          = self.vcpus)
  24.779 +            if err != 0:
  24.780 +                raise VmError('Building domain failed: type=%s dom=%d err=%d'
  24.781 +                              % (ostype, dom, err))
  24.782 +            
  24.783      def create_domain(self, ostype, kernel, ramdisk, cmdline, memmap=''):
  24.784          """Create a domain. Builds the image but does not configure it.
  24.785  
  24.786 @@ -817,87 +728,87 @@ class XendDomainInfo:
  24.787          """
  24.788  
  24.789          self.create_channel()
  24.790 -        if self.console:
  24.791 -            self.console.registerChannel()
  24.792 -        else:
  24.793 -            self.console = xendConsole.console_create(
  24.794 -                self.dom, console_port=self.console_port)
  24.795          self.build_domain(ostype, kernel, ramdisk, cmdline, memmap)
  24.796          self.image = kernel
  24.797          self.ramdisk = ramdisk
  24.798          self.cmdline = cmdline
  24.799  
  24.800      def create_channel(self):
  24.801 -        """Create the channel to the domain.
  24.802 +        """Create the control channel to the domain.
  24.803          If saved info is available recreate the channel using the saved ports.
  24.804 -
  24.805 -        @return: channel
  24.806          """
  24.807          local = 0
  24.808          remote = 1
  24.809          if self.savedinfo:
  24.810 -            consinfo = sxp.child(self.savedinfo, "console")
  24.811 -            if consinfo:
  24.812 -                local = int(sxp.child_value(consinfo, "local_port", 0))
  24.813 -                remote = int(sxp.child_value(consinfo, "remote_port", 1))
  24.814 -        return xend.createDomChannel(self.dom, local_port=local,
  24.815 -                                     remote_port=remote)
  24.816 +            info = sxp.child(self.savedinfo, "channel")
  24.817 +            if info:
  24.818 +                local = int(sxp.child_value(info, "local_port", 0))
  24.819 +                remote = int(sxp.child_value(info, "remote_port", 1))
  24.820 +        self.channel = channelFactory().openChannel(self.dom,
  24.821 +                                                    local_port=local,
  24.822 +                                                    remote_port=remote)
  24.823  
  24.824 +    def create_configured_devices(self):
  24.825 +        devices = sxp.children(self.config, 'device')
  24.826 +        indexes = {}
  24.827 +        for d in devices:
  24.828 +            dev_config = sxp.child0(d)
  24.829 +            if dev_config is None:
  24.830 +                raise VmError('invalid device')
  24.831 +            dev_type = sxp.name(dev_config)
  24.832 +            ctrl_type = get_device_handler(dev_type)
  24.833 +            if ctrl_type is None:
  24.834 +                raise VmError('unknown device type: ' + dev_type)
  24.835 +            # Keep track of device indexes by type, so we can fish
  24.836 +            # out saved info for recreation.
  24.837 +            idx = indexes.get(dev_type, -1)
  24.838 +            idx += 1
  24.839 +            indexes[ctrl_type] = idx
  24.840 +            recreate = self.get_device_recreate(dev_type, idx)
  24.841 +            self.createDevice(ctrl_type, dev_config, recreate=recreate)
  24.842 +        
  24.843      def create_devices(self):
  24.844          """Create the devices for a vm.
  24.845  
  24.846 -        @return: Deferred
  24.847          @raise: VmError for invalid devices
  24.848          """
  24.849 -        dlist = []
  24.850 -        devices = sxp.children(self.config, 'device')
  24.851 -        index = {}
  24.852 -        for d in devices:
  24.853 -            dev = sxp.child0(d)
  24.854 -            if dev is None:
  24.855 -                raise VmError('invalid device')
  24.856 -            dev_name = sxp.name(dev)
  24.857 -            dev_index = index.get(dev_name, 0)
  24.858 -            dev_handler = get_device_handler(dev_name)
  24.859 -            if dev_handler is None:
  24.860 -                raise VmError('unknown device type: ' + dev_name)
  24.861 -            v = dev_handler(self, dev, dev_index)
  24.862 -            append_deferred(dlist, v)
  24.863 -            index[dev_name] = dev_index + 1
  24.864 -        deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
  24.865 -        deferred.addErrback(dlist_err)
  24.866 +        if self.rebooting():
  24.867 +            for ctrl in self.getDeviceControllers():
  24.868 +                ctrl.initController(reboot=True)
  24.869 +        else:
  24.870 +            self.create_configured_devices()
  24.871          if self.is_vmx:
  24.872 -            device_model = sxp.child_value(self.config, 'device_model')
  24.873 -            device_config = sxp.child_value(self.config, 'device_config')
  24.874 -            memory = sxp.child_value(self.config, "memory")
  24.875 -            # Create an event channel
  24.876 -            device_channel = channel.eventChannel(0, self.dom)
  24.877 -            # Fork and exec device_model -f device_config <port>
  24.878 -            os.system(device_model
  24.879 -                      + " -f %s" % device_config
  24.880 -                      + " -d %d" % self.dom
  24.881 -                      + " -p %d" % device_channel['port1']
  24.882 -                      + " -m %s" % memory)
  24.883 -        return deferred
  24.884 +            self.create_vmx_model()
  24.885 +
  24.886 +    def create_vmx_model(self):
  24.887 +        #todo: remove special case for vmx
  24.888 +        device_model = sxp.child_value(self.config, 'device_model')
  24.889 +        if not device_model:
  24.890 +            raise VmError("vmx: missing device model")
  24.891 +        device_config = sxp.child_value(self.config, 'device_config')
  24.892 +        if not device_config:
  24.893 +            raise VmError("vmx: missing device config")
  24.894 +        #todo: self.memory?
  24.895 +        memory = sxp.child_value(self.config, "memory")
  24.896 +        # Create an event channel
  24.897 +        device_channel = channel.eventChannel(0, self.dom)
  24.898 +        # Execute device model.
  24.899 +        #todo: Error handling
  24.900 +        os.system(device_model
  24.901 +                  + " -f %s" % device_config
  24.902 +                  + " -d %d" % self.dom
  24.903 +                  + " -p %d" % device_channel['port1']
  24.904 +                  + " -m %s" % memory)
  24.905  
  24.906      def device_create(self, dev_config):
  24.907          """Create a new device.
  24.908  
  24.909          @param dev_config: device configuration
  24.910 -        @return: deferred
  24.911          """
  24.912 -        dev_name = sxp.name(dev_config)
  24.913 -        dev_handler = get_device_handler(dev_name)
  24.914 -        if dev_handler is None:
  24.915 -            raise VmError('unknown device type: ' + dev_name)
  24.916 -        devs = self.get_devices(dev_name)
  24.917 -        dev_index = len(devs)
  24.918 -        self.config.append(['device', dev_config])
  24.919 -        d = dev_handler(self, dev_config, dev_index, change=1)
  24.920 -        def cbok(dev):
  24.921 -            return dev.sxpr()
  24.922 -        d.addCallback(cbok)
  24.923 -        return d
  24.924 +        dev_type = sxp.name(dev_config)
  24.925 +        dev = self.createDevice(self, dev_config, change=True)
  24.926 +        self.config.append(['device', dev.getConfig()])
  24.927 +        return dev.sxpr()
  24.928  
  24.929      def device_configure(self, dev_config, idx):
  24.930          """Configure an existing device.
  24.931 @@ -906,16 +817,11 @@ class XendDomainInfo:
  24.932          @param idx:  device index
  24.933          """
  24.934          type = sxp.name(dev_config)
  24.935 -        dev = self.get_device_by_index(type, idx)
  24.936 +        dev = self.getDeviceByIndex(type, idx)
  24.937          if not dev:
  24.938              raise VmError('invalid device: %s %s' % (type, idx))
  24.939 -        new_config = dev.configure(dev_config, change=1)
  24.940 -        devs = self.devices.get(type)
  24.941 -        index = devs.index(dev)
  24.942 -        # Patch new config into device configs.
  24.943 -        dev_configs = self.config_devices(type)
  24.944 -        old_config = dev_configs[index]
  24.945 -        dev_configs[index] = new_config
  24.946 +        old_config = dev.getConfig()
  24.947 +        new_config = dev.configure(dev_config, change=True)
  24.948          # Patch new config into vm config.
  24.949          new_full_config = ['device', new_config]
  24.950          old_full_config = ['device', old_config]
  24.951 @@ -929,37 +835,24 @@ class XendDomainInfo:
  24.952          @param type: device type
  24.953          @param idx:  device index
  24.954          """
  24.955 -        dev = self.get_device_by_index(type, idx)
  24.956 +        dev = self.getDeviceByIndex(type, idx)
  24.957          if not dev:
  24.958              raise VmError('invalid device: %s %s' % (type, idx))
  24.959 -        devs = self.devices.get(type)
  24.960          dev.refresh()
  24.961 -        #self.refresh_device(type, dev)
  24.962          
  24.963 -    def device_destroy(self, type, idx):
  24.964 -        """Destroy a device.
  24.965 +    def device_delete(self, type, idx):
  24.966 +        """Destroy and remove a device.
  24.967  
  24.968          @param type: device type
  24.969          @param idx:  device index
  24.970          """
  24.971 -        dev = self.get_device_by_index(type, idx)
  24.972 +        dev = self.getDeviceByIndex(type, idx)
  24.973          if not dev:
  24.974              raise VmError('invalid device: %s %s' % (type, idx))
  24.975 -        devs = self.devices.get(type)
  24.976 -        index = devs.index(dev)
  24.977 -        dev_config = self.config_device(type, index)
  24.978 +        dev_config = dev.getConfig()
  24.979          if dev_config:
  24.980              self.config.remove(['device', dev_config])
  24.981 -        dev.destroy(change=1)
  24.982 -        self.remove_device(type, dev)
  24.983 -
  24.984 -    def configure_memory(self):
  24.985 -        """Configure vm memory limit.
  24.986 -        """
  24.987 -        maxmem = sxp.child_value(self.config, "maxmem")
  24.988 -        if maxmem is None:
  24.989 -            maxmem = self.memory
  24.990 -        xc.domain_setmaxmem(self.dom, maxmem_kb = maxmem * 1024)
  24.991 +        self.deleteDevice(type, dev.getId())
  24.992  
  24.993      def configure_console(self):
  24.994          """Configure the vm console port.
  24.995 @@ -985,15 +878,15 @@ class XendDomainInfo:
  24.996          for the given reason.
  24.997  
  24.998          @param reason: shutdown reason
  24.999 -        @return 1 if needs restaert, 0 otherwise
 24.1000 +        @return True if needs restart, False otherwise
 24.1001          """
 24.1002          if self.restart_mode == RESTART_NEVER:
 24.1003 -            return 0
 24.1004 +            return False
 24.1005          if self.restart_mode == RESTART_ALWAYS:
 24.1006 -            return 1
 24.1007 +            return True
 24.1008          if self.restart_mode == RESTART_ONREBOOT:
 24.1009              return reason == 'reboot'
 24.1010 -        return 0
 24.1011 +        return False
 24.1012  
 24.1013      def restart_cancel(self):
 24.1014          """Cancel a vm restart.
 24.1015 @@ -1010,6 +903,9 @@ class XendDomainInfo:
 24.1016          """
 24.1017          return self.restart_state == STATE_RESTART_PENDING
 24.1018  
 24.1019 +    def rebooting(self):
 24.1020 +        return self.restart_state == STATE_RESTART_BOOTING
 24.1021 +
 24.1022      def restart_check(self):
 24.1023          """Check if domain restart is OK.
 24.1024          To prevent restart loops, raise an error if it is
 24.1025 @@ -1024,20 +920,20 @@ class XendDomainInfo:
 24.1026                  log.error(msg)
 24.1027                  raise VmError(msg)
 24.1028          self.restart_time = tnow
 24.1029 +        self.restart_count += 1
 24.1030  
 24.1031      def restart(self):
 24.1032          """Restart the domain after it has exited.
 24.1033          Reuses the domain id and console port.
 24.1034  
 24.1035 -        @return: deferred
 24.1036          """
 24.1037          try:
 24.1038 +            self.state = STATE_VM_OK
 24.1039              self.restart_check()
 24.1040              self.restart_state = STATE_RESTART_BOOTING
 24.1041 -            d = self.construct(self.config)
 24.1042 +            self.construct(self.config)
 24.1043          finally:
 24.1044              self.restart_state = None
 24.1045 -        return d
 24.1046  
 24.1047      def configure_backends(self):
 24.1048          """Set configuration flags if the vm is a backend for netif or blkif.
 24.1049 @@ -1047,73 +943,70 @@ class XendDomainInfo:
 24.1050              v = sxp.child0(c)
 24.1051              name = sxp.name(v)
 24.1052              if name == 'blkif':
 24.1053 -                self.blkif_backend = 1
 24.1054 +                self.blkif_backend = True
 24.1055              elif name == 'netif':
 24.1056 -                self.netif_backend = 1
 24.1057 +                self.netif_backend = True
 24.1058              elif name == 'usbif':
 24.1059 -                self.usbif_backend = 1
 24.1060 +                self.usbif_backend = True
 24.1061              else:
 24.1062                  raise VmError('invalid backend type:' + str(name))
 24.1063  
 24.1064      def configure(self):
 24.1065          """Configure a vm.
 24.1066  
 24.1067 -        @return: deferred - calls callback with vm
 24.1068          """
 24.1069 -        d = self.create_devices()
 24.1070 -        d.addCallback(lambda x: self.create_blkif())
 24.1071 -        d.addCallback(self._configure)
 24.1072 -        return d
 24.1073 +        self.configure_fields()
 24.1074 +        self.create_console()
 24.1075 +        self.create_devices()
 24.1076 +        self.create_blkif()
 24.1077  
 24.1078 -    def _configure(self, val):
 24.1079 -        d = self.configure_fields()
 24.1080 -        def cbok(results):
 24.1081 -            return self
 24.1082 -        def cberr(err):
 24.1083 -            self.destroy()
 24.1084 -            return err
 24.1085 -        d.addCallback(cbok)
 24.1086 -        d.addErrback(cberr)
 24.1087 -        return d
 24.1088 +    def create_console(self):
 24.1089 +        console = self.getConsole()
 24.1090 +        if not console:
 24.1091 +            config = ['console']
 24.1092 +            if self.console_port:
 24.1093 +                config.append(['console_port', self.console_port])
 24.1094 +            console = self.createDevice('console', config)
 24.1095 +        return console
 24.1096 +
 24.1097 +    def getConsole(self):
 24.1098 +        console_ctrl = self.getDeviceController("console", error=False)
 24.1099 +        if console_ctrl:
 24.1100 +            return console_ctrl.getDevice(0)
 24.1101 +        return None
 24.1102  
 24.1103      def create_blkif(self):
 24.1104          """Create the block device interface (blkif) for the vm.
 24.1105          The vm needs a blkif even if it doesn't have any disks
 24.1106          at creation time, for example when it uses NFS root.
 24.1107  
 24.1108 -        @return: deferred
 24.1109          """
 24.1110 -        if self.get_devices("vbd") == []:
 24.1111 -            ctrl = xend.blkif_create(self.dom, recreate=self.recreate)
 24.1112 -            back = ctrl.getBackendInterface(0)
 24.1113 -            return back.connect(recreate=self.recreate)
 24.1114 -        else:
 24.1115 -            return None
 24.1116 +        blkif = self.getDeviceController("vbd", error=False)
 24.1117 +        if not blkif:
 24.1118 +            blkif = self.createDeviceController("vbd")
 24.1119 +            backend = blkif.getBackend(0)
 24.1120 +            backend.connect(recreate=self.recreate)
 24.1121  
 24.1122      def dom_construct(self, dom, config):
 24.1123          """Construct a vm for an existing domain.
 24.1124  
 24.1125          @param dom: domain id
 24.1126          @param config: domain configuration
 24.1127 -        @return: deferred
 24.1128          """
 24.1129          d = dom_get(dom)
 24.1130          if not d:
 24.1131              raise VmError("Domain not found: %d" % dom)
 24.1132          try:
 24.1133 -            self.restore = 1
 24.1134 +            self.restore = True
 24.1135              self.setdom(dom)
 24.1136 -            #self.name = d['name']
 24.1137              self.memory = d['mem_kb']/1024
 24.1138 -            deferred = self.construct(config)
 24.1139 +            self.construct(config)
 24.1140          finally:
 24.1141 -            self.restore = 0
 24.1142 -        return deferred
 24.1143 +            self.restore = False
 24.1144  
 24.1145      def configure_fields(self):
 24.1146          """Process the vm configuration fields using the registered handlers.
 24.1147          """
 24.1148 -        dlist = []
 24.1149          index = {}
 24.1150          for field in sxp.children(self.config):
 24.1151              field_name = sxp.name(field)
 24.1152 @@ -1122,13 +1015,9 @@ class XendDomainInfo:
 24.1153              # Ignore unknown fields. Warn?
 24.1154              if field_handler:
 24.1155                  v = field_handler(self, self.config, field, field_index)
 24.1156 -                append_deferred(dlist, v)
 24.1157              else:
 24.1158                  log.warning("Unknown config field %s", field_name)
 24.1159              index[field_name] = field_index + 1
 24.1160 -        d = defer.DeferredList(dlist, fireOnOneErrback=1)
 24.1161 -        d.addErrback(dlist_err)
 24.1162 -        return d
 24.1163  
 24.1164      def pgtable_size(self, memory):
 24.1165          """Return the size of memory needed for 1:1 page tables for physical
 24.1166 @@ -1143,6 +1032,25 @@ class XendDomainInfo:
 24.1167              return (1 + ((memory + 3) >> 2)) * 4
 24.1168          return 0
 24.1169  
 24.1170 +    def mem_target_set(self, target):
 24.1171 +        """Set domain memory target in pages.
 24.1172 +        """
 24.1173 +        if self.channel:
 24.1174 +            msg = messages.packMsg('mem_request_t', { 'target' : target * (1 << 8)} )
 24.1175 +            self.channel.writeRequest(msg)
 24.1176 +
 24.1177 +    def shutdown(self, reason, key=0):
 24.1178 +        msgtype = shutdown_messages.get(reason)
 24.1179 +        if not msgtype:
 24.1180 +            raise XendError('invalid reason:' + reason)
 24.1181 +        extra = {}
 24.1182 +        if reason == 'sysrq':
 24.1183 +            extra['key'] = key
 24.1184 +        if self.channel:
 24.1185 +            msg = messages.packMsg(msgtype, extra)
 24.1186 +            self.channel.writeRequest(msg)
 24.1187 +
 24.1188 +
 24.1189  def vm_image_linux(vm, image):
 24.1190      """Create a VM for a linux image.
 24.1191  
 24.1192 @@ -1175,7 +1083,6 @@ def vm_image_plan9(vm, image):
 24.1193  
 24.1194      returns vm 
 24.1195      """
 24.1196 -    #todo: Same as for linux. Is that right? If so can unify them.
 24.1197      kernel = sxp.child_value(image, "kernel")
 24.1198      cmdline = ""
 24.1199      ip = sxp.child_value(image, "ip", "dhcp")
 24.1200 @@ -1188,7 +1095,6 @@ def vm_image_plan9(vm, image):
 24.1201      if args:
 24.1202          cmdline += " " + args
 24.1203      ramdisk = sxp.child_value(image, "ramdisk", '')
 24.1204 -    vifs = vm.config_devices("vif")
 24.1205      vm.create_domain("plan9", kernel, ramdisk, cmdline)
 24.1206      return vm
 24.1207      
 24.1208 @@ -1219,115 +1125,6 @@ def vm_image_vmx(vm, image):
 24.1209      vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap)
 24.1210      return vm
 24.1211  
 24.1212 -def vm_dev_vif(vm, val, index, change=0):
 24.1213 -    """Create a virtual network interface (vif).
 24.1214 -
 24.1215 -    @param vm:        virtual machine
 24.1216 -    @param val:       vif config
 24.1217 -    @param index:     vif index
 24.1218 -    @return: deferred
 24.1219 -    """
 24.1220 -    vif = vm.next_device_index('vif')
 24.1221 -    vmac = sxp.child_value(val, "mac")
 24.1222 -    ctrl = xend.netif_create(vm.dom, recreate=vm.recreate)
 24.1223 -    log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac))
 24.1224 -    recreate = vm.get_device_recreate('vif', index)
 24.1225 -    defer = ctrl.attachDevice(vif, val, recreate=recreate)
 24.1226 -    def cbok(dev):
 24.1227 -        dev.vifctl('up', vmname=vm.name)
 24.1228 -        dev.setIndex(index)
 24.1229 -        vm.add_device('vif', dev)
 24.1230 -        if change:
 24.1231 -            dev.interfaceChanged()
 24.1232 -        return dev
 24.1233 -    defer.addCallback(cbok)
 24.1234 -    return defer
 24.1235 -
 24.1236 -def vm_dev_usb(vm, val, index):
 24.1237 -    """Attach the relevant physical ports to the domains' USB interface.
 24.1238 -
 24.1239 -    @param vm:    virtual machine
 24.1240 -    @param val:   USB interface config
 24.1241 -    @param index: USB interface index
 24.1242 -    @return: deferred
 24.1243 -    """
 24.1244 -    ctrl = xend.usbif_create(vm.dom, recreate=vm.recreate)
 24.1245 -    log.debug("Creating USB interface dom=%d", vm.dom)
 24.1246 -    defer = ctrl.attachDevice(val, recreate=vm.recreate)
 24.1247 -    def cbok(path):
 24.1248 -        vm.add_device('usb', val[1][1])
 24.1249 -        return path
 24.1250 -    defer.addCallback(cbok)
 24.1251 -    return defer
 24.1252 -
 24.1253 -def vm_dev_vbd(vm, val, index, change=0):
 24.1254 -    """Create a virtual block device (vbd).
 24.1255 -
 24.1256 -    @param vm:        virtual machine
 24.1257 -    @param val:       vbd config
 24.1258 -    @param index:     vbd index
 24.1259 -    @return: deferred
 24.1260 -    """
 24.1261 -    idx = vm.next_device_index('vbd')
 24.1262 -    uname = sxp.child_value(val, 'uname')
 24.1263 -    log.debug("Creating vbd dom=%d uname=%s", vm.dom, uname)
 24.1264 -    ctrl = xend.blkif_create(vm.dom, recreate=vm.recreate)
 24.1265 -    recreate = vm.get_device_recreate('vbd', index)
 24.1266 -    defer = ctrl.attachDevice(idx, val, recreate=recreate)
 24.1267 -    def cbok(dev):
 24.1268 -        dev.setIndex(index)
 24.1269 -        vm.add_device('vbd', dev)
 24.1270 -        if change:
 24.1271 -            dev.interfaceChanged()
 24.1272 -        return dev
 24.1273 -    defer.addCallback(cbok)
 24.1274 -    return defer
 24.1275 -
 24.1276 -def parse_pci(val):
 24.1277 -    """Parse a pci field.
 24.1278 -    """
 24.1279 -    if isinstance(val, types.StringType):
 24.1280 -        radix = 10
 24.1281 -        if val.startswith('0x') or val.startswith('0X'):
 24.1282 -            radix = 16
 24.1283 -        v = int(val, radix)
 24.1284 -    else:
 24.1285 -        v = val
 24.1286 -    return v
 24.1287 -
 24.1288 -def vm_dev_pci(vm, val, index, change=0):
 24.1289 -    """Add a pci device.
 24.1290 -
 24.1291 -    @param vm: virtual machine
 24.1292 -    @param val: device configuration
 24.1293 -    @param index: device index
 24.1294 -    @return: 0 on success
 24.1295 -    """
 24.1296 -    bus = sxp.child_value(val, 'bus')
 24.1297 -    if not bus:
 24.1298 -        raise VmError('pci: Missing bus')
 24.1299 -    dev = sxp.child_value(val, 'dev')
 24.1300 -    if not dev:
 24.1301 -        raise VmError('pci: Missing dev')
 24.1302 -    func = sxp.child_value(val, 'func')
 24.1303 -    if not func:
 24.1304 -        raise VmError('pci: Missing func')
 24.1305 -    try:
 24.1306 -        bus = parse_pci(bus)
 24.1307 -        dev = parse_pci(dev)
 24.1308 -        func = parse_pci(func)
 24.1309 -    except:
 24.1310 -        raise VmError('pci: invalid parameter')
 24.1311 -    log.debug("Creating pci device dom=%d bus=%x dev=%x func=%x", vm.dom, bus, dev, func)
 24.1312 -    rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
 24.1313 -                                      func=func, enable=1)
 24.1314 -    if rc < 0:
 24.1315 -        #todo non-fatal
 24.1316 -        raise VmError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
 24.1317 -                      (bus, dev, func))
 24.1318 -    return rc
 24.1319 -    
 24.1320 -
 24.1321  def vm_field_ignore(vm, config, val, index):
 24.1322      """Dummy config field handler used for fields with built-in handling.
 24.1323  
 24.1324 @@ -1355,16 +1152,11 @@ def vm_field_maxmem(vm, config, val, ind
 24.1325          raise VmError("invalid maxmem: " + str(maxmem))
 24.1326      xc.domain_setmaxmem(vm.dom, maxmem_kb = maxmem * 1024)
 24.1327  
 24.1328 +#============================================================================
 24.1329  # Register image handlers.
 24.1330 -add_image_handler('linux',  vm_image_linux)
 24.1331 -add_image_handler('plan9',  vm_image_plan9)
 24.1332 -add_image_handler('vmx',  vm_image_vmx)
 24.1333 -
 24.1334 -# Register device handlers.
 24.1335 -add_device_handler('vif',  vm_dev_vif)
 24.1336 -add_device_handler('vbd',  vm_dev_vbd)
 24.1337 -add_device_handler('pci',  vm_dev_pci)
 24.1338 -add_device_handler('usb',  vm_dev_usb)
 24.1339 +add_image_handler('linux', vm_image_linux)
 24.1340 +add_image_handler('plan9', vm_image_plan9)
 24.1341 +add_image_handler('vmx',   vm_image_vmx)
 24.1342  
 24.1343  # Ignore the fields we already handle.
 24.1344  add_config_handler('name',       vm_field_ignore)
 24.1345 @@ -1380,3 +1172,27 @@ add_config_handler('vcpus',      vm_fiel
 24.1346  
 24.1347  # Register other config handlers.
 24.1348  add_config_handler('maxmem',     vm_field_maxmem)
 24.1349 +
 24.1350 +#============================================================================
 24.1351 +# Register device controllers and their device config types.
 24.1352 +
 24.1353 +from server import console
 24.1354 +controller.addDevControllerClass("console", console.ConsoleController)
 24.1355 +
 24.1356 +from server import blkif
 24.1357 +controller.addDevControllerClass("vbd", blkif.BlkifController)
 24.1358 +add_device_handler("vbd", "vbd")
 24.1359 +
 24.1360 +from server import netif
 24.1361 +controller.addDevControllerClass("vif", netif.NetifController)
 24.1362 +add_device_handler("vif", "vif")
 24.1363 +
 24.1364 +from server import pciif
 24.1365 +controller.addDevControllerClass("pci", pciif.PciController)
 24.1366 +add_device_handler("pci", "pci")
 24.1367 +
 24.1368 +from xen.xend.server import usbif
 24.1369 +controller.addDevControllerClass("usb", usbif.UsbifController)
 24.1370 +add_device_handler("usb", "usb")
 24.1371 +
 24.1372 +#============================================================================
    25.1 --- a/tools/python/xen/xend/XendMigrate.py	Thu Apr 28 08:56:40 2005 +0000
    25.2 +++ b/tools/python/xen/xend/XendMigrate.py	Thu Apr 28 10:46:53 2005 +0000
    25.3 @@ -1,6 +1,7 @@
    25.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    25.5  
    25.6  import traceback
    25.7 +import threading
    25.8  
    25.9  import errno
   25.10  import sys
   25.11 @@ -8,12 +9,8 @@ import socket
   25.12  import time
   25.13  import types
   25.14  
   25.15 -from twisted.internet import reactor
   25.16 -from twisted.internet import defer
   25.17 -#defer.Deferred.debug = 1
   25.18 -from twisted.internet.protocol import Protocol
   25.19 -from twisted.internet.protocol import ClientFactory
   25.20 -from twisted.python.failure import Failure
   25.21 +from xen.web import reactor
   25.22 +from xen.web.protocol import Protocol, ClientFactory
   25.23  
   25.24  import sxp
   25.25  import XendDB
   25.26 @@ -37,11 +34,13 @@ class Xfrd(Protocol):
   25.27          self.parser = sxp.Parser()
   25.28          self.xinfo = xinfo
   25.29  
   25.30 -    def connectionMade(self):
   25.31 +    def connectionMade(self, addr=None):
   25.32          # Send hello.
   25.33          self.request(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR])
   25.34          # Send request.
   25.35          self.xinfo.request(self)
   25.36 +        # Run the transport mainLoop which reads from the peer.
   25.37 +        self.transport.mainLoop()
   25.38  
   25.39      def request(self, req):
   25.40          sxp.show(req, out=self.transport)
   25.41 @@ -60,7 +59,6 @@ class Xfrd(Protocol):
   25.42          if self.parser.at_eof():
   25.43              self.loseConnection()
   25.44              
   25.45 -
   25.46  class XfrdClientFactory(ClientFactory):
   25.47      """Factory for clients of the migration/save daemon xfrd.
   25.48      """
   25.49 @@ -68,7 +66,33 @@ class XfrdClientFactory(ClientFactory):
   25.50      def __init__(self, xinfo):
   25.51          #ClientFactory.__init__(self)
   25.52          self.xinfo = xinfo
   25.53 +        self.readyCond = threading.Condition()
   25.54 +        self.ready = False
   25.55 +        self.err = None
   25.56  
   25.57 +    def start(self):
   25.58 +        print 'XfrdClientFactory>start>'
   25.59 +        reactor.connectTCP('localhost', XFRD_PORT, self)
   25.60 +        try:
   25.61 +            self.readyCond.acquire()
   25.62 +            while not self.ready:
   25.63 +                self.readyCond.wait()
   25.64 +        finally:
   25.65 +            self.readyCond.release()
   25.66 +        print 'XfrdClientFactory>start>', 'err=', self.err
   25.67 +        if self.err:
   25.68 +            raise self.err
   25.69 +        return 0
   25.70 +
   25.71 +    def notifyReady(self):
   25.72 +        try:
   25.73 +            self.readyCond.acquire()
   25.74 +            self.ready = True
   25.75 +            self.err = self.xinfo.error_summary()
   25.76 +            self.readyCond.notify()
   25.77 +        finally:
   25.78 +            self.readyCond.release()
   25.79 +            
   25.80      def startedConnecting(self, connector):
   25.81          pass
   25.82  
   25.83 @@ -76,10 +100,72 @@ class XfrdClientFactory(ClientFactory):
   25.84          return Xfrd(self.xinfo)
   25.85  
   25.86      def clientConnectionLost(self, connector, reason):
   25.87 -        pass
   25.88 +        print "XfrdClientFactory>clientConnectionLost>", reason
   25.89 +        self.notifyReady()
   25.90  
   25.91      def clientConnectionFailed(self, connector, reason):
   25.92 +        print "XfrdClientFactory>clientConnectionFailed>", reason
   25.93          self.xinfo.error(reason)
   25.94 +        self.notifyReady()
   25.95 +
   25.96 +class SuspendHandler:
   25.97 +
   25.98 +    def __init__(self, xinfo, vmid, timeout):
   25.99 +        self.xinfo = xinfo
  25.100 +        self.vmid = vmid
  25.101 +        self.timeout = timeout
  25.102 +        self.readyCond = threading.Condition()
  25.103 +        self.ready = False
  25.104 +        self.err = None
  25.105 +
  25.106 +    def start(self):
  25.107 +        self.subscribe(on=True)
  25.108 +        timer = reactor.callLater(self.timeout, self.onTimeout)
  25.109 +        try:
  25.110 +            self.readyCond.acquire()
  25.111 +            while not self.ready:
  25.112 +                self.readyCond.wait()
  25.113 +        finally:
  25.114 +            self.readyCond.release()
  25.115 +            self.subscribe(on=False)
  25.116 +            timer.cancel()
  25.117 +        if self.err:
  25.118 +            raise XendError(self.err)
  25.119 +
  25.120 +    def notifyReady(self, err=None):
  25.121 +        try:
  25.122 +            self.readyCond.acquire()
  25.123 +            if not self.ready:
  25.124 +                self.ready = True
  25.125 +                self.err = err
  25.126 +                self.readyCond.notify()
  25.127 +        finally:
  25.128 +            self.readyCond.release()
  25.129 +
  25.130 +    def subscribe(self, on=True):
  25.131 +        # Subscribe to 'suspended' events so we can tell when the
  25.132 +        # suspend completes. Subscribe to 'died' events so we can tell if
  25.133 +        # the domain died.
  25.134 +        if on:
  25.135 +            action = eserver.subscribe
  25.136 +        else:
  25.137 +            action = eserver.unsubscribe
  25.138 +        action('xend.domain.suspended', self.onSuspended)
  25.139 +        action('xend.domain.died', self.onDied)
  25.140 +
  25.141 +    def onSuspended(self, e, v):
  25.142 +        if v[1] != self.vmid: return
  25.143 +        print 'SuspendHandler>onSuspended>', e, v
  25.144 +        self.notifyReady()
  25.145 +                
  25.146 +    def onDied(self, e, v):
  25.147 +        if v[1] != self.vmid: return
  25.148 +        print 'SuspendHandler>onDied>', e, v
  25.149 +        self.notifyReady('Domain %s died while suspending' % self.vmid)
  25.150 +
  25.151 +    def onTimeout(self):
  25.152 +         print 'SuspendHandler>onTimeout>'
  25.153 +         self.notifyReady('Domain %s suspend timed out' % self.vmid)
  25.154  
  25.155  class XfrdInfo:
  25.156      """Abstract class for info about a session with xfrd.
  25.157 @@ -88,18 +174,17 @@ class XfrdInfo:
  25.158  
  25.159      """Suspend timeout (seconds).
  25.160      We set a timeout because suspending a domain can hang."""
  25.161 -    timeout = 10
  25.162 +    timeout = 30
  25.163  
  25.164      def __init__(self):
  25.165          from xen.xend import XendDomain
  25.166          self.xd = XendDomain.instance()
  25.167 -        self.deferred = defer.Deferred()
  25.168          self.suspended = {}
  25.169          self.paused = {}
  25.170          self.state = 'init'
  25.171          # List of errors encountered.
  25.172          self.errors = []
  25.173 -        
  25.174 +            
  25.175      def vmconfig(self):
  25.176          dominfo = self.xd.domain_get(self.src_dom)
  25.177          if dominfo:
  25.178 @@ -110,11 +195,8 @@ class XfrdInfo:
  25.179  
  25.180      def add_error(self, err):
  25.181          """Add an error to the error list.
  25.182 -        Returns the error added (which may have been unwrapped if it
  25.183 -        was a Twisted Failure).
  25.184 +        Returns the error added.
  25.185          """
  25.186 -        while isinstance(err, Failure):
  25.187 -            err = err.value
  25.188          if err not in self.errors:
  25.189              self.errors.append(err)
  25.190          return err
  25.191 @@ -122,6 +204,8 @@ class XfrdInfo:
  25.192      def error_summary(self, msg=None):
  25.193          """Get a XendError summarising the errors (if any).
  25.194          """
  25.195 +        if not self.errors:
  25.196 +            return None
  25.197          if msg is None:
  25.198              msg = "errors"
  25.199          if self.errors:
  25.200 @@ -136,34 +220,27 @@ class XfrdInfo:
  25.201          return self.errors
  25.202  
  25.203      def error(self, err):
  25.204 +        print 'XfrdInfo>error>', err
  25.205          self.state = 'error'
  25.206          self.add_error(err)
  25.207 -        if not self.deferred.called:
  25.208 -            self.deferred.errback(self.error_summary())
  25.209  
  25.210      def dispatch(self, xfrd, val):
  25.211 -        
  25.212 -        def cbok(v):
  25.213 -            if v is None: return
  25.214 -            sxp.show(v, out=xfrd.transport)
  25.215 -
  25.216 -        def cberr(err):
  25.217 -            v = ['xfr.err', errno.EINVAL]
  25.218 -            sxp.show(v, out=xfrd.transport)
  25.219 -            self.error(err)
  25.220 -
  25.221 +        print 'XfrdInfo>dispatch>', val
  25.222          op = sxp.name(val)
  25.223          op = op.replace('.', '_')
  25.224          if op.startswith('xfr_'):
  25.225              fn = getattr(self, op, self.unknown)
  25.226          else:
  25.227              fn = self.unknown
  25.228 -        val = fn(xfrd, val)
  25.229 -        if isinstance(val, defer.Deferred):
  25.230 -            val.addCallback(cbok)
  25.231 -            val.addErrback(cberr)
  25.232 -        else:
  25.233 -            cbok(val)
  25.234 +        try:
  25.235 +            val = fn(xfrd, val)
  25.236 +            if val:
  25.237 +                sxp.show(val, out=xfrd.transport)
  25.238 +        except Exception, err:
  25.239 +            print 'XfrdInfo>dispatch> error:', err
  25.240 +            val = ['xfr.err', errno.EINVAL]
  25.241 +            sxp.show(val, out=xfrd.transport)
  25.242 +            self.error(err)
  25.243  
  25.244      def unknown(self, xfrd, val):
  25.245          xfrd.loseConnection()
  25.246 @@ -172,6 +249,7 @@ class XfrdInfo:
  25.247      def xfr_err(self, xfrd, val):
  25.248          # If we get an error with non-zero code the operation failed.
  25.249          # An error with code zero indicates hello success.
  25.250 +        print 'XfrdInfo>xfr_err>', val
  25.251          v = sxp.child0(val)
  25.252          err = int(sxp.child0(val))
  25.253          if not err: return
  25.254 @@ -220,50 +298,19 @@ class XfrdInfo:
  25.255          return ['xfr.err', val]
  25.256  
  25.257      def xfr_vm_suspend(self, xfrd, val):
  25.258 -        """Suspend a domain. Suspending takes time, so we return
  25.259 -        a Deferred that is called when the suspend completes.
  25.260 +        """Suspend a domain.
  25.261          Suspending can hang, so we set a timeout and fail if it
  25.262          takes too long.
  25.263          """
  25.264          try:
  25.265              vmid = sxp.child0(val)
  25.266 -            d = defer.Deferred()
  25.267 -            # Subscribe to 'suspended' events so we can tell when the
  25.268 -            # suspend completes. Subscribe to 'died' events so we can tell if
  25.269 -            # the domain died. Set a timeout and error handler so the subscriptions
  25.270 -            # will be cleaned up if suspending hangs or there is an error.
  25.271 -            def onSuspended(e, v):
  25.272 -                if v[1] != vmid: return
  25.273 -                subscribe(on=0)
  25.274 -                if not d.called:
  25.275 -                    d.callback(v)
  25.276 -                
  25.277 -            def onDied(e, v):
  25.278 -                if v[1] != vmid: return
  25.279 -                if not d.called:
  25.280 -                    d.errback(XendError('Domain %s died while suspending' % vmid))
  25.281 -                
  25.282 -            def subscribe(on=1):
  25.283 -                if on:
  25.284 -                    action = eserver.subscribe
  25.285 -                else:
  25.286 -                    action = eserver.unsubscribe
  25.287 -                action('xend.domain.suspended', onSuspended)
  25.288 -                action('xend.domain.died', onDied)
  25.289 -
  25.290 -            def cberr(err):
  25.291 -                subscribe(on=0)
  25.292 -                self.add_error("suspend failed")
  25.293 -                self.add_error(err)
  25.294 -                return err
  25.295 -
  25.296 -            d.addErrback(cberr)
  25.297 -            d.setTimeout(self.timeout)
  25.298 -            subscribe()
  25.299 +            h = SuspendHandler(self, vmid, self.timeout)
  25.300              val = self.xd.domain_shutdown(vmid, reason='suspend')
  25.301              self.suspended[vmid] = 1
  25.302 -            return d
  25.303 +            h.start()
  25.304 +            print 'xfr_vm_suspend> suspended', vmid
  25.305          except Exception, err:
  25.306 +            print 'xfr_vm_suspend> err', err
  25.307              self.add_error("suspend failed")
  25.308              self.add_error(err)
  25.309              traceback.print_exc()
  25.310 @@ -271,6 +318,7 @@ class XfrdInfo:
  25.311          return ['xfr.err', val]
  25.312  
  25.313      def connectionLost(self, reason=None):
  25.314 +        print 'XfrdInfo>connectionLost>', reason
  25.315          for vmid in self.suspended:
  25.316              try:
  25.317                  self.xd.domain_destroy(vmid)
  25.318 @@ -336,10 +384,9 @@ class XendMigrateInfo(XfrdInfo):
  25.319          self.state = 'ok'
  25.320          self.dst_dom = dom
  25.321          self.xd.domain_destroy(self.src_dom)
  25.322 -        if not self.deferred.called:
  25.323 -            self.deferred.callback(self)
  25.324  
  25.325      def connectionLost(self, reason=None):
  25.326 +        print 'XendMigrateInfo>connectionLost>', reason
  25.327          XfrdInfo.connectionLost(self, reason)
  25.328          if self.state =='ok':
  25.329              log.info('Migrate OK: ' + str(self.sxpr()))
  25.330 @@ -386,10 +433,9 @@ class XendSaveInfo(XfrdInfo):
  25.331      def xfr_save_ok(self, xfrd, val):
  25.332          self.state = 'ok'
  25.333          self.xd.domain_destroy(self.src_dom)
  25.334 -        if not self.deferred.called:
  25.335 -            self.deferred.callback(self)
  25.336  
  25.337      def connectionLost(self, reason=None):
  25.338 +        print 'XendSaveInfo>connectionLost>', reason
  25.339          XfrdInfo.connectionLost(self, reason)
  25.340          if self.state =='ok':
  25.341              log.info('Save OK: ' + str(self.sxpr()))
  25.342 @@ -427,8 +473,6 @@ class XendRestoreInfo(XfrdInfo):
  25.343          dom = int(sxp.child0(val))
  25.344          dominfo = self.xd.domain_get(dom)
  25.345          self.state = 'ok'
  25.346 -        if not self.deferred.called:
  25.347 -            self.deferred.callback(dominfo)
  25.348           
  25.349      def connectionLost(self, reason=None):
  25.350          XfrdInfo.connectionLost(self, reason)
  25.351 @@ -493,29 +537,16 @@ class XendMigrate:
  25.352  
  25.353      def session_begin(self, info):
  25.354          """Add the session to the table and start it.
  25.355 -        Set up callbacks to remove the session from the table
  25.356 -        when it finishes.
  25.357 +        Remove the session from the table when it finishes.
  25.358  
  25.359          @param info: session
  25.360 -        @return: deferred
  25.361          """
  25.362 -        dfr = defer.Deferred()
  25.363 -        def cbok(val):
  25.364 -            self._delete_session(info.xid)
  25.365 -            if not dfr.called:
  25.366 -                dfr.callback(val)
  25.367 -            return val
  25.368 -        def cberr(err):
  25.369 +        self._add_session(info)
  25.370 +        try:
  25.371 +            xcf = XfrdClientFactory(info)
  25.372 +            return xcf.start()
  25.373 +        finally:
  25.374              self._delete_session(info.xid)
  25.375 -            if not dfr.called:
  25.376 -                dfr.errback(err)
  25.377 -            return err
  25.378 -        self._add_session(info)
  25.379 -        info.deferred.addCallback(cbok)
  25.380 -        info.deferred.addErrback(cberr)
  25.381 -        xcf = XfrdClientFactory(info)
  25.382 -        reactor.connectTCP('localhost', XFRD_PORT, xcf)
  25.383 -        return dfr
  25.384      
  25.385      def migrate_begin(self, dominfo, host, port=XFRD_PORT, live=0, resource=0):
  25.386          """Begin to migrate a domain to another host.
  25.387 @@ -523,7 +554,6 @@ class XendMigrate:
  25.388          @param dominfo:  domain info
  25.389          @param host: destination host
  25.390          @param port: destination port
  25.391 -        @return: deferred
  25.392          """
  25.393          xid = self.nextid()
  25.394          info = XendMigrateInfo(xid, dominfo, host, port, live, resource)
  25.395 @@ -534,7 +564,6 @@ class XendMigrate:
  25.396  
  25.397          @param dominfo:  domain info
  25.398          @param file: destination file
  25.399 -        @return: deferred
  25.400          """
  25.401          xid = self.nextid()
  25.402          info = XendSaveInfo(xid, dominfo, file)
    26.1 --- a/tools/python/xen/xend/XendProtocol.py	Thu Apr 28 08:56:40 2005 +0000
    26.2 +++ b/tools/python/xen/xend/XendProtocol.py	Thu Apr 28 10:46:53 2005 +0000
    26.3 @@ -1,5 +1,6 @@
    26.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    26.5  
    26.6 +import socket
    26.7  import httplib
    26.8  import types
    26.9  
   26.10 @@ -122,12 +123,19 @@ class XendClientProtocol:
   26.11          """
   26.12          raise NotImplementedError()
   26.13  
   26.14 -class SynchXendClientProtocol(XendClientProtocol):
   26.15 +class HttpXendClientProtocol(XendClientProtocol):
   26.16      """A synchronous xend client. This will make a request, wait for
   26.17      the reply and return the result.
   26.18      """
   26.19  
   26.20      resp = None
   26.21 +    request = None
   26.22 +
   26.23 +    def makeConnection(self, url):
   26.24 +        return httplib.HTTPConnection(url.location())
   26.25 +
   26.26 +    def makeRequest(self, url, method, args):
   26.27 +        return XendRequest(url, method, args)
   26.28  
   26.29      def xendRequest(self, url, method, args=None):
   26.30          """Make a request to xend.
   26.31 @@ -136,8 +144,8 @@ class SynchXendClientProtocol(XendClient
   26.32          @param method: http method: POST or GET
   26.33          @param args:   request arguments (dict)
   26.34          """
   26.35 -        self.request = XendRequest(url, method, args)
   26.36 -        conn = httplib.HTTPConnection(url.location())
   26.37 +        self.request = self.makeRequest(url, method, args)
   26.38 +        conn = self.makeConnection(url)
   26.39          if DEBUG: conn.set_debuglevel(1)
   26.40          conn.request(method, url.fullpath(), self.request.data, self.request.headers)
   26.41          resp = conn.getresponse()
   26.42 @@ -154,3 +162,29 @@ class SynchXendClientProtocol(XendClient
   26.43      def getHeader(self, key):
   26.44          return self.resp.getheader(key)
   26.45  
   26.46 +class UnixConnection(httplib.HTTPConnection):
   26.47 +    """Subclass of Python library HTTPConnection that uses a unix-domain socket.
   26.48 +    """
   26.49 +
   26.50 +    def __init__(self, path):
   26.51 +        httplib.HTTPConnection.__init__(self, 'localhost')
   26.52 +        self.path = path
   26.53 +
   26.54 +    def connect(self):
   26.55 +        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
   26.56 +        sock.connect(self.path)
   26.57 +        self.sock = sock
   26.58 +
   26.59 +class UnixXendClientProtocol(HttpXendClientProtocol):
   26.60 +    """A synchronous xend client using a unix-domain socket.
   26.61 +    """
   26.62 +
   26.63 +    XEND_PATH_DEFAULT = '/var/lib/xend/xend-socket'
   26.64 +    
   26.65 +    def __init__(self, path=None):
   26.66 +        if path is None:
   26.67 +            path = self.XEND_PATH_DEFAULT
   26.68 +        self.path = path
   26.69 +
   26.70 +    def makeConnection(self, url):
   26.71 +        return UnixConnection(self.path)
    27.1 --- a/tools/python/xen/xend/XendRoot.py	Thu Apr 28 08:56:40 2005 +0000
    27.2 +++ b/tools/python/xen/xend/XendRoot.py	Thu Apr 28 10:46:53 2005 +0000
    27.3 @@ -15,6 +15,7 @@ import sys
    27.4  
    27.5  import EventServer
    27.6  from XendLogging import XendLogging
    27.7 +from XendError import XendError
    27.8  
    27.9  # Initial create of the event server.
   27.10  eserver = EventServer.instance()
   27.11 @@ -44,6 +45,9 @@ class XendRoot:
   27.12  
   27.13      loglevel_default = 'DEBUG'
   27.14  
   27.15 +    """Default for the flag indicating whether xend should run an http server."""
   27.16 +    xend_http_server_default = 'no'
   27.17 +
   27.18      """Default interface address xend listens at. """
   27.19      xend_address_default      = ''
   27.20  
   27.21 @@ -53,7 +57,13 @@ class XendRoot:
   27.22      """Default port xend serves events at. """
   27.23      xend_event_port_default   = '8001'
   27.24  
   27.25 -    """Default inteface address xend listens at for consoles."""
   27.26 +    """Default for the flag indicating whether xend should run a unix-domain server."""
   27.27 +    xend_unix_server_default = 'yes'
   27.28 +
   27.29 +    """Default path the unix-domain server listens at."""
   27.30 +    xend_unix_path_default = '/var/lib/xend/xend-socket'
   27.31 +
   27.32 +    """Default interface address xend listens at for consoles."""
   27.33      console_address_default   = ''
   27.34  
   27.35      """Default port xend serves consoles at. """
   27.36 @@ -157,6 +167,7 @@ class XendRoot:
   27.37          logfile = self.get_config_value("logfile", self.logfile_default)
   27.38          loglevel = self.get_config_value("loglevel", self.loglevel_default)
   27.39          self.logging = XendLogging(logfile, level=loglevel)
   27.40 +        self.logging.addLogStderr()
   27.41  
   27.42      def get_logging(self):
   27.43          """Get the XendLogging instance.
   27.44 @@ -218,15 +229,35 @@ class XendRoot:
   27.45          """
   27.46          return sxp.child_value(self.config, name, val=val)
   27.47  
   27.48 +    def get_config_bool(self, name, val=None):
   27.49 +        v = self.get_config_value(name, val)
   27.50 +        if v in ['yes', '1', 'on', 1, True]:
   27.51 +            return True
   27.52 +        if v in ['no', '0', 'off', 0, False]:
   27.53 +            return False
   27.54 +        raise XendError("invalid xend config %s: expected bool: %s" % (name, v))
   27.55 +
   27.56 +    def get_config_int(self, name, val=None):
   27.57 +        v = self.get_config_value(name, val)
   27.58 +        try:
   27.59 +            return int(v)
   27.60 +        except Exception, ex:
   27.61 +            raise XendError("invalid xend config %s: expected int: %s" % (name, v))
   27.62 +
   27.63 +    def get_xend_http_server(self):
   27.64 +        """Get the flag indicating whether xend should run an http server.
   27.65 +        """
   27.66 +        return self.get_config_bool("xend-http-server", self.xend_http_server_default)
   27.67 +
   27.68      def get_xend_port(self):
   27.69          """Get the port xend listens at for its HTTP interface.
   27.70          """
   27.71 -        return int(self.get_config_value('xend-port', self.xend_port_default))
   27.72 +        return self.get_config_int('xend-port', self.xend_port_default)
   27.73  
   27.74      def get_xend_event_port(self):
   27.75          """Get the port xend listens at for connection to its event server.
   27.76          """
   27.77 -        return int(self.get_config_value('xend-event-port', self.xend_event_port_default))
   27.78 +        return self.get_config_int('xend-event-port', self.xend_event_port_default)
   27.79  
   27.80      def get_xend_address(self):
   27.81          """Get the address xend listens at for its HTTP and event ports.
   27.82 @@ -236,6 +267,16 @@ class XendRoot:
   27.83          """
   27.84          return self.get_config_value('xend-address', self.xend_address_default)
   27.85  
   27.86 +    def get_xend_unix_server(self):
   27.87 +        """Get the flag indicating whether xend should run a unix-domain server.
   27.88 +        """
   27.89 +        return self.get_config_bool("xend-unix-server", self.xend_unix_server_default)
   27.90 +
   27.91 +    def get_xend_unix_path(self):
   27.92 +        """Get the path the xend unix-domain server listens at.
   27.93 +        """
   27.94 +        return self.get_config_value("xend-unix-path", self.xend_unix_path_default)
   27.95 +
   27.96      def get_console_address(self):
   27.97          """Get the address xend listens at for its console ports.
   27.98          This defaults to the empty string which allows all hosts to connect.
   27.99 @@ -247,7 +288,7 @@ class XendRoot:
  27.100      def get_console_port_base(self):
  27.101          """Get the base port number used to generate console ports for domains.
  27.102          """
  27.103 -        return int(self.get_config_value('console-port-base', self.console_port_base_default))
  27.104 +        return self.get_config_int('console-port-base', self.console_port_base_default)
  27.105  
  27.106      def get_block_script(self, type):
  27.107          return self.get_config_value('block-%s' % type, '')
  27.108 @@ -262,8 +303,7 @@ class XendRoot:
  27.109          return self.get_config_value('vif-script', 'vif-bridge')
  27.110  
  27.111      def get_vif_antispoof(self):
  27.112 -        v = self.get_config_value('vif-antispoof', 'yes')
  27.113 -        return v in ['yes', '1', 'on']
  27.114 +        return self.get_config_bool('vif-antispoof', 'yes')
  27.115  
  27.116  def instance():
  27.117      """Get an instance of XendRoot.
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tools/python/xen/xend/scheduler.py	Thu Apr 28 10:46:53 2005 +0000
    28.3 @@ -0,0 +1,51 @@
    28.4 +import threading
    28.5 +
    28.6 +class Scheduler:
    28.7 +
    28.8 +    def __init__(self):
    28.9 +        self.lock = threading.Lock()
   28.10 +        self.schedule = {}
   28.11 +
   28.12 +    def later(self, _delay, _name, _fn, args, kwargs={}):
   28.13 +        """Schedule a function to be called later (if not already scheduled).
   28.14 +
   28.15 +        @param _delay: delay in seconds
   28.16 +        @param _name:  schedule name
   28.17 +        @param _fn:    function
   28.18 +        @param args:   arguments (list)
   28.19 +        @param kwargs  keyword arguments (map)
   28.20 +        """
   28.21 +        try:
   28.22 +            self.lock.acquire()
   28.23 +            if self.schedule.get(_name): return
   28.24 +            runargs = [ _name, _fn, args, kwargs ]
   28.25 +            timer = threading.Timer(_delay, self._run, args=runargs)
   28.26 +            self.schedule[_name] = timer
   28.27 +        finally:
   28.28 +            self.lock.release()
   28.29 +        timer.start()
   28.30 +
   28.31 +    def cancel(self, name):
   28.32 +        """Cancel a scheduled function call.
   28.33 +        
   28.34 +        @param name: schedule name to cancel
   28.35 +        """
   28.36 +        timer = self._remove(name)
   28.37 +        if timer:
   28.38 +            timer.cancel()
   28.39 +
   28.40 +    def _remove(self, name):
   28.41 +        try:
   28.42 +            self.lock.acquire()
   28.43 +            timer = self.schedule.get(name)
   28.44 +            if timer:
   28.45 +                del self.schedule[name]
   28.46 +            return timer
   28.47 +        finally:
   28.48 +            self.lock.release()
   28.49 +
   28.50 +    def _run(self, name, fn, args, kwargs):
   28.51 +        self._remove(name)
   28.52 +        fn(*args, **kwargs)
   28.53 +
   28.54 +        
    29.1 --- a/tools/python/xen/xend/server/SrvBase.py	Thu Apr 28 08:56:40 2005 +0000
    29.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.3 @@ -1,185 +0,0 @@
    29.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    29.5 -
    29.6 -import cgi
    29.7 -
    29.8 -import os
    29.9 -import sys
   29.10 -import types
   29.11 -import StringIO
   29.12 -
   29.13 -from twisted.internet import defer
   29.14 -from twisted.internet import reactor
   29.15 -from twisted.protocols import http
   29.16 -from twisted.web import error
   29.17 -from twisted.web import resource
   29.18 -from twisted.web import server
   29.19 -from twisted.python.failure import Failure
   29.20 -
   29.21 -from xen.xend import sxp
   29.22 -from xen.xend import PrettyPrint
   29.23 -from xen.xend.Args import ArgError
   29.24 -from xen.xend.XendError import XendError
   29.25 -from xen.xend.XendLogging import log
   29.26 -
   29.27 -def uri_pathlist(p):
   29.28 -    """Split a path into a list.
   29.29 -    p		path
   29.30 -    return list of path elements
   29.31 -    """
   29.32 -    l = []
   29.33 -    for x in p.split('/'):
   29.34 -        if x == '': continue
   29.35 -        l.append(x)
   29.36 -    return l
   29.37 -
   29.38 -class SrvBase(resource.Resource):
   29.39 -    """Base class for services.
   29.40 -    """
   29.41 -
   29.42 -    def parse_form(self, req, method):
   29.43 -        """Parse the data for a request, GET using the URL, POST using encoded data.
   29.44 -        Posts should use enctype='multipart/form-data' in the <form> tag,
   29.45 -        rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data'
   29.46 -        handles file upload.
   29.47 -
   29.48 -        req		request
   29.49 -        returns a cgi.FieldStorage instance
   29.50 -        """
   29.51 -        env = {}
   29.52 -        env['REQUEST_METHOD'] = method
   29.53 -        if self.query:
   29.54 -            env['QUERY_STRING'] = self.query
   29.55 -        val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env)
   29.56 -        return val
   29.57 -    
   29.58 -    def use_sxp(self, req):
   29.59 -        """Determine whether to send an SXP response to a request.
   29.60 -        Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
   29.61 -
   29.62 -        req		request
   29.63 -        returns 1 for SXP, 0 otherwise
   29.64 -        """
   29.65 -        ok = 0
   29.66 -        user_agent = req.getHeader('User-Agent')
   29.67 -        accept = req.getHeader('Accept')
   29.68 -        if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
   29.69 -            ok = 1
   29.70 -        return ok
   29.71 -
   29.72 -    def get_op_method(self, op):
   29.73 -        """Get the method for an operation.
   29.74 -        For operation 'foo' looks for 'op_foo'.
   29.75 -
   29.76 -        op	operation name
   29.77 -        returns method or None
   29.78 -        """
   29.79 -        op_method_name = 'op_' + op
   29.80 -        return getattr(self, op_method_name, None)
   29.81 -        
   29.82 -    def perform(self, req):
   29.83 -        """General operation handler for posted operations.
   29.84 -        For operation 'foo' looks for a method op_foo and calls
   29.85 -        it with op_foo(op, req). Replies with code 500 if op_foo
   29.86 -        is not found.
   29.87 -
   29.88 -        The method must return a list when req.use_sxp is true
   29.89 -        and an HTML string otherwise (or list).
   29.90 -        Methods may also return a Deferred (for incomplete processing).
   29.91 -
   29.92 -        req	request
   29.93 -        """
   29.94 -        op = req.args.get('op')
   29.95 -        if op is None or len(op) != 1:
   29.96 -            req.setResponseCode(http.NOT_ACCEPTABLE, "Invalid request")
   29.97 -            return ''
   29.98 -        op = op[0]
   29.99 -        op_method = self.get_op_method(op)
  29.100 -        if op_method is None:
  29.101 -            req.setResponseCode(http.NOT_IMPLEMENTED, "Operation not implemented: " + op)
  29.102 -            req.setHeader("Content-Type", "text/plain")
  29.103 -            req.write("Operation not implemented: " + op)
  29.104 -            return ''
  29.105 -        else:
  29.106 -            return self._perform(op, op_method, req)
  29.107 -
  29.108 -    def _perform(self, op, op_method, req):
  29.109 -        try:
  29.110 -            val = op_method(op, req)
  29.111 -        except Exception, err:
  29.112 -            self._perform_err(err, op, req)
  29.113 -            return ''
  29.114 -            
  29.115 -        if isinstance(val, defer.Deferred):
  29.116 -            val.addCallback(self._perform_cb, op, req, dfr=1)
  29.117 -            val.addErrback(self._perform_err, op, req, dfr=1)
  29.118 -            return server.NOT_DONE_YET
  29.119 -        else:
  29.120 -            self._perform_cb(val, op, req, dfr=0)
  29.121 -            return ''
  29.122 -
  29.123 -    def _perform_cb(self, val, op, req, dfr=0):
  29.124 -        """Callback to complete the request.
  29.125 -        May be called from a Deferred.
  29.126 -
  29.127 -        @param err: the error
  29.128 -        @param req: request causing the error
  29.129 -        @param dfr: deferred flag
  29.130 -        """
  29.131 -        if isinstance(val, error.ErrorPage):
  29.132 -            req.write(val.render(req))
  29.133 -        elif self.use_sxp(req):
  29.134 -            req.setHeader("Content-Type", sxp.mime_type)
  29.135 -            sxp.show(val, out=req)
  29.136 -        else:
  29.137 -            req.write('<html><head></head><body>')
  29.138 -            self.print_path(req)
  29.139 -            if isinstance(val, types.ListType):
  29.140 -                req.write('<code><pre>')
  29.141 -                PrettyPrint.prettyprint(val, out=req)
  29.142 -                req.write('</pre></code>')
  29.143 -            else:
  29.144 -                req.write(str(val))
  29.145 -            req.write('</body></html>')
  29.146 -        if dfr:
  29.147 -            req.finish()
  29.148 -
  29.149 -    def _perform_err(self, err, op, req, dfr=0):
  29.150 -        """Error callback to complete a request.
  29.151 -        May be called from a Deferred.
  29.152 -
  29.153 -        @param err: the error
  29.154 -        @param req: request causing the error
  29.155 -        @param dfr: deferred flag
  29.156 -        """
  29.157 -        if isinstance(err, Failure):
  29.158 -            err = err.getErrorMessage()
  29.159 -        elif not (isinstance(err, ArgError) or
  29.160 -                  isinstance(err, sxp.ParseError) or
  29.161 -                  isinstance(err, XendError)):
  29.162 -            if dfr:
  29.163 -                return err
  29.164 -            else:
  29.165 -                raise
  29.166 -        log.exception("op=%s: %s", op, str(err))
  29.167 -        if self.use_sxp(req):
  29.168 -            req.setHeader("Content-Type", sxp.mime_type)
  29.169 -            sxp.show(['xend.err', str(err)], out=req)
  29.170 -        else:
  29.171 -            req.setHeader("Content-Type", "text/plain")
  29.172 -            req.write('Error ')
  29.173 -            req.write(': ')
  29.174 -            req.write(str(err))
  29.175 -        if dfr:
  29.176 -            req.finish()
  29.177 -        
  29.178 -
  29.179 -    def print_path(self, req):
  29.180 -        """Print the path with hyperlinks.
  29.181 -        """
  29.182 -        pathlist = [x for x in req.prepath if x != '' ]
  29.183 -        s = "/"
  29.184 -        req.write('<h1><a href="/">/</a>')
  29.185 -        for x in pathlist:
  29.186 -            s += x + "/"
  29.187 -            req.write(' <a href="%s">%s</a>/' % (s, x))
  29.188 -        req.write("</h1>")
    30.1 --- a/tools/python/xen/xend/server/SrvConsole.py	Thu Apr 28 08:56:40 2005 +0000
    30.2 +++ b/tools/python/xen/xend/server/SrvConsole.py	Thu Apr 28 10:46:53 2005 +0000
    30.3 @@ -2,7 +2,7 @@
    30.4  
    30.5  from xen.xend import sxp
    30.6  from xen.xend import XendConsole
    30.7 -from SrvDir import SrvDir
    30.8 +from xen.web.SrvDir import SrvDir
    30.9  
   30.10  class SrvConsole(SrvDir):
   30.11      """An individual console.
   30.12 @@ -21,22 +21,18 @@ class SrvConsole(SrvDir):
   30.13          return self.perform(req)
   30.14          
   30.15      def render_GET(self, req):
   30.16 -        try:
   30.17 -            if self.use_sxp(req):
   30.18 -                req.setHeader("Content-Type", sxp.mime_type)
   30.19 -                sxp.show(self.info.sxpr(), out=req)
   30.20 -            else:
   30.21 -                req.write('<html><head></head><body>')
   30.22 -                self.print_path(req)
   30.23 -                #self.ls()
   30.24 -                req.write('<p>%s</p>' % self.info)
   30.25 -                req.write('<p><a href="%s">Connect to domain %d</a></p>'
   30.26 -                          % (self.info.uri(), self.info.dom))
   30.27 -                self.form(req)
   30.28 -                req.write('</body></html>')
   30.29 -            return ''
   30.30 -        except Exception, ex:
   30.31 -            self._perform_err(ex, req)
   30.32 +        if self.use_sxp(req):
   30.33 +            req.setHeader("Content-Type", sxp.mime_type)
   30.34 +            sxp.show(self.info.sxpr(), out=req)
   30.35 +        else:
   30.36 +            req.write('<html><head></head><body>')
   30.37 +            self.print_path(req)
   30.38 +            #self.ls()
   30.39 +            req.write('<p>%s</p>' % self.info)
   30.40 +            req.write('<p><a href="%s">Connect to domain %d</a></p>'
   30.41 +                      % (self.info.uri(), self.info.dom))
   30.42 +            self.form(req)
   30.43 +            req.write('</body></html>')
   30.44  
   30.45      def form(self, req):
   30.46          req.write('<form method="post" action="%s">' % req.prePathURL())
    31.1 --- a/tools/python/xen/xend/server/SrvConsoleDir.py	Thu Apr 28 08:56:40 2005 +0000
    31.2 +++ b/tools/python/xen/xend/server/SrvConsoleDir.py	Thu Apr 28 10:46:53 2005 +0000
    31.3 @@ -31,20 +31,16 @@ class SrvConsoleDir(SrvDir):
    31.4          return v
    31.5  
    31.6      def render_GET(self, req):
    31.7 -        try:
    31.8 -            if self.use_sxp(req):
    31.9 -                req.setHeader("Content-Type", sxp.mime_type)
   31.10 -                self.ls_console(req, 1)
   31.11 -            else:
   31.12 -                req.write("<html><head></head><body>")
   31.13 -                self.print_path(req)
   31.14 -                self.ls(req)
   31.15 -                self.ls_console(req)
   31.16 -                #self.form(req.wfile)
   31.17 -                req.write("</body></html>")
   31.18 -            return ''
   31.19 -        except Exception, ex:
   31.20 -            self._perform_err(ex, req)
   31.21 +        if self.use_sxp(req):
   31.22 +            req.setHeader("Content-Type", sxp.mime_type)
   31.23 +            self.ls_console(req, 1)
   31.24 +        else:
   31.25 +            req.write("<html><head></head><body>")
   31.26 +            self.print_path(req)
   31.27 +            self.ls(req)
   31.28 +            self.ls_console(req)
   31.29 +            #self.form(req.wfile)
   31.30 +            req.write("</body></html>")
   31.31  
   31.32      def ls_console(self, req, use_sxp=0):
   31.33          url = req.prePathURL()
    32.1 --- a/tools/python/xen/xend/server/SrvDaemon.py	Thu Apr 28 08:56:40 2005 +0000
    32.2 +++ b/tools/python/xen/xend/server/SrvDaemon.py	Thu Apr 28 10:46:53 2005 +0000
    32.3 @@ -17,20 +17,11 @@ import StringIO
    32.4  import traceback
    32.5  import time
    32.6  
    32.7 -from twisted.internet import pollreactor
    32.8 -pollreactor.install()
    32.9 -
   32.10 -from twisted.internet import reactor
   32.11 -from twisted.internet import protocol
   32.12 -from twisted.internet import abstract
   32.13 -from twisted.internet import defer
   32.14 -
   32.15  from xen.lowlevel import xu
   32.16  
   32.17  from xen.xend import sxp
   32.18  from xen.xend import PrettyPrint
   32.19 -from xen.xend import EventServer
   32.20 -eserver = EventServer.instance()
   32.21 +from xen.xend import EventServer; eserver = EventServer.instance()
   32.22  from xen.xend.XendError import XendError
   32.23  from xen.xend.server import SrvServer
   32.24  from xen.xend import XendRoot
   32.25 @@ -39,300 +30,22 @@ from xen.xend.XendLogging import log
   32.26  from xen.util.ip import _readline, _readlines
   32.27  
   32.28  import channel
   32.29 -import blkif
   32.30 -import netif
   32.31 -import usbif
   32.32 -import console
   32.33 -import domain
   32.34 +import controller
   32.35 +import event
   32.36  from params import *
   32.37  
   32.38 -DAEMONIZE = 1
   32.39 +DAEMONIZE = 0
   32.40  DEBUG = 1
   32.41  
   32.42 -class NotifierProtocol(protocol.Protocol):
   32.43 -    """Asynchronous handler for i/o on the notifier (event channel).
   32.44 -    """
   32.45 -
   32.46 -    def __init__(self, channelFactory):
   32.47 -        self.channelFactory = channelFactory
   32.48 -
   32.49 -    def notificationReceived(self, idx):
   32.50 -        channel = self.channelFactory.getChannel(idx)
   32.51 -        if channel:
   32.52 -            channel.notificationReceived()
   32.53 -
   32.54 -    def connectionLost(self, reason=None):
   32.55 -        pass
   32.56 -
   32.57 -    def doStart(self):
   32.58 -        pass
   32.59 -
   32.60 -    def doStop(self):
   32.61 -        pass
   32.62 -
   32.63 -    def startProtocol(self):
   32.64 -        pass
   32.65 -
   32.66 -    def stopProtocol(self):
   32.67 -        pass
   32.68 -
   32.69 -class NotifierPort(abstract.FileDescriptor):
   32.70 -    """Transport class for the event channel.
   32.71 -    """
   32.72 -
   32.73 -    def __init__(self, daemon, notifier, proto, reactor=None):
   32.74 -        assert isinstance(proto, NotifierProtocol)
   32.75 -        abstract.FileDescriptor.__init__(self, reactor)
   32.76 -        self.daemon = daemon
   32.77 -        self.notifier = notifier
   32.78 -        self.protocol = proto
   32.79 -
   32.80 -    def startListening(self):
   32.81 -        self._bindNotifier()
   32.82 -        self._connectToProtocol()
   32.83 -
   32.84 -    def stopListening(self):
   32.85 -        if self.connected:
   32.86 -            result = self.d = defer.Deferred()
   32.87 -        else:
   32.88 -            result = None
   32.89 -        self.loseConnection()
   32.90 -        return result
   32.91 -
   32.92 -    def fileno(self):
   32.93 -        return self.notifier.fileno()
   32.94 -
   32.95 -    def _bindNotifier(self):
   32.96 -        self.connected = 1
   32.97 -
   32.98 -    def _connectToProtocol(self):
   32.99 -        self.protocol.makeConnection(self)
  32.100 -        self.startReading()
  32.101 -
  32.102 -    def loseConnection(self):
  32.103 -        if self.connected:
  32.104 -            self.stopReading()
  32.105 -            self.disconnecting = 1
  32.106 -            reactor.callLater(0, self.connectionLost)
  32.107 -
  32.108 -    def connectionLost(self, reason=None):
  32.109 -        abstract.FileDescriptor.connectionLost(self, reason)
  32.110 -        if hasattr(self, 'protocol'):
  32.111 -            self.protocol.doStop()
  32.112 -        self.connected = 0
  32.113 -        #self.notifier.close()   # (this said:) Not implemented.
  32.114 -        #os.close(self.fileno()) # But yes it is...
  32.115 -        del self.notifier        # ...as _dealloc!
  32.116 -        if hasattr(self, 'd'):
  32.117 -            self.d.callback(None)
  32.118 -            del self.d
  32.119 -        
  32.120 -    def doRead(self):
  32.121 -        count = 0
  32.122 -        while 1:            
  32.123 -            notification = self.notifier.read()
  32.124 -            if not notification:
  32.125 -                break
  32.126 -            self.protocol.notificationReceived(notification)
  32.127 -            self.notifier.unmask(notification)
  32.128 -            count += 1
  32.129 -
  32.130 -class EventProtocol(protocol.Protocol):
  32.131 -    """Asynchronous handler for a connected event socket.
  32.132 -    """
  32.133 -
  32.134 -    def __init__(self, daemon):
  32.135 -        #protocol.Protocol.__init__(self)
  32.136 -        self.daemon = daemon
  32.137 -        # Event queue.
  32.138 -        self.queue = []
  32.139 -        # Subscribed events.
  32.140 -        self.events = []
  32.141 -        self.parser = sxp.Parser()
  32.142 -        self.pretty = 0
  32.143 -
  32.144 -        # For debugging subscribe to everything and make output pretty.
  32.145 -        self.subscribe(['*'])
  32.146 -        self.pretty = 1
  32.147 -
  32.148 -    def dataReceived(self, data):
  32.149 -        try:
  32.150 -            self.parser.input(data)
  32.151 -            if self.parser.ready():
  32.152 -                val = self.parser.get_val()
  32.153 -                res = self.dispatch(val)
  32.154 -                self.send_result(res)
  32.155 -            if self.parser.at_eof():
  32.156 -                self.loseConnection()
  32.157 -        except SystemExit:
  32.158 -            raise
  32.159 -        except:
  32.160 -            if DEBUG:
  32.161 -                raise
  32.162 -            else:
  32.163 -                self.send_error()
  32.164 -
  32.165 -    def loseConnection(self):
  32.166 -        if self.transport:
  32.167 -            self.transport.loseConnection()
  32.168 -        if self.connected:
  32.169 -            reactor.callLater(0, self.connectionLost)
  32.170 -
  32.171 -    def connectionLost(self, reason=None):
  32.172 -        self.unsubscribe()
  32.173 -
  32.174 -    def send_reply(self, sxpr):
  32.175 -        io = StringIO.StringIO()
  32.176 -        if self.pretty:
  32.177 -            PrettyPrint.prettyprint(sxpr, out=io)
  32.178 -        else:
  32.179 -            sxp.show(sxpr, out=io)
  32.180 -        print >> io
  32.181 -        io.seek(0)
  32.182 -        return self.transport.write(io.getvalue())
  32.183 -
  32.184 -    def send_result(self, res):
  32.185 -        return self.send_reply(['ok', res])
  32.186 -
  32.187 -    def send_error(self):
  32.188 -        (extype, exval) = sys.exc_info()[:2]
  32.189 -        return self.send_reply(['err',
  32.190 -                                ['type', str(extype)],
  32.191 -                                ['value', str(exval)]])
  32.192 -
  32.193 -    def send_event(self, val):
  32.194 -        return self.send_reply(['event', val[0], val[1]])
  32.195 -
  32.196 -    def unsubscribe(self):
  32.197 -        for event in self.events:
  32.198 -            eserver.unsubscribe(event, self.queue_event)
  32.199 -
  32.200 -    def subscribe(self, events):
  32.201 -        self.unsubscribe()
  32.202 -        for event in events:
  32.203 -            eserver.subscribe(event, self.queue_event)
  32.204 -        self.events = events
  32.205 -
  32.206 -    def queue_event(self, name, v):
  32.207 -        # Despite the name we don't queue the event here.
  32.208 -        # We send it because the transport will queue it.
  32.209 -        self.send_event([name, v])
  32.210 -        
  32.211 -    def opname(self, name):
  32.212 -         return 'op_' + name.replace('.', '_')
  32.213 -
  32.214 -    def operror(self, name, req):
  32.215 -        raise XendError('Invalid operation: ' +name)
  32.216 -
  32.217 -    def dispatch(self, req):
  32.218 -        op_name = sxp.name(req)
  32.219 -        op_method_name = self.opname(op_name)
  32.220 -        op_method = getattr(self, op_method_name, self.operror)
  32.221 -        return op_method(op_name, req)
  32.222 -
  32.223 -    def op_help(self, name, req):
  32.224 -        def nameop(x):
  32.225 -            if x.startswith('op_'):
  32.226 -                return x[3:].replace('_', '.')
  32.227 -            else:
  32.228 -                return x
  32.229 -        
  32.230 -        l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
  32.231 -        return l
  32.232 -
  32.233 -    def op_quit(self, name, req):
  32.234 -        self.loseConnection()
  32.235 -
  32.236 -    def op_exit(self, name, req):
  32.237 -        sys.exit(0)
  32.238 -
  32.239 -    def op_pretty(self, name, req):
  32.240 -        self.pretty = 1
  32.241 -        return ['ok']
  32.242 -
  32.243 -    def op_console_disconnect(self, name, req):
  32.244 -        id = sxp.child_value(req, 'id')
  32.245 -        if not id:
  32.246 -            raise XendError('Missing console id')
  32.247 -        id = int(id)
  32.248 -        self.daemon.console_disconnect(id)
  32.249 -        return ['ok']
  32.250 -
  32.251 -    def op_info(self, name, req):
  32.252 -        val = ['info']
  32.253 -        val += self.daemon.consoles()
  32.254 -        val += self.daemon.blkifs()
  32.255 -        val += self.daemon.netifs()
  32.256 -        val += self.daemon.usbifs()
  32.257 -        return val
  32.258 -
  32.259 -    def op_sys_subscribe(self, name, v):
  32.260 -        # (sys.subscribe event*)
  32.261 -        # Subscribe to the events:
  32.262 -        self.subscribe(v[1:])
  32.263 -        return ['ok']
  32.264 -
  32.265 -    def op_sys_inject(self, name, v):
  32.266 -        # (sys.inject event)
  32.267 -        event = v[1]
  32.268 -        eserver.inject(sxp.name(event), event)
  32.269 -        return ['ok']
  32.270 -
  32.271 -    def op_trace(self, name, v):
  32.272 -        mode = (v[1] == 'on')
  32.273 -        self.daemon.tracing(mode)
  32.274 -
  32.275 -    def op_log_stderr(self, name, v):
  32.276 -        mode = v[1]
  32.277 -        logging = XendRoot.instance().get_logging()
  32.278 -        if mode == 'on':
  32.279 -            logging.addLogStderr()
  32.280 -        else:
  32.281 -            logging.removeLogStderr()
  32.282 -
  32.283 -    def op_debug_msg(self, name, v):
  32.284 -        mode = v[1]
  32.285 -        import messages
  32.286 -        messages.DEBUG = (mode == 'on')
  32.287 -
  32.288 -    def op_debug_controller(self, name, v):
  32.289 -        mode = v[1]
  32.290 -        import controller
  32.291 -        controller.DEBUG = (mode == 'on')
  32.292 -
  32.293 -
  32.294 -class EventFactory(protocol.Factory):
  32.295 -    """Asynchronous handler for the event server socket.
  32.296 -    """
  32.297 -    protocol = EventProtocol
  32.298 -    service = None
  32.299 -
  32.300 -    def __init__(self, daemon):
  32.301 -        #protocol.Factory.__init__(self)
  32.302 -        self.daemon = daemon
  32.303 -
  32.304 -    def buildProtocol(self, addr):
  32.305 -        proto = self.protocol(self.daemon)
  32.306 -        proto.factory = self
  32.307 -        return proto
  32.308 -
  32.309 -class VirqClient:
  32.310 -    def __init__(self, daemon):
  32.311 -        self.daemon = daemon
  32.312 -
  32.313 -    def virqReceived(self, virq):
  32.314 -        print 'VirqClient.virqReceived>', virq
  32.315 -        eserver.inject('xend.virq', virq)
  32.316 -
  32.317 -    def lostChannel(self, channel):
  32.318 -        print 'VirqClient.lostChannel>', channel
  32.319 -        
  32.320  class Daemon:
  32.321      """The xend daemon.
  32.322      """
  32.323      def __init__(self):
  32.324 +        self.channelF = None
  32.325          self.shutdown = 0
  32.326          self.traceon = 0
  32.327 +        self.tracefile = None
  32.328 +        self.traceindent = 0
  32.329  
  32.330      def daemon_pids(self):
  32.331          pids = []
  32.332 @@ -469,6 +182,7 @@ class Daemon:
  32.333              pass
  32.334          else:
  32.335              # Child
  32.336 +            self.daemonize()
  32.337              os.execl("/usr/sbin/xfrd", "xfrd")
  32.338  
  32.339      def daemonize(self):
  32.340 @@ -504,8 +218,6 @@ class Daemon:
  32.341          xfrd_pid = self.cleanup_xfrd()
  32.342  
  32.343  
  32.344 -        self.daemonize()
  32.345 -        
  32.346          if self.set_user():
  32.347              return 4
  32.348          os.chdir("/")
  32.349 @@ -608,146 +320,45 @@ class Daemon:
  32.350          return self.cleanup(kill=True)
  32.351  
  32.352      def run(self):
  32.353 -        xroot = XendRoot.instance()
  32.354 -        log.info("Xend Daemon started")
  32.355 -        self.createFactories()
  32.356 -        self.listenEvent(xroot)
  32.357 -        self.listenNotifier()
  32.358 -        self.listenVirq()
  32.359 -        SrvServer.create(bridge=1)
  32.360 -        reactor.run()
  32.361 -
  32.362 +        try:
  32.363 +            xroot = XendRoot.instance()
  32.364 +            log.info("Xend Daemon started")
  32.365 +            self.createFactories()
  32.366 +            event.listenEvent(self)
  32.367 +            self.listenChannels()
  32.368 +            servers = SrvServer.create()
  32.369 +            self.daemonize()
  32.370 +            print 'running serverthread...'
  32.371 +            servers.start()
  32.372 +        except Exception, ex:
  32.373 +            print >>sys.stderr, 'Exception starting xend:', ex
  32.374 +            if DEBUG:
  32.375 +                traceback.print_exc()
  32.376 +            log.exception("Exception starting xend")
  32.377 +            self.exit(1)
  32.378 +            
  32.379      def createFactories(self):
  32.380          self.channelF = channel.channelFactory()
  32.381 -        self.domainCF = domain.DomainControllerFactory()
  32.382 -        self.blkifCF = blkif.BlkifControllerFactory()
  32.383 -        self.netifCF = netif.NetifControllerFactory()
  32.384 -        self.usbifCF = usbif.UsbifControllerFactory()
  32.385 -        self.consoleCF = console.ConsoleControllerFactory()
  32.386 -
  32.387 -    def listenEvent(self, xroot):
  32.388 -        protocol = EventFactory(self)
  32.389 -        port = xroot.get_xend_event_port()
  32.390 -        interface = xroot.get_xend_address()
  32.391 -        return reactor.listenTCP(port, protocol, interface=interface)
  32.392 -
  32.393 -    def listenNotifier(self):
  32.394 -        protocol = NotifierProtocol(self.channelF)
  32.395 -        p = NotifierPort(self, self.channelF.notifier, protocol, reactor)
  32.396 -        p.startListening()
  32.397 -        return p
  32.398 -
  32.399 -    def listenVirq(self):
  32.400 -        virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC)
  32.401 -        virqChan.registerClient(VirqClient(self))
  32.402 -
  32.403 -    def exit(self):
  32.404 -        reactor.disconnectAll()
  32.405 -        sys.exit(0)
  32.406 -
  32.407 -    def getDomChannel(self, dom):
  32.408 -        """Get the channel to a domain.
  32.409  
  32.410 -        @param dom: domain
  32.411 -        @return: channel (or None)
  32.412 -        """
  32.413 -        return self.channelF.getDomChannel(dom)
  32.414 -
  32.415 -    def createDomChannel(self, dom, local_port=0, remote_port=0):
  32.416 -        """Get the channel to a domain, creating if necessary.
  32.417 +    def listenChannels(self):
  32.418 +        def virqReceived(virq):
  32.419 +            print 'virqReceived>', virq
  32.420 +            eserver.inject('xend.virq', virq)
  32.421  
  32.422 -        @param dom: domain
  32.423 -        @param local_port: optional local port to re-use
  32.424 -        @param remote_port: optional remote port to re-use
  32.425 -        @return: channel
  32.426 -        """
  32.427 -        return self.channelF.domChannel(dom, local_port=local_port,
  32.428 -                                        remote_port=remote_port)
  32.429 -
  32.430 -    def blkif_create(self, dom, recreate=0):
  32.431 -        """Create or get a block device interface controller.
  32.432 -        
  32.433 -        Returns controller
  32.434 -        """
  32.435 -        blkif = self.blkifCF.getController(dom)
  32.436 -        blkif.daemon = self
  32.437 -        return blkif
  32.438 -
  32.439 -    def blkifs(self):
  32.440 -        return [ x.sxpr() for x in self.blkifCF.getControllers() ]
  32.441 -
  32.442 -    def blkif_get(self, dom):
  32.443 -        return self.blkifCF.getControllerByDom(dom)
  32.444 +        self.channelF.setVirqHandler(virqReceived)
  32.445 +        self.channelF.start()
  32.446  
  32.447 -    def netif_create(self, dom, recreate=0):
  32.448 -        """Create or get a network interface controller.
  32.449 -        
  32.450 -        """
  32.451 -        return self.netifCF.getController(dom)
  32.452 -
  32.453 -    def netifs(self):
  32.454 -        return [ x.sxpr() for x in self.netifCF.getControllers() ]
  32.455 -
  32.456 -    def netif_get(self, dom):
  32.457 -        return self.netifCF.getControllerByDom(dom)
  32.458 -
  32.459 -    def usbif_create(self, dom, recreate=0):
  32.460 -        return self.usbifCF.getController(dom)
  32.461 -    
  32.462 -    def usbifs(self):
  32.463 -        return [ x.sxpr() for x in self.usbifCF.getControllers() ]
  32.464 -
  32.465 -    def usbif_get(self, dom):
  32.466 -        return self.usbifCF.getControllerByDom(dom)
  32.467 -
  32.468 -    def console_create(self, dom, console_port=None):
  32.469 -        """Create a console for a domain.
  32.470 -        """
  32.471 -        console = self.consoleCF.getControllerByDom(dom)
  32.472 -        if console is None:
  32.473 -            console = self.consoleCF.createController(dom, console_port)
  32.474 -        return console
  32.475 -
  32.476 -    def consoles(self):
  32.477 -        return [ c.sxpr() for c in self.consoleCF.getControllers() ]
  32.478 -
  32.479 -    def get_consoles(self):
  32.480 -        return self.consoleCF.getControllers()
  32.481 +    def exit(self, rc=0):
  32.482 +        #reactor.disconnectAll()
  32.483 +        if self.channelF:
  32.484 +            self.channelF.stop()
  32.485 +        # Calling sys.exit() raises a SystemExit exception, which only
  32.486 +        # kills the current thread. Calling os._exit() makes the whole
  32.487 +        # Python process exit immediately. There doesn't seem to be another
  32.488 +        # way to exit a Python with running threads.
  32.489 +        #sys.exit(rc)
  32.490 +        os._exit(rc)
  32.491  
  32.492 -    def get_console(self, id):
  32.493 -        return self.consoleCF.getControllerByIndex(id)
  32.494 -
  32.495 -    def get_domain_console(self, dom):
  32.496 -        return self.consoleCF.getControllerByDom(dom)
  32.497 -
  32.498 -    def console_disconnect(self, id):
  32.499 -        """Disconnect any connected console client.
  32.500 -        """
  32.501 -        console = self.get_console(id)
  32.502 -        if not console:
  32.503 -            raise XendError('Invalid console id')
  32.504 -        console.disconnect()
  32.505 -
  32.506 -    def domain_shutdown(self, dom, reason, key=0):
  32.507 -        """Shutdown a domain.
  32.508 -        """
  32.509 -        dom = int(dom)
  32.510 -        ctrl = self.domainCF.getController(dom)
  32.511 -        if not ctrl:
  32.512 -            raise XendError('No domain controller: %s' % dom)
  32.513 -        ctrl.shutdown(reason, key)
  32.514 -        return 0
  32.515 -
  32.516 -    def domain_mem_target_set(self, dom, target):
  32.517 -        """Set memory target for a domain.
  32.518 -        """
  32.519 -        dom = int(dom)
  32.520 -        ctrl = self.domainCF.getController(dom)
  32.521 -        if not ctrl:
  32.522 -            raise XendError('No domain controller: %s' % dom)
  32.523 -        ctrl.mem_target_set(target)
  32.524 -        return 0
  32.525 -        
  32.526  def instance():
  32.527      global inst
  32.528      try:
    33.1 --- a/tools/python/xen/xend/server/SrvDeviceDir.py	Thu Apr 28 08:56:40 2005 +0000
    33.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.3 @@ -1,9 +0,0 @@
    33.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    33.5 -
    33.6 -from SrvDir import SrvDir
    33.7 -
    33.8 -class SrvDeviceDir(SrvDir):
    33.9 -    """Device directory.
   33.10 -    """
   33.11 -
   33.12 -    pass
    34.1 --- a/tools/python/xen/xend/server/SrvDir.py	Thu Apr 28 08:56:40 2005 +0000
    34.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.3 @@ -1,111 +0,0 @@
    34.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    34.5 -
    34.6 -from twisted.protocols import http
    34.7 -from twisted.web import error
    34.8 -
    34.9 -from xen.xend import sxp
   34.10 -from xen.xend.XendError import XendError
   34.11 -
   34.12 -from SrvBase import SrvBase
   34.13 -
   34.14 -class SrvError(error.ErrorPage):
   34.15 -
   34.16 -    def render(self, request):
   34.17 -        val = error.ErrorPage.render(self, request)
   34.18 -        request.setResponseCode(self.code, self.brief)
   34.19 -        return val
   34.20 -
   34.21 -class SrvConstructor:
   34.22 -    """Delayed constructor for sub-servers.
   34.23 -    Does not import the sub-server class or create the object until needed.
   34.24 -    """
   34.25 -    
   34.26 -    def __init__(self, klass):
   34.27 -        """Create a constructor. It is assumed that the class
   34.28 -        should be imported as 'import klass from klass'.
   34.29 -
   34.30 -        klass	name of its class
   34.31 -        """
   34.32 -        self.klass = klass
   34.33 -        self.obj = None
   34.34 -
   34.35 -    def getobj(self):
   34.36 -        """Get the sub-server object, importing its class and instantiating it if
   34.37 -        necessary.
   34.38 -        """
   34.39 -        if not self.obj:
   34.40 -            exec 'from %s import %s' % (self.klass, self.klass)
   34.41 -            klassobj = eval(self.klass)
   34.42 -            self.obj = klassobj()
   34.43 -        return self.obj
   34.44 -
   34.45 -class SrvDir(SrvBase):
   34.46 -    """Base class for directory servlets.
   34.47 -    """
   34.48 -    isLeaf = False
   34.49 -    
   34.50 -    def __init__(self):
   34.51 -        SrvBase.__init__(self)
   34.52 -        self.table = {}
   34.53 -        self.order = []
   34.54 -
   34.55 -    def noChild(self, msg):
   34.56 -        return SrvError(http.NOT_FOUND, msg, msg)
   34.57 -
   34.58 -    def getChild(self, x, req):
   34.59 -        if x == '': return self
   34.60 -        try:
   34.61 -            val = self.get(x)
   34.62 -        except XendError, ex:
   34.63 -            return self.noChild(str(ex))
   34.64 -        if val is None:
   34.65 -            return self.noChild('Not found ' + str(x))
   34.66 -        else:
   34.67 -            return val
   34.68 -
   34.69 -    def get(self, x):
   34.70 -        val = self.table.get(x)
   34.71 -        if val is not None:
   34.72 -            val = val.getobj()
   34.73 -        return val
   34.74 -
   34.75 -    def add(self, x, xclass = None):
   34.76 -        if xclass is None:
   34.77 -            xclass = 'SrvDir'
   34.78 -        self.table[x] = SrvConstructor(xclass)
   34.79 -        self.order.append(x)
   34.80 -
   34.81 -    def render_GET(self, req):
   34.82 -        try:
   34.83 -            if self.use_sxp(req):
   34.84 -                req.setHeader("Content-type", sxp.mime_type)
   34.85 -                self.ls(req, 1)
   34.86 -            else:
   34.87 -                req.write('<html><head></head><body>')
   34.88 -                self.print_path(req)
   34.89 -                self.ls(req)
   34.90 -                self.form(req)
   34.91 -                req.write('</body></html>')
   34.92 -            return ''
   34.93 -        except Exception, ex:
   34.94 -            self._perform_err(ex, "GET", req)
   34.95 -            
   34.96 -    def ls(self, req, use_sxp=0):
   34.97 -        url = req.prePathURL()
   34.98 -        if not url.endswith('/'):
   34.99 -            url += '/'
  34.100 -        if use_sxp:
  34.101 -           req.write('(ls ')
  34.102 -           for k in self.order:
  34.103 -               req.write(' ' + k)
  34.104 -           req.write(')')
  34.105 -        else:
  34.106 -            req.write('<ul>')
  34.107 -            for k in self.order:
  34.108 -                v = self.get(k)
  34.109 -                req.write('<li><a href="%s%s">%s</a></li>'
  34.110 -                          % (url, k, k))
  34.111 -            req.write('</ul>')
  34.112 -
  34.113 -    def form(self, req):
  34.114 -        pass
    35.1 --- a/tools/python/xen/xend/server/SrvDmesg.py	Thu Apr 28 08:56:40 2005 +0000
    35.2 +++ b/tools/python/xen/xend/server/SrvDmesg.py	Thu Apr 28 10:46:53 2005 +0000
    35.3 @@ -5,7 +5,7 @@ import os
    35.4  from xen.xend import sxp
    35.5  from xen.xend import XendDmesg
    35.6  
    35.7 -from SrvDir import SrvDir
    35.8 +from xen.web.SrvDir import SrvDir
    35.9  
   35.10  class SrvDmesg(SrvDir):
   35.11      """Xen Dmesg output.
   35.12 @@ -19,19 +19,15 @@ class SrvDmesg(SrvDir):
   35.13          self.perform(req)
   35.14  
   35.15      def render_GET(self, req):
   35.16 -        try:
   35.17 -            if self.use_sxp(req):
   35.18 -                req.setHeader("Content-Type", "text/plain")
   35.19 -                req.write(self.info())
   35.20 -            else:
   35.21 -                req.write('<html><head></head><body>')
   35.22 -                self.print_path(req)
   35.23 -                req.write('<pre>')
   35.24 -                req.write(self.info())
   35.25 -                req.write('</pre></body></html>')
   35.26 -            return ''
   35.27 -        except Exception, ex:
   35.28 -            self._perform_err(ex, req)
   35.29 +        if self.use_sxp(req):
   35.30 +            req.setHeader("Content-Type", "text/plain")
   35.31 +            req.write(self.info())
   35.32 +        else:
   35.33 +            req.write('<html><head></head><body>')
   35.34 +            self.print_path(req)
   35.35 +            req.write('<pre>')
   35.36 +            req.write(self.info())
   35.37 +            req.write('</pre></body></html>')
   35.38              
   35.39      def info(self):
   35.40          return self.xd.info()
    36.1 --- a/tools/python/xen/xend/server/SrvDomain.py	Thu Apr 28 08:56:40 2005 +0000
    36.2 +++ b/tools/python/xen/xend/server/SrvDomain.py	Thu Apr 28 10:46:53 2005 +0000
    36.3 @@ -1,6 +1,6 @@
    36.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    36.5  
    36.6 -from twisted.protocols import http
    36.7 +from xen.web import http
    36.8  
    36.9  from xen.xend import sxp
   36.10  from xen.xend import XendDomain
   36.11 @@ -8,7 +8,7 @@ from xen.xend import XendConsole
   36.12  from xen.xend import PrettyPrint
   36.13  from xen.xend.Args import FormFn
   36.14  
   36.15 -from SrvDir import SrvDir
   36.16 +from xen.web.SrvDir import SrvDir
   36.17  
   36.18  class SrvDomain(SrvDir):
   36.19      """Service managing a single domain.
   36.20 @@ -26,10 +26,9 @@ class SrvDomain(SrvDir):
   36.21          not a domain name.
   36.22          """
   36.23          fn = FormFn(self.xd.domain_configure,
   36.24 -                    [['dom', 'int'],
   36.25 +                    [['dom',    'int'],
   36.26                       ['config', 'sxpr']])
   36.27 -        deferred = fn(req.args, {'dom': self.dom.dom})
   36.28 -        return deferred
   36.29 +        return fn(req.args, {'dom': self.dom.dom})
   36.30  
   36.31      def op_unpause(self, op, req):
   36.32          val = self.xd.domain_unpause(self.dom.name)
   36.33 @@ -41,9 +40,9 @@ class SrvDomain(SrvDir):
   36.34  
   36.35      def op_shutdown(self, op, req):
   36.36          fn = FormFn(self.xd.domain_shutdown,
   36.37 -                    [['dom', 'str'],
   36.38 +                    [['dom',    'str'],
   36.39                       ['reason', 'str'],
   36.40 -                     ['key', 'int']])
   36.41 +                     ['key',    'int']])
   36.42          val = fn(req.args, {'dom': self.dom.id})
   36.43          req.setResponseCode(http.ACCEPTED)
   36.44          req.setHeader("Location", "%s/.." % req.prePathURL())
   36.45 @@ -51,42 +50,39 @@ class SrvDomain(SrvDir):
   36.46  
   36.47      def op_destroy(self, op, req):
   36.48          fn = FormFn(self.xd.domain_destroy,
   36.49 -                    [['dom', 'str'],
   36.50 +                    [['dom',    'str'],
   36.51                       ['reason', 'str']])
   36.52          val = fn(req.args, {'dom': self.dom.id})
   36.53          req.setHeader("Location", "%s/.." % req.prePathURL())
   36.54          return val
   36.55  
   36.56      def op_save(self, op, req):
   36.57 +        return req.threadRequest(self.do_save, op, req)
   36.58 +
   36.59 +    def do_save(self, op, req):
   36.60          fn = FormFn(self.xd.domain_save,
   36.61 -                    [['dom', 'str'],
   36.62 +                    [['dom',  'str'],
   36.63                       ['file', 'str']])
   36.64 -        deferred = fn(req.args, {'dom': self.dom.id})
   36.65 -        deferred.addCallback(self._op_save_cb, req)
   36.66 -        return deferred
   36.67 -
   36.68 -    def _op_save_cb(self, val, req):
   36.69 +        val = fn(req.args, {'dom': self.dom.id})
   36.70          return 0
   36.71  
   36.72      def op_migrate(self, op, req):
   36.73 +        return req.threadRequest(self.do_migrate, op, req)
   36.74 +    
   36.75 +    def do_migrate(self, op, req):
   36.76          fn = FormFn(self.xd.domain_migrate,
   36.77 -                    [['dom', 'str'],
   36.78 +                    [['dom',         'str'],
   36.79                       ['destination', 'str'],
   36.80 -                     ['live', 'int'],
   36.81 -                     ['resource', 'int']])
   36.82 -        deferred = fn(req.args, {'dom': self.dom.id})
   36.83 -        deferred.addCallback(self._op_migrate_cb, req)
   36.84 -        return deferred
   36.85 -
   36.86 -    def _op_migrate_cb(self, info, req):
   36.87 -        print '_op_migrate_cb>', info, req
   36.88 +                     ['live',        'int'],
   36.89 +                     ['resource',    'int']])
   36.90 +        info = fn(req.args, {'dom': self.dom.id})
   36.91          #req.setResponseCode(http.ACCEPTED)
   36.92          host = info.dst_host
   36.93          port = info.dst_port
   36.94          dom  = info.dst_dom
   36.95          url = "http://%s:%d/xend/domain/%d" % (host, port, dom)
   36.96          req.setHeader("Location", url)
   36.97 -        print '_op_migrate_cb> url=', url
   36.98 +        print 'do_migrate> url=', url
   36.99          return url
  36.100  
  36.101      def op_pincpu(self, op, req):
  36.102 @@ -98,88 +94,84 @@ class SrvDomain(SrvDir):
  36.103  
  36.104      def op_cpu_bvt_set(self, op, req):
  36.105          fn = FormFn(self.xd.domain_cpu_bvt_set,
  36.106 -                    [['dom', 'str'],
  36.107 -                     ['mcuadv', 'int'],
  36.108 -                     ['warpback', 'int'],
  36.109 +                    [['dom',       'str'],
  36.110 +                     ['mcuadv',    'int'],
  36.111 +                     ['warpback',  'int'],
  36.112                       ['warpvalue', 'int'],
  36.113 -                     ['warpl', 'long'],
  36.114 -                     ['warpu', 'long']])
  36.115 +                     ['warpl',     'long'],
  36.116 +                     ['warpu',     'long']])
  36.117          val = fn(req.args, {'dom': self.dom.id})
  36.118          return val
  36.119      
  36.120      def op_maxmem_set(self, op, req):
  36.121          fn = FormFn(self.xd.domain_maxmem_set,
  36.122 -                    [['dom', 'str'],
  36.123 +                    [['dom',    'str'],
  36.124                       ['memory', 'int']])
  36.125          val = fn(req.args, {'dom': self.dom.id})
  36.126          return val
  36.127 +    
  36.128 +    def op_mem_target_set(self, op, req):
  36.129 +        fn = FormFn(self.xd.domain_mem_target_set,
  36.130 +                    [['dom',    'str'],
  36.131 +                     ['target', 'int']])
  36.132 +        val = fn(req.args, {'dom': self.dom.id})
  36.133 +        return val
  36.134 +
  36.135 +    def op_devices(self, op, req):
  36.136 +        fn = FormFn(self.xd.domain_devtype_ls,
  36.137 +                    [['dom',    'str'],
  36.138 +                     ['type',   'str']])
  36.139 +        val = fn(req.args, {'dom': self.dom.id})
  36.140 +        return val
  36.141 +
  36.142 +    def op_device(self, op, req):
  36.143 +        fn = FormFn(self.xd.domain_devtype_get,
  36.144 +                    [['dom',    'str'],
  36.145 +                     ['type',   'str'],
  36.146 +                     ['idx',    'int']])
  36.147 +        val = fn(req.args, {'dom': self.dom.id})
  36.148 +        if val:
  36.149 +            return val.sxpr()
  36.150 +        else:
  36.151 +            raise XendError("invalid device")
  36.152  
  36.153      def op_device_create(self, op, req):
  36.154          fn = FormFn(self.xd.domain_device_create,
  36.155 -                    [['dom', 'str'],
  36.156 +                    [['dom',    'str'],
  36.157                       ['config', 'sxpr']])
  36.158 -        d = fn(req.args, {'dom': self.dom.id})
  36.159 -        return d
  36.160 +        val = fn(req.args, {'dom': self.dom.id})
  36.161 +        return val
  36.162  
  36.163      def op_device_refresh(self, op, req):
  36.164          fn = FormFn(self.xd.domain_device_refresh,
  36.165 -                    [['dom', 'str'],
  36.166 +                    [['dom',  'str'],
  36.167                       ['type', 'str'],
  36.168 -                     ['idx', 'str']])
  36.169 +                     ['idx',  'str']])
  36.170          val = fn(req.args, {'dom': self.dom.id})
  36.171          return val
  36.172  
  36.173      def op_device_destroy(self, op, req):
  36.174          fn = FormFn(self.xd.domain_device_destroy,
  36.175 -                    [['dom', 'str'],
  36.176 +                    [['dom',  'str'],
  36.177                       ['type', 'str'],
  36.178 -                     ['idx', 'str']])
  36.179 +                     ['idx',  'str']])
  36.180          val = fn(req.args, {'dom': self.dom.id})
  36.181          return val
  36.182                  
  36.183      def op_device_configure(self, op, req):
  36.184          fn = FormFn(self.xd.domain_device_configure,
  36.185 -                    [['dom', 'str'],
  36.186 +                    [['dom',    'str'],
  36.187                       ['config', 'sxpr'],
  36.188 -                     ['idx', 'str']])
  36.189 -        d = fn(req.args, {'dom': self.dom.id})
  36.190 -        return d
  36.191 -
  36.192 -    def op_vif_credit_limit(self, op, req):
  36.193 -        fn = FormFn(self.xd.domain_vif_credit_limit,
  36.194 -                    [['dom', 'str'],
  36.195 -                     ['vif', 'int'],
  36.196 -                     ['credit', 'int'],
  36.197 -                     ['period', 'int']])
  36.198 +                     ['idx',    'str']])
  36.199          val = fn(req.args, {'dom': self.dom.id})
  36.200          return val
  36.201  
  36.202 -    def op_vifs(self, op, req):
  36.203 -        devs = self.xd.domain_vif_ls(self.dom.id)
  36.204 -        return [ dev.sxpr() for dev in devs ]
  36.205 -
  36.206 -    def op_vif(self, op, req):
  36.207 -        fn = FormFn(self.xd.domain_vif_get,
  36.208 -                    [['dom', 'str'],
  36.209 -                     ['vif', 'str']])
  36.210 -        val = fn(req.args, {'dom': self.dom.id})
  36.211 -        return val
  36.212 -
  36.213 -    def op_vbds(self, op, req):
  36.214 -        devs = self.xd.domain_vbd_ls(self.dom.id)
  36.215 -        return [ dev.sxpr() for dev in devs ]
  36.216 -
  36.217 -    def op_vbd(self, op, req):
  36.218 -        fn = FormFn(self.xd.domain_vbd_get,
  36.219 -                    [['dom', 'str'],
  36.220 -                     ['vbd', 'str']])
  36.221 -        val = fn(req.args, {'dom': self.dom.id})
  36.222 -        return val
  36.223 -
  36.224 -    def op_mem_target_set(self, op, req):
  36.225 -        fn = FormFn(self.xd.domain_mem_target_set,
  36.226 -                    [['dom', 'str'],
  36.227 -                     ['target', 'int']])
  36.228 +    def op_vif_limit_set(self, op, req):
  36.229 +        fn = FormFn(self.xd.domain_vif_limit_set,
  36.230 +                    [['dom',    'str'],
  36.231 +                     ['vif',    'int'],
  36.232 +                     ['credit', 'int'],
  36.233 +                     ['period', 'int']])
  36.234          val = fn(req.args, {'dom': self.dom.id})
  36.235          return val
  36.236  
    37.1 --- a/tools/python/xen/xend/server/SrvDomainDir.py	Thu Apr 28 08:56:40 2005 +0000
    37.2 +++ b/tools/python/xen/xend/server/SrvDomainDir.py	Thu Apr 28 10:46:53 2005 +0000
    37.3 @@ -3,9 +3,7 @@
    37.4  import traceback
    37.5  from StringIO import StringIO
    37.6  
    37.7 -from twisted.protocols import http
    37.8 -from twisted.web import error
    37.9 -from twisted.python.failure import Failure
   37.10 +from xen.web import http
   37.11  
   37.12  from xen.xend import sxp
   37.13  from xen.xend import XendDomain
   37.14 @@ -13,7 +11,7 @@ from xen.xend.Args import FormFn
   37.15  from xen.xend.XendError import XendError
   37.16  from xen.xend.XendLogging import log
   37.17  
   37.18 -from SrvDir import SrvDir
   37.19 +from xen.web.SrvDir import SrvDir
   37.20  from SrvDomain import SrvDomain
   37.21  
   37.22  class SrvDomainDir(SrvDir):
   37.23 @@ -62,16 +60,15 @@ class SrvDomainDir(SrvDir):
   37.24          if not ok:
   37.25              raise XendError(errmsg)
   37.26          try:
   37.27 -            deferred = self.xd.domain_create(config)
   37.28 -            deferred.addCallback(self._op_create_cb, configstring, req)
   37.29 -            return deferred
   37.30 +            dominfo = self.xd.domain_create(config)
   37.31 +            return self._op_create_cb(dominfo, configstring, req)
   37.32          except Exception, ex:
   37.33              print 'op_create> Exception creating domain:'
   37.34              traceback.print_exc()
   37.35              raise XendError("Error creating domain: " + str(ex))
   37.36  
   37.37      def _op_create_cb(self, dominfo, configstring, req):
   37.38 -        """Callback to handle deferred domain creation.
   37.39 +        """Callback to handle domain creation.
   37.40          """
   37.41          dom = dominfo.name
   37.42          domurl = "%s/%s" % (req.prePathURL(), dom)
   37.43 @@ -93,15 +90,13 @@ class SrvDomainDir(SrvDir):
   37.44      def op_restore(self, op, req):
   37.45          """Restore a domain from file.
   37.46  
   37.47 -        @return: deferred
   37.48          """
   37.49 +        return req.threadRequest(self.do_restore, op, req)
   37.50 +
   37.51 +    def do_restore(self, op, req):
   37.52          fn = FormFn(self.xd.domain_restore,
   37.53                      [['file', 'str']])
   37.54 -        deferred = fn(req.args)
   37.55 -        deferred.addCallback(self._op_restore_cb, req)
   37.56 -        return deferred
   37.57 -
   37.58 -    def _op_restore_cb(self, dominfo, req):
   37.59 +        dominfo = fn(req.args)
   37.60          dom = dominfo.name
   37.61          domurl = "%s/%s" % (req.prePathURL(), dom)
   37.62          req.setResponseCode(http.CREATED)
   37.63 @@ -120,20 +115,16 @@ class SrvDomainDir(SrvDir):
   37.64          return self.perform(req)
   37.65  
   37.66      def render_GET(self, req):
   37.67 -        try:
   37.68 -            if self.use_sxp(req):
   37.69 -                req.setHeader("Content-Type", sxp.mime_type)
   37.70 -                self.ls_domain(req, 1)
   37.71 -            else:
   37.72 -                req.write("<html><head></head><body>")
   37.73 -                self.print_path(req)
   37.74 -                self.ls(req)
   37.75 -                self.ls_domain(req)
   37.76 -                self.form(req)
   37.77 -                req.write("</body></html>")
   37.78 -            return ''
   37.79 -        except Exception, ex:
   37.80 -            self._perform_err(ex, req)
   37.81 +        if self.use_sxp(req):
   37.82 +            req.setHeader("Content-Type", sxp.mime_type)
   37.83 +            self.ls_domain(req, 1)
   37.84 +        else:
   37.85 +            req.write("<html><head></head><body>")
   37.86 +            self.print_path(req)
   37.87 +            self.ls(req)
   37.88 +            self.ls_domain(req)
   37.89 +            self.form(req)
   37.90 +            req.write("</body></html>")
   37.91  
   37.92      def ls_domain(self, req, use_sxp=0):
   37.93          url = req.prePathURL()
    38.1 --- a/tools/python/xen/xend/server/SrvEventDir.py	Thu Apr 28 08:56:40 2005 +0000
    38.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.3 @@ -1,41 +0,0 @@
    38.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    38.5 -
    38.6 -from xen.xend import sxp
    38.7 -from xen.xend import EventServer
    38.8 -from SrvDir import SrvDir
    38.9 -
   38.10 -class SrvEventDir(SrvDir):
   38.11 -    """Event directory.
   38.12 -    """
   38.13 -
   38.14 -    def __init__(self):
   38.15 -        SrvDir.__init__(self)
   38.16 -        self.eserver = EventServer.instance()
   38.17 -
   38.18 -    def op_inject(self, op, req):
   38.19 -        eventstring = req.args.get('event')
   38.20 -        pin = sxp.Parser()
   38.21 -        pin.input(eventstring)
   38.22 -        pin.input_eof()
   38.23 -        sxpr = pin.get_val()
   38.24 -        self.eserver.inject(sxp.name(sxpr), sxpr)
   38.25 -        if req.use_sxp:
   38.26 -            sxp.name(sxpr)
   38.27 -        else:
   38.28 -            return '<code>' + eventstring + '</code>'
   38.29 -        
   38.30 -    def render_POST(self, req):
   38.31 -        return self.perform(req)
   38.32 -
   38.33 -    def form(self, req):
   38.34 -        action = req.prePathURL()
   38.35 -        req.write('<form method="post" action="%s" enctype="multipart/form-data">'
   38.36 -                  % action)
   38.37 -        req.write('<button type="submit" name="op" value="inject">Inject</button>')
   38.38 -        req.write('Event <input type="text" name="event" size="40"><br>')
   38.39 -        req.write('</form>')
   38.40 -        req.write('<form method="post" action="%s" enctype="multipart/form-data">'
   38.41 -                  % action)
   38.42 -        req.write('<button type="submit" name="op" value="inject">Inject</button>')
   38.43 -        req.write('Event file<input type="file" name="event"><br>')
   38.44 -        req.write('</form>')
    39.1 --- a/tools/python/xen/xend/server/SrvNode.py	Thu Apr 28 08:56:40 2005 +0000
    39.2 +++ b/tools/python/xen/xend/server/SrvNode.py	Thu Apr 28 10:46:53 2005 +0000
    39.3 @@ -2,7 +2,7 @@
    39.4  
    39.5  import os
    39.6  
    39.7 -from SrvDir import SrvDir
    39.8 +from xen.web.SrvDir import SrvDir
    39.9  from xen.xend import sxp
   39.10  from xen.xend import XendNode
   39.11  from xen.xend.Args import FormFn
   39.12 @@ -35,26 +35,22 @@ class SrvNode(SrvDir):
   39.13          return self.perform(req)
   39.14  
   39.15      def render_GET(self, req):
   39.16 -        try:
   39.17 -            if self.use_sxp(req):
   39.18 -                req.setHeader("Content-Type", sxp.mime_type)
   39.19 -                sxp.show(['node'] + self.info(), out=req)
   39.20 -            else:
   39.21 -                url = req.prePathURL()
   39.22 -                if not url.endswith('/'):
   39.23 -                    url += '/'
   39.24 -                req.write('<html><head></head><body>')
   39.25 -                self.print_path(req)
   39.26 -                req.write('<ul>')
   39.27 -                for d in self.info():
   39.28 -                    req.write('<li> %10s: %s' % (d[0], str(d[1])))
   39.29 -                req.write('<li><a href="%sdmesg">Xen dmesg output</a>' % url)
   39.30 -                req.write('<li><a href="%slog>Xend log</a>' % url)
   39.31 -                req.write('</ul>')
   39.32 -                req.write('</body></html>')
   39.33 -            return ''
   39.34 -        except Exception, ex:
   39.35 -            self._perform_err(ex, req)
   39.36 +        if self.use_sxp(req):
   39.37 +            req.setHeader("Content-Type", sxp.mime_type)
   39.38 +            sxp.show(['node'] + self.info(), out=req)
   39.39 +        else:
   39.40 +            url = req.prePathURL()
   39.41 +            if not url.endswith('/'):
   39.42 +                url += '/'
   39.43 +            req.write('<html><head></head><body>')
   39.44 +            self.print_path(req)
   39.45 +            req.write('<ul>')
   39.46 +            for d in self.info():
   39.47 +                req.write('<li> %10s: %s' % (d[0], str(d[1])))
   39.48 +            req.write('<li><a href="%sdmesg">Xen dmesg output</a>' % url)
   39.49 +            req.write('<li><a href="%slog>Xend log</a>' % url)
   39.50 +            req.write('</ul>')
   39.51 +            req.write('</body></html>')
   39.52              
   39.53      def info(self):
   39.54          return self.xn.info()
    40.1 --- a/tools/python/xen/xend/server/SrvRoot.py	Thu Apr 28 08:56:40 2005 +0000
    40.2 +++ b/tools/python/xen/xend/server/SrvRoot.py	Thu Apr 28 10:46:53 2005 +0000
    40.3 @@ -2,7 +2,7 @@
    40.4  
    40.5  from xen.xend import XendRoot
    40.6  xroot = XendRoot.instance()
    40.7 -from SrvDir import SrvDir
    40.8 +from xen.web.SrvDir import SrvDir
    40.9  
   40.10  class SrvRoot(SrvDir):
   40.11      """The root of the xend server.
   40.12 @@ -16,8 +16,6 @@ class SrvRoot(SrvDir):
   40.13          ('node',    'SrvNode'       ),
   40.14          ('domain',  'SrvDomainDir'  ),
   40.15          ('console', 'SrvConsoleDir' ),
   40.16 -        ('event',   'SrvEventDir'   ),
   40.17 -        ('device',  'SrvDeviceDir'  ),
   40.18          ('vnet',    'SrvVnetDir'    ),
   40.19          ]
   40.20  
   40.21 @@ -28,3 +26,7 @@ class SrvRoot(SrvDir):
   40.22          for (name, klass) in self.subdirs:
   40.23              self.get(name)
   40.24          xroot.start()
   40.25 +        
   40.26 +    def __repr__(self):
   40.27 +        return "<SrvRoot %x %s>" %(id(self), self.table.keys())
   40.28 +
    41.1 --- a/tools/python/xen/xend/server/SrvServer.py	Thu Apr 28 08:56:40 2005 +0000
    41.2 +++ b/tools/python/xen/xend/server/SrvServer.py	Thu Apr 28 10:46:53 2005 +0000
    41.3 @@ -25,34 +25,40 @@
    41.4  # todo Support security settings etc. in the config file.
    41.5  # todo Support command-line args.
    41.6  
    41.7 -from twisted.web import server, static
    41.8 -from twisted.web import resource, script
    41.9 -from twisted.internet import reactor
   41.10 +from threading import Thread
   41.11 +
   41.12 +from xen.web.httpserver import HttpServer, UnixHttpServer
   41.13  
   41.14 -from xen.xend import XendRoot
   41.15 -xroot = XendRoot.instance()
   41.16 -
   41.17 +from xen.xend import XendRoot; xroot = XendRoot.instance()
   41.18  from xen.xend import Vifctl
   41.19 +from xen.web.SrvDir import SrvDir
   41.20  
   41.21  from SrvRoot import SrvRoot
   41.22  
   41.23 -def create(port=None, interface=None, bridge=0):
   41.24 -    if port is None:
   41.25 -        port = xroot.get_xend_port()
   41.26 -    if interface is None:
   41.27 -        interface = xroot.get_xend_address()
   41.28 -    if bridge:
   41.29 +class XendServers:
   41.30 +
   41.31 +    def __init__(self):
   41.32 +        self.servers = []
   41.33 +
   41.34 +    def add(self, server):
   41.35 +        self.servers.append(server)
   41.36 +
   41.37 +    def start(self):
   41.38          Vifctl.network('start')
   41.39 -    root = resource.Resource()
   41.40 -    xend = SrvRoot()
   41.41 -    root.putChild('xend', xend)
   41.42 -    site = server.Site(root)
   41.43 -    reactor.listenTCP(port, site, interface=interface)
   41.44 +        for server in self.servers:
   41.45 +            thread = Thread(target=server.run)
   41.46 +            thread.start()
   41.47  
   41.48 -def main(port=None, interface=None):
   41.49 -    create(port, interface)
   41.50 -    reactor.run()
   41.51 -
   41.52 -
   41.53 -if __name__ == '__main__':
   41.54 -    main()
   41.55 +def create():
   41.56 +    root = SrvDir()
   41.57 +    root.putChild('xend', SrvRoot())
   41.58 +    servers = XendServers()
   41.59 +    if xroot.get_xend_http_server():
   41.60 +        port = xroot.get_xend_port()
   41.61 +        interface = xroot.get_xend_address()
   41.62 +        servers.add(HttpServer(root=root, interface=interface, port=port))
   41.63 +    if xroot.get_xend_unix_server():
   41.64 +        path = xroot.get_xend_unix_path()
   41.65 +        print 'unix path=', path
   41.66 +        servers.add(UnixHttpServer(path=path, root=root))
   41.67 +    return servers
    42.1 --- a/tools/python/xen/xend/server/SrvUsbif.py	Thu Apr 28 08:56:40 2005 +0000
    42.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.3 @@ -1,239 +0,0 @@
    42.4 -# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    42.5 -
    42.6 -from twisted.protocols import http
    42.7 -
    42.8 -from xen.xend import sxp
    42.9 -from xen.xend import XendDomain
   42.10 -from xen.xend import XendConsole
   42.11 -from xen.xend import PrettyPrint
   42.12 -from xen.xend.Args import FormFn
   42.13 -
   42.14 -from SrvDir import SrvDir
   42.15 -
   42.16 -class SrvDomain(SrvDir):
   42.17 -    """Service managing a single domain.
   42.18 -    """
   42.19 -
   42.20 -    def __init__(self, dom):
   42.21 -        SrvDir.__init__(self)
   42.22 -        self.dom = dom
   42.23 -        self.xd = XendDomain.instance()
   42.24 -        self.xconsole = XendConsole.instance()
   42.25 -
   42.26 -    def op_configure(self, op, req):
   42.27 -        """Configure an existing domain.
   42.28 -        Configure is unusual in that it requires a domain id,
   42.29 -        not a domain name.
   42.30 -        """
   42.31 -        fn = FormFn(self.xd.domain_configure,
   42.32 -                    [['dom', 'int'],
   42.33 -                     ['config', 'sxpr']])
   42.34 -        deferred = fn(req.args, {'dom': self.dom.dom})
   42.35 -        deferred.addErrback(self._op_configure_err, req)
   42.36 -        return deferred
   42.37 -
   42.38 -    def _op_configure_err(self, err, req):
   42.39 -        req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
   42.40 -        return str(err)
   42.41 -        
   42.42 -    def op_unpause(self, op, req):
   42.43 -        val = self.xd.domain_unpause(self.dom.name)
   42.44 -        return val
   42.45 -        
   42.46 -    def op_pause(self, op, req):
   42.47 -        val = self.xd.domain_pause(self.dom.name)
   42.48 -        return val
   42.49 -
   42.50 -    def op_shutdown(self, op, req):
   42.51 -        fn = FormFn(self.xd.domain_shutdown,
   42.52 -                    [['dom', 'str'],
   42.53 -                     ['reason', 'str']])
   42.54 -        val = fn(req.args, {'dom': self.dom.id})
   42.55 -        req.setResponseCode(http.ACCEPTED)
   42.56 -        req.setHeader("Location", "%s/.." % req.prePathURL())
   42.57 -        return val
   42.58 -
   42.59 -    def op_destroy(self, op, req):
   42.60 -        fn = FormFn(self.xd.domain_destroy,
   42.61 -                    [['dom', 'str'],
   42.62 -                     ['reason', 'str']])
   42.63 -        val = fn(req.args, {'dom': self.dom.id})
   42.64 -        req.setHeader("Location", "%s/.." % req.prePathURL())
   42.65 -        return val
   42.66 -
   42.67 -    def op_save(self, op, req):
   42.68 -        fn = FormFn(self.xd.domain_save,
   42.69 -                    [['dom', 'str'],
   42.70 -                     ['file', 'str']])
   42.71 -        deferred = fn(req.args, {'dom': self.dom.id})
   42.72 -        deferred.addCallback(self._op_save_cb, req)
   42.73 -        deferred.addErrback(self._op_save_err, req)
   42.74 -        return deferred
   42.75 -
   42.76 -    def _op_save_cb(self, val, req):
   42.77 -        return 0
   42.78 -
   42.79 -    def _op_save_err(self, err, req):
   42.80 -        req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
   42.81 -        return str(err)
   42.82 -        
   42.83 -    def op_migrate(self, op, req):
   42.84 -        fn = FormFn(self.xd.domain_migrate,
   42.85 -                    [['dom', 'str'],
   42.86 -                     ['destination', 'str'],
   42.87 -                     ['live', 'int']])
   42.88 -        deferred = fn(req.args, {'dom': self.dom.id})
   42.89 -        print 'op_migrate>', deferred
   42.90 -        deferred.addCallback(self._op_migrate_cb, req)
   42.91 -        deferred.addErrback(self._op_migrate_err, req)
   42.92 -        return deferred
   42.93 -
   42.94 -    def _op_migrate_cb(self, info, req):
   42.95 -        print '_op_migrate_cb>', info, req
   42.96 -        #req.setResponseCode(http.ACCEPTED)
   42.97 -        host = info.dst_host
   42.98 -        port = info.dst_port
   42.99 -        dom  = info.dst_dom
  42.100 -        url = "http://%s:%d/xend/domain/%d" % (host, port, dom)
  42.101 -        req.setHeader("Location", url)
  42.102 -        print '_op_migrate_cb> url=', url
  42.103 -        return url
  42.104 -
  42.105 -    def _op_migrate_err(self, err, req):
  42.106 -        print '_op_migrate_err>', err, req
  42.107 -        req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
  42.108 -        return str(err)
  42.109 -
  42.110 -    def op_pincpu(self, op, req):
  42.111 -        fn = FormFn(self.xd.domain_pincpu,
  42.112 -                    [['dom', 'str'],
  42.113 -                     ['cpu', 'int']])
  42.114 -        val = fn(req.args, {'dom': self.dom.id})
  42.115 -        return val
  42.116 -
  42.117 -    def op_cpu_bvt_set(self, op, req):
  42.118 -        fn = FormFn(self.xd.domain_cpu_bvt_set,
  42.119 -                    [['dom', 'str'],
  42.120 -                     ['mcuadv', 'int'],
  42.121 -                     ['warpback', 'int'],
  42.122 -                     ['warpvalue', 'int'],
  42.123 -                     ['warpl', 'long'],
  42.124 -                     ['warpu', 'long']])
  42.125 -        val = fn(req.args, {'dom': self.dom.id})
  42.126 -        return val
  42.127 -    
  42.128 -    def op_cpu_fbvt_set(self, op, req):
  42.129 -        fn = FormFn(self.xd.domain_cpu_fbvt_set,
  42.130 -                    [['dom', 'str'],
  42.131 -                     ['mcuadv', 'int'],
  42.132 -                     ['warp', 'int'],
  42.133 -                     ['warpl', 'int'],
  42.134 -                     ['warpu', 'int']])
  42.135 -        val = fn(req.args, {'dom': self.dom.id})
  42.136 -        return val
  42.137 -
  42.138 -    def op_maxmem_set(self, op, req):
  42.139 -        fn = FormFn(self.xd.domain_maxmem_set,
  42.140 -                    [['dom', 'str'],
  42.141 -                     ['memory', 'int']])
  42.142 -        val = fn(req.args, {'dom': self.dom.id})
  42.143 -        return val
  42.144 -
  42.145 -    def op_device_create(self, op, req):
  42.146 -        fn = FormFn(self.xd.domain_device_create,
  42.147 -                    [['dom', 'str'],
  42.148 -                     ['config', 'sxpr']])
  42.149 -        d = fn(req.args, {'dom': self.dom.id})
  42.150 -        return d
  42.151 -
  42.152 -    def op_device_destroy(self, op, req):
  42.153 -        fn = FormFn(self.xd.domain_device_destroy,
  42.154 -                    [['dom', 'str'],
  42.155 -                     ['type', 'str'],
  42.156 -                     ['idx', 'str']])
  42.157 -        val = fn(req.args, {'dom': self.dom.id})
  42.158 -        return val
  42.159 -                
  42.160 -    def op_vifs(self, op, req):
  42.161 -        devs = self.xd.domain_vif_ls(self.dom.id)
  42.162 -        return [ dev.sxpr() for dev in devs ]
  42.163 -
  42.164 -    def op_vif(self, op, req):
  42.165 -        fn = FormFn(self.xd.domain_vif_get,
  42.166 -                    [['dom', 'str'],
  42.167 -                     ['vif', 'str']])
  42.168 -        val = fn(req.args, {'dom': self.dom.id})
  42.169 -        return val
  42.170 -
  42.171 -    def op_vbds(self, op, req):
  42.172 -        devs = self.xd.domain_vbd_ls(self.dom.id)
  42.173 -        return [ dev.sxpr() for dev in devs ]
  42.174 -
  42.175 -    def op_vbd(self, op, req):
  42.176 -        fn = FormFn(self.xd.domain_vbd_get,
  42.177 -                    [['dom', 'str'],
  42.178 -                     ['vbd', 'str']])
  42.179 -        val = fn(req.args, {'dom': self.dom.id})
  42.180 -        return val
  42.181 -
  42.182 -    def render_POST(self, req):
  42.183 -        return self.perform(req)
  42.184 -        
  42.185 -    def render_GET(self, req):
  42.186 -        op = req.args.get('op')
  42.187 -        if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd']:
  42.188 -            return self.perform(req)
  42.189 -        if self.use_sxp(req):
  42.190 -            req.setHeader("Content-Type", sxp.mime_type)
  42.191 -            sxp.show(self.dom.sxpr(), out=req)
  42.192 -        else:
  42.193 -            req.write('<html><head></head><body>')
  42.194 -            self.print_path(req)
  42.195 -            #self.ls()
  42.196 -            req.write('<p>%s</p>' % self.dom)
  42.197 -            if self.dom.console:
  42.198 -                cinfo = self.dom.console
  42.199 -                cid = str(cinfo.console_port)
  42.200 -                #todo: Local xref: need to know server prefix.
  42.201 -                req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
  42.202 -                          % (cid, cid))
  42.203 -                req.write('<p><a href="%s">Connect to console</a></p>'
  42.204 -                          % cinfo.uri())
  42.205 -            if self.dom.config:
  42.206 -                req.write("<code><pre>")
  42.207 -                PrettyPrint.prettyprint(self.dom.config, out=req)
  42.208 -                req.write("</pre></code>")
  42.209 -            self.form(req)
  42.210 -            req.write('</body></html>')
  42.211 -        return ''
  42.212 -
  42.213 -    def form(self, req):
  42.214 -        url = req.prePathURL()
  42.215 -        req.write('<form method="post" action="%s">' % url)
  42.216 -        req.write('<input type="submit" name="op" value="unpause">')
  42.217 -        req.write('<input type="submit" name="op" value="pause">')
  42.218 -        req.write('</form>')
  42.219 -
  42.220 -        req.write('<form method="post" action="%s">' % url)
  42.221 -        req.write('<input type="submit" name="op" value="destroy">')
  42.222 -        req.write('<input type="radio" name="reason" value="halt" checked>Halt')
  42.223 -        req.write('<input type="radio" name="reason" value="reboot">Reboot')
  42.224 -        req.write('</form>')
  42.225 -
  42.226 -        req.write('<form method="post" action="%s">' % url)
  42.227 -        req.write('<input type="submit" name="op" value="shutdown">')
  42.228 -        req.write('<input type="radio" name="reason" value="poweroff" checked>Poweroff')
  42.229 -        req.write('<input type="radio" name="reason" value="halt">Halt')
  42.230 -        req.write('<input type="radio" name="reason" value="reboot">Reboot')
  42.231 -        req.write('</form>')
  42.232 -        
  42.233 -        req.write('<form method="post" action="%s">' % url)
  42.234 -        req.write('<br><input type="submit" name="op" value="save">')
  42.235 -        req.write(' To file: <input type="text" name="file">')
  42.236 -        req.write('</form>')
  42.237 -        
  42.238 -        req.write('<form method="post" action="%s">' % url)
  42.239 -        req.write('<br><input type="submit" name="op" value="migrate">')
  42.240 -        req.write(' To host: <input type="text" name="destination">')
  42.241 -        req.write('<input type="checkbox" name="live" value="1">Live')
  42.242 -        req.write('</form>')
    43.1 --- a/tools/python/xen/xend/server/SrvVnetDir.py	Thu Apr 28 08:56:40 2005 +0000
    43.2 +++ b/tools/python/xen/xend/server/SrvVnetDir.py	Thu Apr 28 10:46:53 2005 +0000
    43.3 @@ -5,7 +5,7 @@ from xen.xend.Args import FormFn
    43.4  from xen.xend import PrettyPrint
    43.5  from xen.xend import XendVnet
    43.6  
    43.7 -from SrvDir import SrvDir
    43.8 +from xen.web.SrvDir import SrvDir
    43.9  
   43.10  class SrvVnet(SrvDir):
   43.11  
   43.12 @@ -75,20 +75,16 @@ class SrvVnetDir(SrvDir):
   43.13          return self.perform(req)
   43.14  
   43.15      def render_GET(self, req):
   43.16 -        try:
   43.17 -            if self.use_sxp(req):
   43.18 -                req.setHeader("Content-Type", sxp.mime_type)
   43.19 -                self.ls_vnet(req, 1)
   43.20 -            else:
   43.21 -                req.write("<html><head></head><body>")
   43.22 -                self.print_path(req)
   43.23 -                self.ls(req)
   43.24 -                self.ls_vnet(req)
   43.25 -                self.form(req)
   43.26 -                req.write("</body></html>")
   43.27 -            return ''
   43.28 -        except Exception, ex:
   43.29 -            self._perform_err(ex, req)
   43.30 +        if self.use_sxp(req):
   43.31 +            req.setHeader("Content-Type", sxp.mime_type)
   43.32 +            self.ls_vnet(req, 1)
   43.33 +        else:
   43.34 +            req.write("<html><head></head><body>")
   43.35 +            self.print_path(req)
   43.36 +            self.ls(req)
   43.37 +            self.ls_vnet(req)
   43.38 +            self.form(req)
   43.39 +            req.write("</body></html>")
   43.40  
   43.41      def ls_vnet(self, req, use_sxp=0):
   43.42          url = req.prePathURL()
    44.1 --- a/tools/python/xen/xend/server/SrvXendLog.py	Thu Apr 28 08:56:40 2005 +0000
    44.2 +++ b/tools/python/xen/xend/server/SrvXendLog.py	Thu Apr 28 10:46:53 2005 +0000
    44.3 @@ -1,10 +1,10 @@
    44.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    44.5  
    44.6 -from twisted.web import static
    44.7 +from xen.web import static
    44.8  
    44.9  from xen.xend import XendRoot
   44.10  
   44.11 -from SrvDir import SrvDir
   44.12 +from xen.web.SrvDir import SrvDir
   44.13  
   44.14  class SrvXendLog(SrvDir):
   44.15      """Xend log.
   44.16 @@ -18,7 +18,4 @@ class SrvXendLog(SrvDir):
   44.17          self.logfile.encoding = None
   44.18  
   44.19      def render_GET(self, req):
   44.20 -        try:
   44.21 -            return self.logfile.render(req)
   44.22 -        except Exception, ex:
   44.23 -            self._perform_err(ex, req)
   44.24 +        return self.logfile.render(req)
    45.1 --- a/tools/python/xen/xend/server/blkif.py	Thu Apr 28 08:56:40 2005 +0000
    45.2 +++ b/tools/python/xen/xend/server/blkif.py	Thu Apr 28 10:46:53 2005 +0000
    45.3 @@ -2,54 +2,29 @@
    45.4  """Support for virtual block devices.
    45.5  """
    45.6  
    45.7 -from twisted.internet import defer
    45.8 -
    45.9 -from xen.xend import sxp
   45.10 -from xen.xend import Blkctl
   45.11 -from xen.xend.XendLogging import log
   45.12 -from xen.xend.XendError import XendError, VmError
   45.13 -
   45.14  import os
   45.15  import re
   45.16  import string
   45.17 +
   45.18 +from xen.xend.XendError import XendError, VmError
   45.19 +from xen.xend import XendRoot
   45.20 +from xen.xend.XendLogging import log
   45.21 +from xen.xend import sxp
   45.22 +from xen.xend import Blkctl
   45.23 +
   45.24  import channel
   45.25 -import controller
   45.26 +from controller import CtrlMsgRcvr, Dev, DevController
   45.27  from messages import *
   45.28  
   45.29  from xen.util.ip import _readline, _readlines
   45.30  
   45.31  def expand_dev_name(name):
   45.32 +    if not name:
   45.33 +        return name
   45.34      if re.match( '^/dev/', name ):
   45.35 -	return name
   45.36 +        return name
   45.37      else:
   45.38 -	return '/dev/' + name
   45.39 -
   45.40 -def check_mounted(self, name):
   45.41 -    mode = None
   45.42 -    name = expand_dev_name(name)
   45.43 -    lines = _readlines(os.popen('mount 2>/dev/null'))
   45.44 -    exp = re.compile('^' + name + ' .*[\(,]r(?P<mode>[ow])[,\)]')
   45.45 -    for line in lines:
   45.46 -        pm = exp.match(line)
   45.47 -        if not pm: continue
   45.48 -        mode = pm.group('mode')
   45.49 -        break
   45.50 -    if mode is 'w':
   45.51 -        return mode
   45.52 -    if mode is 'o':
   45.53 -        mode = 'r'
   45.54 -    blkifs = self.ctrl.daemon.blkifs()
   45.55 -    for blkif in blkifs:
   45.56 -        if blkif[1][1] is self.ctrl.dom:
   45.57 -            continue
   45.58 -        for dev in self.ctrl.daemon.blkif_get(blkif[1][1]).getDevices():
   45.59 -            if dev.type == 'phy' and name == expand_dev_name(dev.params):
   45.60 -                mode = dev.mode
   45.61 -                if 'w' in mode:
   45.62 -                    return 'w'
   45.63 -    if mode and 'r' in mode:
   45.64 -        return 'r'
   45.65 -    return None
   45.66 +        return '/dev/' + name
   45.67  
   45.68  def blkdev_name_to_number(name):
   45.69      """Take the given textual block-device name (e.g., '/dev/sda1',
   45.70 @@ -58,10 +33,10 @@ def blkdev_name_to_number(name):
   45.71      n = expand_dev_name(name)
   45.72  
   45.73      try:
   45.74 -	return os.stat(n).st_rdev
   45.75 +        return os.stat(n).st_rdev
   45.76      except Exception, ex:
   45.77          log.debug("exception looking up device number for %s: %s", name, ex)
   45.78 -	pass
   45.79 +        pass
   45.80  
   45.81      if re.match( '/dev/sd[a-p]([0-9]|1[0-5])', n):
   45.82          return 8 * 256 + 16 * (ord(n[7:8]) - ord('a')) + int(n[8:])
   45.83 @@ -74,8 +49,8 @@ def blkdev_name_to_number(name):
   45.84  
   45.85      # see if this is a hex device number
   45.86      if re.match( '^(0x)?[0-9a-fA-F]+$', name ):
   45.87 -	return string.atoi(name,16)
   45.88 -	
   45.89 +        return string.atoi(name,16)
   45.90 +        
   45.91      return None
   45.92  
   45.93  def blkdev_segment(name):
   45.94 @@ -90,50 +65,71 @@ def blkdev_segment(name):
   45.95      val = None
   45.96      n = blkdev_name_to_number(name)
   45.97      if n:
   45.98 -	val = { 'device' : n,
   45.99 +        val = { 'device'       : n,
  45.100                  'start_sector' : long(0),
  45.101 -                'nr_sectors' : long(1L<<63),
  45.102 -                'type' : 'Disk' }
  45.103 +                'nr_sectors'   : long(1L<<63),
  45.104 +                'type'         : 'Disk' }
  45.105      return val
  45.106  
  45.107 -class BlkifBackendController(controller.BackendController):
  45.108 -    """ Handler for the 'back-end' channel to a block device driver domain.
  45.109 -    """
  45.110 -
  45.111 -    def __init__(self, factory, dom):
  45.112 -        controller.BackendController.__init__(self, factory, dom)
  45.113 -        self.addMethod(CMSG_BLKIF_BE,
  45.114 -                       CMSG_BLKIF_BE_DRIVER_STATUS,
  45.115 -                       self.recv_be_driver_status)
  45.116 -        self.registerChannel()
  45.117 -
  45.118 -    def recv_be_driver_status(self, msg, req):
  45.119 -        """Request handler for be_driver_status messages.
  45.120 -        
  45.121 -        @param msg: message
  45.122 -        @type  msg: xu message
  45.123 -        @param req: request flag (true if the msg is a request)
  45.124 -        @type  req: bool
  45.125 -        """
  45.126 -        val = unpackMsg('blkif_be_driver_status_t', msg)
  45.127 -        status = val['status']
  45.128 -
  45.129 -class BlkifBackendInterface(controller.BackendInterface):
  45.130 +def mount_mode(name):
  45.131 +    mode = None
  45.132 +    name = expand_dev_name(name)
  45.133 +    lines = _readlines(os.popen('mount 2>/dev/null'))
  45.134 +    exp = re.compile('^' + name + ' .*[\(,]r(?P<mode>[ow])[,\)]')
  45.135 +    for line in lines:
  45.136 +        pm = exp.match(line)
  45.137 +        if not pm: continue
  45.138 +        mode = pm.group('mode')
  45.139 +        break
  45.140 +    if mode == 'w':
  45.141 +        return mode
  45.142 +    if mode == 'o':
  45.143 +        mode = 'r'
  45.144 +    return mode
  45.145 +    
  45.146 +class BlkifBackend:
  45.147      """ Handler for the 'back-end' channel to a block device driver domain
  45.148      on behalf of a front-end domain.
  45.149      Must be connected using connect() before it can be used.
  45.150 -    Do not create directly - use getBackendInterface() on the BlkifController.
  45.151      """
  45.152  
  45.153 -    def __init__(self, ctrl, dom, handle):
  45.154 -        controller.BackendInterface.__init__(self, ctrl, dom, handle)
  45.155 -        self.connected = 0
  45.156 +    def __init__(self, controller, id, dom, recreate=False):
  45.157 +        self.controller = controller
  45.158 +        self.id = id
  45.159 +        self.frontendDomain = self.controller.getDomain()
  45.160 +        self.frontendChannel = None
  45.161 +        self.backendDomain = dom
  45.162 +        self.backendChannel = None
  45.163 +        self.destroyed = False
  45.164 +        self.connected = False
  45.165          self.evtchn = None
  45.166 +        self.status = None
  45.167 +
  45.168 +    def init(self, recreate=False, reboot=False):
  45.169 +        self.destroyed = False
  45.170          self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
  45.171 +        self.frontendDomain = self.controller.getDomain()
  45.172 +        self.frontendChannel = self.controller.getChannel()
  45.173 +        cf = channel.channelFactory()
  45.174 +        self.backendChannel = cf.openChannel(self.backendDomain)
  45.175  
  45.176      def __str__(self):
  45.177 -        return '<BlkifBackendInterface %d %d>' % (self.controller.dom, self.dom)
  45.178 +        return ('<BlkifBackend frontend=%d backend=%d id=%d>'
  45.179 +                % (self.frontendDomain,
  45.180 +                   self.backendDomain,
  45.181 +                   self.id))
  45.182 +
  45.183 +    def getId(self):
  45.184 +        return self.id
  45.185  
  45.186 +    def closeEvtchn(self):
  45.187 +        if self.evtchn:
  45.188 +            channel.eventChannelClose(self.evtchn)
  45.189 +            self.evtchn = None
  45.190 +
  45.191 +    def openEvtchn(self):
  45.192 +        self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
  45.193 +        
  45.194      def getEventChannelBackend(self):
  45.195          val = 0
  45.196          if self.evtchn:
  45.197 @@ -146,91 +142,76 @@ class BlkifBackendInterface(controller.B
  45.198              val = self.evtchn['port2']
  45.199          return val
  45.200  
  45.201 -    def connect(self, recreate=0):
  45.202 +    def connect(self, recreate=False):
  45.203          """Connect to the blkif control interface.
  45.204  
  45.205          @param recreate: true if after xend restart
  45.206 -        @return: deferred
  45.207          """
  45.208          log.debug("Connecting blkif %s", str(self))
  45.209          if recreate or self.connected:
  45.210 -            d = defer.succeed(self)
  45.211 +            self.connected = True
  45.212 +            pass
  45.213          else:
  45.214 -            d = self.send_be_create()
  45.215 -            d.addCallback(self.respond_be_create)
  45.216 -        return d
  45.217 +            self.send_be_create()
  45.218          
  45.219      def send_be_create(self):
  45.220 -        d = defer.Deferred()
  45.221 +        log.debug("send_be_create %s", str(self))
  45.222          msg = packMsg('blkif_be_create_t',
  45.223 -                      { 'domid'        : self.controller.dom,
  45.224 -                        'blkif_handle' : self.handle })
  45.225 -        self.writeRequest(msg, response=d)
  45.226 -        return d
  45.227 +                      { 'domid'        : self.frontendDomain,
  45.228 +                        'blkif_handle' : self.id })
  45.229 +        msg = self.backendChannel.requestResponse(msg)
  45.230 +        #todo: check return status
  45.231 +        self.connected = True
  45.232  
  45.233 -    def respond_be_create(self, msg):
  45.234 -        val = unpackMsg('blkif_be_create_t', msg)
  45.235 -        self.connected = 1
  45.236 -        return self
  45.237 -    
  45.238 -    def destroy(self):
  45.239 +    def destroy(self, change=False, reboot=False):
  45.240          """Disconnect from the blkif control interface and destroy it.
  45.241          """
  45.242 -        def cb_destroy(val):
  45.243 -            self.send_be_destroy()
  45.244 -            self.close()
  45.245 -        d = defer.Deferred()
  45.246 -        d.addCallback(cb_destroy)
  45.247 -        if self.evtchn:
  45.248 -            channel.eventChannelClose(self.evtchn)
  45.249 -        self.send_be_disconnect(response=d)
  45.250 -        
  45.251 -    def send_be_disconnect(self, response=None):
  45.252 +        self.send_be_disconnect()
  45.253 +        self.send_be_destroy()
  45.254 +        self.closeEvtchn()
  45.255 +        self.destroyed = True
  45.256 +        # For change true need to notify front-end, or back-end will do it?
  45.257 +
  45.258 +    def send_be_disconnect(self):
  45.259          msg = packMsg('blkif_be_disconnect_t',
  45.260 -                      { 'domid'        : self.controller.dom,
  45.261 -                        'blkif_handle' : self.handle })
  45.262 -        self.writeRequest(msg, response=response)
  45.263 +                      { 'domid'        : self.frontendDomain,
  45.264 +                        'blkif_handle' : self.id })
  45.265 +        self.backendChannel.writeRequest(msg)
  45.266 +        self.connected = False
  45.267  
  45.268 -    def send_be_destroy(self, response=None):
  45.269 +    def send_be_destroy(self):
  45.270          msg = packMsg('blkif_be_destroy_t',
  45.271 -                      { 'domid'        : self.controller.dom,
  45.272 -                        'blkif_handle' : self.handle })
  45.273 -        self.writeRequest(msg, response=response)
  45.274 +                      { 'domid'        : self.frontendDomain,
  45.275 +                        'blkif_handle' : self.id })
  45.276 +        self.backendChannel.writeRequest(msg)
  45.277  
  45.278      def connectInterface(self, val):
  45.279 -        self.evtchn = channel.eventChannel(self.dom, self.controller.dom)
  45.280 +        self.openEvtchn()
  45.281          log.debug("Connecting blkif to event channel %s ports=%d:%d",
  45.282                    str(self), self.evtchn['port1'], self.evtchn['port2'])
  45.283          msg = packMsg('blkif_be_connect_t',
  45.284 -                      { 'domid'        : self.controller.dom,
  45.285 -                        'blkif_handle' : self.handle,
  45.286 +                      { 'domid'        : self.frontendDomain,
  45.287 +                        'blkif_handle' : self.id,
  45.288                          'evtchn'       : self.getEventChannelBackend(),
  45.289                          'shmem_frame'  : val['shmem_frame'] })
  45.290 -        d = defer.Deferred()
  45.291 -        d.addCallback(self.respond_be_connect)
  45.292 -        self.writeRequest(msg, response=d)
  45.293 -
  45.294 -    def respond_be_connect(self, msg):
  45.295 -        """Response handler for a be_connect message.
  45.296 -
  45.297 -        @param msg: message
  45.298 -        @type  msg: xu message
  45.299 -        """
  45.300 +        msg = self.backendChannel.requestResponse(msg)
  45.301 +        #todo: check return status
  45.302          val = unpackMsg('blkif_be_connect_t', msg)
  45.303          self.status = BLKIF_INTERFACE_STATUS_CONNECTED
  45.304          self.send_fe_interface_status()
  45.305              
  45.306 -    def send_fe_interface_status(self, response=None):
  45.307 +    def send_fe_interface_status(self):
  45.308          msg = packMsg('blkif_fe_interface_status_t',
  45.309 -                      { 'handle' : self.handle,
  45.310 +                      { 'handle' : self.id,
  45.311                          'status' : self.status,
  45.312 -                        'domid'  : self.dom,
  45.313 +                        'domid'  : self.backendDomain,
  45.314                          'evtchn' : self.getEventChannelFrontend() })
  45.315 -        self.controller.writeRequest(msg, response=response)
  45.316 +        self.frontendChannel.writeRequest(msg)
  45.317  
  45.318      def interfaceDisconnected(self):
  45.319          self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
  45.320 -        #todo?: Do this: self.evtchn = None
  45.321 +        #todo?: Close evtchn:
  45.322 +        #self.closeEvtchn()
  45.323          self.send_fe_interface_status()
  45.324          
  45.325      def interfaceChanged(self):
  45.326 @@ -238,83 +219,18 @@ class BlkifBackendInterface(controller.B
  45.327          The front-end should then probe for devices.
  45.328          """
  45.329          msg = packMsg('blkif_fe_interface_status_t',
  45.330 -                      { 'handle' : self.handle,
  45.331 +                      { 'handle' : self.id,
  45.332                          'status' : BLKIF_INTERFACE_STATUS_CHANGED,
  45.333 -                        'domid'  : self.dom,
  45.334 +                        'domid'  : self.backendDomain,
  45.335                          'evtchn' : 0 })
  45.336 -        self.controller.writeRequest(msg)
  45.337 -        
  45.338 -class BlkifControllerFactory(controller.SplitControllerFactory):
  45.339 -    """Factory for creating block device interface controllers.
  45.340 -    """
  45.341 -
  45.342 -    def __init__(self):
  45.343 -        controller.SplitControllerFactory.__init__(self)
  45.344 -
  45.345 -    def createController(self, dom, recreate=0):
  45.346 -        """Create a block device controller for a domain.
  45.347 -
  45.348 -        @param dom: domain
  45.349 -        @type  dom: int
  45.350 -        @param recreate: if true it's a recreate (after xend restart)
  45.351 -        @type  recreate: bool
  45.352 -        @return: block device controller
  45.353 -        @rtype: BlkifController
  45.354 -        """
  45.355 -        blkif = self.getControllerByDom(dom)
  45.356 -        if blkif is None:
  45.357 -            blkif = BlkifController(self, dom)
  45.358 -            self.addController(blkif)
  45.359 -        return blkif
  45.360 -
  45.361 -    def createBackendController(self, dom):
  45.362 -        """Create a block device backend controller.
  45.363 +        self.frontendChannel.writeRequest(msg)
  45.364  
  45.365 -        @param dom: backend domain
  45.366 -        @return: backend controller
  45.367 -        """
  45.368 -        return BlkifBackendController(self, dom)
  45.369 -
  45.370 -    def createBackendInterface(self, ctrl, dom, handle):
  45.371 -        """Create a block device backend interface.
  45.372 -
  45.373 -        @param ctrl: controller
  45.374 -        @param dom: backend domain
  45.375 -        @param handle: interface handle
  45.376 -        @return: backend interface
  45.377 -        """
  45.378 -        return BlkifBackendInterface(ctrl, dom, handle)
  45.379 -
  45.380 -    def getDomainDevices(self, dom):
  45.381 -        """Get the block devices for a domain.
  45.382 -
  45.383 -        @param dom: domain
  45.384 -        @type  dom: int
  45.385 -        @return: devices
  45.386 -        @rtype:  [device]
  45.387 -        """
  45.388 -        blkif = self.getControllerByDom(dom)
  45.389 -        return (blkif and blkif.getDevices()) or []
  45.390 -
  45.391 -    def getDomainDevice(self, dom, idx):
  45.392 -        """Get a block device from a domain.
  45.393 -
  45.394 -        @param dom: domain
  45.395 -        @type  dom: int
  45.396 -        @param idx: device index
  45.397 -        @type  idx: int
  45.398 -        @return: device
  45.399 -        @rtype:  device
  45.400 -        """
  45.401 -        blkif = self.getControllerByDom(dom)
  45.402 -        return (blkif and blkif.getDevice(idx)) or None
  45.403 -
  45.404 -class BlkDev(controller.SplitDev):
  45.405 +class BlkDev(Dev):
  45.406      """Info record for a block device.
  45.407      """
  45.408  
  45.409 -    def __init__(self, idx, ctrl, config):
  45.410 -        controller.SplitDev.__init__(self, idx, ctrl)
  45.411 +    def __init__(self, controller, id, config, recreate=False):
  45.412 +        Dev.__init__(self, controller, id, config, recreate=recreate)
  45.413          self.dev = None
  45.414          self.uname = None
  45.415          self.vdev = None
  45.416 @@ -325,10 +241,24 @@ class BlkDev(controller.SplitDev):
  45.417          self.device = None
  45.418          self.start_sector = None
  45.419          self.nr_sectors = None
  45.420 -        self.ctrl = ctrl
  45.421 -        self.configure(config)
  45.422 +        
  45.423 +        self.frontendDomain = self.getDomain()
  45.424 +        self.frontendChannel = None
  45.425 +        self.backendDomain = None
  45.426 +        self.backendChannel = None
  45.427 +        self.backendId = 0
  45.428 +        self.configure(self.config, recreate=recreate)
  45.429  
  45.430 -    def configure(self, config):
  45.431 +    def init(self, recreate=False, reboot=False):
  45.432 +        self.frontendDomain = self.getDomain()
  45.433 +        self.frontendChannel = self.getChannel()
  45.434 +        backend = self.getBackend()
  45.435 +        self.backendChannel = backend.backendChannel
  45.436 +        self.backendId = backend.id
  45.437 +
  45.438 +    def configure(self, config, change=False, recreate=False):
  45.439 +        if change:
  45.440 +            raise XendError("cannot reconfigure vbd")
  45.441          self.config = config
  45.442          self.uname = sxp.child_value(config, 'uname')
  45.443          if not self.uname:
  45.444 @@ -340,23 +270,29 @@ class BlkDev(controller.SplitDev):
  45.445          if not self.dev:
  45.446              raise VmError('vbd: Missing dev')
  45.447          self.mode = sxp.child_value(config, 'mode', 'r')
  45.448 -        # todo: The 'dev' should be looked up in the context of the domain.
  45.449 +        
  45.450          self.vdev = blkdev_name_to_number(self.dev)
  45.451          if not self.vdev:
  45.452              raise VmError('vbd: Device not found: %s' % self.dev)
  45.453 +        
  45.454          try:
  45.455              self.backendDomain = int(sxp.child_value(config, 'backend', '0'))
  45.456          except:
  45.457              raise XendError('invalid backend domain')
  45.458  
  45.459 -    def recreate(self, savedinfo):
  45.460 -        node = sxp.child_value(savedinfo, 'node')
  45.461 -        self.setNode(node)
  45.462 +        return self.config
  45.463  
  45.464 -    def attach(self):
  45.465 -        node = Blkctl.block('bind', self.type, self.params)
  45.466 -        self.setNode(node)
  45.467 -        return self.attachBackend()
  45.468 +    def attach(self, recreate=False, change=False):
  45.469 +        if recreate:
  45.470 +            node = sxp.child_value(recreate, 'node')
  45.471 +            print 'BlkDev>attach>', 'recreate=', recreate, 'node=', node
  45.472 +            self.setNode(node)
  45.473 +        else:
  45.474 +            node = Blkctl.block('bind', self.type, self.params)
  45.475 +            self.setNode(node)
  45.476 +            self.attachBackend()
  45.477 +        if change:
  45.478 +            self.interfaceChanged()
  45.479  
  45.480      def unbind(self):
  45.481          if self.node is None: return
  45.482 @@ -379,14 +315,15 @@ class BlkDev(controller.SplitDev):
  45.483              return
  45.484          # done.
  45.485              
  45.486 -        mounted_mode = check_mounted(self, node)
  45.487 +        mounted_mode = self.check_mounted(node)
  45.488          if not '!' in self.mode and mounted_mode:
  45.489 -            if mounted_mode is "w":
  45.490 +            if mounted_mode == "w":
  45.491                  raise VmError("vbd: Segment %s is in writable use" %
  45.492                                self.uname)
  45.493              elif 'w' in self.mode:
  45.494                  raise VmError("vbd: Segment %s is in read-only use" %
  45.495                                self.uname)
  45.496 +            
  45.497          segment = blkdev_segment(node)
  45.498          if not segment:
  45.499              raise VmError("vbd: Segment not found: uname=%s" % self.uname)
  45.500 @@ -395,12 +332,28 @@ class BlkDev(controller.SplitDev):
  45.501          self.start_sector = segment['start_sector']
  45.502          self.nr_sectors = segment['nr_sectors']
  45.503  
  45.504 +    def check_mounted(self, name):
  45.505 +        mode = mount_mode(name)
  45.506 +        xd = XendRoot.get_component('xen.xend.XendDomain')
  45.507 +        for vm in xd.domains():
  45.508 +            ctrl = vm.getDeviceController(self.getType(), error=False)
  45.509 +            if (not ctrl): continue
  45.510 +            for dev in ctrl.getDevices():
  45.511 +                if dev is self: continue
  45.512 +                if dev.type == 'phy' and name == expand_dev_name(dev.params):
  45.513 +                    mode = dev.mode
  45.514 +                    if 'w' in mode:
  45.515 +                        return 'w'
  45.516 +        if mode and 'r' in mode:
  45.517 +            return 'r'
  45.518 +        return None
  45.519 +
  45.520      def readonly(self):
  45.521          return 'w' not in self.mode
  45.522  
  45.523      def sxpr(self):
  45.524          val = ['vbd',
  45.525 -               ['idx', self.idx],
  45.526 +               ['id', self.id],
  45.527                 ['vdev', self.vdev],
  45.528                 ['device', self.device],
  45.529                 ['mode', self.mode]]
  45.530 @@ -410,163 +363,157 @@ class BlkDev(controller.SplitDev):
  45.531              val.append(['uname', self.uname])
  45.532          if self.node:
  45.533              val.append(['node', self.node])
  45.534 -        if self.index is not None:
  45.535 -            val.append(['index', self.index])
  45.536 +        val.append(['index', self.getIndex()])
  45.537          return val
  45.538  
  45.539 +    def getBackend(self):
  45.540 +        return self.controller.getBackend(self.backendDomain)
  45.541 +
  45.542      def refresh(self):
  45.543 -        log.debug("Refreshing vbd domain=%d idx=%s", self.controller.dom, self.idx)
  45.544 +        log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, self.id)
  45.545          self.interfaceChanged()
  45.546  
  45.547 -    def destroy(self, change=0):
  45.548 +    def destroy(self, change=False, reboot=False):
  45.549          """Destroy the device. If 'change' is true notify the front-end interface.
  45.550  
  45.551          @param change: change flag
  45.552          """
  45.553 -        log.debug("Destroying vbd domain=%d idx=%s", self.controller.dom, self.idx)
  45.554 -        d = self.send_be_vbd_destroy()
  45.555 +        self.destroyed = True
  45.556 +        log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, self.id)
  45.557 +        self.send_be_vbd_destroy()
  45.558          if change:
  45.559 -            d.addCallback(lambda val: self.interfaceChanged())
  45.560 -        d.addCallback(lambda val: self.unbind())
  45.561 +            self.interfaceChanged()
  45.562 +        self.unbind()
  45.563  
  45.564      def interfaceChanged(self):
  45.565          """Tell the back-end to notify the front-end that a device has been
  45.566          added or removed.
  45.567          """
  45.568 -        self.getBackendInterface().interfaceChanged()
  45.569 +        self.getBackend().interfaceChanged()
  45.570  
  45.571      def attachBackend(self):
  45.572          """Attach the device to its controller.
  45.573  
  45.574          """
  45.575 -        backend = self.getBackendInterface()
  45.576 -        d1 = backend.connect()
  45.577 -        d2 = defer.Deferred()
  45.578 -        d2.addCallback(self.send_be_vbd_create)
  45.579 -        d1.chainDeferred(d2)
  45.580 -        return d2
  45.581 +        self.getBackend().connect()
  45.582 +        self.send_be_vbd_create()
  45.583          
  45.584 -    def send_be_vbd_create(self, val):
  45.585 -        d = defer.Deferred()
  45.586 -        d.addCallback(self.respond_be_vbd_create)
  45.587 -        backend = self.getBackendInterface()
  45.588 +    def send_be_vbd_create(self):
  45.589          msg = packMsg('blkif_be_vbd_create_t',
  45.590 -                      { 'domid'        : self.controller.dom,
  45.591 -                        'blkif_handle' : backend.handle,
  45.592 +                      { 'domid'        : self.frontendDomain,
  45.593 +                        'blkif_handle' : self.backendId,
  45.594                          'pdevice'      : self.device,
  45.595                          'vdevice'      : self.vdev,
  45.596                          'readonly'     : self.readonly() })
  45.597 -        backend.writeRequest(msg, response=d)
  45.598 -        return d
  45.599 +        msg = self.backendChannel.requestResponse(msg)
  45.600          
  45.601 -    def respond_be_vbd_create(self, msg):
  45.602          val = unpackMsg('blkif_be_vbd_create_t', msg)
  45.603 -	status = val['status']
  45.604 -	if status != BLKIF_BE_STATUS_OKAY:
  45.605 +        status = val['status']
  45.606 +        if status != BLKIF_BE_STATUS_OKAY:
  45.607              raise XendError("Creating vbd failed: device %s, error %d"
  45.608                              % (sxp.to_string(self.config), status))
  45.609 -        return self
  45.610  
  45.611      def send_be_vbd_destroy(self):
  45.612 -        d = defer.Deferred()
  45.613 -        backend = self.getBackendInterface()
  45.614          msg = packMsg('blkif_be_vbd_destroy_t',
  45.615 -                      { 'domid'                : self.controller.dom,
  45.616 -                        'blkif_handle'         : backend.handle,
  45.617 +                      { 'domid'                : self.frontendDomain,
  45.618 +                        'blkif_handle'         : self.backendId,
  45.619                          'vdevice'              : self.vdev })
  45.620 -        self.controller.delDevice(self.vdev)
  45.621 -        backend.writeRequest(msg, response=d)
  45.622 -        return d
  45.623 +        return self.backendChannel.writeRequest(msg)
  45.624          
  45.625 -
  45.626 -class BlkifController(controller.SplitController):
  45.627 +class BlkifController(DevController):
  45.628      """Block device interface controller. Handles all block devices
  45.629      for a domain.
  45.630      """
  45.631      
  45.632 -    def __init__(self, factory, dom):
  45.633 +    def __init__(self, vm, recreate=False):
  45.634          """Create a block device controller.
  45.635 -        Do not call directly - use createController() on the factory instead.
  45.636          """
  45.637 -        controller.SplitController.__init__(self, factory, dom)
  45.638 -        self.addMethod(CMSG_BLKIF_FE,
  45.639 -                       CMSG_BLKIF_FE_DRIVER_STATUS,
  45.640 -                       self.recv_fe_driver_status)
  45.641 -        self.addMethod(CMSG_BLKIF_FE,
  45.642 -                       CMSG_BLKIF_FE_INTERFACE_CONNECT,
  45.643 -                       self.recv_fe_interface_connect)
  45.644 -        self.registerChannel()
  45.645 +        DevController.__init__(self, vm, recreate=recreate)
  45.646 +        self.backends = {}
  45.647 +        self.backendId = 0
  45.648 +        self.rcvr = None
  45.649 +
  45.650 +    def initController(self, recreate=False, reboot=False):
  45.651 +        self.destroyed = False
  45.652 +        # Add our handlers for incoming requests.
  45.653 +        self.rcvr = CtrlMsgRcvr(self.getChannel())
  45.654 +        self.rcvr.addHandler(CMSG_BLKIF_FE,
  45.655 +                             CMSG_BLKIF_FE_DRIVER_STATUS,
  45.656 +                             self.recv_fe_driver_status)
  45.657 +        self.rcvr.addHandler(CMSG_BLKIF_FE,
  45.658 +                             CMSG_BLKIF_FE_INTERFACE_CONNECT,
  45.659 +                             self.recv_fe_interface_connect)
  45.660 +        self.rcvr.registerChannel()
  45.661 +        if reboot:
  45.662 +            self.rebootBackends()
  45.663 +            self.rebootDevices()
  45.664  
  45.665      def sxpr(self):
  45.666 -        val = ['blkif', ['dom', self.dom]]
  45.667 +        val = ['blkif', ['dom', self.getDomain()]]
  45.668          return val
  45.669  
  45.670 -    def addDevice(self, idx, config):
  45.671 -        """Add a device to the device table.
  45.672 +    def rebootBackends(self):
  45.673 +        for backend in self.backends.values():
  45.674 +            backend.init(reboot=True)
  45.675 +
  45.676 +    def getBackendById(self, id):
  45.677 +        return self.backends.get(id)
  45.678 +
  45.679 +    def getBackendByDomain(self, dom):
  45.680 +        for backend in self.backends.values():
  45.681 +            if backend.backendDomain == dom:
  45.682 +                return backend
  45.683 +        return None
  45.684  
  45.685 -        @param vdev:     device index
  45.686 -        @type  vdev:     int
  45.687 -        @param config: device configuration
  45.688 -        @return: device
  45.689 -        @rtype:  BlkDev
  45.690 -        """
  45.691 -        if idx in self.devices:
  45.692 -            raise XendError('device exists: ' + str(idx))
  45.693 -        dev = BlkDev(idx, self, config )
  45.694 -        self.devices[idx] = dev
  45.695 -        return dev
  45.696 +    def getBackend(self, dom):
  45.697 +        backend = self.getBackendByDomain(dom)
  45.698 +        if backend: return backend
  45.699 +        backend = BlkifBackend(self, self.backendId, dom)
  45.700 +        self.backendId += 1
  45.701 +        self.backends[backend.getId()] = backend
  45.702 +        backend.init()
  45.703 +        return backend
  45.704  
  45.705 -    def attachDevice(self, idx, config, recreate=0):
  45.706 -        """Attach a device to the specified interface.
  45.707 -        On success the returned deferred will be called with the device.
  45.708 +    def newDevice(self, id, config, recreate=False):
  45.709 +        """Create a device..
  45.710  
  45.711 -        @param idx:      device id
  45.712 +        @param id:      device id
  45.713          @param config:   device configuration
  45.714          @param recreate: if true it's being recreated (after xend restart)
  45.715          @type  recreate: bool
  45.716 -        @return: deferred
  45.717 -        @rtype:  Deferred
  45.718 +        @return: device
  45.719 +        @rtype:  BlkDev
  45.720          """
  45.721 -        dev = self.addDevice(idx, config)
  45.722 -        if recreate:
  45.723 -            dev.recreate(recreate)
  45.724 -            d = defer.succeed(dev)
  45.725 -        else:
  45.726 -            d = dev.attach()
  45.727 -        return d
  45.728 -
  45.729 -    def destroy(self):
  45.730 +        return BlkDev(self, id, config, recreate=recreate)
  45.731 +        
  45.732 +    def destroyController(self, reboot=False):
  45.733          """Destroy the controller and all devices.
  45.734          """
  45.735 -        log.debug("Destroying blkif domain=%d", self.dom)
  45.736 -        self.destroyDevices()
  45.737 -        self.destroyBackends()
  45.738 +        self.destroyed = True
  45.739 +        log.debug("Destroying blkif domain=%d", self.getDomain())
  45.740 +        self.destroyDevices(reboot=reboot)
  45.741 +        self.destroyBackends(reboot=reboot)
  45.742 +        self.rcvr.deregisterChannel()
  45.743  
  45.744 -    def destroyDevices(self):
  45.745 -        """Destroy all devices.
  45.746 -        """
  45.747 -        for dev in self.getDevices():
  45.748 -            dev.destroy()
  45.749 +    def destroyBackends(self, reboot=False):
  45.750 +        for backend in self.backends.values():
  45.751 +            backend.destroy(reboot=reboot)
  45.752  
  45.753 -    def destroyBackends(self):
  45.754 -        for backend in self.getBackendInterfaces():
  45.755 -            backend.destroy()
  45.756 -
  45.757 -    def recv_fe_driver_status(self, msg, req):
  45.758 +    def recv_fe_driver_status(self, msg):
  45.759          val = unpackMsg('blkif_fe_driver_status_t', msg)
  45.760 -        print 'recv_fe_driver_status>', val
  45.761 -        for backend in self.getBackendInterfaces():
  45.762 +        for backend in self.backends.values():
  45.763              backend.interfaceDisconnected()
  45.764  
  45.765 -    def recv_fe_interface_connect(self, msg, req):
  45.766 +    def recv_fe_interface_connect(self, msg):
  45.767          val = unpackMsg('blkif_fe_interface_connect_t', msg)
  45.768 -        handle = val['handle']
  45.769 -        backend = self.getBackendInterfaceByHandle(handle)
  45.770 +        id = val['handle']
  45.771 +        backend = self.getBackendById(id)
  45.772          if backend:
  45.773 -            backend.connectInterface(val)
  45.774 +            try:
  45.775 +                backend.connectInterface(val)
  45.776 +            except IOError, ex:
  45.777 +                log.error("Exception connecting backend: %s", ex)
  45.778          else:
  45.779 -            log.error('interface connect on unknown interface: handle=%d', handle)
  45.780 -
  45.781 -
  45.782 +            log.error('interface connect on unknown interface: id=%d', id)
  45.783      
  45.784  
    46.1 --- a/tools/python/xen/xend/server/channel.py	Thu Apr 28 08:56:40 2005 +0000
    46.2 +++ b/tools/python/xen/xend/server/channel.py	Thu Apr 28 10:46:53 2005 +0000
    46.3 @@ -1,8 +1,14 @@
    46.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    46.5  
    46.6 +import threading
    46.7 +import select
    46.8 +
    46.9  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
   46.10  from xen.lowlevel import xu
   46.11 -from messages import msgTypeName, printMsg
   46.12 +
   46.13 +from xen.xend.XendLogging import log
   46.14 +
   46.15 +from messages import *
   46.16  
   46.17  VIRQ_MISDIRECT  = 0  # Catch-all interrupt for unbound VIRQs.
   46.18  VIRQ_TIMER      = 1  # Timebase update, and/or requested timeout.
   46.19 @@ -10,6 +16,10 @@ VIRQ_DEBUG      = 2  # Request guest to 
   46.20  VIRQ_CONSOLE    = 3  # (DOM0) bytes received on emergency console.
   46.21  VIRQ_DOM_EXC    = 4  # (DOM0) Exceptional event for some domain.
   46.22  
   46.23 +DEBUG = 0
   46.24 +
   46.25 +RESPONSE_TIMEOUT = 20.0
   46.26 +
   46.27  def eventChannel(dom1, dom2):
   46.28      """Create an event channel between domains.
   46.29      The returned dict contains dom1, dom2, port1 and port2 on success.
   46.30 @@ -33,6 +43,7 @@ def eventChannelClose(evtchn):
   46.31              pass
   46.32          
   46.33      if not evtchn: return
   46.34 +    print 'eventChannelClose>', evtchn
   46.35      evtchn_close(evtchn.get('dom1'), evtchn.get('port1'))
   46.36      evtchn_close(evtchn.get('dom2'), evtchn.get('port2'))
   46.37      
   46.38 @@ -45,76 +56,144 @@ class ChannelFactory:
   46.39      """ Channels indexed by index. """
   46.40      channels = {}
   46.41  
   46.42 +    thread = None
   46.43 +
   46.44 +    notifier = None
   46.45 +
   46.46 +    """Map of ports to the virq they signal."""
   46.47 +    virqPorts = {}
   46.48 +
   46.49      def __init__(self):
   46.50          """Constructor - do not use. Use the channelFactory function."""
   46.51          self.notifier = xu.notifier()
   46.52 +        # Register interest in all virqs.
   46.53 +        # Unfortunately virqs do not seem to be delivered.
   46.54 +        self.bind_virq(VIRQ_MISDIRECT)
   46.55 +        self.bind_virq(VIRQ_TIMER)
   46.56 +        self.bind_virq(VIRQ_DEBUG)
   46.57 +        self.bind_virq(VIRQ_CONSOLE)
   46.58 +        self.bind_virq(VIRQ_DOM_EXC)
   46.59 +        self.virqHandler = None
   46.60 +
   46.61 +    def bind_virq(self, virq):
   46.62 +        port = self.notifier.bind_virq(virq)
   46.63 +        self.virqPorts[port] = virq
   46.64 +        log.info("Virq %s on port %s", virq, port)
   46.65 +
   46.66 +    def virq(self):
   46.67 +        self.notifier.virq_send(self.virqPort)
   46.68 +
   46.69 +    def start(self):
   46.70 +        """Fork a thread to read messages.
   46.71 +        """
   46.72 +        if self.thread: return
   46.73 +        self.thread = threading.Thread(name="ChannelFactory",
   46.74 +                                       target=self.main)
   46.75 +        self.thread.setDaemon(True)
   46.76 +        self.thread.start()
   46.77 +
   46.78 +    def stop(self):
   46.79 +        """Signal the thread to stop.
   46.80 +        """
   46.81 +        self.thread = None
   46.82 +
   46.83 +    def main(self):
   46.84 +        """Main routine for the thread.
   46.85 +        Reads the notifier and dispatches to channels.
   46.86 +        """
   46.87 +        while True:
   46.88 +            if self.thread == None: return
   46.89 +            port = self.notifier.read()
   46.90 +            if port:
   46.91 +                virq = self.virqPorts.get(port)
   46.92 +                if virq is not None:
   46.93 +                    self.virqReceived(virq)
   46.94 +                else:
   46.95 +                    self.msgReceived(port)
   46.96 +            else:
   46.97 +                select.select([self.notifier], [], [], 1.0)
   46.98 +
   46.99 +    def msgReceived(self, port):
  46.100 +        # We run the message handlers in their own threads.
  46.101 +        # Note we use keyword args to lambda to save the values -
  46.102 +        # otherwise lambda will use the variables, which will get
  46.103 +        # assigned by the loop and the lambda will get the changed values.
  46.104 +        received = 0
  46.105 +        for chan in self.channels.values():
  46.106 +            if self.thread == None: return
  46.107 +            msg = chan.readResponse()
  46.108 +            if msg:
  46.109 +                received += 1
  46.110 +                chan.responseReceived(msg)
  46.111 +        for chan in self.channels.values():
  46.112 +            if self.thread == None: return
  46.113 +            msg = chan.readRequest()
  46.114 +            if msg:
  46.115 +                received += 1
  46.116 +                self.runInThread(lambda chan=chan, msg=msg: chan.requestReceived(msg))
  46.117 +        if port and received == 0:
  46.118 +            log.warning("Port %s notified, but no messages found", port)
  46.119 +
  46.120 +    def runInThread(self, thunk):
  46.121 +        thread = threading.Thread(target = thunk)
  46.122 +        thread.setDaemon(True)
  46.123 +        thread.start()
  46.124 +
  46.125 +    def setVirqHandler(self, virqHandler):
  46.126 +        self.virqHandler = virqHandler
  46.127 +
  46.128 +    def virqReceived(self, virq):
  46.129 +        if 1 or DEBUG:
  46.130 +            print 'virqReceived>', virq
  46.131 +        if not self.virqHandler: return
  46.132 +        self.runInThread(lambda virq=virq: self.virqHandler(virq))
  46.133 +
  46.134 +    def newChannel(self, dom, local_port, remote_port):
  46.135 +        """Create a new channel.
  46.136 +        """
  46.137 +        return self.addChannel(Channel(self, dom, local_port, remote_port))
  46.138      
  46.139      def addChannel(self, channel):
  46.140 -        """Add a channel. Registers with the notifier.
  46.141 +        """Add a channel.
  46.142          """
  46.143 -        idx = channel.idx
  46.144 -        self.channels[idx] = channel
  46.145 -        self.notifier.bind(idx)
  46.146 -
  46.147 -    def getChannel(self, idx):
  46.148 -        """Get the channel with the given index (if any).
  46.149 -        """
  46.150 -        return self.channels.get(idx)
  46.151 +        self.channels[channel.getKey()] = channel
  46.152 +        return channel
  46.153  
  46.154 -    def delChannel(self, idx):
  46.155 -        """Remove the channel with the given index (if any).
  46.156 -        Deregisters with the notifier.
  46.157 +    def delChannel(self, channel):
  46.158 +        """Remove the channel.
  46.159          """
  46.160 -        if idx in self.channels:
  46.161 -            del self.channels[idx]
  46.162 -            self.notifier.unbind(idx)
  46.163 +        key = channel.getKey()
  46.164 +        if key in self.channels:
  46.165 +            del self.channels[key]
  46.166  
  46.167 -    def domChannel(self, dom, local_port=0, remote_port=0):
  46.168 -        """Get the channel for the given domain.
  46.169 -        Construct if necessary.
  46.170 +    def getChannel(self, dom, local_port, remote_port):
  46.171 +        """Get the channel with the given domain and ports (if any).
  46.172 +        """
  46.173 +        key = (dom, local_port, remote_port)
  46.174 +        return self.channels.get(key)
  46.175 +
  46.176 +    def findChannel(self, dom, local_port=0, remote_port=0):
  46.177 +        """Find a channel. Ports given as zero are wildcards.
  46.178  
  46.179          dom domain
  46.180  
  46.181          returns channel
  46.182          """
  46.183 -        chan = self.getDomChannel(dom)
  46.184 -        if not chan:
  46.185 -            chan = Channel(self, dom, local_port=local_port,
  46.186 -                           remote_port=remote_port)
  46.187 -            self.addChannel(chan)
  46.188 -        return chan
  46.189 -
  46.190 -    def getDomChannel(self, dom):
  46.191 -        """Get the channel for the given domain.
  46.192 -
  46.193 -        dom domain
  46.194 +        chan = self.getChannel(dom, local_port, remote_port)
  46.195 +        if chan: return chan
  46.196 +        if local_port and remote_port:
  46.197 +            return None
  46.198 +        for c in self.channels.values():
  46.199 +            if c.dom != dom: continue
  46.200 +            if local_port and local_port != c.getLocalPort(): continue
  46.201 +            if remote_port and remote_port != c.getRemotePort(): continue
  46.202 +            return c
  46.203 +        return None
  46.204  
  46.205 -        returns channel (or None)
  46.206 -        """
  46.207 -        dom = int(dom)
  46.208 -        for chan in self.channels.values():
  46.209 -            if not isinstance(chan, Channel): continue
  46.210 -            if chan.dom == dom:
  46.211 -                return chan
  46.212 -        return None
  46.213 -        
  46.214 -
  46.215 -    def virqChannel(self, virq):
  46.216 -        """Get the channel for the given virq.
  46.217 -        Construct if necessary.
  46.218 -        """
  46.219 -        for chan in self.channels.values():
  46.220 -            if not isinstance(chan, VirqChannel): continue
  46.221 -            if chan.virq == virq:
  46.222 -                return chan
  46.223 -        chan = VirqChannel(self, virq)
  46.224 -        self.addChannel(chan)
  46.225 -        return chan
  46.226 -
  46.227 -    def channelClosed(self, channel):
  46.228 -        """The given channel has been closed - remove it.
  46.229 -        """
  46.230 -        self.delChannel(channel.idx)
  46.231 +    def openChannel(self, dom, local_port=0, remote_port=0):
  46.232 +        return (self.findChannel(dom, local_port=local_port, remote_port=remote_port)
  46.233 +                or
  46.234 +                self.newChannel(dom, local_port, remote_port))
  46.235  
  46.236      def createPort(self, dom, local_port=0, remote_port=0):
  46.237          """Create a port for a channel to the given domain.
  46.238 @@ -147,122 +226,59 @@ def channelFactory():
  46.239          inst = ChannelFactory()
  46.240      return inst
  46.241  
  46.242 -class BaseChannel:
  46.243 -    """Abstract superclass for channels.
  46.244 -
  46.245 -    The subclass constructor must set idx to the port to use.
  46.246 +class Channel:
  46.247 +    """Chanel to a domain.
  46.248 +    Maintains a list of device handlers to dispatch requests to, based
  46.249 +    on the request type.
  46.250      """
  46.251  
  46.252 -    def __init__(self, factory):
  46.253 +    def __init__(self, factory, dom, local_port, remote_port):
  46.254          self.factory = factory
  46.255 -        self.idx = -1
  46.256 -        self.closed = 0
  46.257 +        self.dom = int(dom)
  46.258 +        # Registered device handlers.
  46.259 +        self.devs = []
  46.260 +        # Handlers indexed by the message types they handle.
  46.261 +        self.devs_by_type = {}
  46.262 +        self.port = self.factory.createPort(self.dom,
  46.263 +                                            local_port=local_port,
  46.264 +                                            remote_port=remote_port)
  46.265 +        self.closed = False
  46.266 +        # Queue of waiters for responses to requests.
  46.267 +        self.queue = ResponseQueue(self)
  46.268 +        # Make sure the port will deliver all the messages.
  46.269 +        self.port.register(TYPE_WILDCARD)
  46.270  
  46.271 -    def getIndex(self):
  46.272 -        """Get the channel index.
  46.273 +    def getKey(self):
  46.274 +        """Get the channel key.
  46.275          """
  46.276 -        return self.idx
  46.277 +        return (self.dom, self.getLocalPort(), self.getRemotePort())
  46.278  
  46.279 -    def notificationReceived(self):
  46.280 -        """Called when a notification is received.
  46.281 -        Calls handleNotification(), which should be defined
  46.282 -        in a subclass.
  46.283 -        """
  46.284 -        if self.closed: return
  46.285 -        self.handleNotification()
  46.286 +    def sxpr(self):
  46.287 +        val = ['channel']
  46.288 +        val.append(['domain', self.dom])
  46.289 +        if self.port:
  46.290 +            val.append(['local_port', self.port.local_port])
  46.291 +            val.append(['remote_port', self.port.remote_port])
  46.292 +        return val
  46.293  
  46.294      def close(self):
  46.295 -        """Close the channel. Calls channelClosed() on the factory.
  46.296 -        Override in subclass.
  46.297 -        """
  46.298 -        self.factory.channelClosed(self)
  46.299 -
  46.300 -    def handleNotification(self):
  46.301 -        """Handle notification.
  46.302 -        Define in subclass.
  46.303 -        """
  46.304 -        pass
  46.305 -        
  46.306 -
  46.307 -class VirqChannel(BaseChannel):
  46.308 -    """A channel for handling a virq.
  46.309 -    """
  46.310 -    
  46.311 -    def __init__(self, factory, virq):
  46.312 -        """Create a channel for the given virq using the given factory.
  46.313 -
  46.314 -        Do not call directly, use virqChannel on the factory.
  46.315 -        """
  46.316 -        BaseChannel.__init__(self, factory)
  46.317 -        self.virq = virq
  46.318 -        self.factory = factory
  46.319 -        # Notification port (int).
  46.320 -        #self.port = xc.evtchn_bind_virq(virq)
  46.321 -        self.port = factory.notifier.bind_virq(virq)
  46.322 -        self.idx = self.port
  46.323 -        # Clients to call when a virq arrives.
  46.324 -        self.clients = []
  46.325 -
  46.326 -    def __repr__(self):
  46.327 -        return ('<VirqChannel virq=%d port=%d>'
  46.328 -                % (self.virq, self.port))
  46.329 -
  46.330 -    def getVirq(self):
  46.331 -        """Get the channel's virq.
  46.332 -        """
  46.333 -        return self.virq
  46.334 -
  46.335 -    def close(self):
  46.336 -        """Close the channel. Calls lostChannel(self) on all its clients and
  46.337 -        channelClosed() on the factory.
  46.338 +        """Close the channel.
  46.339          """
  46.340 -        for c in self.clients[:]:
  46.341 -            c.lostChannel(self)
  46.342 -        self.clients = []
  46.343 -        BaseChannel.close(self)
  46.344 -
  46.345 -    def registerClient(self, client):
  46.346 -        """Register a client. The client will be called with
  46.347 -        client.virqReceived(virq) when a virq is received.
  46.348 -        The client will be called with client.lostChannel(self) if the
  46.349 -        channel is closed.
  46.350 -        """
  46.351 -        self.clients.append(client)
  46.352 -
  46.353 -    def handleNotification(self):
  46.354 -        for c in self.clients:
  46.355 -            c.virqReceived(self.virq)
  46.356 -
  46.357 -    def notify(self):
  46.358 -        # xc.evtchn_send(self.port)
  46.359 -        self.factory.notifier.virq_send(self.port)
  46.360 -
  46.361 +        if DEBUG:
  46.362 +            print 'Channel>close>', self
  46.363 +        if self.closed: return
  46.364 +        self.closed = True
  46.365 +        self.factory.delChannel(self)
  46.366 +        for d in self.devs[:]:
  46.367 +            d.lostChannel(self)
  46.368 +        self.devs = []
  46.369 +        self.devs_by_type = {}
  46.370 +        if self.port:
  46.371 +            self.port.close()
  46.372 +            #self.port = None
  46.373  
  46.374 -class Channel(BaseChannel):
  46.375 -    """A control channel to a domain. Messages for the domain device controllers
  46.376 -    are multiplexed over the channel (console, block devs, net devs).
  46.377 -    """
  46.378 -
  46.379 -    def __init__(self, factory, dom, local_port=0, remote_port=0):
  46.380 -        """Create a channel to the given domain using the given factory.
  46.381 -
  46.382 -        Do not call directly, use domChannel on the factory.
  46.383 -        """
  46.384 -        BaseChannel.__init__(self, factory)
  46.385 -        # Domain.
  46.386 -        self.dom = int(dom)
  46.387 -        # Domain port (object).
  46.388 -        self.port = self.factory.createPort(dom, local_port=local_port,
  46.389 -                                            remote_port=remote_port)
  46.390 -        # Channel port (int).
  46.391 -        self.idx = self.port.local_port
  46.392 -        # Registered devices.
  46.393 -        self.devs = []
  46.394 -        # Devices indexed by the message types they handle.
  46.395 -        self.devs_by_type = {}
  46.396 -        # Output queue.
  46.397 -        self.queue = []
  46.398 -        self.closed = 0
  46.399 +    def getDomain(self):
  46.400 +        return self.dom
  46.401  
  46.402      def getLocalPort(self):
  46.403          """Get the local port.
  46.404 @@ -282,178 +298,218 @@ class Channel(BaseChannel):
  46.405          if self.closed: return -1
  46.406          return self.port.remote_port
  46.407  
  46.408 -    def close(self):
  46.409 -        """Close the channel. Calls lostChannel() on all its devices and
  46.410 -        channelClosed() on the factory.
  46.411 -        """
  46.412 -        if self.closed: return
  46.413 -        self.closed = 1
  46.414 -        for d in self.devs[:]:
  46.415 -            d.lostChannel()
  46.416 -        self.factory.channelClosed(self)
  46.417 -        self.devs = []
  46.418 -        self.devs_by_type = {}
  46.419 -        self.port.disconnect()
  46.420 -
  46.421 -    def registerDevice(self, types, dev):
  46.422 -        """Register a device controller.
  46.423 -
  46.424 -        @param types: message types the controller handles
  46.425 -        @type  types: array of ints
  46.426 -        @param dev:   device controller
  46.427 -        """
  46.428 -        if self.closed: return
  46.429 -        self.devs.append(dev)
  46.430 -        for ty in types:
  46.431 -            self.devs_by_type[ty] = dev
  46.432 -        self.port.register(ty)
  46.433 -
  46.434 -    def deregisterDevice(self, dev):
  46.435 -        """Remove the registration for a device controller.
  46.436 -
  46.437 -        @param dev: device controller
  46.438 -        """
  46.439 -        if dev in self.devs:
  46.440 -            self.devs.remove(dev)
  46.441 -        types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
  46.442 -        for ty in types:
  46.443 -            del self.devs_by_type[ty]
  46.444 -            self.port.deregister(ty)
  46.445 -
  46.446 -    def getDevice(self, type):
  46.447 -        """Get the device controller handling a message type.
  46.448 -
  46.449 -        @param type: message type
  46.450 -        @type  type: int
  46.451 -        @return: controller or None
  46.452 -        @rtype:  device controller
  46.453 -        """
  46.454 -        return self.devs_by_type.get(type)
  46.455 -
  46.456 -    def getMessageType(self, msg):
  46.457 -        """Get a 2-tuple of the message type and subtype.
  46.458 -
  46.459 -        @param msg: message
  46.460 -        @type  msg: xu message
  46.461 -        @return: type info
  46.462 -        @rtype:  (int, int)
  46.463 -        """
  46.464 -        hdr = msg.get_header()
  46.465 -        return (hdr['type'], hdr.get('subtype'))
  46.466 -
  46.467      def __repr__(self):
  46.468          return ('<Channel dom=%d ports=%d:%d>'
  46.469                  % (self.dom,
  46.470                     self.getLocalPort(),
  46.471                     self.getRemotePort()))
  46.472  
  46.473 -    def handleNotification(self):
  46.474 -        """Process outstanding messages in repsonse to notification on the port.
  46.475 -        """
  46.476 -        if self.closed:
  46.477 -            print 'handleNotification> Notification on closed channel', self
  46.478 -            return
  46.479 -        work = 0
  46.480 -        work += self.handleRequests()
  46.481 -        work += self.handleResponses()
  46.482 -        work += self.handleWrites()
  46.483 -        if work:
  46.484 -            self.notify()
  46.485 +
  46.486 +    def registerDevice(self, types, dev):
  46.487 +        """Register a device message handler.
  46.488  
  46.489 -    def notify(self):
  46.490 -        """Notify the other end of the port that messages have been processed.
  46.491 +        @param types: message types handled
  46.492 +        @type  types: array of ints
  46.493 +        @param dev:   device handler
  46.494          """
  46.495          if self.closed: return
  46.496 -        self.port.notify()
  46.497 +        self.devs.append(dev)
  46.498 +        for ty in types:
  46.499 +            self.devs_by_type[ty] = dev
  46.500 +
  46.501 +    def deregisterDevice(self, dev):
  46.502 +        """Remove the registration for a device handler.
  46.503  
  46.504 -    def handleRequests(self):
  46.505 -        work = 0
  46.506 -        while 1:
  46.507 -            msg = self.readRequest()
  46.508 -            if not msg: break
  46.509 -            self.requestReceived(msg)
  46.510 -            work += 1
  46.511 -        return work
  46.512 +        @param dev: device handler
  46.513 +        """
  46.514 +        if dev in self.devs:
  46.515 +            self.devs.remove(dev)
  46.516 +        types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
  46.517 +        for ty in types:
  46.518 +            del self.devs_by_type[ty]
  46.519 +
  46.520 +    def getDevice(self, type):
  46.521 +        """Get the handler for a message type.
  46.522 +
  46.523 +        @param type: message type
  46.524 +        @type  type: int
  46.525 +        @return: controller or None
  46.526 +        @rtype:  device handler
  46.527 +        """
  46.528 +        return self.devs_by_type.get(type)
  46.529  
  46.530      def requestReceived(self, msg):
  46.531 -        (ty, subty) = self.getMessageType(msg)
  46.532 -        #todo:  Must respond before writing any more messages.
  46.533 -        #todo:  Should automate this (respond on write)
  46.534 -        responded = 0
  46.535 +        """A request has been received on the channel.
  46.536 +        Disptach it to the device handlers.
  46.537 +        Called from the channel factory thread.
  46.538 +        """
  46.539 +        if DEBUG:
  46.540 +            print 'Channel>requestReceived>', self,
  46.541 +            printMsg(msg)
  46.542 +        (ty, subty) = getMessageType(msg)
  46.543 +        responded = False
  46.544          dev = self.getDevice(ty)
  46.545          if dev:
  46.546              responded = dev.requestReceived(msg, ty, subty)
  46.547 +        elif DEBUG:
  46.548 +            print "Channel>requestReceived> No device handler", self,
  46.549 +            printMsg(msg)
  46.550          else:
  46.551 -            print ("requestReceived> No device: Message type %s %d:%d"
  46.552 -                   % (msgTypeName(ty, subty), ty, subty)), self
  46.553 +            pass
  46.554          if not responded:
  46.555 -            self.port.write_response(msg)
  46.556 -
  46.557 -    def handleResponses(self):
  46.558 -        work = 0
  46.559 -        while 1:
  46.560 -            msg = self.readResponse()
  46.561 -            if not msg: break
  46.562 -            self.responseReceived(msg)
  46.563 -            work += 1
  46.564 -        return work
  46.565 -
  46.566 -    def responseReceived(self, msg):
  46.567 -        (ty, subty) = self.getMessageType(msg)
  46.568 -        dev = self.getDevice(ty)
  46.569 -        if dev:
  46.570 -            dev.responseReceived(msg, ty, subty)
  46.571 -        else:
  46.572 -            print ("responseReceived> No device: Message type %d:%d"
  46.573 -                   % (msgTypeName(ty, subty), ty, subty)), self
  46.574 +            self.writeResponse(msg)
  46.575  
  46.576 -    def handleWrites(self):
  46.577 -        work = 0
  46.578 -        # Pull data from producers.
  46.579 -        for dev in self.devs:
  46.580 -            work += dev.produceRequests()
  46.581 -        # Flush the queue.
  46.582 -        while self.queue and self.port.space_to_write_request():
  46.583 -            msg = self.queue.pop(0)
  46.584 -            self.port.write_request(msg)
  46.585 -            work += 1
  46.586 -        return work
  46.587 -
  46.588 -    def writeRequest(self, msg, notify=1):
  46.589 -        if self.closed:
  46.590 -            val = -1
  46.591 -        elif self.writeReady():
  46.592 -            self.port.write_request(msg)
  46.593 -            if notify: self.notify()
  46.594 -            val = 1
  46.595 -        else:
  46.596 -            self.queue.append(msg)
  46.597 -            val = 0
  46.598 -        return val
  46.599 +    def writeRequest(self, msg):
  46.600 +        """Write a request to the channel.
  46.601 +        """
  46.602 +        if DEBUG:
  46.603 +            print 'Channel>writeRequest>', self,
  46.604 +            printMsg(msg, all=True)
  46.605 +        if self.closed: return -1
  46.606 +        self.port.write_request(msg)
  46.607 +        return 1
  46.608  
  46.609      def writeResponse(self, msg):
  46.610 -        if self.closed: return -1
  46.611 -        self.port.write_response(msg)
  46.612 +        """Write a response to the channel.
  46.613 +        """
  46.614 +        if DEBUG:
  46.615 +            print 'Channel>writeResponse>', self,
  46.616 +            printMsg(msg, all=True)
  46.617 +        if self.port:
  46.618 +            self.port.write_response(msg)
  46.619          return 1
  46.620  
  46.621 -    def writeReady(self):
  46.622 -        if self.closed or self.queue: return 0
  46.623 -        return self.port.space_to_write_request()
  46.624 -
  46.625      def readRequest(self):
  46.626 +        """Read a request from the channel.
  46.627 +        Called internally.
  46.628 +        """
  46.629          if self.closed:
  46.630 -            return None
  46.631 -        if self.port.request_to_read():
  46.632 +            val =  None
  46.633 +        else:
  46.634              val = self.port.read_request()
  46.635 -        else:
  46.636 -            val = None
  46.637          return val
  46.638          
  46.639      def readResponse(self):
  46.640 +        """Read a response from the channel.
  46.641 +        Called internally.
  46.642 +        """
  46.643 +        if self.closed:
  46.644 +            val = None
  46.645 +        else:
  46.646 +            val = self.port.read_response()
  46.647 +        if DEBUG and val:
  46.648 +            print 'Channel>readResponse>', self,
  46.649 +            printMsg(val, all=True)
  46.650 +        return val
  46.651 +
  46.652 +    def requestResponse(self, msg, timeout=None):
  46.653 +        """Write a request and wait for a response.
  46.654 +        Raises IOError on timeout.
  46.655 +
  46.656 +        @param msg request message
  46.657 +        @param timeout timeout (0 is forever)
  46.658 +        @return response message
  46.659 +        """
  46.660 +        if self.closed:
  46.661 +            raise IOError("closed")
  46.662          if self.closed:
  46.663              return None
  46.664 -        if self.port.response_to_read():
  46.665 -            val = self.port.read_response()
  46.666 +        if timeout is None:
  46.667 +            timeout = RESPONSE_TIMEOUT
  46.668 +        elif timeout <= 0:
  46.669 +            timeout = None
  46.670 +        return self.queue.call(msg, timeout)
  46.671 +
  46.672 +    def responseReceived(self, msg):
  46.673 +        """A response has been received, look for a waiter to
  46.674 +        give it to.
  46.675 +        Called internally.
  46.676 +        """
  46.677 +        if DEBUG:
  46.678 +            print 'Channel>responseReceived>', self,
  46.679 +            printMsg(msg)
  46.680 +        self.queue.response(getMessageId(msg), msg)
  46.681 +
  46.682 +    def virq(self):
  46.683 +        self.factory.virq()
  46.684 +
  46.685 +class Response:
  46.686 +    """Entry in the response queue.
  46.687 +    Used to signal a response to a message.
  46.688 +    """
  46.689 +
  46.690 +    def __init__(self, mid):
  46.691 +        self.mid = mid
  46.692 +        self.msg = None
  46.693 +        self.ready = threading.Event()
  46.694 +
  46.695 +    def response(self, msg):
  46.696 +        """Signal arrival of a response to a waiting thread.
  46.697 +        Passing msg None cancels the wait with an IOError.
  46.698 +        """
  46.699 +        if msg:
  46.700 +            self.msg = msg
  46.701          else:
  46.702 -            val = None
  46.703 -        return val
  46.704 +            self.mid = -1
  46.705 +        self.ready.set()
  46.706 +
  46.707 +    def wait(self, timeout):
  46.708 +        """Wait up to 'timeout' seconds for a response.
  46.709 +        Returns the response or raises an IOError.
  46.710 +        """
  46.711 +        self.ready.wait(timeout)
  46.712 +        if self.mid < 0:
  46.713 +            raise IOError("wait canceled")
  46.714 +        if self.msg is None:
  46.715 +            raise IOError("response timeout")
  46.716 +        return self.msg
  46.717 +
  46.718 +class ResponseQueue:
  46.719 +    """Response queue. Manages waiters for responses to messages.
  46.720 +    """
  46.721 +
  46.722 +    def __init__(self, channel):
  46.723 +        self.channel = channel
  46.724 +        self.lock = threading.Lock()
  46.725 +        self.responses = {}
  46.726 +
  46.727 +    def add(self, mid):
  46.728 +        r = Response(mid)
  46.729 +        self.responses[mid] = r
  46.730 +        return r
  46.731 +
  46.732 +    def get(self, mid):
  46.733 +        return self.responses.get(mid)
  46.734 +
  46.735 +    def remove(self, mid):
  46.736 +        r = self.responses.get(mid)
  46.737 +        if r:
  46.738 +            del self.responses[mid]
  46.739 +        return r
  46.740 +
  46.741 +    def response(self, mid, msg):
  46.742 +        """Process a response - signals any waiter that a response
  46.743 +        has arrived.
  46.744 +        """
  46.745 +        try:
  46.746 +            self.lock.acquire()
  46.747 +            r = self.remove(mid)
  46.748 +        finally:
  46.749 +            self.lock.release()
  46.750 +        if r:
  46.751 +            r.response(msg)
  46.752 +
  46.753 +    def call(self, msg, timeout):
  46.754 +        """Send the message and wait for 'timeout' seconds for a response.
  46.755 +        Returns the response.
  46.756 +        Raises IOError on timeout.
  46.757 +        """
  46.758 +        mid = getMessageId(msg)
  46.759 +        try:
  46.760 +            self.lock.acquire()
  46.761 +            r = self.add(mid)
  46.762 +        finally:
  46.763 +            self.lock.release()
  46.764 +        self.channel.writeRequest(msg)
  46.765 +        return r.wait(timeout)
  46.766 +                
    47.1 --- a/tools/python/xen/xend/server/console.py	Thu Apr 28 08:56:40 2005 +0000
    47.2 +++ b/tools/python/xen/xend/server/console.py	Thu Apr 28 10:46:53 2005 +0000
    47.3 @@ -1,52 +1,54 @@
    47.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    47.5  
    47.6  import socket
    47.7 -
    47.8 -from twisted.internet import reactor
    47.9 -from twisted.internet import protocol
   47.10 +import threading
   47.11 +from errno import EAGAIN, EINTR, EWOULDBLOCK
   47.12 +    
   47.13 +from xen.web import reactor, protocol
   47.14  
   47.15  from xen.lowlevel import xu
   47.16  
   47.17  from xen.xend.XendError import XendError
   47.18 -from xen.xend import EventServer
   47.19 -eserver = EventServer.instance()
   47.20 +from xen.xend import EventServer; eserver = EventServer.instance()
   47.21  from xen.xend.XendLogging import log
   47.22 -from xen.xend import XendRoot
   47.23 -xroot = XendRoot.instance()
   47.24 +from xen.xend import XendRoot; xroot = XendRoot.instance()
   47.25 +from xen.xend import sxp
   47.26  
   47.27 -import controller
   47.28 +from controller import CtrlMsgRcvr, Dev, DevController
   47.29  from messages import *
   47.30  from params import *
   47.31  
   47.32  class ConsoleProtocol(protocol.Protocol):
   47.33 -    """Asynchronous handler for a console TCP socket.
   47.34 +    """Asynchronous handler for a console socket.
   47.35      """
   47.36  
   47.37 -    def __init__(self, controller, idx):
   47.38 -        self.controller = controller
   47.39 -        self.idx = idx
   47.40 +    def __init__(self, console, id):
   47.41 +        self.console = console
   47.42 +        self.id = id
   47.43          self.addr = None
   47.44 -        self.binary = 0
   47.45  
   47.46 -    def connectionMade(self):
   47.47 +    def connectionMade(self, addr=None):
   47.48          peer = self.transport.getPeer()
   47.49 -        self.addr = (peer.host, peer.port)
   47.50 -        if self.controller.connect(self.addr, self):
   47.51 +        self.addr = addr
   47.52 +        if self.console.connect(self.addr, self):
   47.53              self.transport.write("Cannot connect to console %d on domain %d\n"
   47.54 -                                 % (self.idx, self.controller.dom))
   47.55 +                                 % (self.id, self.console.getDomain()))
   47.56              self.loseConnection()
   47.57              return
   47.58          else:
   47.59 -            # KAF: A nice quiet successful connect.
   47.60 -            #self.transport.write("Connected to console %d on domain %d\n"
   47.61 -            #                     % (self.idx, self.controller.dom))
   47.62 +            if len(self.addr) == 2:
   47.63 +                host = str(self.addr[0])
   47.64 +                port = str(self.addr[1])
   47.65 +            else:
   47.66 +                host = 'localhost'
   47.67 +                port = str(addr)
   47.68              log.info("Console connected %s %s %s",
   47.69 -                     self.idx, str(self.addr[0]), str(self.addr[1]))
   47.70 +                     self.id, host, port)
   47.71              eserver.inject('xend.console.connect',
   47.72 -                           [self.idx, self.addr[0], self.addr[1]])
   47.73 +                           [self.id, host, port])
   47.74  
   47.75      def dataReceived(self, data):
   47.76 -        if self.controller.handleInput(self, data):
   47.77 +        if self.console.receiveInput(self, data):
   47.78              self.loseConnection()
   47.79  
   47.80      def write(self, data):
   47.81 @@ -55,55 +57,17 @@ class ConsoleProtocol(protocol.Protocol)
   47.82  
   47.83      def connectionLost(self, reason=None):
   47.84          log.info("Console disconnected %s %s %s",
   47.85 -                 self.idx, str(self.addr[0]), str(self.addr[1]))
   47.86 +                 str(self.id), str(self.addr[0]), str(self.addr[1]))
   47.87          eserver.inject('xend.console.disconnect',
   47.88 -                       [self.idx, self.addr[0], self.addr[1]])
   47.89 -        self.controller.disconnect(conn=self)
   47.90 +                       [self.id, self.addr[0], self.addr[1]])
   47.91 +        self.console.disconnect(conn=self)
   47.92  
   47.93      def loseConnection(self):
   47.94          self.transport.loseConnection()
   47.95  
   47.96 -class ConsoleFactory(protocol.ServerFactory):
   47.97 -    """Asynchronous handler for a console server socket.
   47.98 -    """
   47.99 -    protocol = ConsoleProtocol
  47.100 -    
  47.101 -    def __init__(self, controller, idx):
  47.102 -        #protocol.ServerFactory.__init__(self)
  47.103 -        self.controller = controller
  47.104 -        self.idx = idx
  47.105 -
  47.106 -    def buildProtocol(self, addr):
  47.107 -        proto = self.protocol(self.controller, self.idx)
  47.108 -        proto.factory = self
  47.109 -        return proto
  47.110 -
  47.111 -class ConsoleControllerFactory(controller.ControllerFactory):
  47.112 -    """Factory for creating console controllers.
  47.113 -    """
  47.114 -
  47.115 -    def createController(self, dom, console_port=None):
  47.116 -        if console_port is None:
  47.117 -            console_port = xroot.get_console_port_base() + dom
  47.118 -        for c in self.getControllers():
  47.119 -            if c.console_port == console_port:
  47.120 -                raise XendError('console port in use: ' + str(console_port))
  47.121 -        console = ConsoleController(self, dom, console_port)
  47.122 -        self.addController(console)
  47.123 -        log.info("Created console id=%s domain=%d port=%d",
  47.124 -                 console.idx, console.dom, console.console_port)
  47.125 -        eserver.inject('xend.console.create',
  47.126 -                       [console.idx, console.dom, console.console_port])
  47.127 -        return console
  47.128 -        
  47.129 -    def consoleClosed(self, console):
  47.130 -        log.info("Closed console id=%s", console.idx)
  47.131 -        eserver.inject('xend.console.close', console.idx)
  47.132 -        self.delController(console)
  47.133 -
  47.134 -class ConsoleController(controller.Controller):
  47.135 -    """Console controller for a domain.
  47.136 -    Does not poll for i/o itself, but relies on the notifier to post console
  47.137 +class ConsoleDev(Dev, protocol.ServerFactory):
  47.138 +    """Console device for a domain.
  47.139 +    Does not poll for i/o itself, but relies on the domain to post console
  47.140      output and the connected TCP sockets to post console input.
  47.141      """
  47.142  
  47.143 @@ -112,43 +76,85 @@ class ConsoleController(controller.Contr
  47.144      STATUS_CONNECTED = 'connected'
  47.145      STATUS_LISTENING = 'listening'
  47.146  
  47.147 -    def __init__(self, factory, dom, console_port):
  47.148 -        controller.Controller.__init__(self, factory, dom)
  47.149 -        self.addMethod(CMSG_CONSOLE, 0, None)
  47.150 +    def __init__(self, controller, id, config, recreate=False):
  47.151 +        Dev.__init__(self, controller, id, config)
  47.152 +        self.lock = threading.RLock()
  47.153          self.status = self.STATUS_NEW
  47.154          self.addr = None
  47.155          self.conn = None
  47.156 -        self.rbuf = xu.buffer()
  47.157 -        self.wbuf = xu.buffer()
  47.158 +        self.console_port = None
  47.159 +        self.obuf = xu.buffer()
  47.160 +        self.ibuf = xu.buffer()
  47.161 +        self.channel = None
  47.162 +        self.listening = False
  47.163 +        self.unix_listener = None
  47.164 +        self.tcp_listener = None
  47.165 +        
  47.166 +        console_port = sxp.child_value(self.config, "console_port")
  47.167 +        if console_port is None:
  47.168 +            console_port = xroot.get_console_port_base() + self.getDomain()
  47.169 +        self.checkConsolePort(console_port)
  47.170          self.console_port = console_port
  47.171 +        
  47.172 +        log.info("Created console id=%d domain=%d port=%d",
  47.173 +                 self.id, self.getDomain(), self.console_port)
  47.174 +        eserver.inject('xend.console.create',
  47.175 +                       [self.id, self.getDomain(), self.console_port])
  47.176  
  47.177 -        self.registerChannel()
  47.178 -        self.listener = None
  47.179 -        self.listen()
  47.180 +    def init(self, recreate=False, reboot=False):
  47.181 +        try:
  47.182 +            self.lock.acquire()
  47.183 +            self.destroyed = False
  47.184 +            self.channel = self.getChannel()
  47.185 +            self.listen()
  47.186 +        finally:
  47.187 +            self.lock.release()
  47.188  
  47.189 +    def checkConsolePort(self, console_port):
  47.190 +        """Check that a console port is not in use by another console.
  47.191 +        """
  47.192 +        xd = XendRoot.get_component('xen.xend.XendDomain')
  47.193 +        for vm in xd.domains():
  47.194 +            ctrl = vm.getDeviceController(self.getType(), error=False)
  47.195 +            if (not ctrl): continue
  47.196 +            ctrl.checkConsolePort(console_port)
  47.197 +    
  47.198      def sxpr(self):
  47.199 -        val = ['console',
  47.200 -               ['status', self.status ],
  47.201 -               ['id',     self.idx    ],
  47.202 -               ['domain', self.dom    ] ]
  47.203 -        val.append(['local_port',   self.getLocalPort()  ])
  47.204 -        val.append(['remote_port',  self.getRemotePort() ])
  47.205 -        val.append(['console_port', self.console_port    ])
  47.206 -        if self.addr:
  47.207 -            val.append(['connected', self.addr[0], self.addr[1]])
  47.208 +        try:
  47.209 +            self.lock.acquire()
  47.210 +            val = ['console',
  47.211 +                   ['status', self.status ],
  47.212 +                   ['id',     self.id    ],
  47.213 +                   ['domain', self.getDomain() ] ]
  47.214 +            val.append(['local_port',   self.getLocalPort()  ])
  47.215 +            val.append(['remote_port',  self.getRemotePort() ])
  47.216 +            val.append(['console_port', self.console_port    ])
  47.217 +            val.append(['index', self.getIndex()])
  47.218 +            if self.addr:
  47.219 +                val.append(['connected', self.addr[0], self.addr[1]])
  47.220 +        finally:
  47.221 +            self.lock.release()
  47.222          return val
  47.223  
  47.224      def getLocalPort(self):
  47.225 -        if self.channel:
  47.226 -            return self.channel.getLocalPort()
  47.227 -        else:
  47.228 -            return 0
  47.229 +        try:
  47.230 +            self.lock.acquire()
  47.231 +            if self.channel:
  47.232 +                return self.channel.getLocalPort()
  47.233 +            else:
  47.234 +                return 0
  47.235 +        finally:
  47.236 +            self.lock.release()
  47.237  
  47.238      def getRemotePort(self):
  47.239 -        if self.channel:
  47.240 -            return self.channel.getRemotePort()
  47.241 -        else:
  47.242 -            return 0
  47.243 +        try:
  47.244 +            self.lock.acquire()
  47.245 +            if self.channel:
  47.246 +                return self.channel.getRemotePort()
  47.247 +            else:
  47.248 +                return 0
  47.249 +        finally:
  47.250 +            self.lock.release()
  47.251  
  47.252      def uri(self):
  47.253          """Get the uri to use to connect to the console.
  47.254 @@ -159,42 +165,61 @@ class ConsoleController(controller.Contr
  47.255          host = socket.gethostname()
  47.256          return "telnet://%s:%d" % (host, self.console_port)
  47.257  
  47.258 -    def ready(self):
  47.259 -        return not (self.closed() or self.rbuf.empty())
  47.260 -
  47.261      def closed(self):
  47.262          return self.status == self.STATUS_CLOSED
  47.263  
  47.264      def connected(self):
  47.265          return self.status == self.STATUS_CONNECTED
  47.266  
  47.267 -    def close(self):
  47.268 -        """Close the console controller.
  47.269 +    def destroy(self, change=False, reboot=False):
  47.270 +        """Close the console.
  47.271          """
  47.272 -        self.lostChannel()
  47.273 -
  47.274 -    def lostChannel(self):
  47.275 -        """The channel to the domain has been lost.
  47.276 -        Cleanup: disconnect TCP connections and listeners, notify the controller.
  47.277 -        """
  47.278 -        self.status = self.STATUS_CLOSED
  47.279 -        if self.conn:
  47.280 -            self.conn.loseConnection()
  47.281 -        self.listener.stopListening()
  47.282 -        controller.Controller.lostChannel(self)
  47.283 +        print 'ConsoleDev>destroy>', self, reboot
  47.284 +        if reboot:
  47.285 +            return
  47.286 +        try:
  47.287 +            self.lock.acquire()
  47.288 +            self.status = self.STATUS_CLOSED
  47.289 +            self.listening = False
  47.290 +            if self.conn:
  47.291 +                self.conn.loseConnection()
  47.292 +            if self.tcp_listener:
  47.293 +                self.tcp_listener.stopListening()
  47.294 +                self.tcp_listener = None
  47.295 +            if self.unix_listener:
  47.296 +                self.unix_listener.stopListening()
  47.297 +                self.unix_listener = None
  47.298 +        finally:
  47.299 +            self.lock.release()
  47.300  
  47.301      def listen(self):
  47.302          """Listen for TCP connections to the console port..
  47.303          """
  47.304 -        if self.closed(): return
  47.305 -        self.status = self.STATUS_LISTENING
  47.306 -        if self.listener:
  47.307 -            #self.listener.startListening()
  47.308 -            pass
  47.309 -        else:
  47.310 -            f = ConsoleFactory(self, self.idx)
  47.311 -            interface = xroot.get_console_address()
  47.312 -            self.listener = reactor.listenTCP(self.console_port, f, interface=interface)
  47.313 +        try:
  47.314 +            self.lock.acquire()
  47.315 +            if self.closed():
  47.316 +                return
  47.317 +            if self.listening:
  47.318 +                pass
  47.319 +            else:
  47.320 +                self.listening = True
  47.321 +                self.status = self.STATUS_LISTENING
  47.322 +                if xroot.get_xend_unix_server():
  47.323 +                    path = '/var/lib/xend/console-%s' % self.console_port
  47.324 +                    self.unix_listener = reactor.listenUNIX(path, self)
  47.325 +                if xroot.get_xend_http_server():
  47.326 +                    interface = xroot.get_console_address()
  47.327 +                    self.tcp_listener = reactor.listenTCP(self.console_port, self, interface=interface)
  47.328 +        finally:
  47.329 +            self.lock.release()
  47.330 +
  47.331 +    def buildProtocol(self, addr):
  47.332 +        """Factory function called to create the protocol when a connection is accepted
  47.333 +        by listenTCP.
  47.334 +        """
  47.335 +        proto = ConsoleProtocol(self, self.id)
  47.336 +        proto.factory = self
  47.337 +        return proto
  47.338  
  47.339      def connect(self, addr, conn):
  47.340          """Connect a TCP connection to the console.
  47.341 @@ -205,84 +230,158 @@ class ConsoleController(controller.Contr
  47.342  
  47.343          returns 0 if ok, negative otherwise
  47.344          """
  47.345 -        if self.closed(): return -1
  47.346 -        if self.connected(): return -1
  47.347 -        self.addr = addr
  47.348 -        self.conn = conn
  47.349 -        self.status = self.STATUS_CONNECTED
  47.350 -        self.handleOutput()
  47.351 +        try:
  47.352 +            self.lock.acquire()
  47.353 +            if self.closed():
  47.354 +                return -1
  47.355 +            if self.connected():
  47.356 +                return -1
  47.357 +            self.addr = addr
  47.358 +            self.conn = conn
  47.359 +            self.status = self.STATUS_CONNECTED
  47.360 +            self.writeOutput()
  47.361 +        finally:
  47.362 +            self.lock.release()
  47.363          return 0
  47.364  
  47.365      def disconnect(self, conn=None):
  47.366          """Disconnect the TCP connection to the console.
  47.367          """
  47.368 -        if conn and conn != self.conn: return
  47.369 -        if self.conn:
  47.370 -            self.conn.loseConnection()
  47.371 -        self.addr = None
  47.372 -        self.conn = None
  47.373 -        self.listen()
  47.374 -
  47.375 -    def requestReceived(self, msg, type, subtype):
  47.376 -        """Receive console data from the console channel.
  47.377 +        print 'ConsoleDev>disconnect>', conn
  47.378 +        try:
  47.379 +            self.lock.acquire()
  47.380 +            if conn and conn != self.conn: return
  47.381 +            if self.conn:
  47.382 +                self.conn.loseConnection()
  47.383 +            self.addr = None
  47.384 +            self.conn = None
  47.385 +            self.status = self.STATUS_LISTENING
  47.386 +            self.listen()
  47.387 +        finally:
  47.388 +            self.lock.release()
  47.389  
  47.390 -        msg     console message
  47.391 -        type    major message type
  47.392 -        subtype minor message typ
  47.393 -        """
  47.394 -        self.rbuf.write(msg.get_payload())
  47.395 -        self.handleOutput()
  47.396 -        
  47.397 -    def responseReceived(self, msg, type, subtype):
  47.398 -        """Handle a response to a request written to the console channel.
  47.399 -        Just ignore it because the return values are not interesting.
  47.400 +    def receiveOutput(self, msg):
  47.401 +        """Receive output console data from the console channel.
  47.402  
  47.403          msg     console message
  47.404          type    major message type
  47.405          subtype minor message typ
  47.406          """
  47.407 -        pass
  47.408 -
  47.409 -    def produceRequests(self):
  47.410 -        """Write pending console data to the console channel.
  47.411 -        Writes as much to the channel as it can.
  47.412 +        # Treat the obuf as a ring buffer.
  47.413 +        try:
  47.414 +            self.lock.acquire()
  47.415 +            data = msg.get_payload()
  47.416 +            data_n = len(data)
  47.417 +            if self.obuf.space() < data_n:
  47.418 +                self.obuf.discard(data_n)
  47.419 +            if self.obuf.space() < data_n:
  47.420 +                data = data[-self.obuf.space():]
  47.421 +            self.obuf.write(data)
  47.422 +            self.writeOutput()
  47.423 +        finally:
  47.424 +            self.lock.release()
  47.425 +        
  47.426 +    def writeOutput(self):
  47.427 +        """Handle buffered output from the console device.
  47.428 +        Sends it to the connected TCP connection (if any).
  47.429          """
  47.430 -        work = 0
  47.431 -        while self.channel and not self.wbuf.empty() and self.channel.writeReady():
  47.432 -            msg = xu.message(CMSG_CONSOLE, 0, 0)
  47.433 -            msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
  47.434 -            work += self.channel.writeRequest(msg, notify=0)
  47.435 -        return work
  47.436 -
  47.437 -    def handleInput(self, conn, data):
  47.438 -        """Handle some external input aimed at the console.
  47.439 -        Called from a TCP connection (conn). Ignores the input
  47.440 -        if the calling connection (conn) is not the one connected
  47.441 -        to the console (self.conn).
  47.442 +        try:
  47.443 +            self.lock.acquire()
  47.444 +            if self.closed():
  47.445 +                return -1
  47.446 +            writes = 0
  47.447 +            while self.conn and (writes < 100) and (not self.obuf.empty()):
  47.448 +                try:
  47.449 +                    writes += 1
  47.450 +                    bytes = self.conn.write(self.obuf.peek())
  47.451 +                    if bytes > 0:
  47.452 +                        self.obuf.discard(bytes)
  47.453 +                except socket.error, err:
  47.454 +                    if err.args[0] in (EWOULDBLOCK, EAGAIN, EINTR):
  47.455 +                        pass
  47.456 +                    else:
  47.457 +                        self.disconnect()
  47.458 +                        break
  47.459 +                        
  47.460 +        finally:
  47.461 +            self.lock.release()
  47.462 +        return 0
  47.463 +    
  47.464 +    def receiveInput(self, conn, data):
  47.465 +        """Receive console input from a TCP connection.  Ignores the
  47.466 +        input if the calling connection (conn) is not the one
  47.467 +        connected to the console (self.conn).
  47.468  
  47.469          conn connection
  47.470          data input data
  47.471          """
  47.472 -        if self.closed(): return -1
  47.473 -        if conn != self.conn: return 0
  47.474 -        self.wbuf.write(data)
  47.475 -        if self.channel and self.produceRequests():
  47.476 -            self.channel.notify()
  47.477 +        try:
  47.478 +            self.lock.acquire()
  47.479 +            if self.closed(): return -1
  47.480 +            if conn != self.conn: return 0
  47.481 +            self.ibuf.write(data)
  47.482 +            self.writeInput()
  47.483 +        finally:
  47.484 +            self.lock.release()
  47.485          return 0
  47.486  
  47.487 -    def handleOutput(self):
  47.488 -        """Handle buffered output from the console.
  47.489 -        Sends it to the connected console (if any).
  47.490 +    def writeInput(self):
  47.491 +        """Write pending console input to the console channel.
  47.492 +        Writes as much to the channel as it can.
  47.493          """
  47.494 -        if self.closed():
  47.495 -            return -1
  47.496 -        if not self.conn:
  47.497 -            return 0
  47.498 -        while not self.rbuf.empty():
  47.499 -            try:
  47.500 -                bytes = self.conn.write(self.rbuf.peek())
  47.501 -                if bytes > 0:
  47.502 -                    self.rbuf.discard(bytes)
  47.503 -            except socket.error, error:
  47.504 -                pass
  47.505 -        return 0
  47.506 +        try:
  47.507 +            self.lock.acquire()
  47.508 +            while self.channel and not self.ibuf.empty():
  47.509 +                msg = xu.message(CMSG_CONSOLE, 0, 0)
  47.510 +                msg.append_payload(self.ibuf.read(msg.MAX_PAYLOAD))
  47.511 +                self.channel.writeRequest(msg)
  47.512 +        finally:
  47.513 +            self.lock.release()
  47.514 +
  47.515 +class ConsoleController(DevController):
  47.516 +    """Device controller for all the consoles for a domain.
  47.517 +    """
  47.518 +
  47.519 +    def __init__(self, vm, recreate=False):
  47.520 +        DevController.__init__(self, vm, recreate=recreate)
  47.521 +        self.rcvr = None
  47.522 +
  47.523 +    def initController(self, recreate=False, reboot=False):
  47.524 +        self.destroyed = False
  47.525 +        self.rcvr = CtrlMsgRcvr(self.getChannel())
  47.526 +        self.rcvr.addHandler(CMSG_CONSOLE,
  47.527 +                             0,
  47.528 +                             self.receiveOutput)
  47.529 +        self.rcvr.registerChannel()
  47.530 +        if reboot:
  47.531 +            self.rebootDevices()
  47.532 +
  47.533 +    def destroyController(self, reboot=False):
  47.534 +        print 'ConsoleController>destroyController>', self, reboot
  47.535 +        self.destroyed = True
  47.536 +        self.destroyDevices(reboot=reboot)
  47.537 +        self.rcvr.deregisterChannel()
  47.538 +
  47.539 +    def newDevice(self, id, config, recreate=False):
  47.540 +        return ConsoleDev(self, id, config, recreate=recreate)
  47.541 +
  47.542 +    def checkConsolePort(self, console_port):
  47.543 +        """Check that a console port is not in use by a console.
  47.544 +        """
  47.545 +        for c in self.getDevices():
  47.546 +            if c.console_port == console_port:
  47.547 +                raise XendError('console port in use: ' + str(console_port))
  47.548 +
  47.549 +    def receiveOutput(self, msg):
  47.550 +        """Handle a control request.
  47.551 +        The CMSG_CONSOLE messages just contain data, and no console id,
  47.552 +        so just send to console 0 (if there is one).
  47.553 +
  47.554 +        todo: extend CMSG_CONSOLE to support more than one console?
  47.555 +        """
  47.556 +        console = self.getDevice(0)
  47.557 +        if console:
  47.558 +            console.receiveOutput(msg)
  47.559 +        else:
  47.560 +            log.warning('no console: domain %d', self.getDomain())
  47.561 +
    48.1 --- a/tools/python/xen/xend/server/controller.py	Thu Apr 28 08:56:40 2005 +0000
    48.2 +++ b/tools/python/xen/xend/server/controller.py	Thu Apr 28 10:46:53 2005 +0000
    48.3 @@ -3,84 +3,29 @@
    48.4  for a domain.
    48.5  """
    48.6  
    48.7 -from twisted.internet import defer
    48.8 -#defer.Deferred.debug = 1
    48.9 -
   48.10 -import channel
   48.11 -from messages import msgTypeName, printMsg
   48.12 +from xen.xend.XendError import XendError
   48.13 +from messages import msgTypeName, printMsg, getMessageType
   48.14  
   48.15  DEBUG = 0
   48.16  
   48.17 -class Responder:
   48.18 -    """Handler for a response to a message with a specified id.
   48.19 +class CtrlMsgRcvr:
   48.20 +    """Utility class to dispatch messages on a control channel.
   48.21 +    Once I{registerChannel} has been called, our message types are registered
   48.22 +    with the channel. The channel will call I{requestReceived}
   48.23 +    when a request arrives if it has one of our message types.
   48.24 +
   48.25 +    @ivar channel: channel to a domain
   48.26 +    @type channel: Channel
   48.27 +    @ivar majorTypes: major message types we are interested in
   48.28 +    @type majorTypes: {int:{int:method}}
   48.29 +    
   48.30      """
   48.31  
   48.32 -    def __init__(self, mid, deferred):
   48.33 -        """Create a responder.
   48.34 -
   48.35 -        @param mid: message id of response to handle
   48.36 -        @type  mid: int
   48.37 -        @param deferred: deferred object holding the callbacks
   48.38 -        @type  deferred: Deferred
   48.39 -        """
   48.40 -        self.mid = mid
   48.41 -        self.deferred = deferred
   48.42 -
   48.43 -    def responseReceived(self, msg):
   48.44 -        """Entry point called when a response message with the right id arrives.
   48.45 -        Calls callback on I{self.deferred} with the message.
   48.46 -
   48.47 -        @param msg: response message
   48.48 -        @type  msg: xu message
   48.49 -        """
   48.50 -        if self.deferred.called: return
   48.51 -        self.deferred.callback(msg)
   48.52 -
   48.53 -    def error(self, err):
   48.54 -        """Entry point called when there has been an error.
   48.55 -        Calls errback on I{self.deferred} with the error.
   48.56 -
   48.57 -        @param err: error
   48.58 -        @type  err: Exception
   48.59 -        """
   48.60 -        if self.deferred.called: return
   48.61 -        self.deferred.errback(err)
   48.62 +    def __init__(self, channel):
   48.63 +        self.majorTypes = {}
   48.64 +        self.channel = channel
   48.65  
   48.66 -class CtrlMsgRcvr:
   48.67 -    """Abstract class for things that deal with a control interface to a domain.
   48.68 -    Once I{registerChannel} has been called, our message types are registered
   48.69 -    with the channel to the domain. The channel will call I{requestReceived}
   48.70 -    when a request arrives, or I{responseReceived} when a response arrives,
   48.71 -    if they have one of our message types.
   48.72 -
   48.73 -    @ivar dom: the domain we are a control interface for
   48.74 -    @type dom: int
   48.75 -    @ivar majorTypes: major message types we are interested in
   48.76 -    @type majorTypes: {int:{int:method}}
   48.77 -    @ivar timeout: timeout (in seconds) for message handlers
   48.78 -    @type timeout: int
   48.79 -    
   48.80 -    @ivar channel: channel to the domain
   48.81 -    @type channel: Channel
   48.82 -    @ivar idx: channel index
   48.83 -    @ivar idx: string
   48.84 -    @ivar responders: table of message response handlers
   48.85 -    @type responders: {int:Responder}
   48.86 -    """
   48.87 -
   48.88 -    def __init__(self):
   48.89 -        self.channelFactory = channel.channelFactory()
   48.90 -        self.majorTypes = {}
   48.91 -        self.dom = None
   48.92 -        self.channel = None
   48.93 -        self.idx = None
   48.94 -        self.responders = {}
   48.95 -        self.timeout = 10
   48.96 -
   48.97 -    def setTimeout(self, timeout):
   48.98 -        self.timeout = timeout
   48.99 -
  48.100 -    def getMethod(self, type, subtype):
  48.101 +    def getHandler(self, type, subtype):
  48.102          """Get the method for a type and subtype.
  48.103  
  48.104          @param type: major message type
  48.105 @@ -93,7 +38,7 @@ class CtrlMsgRcvr:
  48.106              method = subtypes.get(subtype)
  48.107          return method
  48.108  
  48.109 -    def addMethod(self, type, subtype, method):
  48.110 +    def addHandler(self, type, subtype, method):
  48.111          """Add a method to handle a message type and subtype.
  48.112          
  48.113          @param type: major message type
  48.114 @@ -124,102 +69,32 @@ class CtrlMsgRcvr:
  48.115          """
  48.116          if DEBUG:
  48.117              print 'requestReceived>',
  48.118 -            printMsg(msg, all=1)
  48.119 +            printMsg(msg, all=True)
  48.120          responded = 0
  48.121 -        method = self.getMethod(type, subtype)
  48.122 +        method = self.getHandler(type, subtype)
  48.123          if method:
  48.124 -            responded = method(msg, 1)
  48.125 +            responded = method(msg)
  48.126          elif DEBUG:
  48.127              print ('requestReceived> No handler: Message type %s %d:%d'
  48.128                     % (msgTypeName(type, subtype), type, subtype)), self
  48.129          return responded
  48.130          
  48.131 -    def responseReceived(self, msg, type, subtype):
  48.132 -        """Dispatch a response to handlers.
  48.133 -        Called by the channel for responses with one of our types.
  48.134 -        
  48.135 -        First looks for a message responder for the message's id.
  48.136 -        See L{callResponders}, L{addResponder}.
  48.137 -        If there is no responder, looks for a message handler for
  48.138 -        the message type/subtype.
  48.139 -
  48.140 -        @param msg:     message
  48.141 -        @type  msg:     xu message
  48.142 -        @param type:    major message type
  48.143 -        @type  type:    int
  48.144 -        @param subtype: minor message type
  48.145 -        @type  subtype: int
  48.146 -        """
  48.147 -        if DEBUG:
  48.148 -            print 'responseReceived>',
  48.149 -            printMsg(msg, all=1)
  48.150 -        if self.callResponders(msg):
  48.151 -            return
  48.152 -        method = self.getMethod(type, subtype)
  48.153 -        if method:
  48.154 -            method(msg, 0)
  48.155 -        elif DEBUG:
  48.156 -            print ('responseReceived> No handler: Message type %s %d:%d'
  48.157 -                   % (msgTypeName(type, subtype), type, subtype)), self
  48.158 -
  48.159 -    def addResponder(self, mid, deferred):
  48.160 -        """Add a responder for a message id.
  48.161 -        The I{deferred} is called with callback(msg) when a response
  48.162 -        with message id I{mid} arrives.
  48.163 -
  48.164 -        Responders have a timeout set and I{deferred} will error
  48.165 -        on expiry.
  48.166 -
  48.167 -        @param mid:      message id of response expected
  48.168 -        @type  mid:      int
  48.169 -        @param deferred: handler for the response
  48.170 -        @type  deferred: Deferred
  48.171 -        @return: responder
  48.172 -        @rtype:  Responder
  48.173 -        """
  48.174 -        resp = Responder(mid, deferred)
  48.175 -        self.responders[resp.mid] = resp
  48.176 -        if self.timeout > 0:
  48.177 -            deferred.setTimeout(self.timeout)
  48.178 -        return resp
  48.179 -
  48.180 -    def callResponders(self, msg):
  48.181 -        """Call any waiting responders for a response message.
  48.182 -        Looks for a responder registered for the message's id.
  48.183 -        See L{addResponder}.
  48.184 -
  48.185 -        @param msg: response message
  48.186 -        @type  msg: xu message
  48.187 -        @return: 1 if there was a responder for the message, 0 otherwise
  48.188 -        @rtype : bool
  48.189 -        """
  48.190 -        hdr = msg.get_header()
  48.191 -        mid = hdr['id']
  48.192 -        handled = 0
  48.193 -        resp = self.responders.get(mid)
  48.194 -        if resp:
  48.195 -            handled = 1
  48.196 -            resp.responseReceived(msg)
  48.197 -            del self.responders[mid]
  48.198 -        # Clean up called responders.
  48.199 -        for resp in self.responders.values():
  48.200 -            if resp.deferred.called:
  48.201 -                del self.responders[resp.mid]
  48.202 -        return handled
  48.203  
  48.204      def lostChannel(self):
  48.205          """Called when the channel to the domain is lost.
  48.206          """
  48.207 -        pass
  48.208 +        if DEBUG:
  48.209 +            print 'CtrlMsgRcvr>lostChannel>',
  48.210 +        self.channel = None
  48.211      
  48.212      def registerChannel(self):
  48.213          """Register interest in our major message types with the
  48.214          channel to our domain. Once we have registered, the channel
  48.215 -        will call requestReceived or responseReceived for our messages.
  48.216 +        will call requestReceived for our messages.
  48.217          """
  48.218 -        self.channel = self.channelFactory.domChannel(self.dom)
  48.219 -        self.idx = self.channel.getIndex()
  48.220 -        if self.majorTypes:
  48.221 +        if DEBUG:
  48.222 +            print 'CtrlMsgRcvr>registerChannel>', self.channel, self.getMajorTypes()
  48.223 +        if self.channel:
  48.224              self.channel.registerDevice(self.getMajorTypes(), self)
  48.225          
  48.226      def deregisterChannel(self):
  48.227 @@ -229,470 +104,353 @@ class CtrlMsgRcvr:
  48.228          """
  48.229          if self.channel:
  48.230              self.channel.deregisterDevice(self)
  48.231 -            self.channel = None
  48.232  
  48.233 -    def produceRequests(self):
  48.234 -        """Produce any queued requests.
  48.235 -
  48.236 -        @return: number produced
  48.237 -        @rtype:  int
  48.238 -        """
  48.239 -        return 0
  48.240 -
  48.241 -    def writeRequest(self, msg, response=None):
  48.242 -        """Write a request to the channel.
  48.243 -
  48.244 -        @param msg:      request message
  48.245 -        @type  msg:      xu message
  48.246 -        @param response: response handler
  48.247 -        @type  response: Deferred
  48.248 -        """
  48.249 -        if self.channel:
  48.250 -            if DEBUG:
  48.251 -                print 'CtrlMsgRcvr>writeRequest>',
  48.252 -                printMsg(msg, all=1)
  48.253 -            if response:
  48.254 -                self.addResponder(msg.get_header()['id'], response)
  48.255 -            self.channel.writeRequest(msg)
  48.256 -        else:
  48.257 -            print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
  48.258 -
  48.259 -    def writeResponse(self, msg):
  48.260 -        """Write a response to the channel. This acknowledges
  48.261 -        a request message.
  48.262 -
  48.263 -        @param msg:      message
  48.264 -        @type  msg:      xu message
  48.265 -        """
  48.266 -        if self.channel:
  48.267 -            if DEBUG:
  48.268 -                print 'CtrlMsgRcvr>writeResponse>',
  48.269 -                printMsg(msg, all=0)
  48.270 -            self.channel.writeResponse(msg)
  48.271 -        else:
  48.272 -            print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
  48.273 -            
  48.274 -class ControllerFactory:
  48.275 -    """Abstract class for factories creating controllers for a domain.
  48.276 -    Maintains a table of controllers.
  48.277 -
  48.278 -    @ivar controllers: mapping of index to controller instance
  48.279 -    @type controllers: {String: Controller}
  48.280 -    @ivar dom: domain
  48.281 -    @type dom: int
  48.282 +class DevControllerTable:
  48.283 +    """Table of device controller classes, indexed by type name.
  48.284      """
  48.285  
  48.286      def __init__(self):
  48.287 -        self.controllers = {}
  48.288 -        
  48.289 -    def addController(self, controller):
  48.290 -        """Add a controller instance (under its index).
  48.291 -        """
  48.292 -        self.controllers[controller.idx] = controller
  48.293 +        self.controllerClasses = {}
  48.294  
  48.295 -    def getControllers(self):
  48.296 -        """Get a list of all controllers.
  48.297 -        """
  48.298 -        return self.controllers.values()
  48.299 +    def getDevControllerClass(self, type):
  48.300 +        return self.controllerClasses.get(type)
  48.301 +
  48.302 +    def addDevControllerClass(self, klass):
  48.303 +        self.controllerClasses[klass.getType()] = klass
  48.304  
  48.305 -    def getControllerByIndex(self, idx):
  48.306 -        """Get a controller from its index.
  48.307 -        """
  48.308 -        return self.controllers.get(idx)
  48.309 -
  48.310 -    def getControllerByDom(self, dom):
  48.311 -        """Get the controller for the given domain.
  48.312 +    def delDevControllerClass(self, type):
  48.313 +        if type in self.controllerClasses:
  48.314 +            del self.controllerClasses[type]
  48.315  
  48.316 -        @param dom: domain id
  48.317 -        @type  dom: int
  48.318 -        @return: controller or None
  48.319 -        """
  48.320 -        for inst in self.controllers.values():
  48.321 -            if inst.dom == dom:
  48.322 -                return inst
  48.323 -        return None
  48.324 -
  48.325 -    def getController(self, dom):
  48.326 -        """Create or find the controller for a domain.
  48.327 +    def createDevController(self, type, vm, recreate=False):
  48.328 +        klass = self.getDevControllerClass(type)
  48.329 +        if not klass:
  48.330 +            raise XendError("unknown device type: " + type)
  48.331 +        return klass.createDevController(vm, recreate=recreate)
  48.332  
  48.333 -        @param dom:      domain
  48.334 -        @return: controller
  48.335 -        """
  48.336 -        ctrl = self.getControllerByDom(dom)
  48.337 -        if ctrl is None:
  48.338 -            ctrl = self.createController(dom)
  48.339 -            self.addController(ctrl)
  48.340 -        return ctrl
  48.341 -    
  48.342 -    def createController(self, dom):
  48.343 -        """Create a controller. Define in a subclass.
  48.344 -
  48.345 -        @param dom: domain
  48.346 -        @type  dom: int
  48.347 -        @return: controller instance
  48.348 -        @rtype:  Controller (or subclass)
  48.349 -        """
  48.350 -        raise NotI