Files @ 27eb6c6418f6
Branch filter:

Location: DistRen/src/common/multiio.c - annotation

binki
Handle resolving hostnames gracefully.
Fix support for hostname:port in remoteio.
Added timeout parameter to multiio_poll().
Fix stupid mistakes in distrenslave's read handler.
The server and client may not sit and play table tennis at last :-D.
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
1c075fe042df
ef03a563218c
ef03a563218c
ef03a563218c
1c075fe042df
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
27eb6c6418f6
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
eb391af42d62
eb391af42d62
27eb6c6418f6
eb391af42d62
eb391af42d62
eb391af42d62
eb391af42d62
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
1c075fe042df
ef03a563218c
eb391af42d62
eb391af42d62
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
eb391af42d62
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
ef03a563218c
/*
  Copyright 2010 Nathan Phillip Brink

  This file is a part of DistRen.

  DistRen is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  DistRen 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "common/multiio.h"

#include <list.h>
#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>

struct multiio_socket_info
{
  /* the type of socket */
  multiio_socket_type_t socket_type;
  /* to be passed to the socket handler */
  void *socket_data;
};

struct multiio_socket_type_info
{
  /* type: struct multiio_socket_type_handler_info */
  list_t type_handlers;
};

/*
  The basic concept is that pollfds is an array. Thus, we have to
  have another array reflecting that array to hold socket-specific
  information.
 */
struct multiio_context
{
  /* the array passed to poll() */
  struct pollfd *pollfds;
  /* the number of entries pollfds could hold */
  nfds_t pollfds_len;
  /* the number of entries that pollfds does hold */
  nfds_t nfds;

  /*
    an array whose order mirrors pollfds containing information
    about the fd mentioned in pollfds.
  */
  struct multiio_socket_info *socket_infos;

  /* the number of socket types registered (equivilent to the type ID of the next registered type) */
  multiio_socket_type_t num_socket_types;
  /* the information about each individual socket type keyed by the type ID */
  struct multiio_socket_type_info *socket_types;
};

/*
  stores information about a handler associated with a socket type/class.
 */
struct multiio_socket_type_handler_info
{
  /* the poll() event to which this handler responds */
  short event;
  /* the handler function to call when the event is matched */
  multiio_event_handler_func_t handler;
  /* the pointer passed to multiio_event_handler_register() */
  void *handler_data;
};

/**
   Finds the index in the context->pollfds array of a particular socket.

   @param context the multiio context
   @param fd the socket to search for
   @param index a pointer which will be filled with the index of the socket if found
   @return 0 if the pollfds entry is found, 1 if the entry is not found
 */
int multiio_pollfd_index_by_fd(const multiio_context_t context, int fd, size_t *index);

multiio_context_t multiio_context_new()
{
  struct multiio_context *context;

  context = malloc(sizeof(struct multiio_context));
  if(!context)
    return NULL;

  context->pollfds = malloc(sizeof(struct pollfd) * 2);
  if(!context->pollfds)
    {
      free(context);
      return NULL;
    }
  context->pollfds_len = 2;
  context->nfds = 0;
  context->socket_infos = malloc(sizeof(struct multiio_socket_info) * 2);

  context->num_socket_types = 0;
  context->socket_types = NULL;

  if(!context->pollfds
     || !context->socket_infos)
    {
      free(context->pollfds);
      free(context->socket_infos);
      free(context);

      return NULL;
    }

  return context;
}

int multiio_context_free(multiio_context_t context)
{
  size_t counter;
  /*
    clean up pollfds and socket_infos
   */
  free(context->pollfds);
  free(context->socket_infos);

  /*
    wipe up the socket_types
   */
  for(counter = 0; counter < context->num_socket_types; counter ++)
    list_free(context->socket_types[counter].type_handlers, LIST_DEALLOC);
  free(context->socket_types);

  /*
    bye!
   */
  free(context);

  return 0;
}

struct multiio_poll_travinfo
{
  multiio_context_t multiio;
  struct multiio_socket_info *socket_info;
  struct pollfd *pollfd;
};
/**
   list traverser for multiio_poll()
 */
int multiio_poll_invoke_handlers(struct multiio_poll_travinfo *travinfo, struct multiio_socket_type_handler_info *handler_info)
{
  short event;

  event = travinfo->pollfd->revents & handler_info->event;
  if(!event)
    return TRUE;

  handler_info->handler(travinfo->multiio,
			travinfo->pollfd->fd,
			event,
			handler_info->handler_data,
			travinfo->socket_info->socket_data);

  return TRUE;
}

int multiio_poll(multiio_context_t context, int timeout)
{
  size_t counter;
  struct multiio_poll_travinfo travinfo;

  int ret;

  ret = poll(context->pollfds, context->nfds, timeout);
  if(ret == -1)
    {
      perror("poll");
    }

  for(counter = 0; counter < context->nfds; counter ++)
    if(context->pollfds[counter].revents)
      {
	travinfo.multiio = context;
	travinfo.socket_info = &context->socket_infos[counter];
	travinfo.pollfd = &context->pollfds[counter];
	list_traverse(context->socket_types[context->socket_infos[counter].socket_type].type_handlers,
		      &travinfo,
		      (list_traverse_func_t)&multiio_poll_invoke_handlers,
		      LIST_FRNT | LIST_SAVE);

	context->pollfds[counter].revents = 0;
      }

  return 0;
}

int multiio_socket_type_register(multiio_context_t context, multiio_socket_type_t *new_type)
{
  struct multiio_socket_type_info *new_socket_types;

  new_socket_types = malloc(sizeof(struct multiio_socket_type_info) * (context->num_socket_types + 1));
  if(!new_socket_types)
    return 1;

  *new_type = context->num_socket_types;
  new_socket_types[*new_type].type_handlers = list_init();
  if(!new_socket_types[*new_type].type_handlers)
    {
      free(new_socket_types);
      return 2;
    }


  if(context->num_socket_types)
    {
      memcpy(new_socket_types, context->socket_types, sizeof(struct multiio_socket_type_info) * context->num_socket_types);
      free(context->socket_types);
    }

  context->socket_types = new_socket_types;
  context->num_socket_types ++;

  return 0;
}

int multiio_event_handler_register(multiio_context_t context, multiio_socket_type_t socket_type, short event, multiio_event_handler_func_t handler_func, void *handler_data)
{
  struct multiio_socket_type_handler_info handler_info;

  if(socket_type >= context->num_socket_types)
    return 1;

  if(!event)
    return 2;

  handler_info.event = event;
  handler_info.handler = handler_func;
  handler_info.handler_data = handler_data;

  list_insert_after(context->socket_types[socket_type].type_handlers, &handler_info, sizeof(struct multiio_socket_type_handler_info));

  return 0;
}

int multiio_socket_add(multiio_context_t context, int fd, multiio_socket_type_t socket_type, void *socket_data, short events)
{
  struct pollfd *pollfds;
  struct multiio_socket_info *socket_infos;
  size_t new_pollfds_len;

  int fdstatus;
  int tmp;

  fdstatus = fcntl(fd, F_GETFL);
  fdstatus |= O_NONBLOCK;
  tmp = fcntl(fd, F_SETFL, fdstatus);
  if(tmp == -1)
    {
      perror("fcntl");
      return 1;
    }

  if(socket_type >= context->num_socket_types)
    return 1;

  /**
     extend sockfds array
   */
  if(context->nfds >= context->pollfds_len)
    {
      new_pollfds_len = (context->pollfds_len + 1) * 2;

      pollfds = malloc(sizeof(struct pollfd) * new_pollfds_len);
      socket_infos = malloc(sizeof(struct multiio_socket_info) * new_pollfds_len);

      if(!pollfds
	 || !socket_infos)
	return 1;

      memcpy(pollfds, context->pollfds, sizeof(struct pollfd) * context->pollfds_len);
      memcpy(socket_infos, context->socket_infos, sizeof(struct multiio_socket_info) * context->pollfds_len);

      free(context->pollfds);
      free(context->socket_infos);

      context->pollfds = pollfds;
      context->socket_infos = socket_infos;
      context->pollfds_len = new_pollfds_len;
    }

  pollfds = context->pollfds;
  socket_infos = context->socket_infos;

  memset(&pollfds[context->nfds], 0, sizeof(struct pollfd));
  pollfds[context->nfds].fd = fd;
  pollfds[context->nfds].events = events;
  socket_infos[context->nfds].socket_type = socket_type;
  socket_infos[context->nfds].socket_data = socket_data;

  context->nfds ++;

  return 0;
}

int multiio_socket_del(multiio_context_t context, int fd)
{
  size_t index;
  int tmp;

  tmp = multiio_pollfd_index_by_fd(context, fd, &index);
  if(tmp)
    return 1;

  /**
   * Special case: one left, if we tried filling in holes... segfault ;-)
   */
  if(context->nfds == 1)
    {
      context->nfds --;
      return 0;
    }

  /**
   * For now we'll unconditionally fill in holes.
   * In fact, it looks simple enough that this method
   * may be what we always use ;-).
   */
  memcpy(&context->pollfds[index], &context->pollfds[context->nfds - 1], sizeof(struct pollfd));
  memcpy(&context->socket_infos[index], &context->socket_infos[context->nfds - 1], sizeof(struct multiio_socket_info));
  context->nfds --;

  return 0;
}

int multiio_socket_event_enable(multiio_context_t context, int fd, short event)
{
  size_t index;
  int tmp;

  tmp = multiio_pollfd_index_by_fd(context, fd, &index);
  if(tmp)
    return 1;

  context->pollfds[index].events |= event;

  return 0;
}

int multiio_socket_event_disable(multiio_context_t context, int fd, short event)
{
  size_t index;
  int tmp;

  tmp = multiio_pollfd_index_by_fd(context, fd, &index);
  if(tmp)
    return 1;

  context->pollfds[index].events &= ~event;

  return 0;
}



int multiio_pollfd_index_by_fd(const multiio_context_t context, int fd, size_t *index)
{
  size_t counter;

  for(counter = 0; counter < context->nfds; counter ++)
    if(context->pollfds[counter].fd == fd)
      {
	*index = counter;
	return 0;
      }

  return 1;
}