Add a client library which makes it easy to access rxpd from other programs
authorChristian Thaeter <ct@pipapo.org>
Tue, 22 Jan 2008 12:24:22 +0000 (13:24 +0100)
committerChristian Thaeter <ct@pipapo.org>
Tue, 22 Jan 2008 12:24:22 +0000 (13:24 +0100)
Makefile.am
configure.ac
src/rxpd_client.c [new file with mode: 0644]
src/rxpd_client.h [new file with mode: 0644]

index 3b471cc..a0af235 100644 (file)
@@ -20,6 +20,7 @@ AUTOMAKE_OPTIONS=gnu
 rxpd_srcdir = $(top_srcdir)/src
 
 bin_PROGRAMS = rxpd
+lib_LIBRARIES = librxpd_client.a
 check_PROGRAMS =
 EXTRA_DIST =
 CLEANFILES =
@@ -41,6 +42,19 @@ rxpd_SOURCES =                                       \
        $(rxpd_srcdir)/rxpd_rule.c              \
        $(rxpd_srcdir)/rxpd_socket.c
 
+
+
+#### client library
+
+librxpd_client_a_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Wextra -Werror
+
+librxpd_client_a_SOURCES =             \
+       $(rxpd_srcdir)/rxpd_client.c
+
+include_HEADERS =                      \
+       $(rxpd_srcdir)/rxpd_client.h
+
+
 #### test suite
 
 tests_srcdir = $(top_srcdir)/tests
index b9c9cc6..159b2f3 100644 (file)
@@ -27,6 +27,7 @@ AC_COPYRIGHT([
 #
 AM_PROG_CC_C_O
 AC_PROG_CPP
+AC_PROG_RANLIB
 
 #
 # test for headers
diff --git a/src/rxpd_client.c b/src/rxpd_client.c
new file mode 100644 (file)
index 0000000..ba882d8
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+    rxpd_client.c - regex policy daemon, client library
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <poll.h>
+
+struct rxpd_client
+{
+  char* address;
+  char* port;
+  struct addrinfo* ai;
+
+  char* prefix;
+  FILE* handle;
+  char buf[4096];
+};
+typedef struct rxpd_client* RxpdClient;
+
+/*
+  initialize a RxpdClient handle 'self'
+  'address' is the address of the rxpd to connect to,
+  either "host:port" for TCP or "path/to/socket" notation for unix domain sockets
+  'prefix' is the leading part for any list queried
+ */
+RxpdClient
+rxpd_client_init (RxpdClient self, const char* address, const char* prefix)
+{
+  if (!self || !address)
+    return NULL;
+
+  self->handle = NULL;
+
+  self->address = strdup (address);
+  self->prefix = strdup (prefix);
+  if (!self->prefix || !self->address)
+    return NULL;
+
+  char* delim = strchr (self->address, ':');
+  if (delim)
+    {
+      /* TCP socket */
+      *delim = '\0';
+      self->port = delim+1;
+    }
+  else if (strchr (self->address, '/'))
+    {
+      /* unix domain socket */
+      self->port = NULL;
+      return NULL; /* TODO: rxpd doesnt yet support unix domain sockets */
+    }
+  else
+    {
+      /* syntax error */
+      return NULL;
+    }
+
+  /* resolve peer */
+  self->ai = NULL;
+  if (getaddrinfo (self->address, self->port, NULL, &self->ai))
+    return NULL;
+
+  return self;
+}
+
+
+/*
+  Destruct a rxpd_client structure
+ */
+RxpdClient
+rxpd_client_destroy (RxpdClient self)
+{
+  if (self)
+    {
+      free (self->prefix);
+      free (self->address);
+      if (self->ai)
+        freeaddrinfo (self->ai);
+      if (self->handle)
+        fclose (self->handle);
+    }
+  return self;
+}
+
+
+/*
+  destruct and free a rxpd_client structure
+*/
+void
+rxpd_client_free (RxpdClient self)
+{
+  free (rxpd_client_destroy (self));
+}
+
+
+/*
+  allocate and initialize a rxpd_client structure
+*/
+RxpdClient
+rxpd_client_new (const char* address, const char* prefix)
+{
+  RxpdClient self = malloc (sizeof (struct rxpd_client));
+  if (!rxpd_client_init (self, address, prefix))
+    {
+      rxpd_client_free (self);
+      return NULL;
+    }
+  return self;
+}
+
+
+/*
+  open connection to rxpd if not already open
+ */
+int
+rxpd_client_open (RxpdClient self)
+{
+  if (self && !self->handle)
+    {
+      int fd;
+      fd = socket (self->ai->ai_family, self->ai->ai_socktype, self->ai->ai_protocol);
+      if (fd == -1)
+        return 0;
+
+      if (connect (fd, self->ai->ai_addr, self->ai->ai_addrlen))
+        {
+          close (fd);
+          return 0;
+        }
+
+      self->handle = fdopen (fd, "rb+");
+      if (!self->handle)
+        {
+          close (fd);
+          return 0;
+        }
+
+      /* Local sockets not yet supported */
+    }
+  return 1;
+}
+
+
+/*
+  close connection when open
+ */
+void
+rxpd_client_close (RxpdClient self)
+{
+  if (self->handle)
+    {
+      fclose (self->handle);
+      self->handle = NULL;
+    }
+}
+
+
+/*
+  send a command to the rxpd
+ */
+int
+rxpd_client_cmd (RxpdClient self, const char* command, const char* list)
+{
+  if (!self || !rxpd_client_open (self))
+    return 0;
+
+  if (fprintf (self->handle, "%s:%s%s\n", command, self->prefix?self->prefix:"", list?list:"") < 0)
+    return 0;
+
+  fflush (self->handle);
+  return 1;
+}
+
+
+/*
+  send data to the rxpd
+*/
+int
+rxpd_client_query (RxpdClient self, const char* fmt, ...)
+{
+  if (!self || !rxpd_client_open (self))
+    return 0;
+
+  va_list args;
+  int r;
+  va_start (args, fmt);
+  r = vfprintf (self->handle, fmt, args);
+  va_end (args);
+  if (r < 0)
+    return 0;
+
+  fflush (self->handle);
+  return 1;
+}
+
+
+/*
+  test if data is available for read from rxpd
+*/
+int
+rxpd_client_pending (RxpdClient self, int timeout)
+{
+  if (!self || !self->handle)
+    return -1;
+
+  struct pollfd pollme;
+
+  pollme.fd = fileno (self->handle);
+  pollme.events = POLLIN;
+
+  return poll (&pollme, 1, timeout);
+}
+
+
+/*
+  read a response from rxpd
+
+  this call is blocking
+*/
+const char*
+rxpd_client_recieve (RxpdClient self)
+{
+  if (!self->handle)
+    return NULL;
+  return fgets (self->buf, 4096, self->handle);
+}
+
+
+#ifdef RXPD_CLIENT_EXAMPLE
+int
+main ()
+{
+  /* how to use */
+  RxpdClient query = rxpd_client_new ("galaxy:2345", "ct@pipapo.org/irc_experimental/");
+
+  if (rxpd_client_cmd (query, "CHECK", "xchat"))
+    {
+      const char* response;
+
+      rxpd_client_query (query, "TEST\n\n");
+
+      while (rxpd_client_pending (query, 1000))
+        {
+          response = rxpd_client_recieve (query);
+          printf ("> %s", response);
+        }
+    }
+  rxpd_client_free (query);
+
+  return 0;
+}
+#endif
diff --git a/src/rxpd_client.h b/src/rxpd_client.h
new file mode 100644 (file)
index 0000000..52007a4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    rxpd_client.h - regex policy daemon, client library
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct rxpd_client
+{
+  char* address;
+  char* port;
+  struct addrinfo* ai;
+
+  char* prefix;
+  FILE* handle;
+  char buf[4096];
+};
+typedef struct rxpd_client* RxpdClient;
+
+RxpdClient
+rxpd_client_init (RxpdClient self, const char* address, const char* prefix);
+
+RxpdClient
+rxpd_client_destroy (RxpdClient self);
+
+void
+rxpd_client_free (RxpdClient self);
+
+RxpdClient
+rxpd_client_new (const char* address, const char* prefix);
+
+int
+rxpd_client_open (RxpdClient self);
+
+void
+rxpd_client_close (RxpdClient self);
+
+int
+rxpd_client_cmd (RxpdClient self, const char* command, const char* list);
+
+int
+rxpd_client_query (RxpdClient self, const char* fmt, ...);
+
+int
+rxpd_client_pending (RxpdClient self, int timeout);
+
+const char*
+rxpd_client_recieve (RxpdClient self);