Changeset - 7c0e60f07a51
[Not reviewed]
default
0 11 0
Nathan Brink (binki) - 15 years ago 2010-07-25 17:23:16
ohnobinki@ohnopublishing.net
Server and client will connect and send DISTREN_REQUEST_VERSION packets immediately.
11 files changed with 212 insertions and 54 deletions:
0 comments (0 inline, 0 general)
doc/architecture.txt
Show inline comments
 
@@ -48,17 +48,19 @@ Concepts:
 
      be completed prior to the said frame. For a server to complete a frame dependent on other
 
      frames, those other frames must be transfered to the first server and made available.
 
  - packaging: To render a single frame and move it about somewhere is normally trivial. However,
 
      one frame or rendering unit of a given backend may produce multiple files. For this reason
 
      and for further uniformity and simplification, the data files representing one frame shall
 
      be transferred using the tarball format.
 

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

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

	
 
- file: There are different uses of files above and distributed rendering requires file distribution.
 
  - file identification: Every file mentioned above was at least in the context of a job. Thus,
 
      file identification numbers shall be assigned in the context of a job identification number.
 
      They shall, however, be numeric.
 
      distren://<servername>/<jobid>/file/<fileid>
src/client/libdistren.c
Show inline comments
 
@@ -14,75 +14,110 @@
 
  GNU Affero General Public License for more details.
 

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

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

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

	
 
#include "libdistren.h"
 

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

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

	
 
int distren_init(distren_t *handle)
 
{
 
  int tmp;
 

	
 
  struct distren_request *req;
 
  void *data;
 

	
 
  if(!handle)
 
    return 1;
 

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

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

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

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

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

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

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

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

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

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

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

	
 
int distren_free(distren_t handle)
 
{
 
  if(handle->rem)
 
    remoteio_close(handle->rem);
src/client/libdistren.h
Show inline comments
 
@@ -21,39 +21,67 @@
 
#define LIBDISTREN_H_ 1
 

	
 
/*
 
  Private definitions for libdistren.
 
 */
 

	
 
#include "distren.h"
 

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

	
 
#include <stdint.h>
 

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

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

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

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

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

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

	
 
  
 
};
 

	
 
struct distren_job
 
{
 
  char *joburi;
 
};
 

	
 
/*
 
  functions
 
*/
 

	
 
/**
src/client/libdistren_request.c
Show inline comments
 
@@ -17,25 +17,25 @@
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
#include "common/config.h"
 

	
 
#include "libdistren.h"
 

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

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

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

	
 
  struct distren_request *req;
 
  void *req_data;
 

	
 
  to_return = 0;
 
@@ -64,25 +64,25 @@ size_t libdistren_remoteio_read_handle(s
 
	  return to_return;
 
	}
 
      if(!last_len)
 
	return to_return;
 

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

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

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

	
 
	default:
 
	  /*
 
	   * we don't implement everything because we don't need to do
 
	   * so. But, we should complain when we get something we
 
	   * don't recognize because... server protocols change
 
	   * ;-). Oh, and when I'm first writing this, this
 
@@ -109,36 +109,52 @@ void libdistren_remoteio_close_handle(vo
 
/* handlers */
 

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

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

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

	
 
  size_t counter;
 
  struct distren_request_version version;
 
  int tmp;
 

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

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

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

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

	
 
  remoteio_close(distren->rem);
 
}
src/common/protocol.h
Show inline comments
 
@@ -181,31 +181,34 @@ enum distren_request_type
 
    DISTREN_REQUEST_FILE = 13,
 
  };
 

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

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

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

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

	
 
struct remoteio;
 
/**
 
   Takes a struct distren_request and its associated data, allocates
 
   a new block of data to hold the whole packet, and packets the req
 
   header and data together.
src/common/request.c
Show inline comments
 
@@ -21,24 +21,59 @@
 

	
 
#include "common/protocol.h"
 

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

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

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

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

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

	
 
  *data = version;
 

	
 
  return 0;
 
}
 

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

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

	
 
  return 0;
 
}
 

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

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

	
src/common/request.h
Show inline comments
 
@@ -11,35 +11,57 @@
 
 * DistRen is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
#ifndef _DISTREN_REQUEST_H
 
#define _DISTREN_REQUEST_H
 

	
 
#include "common/protocol.h"
 

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

	
 

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

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

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

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

	
 
#endif /* _DISTREN_REQUEST_H */
src/server/distrend.c
Show inline comments
 
@@ -22,24 +22,25 @@
 

	
 
#include "common/config.h"
 

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

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

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

	
 
#include <libxml/encoding.h>
 
#include <libxml/parser.h>
 
@@ -80,25 +81,25 @@ struct general_info
 
   Function Prototypes
 
   ********************************************* */
 

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

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

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

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

	
 
/* **************** Main ********************* */
 
int main(int argc, char *argv[])
 
{
 
@@ -198,64 +199,66 @@ int main(int argc, char *argv[])
 

	
 
  xmlcleanup();
 

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

	
 
  return 0;
 
}
 

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

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

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

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

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

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

	
 
      _distren_asprintf(&tmp_str, "You have tried to connect to a %s server when your client claims to be running %s. Bye ;-)\n", PACKAGE_STRING, fixedbuf);
 
      _distren_asprintf(&tmp_str, "You have tried to connect to a %s server when your client claims to be running %s. Bye ;-)\n", PACKAGE_STRING, version.package_string);
 
      if(tmp_str)
 
	{
 
      distrend_send_disconnect(client, tmp_str);
 
	  free(tmp_str);
 
	}
 
      else
 
	distrend_send_disconnect(client, "Invalid PACKAGE_VERSION :-|.");
 
      return 1;
 
    }
 

	
 
  return 0;
 
}
 

	
 
/**
 
   Performs command stored in a client's request. @TODO: Fill stub
 
*/
 
int distrend_do()
 
{
 
  return 0;
 
}
src/server/listen.c
Show inline comments
 
@@ -14,24 +14,25 @@
 
  GNU Affero General Public License for more details.
 

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

	
 
#include "common/config.h"
 

	
 
#include "listen.h"
 

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

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

	
 
@@ -271,26 +272,30 @@ struct distrend_accept_client_proc_data
 
 * Handle new connections.
 
 */
 
int listen_handle_accept(multiio_context_t multiio,
 
			 int fd,
 
			 short revent,
 
			 struct distrend_listens *listens,
 
			 int *port)
 
   //int distrend_accept(struct distrend_listens *listens)//, struct distrend_clientset *clients, distrend_handle_request_t handlereq, void *handlereqdata)
 
 {
 
   struct distrend_client *newclient;
 

	
 
   int newclientsock;
 

	
 
   struct remoteio *rem;
 

	
 
   struct distren_request *req;
 
   void *data;
 

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

	
 
   newclient = distrend_client_new(listens, DISTREND_CLIENT_PREVERSION, NULL);
 

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

	
 
@@ -300,24 +305,33 @@ int listen_handle_accept(multiio_context
 
   tabletennis_add_client(listens->tabletennis, newclient);
 

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

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

	
 
   /*
 
   list_mvfront(listens->clients);
 
   newclient = list_curr(listens->clients);
 
   while(newclient)
 
     {
 
       if(newclient->state == DISTREND_CLIENT_DEAD)
 
	 {
 
	   distrend_listen_poll_deletefd(listens, &newclient->sock);
 
	   distrend_client_free(newclient);
 
	   list_remove_curr(listens->clients);
 
	   fprintf(stderr, "removed dead connection\n");
 
	 }
 
@@ -556,25 +570,25 @@ struct distrend_dispatch_request_data
 
  struct general_info *geninfo;
 
  struct distrend_client *client;
 
  struct distren_request *req;
 
  void *req_data;
 
};
 

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

	
 
  return TRUE;
 
}
 

	
 
/**
 
   helper for distrend_listen_read_handle() which looks up the correct
 
   request handler and handles handing the the request to the
 
   handler. :-p
 
*/
 
int distrend_dispatch_request(struct distrend_listens *listens, struct remoteio *rem, struct distrend_client *client, struct distren_request *req, void *reqdata)
 
{
 
  struct distrend_dispatch_request_data data;
src/server/listen.h
Show inline comments
 
@@ -131,29 +131,29 @@ struct distrend_client
 
   * struct, we need a reverse pointer for something like
 
   * distrend_client_write() to work.
 
   */
 
  struct remoteio *rem;
 
};
 

	
 

	
 

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

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

	
 
/**
 
   Initializes the listens member of struct distrend_config.
 

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

	
 
/**
 
   Adds a socket and configures it to listen().
src/server/tabletennis.c
Show inline comments
 
@@ -36,26 +36,26 @@ struct tabletennis
 
  unsigned int ping_interval;
 
  unsigned int pong_time;
 

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

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

	
 
  struct timespec time_last_check;
 
};
 

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

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

	
 
  tabletennis = malloc(sizeof(struct tabletennis));
 

	
 
  tabletennis->ping_interval = ping_interval;
 
  tabletennis->pong_time = pong_time;
 
  tabletennis->clients_to_ping = q_init();
 
  tabletennis->clients_need_pong = q_init();
 
  clock_gettime(CLOCK_MONOTONIC, &tabletennis->time_last_check);
 
@@ -184,52 +184,52 @@ void tabletennis_free(tabletennis_t tabl
 
  q_free(tabletennis->clients_need_pong, LIST_NODEALLOC);
 

	
 
  free(tabletennis);
 
}
 

	
 
/* implementations of locals */
 

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

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

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

	
 
  return 0;
 
}
 

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

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

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