Changeset - abcf8952747b
AUTHORS
Show inline comments
 
DistRen is a joint initiative of [protofusion] (http://protofusion.org/) and Oh! No! Publishing (http://ohnopublishing.net/)
 

	
 
The principal devs are:
 
Ethan Zonca <ethanzonca@protofusion.org>
 
Ethan Zonca <ez@ethanzonca.com>
 
Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 
Matthew Orlando <onlylordofwar@gmail.com>
 
\ No newline at end of file
ChangeLog
Show inline comments
 
2009-01-04  Nathan Phillip Brink  <ohnobinki@gmail.com>
 

	
 
	* Initial construction of an autoconfy filestructure.
 

	
 
2010-05-18  Ethan Zonca <ez@ethanzonca.com>
 

	
 
	* Distrensimpleslave is now functional, uses php to work around the non-working server code
 
\ No newline at end of file
NEWS
Show inline comments
 
Nothing has happened yet. We have not had time to work on this yet, but have merely developed the concepts
 
\ No newline at end of file
 
2010-05-18  Ethan Zonca <ez@ethanzonca.com>
 

	
 
	* Basic rendering is now possible using http://dev.distren.org/ (see DistRenWeb repo) and distrensimpleslave,
 
		which uses a PHP interface to work around the nonfunctional server codebase.
 
\ No newline at end of file
README
Show inline comments
 
Welcome to the amazing DistRen C-based system. Completely nonfunctional and without a single line of 
 
code.
 
Welcome to the amazing DistRen C-based system. Think it's completely nonfunctional and without a single line of 
 
code? No longer.
 

	
 
Basic documentation resides on http://protofusion.org/wiki/DistRen_Manual, and relevant sections will be transferred to this file in the near future.
 
\ No newline at end of file
TODO
Show inline comments
 
Key:
 
*-An important Item that needs to be finished
 
B-Initial of person who needs to fix this (Binki)
 
M-LordofWar needs to fix this
 
E-normaldotcom needs to fix this
 
x-finished task
 
=-Long-term goal
 
?-needs reconsideration/explanation/rewording
 

	
 
Notes:
 
  Initial release will no longer feature SSH auth, distrend will handle auth telnet-style. User registration will be done via PHP.
 
  Simpleslave uses a PHP API to communicate with the mysql-backed server, allowing debugging while server software is nonfunctional.
 

	
 
Build
 

	
 
General
 
=-documenation: manpages
 
=-runtime support: should we eventually just go with APR, glib, maybe something from suckless people? Is libdaemon (or whatever's out there) useful?
 
=-XML (XML-RPC): useful as a communication protocol? as RPC protocol? see atheme; useful as job description format possibly.
 
*-remoteio: figure out how to handle communications; async + callbacks seems the best method to me atm
 

	
 
Master
 
*=Add lockout of slaves below a certain version
 
*-Complete testing with interactive test mode
 
 -update frame assigner to distribute some frames for lower-priority jobs when there's a higher priority job
 
B-Add calls to remotio -> make API for sending messages ~= a function for every type of message defined in protocol.h
 
 -Write a stub for getting info from the tarball/validifying the tarball. Read distren-job.xml, a file in the tarball, to find out 1. which rendering system to use (that system, e.g. blender/povray, can read more specifics, such as name of file to pass to blender and frames. Options common between different systems will be handled in common as best as possible)
 
 -Write a stub for publishing file and constructing job description so that the job can be shared
 
B-XML-RPC interface for obtaining info
 
=-charsets: the program should operate in UTF-8. This is partially required by libxml2's (and XML's) usage of UTF-8. We want the program's internal charset to be UTF-8 and figure out if we need w_char/whatever to fulfill UTF-8. I don't believe we do... mabye we just need a declaration that al data stored must be in UTF-8 format. -> we need to consider how charsets work when and if issues come up
 
M-explain members of struct general_info; e.g., what is timestamp used for, what's the point of the hibernate var, etc.
 
*-resolve conflict between liblist and libmysqlclient
 
*-figure out delete-during-traversal for liblist
 
 
 
Slave
 
 -Fix current bugs
 
*-Add calls to remoteio, once it works or even before it works -> write message API functions and API
 
=-Make code more flexible for different types of jobs and operating systems (such as paths, libs, etc)
 
=-Add code to allow pausing/resuming of the slave (including a running blender process) -> signal handling (SIGTSTP vs. SIGSTOP), distrenslave_control cmdline interface
 
B-Add tmpdir variable (just like the datadir variable) that is compile-time or whatever -> simple API to allow configuration-file override while taking into account defaults set by ./configure
 
*-Finish stub to delete old job data and output
 
=-Upload finished frames' output files while rendering subsequent frames
 
x-Add simpleslave with code to work around nonexisting server codebase
 

	
 
Options
 
=-Rewrite some stuff, try to make it simpler
 
x-Move server and client confuse code into their individual files, rather than in the common file. -- note: there wasn't any client code in options.c. There was the ``server'' section. That section is passed multiple times and provides information to remoteio on how to connect to servers
 
=-Review all confuse interfacing
 
B-Push patch for relative includes in confuse to the confuse developers -- windows/mingw32 testing required first
 
?-Expand execio() to support stderr
configure.ac
Show inline comments
 
# Copyright 2009 Nathan Phillip Brink, Ethan Zonca
 
# Copyright 2010 Nathan Phillip Brink, Ethan Zonca
 
#
 
# 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/>.
 

	
 
AC_PREREQ(2.61)
 
AC_INIT([distren],[0.0],[http://bugs.ohnopub.net/])
 
AC_CONFIG_SRCDIR([src/server/distrend.c])
 
AC_CONFIG_MACRO_DIR([m4])
 

	
 
AC_PROG_CC
 
AC_PROG_LIBTOOL
 
#AC_PROG_RANLIB #don't add this even if autoscan says to, because AC_PROG_LIBTOOL is enough
 

	
 
AM_INIT_AUTOMAKE([gnu dist-bzip2 subdir-objects -Wall])
 
AM_PROG_CC_C_O
 

	
 
#basic low-level checks (suggested by autoscan)
 
AC_CHECK_FUNCS([dup2])
 
AC_CHECK_FUNCS([memset])
 
AC_CHECK_FUNCS([strdup])
 

	
 
AC_CHECK_HEADERS([fcntl.h])
 
AC_CHECK_HEADERS([malloc.h])
 

	
 
AC_FUNC_FORK
 
AC_FUNC_MALLOC
 

	
 
AC_TYPE_PID_T
 
AC_TYPE_SIZE_T
 

	
 
# selective compilation
 
# For now, this is only left for when the C-based client is
 
# reintroducded.
 
AC_ARG_ENABLE([server],
 
	[AS_HELP_STRING([--disable-server],[Don't build the distren server])],
 
	[enable_server=$enableval],
 
	[enable_server=yes])
 
AM_CONDITIONAL([ENABLE_SERVER],
 
	[test "x$enable_server" = "xyes"])
 

	
 
# to grab GNU-specific function prototypes for the following functions:
 
# getline
 
AC_DEFINE([_GNU_SOURCE], [1])
 

	
 
#package dependencies:
 

	
 
PKG_PROG_PKG_CONFIG(0.17.2)
 

	
 

	
 
PKGCONFIG_OHNOWRAP([DISTLIBS], [libconfuse >= 2.5 libcurl libxml-2.0 liblist >= 2.2.1 libarchive >= 2.8.0 ])
 
AX_LIB_MYSQL
 
AS_IF( [test "x${MYSQL_VERSION}" = "x"],
 
	[ AC_MSG_ERROR([I need mysql]) ] )
 

	
 
PKGCONFIG_OHNOWRAP([CHECK], [check >= 0.9.3])
 

	
 
# define paths for configuration files:
 

	
 
AC_DEFINE_DIR([LOCALSTATEDIR], [localstatedir], [Default directory for storing state information])
 
AC_DEFINE_DIR([RUNSTATEDIR], [localstatedir/run], [Default directory for registering runtime information like pid-files])
 

	
 
AC_CONFIG_FILES([Makefile
 
etc/distrendaemon.conf
 
etc/distrenslave.conf
 
])
 

	
 
AC_OUTPUT
src/client/distren.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 
*/
 

	
 

	
 
/* This code is meant to submit files to the distren server(s). Let's say server for now. And let's state file purpose in each file just so we don't get screwed up! */
 

	
 

	
 
/* Ideas for php-side stuff:
 
 *
 
 * PHP adds the users... has captcha and email confirmation wth a pseudo-random number that
 
 * the user must enter on the site. Apache should be running mod_peruser for safety, and I'm
 
 * thinking zserver2 for web serving for convenience...
 
 */
 

	
 

	
 
#include "distren.h"
 

	
 
#include <stdio.h> /* sprintf, printf */
 
#include <stdlib.h> /* malloc, free */
 
#include <unistd.h> /* getopt */
 
#include <confuse.h>
 
#include <string.h> // for strcat
 

	
 

	
 
int main(int argc, char *argv[])
 
{
 
  int doLogin = 0;
 

	
 
  char *input;
 
  char *output;
 
  char *jobid;
 

	
 
  char *username;
 
  char *password;
 

	
 
  char curopt;
 

	
 
  distren_t distren;
 
  distren_job_t distren_job;
 

	
 
  input = NULL;
 
  output = NULL;
 

	
 
  while(-1 != (curopt = getopt(argc, argv, "i:o:u:p:h")))
 
    {
 
      if(curopt == ':')
 
	{
 
	  fprintf(stderr, "-%c: is missing an argument\n", optopt);
 
	  return 1;
 
	}
 
      else if(curopt == '?')
 
	{
 
	  fprintf(stderr, "-%c: invalid option specified\n", optopt);
 
	  return 1;
 
	}
 
      else if(curopt == 'h')
 
	{
 
	  fprintf(stderr, "Usage: %s -i <inputfile> -o <outputfile> [ -u <username> -p <password> ]\n", argv[0]);
 
	  fprintf(stderr, "\t-i\tSpecifies the input file\n\
 
\t-o\tSpecifies the output file\n\
 
\t-h\tShows this help message\n");
 
	  
 
	  //  don't return here because options_init will have an overall
 
	  //  options help page
 
	  
 
	}
 
      else if(curopt == 'u') {
 
        doLogin = 1;
 
        username = strdup(optarg);
 
      }
 
      else if(curopt == 'p') {
 
        doLogin = 1;
 
        password = strdup(optarg);
 
      }
 
      else if(curopt == 'i')
 
	
 
	 //  TODO: is strdup good or bad? what about
 
	 //  the idea that all libs should allow plugging different
 
	 //  malloc/free implementations in?
 
	 
 
	input = strdup(optarg);
 
      else if(curopt == 'o')
 
	output = strdup(optarg);
 
    }
 

	
 
  
 
     // 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");
 
    return 1;
 
  }
 
  if(doLogin == 1){
 
    fprintf(stderr, "Trying username and password on server...");
 
    return 0;
 
  }
 
  if(!input
 
     || !output)
 
    {
 
      fprintf(stderr, "Input and output files must be specified\n");
 
      return 1;
 
    }
 

	
 
  fprintf(stderr, "reading from %s\nwriting to %s\n", input, output);
 

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

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

	
 
  if(distren_job_getid(distren_job, &jobid))
 
    {
 
      fprintf(stderr, "error retrieving job id\n");
 
      return 1;
 
    }
 
  fprintf(stdout, "jobid: %s\n", jobid);
 

	
 
  if(distren_job_retrieve_file(distren_job, output))
 
    {
 
      fprintf(stderr, "error retrieving output file\n");
 
      return 1;
 
    }
 

	
 
  // if these following lines fail, it'll be reported as a core dump ;-)
 
  distren_job_free(distren_job);
 
  distren_free(distren);
 

	
 

	
 

	
 
 return 0;
 
};
 

	
 

	
 

	
 

	
 

	
src/client/distren.h
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 
  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/>.
 
*/
 

	
 
#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.
 
*/
 
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_getid(distren_job_t job, char **jobid);
 

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

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

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

	
 
#endif
src/client/libdistren.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 
  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 "libdistren.h"
 

	
 
#include <malloc.h>
 
#include <stdio.h>
 

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

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

	
 
  (*handle)->malloc = mymalloc;
 
  (*handle)->free = myfree;
 

	
 
  /* 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. 
 
   */
 
  
 
  return 0;
 
}
 

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

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

	
 
/**
 

	
 
 */
 
int distren_free(distren_t handle)
 
{
 
  _free(handle, handle);
 
  return 0;
 
}
src/client/libdistren.h
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 
  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/>.
 
*/
 

	
 
#ifndef LIBDISTREN_H_
 
#define LIBDISTREN_H_ 1
 

	
 
/*
 
  Private definitions for libdistren.
 
 */
 

	
 
#include "distren.h"
 

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

	
 
struct distren_job
 
{
 
  char *jobid;
 
};
 

	
 
/*
 
  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.
 
 */
 
int _distren_getoptions(distren_t handle);
 

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

	
 
#endif
 

	
src/client/libdistren_config.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 
  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/>.
 
*/
 

	
 
/*
 
  Functions and code for retrieving the client's configuration information.
 
 */
 

	
 
#include "client/libdistren.h"
 
#include "common/options.h"
 

	
 
/**
 
@todo Stub
 
 */
 
int _distren_getoptions(distren_t handle)
 
{
 
  cfg_t *cfg;
 

	
 
  cfg_opt_t cfg_opts[] =
 
    {
 
      CFG_STR("server", NULL, 0),
 
      CFG_END()
 
    };
 
  
 
  if(options_init(0, NULL, &cfg, cfg_opts, "client", &handle->options))
 
    {
 
      fprintf(stderr, "error getting configuration\n");
 
      return 1;
 
    }
 
  
 
  handle->server = cfg_getstr(cfg, "server");
 
  fprintf(stderr, "using ``%s'' as server\n", handle->server);
 

	
 
  return 0;
 
}
 

	
 
/**
 
@todo stubish
 
 */
 
int _distren_loseoptions(distren_t handle)
 
{
 
  options_free(handle->options);
 
  
 
  return 0;
 
}
src/client/libdistren_job.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 
  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_job_* functions from distren.h.
 
 */
 

	
 
#include "libdistren.h"
 

	
 
/**
 
   @todo Stub
 
 */
 
int distren_job_getid(distren_job_t job, char **jobid)
 
{
 
  return 1;
 
}
 

	
 
/**
 
   @todo Stub
 
 */
 
int distren_job_retrieve_file(distren_job_t job, const char *outfile)
 
{
 
  return 1;
 
}
 

	
 
/**
 
   @todo Stub
 
 */
 
int distren_job_free(distren_job_t job)
 
{
 
  return 1;
 
}
src/client/libdistren_unbias.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca, Matt Orlando
 
  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 libdistren functions that exist to prevent this library from being biased toward certain methods of reporting errors/debug info or free()ing and malloc()ing
 
 */
 

	
 
#include "libdistren.h"
 

	
 
void *_malloc(distren_t distren, size_t size)
 
{
 
  return (*distren->malloc)(size);
 
}
 

	
 
void _free(distren_t distren, void *tofree)
 
{
 
  (*distren->free)(tofree);
 
}
src/common/execio.h
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca
 

	
 
  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_EXECIO_H
 
#define _DISTREN_EXECIO_H
 

	
 
/*
 
  This file tries to abstract away getting a socket/fd that talks to a spawned program
 
 */
 

	
 
#include <unistd.h>
 

	
 
enum execio_state
 
  {
 
    EXECIO_STATE_ERROR,
 
    EXECIO_STATE_EOF
 
  };
 

	
 

	
 
struct execio
 
{
 
  int pipe_write;
 
  int pipe_read;
 

	
 
  enum execio_state state;
 

	
 
  pid_t child;
 
};
 

	
 
/**
 
  runs progname with the arguments in argv. argv must be null terminated!!!!!!!!!
 

	
 
  returns nonzero return on error
 
*/
 
int execio_open(struct execio **eio, const char *progname, char *const argv[]);
 

	
 
/**
 
   doesn't block,
 
   returns 0 on success, 1 on failure
 
*/
 
int execio_read(struct execio *eio, void *buf, size_t len, size_t *bytesread);
 
int execio_write(struct execio *eio, void *buf, size_t len, size_t *byteswritten);
 

	
 
/**
 
  use this function to determine if the using program should keep trying to read/write
 

	
 
  @todo is this function good enough/necessary?
 
 */
 
enum execio_state execio_state(struct execio *eio);
 

	
 
/**
 
   Closes an execio session.
 
   @return nonzero on error 
 
*/
 
int execio_close(struct execio *eio);
 

	
 
#endif
 

	
src/common/libremoteio.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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_LIBREMOTEIO_H
 
#define _DISTREN_LIBREMOTEIO_H
 

	
 
#include "remoteio.h"
 
#include <confuse.h>
 

	
 
/**
 
  private declarations for remoteio, to be included by options.c and remoteio.c
 
 */
 

	
 
enum remoteio_method
 
  {
 
    REMOTEIO_METHOD_SSH = 0,
 
#ifndef WINDOWS
 
    REMOTEIO_METHOD_UNIX = 1,
 
#endif
 
    REMOTEIO_METHOD_TCP = 2,
 
    /*    REMOETIO_METHOD_XMLRPC */ /*< maybe someday */
 
    REMOTEIO_METHOD_MAX = 3 /*< This is a number used to check the consitency of remoteio_server structs */
 
  };
 

	
 
struct remoteio_server
 
{
 
  struct remoteio_server *next;
 
  char *name; /*< The friendly named passed to remoteio_open() */
 
  char *hostname;
 
  char *username;
 
  enum remoteio_method method;
 
  unsigned int types; /*< See ``Server types'' in protocol.h */
 
};
 

	
 
struct remoteio_opts
 
{
 
  char *ssh_command;
 
  struct remoteio_server *servers;
 
};
 

	
 
struct remoteio {
 
  enum remoteio_method method;
 
  struct remoteio_opts *opts;
 
  struct execio *execio;
 
#ifndef WINDOWS
 
  int sock;
 
#endif
 
};
 

	
 

	
 
/* lookup table */
 
typedef int remoteio_open_func_t(struct remoteio *rem, struct remoteio_server *server);
 
typedef int remoteio_read_func_t(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
typedef int remoteio_write_func_t(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
typedef int remoteio_close_func_t(struct remoteio *rem);
 

	
 
struct remoteio_method_funcmap
 
{
 
  enum remoteio_method method;
 

	
 
  remoteio_open_func_t *open_func;
 
  remoteio_read_func_t *read_func;
 
  remoteio_write_func_t *write_func;
 
  remoteio_close_func_t *close_func;
 

	
 
  char *name; /*< used for error messages */
 
};
 

	
 
int remoteio_config(cfg_t *cfg, struct remoteio_opts *opts);
 

	
 
#endif
src/common/options.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca
 

	
 
  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 "options.h"
 

	
 
#include "common/asprintf.h"
 
#include "common/misc.h"
 
#include "common/libremoteio.h"
 
#include "common/protocol.h"
 

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

	
 
struct options_common_data
 
{
 
  cfg_t *cfg;
 
};
 

	
 

	
 
/**
 
   Not reentrant because of call to getenv()
 
   @todo replace abort()s with something useful
 
 */
 
int options_init(int argc, char *argv[], cfg_t **mycfg, cfg_opt_t *myopts, char *myname, struct options_common **allopts)
 
{
 
  char *configfileprefix;
 
  char *configfile;
 

	
 
  size_t i;
 

	
 
  char *optstring = "hc:";
 
  char curopt;
 

	
 
  char *workingdir;
 
  char *tmp;
 

	
 
  configfileprefix = NULL;
 
  while((curopt = getopt(argc, argv, optstring)) != (char)-1)
 
    switch(curopt)
 
      {
 
      case 'h':
 
	fprintf(stderr, "libdistren common options\n\
 
\n\
 
\t-h\tShow this help.\n\
 
\t-c <path>\tBasename for configuration files. For instance, if distrencommon.conf is located at /etc/distren/distrencommon.conf, set this option /etc/distren/distren . Default value: %s\n\
 
\n", SYSCONFDIR "/distren");
 
	return 2;
 
	break;
 
      case 'c':
 
	configfileprefix = strdup(optarg);
 
	if(!configfileprefix)
 
	  /* return is unnecessary here */
 
	  fprintf(stderr, "OOM\n");
 
	break;
 
      case ':':
 
	fprintf(stderr, "Option -%c requires an argument\n", optopt);
 
	return 1;
 
      }
 
  /* restore optind for other people who use getopt */
 
  optind = 1;
 
  
 
  if(!configfileprefix
 
     && (configfileprefix = getenv("DISTREN_CONFIG_PREFIX")) )
 
    {
 
      configfileprefix = strdup(configfileprefix);
 
      if(!configfileprefix)
 
	{
 
	  fprintf(stderr, "OOM\n");
 
	  return 1;
 
	}
 
    }
 
  /* For those of you who don't know, the following is an example of concatenation of constant strings by the C compiler. Now, that doesn't mean you can do run-time string concatenation ;-)
 
     strdup is because someday configfile will be customizable via argv[]
 
  */
 
  if(!configfileprefix)
 
      configfileprefix = strdup(SYSCONFDIR);
 
  if(!configfileprefix)
 
    {
 
      fprintf(stderr, "OOM\n");
 
      return 1;
 
    }
 

	
 
  workingdir = distren_getcwd();
 
  if(!workingdir)
 
    fprintf(stderr, "Error finding working directory, I will not be able to return to it after reading the configuration files\n");
 
  if(chdir(configfileprefix))
 
    fprintf(stderr, "Unable to chdir(\"%s\") where I expected to find config files, expect failure\n", configfileprefix);
 

	
 
  free(configfileprefix);
 

	
 
  _distren_asprintf(&configfile, "%s%s.conf", PACKAGE, myname);
 
  if(!configfile)
 
    {
 
      perror("blah");
 
      free(workingdir);
 
      return 1;
 
    }
 

	
 
  tmp = distren_getcwd();
 
  fprintf(stderr, "using configuration file: ``%s'' (CWD=``%s'')\n", configfile, tmp ? tmp : "");
 
  free(tmp);
 

	
 
  /* initialize structs */
 
  *allopts = malloc(sizeof(struct options_common));
 
  if(!*allopts)
 
    {
 
      perror("malloc");
 
      free(workingdir);
 
      free(configfile);
 
      return 1;
 
    }
 
  memset(*allopts, '\0', sizeof(struct options_common));
 

	
 
  (*allopts)->data = malloc(sizeof(struct options_common_data));
 
  if(!(*allopts)->data)
 
    {
 
      perror("malloc");
 
      free(workingdir);
 
      free(configfile);
 
      free(*allopts);
 
      return 1;
 
    }
 
  memset((*allopts)->data, '\0', sizeof(struct options_common_data));
 

	
 
  (*allopts)->remoteio = malloc(sizeof(struct remoteio_opts));
 
  if(!(*allopts)->data)
 
    {
 
      perror("malloc");
 
      free(workingdir);
 
      free(configfile);
 
      free((*allopts)->data);
 
      free(*allopts);
 
      return 1;
 
    }
 
  memset((*allopts)->remoteio, '\0', sizeof(struct remoteio_opts));
 
  (*allopts)->remoteio->ssh_command = strdup("ssh");
 
  /** @TODO: check for NULL return above */
 

	
 

	
 
  cfg_opt_t common_opts[] =
 
    {
 
      CFG_SIMPLE_STR("ssh-command", &(*allopts)->remoteio->ssh_command),
 
      CFG_END()
 
    };
 

	
 
  /**
 
    In these arrays, I should replace NULL with a pointer to a string in the struct which should hold the result of confuse processing an option. This is partially because confuse will not free the values it parses.
 
    the server sections in the distrencommon.conf describe different servers that the client may connect to
 
   */
 
  cfg_opt_t server_opts[] =
 
    {
 
      CFG_STR("username", NULL, CFGF_NONE),
 
      CFG_STR("hostname", NULL, CFGF_NONE),
 
      CFG_STR("method", "ssh", CFGF_NONE),
 
      CFG_STR_LIST("types", NULL, CFGF_NONE),
 
      CFG_END()
 
    };
 

	
 
  cfg_opt_t opts[] =
 
    {
 
      CFG_SEC("common",
 
	      common_opts,
 
	      CFGF_NONE),
 
      CFG_SEC("server",
 
	      server_opts,
 
	      CFGF_MULTI | CFGF_TITLE),
 
      CFG_SEC(myname,
 
	      myopts,
 
	      CFGF_NONE),
 
      CFG_FUNC("include",
 
	       &cfg_include),
 
      CFG_END()
 
    };
 

	
 

	
src/common/options.h
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca
 

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

	
 
/*
 
  The point of this file is to handle options parsing that is common to both the server and client of distren. Options parsing that is specific to either should be managed by the server or the client. This means that the user of this interface will be given a handle to a part of a confuse config tree and have to eat that part of the tree to fulfill its own options.
 
  Unfortunately, this extra layer of abstraction shall possibly require a common_opts struct to be made that must be passed to all functions that use the common config. This would include any interface in /src/common/
 
 */
 

	
 
#ifndef _DISTREN_OPTIONS_H
 
#define _DISTREN_OPTIONS_H
 

	
 
#include <confuse.h>
 

	
 
/**
 
  incomplete:
 
  maybe remoteio.h should define its own struct which is injected into this struct and have its own handlers that parse its section of the confuse config file... (it'd be more modular)?
 
  Maybe we should just stick with compile-time modularity :-D (did I just suggest we make tons of macros?)
 
 */
 
struct options_common
 
{
 
  struct options_common_data *data;
 
  struct remoteio_opts *remoteio;
 
  struct client_opts *client;
 
  struct daemon_opts *daemon;
 
};
 

	
 
/**
 
  This function needs to eat some of your arguments to it, just like gtk+ and other libs like to. It particularly needs to be able to find the location of the config file, which should be taken from arguments if it's there. The argument list will have members that I recognize removed.
 

	
 
  Options should be kept alive during the program's life.
 

	
 
  The environment variable DISTREN_CONFIG_PREFIX, the built-in default config file location, or arguments passed on the commandline are used to determine the prefix of the config file name. Order of precedence: The command line is used first, then the environment variable, and then the default if no others sources specify the prefix.
 

	
 
  A calling function must call options_init() before processing its own arguments so that the libdistrencommon-specific help listing may be shown. The caller must also ignore libdistrencommon specific options. To avoid complication, those arguments are "c:h". Obviously, "h" should be handled sspecially ;-) (i.e., the caller should not ignore the "h" switch... it should output information about arguments it supports). Of course, calling functions could just rely on the 
 

	
 
  \param mycfg will be set to the section of the configuration file specific to the caller (client or server specific section). Who is supposed to free this variable?
 
  \param myopts holds the caller's confuse option declarations
 
  \param myname holds the name of the section of the config file that refers to mycfg and myopts -- currently ``slave'', ``client'', and ``server'' are valid
 

	
 
  \param allopts will be set to a pointer that many functions need for operation
 
  \param argc the argc that was passed to main() -- these will be used to determine the location of the config file
 
  \param argv the argv that was passed to main()
 
 */
 
int options_init(int argc, char *argv[], cfg_t **mycfg, cfg_opt_t *myopts, char *myname, struct options_common **allopts);
 

	
 
/**
 
   Frees the struct options_common. This should be run before the program exits.
 
 */
 
int options_free(struct options_common *allopts);
 
#endif
src/common/protocol.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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 "protocol.h"
 

	
 
#include <malloc.h>
 

	
 
#define DISTREN_REQUEST_MAGIC (0x32423434)
 

	
 
int distren_request_new(struct distren_request **req, uint32_t len, enum distren_request_type type)
 
{
 
  struct distren_request *newreq;
 

	
 
  newreq = malloc(sizeof(struct distren_request));
 
  if(!newreq)
 
    {
 
      (*req) = NULL;
 
      return 1;
 
    }
 

	
 
  newreq->magic = DISTREN_REQUEST_MAGIC;
 
  newreq->len = len;
 
  newreq->enumsize = sizeof(enum distren_request_type);
 
  newreq->type = type;
 

	
 
  (*req) = newreq;
 
  return 0;
 
}
 

	
 
int distren_request_free(struct distren_request *req)
 
{
 
  free(req);
 
  return 0;
 
}
src/common/protocol.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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_PROTOCOL_H
 
#define DISTREN_PROTOCOL_H
 

	
 
#include <stdint.h>
 

	
 
/**
 
   Server types:
 
 */
 
#define DISTREN_SERVERTYPE_SUBMIT (0x1)
 
#define DISTREN_SERVERTYPE_DISTRIBUTE (0x2)
 
#define DISTREN_SERVERTYPE_RENDER (0x4)
 

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

	
 
/**
 
   generic, shared requests
 
 */
 
enum distren_request_type
 
  {
 
    DISTREN_REQUEST_VERSION = 1, /*< identifies the version of software being
 
				   used by the sender and tells if it is a client or server */
 
    DISTREN_REQUEST_PING = 2,
 
    DISTREN_REQUEST_PONG = 3,
 
    DISTREN_REQUEST_DISCONNECT = 4,
 

	
 
    /**
 
       client->server only requests
 
    */
 
    DISTREN_REQUEST_SUBMIT = 5,
 

	
 
    /**
 
       anything->server requests
 
     */
 
    DISTREN_REQUEST_JOBINFO = 6, /*< retrieves information about a job based on its number */
 

	
 
    /**
 
       server->anything
 
     */
 
    DISTREN_REQUEST_JOBINFO_RESPONSE = 7, /*< returns information about a job */
 

	
 
    /**
 
       server->server
 
    */
 
    DISTREN_REQUEST_RENDERFRAME = 8,
 
    DISTREN_REQUEST_DONEFRAME = 9,
 
    DISTREN_REQUEST_PROGRESS = 10, /*< tells another server of the progress of the first server's work at rendering */
 
    DISTREN_REQUEST_GETWORK = 11,
 

	
 
  };
 

	
 
struct distren_request
 
{
 
  uint32_t magic;
 
  uint32_t len;
 
  uint8_t enumsize;
 
  enum distren_request_type type;
 
};
 

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

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

	
 
#endif
src/common/remoteio.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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 "libremoteio.h"
 
#include "execio.h"
 
#include "asprintf.h"
 

	
 
#include <errno.h>
 
#ifndef _WIN32
 
#include <netdb.h>
 
#endif
 
#include <stdlib.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <sys/types.h>
 
#ifdef _WIN32
 
#include <winsock2.h>
 
#include <ws2tcpip.h>
 
#else
 
#include <sys/socket.h>
 
#endif
 
#include <unistd.h>
 

	
 
#ifndef _WIN32
 
#include <sys/un.h>
 
#endif
 

	
 
/* local */
 

	
 
#define REMOTEIO_DEFAULT_PORT "4050"
 

	
 
int _remoteio_ssh_open(struct remoteio *rem, struct remoteio_server *server);
 
int _remoteio_ssh_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
int _remoteio_ssh_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten);
 
int _remoteio_ssh_close(struct remoteio *rem);
 

	
 
#ifndef _WIN32
 
int _remoteio_sock_open(struct remoteio *rem, struct remoteio_server *server);
 
int _remoteio_sock_close(struct remoteio *rem);
 
#endif
 
int _remoteio_sock_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
int _remoteio_sock_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten);
 

	
 
int _remoteio_tcp_open(struct remoteio *rem, struct remoteio_server *server);
 
int _remoteio_tcp_close(struct remoteio *rem);
 

	
 
/**
 
  lookup table for different methods of remoteio:
 
  the enum remoteio_method is the index of the entry to use for that method. 
 
  Regardless, a NULL terminator is required because the configuration function
 
  searches through this table for the method specified in the config file.
 
*/
 
struct remoteio_method_funcmap funcmap[] = 
 
  {
 
    /* [REMOTEIO_METHOD_SSH] */
 
    {REMOTEIO_METHOD_SSH, &_remoteio_ssh_open, &_remoteio_ssh_read, &_remoteio_ssh_write, &_remoteio_ssh_close, "ssh"},
 
#ifndef _WIN32
 
    {REMOTEIO_METHOD_UNIX, &_remoteio_sock_open, &_remoteio_sock_read, &_remoteio_sock_write, &_remoteio_sock_close, "unix"},
 
#endif
 
    {REMOTEIO_METHOD_TCP, &_remoteio_tcp_open, &_remoteio_sock_read, &_remoteio_sock_write, &_remoteio_tcp_close, "tcp"},
 
    {REMOTEIO_METHOD_MAX, NULL, NULL, NULL, NULL, NULL}
 
  };
 

	
 
struct remoteio_server *remoteio_getserver(const struct remoteio_opts *opts, const char *servername);
 

	
 
int remoteio_config(cfg_t *cfg, struct remoteio_opts *opts)
 
{
 
  size_t numservers;
 
  size_t counter;
 
  static int haslisted_methods = 0;
 
  
 
  struct remoteio_server *aserver;
 

	
 
  opts->servers = malloc(sizeof(struct remoteio_server));
 
  if(!opts->servers)
 
    {
 
      fprintf(stderr, "@todo cleanup!\n");
 
      abort();
 
    }
 
  
 
  aserver = opts->servers;
 
  
 
  numservers = cfg_size(cfg, "server"); 
 
  for(counter = 0; counter < numservers; counter ++)
 
    {
 
      cfg_t *cfg_aserver;
 
      char *method;
 
      
 
      cfg_aserver = cfg_getnsec(cfg, "server", counter);
 
      
 
      if(!aserver) /*< if the malloc in the previous loop failed */
 
	abort();
 
      
 
      aserver->name = strdup(cfg_title(cfg_aserver));
 
      aserver->hostname = strdup(cfg_getstr(cfg_aserver, "hostname"));
 
      aserver->username = strdup(cfg_getstr(cfg_aserver, "username"));
 

	
 
      aserver->method = REMOTEIO_METHOD_MAX;
 
      method = cfg_getstr(cfg_aserver, "method");
 
      for(counter = 0; funcmap[counter].name; counter ++)
 
	if(strcmp(method, funcmap[counter].name) == 0)
 
	  aserver->method = REMOTEIO_METHOD_SSH;
 
      if(aserver->method == REMOTEIO_METHOD_MAX)
 
	{
 
	  fprintf(stderr, "No such method as %s\n", method);
 
	  if(!haslisted_methods)
 
	    {
 
	      fprintf(stderr, "Available methods:\n");
 
	      for(counter = 0; funcmap[counter].name; counter ++)
 
		fprintf(stderr, "\t%s\n", funcmap[counter].name);
 
	      
 
	      haslisted_methods ++;
 
	    }
 
	  abort();
 
	}
 
      
 
      if(counter < numservers - 1)
 
	{
 
	  aserver->next = malloc(sizeof(struct remoteio_server));
 
	  aserver = aserver->next;
 
	}
 
    }
 
  aserver->next = NULL;
 
  
 
  return 0;
 
}
 

	
 

	
 

	
 
int remoteio_open(struct remoteio **remoteio, struct remoteio_opts *opts, const char *servername)
 
{
 
  struct remoteio_server *theserver;
 
  struct remoteio *rem;
 

	
 
  int tmp;
 

	
 
  if(!opts)
 
    {
 
      fprintf(stderr, "%s:%d: no null opts!\n\tThis is a bug, please report it (after making sure it isn't already reported)\n", __FILE__, __LINE__);
 
      return 1;
 
    }
 

	
 
  theserver = remoteio_getserver(opts, servername);
 
  if(!theserver)
 
    {
 
      fprintf(stderr, "%s:%d: Could not find server named ``%s''\n", __FILE__, __LINE__, servername);
 
      return 1;
 
    }
 

	
 
  if(theserver->method >= REMOTEIO_METHOD_MAX
 
     || theserver->method < 0)
 
    {
 
      fprintf(stderr, "%s:%d: Unsupported remoteio method %d\n\tThis is a bug, probably indicating memory corruption. This is, of course, probably my fault (not your hardware's) ;-)\n", __FILE__, __LINE__, theserver->method);
 
      return 1;
 
    }
 
  rem = malloc(sizeof(struct remoteio));
 
  if(!rem)
 
    {
 
      fprintf(stderr, "OOM\n");
 
      return 2;
 
    }
 
  *remoteio = rem;
 

	
 
  rem->method = theserver->method;
 
  rem->opts = opts;
 

	
 
  tmp = funcmap[theserver->method].open_func(rem, theserver);
 
  if(tmp)
 
    {
 
      fprintf(stderr, "Error using method %s for server ``%s''", funcmap[theserver->method].name, servername);
 
      free(rem);
 
      *remoteio = NULL;
 
      return tmp;
 
    }
 
  
 
  return 0;
 
}
src/common/remoteio.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca
 

	
 
  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_REMOTEIO_H
 
#define _DISTREN_REMOTEIO_H
 

	
 
#include <stdlib.h>
 

	
 
/*
 
  RemoteIO provides an abstraction to the method of talking to a remote distrend. It is a layer on top of execio that should provide an equivalent interface.
 
 */
 

	
 
struct remoteio_opts;
 
struct remoteio;
 

	
 
/**
 
   Opens connection with remote distrend. Returns 1 on error.
 

	
 
   @todo should this be asynchronous?
 
 */
 
int remoteio_open(struct remoteio **rem, struct remoteio_opts *opts, const char *servername);
 

	
 
/**
 
   non-blocking I/O.
 
   @param len must be greater than 0
 

	
 
   @return 0 on success, 1 on failure. 
 
 */
 
int remoteio_read(struct remoteio *rem, void *buf, size_t len, size_t *bytesread);
 
int remoteio_write(struct remoteio *rem, void *buf, size_t len, size_t *byteswritten);
 

	
 
/**
 
   Closes a remoteio session.
 
   @return nonzero on error
 
*/
 
int remoteio_close(struct remoteio *rem);
 

	
 
#endif
src/server/distrend.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 

	
 
*/
 

	
 
/* 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 "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 <confuse.h>
 
#include <malloc.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;
 

	
 
  struct
 
  {
 
    /** general_info.xml */
 
    char *geninfo;
 
    
 
  } files;
 

	
 
  int jobs_in_queue;
 
  unsigned int free_clients;
 
  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();
 
void frame_watchdog(struct distrenjob *distrenjob_head);
 
int distrend_do_config(int argc, char *argv[], struct distrend_config **config);
 
int distrend_config_free(struct distrend_config *config);
 

	
 
/* **************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, struct general_info *general_info);
 

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

	
 
  enum clientstatus
 
  {
 
    CLIENTSTATUS_UNINITIALIZED = 0,
 
    CLIENTSTATUS_BUSY = 1,
 
    CLIENTSTATUS_IDLE = 2
 
  } clientstatus;
 

	
 
  clientstatus = CLIENTSTATUS_UNINITIALIZED;
 
  // xmlinit();
 

	
 
  for(counter = 0; counter < argc; counter ++)
 
    {
 
      if(strcmp(argv[counter], "-h") == 0)
 
      {
 
    	  fprintf(stderr, "Usage: distrend [option] \nStarts the distrend server\n\t-h\tshow this help\n\t-t\tlaunches queue testing interface \n");
 
	  return 2;
 
      }
 

	
 
      else if(strcmp(argv[counter], "-t") == 0)
 
      {
 
    	  fprintf(stderr, "Entering into test mode...\n\n");
 
    	  test = 1;
 
      }
 
    }
 

	
 

	
 
  if(distrend_do_config(argc, argv, &general_info.config))
 
    return 1;
 

	
 
  /** preset paths */
 
  _distren_asprintf(&general_info.files.geninfo, "%s/general_info.xml",
 
		    general_info.config->datadir);
 

	
 
  /** MySQL Connection */
 
  fprintf(stderr,"Connecting to mysql...\n");
 
  if(mysqlConnect(&general_info.conn))
 
    {
 
      fprintf(stderr, "%s:%d: mysqlConnect() failed\n", __FILE__, __LINE__);
 
      fprintf(stderr, "don't test mysql stuff\n");
 
      interactiveTest(test, &general_info);
 
      return 1;
 
    }
 
  fprintf(stderr,"Finished connecting!\n");
 

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

	
 
  distrend_listen(general_info.config, &clients);
 

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

	
 
      distrend_accept(general_info.config, clients);
 

	
 
      /* Make the following code more event-driven */
 
      frame_watchdog(&general_info.head);
 

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

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

	
 
      /* If the client is idle, must be modified for climbing through linked list of clients (client->clientnum) */
 
      if(clientstatus == CLIENTSTATUS_IDLE)
 
	{
 
	  int returnnum = find_jobframe(general_info.conn, slaveKey, &job->jobnum, &frame.num); // Finds a frame to render @FIXME: Slavenum :D
 
	  if(returnnum)
 
	    {
 
	      fprintf(stderr,"No frames are available to render at this time. Idling...\n");
 
	      sleep(10);
 
	    }
 
	  else
 
	    remotio_send_to_client(frame.num, job->jobnum); // Pseudo-sends data to client
 
	}
 
      /* If the client states that they finished the frame */
 
      if(clientsays == 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_unlisten(general_info.config->listens, clients);
 
  distrend_config_free(general_info.config);
 

	
src/server/distrend.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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/>.
 

	
 
*/
 

	
 
struct distrend_config;
 

	
 
#ifndef _DISTREN_DISTREN_H_
 
#define _DISTREN_DISTREN_H_
 

	
 
#include <confuse.h>
 

	
 
#include "listen.h"
 

	
 
struct distrend_config
 
{
 
  cfg_t *mycfg;
 
  struct options_common *options;
 
  struct distrend_listen *listens; /*< Null terminated array of structs */
 
  char *datadir;
 

	
 
  int die;
 
};
 

	
 
#endif
src/server/distrenjob.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 
  Copyright 2010 Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 

	
 
  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 "distrenjob.h"
 
#include "slavefuncs.h"
 

	
 
#include "common/asprintf.h"
 

	
 
#include <libxml/parser.h>
 
#include <libxml/tree.h>
 
#include <libxml/xmlwriter.h>
 

	
 
void distrenjob_free(struct distrenjob **distrenjob)
 
{
 
  struct distrenjob *dj;
 

	
 
  dj = *distrenjob;
 
  xmlFree(dj->name);
 
  xmlFree(dj->submitter);
 

	
 
  free(dj->frameset);
 

	
 
  free(dj);
 
  *distrenjob = NULL;
 
}
 

	
 
int distrenjob_new(struct distrenjob **distrenjob)
 
{
 
  struct distrenjob *dj;
 

	
 
  dj = malloc(sizeof(struct distrenjob));
 
  if(!dj)
 
    {
 
      /* try to catch code that doesn't respect return values
 
       faster: */
 
      *distrenjob = NULL;
 
      return 1;
 
    }
 
  *distrenjob = dj;
 

	
 
  dj->next = NULL;
 
  dj->jobnum = 0; /*< @todo there should be a central jobnum allocator and a way to save the maximum jobnumber allocated */
 
  dj->type = 1;
 
  dj->name = (char *)NULL;
 
  dj->submitter = (char *)NULL;
 

	
 
  dj->output_format = (char *)NULL;
 
  dj->width = 0;
 
  dj->height = 0;
 

	
 
  dj->priority = 0;
 
  dj->completed_frames = 0;
 
  dj->assigned_frames = 0;
 
  dj->total_frames = 0;
 
  dj->prev_frame_index = -1;
 

	
 
  dj->total_render_time = 0;
 
  dj->assigned_render_power = 0;
 
  dj->watchdog_forgiveness = 3600; // initialize watchdog forgiveness at 1 hour
 
  dj->hibernate = 0;
 
  dj->frameset = (struct frameset *)NULL; /*< @todo does frameset need to be initialized here? */
 

	
 
  return 0;
 
}
 

	
 
/**
 
   read an unsigned integer property from an xmlNode
 

	
 
   convenience function for distrenjob_unserialize()
 
   @param xmlnode may be NULL for convenience
 
   @return 0 on success, other on error
 
 */
 
int _distrenjob_xml_readuint(xmlNodePtr xmlnode, xmlChar *propname, unsigned int *num)
 
{
 
  xmlChar *string;
 

	
 
  if(!xmlnode)
 
    return 1;
 

	
 
  string = xmlGetProp(xmlnode, propname);
 
  if(!string)
 
    {
 
      fprintf(stderr, "_distrenjob_xml_readuint(): warning: unable to get property ``%s''\n",
 
	      propname);
 
      return 1;
 
    }
 
  
 
  *num = (unsigned int)strtoul((char *)string, (char **)NULL, 10);
 

	
 
  xmlFree(string);
 
  return 0;
 
}
 

	
 
/**
 
   Loads a distrenjob that was serialized with distrenjob_serialize()
 

	
 
   @see distrenjob_serialize()
 
   @param pathtoxml path to XML file
 
   @param distrenjob will be set to a pointer
 
*/
 
int distrenjob_unserialize(struct distrenjob **distrenjob, char *pathtoxml)
 
{
 
  struct distrenjob *dj;
 
  struct frameset *fs;
 
  unsigned int start_frame;
 
  unsigned int end_frame;
 
  unsigned int counter;
 

	
 
  struct tm tm;
 

	
 
  xmlDocPtr xmldoc;
 
  xmlNodePtr xmlnode;
 
  xmlChar *xmlchar;
 

	
 
  xmlXPathContextPtr xmlxpathcontext;
 

	
 
  int tmp;
 

	
 
  if(distrenjob_new(distrenjob))
 
    return 1;
 
  dj = *distrenjob;
 

	
 
  xmldoc = xmlReadFile(pathtoxml, NULL, XML_PARSE_PEDANTIC);
 
  if(!xmldoc)
 
    {
 
      /**
 
	 @todo are we able to depend on libxml2's printed errors or
 
	 channel them into syslog output (eventually)? Currently,
 
	 this error is repetitious of a libxml2 error printed on stderr
 
	 for us.
 
       */
 
      fprintf(stderr, "error reading XML file ``%s''\n", pathtoxml);
 

	
 
      distrenjob_free(distrenjob);
 
      return 2;
 
    }
 

	
 
  xmlxpathcontext = xmlXPathNewContext(xmldoc);
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job");
 
  if(!xmlnode)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 3;
 
    }
 

	
 
  /*< @todo should we use xmlChar everywhere too? */
 
  dj->name = (char *)xmlGetProp(xmlnode, (xmlChar *)"name");
 
  if(!dj->name)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 4;
 
    }
 

	
 
  /*< @todo validation needs to be done on usernames. e.g., currently, they shouldn't contain the '"' char  */
 
  dj->submitter = (char *)xmlGetProp(xmlnode, (xmlChar *)"submitter");
 
  if(!dj->submitter)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 5;
 
    }
 
  tmp = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"priority", &dj->priority);
 
  if(tmp)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 6;
 
    }
 
  
 
  dj->output_format = (char *)xmlGetProp(xmlnode, (xmlChar *)"output_format");
 
  if(!dj->output_format)
 
    {
 
      distrenjob_free(distrenjob);
 

	
 
      return 6;
 
    }
 

	
 
  tmp = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"jobnum", &dj->jobnum);
 
  if(tmp)
 
    {
src/server/distrenjob.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 

	
 
*/
 

	
 
#ifndef _DISTREN_DISTRENJOB_H
 
#define _DISTREN_DISTRENJOB_H
 

	
 
/**
 
   This file stores the distrenjob and frameset structs and prototypes for some functions to manipulate/use these.
 
 */
 

	
 
#include <time.h> /*< clock_t, time_t */
 

	
 
typedef unsigned int jobnum_t;
 

	
 
/**
 
   Stores Blender Job Info
 
*/
 
struct distrenjob
 
{
 
  struct distrenjob *next; /*< next will be NULL unless if there is another distrenjob */
 
  jobnum_t jobnum;
 
  short int type; /*< 1:Blender, 2:something else */
 
  char *name;
 
  char *submitter;
 

	
 
  char *output_format; /*< currently is the file extension of the request output format. @todo make this mime-type based/not a string */
 
  unsigned int width; /*< width in pixels of the frames to be rendered */
 
  unsigned int height; /*< height in pixels of the frames to be rendered */
 

	
 
  unsigned int priority;  /*< 1 is lowest, 10 is highest, 0 means the job is done */
 
  unsigned int completed_frames; /*< number of completed frames for stats/etc */
 
  unsigned int assigned_frames; /*< number of assigned frames (that are not yet completed) for stats/etc */
 
  unsigned int total_frames; /*< how many frames are in the animation for stats/etc (unassigned frames) */
 
  int prev_frame_index; /*< the position in the array of the last frame that was assigned */
 

	
 
  time_t total_render_time; /*< total seconds of time spent on all the completed frames */
 
  unsigned long int assigned_render_power;
 
  unsigned int watchdog_forgiveness; /*< how many seconds 'til the frame is re-assigned (if client computer crashes etc); */
 
  short int hibernate; /*< @todo DOCUMENT THIS */
 
  struct frameset *frameset;
 
};
 

	
 

	
 

	
 
/**
 
   Frameset Structure
 
*/
 
enum framesetstatus
 
  {
 
    FRAMESETSTATUS_CANCELED, /*< The use has canceled this frame */
 
    FRAMESETSTATUS_UNASSIGNED, /*< The frame has not been assigned */
 
    FRAMESETSTATUS_ASSIGNED, /*< The frame has been assigned */
 
    FRAMESETSTATUS_DONE /*< The frame has completed rendering and the slave has returned the product to me */
 
  };
 

	
 
struct frameset {
 
  int num; /*< frame number to render */
 
  char slave_name; /*< user that frame is assigned to */
 
  enum framesetstatus status; /*< status of frame, 0= unassigned, 1= taken, 2= done */
 
  clock_t start_time; /*< time the frame was started */
 
};
 

	
 
/*
 
  related functions
 
*/
 

	
 
/**
 

	
 
   @param distrenjob the address where we will store the pointer of a malloc()ed
 
   distrenjob struct.
 
   @param pathtoxml filename/pathname of the xml file to be read into a distrenjob struct
 
 */
 
int distrenjob_unserialize(struct distrenjob **distrenjob, char *pathtoxml);
 

	
 
/**
 
   serialize a distrenjob into XML
 
   @param distrenjob the address where we will store the pointer of a malloc()ed
 
   distrenjob struct.
 
   @param xmloutput filename/pathname of the xml file to be written
 
 */
 
int distrenjob_serialize(struct distrenjob *distrenjob, char *xmloutputpath);
 

	
 

	
 
/**
 
   support function for distrenjob_unserialize() to help cleaning up a
 
   struct distrenjob when it is incompletely initialized.
 
   Also acts as a general-purpose struct distrenjob free()er ;-)
 
 */
 
void distrenjob_free(struct distrenjob **distrenjob);
 

	
 
/**
 
   initializes an empty, pointless struct distrenjob. This
 
   DOES run malloc() for you. It could return nonzero on error,
 
   but there are no errors to have yet (except for nomem). This
 
   sets all char* to NULL.
 

	
 
   You have to initialize your own frameset.
 
 */
 
int distrenjob_new(struct distrenjob **distrenjob);
 

	
 
#endif
src/server/listen.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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 "listen.h"
 

	
 
#include <errno.h>
 
#include <fcntl.h>
 
#include <list.h>
 
#include <malloc.h>
 
#include <netinet/in.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <sys/types.h>
 
#include <sys/select.h>
 
#include <sys/socket.h>
 
#include <unistd.h>
 

	
 
/* local */
 

	
 
struct distrend_clientset
 
{
 
  LIST *clients;
 

	
 
  int nfds;
 
};
 

	
 
struct distrend_packet
 
{
 
  size_t len;
 
  char *data;
 
};
 

	
 
int distrend_client_new(struct distrend_client **client, int sock, enum distrend_client_state state);
 
int distrend_client_free(struct distrend_client *client);
 
void distrend_packet_free(struct distrend_packet *packet);
 
int distrend_makesocknonblock(int sock);
 

	
 
int distrend_listen(struct distrend_config *config, struct distrend_clientset **clients)
 
{
 
  int tmp;
 

	
 
  struct sockaddr_in6 sockaddr =
 
    {
 
      .sin6_family = AF_INET6,
 
      .sin6_port = 0,
 
      .sin6_flowinfo = 0,
 
      .sin6_addr = IN6ADDR_ANY_INIT,
 
      .sin6_scope_id = 0
 
    };
 

	
 
  *clients = malloc(sizeof(struct distrend_clientset));
 

	
 
  (*clients)->clients = list_init();
 
  (*clients)->nfds = 1;
 

	
 
  sockaddr.sin6_port = htons(4050);
 

	
 
  config->listens->sock = socket(AF_INET6, SOCK_STREAM, 0);
 
  tmp = bind(config->listens->sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
 
  if(tmp == -1)
 
    {
 
      perror("bind");
 
      free(*clients);
 

	
 
      return 1;
 
    }
 

	
 
  tmp = listen(config->listens->sock, 1);
 
  if(tmp == -1)
 
    {
 
      perror("listen");
 
      free(*clients);
 
      
 
      return 1;
 
    }
 

	
 
  tmp = distrend_makesocknonblock(config->listens->sock);
 
  if(tmp)
 
    {
 
      free(*clients);
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
int distrend_handleread(struct distrend_config *config,
 
		    struct distrend_client *client)
 
{
 
  struct distrend_packet *packet;
 
  ssize_t readlen;
 
  char buf[8192];
 

	
 
  packet = malloc(sizeof(struct distrend_packet));
 
  if(!packet)
 
    {
 
      fprintf(stderr, "OOM\n");
 
      return 1;
 
    }
 
  packet->len = 0;
 
  packet->data = NULL;
 

	
 
  readlen = read(client->sock, buf, sizeof(buf));
 
  if(readlen == -1)
 
    {
 
      perror("read");
 
      switch(errno)
 
	{
 
	case EINTR:
 
	case EAGAIN:
 
	  break;
 

	
 
	default:
 
	  client->state = DISTREND_CLIENT_DEAD;
 

	
 
	  free(packet);
 
	  return 1;
 
	}
 
    }
 
  if(readlen == 0)
 
    /* handle EOF */
 
    {
 
      client->state = DISTREND_CLIENT_DEAD;
 

	
 
      free(packet);
 
      return 1;
 
    }
 

	
 
  packet->len = readlen;
 
  packet->data = malloc(readlen);
 
  if(!packet->data)
 
    {
 
      fprintf(stderr, "OOM!\n");
 

	
 
      free(packet);
 
      return 1;
 
    }
 
  memcpy(packet->data, buf, readlen);
 

	
 
  return 0;
 
}
 

	
 
struct distrend_accept_fdset_prepare_data
 
{
 
  fd_set readfds;
 
  fd_set writefds;
 
  /**
 
     stores the highest FD number which is one less than the first
 
   arfgument to select(). So do select(maxfd + 1, ...)
 
  */
 
  int maxfd;
 
};
 
int distrend_accept_fdset_prepare(struct distrend_accept_fdset_prepare_data *data,
 
				  struct distrend_client *client)
 
{
 
  if(client->state == DISTREND_CLIENT_DEAD)
 
    return TRUE;
 

	
 
  if(client->sock > data->maxfd)
 
    data->maxfd = client->sock;
 
  FD_SET(client->sock, &data->readfds);
 
  /**
 
     Only select on an outgoing socket if we have something to
 
     say.
 
   */
 
  if(!q_empty(client->outmsgs))
 
    FD_SET(client->sock, &data->writefds);
 
  
 
  return TRUE;
 
}
 

	
 
struct distrend_accept_client_proc_data
 
{
 
  fd_set *fdset;
 
  struct distrend_config *config;
 
  enum {DISTREND_ACCEPT_CLIENT_READ, DISTREND_ACCEPT_CLIENT_WRITE} mode;
 
};
 
int distrend_accept_client_proc(struct distrend_accept_client_proc_data *data,
src/server/listen.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink
 
  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/>.
 
*/
 

	
 
struct distrend_clientset;
 
struct distrend_listen;
 
struct distrend_client;
 

	
 
#ifndef _DISTREN_LISTEN_H
 
#define _DISTREN_LISTEN_H
 

	
 
#include "distrend.h"
 

	
 
#include <queue.h>
 

	
 
enum distrend_client_state
 
  {
 
    DISTREND_CLIENT_PREAUTH,
 
    DISTREND_CLIENT_GOODDOGGY,
 
    DISTREND_CLIENT_BADBOY,
 
    DISTREND_CLIENT_DEAD
 
  };
 

	
 
struct distrend_listen
 
{
 
  int port;
 
  int sock;
 
};
 

	
 
struct distrend_client
 
{
 
  int sock;
 
  enum distrend_client_state state;
 
  QUEUE *inmsgs;
 
  QUEUE *outmsgs;
 
};
 

	
 

	
 

	
 
/**
 
   initializes the listens and clientset
 
   @param config the configuration from distrend
 
   @param clients a pointer to a struct distrend_clientset pointer which will be set to memory allocated for the clientset
 
 */
 
int distrend_listen(struct distrend_config *config, struct distrend_clientset **clients);
 

	
 
/**
 
   checks states of the sockets I'm managing. If there are any new connections,
 
   or activity on any sockets, I'll call the appropriate function.
 
   I will block until there is some sort of activity, including
 
   signals. If you want to cleanly shut down, it's best to register
 
   signal handlers somewhere
 
 */
 
int distrend_accept(struct distrend_config *config, struct distrend_clientset *clients);
 

	
 
/**
 
   cleans listening socket. Unnecessary for a working server, currently a stub.
 
 */
 
int distrend_unlisten(struct distrend_listen *listens, struct distrend_clientset *clients);
 

	
 
/**
 
   writes message to client.
 
   @param towrite the caller is expected to free this string. This function will
 
   strdup() it, in essence.
 
 */
 
int distrend_client_write(struct distrend_client *client, char *towrite, size_t msglen);
 

	
 
/**
 
   This is probably just NOT a placeholder for remotio
 
*/
 
void remotio_send_to_client();
 

	
 
#endif
src/server/mysql.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 

	
 
*/
 

	
 
#include "mysql.h"
 
#include <mysql/mysql.h>
 

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

	
 
#include <stdio.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <stdlib.h>
 
#include <sys/stat.h>
 
#include <fcntl.h>
 

	
 
/**
 
   local types
 
 */
 

	
 
#define SEVENTY_FIVE 75
 
#define FORTY_TWO 42
 

	
 
/**
 
   performs mysql query.
 
   errors will be logged to the user by this function.
 
   @return pointer to query handle on success, NULL on failure or if expected_columns=0 (no result set expected)
 
 */
 
distrend_mysql_result_t mysqlQuery(distrend_mysql_conn_t conn, char *query, MYSQL_FIELD_OFFSET expected_columns);
 

	
 
/**
 
   frees mysql query result. Accepts a NULL pointer and ignores it to
 
   help deal with one-shot calls to mysqlQuery so that you don't have to
 
   check if it returned NULL or not.
 
   @return 0 on success
 
 */
 
int mysqlResultFree(distrend_mysql_conn_t conn, distrend_mysql_result_t result);
 

	
 
/**
 
   reads an integer mysql field value
 
   @return 0 on success
 
*/
 
int distrend_mysql_getint(MYSQL_ROW row, MYSQL_FIELD_OFFSET column, int32_t *theint)
 
{
 
  if(!row[column])
 
    return 1;
 

	
 
  *theint = atol(row[column]);
 

	
 
  return 0;
 
}
 

	
 

	
 
struct distrend_mysql_conn
 
{
 
  MYSQL *mysqlconn;
 
  short pointlesscheck;
 
};
 

	
 
struct distrend_mysql_result
 
{
 
  MYSQL_RES *mysqlresult;
 
  short pointlesscheck;
 
};
 

	
 
/**
 
    funcs
 
 */
 

	
 
int mysqlConnect(distrend_mysql_conn_t *conn)
 
{
 
  MYSQL *mysqlconn;
 

	
 
  char *server = "zserver1";
 
  char *user = "distren";
 
  char *password = "HwLxuBqTvJ6J7FWj";
 
  char *database = "distren";
 

	
 
  my_bool mybool;
 

	
 
  mysqlconn = mysql_init(NULL);
 

	
 
  if(!mysql_real_connect(mysqlconn, server, user, password, database, 0, NULL, CLIENT_MULTI_STATEMENTS))
 
    {
 
      fprintf(stderr, "%s\n", mysql_error(mysqlconn));
 
      return 1;
 
    }
 

	
 
  /**
 
     Called after mysql_real_connect() due to bug fixed in MySQL 5.1.6 and later
 
  */
 
  mybool = 1;
 
  mysql_options(mysqlconn, MYSQL_OPT_RECONNECT, (char *)&mybool);
 

	
 

	
 
  *conn = malloc(sizeof(struct distrend_mysql_conn));
 
  if(!*conn)
 
    {
 
      mysql_close(mysqlconn);
 
      mysql_server_end();
 
      return 2;
 
    }
 
  (*conn)->mysqlconn = mysqlconn;
 
  (*conn)->pointlesscheck = SEVENTY_FIVE;
 

	
 
  return 0;
 
}
 

	
 
int mysqlDisconnect(distrend_mysql_conn_t conn)
 
{
 
  /**
 
     check if this handle is valid
 
   */
 
  if(conn->pointlesscheck != SEVENTY_FIVE)
 
    fprintf(stderr, "warning, I was passed a bad struct distrend_mysql_conn...\n");
 

	
 
  /**
 
     invalidate handle :-D
 
   */
 
  conn->pointlesscheck ++;
 

	
 
  mysql_close(conn->mysqlconn);
 
  mysql_server_end();
 
  free(conn);
 

	
 
  return 0;
 
}
 

	
 

	
 
distrend_mysql_result_t mysqlQuery(distrend_mysql_conn_t conn, char *query, MYSQL_FIELD_OFFSET expected_columns)
 
{
 
  MYSQL_RES *result;
 
  distrend_mysql_result_t distrenresult;
 
  MYSQL_FIELD_OFFSET num_columns;
 

	
 
  /**
 
     pointless sanity check
 
  */
 
  if(conn->pointlesscheck != SEVENTY_FIVE)
 
    fprintf(stderr, "warning, I was passed a bad struct distrend_mysql_conn...\n");
 

	
 
  /** make sure that connection is still alive
 
   */
 
  
 
  if(mysql_ping(conn->mysqlconn))
 
    {
 
      fprintf(stderr, "mysql_ping() failed: %s\n", mysql_error(conn->mysqlconn));
 
      return NULL;
 
    }
 

	
 
  fprintf(stderr,"Querying... ");
 
  if (mysql_query(conn->mysqlconn, query))
 
    {
 
      fprintf(stderr, "calling mysql_query() resulted in: %s\n", mysql_error(conn->mysqlconn));
 
      return NULL;
 
    }
 
  fprintf(stderr,"Queried!\n");
 

	
 
  fprintf(stderr,"Getting results... ");
 
  result = mysql_use_result(conn->mysqlconn);
 
  
 
  /**
 
     Flush stuff out when an empty set is expected.
 
   */
 
  if(!expected_columns)
 
    {
 
      if(result)
 
	{
 
	  while(mysql_fetch_row(result))
 
	    ;
 
	  mysql_free_result(result);
 
	}
 
      return NULL;
 
    }
 

	
 
  if(!result)
 
    {
src/server/mysql.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 

	
 
*/
 

	
 

	
 
#ifndef MYSQL_H_
 
#define MYSQL_H_
 

	
 
#include "distrenjob.h"
 

	
 
#include <stdint.h>
 

	
 
struct distrend_mysql_conn;
 
struct distrend_mysql_result;
 

	
 
typedef struct distrend_mysql_conn *distrend_mysql_conn_t;
 
typedef struct distrend_mysql_result *distrend_mysql_result_t;
 

	
 
/**
 
   initiates a MySQL connection
 
   @param conn, pointer will be set to the struct
 
   @return 0 on success
 
 */
 
int mysqlConnect(distrend_mysql_conn_t *conn);
 

	
 
/**
 
   cleans and disconnects MySQL connection
 
   @param conn connection to clean
 
   @return 0 on success
 
*/
 
int mysqlDisconnect(distrend_mysql_conn_t conn);
 

	
 
/**
 
   Mark a frame as finished in the database and calculate the seconds spent on that frame.
 
 */
 
void finish_frame(distrend_mysql_conn_t conn, int32_t slavekey, int32_t jobkey, int32_t framenum);
 

	
 
/**
 
   Mark a frame as started in the database and save the time at which it started.
 
 */
 
void start_frame(distrend_mysql_conn_t conn, int32_t slavekey, int32_t jobkey, int32_t framenum);
 

	
 
/**
 
   Mark a frame as started in the database and save the time at which it started.
 
*/
 
void set_renderpower(distrend_mysql_conn_t conn, int32_t slavekey, int32_t renderpower);
 

	
 
/**
 
   Changes the priority of an existing (and maybe running) job. @arg head I may end up changing the head if job == head
 
*/
 
int change_job_priority(distrend_mysql_conn_t conn, int32_t jobkey, int32_t newpriority);
 

	
 
/**
 
  Frame Finder: Finds a frame for a slave to render
 
*/
 
int find_jobframe(distrend_mysql_conn_t conn, int32_t slaveKey, jobnum_t *jobKey, int32_t *frameNum);
 

	
 
/**
 
  Auth Slave: Checks username/password of slave
 
*/
 
int auth_slave(distrend_mysql_conn_t conn, int32_t slavekey, char *slavepass);
 

	
 

	
 

	
 
#endif /* MYSQL_H_ */
src/server/simpleslave.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 

	
 
*/
 

	
 
#include "slavefuncs.h"
 

	
 
#include "common/asprintf.h"
 
#include "common/options.h"
 

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

	
 
#define DEBUG 1
 

	
 
int main(int argc, char *argv[])
 
{
 
  char *datadir;
 
  char *server;
 
  char *username;
 
  char *password;
 
  char *hostname;
 

	
 
  cfg_opt_t myopts[] = {
 
    CFG_SIMPLE_STR("username", &username),
 
    CFG_SIMPLE_STR("password", &password),
 
    CFG_SIMPLE_STR("datadir", &datadir),
 
    CFG_SIMPLE_STR("server", &server),
 
    CFG_SIMPLE_STR("hostname", &hostname),
 
    CFG_END()
 
  };
 
  cfg_t * my_cfg;
 

	
 
  struct options_common *commonopts;
 

	
 
  /**
 
     initializations
 
  */
 
  datadir = NULL;
 
  server = NULL;
 
  username = NULL;
 
  password = NULL;
 
  hostname = NULL;
 

	
 
  char curopt;
 

	
 
  while(((char)-1) != (curopt = getopt(argc, argv, "u:th")))
 
     {
 
       if(curopt == ':')
 
         {
 
           fprintf(stderr, "-%c: is missing an argument\n", optopt);
 
           return 1;
 
         }
 
       else if(curopt == '?')
 
         {
 
           fprintf(stderr, "-%c: invalid option specified\n", optopt);
 
           return 1;
 
         }
 
       else if(curopt == 'h')
 
         {
 
           fprintf(stderr, "Usage: distrenslave [option] \nStarts a distren slave\n\t-u\tset username (run after fresh install)\n\t-t\tEnter test mode\n\t-h\tshow this help\n");
 
           return 2;
 
         }
 
       else if(curopt == 't')
 
         {
 
           slaveTest();
 
           return 0;
 
         }
 
       else if(curopt == 'u')
 
         username = strdup(optarg);
 
         fprintf(stderr, "Putting username \"%s\" in distrenslave.conf\n", username);
 
         conf_replace("distrenslave.conf", "!username", username);
 
         fprintf(stderr, "Please invoke distrenslave with no arguments to run with the username you just set\n");
 
         return 0;
 
     }
 

	
 
  /* Get conf data */
 
  options_init(argc, argv, &my_cfg, myopts, "slave", &commonopts);
 

	
 
  if(!datadir)
 
    {
 
      fprintf(stderr, "datadir not set\n");
 
      return 1;
 
    }
 
  if(!server)
 
    {
 
      fprintf(stderr, "server not set\n");
 
      return 1;
 
    }
 
  if(!username)
 
    {
 
      fprintf(stderr, "username not set\n");
 
      return 1;
 
    }
 
  if(!password)
 
    {
 
      fprintf(stderr, "password not set\n");
 
      return 1;
 
    }
 
  if(!hostname)
 
    {
 
      fprintf(stderr, "hostname not set\n");
 
      return 1;
 
    }
 

	
 
  
 

	
 
  /* Notifies the user if there no username in .conf */
 
  if(checkUsername(username))
 
    return 1;
 
  if(!strncmp(password, "!password",10))
 
    {
 
      fprintf(stderr, "You haven't specified a password. Please edit your distrenslave.conf file appropriately\n");
 
      return 1;
 
    }
 

	
 
  // Variables needed for main loop
 
  int jobnum = 0;
 
  int framenum = 0;
 
  int slavekey = atoi(username); // @TODO: Make this more friendly
 

	
 
  char *urltoTar;      /* Full URL to the server-side location of job#.tgz */
 
  char *pathtoTar;     /* Full path to the location of the job#.tgz */
 
  char *pathtoTardir;
 

	
 
  // Temporary for uncomressed testing
 
  char *urltoJobfile;
 

	
 
  char *urltoOutput;   /* Full URL where output is posted */
 
  char *pathtoOutput;  /* Full path to the output (rendered) file */
 
  char *pathtoOutdir;  /* Full path to output directory */
 
  char *pathtoRenderOutput; /* Contains blender framenum placeholder */
 

	
 
  char *pathtoJob; /* Path to job data folder */
 
  char *pathtoJobfile; /* Full path to the job's main file */
 
  char *outputExt = "jpg";     /* Output Extension (e.g., JPG) */
 

	
 
  int haveWork = 0;
 
  int quit = 0;
 

	
 
  fprintf(stderr,"DistRenSimpleSlave Pre-Alpha\n\t- this version of DistRen is still experimental\n\t  so things might go horribly wrong!\n");
 

	
 
  int benchmarkTime = 0;
 
  int renderPower = 0;
 

	
 
  char option[1] = "";
 
  fprintf(stderr,"Do you want to recalculate render power? (y/n): ");
 
  scanf("%s", option);
 
  if(!strcmp(option, "y"))
 
    {
 
      if(slaveBenchmark(datadir, &benchmarkTime, &renderPower))
 
	{
 
	  fprintf(stderr,"Benchmark failed! Exiting.\n");
 
	  return 1;
 
	}
 
      else
 
	{
 
	  fprintf(stderr,"Benchmark successful, time taken was %d seconds, giving you a render power of %d.\n",
 
		  benchmarkTime, renderPower);
 
	  _web_setrenderpower(slavekey, password, renderPower);
 
	}
 
    }
 
  if(!DEBUG)
 
    fprintf(stderr, "Running..");
 
  // Main loop
 
  while(!quit)
 
    {
 

	
 
    // request work
 
    if(DEBUG)
 
      fprintf(stderr,"Requesting work from %s...\n", hostname);
 
    haveWork = _web_getwork(slavekey, password, &jobnum, &framenum);
 

	
 
    /* If we got a frame */
 
    if(haveWork)
 
      {
src/server/slave.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 

	
 
*/
 

	
 
#include "slavefuncs.h"
 

	
 
#include "common/asprintf.h"
 
#include "common/options.h"
 
#include "common/protocol.h"
 
#include "common/remoteio.h"
 

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

	
 

	
 
int main(int argc, char *argv[])
 
{
 

	
 
  char *datadir;
 
  char *server;
 
  char *username;
 
  char *hostname;
 
  cfg_opt_t myopts[] = {
 
    CFG_SIMPLE_STR("username", &username),
 
    CFG_SIMPLE_STR("datadir", &datadir),
 
    CFG_SIMPLE_STR("server", &server),
 
    CFG_SIMPLE_STR("hostname", &hostname),
 
    CFG_END()
 
  };
 
  cfg_t * my_cfg;
 

	
 
  struct options_common *commonopts;
 

	
 
  struct distrenjob *myjob; /* Structure to hold data gathered from the XML file */
 

	
 
  struct remoteio *comm_slave;
 

	
 
  /**
 
     initializations
 
  */
 
  datadir = NULL;
 
  server = NULL;
 
  username = NULL;
 

	
 
  char curopt;
 

	
 
  while(((char)-1) != (curopt = getopt(argc, argv, "u:th")))
 
     {
 
       if(curopt == ':')
 
         {
 
           fprintf(stderr, "-%c: is missing an argument\n", optopt);
 
           return 1;
 
         }
 
       else if(curopt == '?')
 
         {
 
           fprintf(stderr, "-%c: invalid option specified\n", optopt);
 
           return 1;
 
         }
 
       else if(curopt == 'h')
 
         {
 
           fprintf(stderr, "Usage: distrenslave [option] \nStarts a distren slave\n\t-u\tset username (run after fresh install)\n\t-t\tEnter test mode\n\t-h\tshow this help\n");
 
           return 2;
 
         }
 
       else if(curopt == 't')
 
         {
 
           slaveTest();
 
           return 0;
 
         }
 
       else if(curopt == 'u')
 
         username = strdup(optarg);
 
         fprintf(stderr, "Putting username \"%s\" in distrenslave.conf\n", username);
 
         conf_replace("distrenslave.conf", "!username", username);
 
         fprintf(stderr, "Please invoke distrenslave with no arguments to run with the username you just set\n");
 
         return 0;
 
     }
 

	
 
  /* Get conf data */
 
  options_init(argc, argv, &my_cfg, myopts, "slave", &commonopts);
 

	
 

	
 
  /* Notifies the user if there no username in .conf */
 
  if(checkUsername(username))
 
    return 1;
 

	
 
  fprintf(stderr, "Connecting to server...\n");
 
  if(remoteio_open(&comm_slave, commonopts->remoteio, server))
 
    {
 
      fprintf(stderr, "Error connecting to server; exiting\n");
 
      return 1;
 
    }
 

	
 

	
 
  // Variables needed for main loop
 
  int jobnum = 0;
 
  int framenum = 0;
 
  int slavekey = atoi(username); // @TODO: Make this more friendly
 
  char *urltoTar;      /* Full URL to the server-side location of job#.tgz */
 
  char *pathtoTar;     /* Full path to the location of the job#.tgz */
 
  char *pathtoTardir;
 
  char *pathtoRenderOutput;
 

	
 
  char *urltoOutput;   /* Full URL where output is posted */
 
  char *pathtoOutput;  /* Full path to the output (rendered) file */
 
  char *pathtoOutdir;  /* Full path to output directory */
 

	
 
  // Temporary for uncomressed testing
 
  char *urltoJobfile;
 

	
 
  char *pathtoJob;     /* Full path to job data folder */
 
  char *pathtoJobfile; /* Full path to the job's main file */
 
  char *outputExt;     /* Output Extension (e.g., JPG) */
 

	
 
  int haveWork = 0;
 
  int quit = 0;
 

	
 
  // Main loop
 
  while(!quit)
 
    {
 

	
 
    // request work
 
    fprintf(stderr,"Requesting work...\n");
 
    sendSignal(comm_slave, DISTREN_REQUEST_GETWORK);
 

	
 
    /* If we got a frame */
 
    if(haveWork)
 
      {
 
        fprintf(stderr,"Got work from server...\n");
 
        /* @TODO: Add remotio hooks */
 
        // jobnum = remoteio_read(jobnum); /* Set jobnum from remoteio (we could use info from struct, but we need this info to download the xmlfile */
 
        // framenum = remoteio_read(jobnum); /* Set framenum from remoteio */
 
        // outputExt = remotio)read(outputExt); /* Set output extension from remotio */
 

	
 
        fprintf(stderr, "Preparing to render frame %d in job %d\n", framenum, jobnum);
 

	
 
        prepareJobPaths(jobnum, framenum, outputExt, datadir, &urltoTar, &pathtoTar,&pathtoTardir,&pathtoJob, &pathtoJobfile, &urltoJobfile, &urltoOutput, &pathtoOutput, &pathtoRenderOutput, &pathtoOutdir);
 
        free(outputExt);
 

	
 
        if(downloadTar(urltoTar, pathtoTar))
 
          return 1;
 

	
 
        unpackJob(datadir, pathtoTar);
 

	
 
        /* Execute blender */
 
        if(exec_blender(pathtoJobfile, pathtoOutput, framenum))
 
          {
 
            fprintf(stderr,"Error running Blender. Check your installation and/or your PATH.\n");
 
            return 1;
 
          }
 
        free(pathtoJobfile);
 

	
 
        /* Post-execution */
 
        fprintf(stderr, "Finished frame %d in job %d, uploading...\n", framenum, jobnum);
 
        uploadOutput(pathtoOutput, urltoOutput, jobnum, framenum, slavekey); // @TODO: Handle return value
 

	
 
        free(urltoOutput);
 
        free(pathtoOutput);
 

	
 
        // Tell the server that rendering and upload are complete of "jobjum.framenum"
 
	char *jobFrame;
 
	_distren_asprintf(&jobFrame, "%s.%s", jobnum, framenum);
 
        sendExtSignal(comm_slave, DISTREN_REQUEST_DONEFRAME, jobFrame);
 
	free(jobFrame);
 
      }
 
    else
 
      fprintf(stderr,"Nothing to do. Idling...\n");
 

	
 
    // @TODO: If the server says that every frame for the last jobnum is finished, OR if the data is getting old
 
    if(1 == 0)
 
      {
 
        // Note: individual frames are already deleted after uploading,
 
        // except for ones that couldn't be uploaded
 
        delete_jobdata(jobnum, datadir);
 
      }
 

	
 
    sleep(5); // Poll 5 seconds. @TODO: Remove all polling
src/server/slavefuncs.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 
*/
 

	
 
#include "distrenjob.h"
 
#include "slavefuncs.h"
 

	
 
#include "common/asprintf.h"
 
#include "common/execio.h"
 
#include "common/protocol.h"
 
#include "common/remoteio.h"
 

	
 
#include <curl/curl.h>
 
#include <curl/easy.h>
 
#include <curl/types.h>
 

	
 
#include <archive.h>
 
#include <archive_entry.h>
 

	
 
#include <stdio.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <stdlib.h>
 
#include <sys/stat.h>
 
#include <fcntl.h>
 

	
 
#include <time.h>
 

	
 
/**
 
   Sends the server a single request (see protocol.h)
 
*/
 
int sendSignal(struct remoteio *rem, char signal)
 
{
 
  size_t written;
 
  size_t towrite;
 
  char *ssignal;
 

	
 
  _distren_asprintf(&ssignal, "%c", signal);
 
  towrite = strlen(ssignal);
 
  while( towrite
 
	 && !remoteio_write(rem, ssignal, towrite, &written))
 
    {
 
      fprintf(stderr, "Sending request...\n");
 
      towrite -= written;
 
    }
 
  if(written)
 
    return 0;
 

	
 
  /**
 
     if remoteio_write returned 1, the connection
 
     is probably dead or there was a real error
 
   */
 
  return 1;
 
}
 

	
 
/**
 
   Sends the server an extended signal (request + data)
 
*/
 
int sendExtSignal(struct remoteio *rem, char signal, char *data){
 
  size_t written;
 
  size_t towrite;
 
  char *ssignal;
 
  _distren_asprintf(&ssignal, "%c%s", signal, data); // Just append the data FIXME: We should do this differently
 
  towrite = strlen(ssignal);
 
  while( towrite
 
          && !remoteio_write(rem, ssignal, towrite, &written))
 
     {
 
       fprintf(stderr, "Sending request...\n");
 
       towrite -= written;
 
     }
 
   if(written)
 
     return 0;
 

	
 
   /**
 
      if remoteio_write returned 1, the connection
 
      is probably dead or there was a real error
 
    */
 
   return 1;
 
}
 

	
 

	
 

	
 
/**
 
   Grabs the xml DOM node reached by an XPath.
 

	
 
   @param path an XPath that lead to DOM node
 
   @return the first node associated with the path or NULL if there is no match
 
 */
 
xmlNodePtr xml_quickxpath(xmlXPathContextPtr xpathctxt, xmlChar *path)
 
{
 
  xmlNodePtr toreturn;
 

	
 
  xmlXPathObjectPtr xmlxpathobjptr;
 
  xmlxpathobjptr = xmlXPathEval(path, xpathctxt);
 
  if(!xmlxpathobjptr
 
     || !xmlxpathobjptr->nodesetval->nodeNr)
 
    {
 
      fprintf(stderr, "XPath resolution failed for ``%s'' in ``%s'' (``%s'')\n", path, xpathctxt->doc->name, xpathctxt->doc->URL);
 
      return (xmlNodePtr)NULL;
 
    }
 

	
 
  toreturn = *(xmlxpathobjptr->nodesetval->nodeTab);
 

	
 
  xmlXPathFreeObject(xmlxpathobjptr);
 

	
 
  return toreturn;
 
}
 

	
 

	
 
/** Stub for deleting job data from the disk. @TODO: unstubify me! */
 
int delete_jobdata(int jobnum, char *datadir)
 
{
 
  char *jobpath;
 
  _distren_asprintf(&jobpath, "%s/%d", datadir, jobnum);
 
  // rmdir(jobpath);
 
  fprintf(stderr, "Please manually remove %s. Automatic removal is currently not implemented.\n", jobpath);
 
  return 0;
 
}
 

	
 
/** Function referenced by curlget() to write data to disk. */
 
size_t curl_writetodisk(void *ptr, size_t size, size_t nmemb, FILE *stream)
 
 {
 
    return fwrite(ptr, size, nmemb, stream);
 
  }
 

	
 
/** Helper function for cURL's progress display */
 
int curl_progress(char *Bar, double t, double d, double ultotal, double ulnow)
 
{
 
fprintf(stderr,"Downloading: %f%% complete\r",d/t*100);
 
return 0;
 
}
 

	
 
/** Retrieves a URL with cURL and saves it to disk */
 
CURLcode curlget(char *url, char *out){
 
  fprintf(stderr,"Preparing to download %s\n",url);
 
  double *Bar; // Stores cURL progress display info
 
  CURL *curl;
 
  CURLcode res;
 
  FILE *outfile;
 

	
 
  res = CURLE_FAILED_INIT;
 
  curl = curl_easy_init();
 
  if(curl)
 
    {
 
    outfile = fopen(out, "w"); // Open where we're writing to
 
    if(outfile == NULL)
 
      return 2; // Output dir doesn't exist
 
    curl_easy_setopt(curl, CURLOPT_URL, url);
 
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
 
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writetodisk); // this MUST be set for win32 compat.
 
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
 
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&curl_progress);
 
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &Bar);
 
    res = curl_easy_perform(curl);
 
    curl_easy_cleanup(curl);
 
    fclose(outfile);
 
  }
 
  fprintf(stderr,"\n"); // Clears out he progressbar's carriage return
 
  return res; // 0 is OK, 1 is 404 or other error
 
}
 

	
 
/** Posts a file to a url with cUrl */
 
CURLcode curlpost(char *filename, char *url, int jobnum, int framenum, int slavekey)
 
{
 
  char *targetname = "uploadedfile"; // Name of the target in the php file on the server (Don't change me unless you have different PHP code)
 
  CURL *curl;
 
  CURLcode res;
 
  struct curl_httppost *formpost=NULL;
 
  struct curl_httppost *lastptr=NULL;
 
  struct curl_slist *headerlist=NULL;
 
  static const char buf[] = "Expect:";
 

	
 
  char *sjobnum;
 
  char *sframenum;
 
  char *sslavekey;
 

	
 
  fprintf(stderr,"Uploading to %s\n", url);
 

	
 
  _distren_asprintf(&sjobnum,"%d",jobnum);
src/server/slavefuncs.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 
*/
 

	
 
#ifndef _DISTREN_SLAVEFUNCS_H
 
#define _DISTREN_SLAVEFUNCS_H
 

	
 
#include "distrenjob.h"
 

	
 
#include "common/remoteio.h"
 

	
 
#include <curl/curl.h>
 
#include <libxml/xpath.h>
 
#include <stdio.h>
 

	
 

	
 
struct msg;
 
int sendSignal(struct remoteio *rem, char signal);
 
int sendExtSignal(struct remoteio *rem, char signal, char *data);
 
xmlNodePtr xml_quickxpath(xmlXPathContextPtr xpathctxt, xmlChar *path);
 
int software_updatecheck();
 
int delete_jobdata(int jobnum, char *datadir);
 
size_t curl_writetodisk(void *ptr, size_t size, size_t nmemb, FILE *stream);
 
CURLcode curlget(char *url, char *out);
 
CURLcode curlpost(char *filename, char *url, int jobnum, int framenum, int slavekey);
 
int ssh_keygen();
 
int register_user(char *username, char *email);
 
int login_user(char *username);
 
int conf_replace(char *conffile, char *wordtoreplace, char *replacewith);
 
int exec_blender(char *input, char *output, int frame);
 
void xmlinit();
 
void xmlcleanup();
 
int distren_mkdir_recurse(char *dirname);
 
int job_build_path(char *filename, unsigned int jobnum);
 
int downloadTar(char *url, char *destinationPath);
 
int uploadOutput(char *pathtoOutput, char *urltoOutput, int jobnum, int framenum, int slavekey);
 
int unpackJob(char *outdir, char *pathtoTar);
 
void prepareJobPaths(int jobnum, int framenum, char *outputExt, char *datadir, char **urltoTar,char **pathtoTar,char **pathtoTardir,char **pathtoJob, char **pathtoJobfile,char **urltoJobfile,char **urltoOutput,char **pathtoOutput, char **pathtoRenderOutput, char **pathtoOutdir);
 
int checkUsername(char *username);
 
void slaveTest();
 

	
 
/* Simple slave */
 
struct _web_memorystruct;
 
void *_web_myrealloc(void *ptr, size_t size);
 
size_t _web_writememorycallback(void *ptr, size_t size, size_t nmemb, void *data);
 
struct _web_memorystruct _web_getrequest(char *url);
 
void _web_finishframe(int slavekey, char *slavepass, int jobnum, int framenum);
 
void _web_startframe(int slavekey, char *slavepass, int jobnum, int framenum);
 
void _web_resetframe(int slavekey, char *slavepass, int jobnum, int framenum);
 
int _web_getwork(int slavekey, char *slavepass, int *jobnum, int *framenum);
 
void _web_setrenderpower(int slavekey, char *slavepass, int renderpower);
 
int slaveBenchmark(char *datadir, int *benchmarkTime, int *renderPower);
 

	
 
#endif
src/server/user_mgr.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 
*/
 

	
 
#include "user_mgr.h"
 

	
 
#include "common/asprintf.h"
 

	
 

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

	
 
#include <malloc.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <sys/stat.h>
 

	
 
struct user_mgr_info
 
{
 
	struct user *user_array;
 
	int current_users;
 
	int user_array_size;
 
} user_mgr_info;
 

	
 
int resize_user_array()
 
{
 
	int counter;
 
	int counter2;
 

	
 
	// create array twice the size of the current amount of users
 
	user_mgr_info.user_array_size = user_mgr_info.current_users * 2;
 
	struct user *new_user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size);
 

	
 
	// this copies the original user_array over to the new one
 
	// using two counters allows the array to be resized at any time
 
	// leaving exactly 1 open space between each user when it is done;
 
	counter2 = 0;
 
	for(counter = 0; counter < user_mgr_info.current_users; counter++)
 
	{
 
		if(user_mgr_info.user_array[counter].username != 0)
 
		{
 
			new_user_array[counter2*2] = user_mgr_info.user_array[counter];
 
			counter2++;
 
		}
 
	}
 

	
 
	// cleanup old array
 
	free(user_mgr_info.user_array);
 

	
 
	// change the pointer to point to the new user array
 
	user_mgr_info.user_array = new_user_array;
 

	
 
	return 1;
 
}
 

	
 
struct user *findUser(char *nameOfUser)
 
{
 
	int high;
 
	int low;
 
	int middle;
 
	int result;
 
	high = user_mgr_info.user_array_size - 1;
 
	low = 0;
 

	
 
	for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2)
 
	{
 
		// in case middle lands on a part of the array with no user
 
		while(user_mgr_info.user_array[middle].username == 0)
 
		{
 
			if(result < 0)
 
				middle--;
 
			else
 
				middle++;
 
		}
 

	
 
		// this is where the array is cut in half and the half that the nameOfUser is on is kept
 
		result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username);
 
		if(result == 0)
 
			return &user_mgr_info.user_array[middle];
 
		else if(result < 0)
 
			high = middle;
 
		else
 
			low = middle;
 

	
 
		// in case the user doesn't exist
 
		if(high-low <= 0)
 
			return 0;
 
	}
 
}
 

	
 
int deleteUser(struct user *user_ptr)
 
{
 
	free(user_ptr->username);
 
	memset(user_ptr, '\0', sizeof(struct user));
 

	
 
	user_mgr_info.current_users--;
 

	
 
	return 1;
 

	
 
	backup_list_XML();
 
}
 

	
 
int createUser(struct user *user_ptr, char *nameOfUser)
 
{
 
	// clear old memory
 
	memset(user_ptr, '\0', sizeof(struct user));
 

	
 
	user_ptr->username = nameOfUser;
 
	user_ptr->render_power = 0;
 
	user_ptr->last_job = 0;
 

	
 
	user_mgr_info.current_users++;
 

	
 
	return 1;
 
}
 

	
 
// places the new user at position index in the array, moves other users if it needs to
 
int placeUser(int index, char *nameOfUser)
 
{
 
	int higher;
 
	int lower;
 
	int total_moves;
 

	
 
	// I shift data in the array to create an open the space where the user should be added
 
	// but first I figure out which way is the shortest
 
	if(user_mgr_info.user_array[index].username != 0)
 
	{
 
		higher = index + 1;
 
		while(user_mgr_info.user_array[higher].username != 0)
 
			higher++;
 

	
 
		lower = index - 1;
 
		while(user_mgr_info.user_array[lower].username != 0)
 
			lower--;
 

	
 
		// here the data is shifted to open up a space
 
		if(index - lower < higher - index)
 
		  {
 
		    total_moves = index - lower;
 
		    for(; lower < index; lower++)
 
				memcpy(&user_mgr_info.user_array[lower], &user_mgr_info.user_array[lower + 1], sizeof(struct user));
 
		  }
 
		else
 
		  {
 
		    total_moves = higher - index;
 
		    for(; higher > index; higher--)
 
				memcpy(&user_mgr_info.user_array[higher], &user_mgr_info.user_array[higher - 1], sizeof(struct user));
 
		  }
 
	}
 

	
 
	// add the user to the array
 
	createUser(&user_mgr_info.user_array[index], nameOfUser);
 

	
 
	if(total_moves > 50){
 
	  resize_user_array();
 
	}
 
	return 1;
 
}
 

	
 
int addUser(char *nameOfUser)
 
{
 
	int high;
 
	int low;
 
	int middle;
 
	int result;
 
	high = user_mgr_info.user_array_size - 1;
 
	low = 0;
 

	
 
	for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2)
 
	{
 
		// in case middle lands on a part of the array with no user
 
		while(user_mgr_info.user_array[middle].username == 0)
 
		{
src/server/user_mgr.h
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew 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/>.
 
*/
 

	
 
/*
 
 * Stores, keeps track of, retrieves information concerning,
 
 * and backs up to XML DistRen's userdb system
 
 */
 

	
 
#ifndef _DISTREN_USER_MGR_H
 
#define _DISTREN_USER_MGR_H
 

	
 
struct user
 
{
 
	char *username;
 
	int render_power;
 
	int last_job;
 
};
 

	
 

	
 
int restart_From_XML_backup();
 
int backup_list_XML();
 

	
 
#endif
test/check_asprintf.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink
 
  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/asprintf.h"
 

	
 
#include <check.h>
 
#include <string.h>
 

	
 
START_TEST (check_asprintf)
 
{
 
  /* tere _must_ be a better way to test this... */
 
  char *teststring = "abcdefghijklmnopqrstuvwxyz";
 
  char *result;
 
  
 
  _distren_asprintf(&result, "I am te%sting\n", teststring);
 
  
 
  fail_unless(strcmp(result, "I am teabcdefghijklmnopqrstuvwxyzting\n") == 0,
 
	      "simple asprintf check failed");
 
}
 
END_TEST
 

	
 
int main(int argc, char *argv[])
 
{
 
  return 0;
 
  /* see http://check.sourceforge.net/doc/check.html/check_6.html#SEC6 */
 
}
 

	
test/check_execio.c
Show inline comments
 
/*
 
  Copyright 2008 Nathan Phillip Brink, Ethan Zonca
 
  Copyright 2010 Nathan Phillip Brink, Ethan Zonca
 

	
 
  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/execio.h"
 

	
 
#include <check.h>
 

	
 
START_TEST (check_execio)
 
{
 
  struct execio *eio;
 
  char *echoargv[] = 
 
    {
 
      "echo",
 
      "test"
 
    };
 

	
 
  char inbuf[20];
 
  size_t bytesread;
 
  
 
  fail_unless(execio_open(&eio, echoargv[0], echoargv) == 0,
 
	      "execio_open failed");
 
  
 
  fail_unless(execio_read(eio, inbuf, sizeof(inbuf) - 1, &bytesread) == 0,
 
	      "error using execio_read\n");
 
  
 
  fail_unless(execio_close(eio) == 0,
 
	      "error using execio_close\n");
 
}
 
END_TEST
 

	
 
int main(int argc, char *argv[])
 
{
 
  return 0;
 
  /* see http://check.sourceforge.net/doc/check.html/check_6.html#SEC6 */
 
}
 

	
0 comments (0 inline, 0 general)