Changeset - da79b5082151
[Not reviewed]
default
0 10 1
Nathan Brink (binki) - 15 years ago 2010-07-23 00:43:32
ohnobinki@ohnopublishing.net
Extend the distren CLI a little bit more and specify some more of the protocol so that the client can be further worked on while cleaning up nonfunctional distrend.
11 files changed with 436 insertions and 116 deletions:
0 comments (0 inline, 0 general)
Makefile.am
Show inline comments
 
@@ -14,49 +14,50 @@ endif
 

	
 
include_HEADERS = src/client/distren.h
 

	
 
lib_LTLIBRARIES = libdistren.la
 
pkglib_LTLIBRARIES = libdistrencommon.la
 

	
 
# libdistrencommon.la:
 
libdistrencommon_la_SOURCES = src/common/asprintf.c src/common/asprintf.h \
 
	src/common/execio.c src/common/execio.h \
 
	src/common/misc.c src/common/misc.h \
 
	src/common/multiio.c src/common/multiio.h \
 
	src/common/options.c src/common/options.h \
 
	src/common/protocol.c src/common/protocol.h \
 
	src/common/remoteio.h \
 
	src/common/remoteio.c src/common/libremoteio.h \
 
	src/common/request.c src/common/request.h
 
#see http://sources.redhat.com/autobook/autobook/autobook_91.html
 
# either increase the revision number or the interface number each release!
 
libdistrencommon_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0
 

	
 
#library client
 
libdistren_la_SOURCES = \
 
	src/client/libdistren.c src/client/libdistren.h \
 
	src/client/libdistren_config.c \
 
	src/client/libdistren_job.c
 
	src/client/libdistren_job.c \
 
	src/client/libdistren_request.c
 
libdistren_la_LIBADD = libdistrencommon.la
 

	
 
#CLI client.
 
distren_SOURCES = \
 
	src/client/distren.c
 
distren_LDADD = libdistrencommon.la libdistren.la
 

	
 
# shared server sources:
 
SERVER_SOURCES = \
 
	src/server/slavefuncs.c	src/server/slavefuncs.h \
 
	src/server/distrenjob.c	src/server/distrenjob.h
 
# distrend:
 
distrend_CFLAGS = $(AM_CFLAGS) $(MYSQL_CFLAGS)
 
distrend_LDFLAGS = $(AM_LDFLAGS) $(MYSQL_LDFLAGS)
 
distrend_SOURCES = $(SERVER_SOURCES) \
 
	src/server/distrend.c	src/server/distrend.h \
 
	src/server/listen.h	src/server/listen.c \
 
	src/server/mysql.h	src/server/mysql.c \
 
	src/server/tabletennis.c	src/server/tabletennis.h \
 
	src/server/user_mgr.c	src/server/user_mgr.h
 

	
 
distrend_LDADD = libdistrencommon.la
 
# distrenslave:
 
distrenslave_SOURCES = $(SERVER_SOURCES) \
doc/architecture.txt
Show inline comments
 
@@ -15,44 +15,50 @@ Concepts:
 
- job: Represents a collection of renderings that must be unbundled, rendered, and bundled together again.
 
  - job identification: A server shall internally assign numeric job identifiers. It must only
 
      make sure that it never issues the same numeric job identifier to multiple jobs. To allow
 
      multiple servers to share jobs with eachother (which is the the whole point of distren),
 
      a job shall be refered to by prefixing the job a server identification. For example,
 
      distren://<servername>/<jobid>
 
  - job packaging: Currently, the most creative way of dealing with jobs I have at the moment is
 
      storing all of the data necessary to render the job in a tarball. This tarball can be
 
      treated as a directory of a normal filesystem. A job's directory would contain at least one
 
      file called ``distrenjob.xml'' which provides information necessary to render the job. This
 
      will be an XML file rather than a rigidly defined binary format because XML supports
 
      arbitrary data storage out of the box. This should allow different rendering backends to
 
      store the extra information that is specific to that backend.
 
  - post-render rebundling: Again, to make things simpler, the server where a job is rendered
 
      shall be responsible for collecting the individual completed frames and collecting them
 
      into a tarball. This tarball may be called for using a client. This tarball is a bundle
 
      of completed frames and will exclude the seed tarball.
 

	
 
- frame: Represents a distinct, and hopefully small, unit of work that a renderer backend can perform.
 
  - frame identification: Like a job numeral is useless without a qualifying servername, a 
 
      frame's identification number would be useless without an accompanying job identifier. The
 
      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>/<frameid>
 
      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.
 

	
 
- 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/distren.c
Show inline comments
 
@@ -129,49 +129,49 @@ int main(int argc, char *argv[])
 
	  printinfo = 1;
 
	  break;
 
	}
 
    }
 

	
 
  
 
     // give this error after the general arguments parsing so that
 
     // the general help from options_init can have effect
 
  if(!username || !password)
 
    {
 
      fprintf(stderr, "Username and password must be specified:\n");
 
      if(!username)
 
	fprintf(stderr, "\tyou did not specify a username\n");
 
      if(!password)
 
	fprintf(stderr, "\tyou did not specify a password\n");
 
      return 1;
 
    }
 
  if(dologin)
 
    {
 
      fprintf(stderr, "Trying username and password on server...");
 
      fprintf(stderr, "STUB\n");
 
      lazy = 0;
 
    }
 

	
 
  if(distren_init_mf(&distren, &malloc, &free))
 
  if(distren_init(&distren))
 
    {
 
      fprintf(stderr, "error initializing the distren handle\n");
 
      return 1;
 
    }
 

	
 
  if(input)
 
    {
 
      if(distren_submit_file(distren, &distren_job, input))
 
	{
 
	  fprintf(stderr, "error submitting file\n");
 
	  return 1;
 
	}
 

	
 
      if(distren_job_geturi(distren_job, &joburi))
 
	{
 
	  fprintf(stderr, "error retrieving joburi\n");
 
	  return 1;
 
	}
 

	
 
      lazy = 0;
 
      fprintf(stdout, "joburi: %s\n", joburi);
 
    }
 

	
 
  if(output)
src/client/distren.h
Show inline comments
 
@@ -7,79 +7,69 @@
 
  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_H
 
#define DISTREN_H 1
 

	
 
/*
 
  Public API for DistRen
 
 */
 

	
 
#include <stddef.h> /* size_t */
 

	
 
typedef struct distren *distren_t;
 

	
 
typedef void* (*distren_malloc_t)(size_t);
 
typedef void (*distren_free_t)(void*);
 

	
 
typedef struct distren_job *distren_job_t;
 

	
 
/**
 
 Initialize a libdistren handle. In the spirit of respecting client programs' choices,
 
 this initialization function allows malloc() and free() compatible function pointers
 
 to be passed.
 
*/
 
int distren_init_mf(distren_t *handle, distren_malloc_t mymalloc, distren_free_t myfree);
 

	
 
/**
 
 Initializes a libdistren handle using the system malloc() and free() implementation.
 
*/
 
 * Initializes a libdistren handle.
 
 */
 
int distren_init(distren_t *handle);
 

	
 
/**
 
 Submits a file to distren.
 
 @param job must not refer to a valid job.
 
 @TODO create a stream-based interface
 
*/
 
int distren_submit_file(distren_t handle, distren_job_t *job, const char *filename);
 

	
 
/**
 
   Retrieve a job-ID that can be used to refer to the job after the client's process has recycled. Currently, this will be the only way to retrieve a job handle (a distren_job_t) and, consequently, the only way to retrieve a finished render.
 
   A job ID is representable using a character string. Hopefully, they will be kept at a reasonably small length. It should be made up of alphanumeric characters so as to be useful in most situations. 
 
   @param jobid This will be set to a string allocated by the specified malloc implementation
 
   @param job The distren_job_t from which to retrieve a jobid
 
*/
 
int distren_job_geturi(distren_job_t job, char **joburi);
 

	
 
/**
 
   Retrieves a tarball of a rendering's result.
 
   @param outfile Filename to save the result to
 
 */
 
int distren_job_retrieve_file(distren_job_t job, const char *outfile);
 

	
 
/*
 
 TODO: extraction of a job-ID, retrieving job handle by job-ID, getting information
 
 for a job handle, retrieving results of a job, callbacks for progress (i.e., job_is_finished callback)
 
 -- threads? -- noooo!
 
*/
 

	
 
/**
 
 Destroys and frees a job handle
 
*/
 
int distren_job_free(distren_job_t job);
 

	
 
/**
 
 Destroys and frees a libdistren handle
 
*/
 
 * Destroys and frees a libdistren handle
 
 */
 
int distren_free(distren_t handle);
 

	
 
#endif
src/client/libdistren.c
Show inline comments
 
/*
 
  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/remoteio.h"
 

	
 
#include "libdistren.h"
 

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

	
 
/**
 
   @todo needs to read configuration in
 
 */
 
int distren_init_mf(distren_t *handle, distren_malloc_t mymalloc, distren_free_t myfree)
 
int distren_init(distren_t *handle)
 
{
 
  if(!handle
 
     || !mymalloc
 
     || !myfree)
 
    {
 
      fprintf(stderr, "distren_init_mf passed NULL pointers\n");
 
      return 1;
 
    }
 
  int tmp;
 

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

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

	
 
  (*handle)->malloc = mymalloc;
 
  (*handle)->free = myfree;
 
  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);
 
      return 1;
 
    }
 
  
 
  /**
 
     @todo open a connection to the server now and return error if we can't
 
     connect. 
 
   */
 

	
 
  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);
 
      return 1;
 
    }
 

	
 
  multiio_poll((*handle)->multiio, 2000);
 
  multiio_poll((*handle)->multiio, 2000);
 
  multiio_poll((*handle)->multiio, 2000);
 
  
 
  return 0;
 
}
 

	
 
int distren_init(distren_t *handle)
 
{
 
  return distren_init_mf(handle, &malloc, &free);
 
}
 

	
 
/**
 
   @todo Stub
 
 * @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
 
@@ -6,80 +6,103 @@
 
  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 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"
 

	
 
struct distren
 
{
 
  distren_malloc_t malloc;
 
  distren_free_t free;
 
  struct options_common *options; /*< use a pointer just to avoid #include "options.h"? */
 
  struct options_common *options;
 
  char *server;
 

	
 
  /* if rem is NULL, we're not connected to the server */
 
  struct remoteio *rem;
 
  /*
 
   * for libdistren_remoteio_read_handle(): determine whether or not
 
   * we've passed through the server's hacky MOTD
 
   */
 
  short done_ad;
 

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

	
 
struct distren_job
 
{
 
  char *jobid;
 
  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
 
/**
 
   All of libdisren should use this instead of malloc.h's free()
 
*/
 
void _free(distren_t distren, void *tofree);
 

	
 
/**
 
 * Sets up the distren handle with information garnered from
 
 * configuration files, etc. Uses the environment variable
 
 * DISTREN_CONFIG or the built-in default config file location.
 
 *
 
 * Also initializes multiio.
 
 */
 
int _distren_getoptions(distren_t handle);
 

	
 
/**
 
 * Unsets-up the distren handle with options loadable from a config file.
 
 *
 
 * Also unloads multiio.
 
 */
 
int _distren_loseoptions(distren_t handle);
 

	
 
/**
 
 * Handle newly read data.
 
 *
 
 * Matches remoteio_read_handle_func_t
 
 */
 
size_t libdistren_remoteio_read_handle(struct remoteio *rem, void *garbage, void *buf, size_t len, distren_t distren);
 

	
 
/**
 
 * React to a remoteio-based connection closing.
 
 *
 
 * Matches remoteio_close_handle_func_t
 
 */
 
void libdistren_remoteio_close_handle(void *garbage, distren_t distren);
 

	
 
#endif
 

	
src/client/libdistren_request.c
Show inline comments
 
new file 100644
 
/*
 
 * 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 "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_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);
 
	  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 const char *package_string = PACKAGE_STRING;
 

	
 
  size_t counter;
 

	
 
  fprintf(stderr, "info: connected to a server running ");
 
  for(counter = 0; counter < req->len; counter ++)
 
    putc(((char *)req_data)[counter], stderr);
 
  putc('\n', stderr);
 

	
 
  /* am I supposed to respond here? ;-) */
 
}
 

	
 
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.c
Show inline comments
 
@@ -93,29 +93,81 @@ int distren_request_new_fromdata(struct 
 
      fputs("\n\tmagic=`", stderr);
 
      debugtmp = DISTREN_REQUEST_MAGIC;
 
      for(counter = 0; counter < sizeof(uint32_t); counter ++)
 
	putc(((char *)&debugtmp)[counter], stderr);
 
      fputs("'\n\t`", stderr);
 
      for(counter = 0; counter < sizeof(struct distren_request); counter ++)
 
	putc(((char *)data)[counter], stderr);
 
      fputs("'\n", stderr);
 
#endif
 
      return 1;
 
    }
 

	
 
  newreq = malloc(sizeof(struct distren_request));
 
  if(!newreq)
 
    {
 
      fprintf(stderr, "OOM\n");
 
      return 1;
 
    }
 

	
 
  memcpy(newreq, data, sizeof(struct distren_request));
 
  (*req) = newreq;
 
  return 0;
 
}
 

	
 
size_t distren_request_handle(size_t *expectlen,
 
			      void *buf,
 
			      size_t len,
 
			      struct distren_request **req,
 
			      void **req_data,
 
			      short *err)
 
{
 
  size_t dead_expectlen;
 

	
 
  *err = 0;
 
  *req = NULL;
 

	
 
  if(!expectlen)
 
    {
 
      dead_expectlen = 0;
 
      expectlen = &dead_expectlen;
 
    }
 

	
 
  if(!*expectlen)
 
    {
 
      if(len < sizeof(struct distren_request))
 
	return 0;
 

	
 
      if(distren_request_new_fromdata(req, buf, len))
 
	{
 
	  fprintf(stderr, "Error trying to handle packet\n");
 
	  *err = 1;
 
	  return 0;
 
	}
 

	
 
      *expectlen = sizeof(struct distren_request) + (*req)->len;
 
    }
 

	
 
  if(!*expectlen
 
     || len < *expectlen)
 
    {
 
      if(*req)
 
	{
 
	  distren_request_free(*req);
 
	  *req = NULL;
 
	}
 

	
 
      return 0;
 
    }
 

	
 
  if(!*req)
 
    distren_request_new_fromdata(req, buf, len);
 
  *req_data = buf + sizeof(struct distren_request);
 

	
 
  return sizeof(struct distren_request) + (*req)->len;
 
}
 

	
 
int distren_request_free(struct distren_request *req)
 
{
 
  free(req);
 
  return 0;
 
}
src/common/protocol.h
Show inline comments
 
@@ -3,140 +3,262 @@
 

	
 
  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_PROTOCOL_H
 
#define DISTREN_PROTOCOL_H
 

	
 
#include <stddef.h>
 
#include <stdint.h>
 

	
 
/**
 
   Server types:
 
 * Server types:
 
 *
 
 * It is assumed that any client has at least the functionality of a
 
 * normal client (i.e., accepts all of the REQUIRED requests). These
 
 * bitmask values add to the types of requests one may make to a
 
 * server. After first connecting to a server or receiving a
 
 * connection, a client shall send a DISTREN_REQUEST_VERSION packet
 
 * describing its version.
 
 */
 
#define DISTREN_SERVERTYPE_SUBMIT (0x1)
 
#define DISTREN_SERVERTYPE_DISTRIBUTE (0x2)
 
#define DISTREN_SERVERTYPE_RENDER (0x4)
 
#define DISTREN_SERVERTYPE_CLIENT (0x8)
 

	
 
/**
 
   This file defines the constants and structs that the client uses to talk to the server and that the servers use to talk to eachother.
 
 * This file defines the constants and structs that distren clients
 
 * and server use to converse.
 
 */
 

	
 

	
 
/**
 
   generic, shared requests
 
 * List of request types and metadata.
 
 */
 
enum distren_request_type
 
  {
 
    /**
 
       identifies the version of software being
 
       used by the sender and tells if it is a client or server.
 
       Just send PACKAGE_STRING.
 
     * identifies the version of software being used by the sender and
 
     * tells if it is a client or server. Sends PACKAGE_STRING as well
 
     * as informing the other server what type of server this is.
 
     *
 
     * DATA: struct distren_request followed by PACKAGE_STRING. The length of PACKAGE_STRING must be no longer than 32 bytes.
 
     *
 
     * REQUIRED: ALL
 
    */
 
    DISTREN_REQUEST_VERSION = 1,
 
    /**
 
     * DATA: up to 32 bytes of a PING cookie
 
     *
 
     * REQUIRED: ALL
 
     */
 
    DISTREN_REQUEST_PING = 2,
 
    /**
 
     * DATA: up to 32 bytes copied from a received PING cookie
 
     *
 
     * REQUIRED: ALL
 
     */
 
    DISTREN_REQUEST_PONG = 3,
 
    /**
 
       The data is the a reason describing why the one end is
 
       disconnecting. The other end should respectfully close()
 
       the socket or the sender will timeout shortly.
 
     * The data is the a reason describing why the one end is
 
     * disconnecting. The other end should respectfully close()
 
     * the socket or the sender will timeout shortly.
 
     *
 
     * DATA: A string describing the reason for the connection's
 
     * termination.
 
     *
 
     * REQUIRED: ALL
 
     */
 
    DISTREN_REQUEST_DISCONNECT = 4,
 

	
 
    /**
 
       client->server only requests
 
    */
 
     * DATA: struct distren_request_submit
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT
 
     */
 
    DISTREN_REQUEST_SUBMIT = 5,
 

	
 
    /**
 
       anything->server requests
 
     * Inform the other party about a job.
 
     *
 
     * DATA: struct distren_request_jobinfo
 
     *
 
     * REQUIRED: ALL
 
     */
 
    DISTREN_REQUEST_JOBINFO = 6, /*< retrieves information about a job based on its number */
 
    DISTREN_REQUEST_JOBINFO = 6,
 

	
 
    /**
 
       server->anything
 
     * Request a DISTREN_REQUEST_JOBINFO
 
     *
 
     * DATA: struct distren_request_jobinfo_get
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT, DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_JOBINFO_RESPONSE = 7, /*< returns information about a job */
 
    DISTREN_REQUEST_JOBINFO_GET = 7,
 

	
 
    /**
 
     * Command the other party to render a frame
 
     *
 
     * DATA: struct distren_request_frame_render
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_RENDER
 
     */
 
    DISTREN_REQUEST_FRAME_RENDER = 8,
 
    /**
 
     * Inform the receiver of the sender's state, such as frames being
 
     * rendered or jobs that need to be completed.
 
     *
 
     * DATA: struct distren_request_status
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_RENDER, DISTREN_SERVERTYPE_DISTRIBUTE, DISTREN_SERVERTYPE_CLIENT
 
     */
 
    DISTREN_REQUEST_STATUS = 9,
 

	
 
    /**
 
       server->server
 
    */
 
    DISTREN_REQUEST_RENDERFRAME = 8,
 
    DISTREN_REQUEST_DONEFRAME = 9, /* server should check to make sure the
 
slave is repoting on a frame it's actually assigned to */
 
    DISTREN_REQUEST_PROGRESS = 10, /*< tells another server of the progress of the first server's work at rendering */
 
    DISTREN_REQUEST_GETWORK = 11,
 
    DISTREN_REQUEST_GETVERSION = 12, /*< returns version of software that slave should be running */
 
    DISTREN_REQUEST_GETRENDERPOWER = 13, /* returns the render power of a slave */
 
    DISTREN_REQUEST_SETRENDERPOWER = 14, /* sets renderpower in server
 
database */
 
     * Request that the receiver send a DISTREN_REQUEST_FRAME_STATUS
 
     * packet. No data because the sending party might not beforehand
 
     * know what frames/jobs the receiving server is managing.
 
     *
 
     * DATA: (none)
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_RENDER
 
     */
 
    DISTREN_REQUEST_STATUS_GET = 10,
 

	
 
    /**
 
       sets a frame back to unassigned,
 
       happens if the slave quits for some reason. server code should only allow
 
       resetting of a frame assigned to the slave calling the request (see php
 
       code)
 
    */ 
 
    DISTREN_REQUEST_RESETFRAME = 15,
 
     * Allow a client to upload a job tarball over a remoteio line.  A
 
     * client that wants to do this must take care not to overbuffer
 
     * his sendqueue so as to be able to respond to PING packets in
 
     * time. A server receiving such a message will want to write the
 
     * file as directly to disk as possible to avoid bagging a server
 
     * down in swap.
 
     *
 
     * It is potential that if a server is DISTREN_SERVERTYPE_SUBMIT
 
     * but not also DISTREN_SERVERTYPE_DISTRIBUTE, that this request
 
     * would be relayed by the DISTREN_SERVERTYPE_SUBMIT server to a
 
     * DISTREN_SERVERTYPE_DISTRIBUTE server so that other clients can
 
     * obtain the file from the distribution server. In this case, the
 
     * file's URL is already known.
 
     *
 
     * Of course, having this sort of functionality at all is where
 
     * the nasty security issues start coming into play :-D.
 
     *
 
     * DATA: struct distren_request_file_post followed by a maximum of 131072 bytes (128kB).
 
     *
 
     * REQUIRED: DISTREN_SERVERTYPE_SUBMIT, DISTREN_SERVERTYPE_DISTRIBUTE
 
     */
 
    DISTREN_REQUEST_FILE_POST = 11,
 

	
 
    /**
 
     * Request information about obtaining a file (such as a
 
     * cURL-compatible URL) based on a distren file URL.
 
     *
 
     * DATA: struct distren_request_file_find
 
     *
 
     * 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;
 
};
 

	
 
/**
 
 * A DISTREN_REQUEST_VERSION is started with a bitmask specification
 
 * of the DISTREN_SERVERTYPE_* values.
 
 */
 
struct distren_request_version
 
{
 

	
 
};
 

	
 
/**
 
 * 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.
 
 *
 
 * @return 0 on success, 1 on failure
 
 */
 
int distren_request_new_fromdata(struct distren_request **req, void *data, size_t len);
 

	
 
/**
 
 * Parses requests in a way suitable to be called from a
 
 * remoteio_read_handle_func_t.
 
 *
 
 * If this function returns non-zero, you should handle the request
 
 * and then call this function again (after shortening len and
 
 * incrementing buf, of course).
 
 *
 
 * @param expectlen A pointer to a state variable that, if not NULL, can speed up this function. If you want to use this, you must set the variable to 0 before the first call and preserve the variable.
 
 * @param buf the input buffer.
 
 * @param len the length of buf.
 
 * @param req a pointer to where we should set NULL if we don't have a full request or where we store the address of a newly allocated request. You should call distren_request_free() on this.
 
 * @param req_data a pointer to where the request data pointer should be stored. This will just be set to a pointer in buf, so don't free() this.
 
 * @param err this will be set to 0 if there is no error and to 1 if there is an error and the connection should be closed. You must check this.
 
 * @return number of bytes that we have used from buf and that should be marked used.
 
 */
 
size_t distren_request_handle(size_t *expectlen,
 
			      void *buf,
 
			      size_t len,
 
			      struct distren_request **req,
 
			      void **req_data,
 
			      short *err);
 

	
 
/**
 
 * frees request
 
 */
 
int distren_request_free(struct distren_request *req);
 

	
 
/**
 
 * An implementation of remoteio_read_handle_func_t for use with remoteio.
 
 *
 
 * To use this handler, first initialize a struct distren_request_remoteio_data.
 
 * (to be continued... or not...? ;-) )
 
 */
 
/* size_t distren_request_remoteio_handle(struct remoteio *rem, void *generic_data, void *buf, size_t len, void *data); */
 

	
 
#endif
src/server/distrend.c
Show inline comments
 
@@ -160,83 +160,58 @@ int main(int argc, char *argv[])
 
  fprintf(stderr,"Finished connecting!\n");
 

	
 
  /** Execute test function */
 
  interactiveTest(test, multiio, &general_info);
 

	
 
  general_info.config->listens = distrend_listens_new(multiio, &general_info, general_info.config->options);
 
  if(!general_info.config->listens)
 
    {
 
      fprintf(stderr, "error initializing listens\n");
 
      return 1;
 
    }
 
  remoteio_generic_data_set(general_info.config->options->remoteio, general_info.config->listens);
 
  for(counter = 0; general_info.config->listen_ports[counter]; counter ++)
 
    {
 
      tmp = distrend_listen_add(general_info.config->listens, general_info.config->listen_ports[counter]);
 
      if(tmp)
 
	{
 
	  fprintf(stderr, "Error listening on port %d\n", general_info.config->listen_ports[counter]);
 
	  return 1;
 
	}
 
    }
 

	
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_VERSION, &distrend_handle_version);
 

	
 
  int slaveKey = 0; // Remotio should set me on a per-slave basis
 
  /* Main Loop */
 
  general_info.config->die = 0;
 
  while(!general_info.config->die)
 
    {
 
      int clientrequest = 0; /*< temporary example variable, will be replaced when we can handle messages */
 

	
 
      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);
 

	
 
      struct frameset frame;
 
      struct distrenjob *job;
 
      distrenjob_new(&job);
 

	
 
      memset(&frame, '\0', sizeof(frame));
 

	
 
      /** If client requests work */
 
      if(clientrequest == DISTREN_REQUEST_GETWORK)
 
	{
 
	  int returnnum = find_jobframe(general_info.conn, slaveKey, &job->jobnum, &frame.num); // Finds a frame to render @FIXME: Slavenum :D
 
	  if(returnnum); /* No work on server */
 
	  else
 
	    remotio_send_to_client(frame.num, job->jobnum); // Pseudo-sends data to client
 
	}
 
      /* If the client states that they finished the frame */
 
      else if(clientrequest == DISTREN_REQUEST_DONEFRAME)
 
	{
 
	  clientstatus = CLIENTSTATUS_IDLE; // Sets the client back to idle
 
	  finish_frame(general_info.conn, 0, job->jobnum, frame.num); // @TODO: Make sure this actually works.
 
	}
 
      distrenjob_free(&job);
 
    }
 

	
 
  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)
 
{
 
  char *tmp_str;
 
  char fixedbuf[32];
 

	
 
  struct distren_request *newreq;
 

	
 
  if(client->state != DISTREND_CLIENT_PREVERSION)
src/server/slavefuncs.c
Show inline comments
 
@@ -875,104 +875,107 @@ int sendExtSignal(struct remoteio *rem, 
 

	
 
  /**
 
   * Just append the data FIXME: We should do this differently
 
   */
 
  _distren_asprintf(&ssignal, "%c%s", signal, data);
 
  len = strlen(ssignal);
 
  remoteio_write(rem, ssignal, len);
 

	
 
  return 0;
 
}
 

	
 

	
 
/* Port of web functions for standard code
 

	
 
   Currently, most functions are stubs due to lack
 
   of socket reading code
 

	
 
   ohnobinki: I can take care of a fair amount of this, but the remotio reading and writing is where you should really lay down some code.
 
*/
 

	
 
/** marks frame finished on server */
 
void finishframe(struct remoteio *rem, int jobnum, int framenum){
 
  char* data;
 
  _distren_asprintf(&data, "%d%d", jobnum, framenum);
 
  sendExtSignal(rem, DISTREN_REQUEST_DONEFRAME, data);
 
  sendExtSignal(rem, DISTREN_REQUEST_STATUS, data);
 
}
 

	
 
/** resets frame to unassigned on server */
 
void resetframe(struct remoteio *rem, int jobnum, int framenum){
 
  fprintf(stderr,"Resetting frame %d in job %d on server... ",framenum,jobnum);
 
  char* data;
 
  _distren_asprintf(&data, "%d%d", jobnum, framenum);
 
 sendExtSignal(rem, DISTREN_REQUEST_RESETFRAME, data);
 
 sendExtSignal(rem, DISTREN_REQUEST_STATUS, data);
 

	
 
}
 

	
 
/** marks frame assigned on server */
 
void startframe(struct remoteio *rem, int jobnum, int framenum){
 
  if(DEBUG)
 
    fprintf(stderr,"Marking frame %d started on server... ",framenum);
 
  char* data;
 
  _distren_asprintf(&data, "%d%d", jobnum, framenum);
 
  sendExtSignal(rem, DISTREN_REQUEST_RENDERFRAME, data);
 
  sendExtSignal(rem, DISTREN_REQUEST_STATUS, data);
 

	
 
}
 

	
 
/**
 
   Greets the server.
 

	
 
   We send PACKAGE_STRING as our version ping thing.
 
 */
 
int greet_server(struct remoteio *rem)
 
{
 
  int err;
 
  struct distren_request *req;
 

	
 
  err = 0;
 

	
 
  fprintf(stderr, "Saying hello to the server ;-)...\n");
 

	
 
  err += distren_request_new(&req, strlen(PACKAGE_STRING), DISTREN_REQUEST_VERSION);
 
  err += distren_request_send(rem, req, PACKAGE_STRING);
 
  err += distren_request_free(req);
 

	
 
  return err;
 
}
 

	
 
/** retrieves job from server */
 
int getwork(struct remoteio *rem, int *jobnum, int *framenum)
 
{
 
  struct distren_request *req;
 
  char *data;
 
  int len; /*< asprintf() uses int, not size_t */
 
  len = _distren_asprintf(&data, "%d.%d", jobnum, framenum);
 

	
 
  //distren_request_new(&req, 
 

	
 

	
 
  sendExtSignal(rem, DISTREN_REQUEST_GETWORK, data);
 
  sendExtSignal(rem, DISTREN_REQUEST_STATUS, data);
 
  return 0;
 
}
 

	
 
/** sets render power of slave on server */
 
void setrenderpower(struct remoteio *rem, int renderpower){
 
void setrenderpower(struct remoteio *rem, int renderpower)
 
{
 
  fprintf(stderr,"Setting render power on server... ");
 
  char* data;
 
  _distren_asprintf(&data, "%d", renderpower);
 
  sendExtSignal(rem,DISTREN_REQUEST_SETRENDERPOWER, data);
 
  /* sendExtSignal(rem,DISTREN_REQUEST_SETRENDERPOWER, data); */
 
}
 

	
 
/** retrieves render power of slave from server */
 
int getrenderpower(struct remoteio *rem){
 
  sendSignal(rem, DISTREN_REQUEST_GETRENDERPOWER);
 
int getrenderpower(struct remoteio *rem)
 
{
 
  /*  sendSignal(rem, DISTREN_REQUEST_GETRENDERPOWER);*/
 
  return 0;
 
}
 

	
 
/** compares slave software version with server software version */
 
int checkslaveversion(struct remoteio *rem){
 
  sendSignal(rem, DISTREN_REQUEST_GETVERSION);
 
int checkslaveversion(struct remoteio *rem)
 
{
 
  sendSignal(rem, DISTREN_REQUEST_VERSION);
 
  char* serverVersionFromRemotio = "9000";
 
  if(!strcmp(PACKAGE_VERSION, serverVersionFromRemotio)) // compare versions
 
    return 1;
 
  return 0;
 
}
0 comments (0 inline, 0 general)