handle default key sizes in openssl_crypter
[strongswan.git] / src / dumm / mconsole.c
index 01547e1..d9864f6 100644 (file)
@@ -16,6 +16,8 @@
  * for more details.
  */
 
+#define _GNU_SOURCE
+
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -42,6 +44,8 @@ struct private_mconsole_t {
        int notify;
        /** address of uml socket */
        struct sockaddr_un uml;
+       /** idle function */
+       void (*idle)(void);
 };
 
 /**
@@ -84,42 +88,67 @@ struct mconsole_notify {
 /**
  * send a request to UML using mconsole
  */
-static bool request(private_mconsole_t *this, char *command)
+static int request(private_mconsole_t *this, char *command,
+                                  char buf[], size_t *size)
 {
        mconsole_request request;
        mconsole_reply reply;
-       bool first = TRUE, good = TRUE;
-       int len;
+       int len, total = 0, flags = 0;
        
        memset(&request, 0, sizeof(request));
        request.magic = MCONSOLE_MAGIC;
        request.version = MCONSOLE_VERSION;
        request.len = min(strlen(command), sizeof(reply.data) - 1);
        strncpy(request.data, command, request.len);
+       *buf = '\0';
+       (*size)--;
 
-       if (sendto(this->console, &request, sizeof(request), 0,
-               (struct sockaddr*)&this->uml, sizeof(this->uml)) < 0)
+       if (this->idle)
        {
-               DBG1("sending mconsole command to UML failed: %m");
-               return FALSE;
+               flags = MSG_DONTWAIT;
+       }
+       do
+       {
+               if (this->idle)
+               {
+                       this->idle();
+               }
+               len = sendto(this->console, &request, sizeof(request), flags,
+                                        (struct sockaddr*)&this->uml, sizeof(this->uml));
+       }
+       while (len < 0 && (errno == EINTR || errno == EAGAIN));
+       
+       if (len < 0)
+       {
+               snprintf(buf, *size, "sending mconsole command to UML failed: %m");
+               return -1;
        }
        do 
        {
-               len = recvfrom(this->console, &reply, sizeof(reply), 0, NULL, 0);
+               len = recv(this->console, &reply, sizeof(reply), flags);
+               if (len < 0 && (errno == EINTR || errno == EAGAIN))
+               {
+                       if (this->idle)
+                       {
+                               this->idle();
+                       }
+                       continue;
+               }
                if (len < 0)
                {
-                       DBG1("receiving from mconsole failed: %m");
-               return FALSE;
+                       snprintf(buf, *size, "receiving from mconsole failed: %m");
+                       return -1;
                }
-               if (first && reply.err)
+               if (len > 0)
                {
-                       good = FALSE;
-                       DBG1("received error from UML mconsole: %s", reply.data);
+                       strncat(buf, reply.data, min(reply.len, *size - total));
+                       total += reply.len;
                }
-               first = FALSE;
        }
        while (reply.more);
-       return good;
+       
+       *size = total;
+       return reply.err;
 }
 
 /**
@@ -135,7 +164,13 @@ static bool add_iface(private_mconsole_t *this, char *guest, char *host)
        {
                return FALSE;
        }
-       return request(this, buf);
+       len = sizeof(buf);
+       if (request(this, buf, buf, &len) != 0)
+       {
+               DBG1("adding interface failed: %.*s", len, buf);
+               return FALSE;
+       }
+       return TRUE;
 }
 
 /**
@@ -151,7 +186,47 @@ static bool del_iface(private_mconsole_t *this, char *guest)
        {
                return FALSE;
        }
-       return request(this, buf);
+       if (request(this, buf, buf, &len) != 0)
+       {
+               DBG1("removing interface failed: %.*s", len, buf);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * Poll until guest is ready
+ */
+static bool wait_bootup(private_mconsole_t *this)
+{
+       char buf[128];
+       int len, res;
+       
+       while (TRUE)
+       {
+               len = sizeof(buf);
+               res = request(this, "config eth9=mcast", buf, &len);
+               if (res < 0)
+               {
+                       return FALSE;
+               }
+               if (res == 0)
+               {
+                       while (request(this, "remove eth9", buf, &len) != 0)
+                       {
+                               usleep(50000);
+                       }
+                       return TRUE;
+               }
+               if (this->idle)
+               {
+                       this->idle();
+               }
+               else
+               {
+                       usleep(50000);
+               }
+       }
 }
 
 /**
@@ -171,7 +246,7 @@ static bool wait_for_notify(private_mconsole_t *this, char *nsock)
 {
        struct sockaddr_un addr;
        mconsole_notify notify;
-       int len;
+       int len, flags = 0;
 
        this->notify = socket(AF_UNIX, SOCK_DGRAM, 0);
        if (this->notify < 0)
@@ -188,10 +263,20 @@ static bool wait_for_notify(private_mconsole_t *this, char *nsock)
                close(this->notify);
                return FALSE;
        }
+       if (this->idle)
+       {
+               flags = MSG_DONTWAIT;
+       }
        do
        {
-               len = recvfrom(this->notify, &notify, sizeof(notify), 0, NULL, 0);
-       } while (len < 0 && errno == EINTR);
+               if (this->idle)
+               {
+                       this->idle();
+               }
+               len = recvfrom(this->notify, &notify, sizeof(notify), flags, NULL, 0);
+       }
+       while (len < 0 && (errno == EINTR || errno == EAGAIN));
+       
        if (len < 0 || len >= sizeof(notify))
        {
                DBG1("reading from mconsole notify socket failed: %m");
@@ -244,7 +329,7 @@ static bool setup_console(private_mconsole_t *this)
 /**
  * create the mconsole instance
  */
-mconsole_t *mconsole_create(char *notify)
+mconsole_t *mconsole_create(char *notify, void(*idle)(void))
 {
        private_mconsole_t *this = malloc_thing(private_mconsole_t);
        
@@ -252,6 +337,8 @@ mconsole_t *mconsole_create(char *notify)
        this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface;
        this->public.destroy = (void*)destroy;
        
+       this->idle = idle;
+       
        if (!wait_for_notify(this, notify))
        {
                free(this);
@@ -267,6 +354,12 @@ mconsole_t *mconsole_create(char *notify)
        }
        unlink(notify);
        
+       if (!wait_bootup(this))
+       {
+               destroy(this);
+               return NULL;
+       }
+       
        return &this->public;
 }