Author: mattm
Date: 2016-09-21 12:24:50 +0200 (Wed, 21 Sep 2016)
New Revision: 26241

Modified:
   trunk/openvas-libraries/ChangeLog
   trunk/openvas-libraries/misc/openvas_server.c
   trunk/openvas-libraries/misc/openvas_server.h
   trunk/openvas-libraries/omp/omp.c
   trunk/openvas-libraries/omp/omp.h
   trunk/openvas-libraries/omp/xml.c
   trunk/openvas-libraries/omp/xml.h
Log:
        Add support for working with a connection, like the openvas_server_*
        functions, but where the connection can be either over TLS-TCP or a UNIX
        socket.

        * misc/openvas_server.h: Export connection functions.
        (openvas_connection_t): New type.

        * misc/openvas_server.c (close_unix, openvas_connection_free)
        (openvas_connection_close, unix_vsendf_internal)
        (openvas_connection_vsendf_internal, openvas_connection_vsendf)
        (openvas_connection_vsendf_quiet, openvas_connection_sendf)
        (openvas_connection_sendf_quiet, openvas_connection_sendf_xml)
        (openvas_connection_sendf_xml_quiet): New functions.

        * omp/omp.c (omp_authenticate_info_ext_c, omp_start_task_report_c)
        (check_response_c, omp_stop_task_c, omp_resume_task_report_c): New
        functions.

        * omp/omp.h: Add headers accordingly.

        * omp/xml.c (try_read_entity_and_string_c, read_entity_and_string_c)
        (read_entity_and_text_c, read_string_c, try_read_entity_c)
        (read_entity_c): New function.

        * omp/xml.h: Add headers accordingly.

Modified: trunk/openvas-libraries/ChangeLog
===================================================================
--- trunk/openvas-libraries/ChangeLog   2016-09-21 09:04:30 UTC (rev 26240)
+++ trunk/openvas-libraries/ChangeLog   2016-09-21 10:24:50 UTC (rev 26241)
@@ -1,3 +1,31 @@
+2016-09-21  Matthew Mundell <matthew.mund...@greenbone.net>
+
+       Add support for working with a connection, like the openvas_server_*
+       functions, but where the connection can be either over TLS-TCP or a UNIX
+       socket.
+
+       * misc/openvas_server.h: Export connection functions.
+       (openvas_connection_t): New type.
+
+       * misc/openvas_server.c (close_unix, openvas_connection_free)
+       (openvas_connection_close, unix_vsendf_internal)
+       (openvas_connection_vsendf_internal, openvas_connection_vsendf)
+       (openvas_connection_vsendf_quiet, openvas_connection_sendf)
+       (openvas_connection_sendf_quiet, openvas_connection_sendf_xml)
+       (openvas_connection_sendf_xml_quiet): New functions.
+
+       * omp/omp.c (omp_authenticate_info_ext_c, omp_start_task_report_c)
+       (check_response_c, omp_stop_task_c, omp_resume_task_report_c): New
+       functions.
+
+       * omp/omp.h: Add headers accordingly.
+
+       * omp/xml.c (try_read_entity_and_string_c, read_entity_and_string_c)
+       (read_entity_and_text_c, read_string_c, try_read_entity_c)
+       (read_entity_c): New function.
+
+       * omp/xml.h: Add headers accordingly.
+
 2016-09-16  Hani Benhabiles <hani.benhabi...@greenbone.net>
 
        * misc/network.c (ovas_scanner_context_s): Remove unused struct.

Modified: trunk/openvas-libraries/misc/openvas_server.c
===================================================================
--- trunk/openvas-libraries/misc/openvas_server.c       2016-09-21 09:04:30 UTC 
(rev 26240)
+++ trunk/openvas-libraries/misc/openvas_server.c       2016-09-21 10:24:50 UTC 
(rev 26241)
@@ -91,6 +91,62 @@
 
 
 
+/* Connections. */
+
+/**
+ * @brief Close UNIX socket connection.
+ *
+ * @param[in]  client_connection  Client connection.
+ *
+ * @return 0 success, -1 error.
+ */
+static int
+close_unix (openvas_connection_t *client_connection)
+{
+  /* Turn off blocking. */
+  if (fcntl (client_connection->socket, F_SETFL, O_NONBLOCK) == -1)
+    {
+      g_warning ("%s: failed to set server socket flag: %s\n", __FUNCTION__,
+                 strerror (errno));
+      return -1;
+    }
+
+  if (shutdown (client_connection->socket, SHUT_RDWR) == -1)
+    {
+      if (errno == ENOTCONN)
+        return 0;
+      g_warning ("%s: failed to shutdown server socket: %s\n", __FUNCTION__,
+                 strerror (errno));
+      return -1;
+    }
+
+  if (close (client_connection->socket) == -1)
+    {
+      g_warning ("%s: failed to close server socket: %s\n", __FUNCTION__,
+                 strerror (errno));
+      return -1;
+    }
+
+  return 0;
+}
+
+/**
+ * @brief Free connection.
+ *
+ * @param[in]  client_connection  Connection.
+ */
+void
+openvas_connection_free (openvas_connection_t *client_connection)
+{
+  if (client_connection->tls)
+    openvas_server_free (client_connection->socket,
+                         client_connection->session,
+                         client_connection->credentials);
+  else
+    close_unix (client_connection);
+}
+
+
 /* Certificate verification. */
 
 /**
@@ -424,6 +480,18 @@
   return openvas_server_free (socket, session, NULL);
 }
 
+/**
+ * @brief Close a server connection and its socket.
+ *
+ * @param[in]  connection  Connection.
+ *
+ * @return 0 on success, -1 on error.
+ */
+void
+openvas_connection_close (openvas_connection_t *connection)
+{
+  openvas_connection_free (connection);
+}
 
 /**
  * @brief Connect to a server.
@@ -641,12 +709,107 @@
 /**
  * @brief Send a string to the server.
  *
+ * @param[in]  socket   Socket.
+ * @param[in]  fmt      Format of string to send.
+ * @param[in]  ap       Args for fmt.
+ * @param[in]  quiet    Whether to log debug and info messages.  Useful for
+ *                      hiding passwords.
+ *
+ * @return 0 on success, 1 if server closed connection, -1 on error.
+ */
+static int
+unix_vsendf_internal (int socket, const char *fmt, va_list ap, int quiet)
+{
+#ifndef _WIN32
+  struct sigaction new_action, original_action;
+#endif
+  char *string_start, *string;
+  int rc = 0, left;
+
+#ifndef _WIN32
+  new_action.sa_flags = 0;
+  if (sigemptyset (&new_action.sa_mask))
+    // FIX warning
+    return -1;
+  new_action.sa_handler = SIG_IGN;
+  if (sigaction (SIGPIPE, &new_action, &original_action))
+    // FIX warning
+    return -1;
+#endif
+
+  left = vasprintf (&string, fmt, ap);
+  if (left == -1)
+    string = NULL;
+
+  string_start = string;
+  while (left > 0)
+    {
+      ssize_t count;
+
+      if (quiet == 0)
+        g_debug ("   send %d from %.*s[...]",
+                 left, left < 30 ? left : 30, string);
+      count = write (socket, string, left);
+      if (count < 0)
+        {
+          if (errno == EINTR || errno == EAGAIN)
+            continue;
+          g_warning ("Failed to write to server: %s", strerror (errno));
+
+#ifndef _WIN32
+          sigaction (SIGPIPE, &original_action, NULL);
+#endif
+
+          rc = -1;
+          goto out;
+        }
+      if (quiet == 0)
+        g_debug ("=> %.*s", (int) count, string);
+
+      string += count;
+      left -= count;
+    }
+  if (quiet == 0)
+    g_debug ("=> done");
+
+#ifndef _WIN32
+  sigaction (SIGPIPE, &original_action, NULL);
+#endif
+
+out:
+  g_free (string_start);
+  return rc;
+}
+
+/**
+ * @brief Send a string to the connection.
+ *
  * @param[in]  session  Pointer to GNUTLS session.
  * @param[in]  fmt      Format of string to send.
  * @param[in]  ap       Args for fmt.
+ * @param[in]  quiet    Whether to log debug and info messages.  Useful for
+ *                      hiding passwords.
  *
  * @return 0 on success, 1 if server closed connection, -1 on error.
  */
+static int
+openvas_connection_vsendf_internal (openvas_connection_t *connection,
+                                    const char *fmt, va_list ap, int quiet)
+{
+  if (connection->tls)
+    return openvas_server_vsendf_internal (&connection->session, fmt, ap, 
quiet);
+  return unix_vsendf_internal (connection->socket, fmt, ap, quiet);
+}
+
+/**
+ * @brief Send a string to the server.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ * @param[in]  fmt      Format of string to send.
+ * @param[in]  ap       Args for fmt.
+ *
+ * @return 0 on success, 1 if server closed connection, -1 on error.
+ */
 int
 openvas_server_vsendf (gnutls_session_t *session, const char *fmt, va_list ap)
 {
@@ -654,6 +817,22 @@
 }
 
 /**
+ * @brief Send a string to the server.
+ *
+ * @param[in]  connection  Connection.
+ * @param[in]  fmt         Format of string to send.
+ * @param[in]  ap          Args for fmt.
+ *
+ * @return 0 on success, 1 if server closed connection, -1 on error.
+ */
+int
+openvas_connection_vsendf (openvas_connection_t *connection, const char *fmt,
+                           va_list ap)
+{
+  return openvas_connection_vsendf_internal (connection, fmt, ap, 0);
+}
+
+/**
  * @brief Send a string to the server, refraining from logging besides 
warnings.
  *
  * @param[in]  session  Pointer to GNUTLS session.
@@ -670,6 +849,23 @@
 }
 
 /**
+ * @brief Send a string to the server, refraining from logging besides 
warnings.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ * @param[in]  fmt      Format of string to send.
+ * @param[in]  ap       Args for fmt.
+ *
+ * @return 0 on success, 1 if server closed connection, -1 on error.
+ */
+int
+openvas_connection_vsendf_quiet (openvas_connection_t *connection,
+                                 const char *fmt,
+                                 va_list ap)
+{
+  return openvas_connection_vsendf_internal (connection, fmt, ap, 1);
+}
+
+/**
  * @brief Format and send a string to the server.
  *
  * @param[in]  session  Pointer to GNUTLS session.
@@ -698,6 +894,28 @@
  * @return 0 on success, -1 on error.
  */
 int
+openvas_connection_sendf (openvas_connection_t *connection,
+                          const char *format,
+                          ...)
+{
+  va_list ap;
+  int rc;
+
+  va_start (ap, format);
+  rc = openvas_connection_vsendf (connection, format, ap);
+  va_end (ap);
+  return rc;
+}
+
+/**
+ * @brief Format and send a string to the server.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ * @param[in]  format   printf-style format string for message.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int
 openvas_server_sendf_quiet (gnutls_session_t * session, const char *format, 
...)
 {
   va_list ap;
@@ -710,6 +928,28 @@
 }
 
 /**
+ * @brief Format and send a string to the server.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ * @param[in]  format   printf-style format string for message.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int
+openvas_connection_sendf_quiet (openvas_connection_t *connection,
+                                const char *format,
+                                ...)
+{
+  va_list ap;
+  int rc;
+
+  va_start (ap, format);
+  rc = openvas_connection_vsendf_quiet (connection, format, ap);
+  va_end (ap);
+  return rc;
+}
+
+/**
  * @brief Format and send an XML string to the server.
  *
  * Escape XML in string and character args.
@@ -739,6 +979,32 @@
  *
  * Escape XML in string and character args.
  *
+ * @param[in]  connection  Connection.
+ * @param[in]  format      printf-style format string for message.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int
+openvas_connection_sendf_xml (openvas_connection_t *connection,
+                              const char *format, ...)
+{
+  va_list ap;
+  gchar *msg;
+  int rc;
+
+  va_start (ap, format);
+  msg = g_markup_vprintf_escaped (format, ap);
+  rc = openvas_connection_sendf (connection, "%s", msg);
+  g_free (msg);
+  va_end (ap);
+  return rc;
+}
+
+/**
+ * @brief Format and send an XML string to the server.
+ *
+ * Escape XML in string and character args.
+ *
  * Quiet version, only logs warnings.
  *
  * @param[in]  session  Pointer to GNUTLS session.
@@ -762,6 +1028,35 @@
   return rc;
 }
 
+/**
+ * @brief Format and send an XML string to the server.
+ *
+ * Escape XML in string and character args.
+ *
+ * Quiet version, only logs warnings.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ * @param[in]  format   printf-style format string for message.
+ *
+ * @return 0 on success, -1 on error.
+ */
+int
+openvas_connection_sendf_xml_quiet (openvas_connection_t *connection,
+                                    const char *format,
+                                    ...)
+{
+  va_list ap;
+  gchar *msg;
+  int rc;
+
+  va_start (ap, format);
+  msg = g_markup_vprintf_escaped (format, ap);
+  rc = openvas_connection_sendf_quiet (connection, "%s", msg);
+  g_free (msg);
+  va_end (ap);
+  return rc;
+}
+
 static int
 server_new_gnutls_init (gnutls_certificate_credentials_t *server_credentials)
 {

Modified: trunk/openvas-libraries/misc/openvas_server.h
===================================================================
--- trunk/openvas-libraries/misc/openvas_server.h       2016-09-21 09:04:30 UTC 
(rev 26240)
+++ trunk/openvas-libraries/misc/openvas_server.h       2016-09-21 10:24:50 UTC 
(rev 26241)
@@ -52,6 +52,21 @@
 #include <netinet/ip.h>
 #endif
 
+/**
+ * @brief Connection.
+ */
+typedef struct
+{
+  int tls;                     ///< Whether uses TCP-TLS (vs UNIX socket).
+  int socket;                  ///< Socket.
+  gnutls_session_t session;                      ///< Session.
+  gnutls_certificate_credentials_t credentials;  ///< Credentials.
+} openvas_connection_t;
+
+void openvas_connection_free (openvas_connection_t *);
+
+void openvas_connection_close (openvas_connection_t *);
+
 int openvas_server_verify (gnutls_session_t);
 
 int openvas_server_open (gnutls_session_t *, const char *, int);
@@ -74,6 +89,12 @@
 int openvas_server_sendf_xml (gnutls_session_t *, const char *, ...);
 int openvas_server_sendf_xml_quiet (gnutls_session_t *, const char *, ...);
 
+int openvas_connection_sendf_xml (openvas_connection_t *, const char *, ...);
+int openvas_connection_sendf_xml_quiet (openvas_connection_t *, const char *,
+                                        ...);
+
+int openvas_connection_sendf (openvas_connection_t *, const char *, ...);
+
 int openvas_server_new (unsigned int, gchar *, gchar *, gchar *,
                         gnutls_session_t *, gnutls_certificate_credentials_t 
*);
 

Modified: trunk/openvas-libraries/omp/omp.c
===================================================================
--- trunk/openvas-libraries/omp/omp.c   2016-09-21 09:04:30 UTC (rev 26240)
+++ trunk/openvas-libraries/omp/omp.c   2016-09-21 10:24:50 UTC (rev 26241)
@@ -326,6 +326,98 @@
 }
 
 /**
+ * @brief Authenticate with the manager.
+ *
+ * @param[in]  connection  Connection
+ * @param[in]  opts        Struct containing the options to apply.
+ *
+ * @return 0 on success, 1 if manager closed connection, 2 if auth failed,
+ *         3 on timeout, -1 on error.
+ */
+int
+omp_authenticate_info_ext_c (openvas_connection_t *connection,
+                             omp_authenticate_info_opts_t opts)
+{
+  entity_t entity;
+  const char* status;
+  char first;
+  int ret;
+
+  if (opts.timezone)
+    *(opts.timezone) = NULL;
+
+  /* Send the auth request. */
+
+  ret = openvas_connection_sendf_xml_quiet (connection,
+                                            "<authenticate>"
+                                            "<credentials>"
+                                            "<username>%s</username>"
+                                            "<password>%s</password>"
+                                            "</credentials>"
+                                            "</authenticate>",
+                                            opts.username,
+                                            opts.password);
+  if (ret)
+    return ret;
+
+  /* Read the response. */
+
+  entity = NULL;
+  switch (try_read_entity_c (connection, opts.timeout, &entity))
+    {
+      case 0:
+        break;
+      case -4:
+        return 3;
+      default:
+        return -1;
+    }
+
+  /* Check the response. */
+
+  status = entity_attribute (entity, "status");
+  if (status == NULL)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  if (strlen (status) == 0)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  first = status[0];
+  if (first == '2')
+    {
+      entity_t timezone_entity, role_entity, severity_entity;
+      /* Get the extra info. */
+      timezone_entity = entity_child (entity, "timezone");
+      if (timezone_entity && opts.timezone)
+        *opts.timezone = g_strdup (entity_text (timezone_entity));
+      role_entity = entity_child (entity, "role");
+      if (role_entity && opts.role)
+        *opts.role = g_strdup (entity_text (role_entity));
+      severity_entity = entity_child (entity, "severity");
+      if (severity_entity && opts.severity)
+        *opts.severity = g_strdup (entity_text (severity_entity));
+      if (opts.pw_warning)
+        {
+          entity_t pw_warn_entity;
+          pw_warn_entity = entity_child (entity, "password_warning");
+          if (pw_warn_entity)
+            *(opts.pw_warning) = g_strdup (entity_text (pw_warn_entity));
+          else
+            *(opts.pw_warning) = NULL;
+        }
+
+      free_entity (entity);
+      return 0;
+    }
+  free_entity (entity);
+  return 2;
+}
+
+/**
  * @brief Create a task.
  *
  * FIXME: Using the according opts it should be possible to generate
@@ -623,6 +715,68 @@
   return 1;
 }
 
+/**
+ * @brief Start a task and read the manager response.
+ *
+ * @param[in]   connection  Connection.
+ * @param[in]   task_id     ID of task.
+ * @param[out]  report_id   ID of report.
+ *
+ * @return 0 on success, 1 on failure, -1 on error.
+ */
+int
+omp_start_task_report_c (openvas_connection_t *connection, const char *task_id,
+                         char **report_id)
+{
+  entity_t entity;
+  const char *status;
+  char first;
+
+  if (openvas_connection_sendf (connection,
+                                "<start_task task_id=\"%s\"/>",
+                                task_id)
+      == -1)
+    return -1;
+
+  /* Read the response. */
+
+  entity = NULL;
+  if (read_entity_c (connection, &entity)) return -1;
+
+  /* Check the response. */
+
+  status = entity_attribute (entity, "status");
+  if (status == NULL)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  if (strlen (status) == 0)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  first = status[0];
+  if (first == '2')
+    {
+      if (report_id)
+        {
+          entity_t report_id_xml = entity_child (entity, "report_id");
+          if (report_id_xml)
+            *report_id = g_strdup (entity_text (report_id_xml));
+          else
+            {
+              free_entity (entity);
+              return -1;
+            }
+        }
+      free_entity (entity);
+      return 0;
+    }
+  free_entity (entity);
+  return 1;
+}
+
 /** @todo Use this in the other functions. */
 /**
  * @brief Read response and convert status of response to a return value.
@@ -668,6 +822,49 @@
 }
 
 /**
+ * @brief Read response and convert status of response to a return value.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ *
+ * @return 0 on success, -1 or OMP response code on error.
+ */
+int
+check_response_c (openvas_connection_t *connection)
+{
+  int ret;
+  const char* status;
+  entity_t entity;
+
+  /* Read the response. */
+
+  entity = NULL;
+  if (read_entity_c (connection, &entity)) return -1;
+
+  /* Check the response. */
+
+  status = entity_attribute (entity, "status");
+  if (status == NULL)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  if (strlen (status) == 0)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  if (status[0] == '2')
+    {
+      free_entity (entity);
+      return 0;
+    }
+  ret = (int) strtol (status, NULL, 10);
+  free_entity (entity);
+  if (errno == ERANGE) return -1;
+  return ret;
+}
+
+/**
  * @brief Read response status and resource UUID.
  *
  * @param[in]  session  Pointer to GNUTLS session.
@@ -744,6 +941,26 @@
 }
 
 /**
+ * @brief Stop a task and read the manager response.
+ *
+ * @param[in]  session  Pointer to GNUTLS session.
+ * @param[in]  id       ID of task.
+ *
+ * @return 0 on success, OMP response code on failure, -1 on error.
+ */
+int
+omp_stop_task_c (openvas_connection_t *connection, const char* id)
+{
+  if (openvas_connection_sendf (connection,
+                                "<stop_task task_id=\"%s\"/>",
+                                id)
+      == -1)
+    return -1;
+
+  return check_response_c (connection);
+}
+
+/**
  * @brief Resume a task and read the manager response.
  *
  * @param[in]   session    Pointer to GNUTLS session.
@@ -802,6 +1019,64 @@
 }
 
 /**
+ * @brief Resume a task and read the manager response.
+ *
+ * @param[in]   connection  Connection.
+ * @param[in]   task_id     ID of task.
+ * @param[out]  report_id   ID of report.
+ *
+ * @return 0 on success, 1 on OMP failure, -1 on error.
+ */
+int
+omp_resume_task_report_c (openvas_connection_t *connection, const char* 
task_id,
+                          char** report_id)
+{
+  if (openvas_connection_sendf (connection,
+                                "<resume_task task_id=\"%s\"/>",
+                                task_id)
+      == -1)
+    return -1;
+
+  /* Read the response. */
+
+  entity_t entity = NULL;
+  if (read_entity_c (connection, &entity)) return -1;
+
+  /* Check the response. */
+
+  const char* status = entity_attribute (entity, "status");
+  if (status == NULL)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  if (strlen (status) == 0)
+    {
+      free_entity (entity);
+      return -1;
+    }
+  char first = status[0];
+  if (first == '2')
+    {
+      if (report_id)
+        {
+          entity_t report_id_xml = entity_child (entity, "report_id");
+          if (report_id_xml)
+            *report_id = g_strdup (entity_text (report_id_xml));
+          else
+            {
+              free_entity (entity);
+              return -1;
+            }
+        }
+      free_entity (entity);
+      return 0;
+    }
+  free_entity (entity);
+  return 1;
+}
+
+/**
  * @brief Delete a task and read the manager response.
  *
  * @param[in]  session   Pointer to GNUTLS session.

Modified: trunk/openvas-libraries/omp/omp.h
===================================================================
--- trunk/openvas-libraries/omp/omp.h   2016-09-21 09:04:30 UTC (rev 26240)
+++ trunk/openvas-libraries/omp/omp.h   2016-09-21 10:24:50 UTC (rev 26241)
@@ -278,6 +278,9 @@
 
 int omp_authenticate_info_ext (gnutls_session_t*, 
omp_authenticate_info_opts_t);
 
+int omp_authenticate_info_ext_c (openvas_connection_t *,
+                                 omp_authenticate_info_opts_t);
+
 int omp_create_task (gnutls_session_t *, const char *, const char *,
                      const char *, const char *, gchar **);
 
@@ -285,10 +288,16 @@
 
 int omp_start_task_report (gnutls_session_t *, const char *, char **);
 
+int omp_start_task_report_c (openvas_connection_t *, const char *, char **);
+
 int omp_stop_task (gnutls_session_t *, const char *);
 
+int omp_stop_task_c (openvas_connection_t *, const char *);
+
 int omp_resume_task_report (gnutls_session_t*, const char*, char**);
 
+int omp_resume_task_report_c (openvas_connection_t *, const char *, char **);
+
 int omp_get_tasks (gnutls_session_t *, const char *, int, int, entity_t *);
 
 int omp_get_tasks_ext (gnutls_session_t *, omp_get_tasks_opts_t, entity_t *);

Modified: trunk/openvas-libraries/omp/xml.c
===================================================================
--- trunk/openvas-libraries/omp/xml.c   2016-09-21 09:04:30 UTC (rev 26240)
+++ trunk/openvas-libraries/omp/xml.c   2016-09-21 10:24:50 UTC (rev 26241)
@@ -599,6 +599,210 @@
 /**
  * @brief Try read an XML entity tree from the manager.
  *
+ * @param[in]   connection  Connection.
+ * @param[in]   timeout   Server idle time before giving up, in seconds.  0 to
+ *                        wait forever.
+ * @param[out]  entity    Pointer to an entity tree.
+ * @param[out]  string    An optional return location for the text read
+ *                        from the session.  If NULL then it simply
+ *                        remains NULL.  If a pointer to NULL then it points
+ *                        to a freshly allocated GString on successful return.
+ *                        Otherwise it points to an existing GString onto
+ *                        which the text is appended.
+ *
+ * @return 0 success, -1 read error, -2 parse error, -3 end of file, -4 
timeout.
+ */
+int
+try_read_entity_and_string_c (openvas_connection_t *connection, int timeout,
+                              entity_t * entity, GString ** string_return)
+{
+  GMarkupParser xml_parser;
+  GError *error = NULL;
+  GMarkupParseContext *xml_context;
+  GString *string;
+  time_t last_time;
+  /* Buffer for reading from the manager. */
+  char buffer_start[BUFFER_SIZE];
+  /* End of the manager reading buffer. */
+  char *buffer_end = buffer_start + BUFFER_SIZE;
+
+  if (connection->tls)
+    return try_read_entity_and_string (&connection->session, timeout, entity,
+                                       string_return);
+
+  /* Record the start time. */
+
+  if (time (&last_time) == -1)
+    {
+      g_warning ("   failed to get current time: %s\n",
+                 strerror (errno));
+      return -1;
+    }
+
+  if (timeout > 0)
+    {
+      /* Turn off blocking. */
+
+      if (fcntl (connection->socket, F_SETFL, O_NONBLOCK) == -1)
+        return -1;
+    }
+
+  /* Setup return arg. */
+
+  if (string_return == NULL)
+    string = NULL;
+  else if (*string_return == NULL)
+    string = g_string_new ("");
+  else
+    string = *string_return;
+
+  /* Create the XML parser. */
+
+  xml_parser.start_element = handle_start_element;
+  xml_parser.end_element = handle_end_element;
+  xml_parser.text = handle_text;
+  xml_parser.passthrough = NULL;
+  xml_parser.error = handle_error;
+
+  context_data_t context_data;
+  context_data.done = FALSE;
+  context_data.first = NULL;
+  context_data.current = NULL;
+
+  /* Setup the XML context. */
+
+  xml_context =
+    g_markup_parse_context_new (&xml_parser, 0, &context_data, NULL);
+
+  /* Read and parse, until encountering end of file or error. */
+
+  while (1)
+    {
+      int count;
+      while (1)
+        {
+          g_debug ("   asking for %i\n", (int) (buffer_end - buffer_start));
+          count = read (connection->socket, buffer_start,
+                        buffer_end - buffer_start);
+          if (count < 0)
+            {
+              if (errno == EINTR)
+                /* Interrupted, try read again. */
+                continue;
+              if (timeout > 0)
+                {
+                  if ((errno == EAGAIN) || (errno == EAGAIN))
+                    {
+                      /* Server still busy, either timeout or try read again. 
*/
+                      if ((timeout - (time (NULL) - last_time))
+                          <= 0)
+                        {
+                          g_warning ("   timeout\n");
+                          fcntl (connection->socket, F_SETFL, 0L);
+                          g_markup_parse_context_free (xml_context);
+                          return -4;
+                        }
+                    }
+                  continue;
+                }
+              if (context_data.first && context_data.first->data)
+                {
+                  free_entity (context_data.first->data);
+                  g_slist_free_1 (context_data.first);
+                }
+              if (string && *string_return == NULL)
+                g_string_free (string, TRUE);
+              if (timeout > 0)
+                fcntl (connection->socket, F_SETFL, 0L);
+              g_markup_parse_context_free (xml_context);
+              return -1;
+            }
+          if (count == 0)
+            {
+              /* End of file. */
+              g_markup_parse_context_end_parse (xml_context, &error);
+              if (error)
+                {
+                  g_warning ("   End error: %s\n", error->message);
+                  g_error_free (error);
+                }
+              if (context_data.first && context_data.first->data)
+                {
+                  free_entity (context_data.first->data);
+                  g_slist_free_1 (context_data.first);
+                }
+              if (string && *string_return == NULL)
+                g_string_free (string, TRUE);
+              if (timeout > 0)
+                fcntl (connection->socket, F_SETFL, 0L);
+              g_markup_parse_context_free (xml_context);
+              return -3;
+            }
+          break;
+        }
+
+      g_debug ("<= %.*s\n", (int) count, buffer_start);
+
+      if (string)
+        g_string_append_len (string, buffer_start, count);
+
+      g_markup_parse_context_parse (xml_context, buffer_start, count, &error);
+      if (error)
+        {
+          g_error_free (error);
+          // FIX there may be multiple entries in list
+          if (context_data.first && context_data.first->data)
+            {
+              free_entity (context_data.first->data);
+              g_slist_free_1 (context_data.first);
+            }
+          if (string && *string_return == NULL)
+            g_string_free (string, TRUE);
+          if (timeout > 0)
+            fcntl (connection->socket, F_SETFL, 0L);
+          g_markup_parse_context_free (xml_context);
+          return -2;
+        }
+      if (context_data.done)
+        {
+          g_markup_parse_context_end_parse (xml_context, &error);
+          if (error)
+            {
+              g_warning ("   End error: %s\n", error->message);
+              g_error_free (error);
+              if (context_data.first && context_data.first->data)
+                {
+                  free_entity (context_data.first->data);
+                  g_slist_free_1 (context_data.first);
+                }
+              if (timeout > 0)
+                fcntl (connection->socket, F_SETFL, 0L);
+              g_markup_parse_context_free (xml_context);
+              return -2;
+            }
+          *entity = (entity_t) context_data.first->data;
+          if (string)
+            *string_return = string;
+          if (timeout > 0)
+            fcntl (connection->socket, F_SETFL, 0L);
+          g_markup_parse_context_free (xml_context);
+          return 0;
+        }
+
+      if ((timeout > 0) && (time (&last_time) == -1))
+        {
+          g_warning ("   failed to get current time (1): %s\n",
+                     strerror (errno));
+          fcntl (connection->socket, F_SETFL, 0L);
+          g_markup_parse_context_free (xml_context);
+          return -1;
+        }
+    }
+}
+
+/**
+ * @brief Try read an XML entity tree from the manager.
+ *
  * @param[in]   session          Pointer to GNUTLS session.
  * @param[out]  entity           Pointer to an entity tree.
  * @param[out]  string_return    An optional return location for the text read
@@ -618,6 +822,27 @@
 }
 
 /**
+ * @brief Try read an XML entity tree from the manager.
+ *
+ * @param[in]   connection       Connection.
+ * @param[out]  entity           Pointer to an entity tree.
+ * @param[out]  string_return    An optional return location for the text read
+ *                               from the session.  If NULL then it simply
+ *                               remains NULL.  If a pointer to NULL then it 
points
+ *                               to a freshly allocated GString on successful 
return.
+ *                               Otherwise it points to an existing GString 
onto
+ *                               which the text is appended.
+ *
+ * @return 0 success, -1 read error, -2 parse error, -3 end of file.
+ */
+int
+read_entity_and_string_c (openvas_connection_t *connection, entity_t * entity,
+                          GString ** string_return)
+{
+  return try_read_entity_and_string_c (connection, 0, entity, string_return);
+}
+
+/**
  * @brief Read an XML entity tree from the manager.
  *
  * @param[in]   session   Pointer to GNUTLS session.
@@ -649,6 +874,37 @@
   return read_entity_and_string (session, entity, NULL);
 }
 
+/**
+ * @brief Read an XML entity tree from the manager.
+ *
+ * @param[in]   connection  Connection.
+ * @param[out]  entity      Entity tree.
+ * @param[out]  text      A pointer to a pointer, at which to store the
+ *                        address of a newly allocated string holding the
+ *                        text read from the session, if the text is required,
+ *                        else NULL.
+ *
+ * @return 0 success, -1 read error, -2 parse error, -3 end of file.
+ */
+int
+read_entity_and_text_c (openvas_connection_t *connection, entity_t *entity,
+                        char **text)
+{
+  if (text)
+    {
+      GString *string = NULL;
+      int ret = read_entity_and_string_c (connection, entity, &string);
+      if (ret)
+        {
+          if (string)
+            g_string_free (string, TRUE);
+          return ret;
+        }
+      *text = g_string_free (string, FALSE);
+      return 0;
+    }
+  return read_entity_and_string_c (connection, entity, NULL);
+}
 
 /**
  * @brief Read entity and text. Free the entity immediately.
@@ -671,6 +927,26 @@
 }
 
 /**
+ * @brief Read entity and text. Free the entity immediately.
+ *
+ * @param[in]   connection  Connection.
+ * @param[out]  string      Return location for the string.
+ *
+ * @return 0 success, -1 read error, -2 parse error, -3 end of file.
+ */
+int
+read_string_c (openvas_connection_t *connection, GString **string)
+{
+  int ret = 0;
+  entity_t entity;
+
+  if (!(ret = read_entity_and_string_c (connection, &entity, string)))
+    free_entity (entity);
+
+  return ret;
+}
+
+/**
  * @brief Try read an XML entity tree from the manager.
  *
  * @param[in]   session   Pointer to GNUTLS session.
@@ -687,6 +963,23 @@
 }
 
 /**
+ * @brief Try read an XML entity tree from the manager.
+ *
+ * @param[in]   connection  Connection.
+ * @param[in]   timeout     Server idle time before giving up, in seconds.  0 
to
+ *                          wait forever.
+ * @param[out]  entity      Pointer to an entity tree.
+ *
+ * @return 0 success, -1 read error, -2 parse error, -3 end of file, -4 
timeout.
+ */
+int
+try_read_entity_c (openvas_connection_t *connection, int timeout,
+                   entity_t * entity)
+{
+  return try_read_entity_and_string_c (connection, timeout, entity, NULL);
+}
+
+/**
  * @brief Read an XML entity tree from the manager.
  *
  * @param[in]   session   Pointer to GNUTLS session.
@@ -701,6 +994,20 @@
 }
 
 /**
+ * @brief Read an XML entity tree from the manager.
+ *
+ * @param[in]   session   Pointer to GNUTLS session.
+ * @param[out]  entity    Pointer to an entity tree.
+ *
+ * @return 0 success, -1 read error, -2 parse error, -3 end of file.
+ */
+int
+read_entity_c (openvas_connection_t *connection, entity_t *entity)
+{
+  return try_read_entity_c (connection, 0, entity);
+}
+
+/**
  * @brief Read an XML entity tree from a string.
  *
  * @param[in]   string  Input string.

Modified: trunk/openvas-libraries/omp/xml.h
===================================================================
--- trunk/openvas-libraries/omp/xml.h   2016-09-21 09:04:30 UTC (rev 26240)
+++ trunk/openvas-libraries/omp/xml.h   2016-09-21 10:24:50 UTC (rev 26241)
@@ -30,6 +30,8 @@
 #include <gnutls/gnutls.h>
 #include <stdio.h>
 
+#include "../misc/openvas_server.h"
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -87,16 +89,29 @@
 int try_read_entity_and_string (gnutls_session_t *, int, entity_t *,
                                 GString **);
 
+int try_read_entity_and_string_c (openvas_connection_t *, int, entity_t *,
+                                  GString **);
+
 int read_entity_and_string (gnutls_session_t *, entity_t *, GString **);
 
+int read_entity_and_string_c (openvas_connection_t *, entity_t *, GString **);
+
 int read_entity_and_text (gnutls_session_t *, entity_t *, char **);
 
+int read_entity_and_text_c (openvas_connection_t *, entity_t *, char **);
+
 int try_read_entity (gnutls_session_t *, int, entity_t *);
 
+int try_read_entity_c (openvas_connection_t *, int, entity_t *);
+
 int read_entity (gnutls_session_t *, entity_t *);
 
+int read_entity_c (openvas_connection_t *, entity_t *);
+
 int read_string (gnutls_session_t *, GString **);
 
+int read_string_c (openvas_connection_t *, GString **);
+
 int parse_entity (const char *, entity_t *);
 
 void print_entity_to_string (entity_t entity, GString * string);

_______________________________________________
Openvas-commits mailing list
Openvas-commits@wald.intevation.org
https://lists.wald.intevation.org/cgi-bin/mailman/listinfo/openvas-commits

Reply via email to