[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] [patch 05/12] Add network config parsing to qemud



Implement the qemud's network stubs, but don't actually do anything
when starting a network.

Note, an example XML file would be:

<network>
  <name>TestNetwork</name>
  <uuid>ac57b808-bfdd-4aa3-8da8-0bd4ac1faceb</uuid>
  <ip address="10.0.0.1" netmask="255.255.255.0">
    <dhcp>
      <range start="10.0.0.16" end="10.0.0.32" />
      <range start="10.0.0.128" end="10.0.0.254" />
    </dhcp>
  </ip>
</network>

Signed-off-by: Mark McLoughlin <markmc redhat com>

Index: libvirt-foo/qemud/conf.c
===================================================================
--- libvirt-foo.orig/qemud/conf.c	2007-02-14 14:57:31.000000000 +0000
+++ libvirt-foo.orig/qemud/conf.c	2007-02-14 14:57:31.000000000 +0000
@@ -1098,17 +1098,186 @@ struct qemud_vm *qemudLoadConfigXML(stru
 }
 
 
+void qemudFreeNetwork(struct qemud_network *network) {
+    free(network);
+}
+
+
+static int qemudSaveNetworkConfig(struct qemud_server *server,
+                                  struct qemud_network *network) {
+    char *xml;
+    int fd, ret = -1;
+    int towrite;
+
+    if (!(xml = qemudGenerateNetworkXML(server, network))) {
+        return -1;
+    }
+
+    if (qemudEnsureConfigDir(server, server->networkConfigDir) < 0) {
+        goto cleanup;
+    }
+
+    if ((fd = open(network->configFile,
+                   O_WRONLY | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR )) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create config file %s", network->configFile);
+        goto cleanup;
+    }
+
+    towrite = strlen(xml);
+    if (write(fd, xml, towrite) != towrite) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot write config file %s", network->configFile);
+        goto cleanup;
+    }
+
+    if (close(fd) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot save config file %s", network->configFile);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+
+    free(xml);
+
+    return ret;
+}
+
+
+static int qemudParseNetworkXML(struct qemud_server *server,
+                                xmlDocPtr xml,
+                                struct qemud_network *network) {
+    xmlNodePtr root = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlXPathObjectPtr obj = NULL;
+
+    /* Prepare parser / xpath context */
+    root = xmlDocGetRootElement(xml);
+    if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "network"))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "incorrect root element");
+        goto error;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        qemudReportError(server, VIR_ERR_NO_MEMORY, "xmlXPathContext");
+        goto error;
+    }
+
+
+    /* Extract network name */
+    obj = xmlXPathEval(BAD_CAST "string(/network/name[1])", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        qemudReportError(server, VIR_ERR_NO_NAME, NULL);
+        goto error;
+    }
+    if (strlen((const char *)obj->stringval) >= (QEMUD_MAX_NAME_LEN-1)) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "network name length too long");
+        goto error;
+    }
+    strcpy(network->def.name, (const char *)obj->stringval);
+    xmlXPathFreeObject(obj);
+
+
+    /* Extract network uuid */
+    obj = xmlXPathEval(BAD_CAST "string(/network/uuid[1])", ctxt);
+    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
+        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
+        /* XXX auto-generate a UUID */
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "missing uuid element");
+        goto error;
+    }
+    if (qemudParseUUID((const char *)obj->stringval, network->def.uuid) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "%s", "malformed uuid element");
+        goto error;
+    }
+    xmlXPathFreeObject(obj);
+
+    xmlXPathFreeContext(ctxt);
+
+    return 0;
+
+ error:
+    /* XXX free all the stuff in the qemud_network struct, or leave it upto
+       the caller ? */
+    if (obj)
+        xmlXPathFreeObject(obj);
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    return -1;
+}
+
+
+struct qemud_network *qemudLoadNetworkConfigXML(struct qemud_server *server,
+                                                const char *file,
+                                                const char *doc,
+                                                int save) {
+    struct qemud_network *network = NULL;
+    xmlDocPtr xml;
+
+    if (!(xml = xmlReadDoc(BAD_CAST doc, file ? file : "network.xml", NULL,
+                           XML_PARSE_NOENT | XML_PARSE_NONET |
+                           XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+        qemudReportError(server, VIR_ERR_XML_ERROR, NULL);
+        return NULL;
+    }
+
+    if (!(network = calloc(1, sizeof(struct qemud_network)))) {
+        qemudReportError(server, VIR_ERR_NO_MEMORY, "network");
+        return NULL;
+    }
+
+    if (qemudParseNetworkXML(server, xml, network) < 0) {
+        xmlFreeDoc(xml);
+        qemudFreeNetwork(network);
+        return NULL;
+    }
+    xmlFreeDoc(xml);
+
+    if (qemudFindNetworkByUUID(server, network->def.uuid) ||
+        qemudFindNetworkByName(server, network->def.name)) {
+        qemudReportError(server, VIR_ERR_NETWORK_EXIST, network->def.name);
+        qemudFreeNetwork(network);
+        return NULL;
+    }
+
+    if (file) {
+        strncpy(network->configFile, file, PATH_MAX);
+        network->configFile[PATH_MAX-1] = '\0';
+    } else {
+        if (save) {
+            if (qemudMakeConfigPath(server->networkConfigDir, network->def.name, ".xml", network->configFile, PATH_MAX) < 0) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot construct config file path");
+                qemudFreeNetwork(network);
+                return NULL;
+            }
+
+            if (qemudSaveNetworkConfig(server, network) < 0) {
+                qemudFreeNetwork(network);
+                return NULL;
+            }
+        } else {
+            network->configFile[0] = '\0';
+        }
+    }
+
+    return network;
+}
+
+
 /* Load a guest from its persistent config file */
 static void qemudLoadConfig(struct qemud_server *server,
-                            const char *file) {
+                            const char *file,
+                            int isGuest) {
     FILE *fh;
     struct stat st;
-    struct qemud_vm *vm;
     char xml[QEMUD_MAX_XML_LEN];
     int ret;
 
     if (!(fh = fopen(file, "r"))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open guest config file %s", file);
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open config file %s", file);
         return;
     }
 
@@ -1118,7 +1287,7 @@ static void qemudLoadConfig(struct qemud
     }
 
     if (st.st_size >= QEMUD_MAX_XML_LEN) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "guest config too large in file %s", file);
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "config too large in file %s", file);
         goto cleanup;
     }
 
@@ -1128,10 +1297,20 @@ static void qemudLoadConfig(struct qemud
     }
     xml[st.st_size] = '\0';
 
-    if ((vm = qemudLoadConfigXML(server, file, xml, 1))) {
-        vm->next = server->inactivevms;
-        server->inactivevms = vm;
-        server->ninactivevms++;
+    if (isGuest) {
+        struct qemud_vm *vm;
+        if ((vm = qemudLoadConfigXML(server, file, xml, 1))) {
+            vm->next = server->inactivevms;
+            server->inactivevms = vm;
+            server->ninactivevms++;
+        }
+    } else {
+        struct qemud_network *network;
+        if ((network = qemudLoadNetworkConfigXML(server, file, xml, 1))) {
+            network->next = server->inactivenetworks;
+            server->inactivenetworks = network;
+            server->ninactivenetworks++;
+        }
     }
   
  cleanup:
@@ -1141,7 +1320,8 @@ static void qemudLoadConfig(struct qemud
 
 static
 int qemudScanConfigDir(struct qemud_server *server,
-                       const char *configDir) {
+                       const char *configDir,
+                       int isGuest) {
     DIR *dir;
     struct dirent *entry;
 
@@ -1159,7 +1339,7 @@ int qemudScanConfigDir(struct qemud_serv
         if (qemudMakeConfigPath(configDir, entry->d_name, NULL, file, PATH_MAX) < 0)
             continue;
 
-        qemudLoadConfig(server, file);
+        qemudLoadConfig(server, file, isGuest);
     }
 
     closedir(dir);
@@ -1169,7 +1349,9 @@ int qemudScanConfigDir(struct qemud_serv
 
 /* Scan for all guest and network config files */
 int qemudScanConfigs(struct qemud_server *server) {
-    return qemudScanConfigDir(server, server->configDir);
+    if (qemudScanConfigDir(server, server->configDir, 0) < 0)
+        return -1;
+    return qemudScanConfigDir(server, server->networkConfigDir, 1);
 }
 
 /* Simple grow-on-demand string buffer */
@@ -1424,19 +1606,54 @@ char *qemudGenerateXML(struct qemud_serv
 }
 
 
-int qemudDeleteConfigXML(struct qemud_server *server, struct qemud_vm *vm) {
-    if (!vm->configFile[0]) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for guest %s", vm->def.name);
+char *qemudGenerateNetworkXML(struct qemud_server *server,
+                              struct qemud_network *network) {
+    struct qemudBuffer buf;
+    unsigned char *uuid;
+
+    buf.len = QEMUD_MAX_XML_LEN;
+    buf.used = 0;
+    buf.data = malloc(buf.len);
+
+    if (qemudBufferPrintf(&buf, "<network>\n") < 0)
+        goto no_memory;
+
+    if (qemudBufferPrintf(&buf, "  <name>%s</name>\n", network->def.name) < 0)
+        goto no_memory;
+
+    uuid = network->def.uuid;
+    if (qemudBufferPrintf(&buf, "  <uuid>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</uuid>\n",
+                          uuid[0], uuid[1], uuid[2], uuid[3],
+                          uuid[4], uuid[5], uuid[6], uuid[7],
+                          uuid[8], uuid[9], uuid[10], uuid[11],
+                          uuid[12], uuid[13], uuid[14], uuid[15]) < 0)
+        goto no_memory;
+
+    if (qemudBufferAdd(&buf, "</network>\n") < 0)
+        goto no_memory;
+
+    return buf.data;
+
+ no_memory:
+    qemudReportError(server, VIR_ERR_NO_MEMORY, "xml");
+    free(buf.data);
+    return NULL;
+}
+
+
+int qemudDeleteConfig(struct qemud_server *server,
+                      const char *configFile,
+                      const char *name) {
+    if (!configFile[0]) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "no config file for %s", name);
         return -1;
     }
 
-    if (unlink(vm->configFile) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for guest %s", vm->def.name);
+    if (unlink(configFile) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot remove config for %s", name);
         return -1;
     }
 
-    vm->configFile[0] = '\0';
-
     return 0;
 }
 
Index: libvirt-foo/qemud/conf.h
===================================================================
--- libvirt-foo.orig/qemud/conf.h	2007-02-14 15:06:41.000000000 +0000
+++ libvirt-foo.orig/qemud/conf.h	2007-02-14 15:06:41.000000000 +0000
@@ -30,18 +30,26 @@ int qemudBuildCommandLine(struct qemud_s
                           struct qemud_vm *vm,
                           char ***argv);
 
+int qemudScanConfigs(struct qemud_server *server);
+int qemudDeleteConfig(struct qemud_server *server,
+                      const char *configFile,
+                      const char *name);
+
 void qemudFreeVM(struct qemud_vm *vm);
 struct qemud_vm *qemudLoadConfigXML(struct qemud_server *server,
                                     const char *file,
                                     const char *doc,
                                     int persist);
-int qemudScanConfigs(struct qemud_server *server);
 char *qemudGenerateXML(struct qemud_server *server,
                        struct qemud_vm *vm);
 
-int qemudDeleteConfigXML(struct qemud_server *server,
-                         struct qemud_vm *vm);
-
+void qemudFreeNetwork(struct qemud_network *network);
+struct qemud_network *qemudLoadNetworkConfigXML(struct qemud_server *server,
+                                                const char *file,
+                                                const char *doc,
+                                                int persist);
+char *qemudGenerateNetworkXML(struct qemud_server *server,
+                              struct qemud_network *network);
 
 #endif
 
Index: libvirt-foo/qemud/driver.c
===================================================================
--- libvirt-foo.orig/qemud/driver.c	2007-02-14 15:46:58.000000000 +0000
+++ libvirt-foo.orig/qemud/driver.c	2007-02-14 15:46:58.000000000 +0000
@@ -522,9 +522,11 @@ int qemudDomainUndefine(struct qemud_ser
         return -1;
     }
 
-    if (qemudDeleteConfigXML(server, vm) < 0)
+    if (qemudDeleteConfig(server, vm->configFile, vm->def.name) < 0)
         return -1;
 
+    vm->configFile[0] = '\0';
+
     while (curr) {
         if (curr == vm) {
             if (prev) {
@@ -547,67 +549,198 @@ int qemudDomainUndefine(struct qemud_ser
 
 struct qemud_network *qemudFindNetworkByUUID(const struct qemud_server *server,
                                              const unsigned char *uuid) {
-    server = NULL; uuid = NULL;
+    struct qemud_network *network = server->activenetworks;
+
+    while (network) {
+        if (!memcmp(network->def.uuid, uuid, QEMUD_UUID_RAW_LEN))
+            return network;
+        network = network->next;
+    }
+
+    network = server->inactivenetworks;
+    while (network) {
+        if (!memcmp(network->def.uuid, uuid, QEMUD_UUID_RAW_LEN))
+            return network;
+        network = network->next;
+    }
+
     return NULL;
 }
 
 struct qemud_network *qemudFindNetworkByName(const struct qemud_server *server,
                                              const char *name) {
-    server = NULL; name = NULL;
+    struct qemud_network *network = server->activenetworks;
+
+    while (network) {
+        if (!strcmp(network->def.name, name))
+            return network;
+        network = network->next;
+    }
+
+    network = server->inactivenetworks;
+    while (network) {
+        if (!strcmp(network->def.name, name))
+            return network;
+        network = network->next;
+    }
+
     return NULL;
 }
 
 int qemudNumNetworks(struct qemud_server *server) {
-    server = NULL;
-    return 0;
+    return server->nactivenetworks;
 }
 
 int qemudListNetworks(struct qemud_server *server, char *const*names, int nnames) {
-    server = NULL; names = NULL; nnames = 0;
-    return 0;
+    struct qemud_network *network = server->activenetworks;
+    int got = 0;
+    while (network && got < nnames) {
+        strncpy(names[got], network->def.name, QEMUD_MAX_NAME_LEN-1);
+        names[got][QEMUD_MAX_NAME_LEN-1] = '\0';
+        network = network->next;
+        got++;
+    }
+    return got;
 }
 
 int qemudNumDefinedNetworks(struct qemud_server *server) {
-    server = NULL;
-    return 0;
+    return server->ninactivenetworks;
 }
 
 int qemudListDefinedNetworks(struct qemud_server *server, char *const*names, int nnames) {
-    server = NULL; names = NULL; nnames = 0;
-    return 0;
+    struct qemud_network *network = server->inactivenetworks;
+    int got = 0;
+    while (network && got < nnames) {
+        strncpy(names[got], network->def.name, QEMUD_MAX_NAME_LEN-1);
+        names[got][QEMUD_MAX_NAME_LEN-1] = '\0';
+        network = network->next;
+        got++;
+    }
+    return got;
 }
 
 struct qemud_network *qemudNetworkCreate(struct qemud_server *server, const char *xml) {
-    server = NULL; xml = NULL;
-    return NULL;
+    struct qemud_network *network;
+
+    if (!(network = qemudLoadNetworkConfigXML(server, NULL, xml, 0))) {
+        return NULL;
+    }
+
+    if (qemudStartNetworkDaemon(server, network) < 0) {
+        qemudFreeNetwork(network);
+        return NULL;
+    }
+
+    network->next = server->activenetworks;
+    server->activenetworks = network;
+    server->nactivenetworks++;
+
+    return network;
 }
 
 struct qemud_network *qemudNetworkDefine(struct qemud_server *server, const char *xml) {
-    server = NULL; xml = NULL;
-    return NULL;
+    struct qemud_network *network;
+
+    if (!(network = qemudLoadNetworkConfigXML(server, NULL, xml, 1))) {
+        return NULL;
+    }
+
+    network->next = server->inactivenetworks;
+    server->inactivenetworks = network;
+    server->ninactivenetworks++;
+
+    return network;
 }
 
 int qemudNetworkUndefine(struct qemud_server *server, const unsigned char *uuid) {
-    qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid");
-    uuid = NULL;
-    return -1;
+    struct qemud_network *network = qemudFindNetworkByUUID(server, uuid);
+    struct qemud_network *prev = NULL, *curr = server->inactivenetworks;
+
+    if (!network) {
+        qemudReportError(server, VIR_ERR_INVALID_DOMAIN, "no network with matching uuid");
+        return -1;
+    }
+
+    if (qemudDeleteConfig(server, network->configFile, network->def.name) < 0)
+        return -1;
+
+    network->configFile[0] = '\0';
+
+    while (curr) {
+        if (curr == network) {
+            if (prev) {
+                prev->next = curr->next;
+            } else {
+                server->inactivenetworks = curr->next;
+            }
+            server->ninactivenetworks--;
+            break;
+        }
+
+        prev = curr;
+        curr = curr->next;
+    }
+
+    qemudFreeNetwork(network);
+
+    return 0;
 }
 
 int qemudNetworkStart(struct qemud_server *server, struct qemud_network *network) {
-    server = NULL; network = NULL;
-    return 1;
+    struct qemud_network *prev = NULL, *curr = server->inactivenetworks;
+    if (qemudStartNetworkDaemon(server, network) < 0) {
+        return 1;
+    }
+
+    while (curr) {
+        if (curr == network) {
+            if (prev)
+                prev->next = curr->next;
+            else
+                server->inactivenetworks = curr->next;
+            server->ninactivenetworks--;
+            break;
+        }
+        prev = curr;
+        curr = curr->next;
+    }
+
+    network->next = server->activenetworks;
+    server->activenetworks = network;
+    server->nactivenetworks++;
+
+    return 0;
 }
 
 int qemudNetworkDestroy(struct qemud_server *server, const unsigned char *uuid) {
-    uuid = NULL;
-    qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid");
-    return -1;
+    struct qemud_network *network = qemudFindNetworkByUUID(server, uuid);
+    if (!network) {
+        qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid");
+        return -1;
+    }
+
+    if (qemudShutdownNetworkDaemon(server, network) < 0)
+        return -1;
+
+    return 0;
 }
 
 int qemudNetworkDumpXML(struct qemud_server *server, const unsigned char *uuid, char *xml, int xmllen) {
-    qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid");
-    uuid = NULL; xml = NULL; xmllen = 0;
-    return -1;
+    struct qemud_network *network = qemudFindNetworkByUUID(server, uuid);
+    char *networkxml;
+    if (!network) {
+        qemudReportError(server, VIR_ERR_INVALID_NETWORK, "no network with matching uuid");
+        return -1;
+    }
+
+    networkxml = qemudGenerateNetworkXML(server, network);
+    if (!networkxml)
+        return -1;
+
+    strncpy(xml, networkxml, xmllen);
+    xml[xmllen-1] = '\0';
+
+    return 0;
 }
 
 /*
Index: libvirt-foo/qemud/internal.h
===================================================================
--- libvirt-foo.orig/qemud/internal.h	2007-02-14 15:46:58.000000000 +0000
+++ libvirt-foo.orig/qemud/internal.h	2007-02-14 15:46:58.000000000 +0000
@@ -207,6 +207,8 @@ struct qemud_network_def {
 
 /* Virtual Network runtime state */
 struct qemud_network {
+    char configFile[PATH_MAX];
+
     struct qemud_network_def def;
     struct qemud_network *next;
 };
@@ -243,7 +245,12 @@ struct qemud_server {
     int ninactivevms;
     struct qemud_vm *inactivevms;
     int nextvmid;
+    int nactivenetworks;
+    struct qemud_network *activenetworks;
+    int ninactivenetworks;
+    struct qemud_network *inactivenetworks;
     char configDir[PATH_MAX];
+    char networkConfigDir[PATH_MAX];
     char errorMessage[QEMUD_MAX_ERROR_LEN];
     int errorCode;
 };
@@ -254,6 +261,13 @@ int qemudStartVMDaemon(struct qemud_serv
 int qemudShutdownVMDaemon(struct qemud_server *server,
                           struct qemud_vm *vm);
 
+int qemudStartNetworkDaemon(struct qemud_server *server,
+                            struct qemud_network *network);
+
+int qemudShutdownNetworkDaemon(struct qemud_server *server,
+                               struct qemud_network *network);
+
+
 #endif
 
 /*
Index: libvirt-foo/qemud/qemud.c
===================================================================
--- libvirt-foo.orig/qemud/qemud.c	2007-02-14 14:53:23.000000000 +0000
+++ libvirt-foo.orig/qemud/qemud.c	2007-02-14 14:53:23.000000000 +0000
@@ -251,6 +251,9 @@ static struct qemud_server *qemudInitial
         if (snprintf(server->configDir, sizeof(server->configDir), "%s/qemud", SYSCONF_DIR) >= (int)sizeof(server->configDir)) {
             goto cleanup;
         }
+        if (snprintf(server->networkConfigDir, sizeof(server->networkConfigDir), "%s/qemud/networks", SYSCONF_DIR) >= (int)sizeof(server->networkConfigDir)) {
+            goto cleanup;
+        }
     } else {
         struct passwd *pw;
         int uid;
@@ -264,8 +267,13 @@ static struct qemud_server *qemudInitial
         if (snprintf(server->configDir, sizeof(server->configDir), "%s/.qemud", pw->pw_dir) >= (int)sizeof(server->configDir)) {
             goto cleanup;
         }
+
+        if (snprintf(server->networkConfigDir, sizeof(server->networkConfigDir), "%s/.qemud.d/networks", pw->pw_dir) >= (int)sizeof(server->networkConfigDir)) {
+            goto cleanup;
+        }
     }
 
+
     if (qemudListen(server, sys) < 0) {
         goto cleanup;
     }
@@ -696,6 +704,20 @@ static int qemudDispatchVMFailure(struct
 }
 
 
+int qemudStartNetworkDaemon(struct qemud_server *server,
+                            struct qemud_network *network) {
+    server = NULL; network = NULL;
+    return 0;
+}
+
+
+int qemudShutdownNetworkDaemon(struct qemud_server *server,
+                               struct qemud_network *network) {
+    server = NULL; network = NULL;
+    return 0;
+}
+
+
 static int qemudDispatchPoll(struct qemud_server *server, struct pollfd *fds) {
     struct qemud_socket *sock = server->sockets;
     struct qemud_client *client = server->clients;

-- 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]