Logo Search packages:      
Sourcecode: nautilus-cd-burner version File versions  Download package

mapping-protocol.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
 *
 * mapping-protocol.c - code to talk with the mapping daemon
 *
 * Copyright (C) 2002 Red Hat Inc,
 * Copyright (C) 2005 William Jon McCann <mccann@jhu.edu>
 *
 * The Gnome Library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * The Gnome Library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with the Gnome Library; see the file COPYING.LIB.  If not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Authors: Alexander Larsson <alexl@redhat.com>
 *          William Jon McCann <mccann@jhu.edu>
 */

#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

#include "mapping-protocol.h"

char *
mapping_protocol_get_unix_name (void)
{
      char *path;
      char *name;

      name = g_strdup_printf ("mapping-%s", g_get_user_name ());
      path = g_build_filename (g_get_tmp_dir (), name, NULL);

      g_free (name);

      return path;
}

/* adapted from gamin_data_available() */
int
mapping_protocol_data_available (MappingProtocolChannel *channel)
{
      fd_set         read_set;
      struct timeval tv;
      int            avail;
      int            fd;

      g_return_val_if_fail (channel != NULL, -1);

      /* First check our read buffers */
      if (channel->read_len > 0) {
            return 1;
      }

      fd = g_io_channel_unix_get_fd (channel->iochannel);

 retry:
      FD_ZERO (&read_set);
      FD_SET (fd, &read_set);
      tv.tv_sec = 0;
      tv.tv_usec = 0;

      avail = select (fd + 1, &read_set, NULL, NULL, &tv);
      if (avail < 0) {
            if (errno == EINTR)
                  goto retry;
            g_warning ("Failed to check data availability on socket %d\n", fd);
            return (-1);
      }
      if (avail == 0)
            return (0);
      return (1);
}

MappingProtocolChannel *
mapping_protocol_channel_new (int fd)
{
      MappingProtocolChannel *channel;
      GIOChannel             *iochannel = NULL;

      channel = g_new0 (MappingProtocolChannel, 1);

      iochannel = g_io_channel_unix_new (fd);
      g_io_channel_set_close_on_unref (iochannel, TRUE);

      channel->iochannel = iochannel;
      channel->read_ptr = NULL;
      channel->read_len = 0;
      channel->ref_count = 1;

      return channel;
}

static void
mapping_protocol_channel_free (MappingProtocolChannel *channel)
{
      g_io_channel_unref (channel->iochannel);

      g_free (channel);
      channel = NULL;
}

void
mapping_protocol_channel_ref (MappingProtocolChannel *channel)
{
      g_return_if_fail (channel != NULL);
      g_return_if_fail (channel->ref_count > 0);

      channel->ref_count += 1;
}

void
mapping_protocol_channel_unref (MappingProtocolChannel *channel)
{
      g_return_if_fail (channel != NULL);
      g_return_if_fail (channel->ref_count > 0);

      if (channel->ref_count > 1)
            channel->ref_count -= 1;
      else
            mapping_protocol_channel_free (channel);
}

static int
write_all (MappingProtocolChannel *channel,
         char                       *buf,
         int                     len)
{
      int bytes;
      int bytes_written;
      int fd;

      g_return_val_if_fail (channel != NULL, -1);

      fd = g_io_channel_unix_get_fd (channel->iochannel);

      bytes = 0;
      while (bytes < len) {
            bytes_written = write (fd, buf + bytes, len - bytes);
            if (bytes_written <= 0) {
                  g_warning ("Write error: %s", strerror (errno));
                  return -1;
            }
            bytes += bytes_written;
      }

      return 0;
}

static int
read_all (MappingProtocolChannel *channel,
        char                   *buf,
        int                     len)
{
      int bytes_read;
      int fd;

      g_return_val_if_fail (channel != NULL, -1);

      while (len) {
            if (channel->read_len) {
                  const int tocopy = MIN (len, channel->read_len);

                  memcpy (buf, channel->read_ptr, tocopy);
                  channel->read_len -= tocopy;
                  channel->read_ptr += tocopy;
                  buf += tocopy;
                  len -= tocopy;
                  
                  if (len == 0)
                        break;
            }

            /* Still more to read in, so re-fill the buffer */
            fd = g_io_channel_unix_get_fd (channel->iochannel);

            bytes_read = read (fd, channel->read_buffer, MAPPING_PROTOCOL_BUFFER_LEN);
            if (bytes_read <= 0) {
                  g_warning ("Read error: bytes %d: %s", bytes_read, strerror (errno));
                  return -1;
            }

            /* Reset the counters */
            channel->read_ptr = channel->read_buffer;
            channel->read_len = bytes_read;
      }

      return 0;
}

static int
encode_int (GString *str,
          gint32   val)
{
      char  *ptr;
      gint32 val2;

      val2 = g_htonl (val);

      ptr = (char *) &val2;
      g_string_append_len (str, ptr, 4);
      return 0;
}

static int
decode_int (MappingProtocolChannel *channel,
          gint32                 *out_val)
{
      unsigned char ptr [4];
      guint32       val;
      int           res;

      res = read_all (channel, (char *)ptr, 4);
      if (res != 0) return res;

      val = ptr [0] << 24 |
            ptr [1] << 16 |
            ptr [2] << 8 |
            ptr [3];

      *out_val = (gint32)val;

      return 0;
}

static int
encode_string (GString *gstring,
             char    *str)
{
      int len;
      int res;
      
      if (str == NULL) {
            res = encode_int (gstring, -1);
      } else {
            len = strlen (str);
            res = encode_int (gstring, len);
            if (res == 0)
                  g_string_append (gstring, str);
      }

      return res;
}

static int
decode_string (MappingProtocolChannel *channel,
             char                  **out)
{
      gint32   len;
      int      res;
      char    *str;

      res = decode_int (channel, &len);
      if (res != 0) return res;

      if (len == -1) {
            *out = NULL;
            return 0;
      }

      str = g_malloc (len + 1);

      res = read_all (channel, str, len);
      if (res != 0) {
            g_free (str);
            return res;
      }
      str [len] = 0;

      *out = str;
      return 0;
}

static int
encode_pointer (GString *str,
            gpointer val)
{
      int len;
      int res;

      /* We use only local socket so no need for network byte order conversion */
      
      if (val == NULL) {
            res = encode_int (str, -1);
      } else {
            len = sizeof (gpointer);
            res = encode_int (str, len);
            if (res == 0) {
                  g_string_append_len (str, (char *)&val, len);
            }
      }
      return res;
}

static int
decode_pointer (MappingProtocolChannel *channel,
            gpointer               *out_val)
{
      int       len;
      int       res;
      char     *str;
      gpointer *ptr;

      /* We use only local socket so no need for network byte order conversion */

      res = decode_int (channel, &len);
      if (res != 0) return res;

      if (len == -1) {
            *out_val = NULL;
            return 0;
      }

      str = g_malloc (len);
      res = read_all (channel, str, len);
      if (res != 0) {
            g_free (str);
            return res;
      }

      /* FIXME: compare sizes */

      ptr = g_memdup (str, sizeof (gpointer));

      if (out_val)
            *out_val = *ptr;

      g_free (str);
      g_free (ptr);

      return 0;
}

int
mapping_protocol_request_encode (MappingProtocolChannel *channel,
                         gint32                  operation,
                         char                   *root,
                         char                   *path1,
                         char                   *path2,
                         gboolean                option,
                         void                   *userdata)
{
      int      res;
      GString *str;

      g_return_val_if_fail (channel != NULL, -1);
      
      str = g_string_new (NULL);

      res = encode_int (str, operation);
      if (res != 0) return res;
      
      res = encode_string (str, root);
      if (res != 0) return res;

      res = encode_string (str, path1);
      if (res != 0) return res;

      res = encode_string (str, path2);
      if (res != 0) return res;

      res = encode_int (str, option);
      if (res != 0) return res;

      res = encode_pointer (str, userdata);
      if (res != 0) return res;

      res = write_all (channel, str->str, str->len);
      g_string_free (str, TRUE);
      if (res != 0) return res;

        g_io_channel_flush (channel->iochannel, NULL);

      return 0;
}

int
mapping_protocol_request_decode (MappingProtocolChannel *channel,
                         MappingProtocolRequest     *req)
{
      int res;

      g_return_val_if_fail (channel != NULL, -1);
      
      memset (req, 0, sizeof (MappingProtocolRequest));

      res = decode_int (channel, &req->operation);
      if (res != 0) return res;
      
      res = decode_string (channel, &req->root);
      if (res != 0) return res;

      res = decode_string (channel, &req->path1);
      if (res != 0) return res;

      res = decode_string (channel, &req->path2);
      if (res != 0) return res;

      res = decode_int (channel, &req->option);
      if (res != 0) return res;

      res = decode_pointer (channel, &req->userdata);
      if (res != 0) return res;

      return 0;
}

void
mapping_protocol_request_destroy (MappingProtocolRequest *req)
{
      g_free (req->root);
      g_free (req->path1);
      g_free (req->path2);
}

/* this isn't a real handshake but a more of a sanity check to see if
   there is a listener out there.
 */
static int
encode_handshake (GString *str,
              char     c)
{
      g_string_append_c (str, c);

      return 0;
}

/* this isn't a real handshake but a more of a sanity check to see if
   there is a listener out there.
 */
static int
decode_handshake (MappingProtocolChannel *channel,
              char                    c)
{
      int  res;
      char buf [2];

      memset (buf, 0, sizeof (buf));

      res = read_all (channel, buf, 1);
      if (res != 0) {
            return -1;
      }

      if (buf [0] != c) {
            char *str = g_strdup_printf ("Read %s instead of %c as handshake", buf, c);
            g_error (str);
      }

      return 0;
}

int
mapping_protocol_reply_encode (MappingProtocolChannel *channel,
                         MappingProtocolReply   *reply)
{
      int res;
      int i;
      GString * str;

      g_return_val_if_fail (channel != NULL, -1);

      str = g_string_new (NULL);

      res = encode_handshake (str, 'R');
      if (res != 0) return res;

      res = encode_int (str, reply->result);
      if (res != 0) return res;
      
      res = encode_string (str, reply->path);
      if (res != 0) return res;

      res = encode_int (str, reply->option);
      if (res != 0) return res;

      res = encode_int (str, reply->n_strings);
      if (res != 0) return res;

      for (i = 0; i < reply->n_strings; i++) {
            res = encode_string (str, reply->strings [i]);
            if (res != 0) return res;
      }

      res = write_all (channel, str->str, str->len);
      g_string_free (str, TRUE);
      if (res != 0) return res;

        g_io_channel_flush (channel->iochannel, NULL);
      
      return 0;
}

static void
decode_reply_error (MappingProtocolReply *reply,
                int                   res,
                const char           *message)
{
      char *str;

      str = g_strdup_printf ("Error decoding reply: %s  code: %d result: %d path: %s option: %d n_strings: %d",
                         message,
                         res,
                         reply->result,
                         reply->path, reply->option, reply->n_strings);
      g_error (str);
}

int
mapping_protocol_reply_decode (MappingProtocolChannel *channel,
                         MappingProtocolReply       *reply)
{
      int i;
      int res;

      g_return_val_if_fail (channel != NULL, -1);

      memset (reply, 0, sizeof (MappingProtocolReply));

      res = decode_handshake (channel, 'R');
      if (res != 0) return res;

      res = decode_int (channel, &reply->result);
      if (res != 0) return res;
      
      res = decode_string (channel, &reply->path);
      if (res != 0) return res;

      res = decode_int (channel, &reply->option);
      if (res != 0) return res;

      res = decode_int (channel, &reply->n_strings);
      if (res != 0) return res;

      if (reply->n_strings > 100000)
            decode_reply_error (reply, 0, "Crazy number of strings detected");

      g_assert (reply->n_strings < 100000);
      g_assert (reply->n_strings >= 0);

      reply->strings = g_new0 (char *, reply->n_strings);
      
      for (i = 0; i < reply->n_strings; i++) {
            res = decode_string (channel, &reply->strings [i]);
            if (res != 0) {
                  g_free (reply->strings);
                  reply->strings = NULL;
                  return res;
            }
      }
      
      return 0;
}

void
mapping_protocol_reply_destroy (MappingProtocolReply *reply)
{
#if 0
      int i;
#endif

      g_return_if_fail (reply != NULL);

      g_free (reply->path);

#if 0
      for (i = 0; i < reply->n_strings; i++) {
            g_free (reply->strings [i]);
      }
      g_free (reply->strings);
#endif
}

int
mapping_protocol_monitor_event_encode (MappingProtocolChannel      *channel,
                               MappingProtocolMonitorEvent *event)
{
      int res;
      GString *str;

      g_return_val_if_fail (channel != NULL, -1);

      str = g_string_new (NULL);

      res = encode_handshake (str, 'E');
      if (res != 0) return res;

      res = encode_int (str, event->type);
      if (res != 0) return res;

      res = encode_pointer (str, event->userdata);
      if (res != 0) return res;

      res = encode_string (str, event->path);
      if (res != 0) return res;

      res = write_all (channel, str->str, str->len);
      g_string_free (str, TRUE);
      if (res != 0) return res;

        g_io_channel_flush (channel->iochannel, NULL);

      return 0;
}

int
mapping_protocol_monitor_event_decode (MappingProtocolChannel      *channel,
                               MappingProtocolMonitorEvent *event)
{
      int res;

      g_return_val_if_fail (channel != NULL, -1);

      memset (event, 0, sizeof (MappingProtocolMonitorEvent));

      res = decode_handshake (channel, 'E');
      if (res != 0) return res;

      res = decode_int (channel, &event->type);
      if (res != 0) return res;

      res = decode_pointer (channel, &event->userdata);
      if (res != 0) return res;

      res = decode_string (channel, &event->path);
      if (res != 0) return res;

      return 0;
}

void
mapping_protocol_monitor_event_destroy (MappingProtocolMonitorEvent *event)
{
      g_free (event->path);
}

Generated by  Doxygen 1.6.0   Back to index