Changeset - 7c0e60f07a51
[Not reviewed]
default
0 11 0
Nathan Brink (binki) - 15 years ago 2010-07-25 17:23:16
ohnobinki@ohnopublishing.net
Server and client will connect and send DISTREN_REQUEST_VERSION packets immediately.
11 files changed with 216 insertions and 58 deletions:
0 comments (0 inline, 0 general)
doc/architecture.txt
Show inline comments
 
@@ -36,29 +36,31 @@ Concepts:
 
      numeric value of a frame identification value must be unique to that job. There are no
 
      restrictions of ordering of frame numbers except that they are not to be negative. There
 
      need be no sequencing of frame numbers either. Thus, a frame identification URL would look
 
      like distren://<servername>/<jobid>/frame/<frameid>
 
  - size: A frame hopefully represents a smaller unit of work in terms of the rendering
 
      back-end's capabilities. For example, POV-Ray's CLI can initiate and carry out the rendering
 
      of an entire animation. But distren would hopefully be able to provide a clean method for
 
      rendering each individual frame and bringing the resulting set of files back to the user
 
      in a much shorter time than a single computer could on its own. Many smaller and distinct
 
      is key to a project being benefited by distren.
 
  - dependencies: One cannot escape from frame's completion potentially requiring the completion
 
      of another. Thus, each frame's record must explicitly list the URLs of frames that need to
 
      be completed prior to the said frame. For a server to complete a frame dependent on other
 
      frames, those other frames must be transfered to the first server and made available.
 
  - packaging: To render a single frame and move it about somewhere is normally trivial. However,
 
      one frame or rendering unit of a given backend may produce multiple files. For this reason
 
      and for further uniformity and simplification, the data files representing one frame shall
 
      be transferred using the tarball format.
 

	
 
- client: A distren client is able to submit, query state of, and download completed frames of
 
      jobs registered in a server.
 
  - servers: A server, though having many more functions, shall be able to also perform the list
 
      of actions a client may perform.
 

	
 
- user: A user is an entity which is given access to a distren server.
 

	
 
- file: There are different uses of files above and distributed rendering requires file distribution.
 
  - file identification: Every file mentioned above was at least in the context of a job. Thus,
 
      file identification numbers shall be assigned in the context of a job identification number.
 
      They shall, however, be numeric.
 
      distren://<servername>/<jobid>/file/<fileid>
src/client/libdistren.c
Show inline comments
 
@@ -2,90 +2,125 @@
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 

	
 
  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/>.
 
*/
 

	
 
/*
 
  Implementation of distren_* functions from distren.h excluding distren_job_* functions.
 
 */
 

	
 
#include "common/config.h"
 
#include "common/options.h"
 
#include "common/protocol.h"
 
#include "common/remoteio.h"
 
#include "common/request.h"
 

	
 
#include "libdistren.h"
 

	
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 

	
 
/**
 
 * Handle common cleanup actions for distren_init().
 
 */
 
static void distren_init_cleanup(distren_t distren);
 

	
 
int distren_init(distren_t *handle)
 
{
 
  int tmp;
 

	
 
  struct distren_request *req;
 
  void *data;
 

	
 
  if(!handle)
 
    return 1;
 

	
 
  *handle = malloc(sizeof(struct distren));
 
  if(!*handle)
 
    return 1;
 

	
 
  memset(*handle, 0, sizeof(struct distren));
 

	
 
  /* now the environment is ready for general use */
 
  if(_distren_getoptions(*handle))
 
    {
 
      fprintf(stderr, "error getting configuration\n");
 
      distren_free(*handle);
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 

	
 
  tmp = remoteio_open_server(&(*handle)->rem,
 
			     (*handle)->options->remoteio,
 
			     (remoteio_read_handle_func_t)&libdistren_remoteio_read_handle,
 
			     *handle,
 
			     (remoteio_close_handle_func_t)&libdistren_remoteio_close_handle,
 
			     (*handle)->server);
 
  if(tmp)
 
    {
 
      fprintf(stderr, "error: unable to connect to server\n");
 

	
 
      (*handle)->rem = NULL;
 
      distren_free(*handle);
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 

	
 
  multiio_poll((*handle)->multiio, 2000);
 
  multiio_poll((*handle)->multiio, 2000);
 
  multiio_poll((*handle)->multiio, 2000);
 
  
 
  /* send off a DISTREN_REQUEST_VERSION to the server */
 
  tmp = distren_request_version(&req, &data, DISTREN_SERVERTYPE_CLIENT, PACKAGE_STRING);
 
  if(tmp)
 
    {
 
      fprintf(stderr, "error: unable to allocate request");
 

	
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 
  distren_request_send((*handle)->rem, req, data);
 
  distren_request_free_with_data(req, data);
 

	
 
  while((*handle)->rem
 
	&& (*handle)->state == DISTREN_STATE_VERSION)
 
      multiio_poll((*handle)->multiio, 500);
 

	
 
  if(!(*handle)->rem)
 
    {
 
      distren_init_cleanup(*handle);
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
static void distren_init_cleanup(distren_t distren)
 
{
 
  if(distren->rem)
 
    remoteio_close(distren->rem);
 
  distren->rem = NULL;
 
  distren_free(distren);
 
}
 

	
 
/**
 
 * @todo Stub
 
 */
 
int distren_submit_file(distren_t handle, distren_job_t *job, const char *filename)
 
{
 
  return 1;
 
}
 

	
 
int distren_free(distren_t handle)
 
{
 
  if(handle->rem)
 
    remoteio_close(handle->rem);
 
  free(handle);
 
  return 0;
 
}
src/client/libdistren.h
Show inline comments
 
@@ -9,63 +9,91 @@
 
  (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/>.
 
*/
 

	
 
#ifndef LIBDISTREN_H_
 
#define LIBDISTREN_H_ 1
 

	
 
/*
 
  Private definitions for libdistren.
 
 */
 

	
 
#include "distren.h"
 

	
 
#include "common/multiio.h"
 
#include "common/options.h"
 
#include "common/remoteio.h"
 

	
 
#include <stdint.h>
 

	
 
enum distren_state
 
  {
 
    /**
 
     * client is waiting for a VERSION packet from the server.
 
     */
 
    DISTREN_STATE_VERSION,
 
    /**
 
     * We are waiting to be authenticated.
 
     */
 
    DISTREN_STATE_AUTH,
 
    DISTREN_STATE_NORMAL,
 
    DISTREN_STATE_UPLOADING,
 
  };
 

	
 
struct distren
 
{
 
  struct options_common *options;
 
  char *server;
 

	
 
  /* if rem is NULL, we're not connected to the server */
 
  enum distren_state state;
 

	
 
  /*
 
   * If rem is NULL, we're not connected to the server. This is the
 
   * way to detect a communication error.
 
   */
 
  struct remoteio *rem;
 
  /*
 
   * for libdistren_remoteio_read_handle(): determine whether or not
 
   * we've passed through the server's hacky MOTD
 
   */
 
  short done_ad;
 

	
 
  /*
 
   * The servertype bitmask of the remote server.
 
   */
 
  uint32_t servertype;
 

	
 
  /* something on which to call multiio_poll() ;-) */
 
  multiio_context_t multiio;
 

	
 
  
 
};
 

	
 
struct distren_job
 
{
 
  char *joburi;
 
};
 

	
 
/*
 
  functions
 
*/
 

	
 
/**
 
   Avoid poluting the public namespace until we fix visibility.
 
 */
 
#define _malloc _distren_malloc
 
/**
 
   All of libdistren should use this rather than malloc.h's malloc.
 
 */
 
void *_malloc(distren_t distren, size_t size);
 

	
 
/**
 
   Avoid poluting the public namespace until we fix visibility.
 
 */
 
#define _free _distren_free
src/client/libdistren_request.c
Show inline comments
 
@@ -5,140 +5,156 @@
 
 *
 
 * 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/config.h"
 

	
 
#include "libdistren.h"
 

	
 
#include "common/protocol.h"
 
#include "common/remoteio.h"
 
#include "common/request.h"
 

	
 
static void handle_ping(struct remoteio *rem, struct distren_request *req, void *req_data);
 
static void handle_version(struct remoteio *rem, struct distren_request *req, void *req_data);
 
static void handle_version(distren_t distren, struct distren_request *req, void *req_data);
 
static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data);
 

	
 
size_t libdistren_remoteio_read_handle(struct remoteio *rem, void *garbage, void *buf, size_t len, distren_t distren)
 
{
 
  size_t to_return;
 
  size_t last_len;
 
  short err;
 

	
 
  struct distren_request *req;
 
  void *req_data;
 

	
 
  to_return = 0;
 
  while(!distren->done_ad)
 
    {
 
      if(!len)
 
	return to_return;
 

	
 
      putchar(*(char *)buf);
 
      if(*(char *)buf == '\n')
 
	distren->done_ad = 1;
 

	
 
      len --;
 
      to_return ++;
 
      buf ++;
 
    }
 

	
 
  /* hack to get into the loop at all ;-) */
 
  last_len = 1; 
 
  while(last_len)
 
    {
 
      last_len = distren_request_handle(NULL, buf, len, &req, &req_data, &err);
 
      if(err)
 
	{
 
	  remoteio_close(rem);
 
	  return to_return;
 
	}
 
      if(!last_len)
 
	return to_return;
 

	
 
      switch((enum distren_request_type)req->type)
 
	{
 
	case DISTREN_REQUEST_PING:
 
	  handle_ping(rem, req, req_data);
 
	  break;
 

	
 
	case DISTREN_REQUEST_VERSION:
 
	  handle_version(rem, req, req_data);
 
	  handle_version(distren, req, req_data);
 
	  break;
 

	
 
	case DISTREN_REQUEST_DISCONNECT:
 
	  handle_disconnect(distren, rem, req, req_data);
 
	  break;
 

	
 
	default:
 
	  /*
 
	   * we don't implement everything because we don't need to do
 
	   * so. But, we should complain when we get something we
 
	   * don't recognize because... server protocols change
 
	   * ;-). Oh, and when I'm first writing this, this
 
	   * block will be hit a lot ;-).
 
	   */
 
	  fprintf(stderr, "Unrecognized request type: %lu\n", (unsigned long)req->type);
 
	  break;
 
	}
 

	
 
      distren_request_free(req);
 
      buf += last_len;
 
      len -= last_len;
 
    }
 

	
 
  return to_return;
 
}
 

	
 
void libdistren_remoteio_close_handle(void *garbage, distren_t distren)
 
{
 
  distren->rem = NULL;
 
}
 

	
 

	
 
/* handlers */
 

	
 
static void handle_ping(struct remoteio *rem, struct distren_request *req, void *req_data)
 
{
 
  struct distren_request *pong_req;
 
  void *pong_req_data;
 

	
 
  distren_request_poing(&pong_req, &pong_req_data, 0, req_data, req->len);
 
  distren_request_send(rem, pong_req, pong_req_data);
 
  distren_request_free_with_data(pong_req, pong_req_data);
 
}
 

	
 
static void handle_version(struct remoteio *rem, struct distren_request *req, void *req_data)
 
static void handle_version(distren_t distren, struct distren_request *req, void *req_data)
 
{
 
  static const char *package_string = PACKAGE_STRING;
 

	
 
  size_t counter;
 
  struct distren_request_version version;
 
  int tmp;
 

	
 
  fprintf(stderr, "info: connected to a server running ");
 
  for(counter = 0; counter < req->len; counter ++)
 
    putc(((char *)req_data)[counter], stderr);
 
  putc('\n', stderr);
 
  tmp = distren_request_parse_version(req, req_data, &version);
 
  if(tmp)
 
    {
 
      fprintf(stderr, "error: Invalid DISTREN_REQUEST_VERSION, disconnecting from server\n");
 
      /*
 
       * our remoteio_close handler sets distren->rem to NULL, thus we
 
       * don't need to return an error code.
 
       */
 
      remoteio_close(distren->rem);
 
      return;
 
    }
 
  distren->servertype = version.servertype;
 
  distren->state = DISTREN_STATE_AUTH;
 

	
 
  /* am I supposed to respond here? ;-) */
 
  fprintf(stderr, "info: connected to a server running %s\n", version.package_string);
 
  if(version.servertype & DISTREN_SERVERTYPE_CLIENT)
 
    fprintf(stderr, "\tis a client\n");
 
  if(version.servertype & DISTREN_SERVERTYPE_SUBMIT)
 
    fprintf(stderr, "\taccepts frame submissions\n");
 
  if(version.servertype & DISTREN_SERVERTYPE_RENDER)
 
    fprintf(stderr, "\trenders frames\n");
 
  if(version.servertype & DISTREN_SERVERTYPE_DISTRIBUTE)
 
    fprintf(stderr, "\thandles file distribution\n");
 
}
 

	
 
static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data)
 
{
 
  size_t tmp;
 

	
 
  fputs("warning: The server has disconnected us because ``", stderr);
 
  tmp = fwrite(req_data, 1, req->len, stderr);
 
  fputs("''\n", stderr);
 

	
 
  remoteio_close(distren->rem);
 
}
src/common/protocol.h
Show inline comments
 
@@ -169,55 +169,58 @@ enum distren_request_type
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE_FIND = 12,
 

	
 
    /**
 
     * Provide information about obtaining a file (such as a URL).
 
     *
 
     * DATA: struct distren_request_file
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE = 13,
 
  };
 

	
 
struct distren_request
 
{
 
  uint32_t magic;
 
  /* the length of the data associated with the packet excluding the header */
 
  uint32_t len;
 
  /** treat type as an enum distren_request_type using casting */
 
  uint32_t /* enum distren_request_type */ type;
 
};
 

	
 
#define DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN (32)
 
/**
 
 * A DISTREN_REQUEST_VERSION is started with a bitmask specification
 
 * of the DISTREN_SERVERTYPE_* values.
 
 */
 
struct distren_request_version
 
{
 

	
 
  uint32_t servertype;
 
  /* + 1 is for terminating NULL */
 
  char package_string[DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN + 1];
 
};
 

	
 
/**
 
 * initializes and allocates request
 
 */
 
int distren_request_new(struct distren_request **req, uint32_t len, enum distren_request_type type);
 

	
 
struct remoteio;
 
/**
 
   Takes a struct distren_request and its associated data, allocates
 
   a new block of data to hold the whole packet, and packets the req
 
   header and data together.
 

	
 
   @param rem A remoteio handle to ship this packet off to
 
   @param req Something you initialized with distren_request_new(). You are responsible for distren_request_free()ing this yourself.
 
   @param data A chunk of data the size of req->len. You are responsible for free()ing this yourself.
 
   @return 0 on success and 1 on failure.
 
 */
 
int distren_request_send(struct remoteio *rem, struct distren_request *req, void *data);
 

	
 
/**
 
 * initializes and allocates request based on raw input data
 
 * which includes the headers of the request.
 
 *
src/common/request.c
Show inline comments
 
@@ -9,38 +9,73 @@
 
 * (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/config.h"
 

	
 
#include "common/protocol.h"
 

	
 
#include <stdlib.h>
 
#include <string.h>
 

	
 
int distren_request_free_with_data(struct distren_request *req, void *data)
 
{
 
  free(data);
 
  return distren_request_free(req);
 
}
 

	
 
int distren_request_version(struct distren_request **req, void **data, uint32_t servertype, const char *package_string)
 
{
 
  struct distren_request_version *version;
 

	
 
  distren_request_new(req, sizeof(struct distren_request_version), DISTREN_REQUEST_VERSION);
 
  version = malloc(sizeof(struct distren_request_version));
 
  if(!version || !*req)
 
    {
 
      free(version);
 
      if(*req)
 
	distren_request_free(*req);
 
      return 1;
 
    }
 

	
 
  memset(version, 0, sizeof(struct distren_request_version));
 
  version->servertype = servertype;
 
  strncpy(version->package_string, package_string, DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN);
 

	
 
  *data = version;
 

	
 
  return 0;
 
}
 

	
 
int distren_request_parse_version(struct distren_request *req, void *data, struct distren_request_version *version)
 
{
 
  if(req->len < sizeof(struct distren_request_version))
 
    return 1;
 

	
 
  memcpy(version, data, sizeof(struct distren_request_version));
 
  /* there is space for another '\0' */
 
  version->package_string[DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN] = '\0';
 

	
 
  return 0;
 
}
 

	
 
int distren_request_poing(struct distren_request **req, void **data, short is_ping, const void *poing_cookie, size_t poing_data_len)
 
{
 
  enum distren_request_type type;
 

	
 
  if(is_ping)
 
    type = DISTREN_REQUEST_PING;
 
  else
 
    type = DISTREN_REQUEST_PONG;
 
  distren_request_new(req, poing_data_len, type);
 
  (*data) = malloc(poing_data_len);
 
  memcpy(*data, poing_cookie, poing_data_len);
 

	
 
  return 0;
 
}
src/common/request.h
Show inline comments
 
/*
 
 * 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/>.
 
 */
 

	
 
#ifndef _DISTREN_REQUEST_H
 
#define _DISTREN_REQUEST_H
 

	
 
#include "common/protocol.h"
 

	
 
/**
 
 * @file functions to initialize various requests that the server and
 
 * client may both use.
 
 */
 

	
 

	
 
/**
 
 * Free any request made with one of the functions below
 
 */
 
int distren_request_free_with_data(struct distren_request *req, void *data);
 

	
 
/**
 
 * Initialize a VERSION request.
 
 *
 
 * @param req pointer to where the poitner to the new req should be stored..
 
 * @param data pointer to where the newly allocated data's address should go.
 
 * @param servertype the ORing of different DISTREN_SERVERTYPE_* constants.
 
 * @param package_string the PACKAGE_STRING constant.
 
 */
 
int distren_request_version(struct distren_request **req, void **data, uint32_t servertype, const char *package_string);
 

	
 
/**
 
 * Parses a DISTREN_REQUEST_VERSION packet.
 
 *
 
 * @param req the request to parse.
 
 * @param data the request's data.
 
 * @param version where the result should be stored.
 
 * @return 0 on success, 1 if the packet is invalid (if the length of package_version is longer than 32-bytes, for example).
 
 */
 
int distren_request_parse_version(struct distren_request *req, void *data, struct distren_request_version *version);
 

	
 
/**
 
 * Initialize a PING or PONG request.
 
 *
 
 * @param data a place to allocate storage for the data associated with this request
 
 * @param is_ping 1 if this is a DISTREN_REQUEST_PING or 0 if this is a DISTREN_REQUEST_PONG
 
 * @param poing_cookie chocolate chip, chocolate chunk, or oatmeal chocolate chip
 
 * @param poing_data_len bytes in the poing_cookie
 
 * @return the length of the data allocated for this request
 
 */
 
uint32_t distren_request_poing(struct distren_request **req, void **data, short is_ping, const void *poing_cookie, size_t poing_data_len);
 

	
 
#endif /* _DISTREN_REQUEST_H */
src/server/distrend.c
Show inline comments
 
@@ -10,48 +10,49 @@
 

	
 
  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/>.
 

	
 
*/
 

	
 
/* This file contains the code which both processes (renders) jobs as a slave, and the code which distributes frames to slaves after receiving them from the client portion of the codebase. */
 

	
 
#include "common/config.h"
 

	
 
#include "distrenjob.h"
 
#include "listen.h"
 
#include "slavefuncs.h"
 
#include "mysql.h"
 

	
 
#include "common/asprintf.h"
 
#include "common/execio.h"
 
#include "common/options.h"
 
#include "common/protocol.h"
 
#include "common/request.h"
 

	
 
#include <confuse.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <sys/stat.h>
 
#include <sys/types.h>
 
#include <time.h>
 
#include <unistd.h>
 

	
 
#include <libxml/encoding.h>
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 
#include <libxml/xmlmemory.h>
 
#include <libxml/xmlreader.h>
 
#include <libxml/xmlwriter.h>
 

	
 
/* ******************* Structs ************************ */
 
struct general_info
 
{
 
  struct distrenjob head;
 
  distrend_mysql_conn_t conn;
 

	
 
  struct distrend_config *config;
 
@@ -68,49 +69,49 @@ struct general_info
 
  unsigned int rendering_clients;
 
  unsigned int total_finished_jobs;
 
  unsigned int total_frames_rendered;
 
  unsigned int highest_jobnum;
 
  int hibernate;
 
  time_t timestamp;
 
  unsigned long total_render_power;
 
  unsigned long total_priority_pieces;
 
};
 

	
 

	
 
/* *********************************************
 
   Function Prototypes
 
   ********************************************* */
 

	
 
/* ************General Functions************* */
 
int distrend_do();
 
int distrend_do_config(int argc, char *argv[], struct distrend_config **config, multiio_context_t multiio);
 
int distrend_config_free(struct distrend_config *config);
 
int distrend_handle_request(struct distrend_listens *listens, struct distrend_client *client, struct distren_request *req, void *reqdata, struct general_info *geninfo);
 

	
 
/**
 
   client request handlers
 
 */
 
int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data);
 
int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 

	
 
/* **************XML Functions**************** */
 
void update_general_info(struct general_info *geninfo);
 
int import_general_info(struct general_info *general_info);
 
int update_xml_joblist(struct general_info *geninfo);
 

	
 
/* **************Test Functions**************** */
 
int interactiveTest(int test, multiio_context_t multiio, struct general_info *general_info);
 

	
 
/* **************** Main ********************* */
 
int main(int argc, char *argv[])
 
{
 
  /* Parse arguments */
 
  int counter;
 
  int test = 0; /*< Interactive mode if 1 */
 
  int tmp;
 
  struct general_info general_info;
 
  multiio_context_t multiio;
 

	
 
  enum clientstatus
 
  {
 
    CLIENTSTATUS_UNINITIALIZED = 0,
 
    CLIENTSTATUS_BUSY = 1,
 
    CLIENTSTATUS_IDLE = 2
 
@@ -186,88 +187,90 @@ int main(int argc, char *argv[])
 
  while(!general_info.config->die)
 
    {
 
      multiio_poll(multiio, 15000);
 

	
 
      tabletennis_serve(general_info.config->listens->tabletennis);
 

	
 
      /* Run the watchdog, @TODO: like every 10 mins or something */
 
      frame_watchdog(general_info.conn);
 
    }
 

	
 
  distrend_listen_free(general_info.config->listens);
 
  distrend_config_free(general_info.config);
 

	
 
  xmlcleanup();
 

	
 
  /** free() paths */
 
  free(general_info.files.geninfo);
 
  mysqlDisconnect(general_info.conn);
 

	
 
  return 0;
 
}
 

	
 
/* ********************** Functions ************************* */
 

	
 
int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data)
 
int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data)
 
{
 
  char *tmp_str;
 
  char fixedbuf[32];
 
  struct distren_request_version version;
 

	
 
  struct distren_request *newreq;
 
  if(distren_request_parse_version(req, req_data, &version))
 
    {
 
      distrend_send_disconnect(client, "Invalid DISTREN_REQUEST_VERSION packet.");
 
      return 1;
 
    }
 

	
 
  if(client->state != DISTREND_CLIENT_PREVERSION)
 
    {
 
      distrend_send_disconnect(client, "You have already sent the VERSION command.");
 
      return 1;
 
    }
 
  if(strlen(PACKAGE_STRING) == req_len
 
     && !strncmp(PACKAGE_STRING, req_data, req_len))
 
  if(!strncmp(PACKAGE_STRING, version.package_string, DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN))
 
    {
 
      /**
 
	 The client and I claim to be of the same version of distren :-D
 
	 Now we will mark the client as valid.
 

	
 
	 We won't increment his time to live, though, because it shouldn't take
 
	 him that long to auth.
 
      */
 
       * The client and I claim to be of the same version of distren :-D
 
       * Now we will mark the client as valid.
 
       *
 
       * We won't increment his time to live, though, because it shouldn't take
 
       * him that long to auth.
 
       */
 
      client->state = DISTREND_CLIENT_PREAUTH;
 

	
 
      distren_request_new(&newreq, strlen(PACKAGE_STRING), DISTREN_REQUEST_VERSION);
 
      distrend_client_write_request(client, newreq, PACKAGE_STRING);
 
      distren_request_free(newreq);
 
    }
 
  else
 
    {
 
      /**
 
	 The client claims to be of a different version of distren.
 
	 Now we will just send a disconnect packet and disconnect the client.
 
      */
 
      strncpy(fixedbuf, req_data, 31);
 
      fixedbuf[31] = '\0';
 
      if(req_len < 31)
 
	fixedbuf[req_len] = '\0';
 

	
 
      _distren_asprintf(&tmp_str, "You have tried to connect to a %s server when your client claims to be running %s. Bye ;-)\n", PACKAGE_STRING, fixedbuf);
 
      distrend_send_disconnect(client, tmp_str);
 
       * The client claims to be of a different version of distren.
 
       * Now we will just send a disconnect packet and disconnect the client.
 
       */
 
      _distren_asprintf(&tmp_str, "You have tried to connect to a %s server when your client claims to be running %s. Bye ;-)\n", PACKAGE_STRING, version.package_string);
 
      if(tmp_str)
 
	{
 
	  distrend_send_disconnect(client, tmp_str);
 
	  free(tmp_str);
 
	}
 
      else
 
	distrend_send_disconnect(client, "Invalid PACKAGE_VERSION :-|.");
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
/**
 
   Performs command stored in a client's request. @TODO: Fill stub
 
*/
 
int distrend_do()
 
{
 
  return 0;
 
}
 

	
 
/* Grabs config info from confs */
 
int distrend_do_config(int argc, char *argv[], struct distrend_config **config, multiio_context_t multiio)
 
{
 
  unsigned int counter;
 

	
 
  cfg_opt_t myopts_listen[] =
 
    {
 
      CFG_SIMPLE_STR("type", NULL),
 
      CFG_SIMPLE_STR("path", NULL),
 
      CFG_SIMPLE_INT("port", NULL),
 
      CFG_END()
src/server/listen.c
Show inline comments
 
@@ -2,48 +2,49 @@
 
  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/config.h"
 

	
 
#include "listen.h"
 

	
 
#include "common/protocol.h"
 
#include "common/remoteio.h"
 
#include "common/request.h"
 

	
 
#include <errno.h>
 
#include <list.h>
 
#include <netinet/in.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <sys/types.h>
 
#include <poll.h>
 
#include <sys/socket.h>
 
#include <unistd.h>
 

	
 
/* local */
 

	
 
struct distrend_request_handler_info
 
{
 
  enum distren_request_type request_type;
 
  distrend_handle_request_func_t handler;
 
};
 

	
 
struct distrend_client *distrend_client_new(struct distrend_listens *listens,
 
					    enum distrend_client_state state,
 
					    struct remoteio *rem);
 
int distrend_client_free(struct distrend_client *client);
 
@@ -259,77 +260,90 @@ int listen_handle_existence(multiio_cont
 
      }
 
  return 0;
 
}
 

	
 
struct distrend_accept_client_proc_data
 
{
 
  struct distrend_listens *listens;
 
  time_t current_time;
 
};
 

	
 

	
 
/**
 
 * Handle new connections.
 
 */
 
int listen_handle_accept(multiio_context_t multiio,
 
			 int fd,
 
			 short revent,
 
			 struct distrend_listens *listens,
 
			 int *port)
 
   //int distrend_accept(struct distrend_listens *listens)//, struct distrend_clientset *clients, distrend_handle_request_t handlereq, void *handlereqdata)
 
 {
 
   struct distrend_client *newclient;
 

	
 
   int newclientsock;
 

	
 
   struct remoteio *rem;
 

	
 
   struct distren_request *req;
 
   void *data;
 

	
 
   newclientsock = accept(fd, (struct sockaddr *)NULL, (socklen_t *)NULL);
 
   /* used to call int distrend_client_add(struct distrend_listens *listens, int sock, DISTREND_CLIENT_PREVERSION)*/
 

	
 
   newclient = distrend_client_new(listens, DISTREND_CLIENT_PREVERSION, NULL);
 

	
 
   if(remoteio_open_socket(&rem, listens->options->remoteio, (remoteio_read_handle_func_t)&distrend_listen_read_handle, newclient, (remoteio_close_handle_func_t)&distrend_listen_remoteio_handle_close, newclientsock))
 
     {
 
       fprintf(stderr, "error allocating/adding client struct\n");
 
       return 1;
 
     }
 
   newclient->rem = rem;
 

	
 
   fprintf(stderr, "accepted new connection; fd=%d\n", newclientsock);
 

	
 
   /* tabletennis */
 
   tabletennis_add_client(listens->tabletennis, newclient);
 

	
 
   /**
 
    * For those using netcat/telnet to debug their internets.
 
    */
 
 #ifndef PACKAGE_URL
 
 #define PACKAGE_URL "http://ohnopub.net/distren/"
 
 #endif
 
 #define DISTREN_GREETING PACKAGE_STRING " " PACKAGE_URL " : Nathan Phillip Brink && Ethan Michael Zonca\n"
 
   /* using sizeof() - 1 because the sizeof() includes a NULL byte we want to ignore. */
 
   remoteio_write(newclient->rem, DISTREN_GREETING, sizeof(DISTREN_GREETING) - 1);
 

	
 
   /* send a DISTREN_REQUEST_VERSION immediately as per protocol */
 
   distren_request_version(&req, &data,
 
			   DISTREN_SERVERTYPE_SUBMIT
 
			   | DISTREN_SERVERTYPE_DISTRIBUTE
 
			   | DISTREN_SERVERTYPE_RENDER,
 
			   PACKAGE_STRING);
 
   distren_request_send(rem, req, data);
 
   distren_request_free_with_data(req, data);
 

	
 
   /*
 
   list_mvfront(listens->clients);
 
   newclient = list_curr(listens->clients);
 
   while(newclient)
 
     {
 
       if(newclient->state == DISTREND_CLIENT_DEAD)
 
	 {
 
	   distrend_listen_poll_deletefd(listens, &newclient->sock);
 
	   distrend_client_free(newclient);
 
	   list_remove_curr(listens->clients);
 
	   fprintf(stderr, "removed dead connection\n");
 
	 }
 
       list_mvnext(listens->clients);
 
   *//* provide for termination of this loop *//*
 
       if(newclient == list_curr(listens->clients))
 
	 newclient = NULL;
 
       else
 
	 newclient = list_curr(listens->clients);
 
     }
 
					       */
 
   return 0;
 
 }
 

	
 
 /**
 
@@ -544,47 +558,47 @@ int distrend_listen_handler_add(struct d
 
  if(!handler_info)
 
    return 1;
 

	
 
  handler_info->request_type = type;
 
  handler_info->handler = handler;
 
  list_insert_after(listens->request_handlers, handler_info, 0);
 

	
 
  return 0;
 
}
 

	
 
struct distrend_dispatch_request_data
 
{
 
  struct general_info *geninfo;
 
  struct distrend_client *client;
 
  struct distren_request *req;
 
  void *req_data;
 
};
 

	
 
/**
 
   traversal function for distrend_dispatch_request().
 
 */
 
int _distrend_dispatch_request_trav(struct distrend_dispatch_request_data *data, struct distrend_request_handler_info *handler_info)
 
{
 
  if(handler_info->request_type == data->req->type)
 
    (*handler_info->handler)(data->geninfo, data->client, data->req->len, data->req_data);
 
    (*handler_info->handler)(data->geninfo, data->client, data->req, data->req_data);
 

	
 
  return TRUE;
 
}
 

	
 
/**
 
   helper for distrend_listen_read_handle() which looks up the correct
 
   request handler and handles handing the the request to the
 
   handler. :-p
 
*/
 
int distrend_dispatch_request(struct distrend_listens *listens, struct remoteio *rem, struct distrend_client *client, struct distren_request *req, void *reqdata)
 
{
 
  struct distrend_dispatch_request_data data;
 

	
 
  data.geninfo = listens->geninfo;
 
  data.client = client;
 
  data.req = req;
 
  data.req_data = reqdata;
 

	
 
  list_traverse(listens->request_handlers, &data, (list_traverse_func_t)&_distrend_dispatch_request_trav, LIST_FRNT | LIST_SAVE);
 

	
 
  return 0;
 
}
src/server/listen.h
Show inline comments
 
@@ -119,53 +119,53 @@ struct distrend_client
 
     used to implement ping timeouts (if state == DISTREND_CLIENT_GOOD) and 
 
     disconnect message grace time (if state == DISTREND_CLIENT_BAD).
 
   */
 
  time_t cleanup_time;
 

	
 
  size_t inlen; /*< number of bytes waiting to be processed */
 
  size_t expectlen; /*< number of bytes that inlen has to be for a complete request to be had, 0 when waiting on header */
 

	
 
  struct tabletennis_client tabletennis_client;
 

	
 
  /**
 
   * Yes, even though the remoteio will have a void *pointer to this
 
   * struct, we need a reverse pointer for something like
 
   * distrend_client_write() to work.
 
   */
 
  struct remoteio *rem;
 
};
 

	
 

	
 

	
 
/**
 
   A function signature that may be registered as a client
 
   request handler.
 

	
 
   @param client the client that sent the request
 
   @param len the length of the message in bytes
 
   @param data the message received from the client
 
   @param client the client that sent the request.
 
   @param req the distren request header.
 
   @param data the message received from the client.
 
 */
 
typedef int(*distrend_handle_request_func_t)(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data);
 
typedef int(*distrend_handle_request_func_t)(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 

	
 
/**
 
   Initializes the listens member of struct distrend_config.
 

	
 
   @param multiio the multiio context in which we should register a new socket type and insert records for clients who connect.
 
   @param geninfo general info to apss to the request handler.
 
   @return Must be free()d with distrend_listen_free();
 
*/
 
struct distrend_listens *distrend_listens_new(multiio_context_t multiio, struct general_info *geninfo, struct options_common *opts);
 

	
 
/**
 
   Adds a socket and configures it to listen().
 

	
 

	
 
   @param listens The handle for this set of listens, obtained via distrend_listen_init().
 
 */
 
int distrend_listen_add(struct distrend_listens *listens, int port);
 

	
 
/**
 
 * Register a request handler with the listener.
 
 *
 
 * @param config distrend's configuration
 
 * @param type the request type for which this handler should be called
 
 * @param handler the handler to call when a request of type type is received.
src/server/tabletennis.c
Show inline comments
 
@@ -24,50 +24,50 @@
 
#include "tabletennis.h"
 

	
 
#include "common/request.h"
 
#include "common/protocol.h"
 

	
 
#include <queue.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <time.h>
 

	
 
struct tabletennis
 
{
 
  unsigned int ping_interval;
 
  unsigned int pong_time;
 

	
 
  /* of type (struct distrend_client *) */
 
  queue_t clients_to_ping;
 

	
 
  /* of type (struct distrend_client *) */
 
  queue_t clients_need_pong;
 

	
 
  struct timespec time_last_check;
 
};
 

	
 
static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data);
 
static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data);
 
static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 
static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data);
 

	
 
tabletennis_t tabletennis_new(struct distrend_listens *listens, unsigned int ping_interval, unsigned int pong_time)
 
{
 
  tabletennis_t tabletennis;
 

	
 
  tabletennis = malloc(sizeof(struct tabletennis));
 

	
 
  tabletennis->ping_interval = ping_interval;
 
  tabletennis->pong_time = pong_time;
 
  tabletennis->clients_to_ping = q_init();
 
  tabletennis->clients_need_pong = q_init();
 
  clock_gettime(CLOCK_MONOTONIC, &tabletennis->time_last_check);
 

	
 
  distrend_listen_handler_add(listens, DISTREN_REQUEST_PING, &tabletennis_ping_request_handle);
 
  distrend_listen_handler_add(listens, DISTREN_REQUEST_PONG, &tabletennis_pong_request_handle);
 

	
 
  return tabletennis;
 
}
 

	
 
int tabletennis_add_client(tabletennis_t tabletennis, struct distrend_client *client)
 
{
 
  client->tabletennis_client.state = TABLETENNIS_NEED_PING;
 
  client->tabletennis_client.time_next_check = tabletennis->time_last_check.tv_sec
 
    + tabletennis->ping_interval;
 
@@ -172,64 +172,64 @@ int tabletennis_del_client(tabletennis_t
 

	
 
  list_traverse(thelist, (void *)client, (list_traverse_func_t)&tabletennis_del_client_traverse,
 
		LIST_FORW | LIST_FRNT | LIST_SAVE);
 
  if(list_curr(thelist) == client)
 
    list_remove_curr(thelist);
 

	
 
  return 0;
 
}
 

	
 
void tabletennis_free(tabletennis_t tabletennis)
 
{
 
  q_free(tabletennis->clients_to_ping, LIST_NODEALLOC);
 
  q_free(tabletennis->clients_need_pong, LIST_NODEALLOC);
 

	
 
  free(tabletennis);
 
}
 

	
 
/* implementations of locals */
 

	
 
/**
 
 * Handles a DISTREN_REQUEST_PING from a client.
 
 *
 
 * @todo throttling?
 
 */
 
static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data)
 
static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data)
 
{
 
  struct distren_request *pong_req;
 

	
 
  if(req_len > 32)
 
  if(req->len > 32)
 
    distrend_send_disconnect(client, "You have tried to send a PING packet with a length longer than 32 bytes.");
 

	
 
  /**
 
      respond to the client using the data he sent in his PONG
 
      command.
 
   */
 
  distren_request_new(&pong_req, req_len, DISTREN_REQUEST_PONG);
 
  distren_request_new(&pong_req, req->len, DISTREN_REQUEST_PONG);
 
  distrend_client_write_request(client, pong_req, req_data);
 
  distren_request_free(pong_req);
 

	
 
  return 0;
 
}
 

	
 
static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data)
 
static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data)
 
{
 
  fprintf(stderr, "got pong\n");
 

	
 
  /*
 
   * The only place that sends PINGs from distrend is
 
   * tabletennis_serve() and it uses
 
   * client->tabletennis_client.time_next_check as the cookie.
 
   */
 
  if(client->tabletennis_client.state == TABLETENNIS_NEED_PONG
 
     && req_len == sizeof(client->tabletennis_client.time_next_check)
 
     && req->len == sizeof(client->tabletennis_client.time_next_check)
 
     && !memcmp(req_data, &client->tabletennis_client.time_next_check, sizeof(client->tabletennis_client.time_next_check)))
 
    {
 
      /* valid match */
 
      client->tabletennis_client.state = TABLETENNIS_HAS_PONG;
 

	
 
      return 0;
 
    }
 
  /* no match or invalid state */
 
  distrend_send_disconnect(client, "You tried to send a PONG packet without first receiving a PING packet.");
 
  return 0;
 
}
0 comments (0 inline, 0 general)