Changeset - eb391af42d62
[Not reviewed]
default
0 13 4
Nathan Brink (binki) - 15 years ago 2010-07-21 21:18:20
ohnobinki@ohnopublishing.net
Non-working tabletennis, better poll() resiliency, some fixups to the slave, etc.
17 files changed with 712 insertions and 93 deletions:
0 comments (0 inline, 0 general)
Makefile.am
Show inline comments
 
@@ -23,28 +23,26 @@ libdistrencommon_la_SOURCES = src/common
 
	src/common/options.c src/common/options.h \
 
	src/common/protocol.c src/common/protocol.h \
 
	src/common/remoteio.h \
 
	src/common/remoteio.c src/common/libremoteio.h
 
	src/common/remoteio.c src/common/libremoteio.h \
 
	src/common/request.c src/common/request.h
 
#see http://sources.redhat.com/autobook/autobook/autobook_91.html
 
# either increase the revision number or the interface number each release!
 
libdistrencommon_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0
 

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

	
 
distrend_LDADD = libdistrencommon.la
 
# distrenslave:
 
distrenslave_SOURCES = $(SERVER_SOURCES) \
src/common/libremoteio.h
Show inline comments
 
@@ -90,6 +90,8 @@ struct remoteio
 
  remoteio_read_handle_func_t read_handler;
 
  /* for the read_handler */
 
  void *read_handler_data;
 
  /* so that read_handler_data can be cleaned up */
 
  remoteio_close_handle_func_t close_handler;
 

	
 
  /**
 
   * Store a buffer of data waiting to be processed.
src/common/multiio.c
Show inline comments
 
@@ -179,7 +179,13 @@ int multiio_poll(multiio_context_t conte
 
  size_t counter;
 
  struct multiio_poll_travinfo travinfo;
 

	
 
  poll(context->pollfds, context->nfds, -1);
 
  int ret;
 

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

	
 
  for(counter = 0; counter < context->nfds; counter ++)
 
    if(context->pollfds[counter].revents)
 
@@ -191,6 +197,8 @@ int multiio_poll(multiio_context_t conte
 
		      &travinfo,
 
		      (list_traverse_func_t)&multiio_poll_invoke_handlers,
 
		      LIST_FRNT | LIST_SAVE);
 

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

	
 
  return 0;
 
@@ -293,6 +301,7 @@ int multiio_socket_add(multiio_context_t
 
  pollfds = context->pollfds;
 
  socket_infos = context->socket_infos;
 

	
 
  memset(&pollfds[context->nfds], 0, sizeof(struct pollfd));
 
  pollfds[context->nfds].fd = fd;
 
  pollfds[context->nfds].events = events;
 
  socket_infos[context->nfds].socket_type = socket_type;
src/common/protocol.c
Show inline comments
 
@@ -24,7 +24,7 @@
 
#include <stdio.h>
 
#include <string.h>
 

	
 
#define DISTREN_REQUEST_MAGIC (0x32423434)
 
#define DISTREN_REQUEST_MAGIC ((uint32_t)0x32423434)
 

	
 
int distren_request_new(struct distren_request **req, uint32_t len, enum distren_request_type type)
 
{
src/common/protocol.h
Show inline comments
 
@@ -94,6 +94,7 @@ database */
 
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;
 
@@ -120,6 +121,8 @@ int distren_request_send(struct remoteio
 
/**
 
 * initializes and allocates request based on raw input data
 
 * which includes the headers of the request.
 
 *
 
 * @return 0 on success, 1 on failure
 
 */
 
int distren_request_new_fromdata(struct distren_request **req, void *data, size_t len);
 

	
src/common/remoteio.c
Show inline comments
 
@@ -179,7 +179,8 @@ int remoteio_open_common(struct remoteio
 
			 enum remoteio_method method,
 
			 struct remoteio_opts *opts,
 
			 remoteio_read_handle_func_t read_handler,
 
			 void *read_handler_data)
 
			 void *read_handler_data,
 
			 remoteio_close_handle_func_t close_handler)
 
{
 
  struct remoteio *rem;
 

	
 
@@ -200,6 +201,7 @@ int remoteio_open_common(struct remoteio
 
  rem->outmsgs = q_init();
 
  rem->read_handler = read_handler;
 
  rem->read_handler_data = read_handler_data;
 
  rem->close_handler = close_handler;
 
  /*
 
   * the following initialization is very important... though the
 
   * others are too, I suppose :-p. See remoteio_close()
 
@@ -213,10 +215,11 @@ int remoteio_open_socket(struct remoteio
 
			 struct remoteio_opts *opts,
 
			 remoteio_read_handle_func_t read_handler,
 
			 void *read_handler_data,
 
			 remoteio_close_handle_func_t close_handler,
 
			 int fd)
 
{
 
  struct remoteio *rem;
 
  if(remoteio_open_common(remoteio, REMOTEIO_METHOD_SOCKET, opts, read_handler, read_handler_data))
 
  if(remoteio_open_common(remoteio, REMOTEIO_METHOD_SOCKET, opts, read_handler, read_handler_data, close_handler))
 
    return 1;
 
  rem = *remoteio;
 

	
 
@@ -230,6 +233,7 @@ int remoteio_open_server(struct remoteio
 
			 struct remoteio_opts *opts,
 
			 remoteio_read_handle_func_t read_handler,
 
			 void *read_handler_data,
 
			 remoteio_close_handle_func_t close_handler,
 
			 const char *servername)
 
{
 
  struct remoteio_server *theserver;
 
@@ -257,7 +261,7 @@ int remoteio_open_server(struct remoteio
 
      return 1;
 
    }
 

	
 
  if(remoteio_open_common(remoteio, theserver->method, opts, read_handler, read_handler_data))
 
  if(remoteio_open_common(remoteio, theserver->method, opts, read_handler, read_handler_data, close_handler))
 
    return 1;
 
  rem = *remoteio;
 

	
 
@@ -484,6 +488,10 @@ int remoteio_close(struct remoteio *rem)
 
      return 0;
 
    }
 

	
 
  /* call close handler */
 
  if(rem->close_handler)
 
    (*rem->close_handler)(rem->opts->generic_handler_data, rem->read_handler_data);
 

	
 
  /* cleanup multiiio stuff */
 
  multiio_socket_del(rem->opts->multiio, rem->sock);
 

	
src/common/remoteio.h
Show inline comments
 
@@ -49,12 +49,25 @@ struct remoteio;
 
 * @param generic_data a pointer that is stored in remoteio's struct remoteio_opts which isn't client-specific
 
 * @param buf a pointer to the buffer containing data waiting to be processed
 
 * @param len the size of buf that may be accessed
 
 * @param data the pointer passed to remoteio_open. _NOT_ the data just received on the socket.
 
 * @param data the pointer passed to remoteio_open(). _NOT_ the data just received on the socket.
 
 * @return the number of bytes that the function accepted and thus should be removed from the rem handle.
 
 */
 
typedef size_t(*remoteio_read_handle_func_t)(struct remoteio *rem, void *generic_data, void *buf, size_t len, void *data);
 

	
 
/**
 
 * asynchronous close handler which is called whenever remoteio_close() is called.
 
 *
 
 * As reading is now event-oriented and as libremoteio may itself call
 
 * remoteio_close(), you need a way to be informed that a socket is
 
 * being closed. This is particularly important if you have to clean
 
 * up your read_handler_data.
 
 *
 
 * @param generic_data a pointer set by a call to remoteio_generic_data_set().
 
 * @param data the same pointer passed to remoteio_open().
 
 */
 
typedef void (*remoteio_close_handle_func_t)(void *generic_data, void *data);
 

	
 
/**
 
 * Determines the value of generic_data which is passed to
 
 * remoteio_read_handle_func_t
 
 *
 
@@ -76,6 +89,7 @@ int remoteio_open_server(struct remoteio
 
			 struct remoteio_opts *opts,
 
			 remoteio_read_handle_func_t read_handler,
 
			 void *read_handler_data,
 
			 remoteio_close_handle_func_t close_handler,
 
			 const char *servername);
 

	
 
/**
 
@@ -92,6 +106,7 @@ int remoteio_open_socket(struct remoteio
 
			 struct remoteio_opts *opts,
 
			 remoteio_read_handle_func_t read_handler,
 
			 void *read_handler_data,
 
			 remoteio_close_handle_func_t close_handler,
 
			 int fd);
 

	
 
/**
src/common/request.c
Show inline comments
 
new file 100644
 
/*
 
 * Copyright 2010 Nathan Phillip Brink
 
 *
 
 * This file is a part of DistRen.
 
 *
 
 * DistRen is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * DistRen is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
#include "common/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);
 
}
 

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

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

	
 
  return (uint32_t)poing_data_len;
 
}
src/common/request.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright 2010 Nathan Phillip Brink
 
 *
 
 * This file is a part of DistRen.
 
 *
 
 * DistRen is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * DistRen is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
#ifndef _DISTREN_REQUEST_H
 
#define _DISTREN_REQUEST_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 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
 
@@ -89,7 +89,6 @@ int distrend_handle_request(struct distr
 
   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_ping(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data);
 

	
 
/* **************XML Functions**************** */
 
void update_general_info(struct general_info *geninfo);
 
@@ -180,7 +179,6 @@ int main(int argc, char *argv[])
 
    }
 

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

	
 
  int slaveKey = 0; // Remotio should set me on a per-slave basis
 
  /* Main Loop */
 
@@ -190,7 +188,8 @@ int main(int argc, char *argv[])
 
      int clientrequest = 0; /*< temporary example variable, will be replaced when we can handle messages */
 

	
 
      multiio_poll(multiio);
 
      /*      distrend_accept(general_info.config->listens); */
 

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

	
 
      /* Run the watchdog, @TODO: like every 10 mins or something */
 
      frame_watchdog(general_info.conn);
 
@@ -277,24 +276,6 @@ int distrend_handle_version(struct gener
 
  return 0;
 
}
 

	
 
int distrend_handle_ping(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data)
 
{
 
  struct distren_request *pong_req;
 

	
 
  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);
 
  distrend_client_write_request(client, pong_req, req_data);
 
  distren_request_free(pong_req);
 

	
 
  return 0;
 
}
 

	
 
/**
 
   Performs command stored in a client's request. @TODO: Fill stub
 
*/
 
@@ -599,6 +580,7 @@ int interactiveTest(int test, multiio_co
 
       while(1)
 
	 {
 
	   multiio_poll(multiio);
 
	   tabletennis_serve(geninfo->config->listens->tabletennis);
 
	 }
 
       break;
 
       
src/server/listen.c
Show inline comments
 
@@ -46,7 +46,8 @@ struct distrend_client *distrend_client_
 
int distrend_client_free(struct distrend_client *client);
 
int distrend_dispatch_request(struct distrend_listens *listens, struct remoteio *rem, struct distrend_client *client, struct distren_request *req, void *reqdata);
 
struct distrend_polled_sock *distrend_polled_sock_get_by_offset(struct distrend_listens *listens, size_t pollfds_offset);
 
size_t distrend_listen_read_handle(struct remoteio *rem, struct distrend_listens *listens, void *buf, size_t len, struct distrend_client *client);
 
static size_t distrend_listen_read_handle(struct remoteio *rem, struct distrend_listens *listens, void *buf, size_t len, struct distrend_client *client);
 
static void distrend_listen_remoteio_handle_close(struct distrend_listens *listens, struct distrend_client *client);
 

	
 
int listen_handle_accept(multiio_context_t multiio,
 
			 int fd,
 
@@ -94,6 +95,9 @@ struct distrend_listens *distrend_listen
 
  /* multiio */
 
  listens->multiio = multiio;
 

	
 
  /* tabletennis */
 
  listens->tabletennis = tabletennis_new(listens, 32, 16);
 

	
 
  /* This type is used for accepting connections with accept() */
 
  multiio_socket_type_register(multiio, &listens->socket_type);
 

	
 
@@ -288,16 +292,18 @@ int listen_handle_accept(multiio_context
 

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

	
 
   fprintf(stderr, __FILE__ ":%d: This client SHOULD be registered in the table tennis system here\n", __LINE__);
 
   fprintf(stderr, "accepted new connection; fd=%d\n", newclientsock);
 

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

	
 
   /**
 
    * For those using netcat/telnet to debug their internets.
 
    */
 
@@ -417,8 +423,24 @@ size_t distrend_listen_read_handle(struc
 
  return 0;
 
}
 

	
 
/**
 
 * Handle cleaning up after remoteio_close() has been called. This includes cleaning up the struct distrend_client and stuffs
 
 */
 
void distrend_listen_remoteio_handle_close(struct distrend_listens *listens, struct distrend_client *client)
 
{
 
  /*
 
   * remoteio handles removing itself from multiio for us. We just
 
   * have to clean up tabletennis and the struct itself.
 
   */
 

	
 
  tabletennis_del_client(listens->tabletennis, client);
 

	
 
  free(client);
 
}
 

	
 
int distrend_listen_free(struct distrend_listens *listens)
 
{
 
  tabletennis_free(listens->tabletennis);
 
  fprintf(stderr, "%s:%d: I am a stub that needn't be implemented 'til later\n", __FILE__, __LINE__);
 

	
 
  return 1;
 
@@ -456,21 +478,6 @@ struct distrend_client *distrend_client_
 
  return client;
 
}
 

	
 
/**
 
   This function shall only be called after the appropriate
 
   distrend_listen_poll_deletefd() has been called
 

	
 
   @deprecated blah
 
   @todo kill this func?
 
 */
 
int distrend_client_free(struct distrend_client *client)
 
{
 
  fprintf(stderr, " Kaaaaaaa bOOOOOOOOMNMMMM!\n");
 
  abort();
 
  
 
  return 0;
 
}
 

	
 
int distrend_client_write_request(struct distrend_client *client, const struct distren_request *req, const void *data)
 
{
 
  char *towrite;
src/server/listen.h
Show inline comments
 
@@ -33,6 +33,7 @@ struct distrend_client;
 
#define _DISTREN_LISTEN_H
 

	
 
#include "distrend.h"
 
#include "tabletennis.h"
 

	
 
#include "common/options.h"
 
#include "common/multiio.h"
 
@@ -89,6 +90,8 @@ struct distrend_listens
 
  /* the distrend config */
 
  struct options_common *options;
 

	
 
  tabletennis_t tabletennis;
 

	
 
  /* of type (struct distrend_client)  (multiio stores a pointer per socket, we'll store each strut distrend_client as that pointer instead of using this list) */
 
  /* list_t clients; */
 

	
 
@@ -121,6 +124,8 @@ struct distrend_client
 
  size_t inlen; /*< number of bytes waiting to be processed */
 
  size_t expectlen; /*< number of bytes that inlen has to be for a complete request to be had, 0 when waiting on header */
 

	
 
  struct tabletennis_client tabletennis_client;
 

	
 
  /**
 
   * Yes, even though the remoteio will have a void *pointer to this
 
   * struct, we need a reverse pointer for something like
src/server/mysql.c
Show inline comments
 
@@ -202,7 +202,7 @@ distrend_mysql_result_t mysqlQuery(distr
 
      mysql_free_result(result);
 
      return NULL;
 
    }
 
  fprintf(stderr,"Done!\n");
 
  fprintf(stderr, "Done!\n");
 

	
 
  /**
 
     Prepare data for return.
src/server/slave.c
Show inline comments
 
@@ -25,6 +25,7 @@
 
#include "common/options.h"
 
#include "common/protocol.h"
 
#include "common/remoteio.h"
 
#include "common/request.h"
 

	
 
#include <stdio.h>
 
#include <stdlib.h>
 
@@ -34,11 +35,33 @@
 

	
 
#define DEBUG 0
 

	
 
struct slave_state
 
{
 
  /* whether or not we've gotten past the copyright line */
 
  short copyright_done;
 

	
 
  /* number of bytes that we need to read before we have a whole packet */
 
  size_t expectlen;
 
  /* whether or not we should exit */
 
  int quit;
 

	
 
  /* the server's remoteio handle */
 
  struct remoteio *rem;
 
};
 

	
 
static void distren_slave_remoteio_close_handle(void *blah, void *data);
 
static size_t distren_slave_remoteio_read_handle(struct remoteio *rem,
 
						 void *blah,
 
						 void *buf,
 
						 size_t len,
 
						 void *data);
 

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

	
 
  struct slave_state slave_state;
 

	
 
  char *datadir;
 
  char *server;
 
  char *username;
 
@@ -59,8 +82,6 @@ int main(int argc, char *argv[])
 

	
 
  // struct distrenjob *myjob; /* Structure to hold data gathered from the XML file - not needed anymore? */
 

	
 
  struct remoteio *comm_slave;
 

	
 
  /**
 
     initializations
 
  */
 
@@ -145,14 +166,6 @@ int main(int argc, char *argv[])
 
      return 1;
 
    }
 

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

	
 
  // Variables needed for main loop
 
  int jobnum = 0;
 
  int framenum = 0;
 
@@ -174,13 +187,25 @@ int main(int argc, char *argv[])
 
  char *outputExt = "jpg";     /* Output Extension (e.g., JPG) */
 

	
 
  int haveWork = 0;
 
  int quit = 0;
 

	
 
  fprintf(stderr,"\nDistRen Slave Pre-Alpha %s\n- Experimental build: Use at your own risk!\n\n", PACKAGE_VERSION);
 

	
 
  int benchmarkTime = 0;
 
  int renderPower = 0;
 

	
 
  slave_state.copyright_done = 0;
 
  slave_state.expectlen = 0;
 
  slave_state.quit = 0;
 

	
 
  fprintf(stderr, "Connecting to server...\n");
 
  if(remoteio_open_server(&slave_state.rem, commonopts->remoteio, &distren_slave_remoteio_read_handle, &slave_state, &distren_slave_remoteio_close_handle, server))
 
    {
 
      fprintf(stderr, "Error connecting to server; exiting\n");
 
      return 1;
 
    }
 
  greet_server(slave_state.rem);
 

	
 

	
 
  fprintf(stderr,"\nDistRen Slave Pre-Alpha %s\n- Experimental build: Use at your own risk!\n\n", PACKAGE_VERSION);
 

	
 
  // @TODO: add call to function to force recalc if $render_power == ""
 
  if(runBenchmark)
 
    {
 
@@ -203,12 +228,16 @@ int main(int argc, char *argv[])
 

	
 

	
 
  // Main loop
 
  while(!quit)
 
  while(!slave_state.quit)
 
    {
 
      multiio_poll(multiio);
 

	
 
      if(slave_state.quit)
 
	break;
 

	
 
    // request work
 
    fprintf(stderr, "Waiting...\n");
 
    haveWork = getwork(comm_slave, &jobnum, &framenum);
 
    haveWork = getwork(slave_state.rem, &jobnum, &framenum);
 

	
 
    /* If we got a frame */
 
    if(haveWork)
 
@@ -223,13 +252,12 @@ int main(int argc, char *argv[])
 
          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);
 

	
 
        int dlret = downloadTar(urltoTar, pathtoTar);
 
        if(dlret == 0)
 
          fprintf(stderr,"Data retrieved successfully!\n");
 
        else if(dlret == 3){
 
          resetframe(comm_slave, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
          resetframe(slave_state.rem, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
          return 0; // ouput dir doesn't exist
 
        }
 
        else
 
@@ -245,7 +273,7 @@ int main(int argc, char *argv[])
 

	
 
          // If error unpacking tarball
 
          if(unpackJob(pathtoJob, pathtoTar)){
 
            resetframe(comm_slave, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
            resetframe(slave_state.rem, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
            fprintf(stderr,"Error decompressing tarball! Exiting.\n");
 
            return 1;
 
          }
 
@@ -270,7 +298,7 @@ int main(int argc, char *argv[])
 
        if(exec_blender(pathtoJobfile, pathtoOutput, framenum))
 
          {
 
            fprintf(stderr,"Error running Blender. Check your installation and/or your PATH.\n");
 
            resetframe(comm_slave, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
            resetframe(slave_state.rem, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
            return 1;
 
          }
 
        free(pathtoJobfile);
 
@@ -280,7 +308,7 @@ int main(int argc, char *argv[])
 
        int fstatus = stat(pathtoOutput, &buffer);
 
        if(fstatus == -1){
 
          fprintf(stderr,"*** %s doesn't exist! Scene may not have camera, or your blender installation is not working.\n", pathtoOutput);
 
          resetframe(comm_slave, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
          resetframe(slave_state.rem, jobnum, framenum);  // Unassign the frame on the server so other slaves can render it
 
          return 1;
 
        }
 
        else{
 
@@ -297,7 +325,18 @@ int main(int argc, char *argv[])
 
          pathtoOutput = NULL;
 

	
 
          // Tell the server that rendering and upload are complete of "jobjum.framenum"
 
          finishframe(comm_slave, jobnum, framenum);
 
          finishframe(slave_state.rem, jobnum, framenum);
 

	
 
  free(urltoTar);
 
  free(pathtoTar);
 
  free(pathtoTardir);
 
  free(pathtoJob);
 
  free(pathtoJobfile);
 
  free(urltoJobfile);
 
  free(urltoOutput);
 
  free(pathtoRenderOutput);
 
  free(pathtoOutdir);
 

	
 
        }
 
     }
 
    else{
 
@@ -323,20 +362,138 @@ int main(int argc, char *argv[])
 
    sleep(5); // Poll 5 seconds. @TODO: Remove all polling
 
  }
 

	
 
  fprintf(stderr,"Closing connection to server...\n");
 
  remoteio_close(comm_slave);
 
  fprintf(stderr, "Quitting...\n");
 

	
 
  free(my_cfg);
 
  free(outputExt);
 
  free(datadir);
 
  free(urltoTar);
 
  free(pathtoTar);
 
  free(pathtoTardir);
 
  free(pathtoJob);
 
  free(pathtoJobfile);
 
  free(urltoJobfile);
 
  free(urltoOutput);
 
  free(pathtoRenderOutput);
 
  free(pathtoOutdir);
 
  fprintf(stderr,"Goodbye!\n");
 
  fprintf(stderr, "Goodbye!\n");
 
  return 0;
 
}
 

	
 
static void distren_slave_remoteio_close_handle(void *blah, void *data)
 
{
 
  struct slave_state *slave_state = (struct slave_state *)data;
 

	
 
  fprintf(stderr, "Lost connection to server\n");
 

	
 
  slave_state->quit = 1;
 
}
 

	
 
static size_t distren_slave_remoteio_read_handle(struct remoteio *rem,
 
						 void *blah,
 
						 void *buf,
 
						 size_t len,
 
						 void *data)
 
{
 
  struct slave_state *slave_state = (struct slave_state *)data;
 

	
 
  struct distren_request *req, *my_req;
 
  void *req_data, *my_req_data;
 

	
 
  size_t to_return;
 

	
 
  size_t counter;
 

	
 
  /* to_return shall record how much of buf we've eaten already */
 
  to_return = 0;
 

	
 
  if(!slave_state->copyright_done)
 
    {
 
      putchar('\n');
 
      /* we have to flush through data until we hit a newline */
 
      for(counter = 0;
 
	  counter + slave_state->expectlen < 256 && counter < len && ((char *)buf)[counter] != '\n';
 
	  counter ++)
 
	{
 
	  putchar(((char *)buf)[counter]);
 
	}
 
      slave_state->expectlen += counter - 1;
 
      if(slave_state->expectlen == 256)
 
	{
 
	  fprintf(stderr, "\nThe server's greeting is too long. Maybe it speaks a foreign language\n");
 
	  slave_state->quit = 1;
 
	}
 
      if(counter < len && ((char *)buf)[counter] == '\n')
 
	{
 
	  putchar('\n');
 
	  counter ++;
 
	  slave_state->expectlen = 0;
 
	  slave_state->copyright_done = 1;
 
	  to_return += counter;
 
	  buf += counter;
 
	  len -= counter;
 
	}
 
      if(!slave_state->copyright_done)
 
	return to_return;
 
    }
 

	
 
  while(1)
 
    {
 
      /* if we haven't read a full header yet: */
 
      if(!slave_state->expectlen)
 
	{
 
	  if(len < sizeof(struct distren_request))
 
	    return 0;
 

	
 
	  /* figure out how much we need to read in before we can get anywhere */
 
	  if(distren_request_new_fromdata(&req, buf, len))
 
	    {
 
	      fprintf(stderr, "Failing to interpret data from server, exiting\n");
 
	      slave_state->quit = 1;
 
	      return 0;
 
	    }
 
	  slave_state->expectlen = sizeof(struct distren_request) + req->len;
 
	  distren_request_free(req);
 
	}
 

	
 
      if(slave_state->expectlen
 
	    && slave_state->expectlen <= len)
 
	{
 
	  distren_request_new_fromdata(&req, buf, len);
 
	  req_data = buf + sizeof(struct distren_request);
 

	
 
	  switch((enum distren_request_type)req->type)
 
	    {
 
	    case DISTREN_REQUEST_VERSION:
 
	      fprintf(stderr, "The server runs ");
 
	      for(counter = 0; counter < req->len; counter ++)
 
		putc(((char *)req_data)[counter], stderr);
 
	      putc('\n', stderr);
 
	      break;
 

	
 
	    case DISTREN_REQUEST_PING:
 
	      fprintf(stderr, "PONG ! :-D\n");
 

	
 
	      distren_request_poing(&my_req, &my_req_data, 0, req_data, req->len);
 
	      remoteio_write(slave_state->rem, &my_req, sizeof(struct distren_request));
 
	      remoteio_write(slave_state->rem, &my_req_data, req->len);
 
	      distren_request_free_with_data(my_req, my_req_data);
 
	      break;
 

	
 
	    case DISTREN_REQUEST_DISCONNECT:
 
	      /* hopefully this ends up being a useful message... */
 
	      printf("You have been disconnected: \"");
 
	      for(counter = 0; counter < req->len; counter ++)
 
		putchar(((char *)buf)[counter]);
 
	      putchar('"');
 
	      putchar('\n');
 
	      break;
 

	
 
	    default:
 
	      fprintf(stderr, "something\n");
 
	      break;
 
	    }
 

	
 
	  distren_request_free(req);
 
	  slave_state->expectlen = 0;
 

	
 
	  counter = req->len + sizeof(struct distren_request);
 

	
 
	  len -= counter;
 
	  buf += counter;
 
	  to_return += counter;
 
	}
 
    }
 

	
 
  return to_return;
 
}
src/server/slavefuncs.c
Show inline comments
 
@@ -844,6 +844,9 @@ int login_user(char *username)
 
*/
 
int sendSignal(struct remoteio *rem, char signal)
 
{
 

	
 
  fprintf(stderr, __FILE__ ":%d: Ignoring call to DEPRECATED and WRONG sendSignal() function. See similar message for sendExtSignal() for details\n", __LINE__);
 
  return 1;
 
  remoteio_write(rem, &signal, 1);
 

	
 
  /**
 
@@ -864,6 +867,10 @@ int sendExtSignal(struct remoteio *rem, 
 
{
 
  size_t len;
 
  char *ssignal;
 

	
 
  fprintf(stderr, __FILE__ ":%d: Ignoring call to DEPRECATED and WRONG sendExtSignal() function. First of all, this function's name is camelCase. Secondly, it doesn't use protocol.h properly. I'll show how later. Thirdly, when protocol.h and request.h (still being written) are used properly, you don't need sendExtSignal() at all.\n", __LINE__);
 
  return 1;
 

	
 
  /**
 
   * Just append the data FIXME: We should do this differently
 
   */
src/server/tabletennis.c
Show inline comments
 
new file 100644
 
/*
 
 * Copyright 2010 Nathan Phillip Brink
 
 *
 
 * This file is a part of DistRen.
 
 *
 
 * DistRen is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * DistRen is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
#include "distrend.h"
 
#include "listen.h"
 
#include "tabletennis.h"
 

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

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

	
 
struct tabletennis
 
{
 
  unsigned int ping_interval;
 
  unsigned int pong_time;
 

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

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

	
 
  struct timespec time_last_check;
 
};
 

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

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

	
 
  tabletennis = malloc(sizeof(struct tabletennis));
 

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

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

	
 
  return tabletennis;
 
}
 

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

	
 
  q_enqueue(tabletennis->clients_to_ping, client, 0);
 

	
 
  return 0;
 
}
 

	
 
int tabletennis_serve(tabletennis_t tabletennis)
 
{
 
  struct timespec time_now;
 
  struct distrend_client *client;
 
  time_t time_next_check;
 

	
 
  struct distren_request *req;
 
  void *req_data;
 
  size_t req_len;
 

	
 
  clock_gettime(CLOCK_MONOTONIC, &time_now);
 

	
 
  time_next_check = time_now.tv_sec + tabletennis->pong_time;
 
  for(client = q_front(tabletennis->clients_to_ping);
 
      client && client->tabletennis_client.time_next_check < time_now.tv_sec;
 
      client = q_front(tabletennis->clients_to_ping))
 
    {
 
      q_dequeue(tabletennis->clients_to_ping);
 

	
 
      /* use time_next_check as the ping data */
 
      req_len = distren_request_poing(&req, &req_data, 1, &time_next_check, sizeof(time_next_check));
 
      distrend_client_write_request(client, req, req_data);
 
      distren_request_free_with_data(req, req_data);
 

	
 
      client->tabletennis_client.state = TABLETENNIS_NEED_PONG;
 

	
 
      client->tabletennis_client.time_next_check = time_next_check;
 

	
 
      q_enqueue(tabletennis->clients_need_pong, client, 0);
 
    }
 

	
 
  time_next_check = time_now.tv_sec + tabletennis->ping_interval;
 
  for(client = q_front(tabletennis->clients_need_pong);
 
      client && client->tabletennis_client.time_next_check < time_now.tv_sec;
 
      client = q_front(tabletennis->clients_need_pong))
 
    {
 
      q_dequeue(tabletennis->clients_need_pong);
 

	
 
      if(client->tabletennis_client.state == TABLETENNIS_NEED_PONG)
 
	{
 
	  distrend_send_disconnect(client, "You failed to respond to a PING packet after some seconds!");
 
	  client->tabletennis_client.state = TABLETENNIS_DELINQUENT;
 
	}
 
      else /* state must be TABLETENNIS_HAS_PONG */
 
	{
 
	  client->tabletennis_client.time_next_check = time_next_check;
 
	  client->tabletennis_client.state = TABLETENNIS_NEED_PING;
 

	
 
	  q_enqueue(tabletennis->clients_to_ping, client, 0);
 
	}
 
    }
 

	
 
  /* for tabletennis_add_client() */
 
  memcpy(&tabletennis->time_last_check, &time_now, sizeof(struct timespec));
 

	
 
  return 0;
 
}
 

	
 
/**
 
 * helper for tabletennis_del_client() which just looks for a
 
 * particular pointer in the queue (a.k.a., list).
 
 */
 
static int tabletennis_del_client_traverse(void *trav_data, void *client)
 
{
 
  if(trav_data == client)
 
    return FALSE;
 

	
 
  return TRUE;
 
}
 

	
 
int tabletennis_del_client(tabletennis_t tabletennis, struct distrend_client *client)
 
{
 
  list_t thelist;
 

	
 
  thelist = NULL;
 
  switch(client->tabletennis_client.state)
 
    {
 
    case TABLETENNIS_NEED_PING:
 
      thelist = tabletennis->clients_to_ping;
 
      break;
 

	
 
    case TABLETENNIS_NEED_PONG:
 
    case TABLETENNIS_HAS_PONG:
 
      thelist = tabletennis->clients_need_pong;
 
      break;
 

	
 
    case TABLETENNIS_DELINQUENT:
 
      thelist = NULL;
 
      break;
 
    }
 

	
 
  if(!thelist)
 
    return 0;
 

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

	
 
  return 0;
 
}
 

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

	
 
  free(tabletennis);
 
}
 

	
 
/* implementations of locals */
 

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

	
 
  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);
 
  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)
 
{
 
  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)
 
     && !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;
 
}
src/server/tabletennis.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright 2010 Nathan Phillip Brink
 
 *
 
 * This file is a part of DistRen.
 
 *
 
 * DistRen is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * DistRen is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
#ifndef _DISTREN_TABLETENNIS_H
 
#define _DISTREN_TABLETENNIS_H
 

	
 
/**
 
 * @file For managing the PINGs and PONGs of our present life.
 
 *
 
 * Do not call ping pong ping pong! Any professional ping-ponger will
 
 * be immediately offended. Use tabletennis instead and prosper.
 
 */
 

	
 
#include "distrend.h"
 

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

	
 
struct tabletennis;
 
typedef struct tabletennis *tabletennis_t;
 

	
 
/**
 
 * this struct should be embedded into struct distrend_client
 
 */
 
struct tabletennis_client
 
{
 
  /*
 
   * the time that the client should be processed from the
 
   * clients_to_ping or clients_need_pong queues.
 
   */
 
  time_t time_next_check;
 

	
 
  enum tabletennis_client_state
 
    {
 
      /* in clients_to_ping */
 
      TABLETENNIS_NEED_PING,
 
      /* in clients_need_pong */
 
      TABLETENNIS_NEED_PONG,
 
      TABLETENNIS_HAS_PONG,
 
      /* not in any queue */
 
      TABLETENNIS_DELINQUENT,
 
    } state;
 
};
 

	
 
/**
 
 * Initializes the context data for tabletennis.
 
 *
 
 * @param listens to register tabletennis's PING and PONG handlers
 
 * @param ping_interval The number of seconds to wait before sending a client a PING packet.
 
 * @param pong_time The number of seconds to wait before checking if a client sent a PONG packet.
 
 */
 
tabletennis_t tabletennis_new(struct distrend_listens *listens, unsigned int ping_interval, unsigned int pong_time);
 

	
 
/**
 
 * Add a client to the tabletennis game.
 
 *
 
 * @param tabletennis the tabletennis context.
 
 * @param client the client
 
 */
 
int tabletennis_add_client(tabletennis_t tabletennis, struct distrend_client *client);
 

	
 
/**
 
 * Sends PING packets to clients that need them and checks that
 
 * clients have sent PONG packets on time.
 
 *
 
 * @param clients_to_ping a queue initialized
 
 */
 
int tabletennis_serve(tabletennis_t tabletennis);
 

	
 
/**
 
 * Remove a client to the tabletennis game.
 
 *
 
 * @param tabletennis the tabletennis context.
 
 * @param client the client
 
 */
 
int tabletennis_del_client(tabletennis_t tabletennis, struct distrend_client *client);
 

	
 
/**
 
 * Deallocates and frees the tabletennis context data.
 
 *
 
 * Does not free the distren_client structs
 
 *
 
 * @param tabletennis the tabletennis context.
 
 */
 
void tabletennis_free(tabletennis_t tabletennis);
 

	
 
#endif
0 comments (0 inline, 0 general)