Changeset - e22839d03ac9
[Not reviewed]
default
0 2 0
Nathan Brink (binki) - 15 years ago 2010-07-02 12:13:57
ohnobinki@ohnopublishing.net
Add DISTREN_REQUEST_PING handler to distrend and fix one of many memory leaks.
2 files changed with 21 insertions and 0 deletions:
0 comments (0 inline, 0 general)
src/server/distrend.c
Show inline comments
 
@@ -44,277 +44,297 @@
 
#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();
 
int distrend_do_config(int argc, char *argv[], struct distrend_config **config);
 
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_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);
 
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 */
 
  int tmp;
 
  struct general_info general_info;
 

	
 
  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,
 
		  general_info.config->mysql_user,
 
		  general_info.config->mysql_host,
 
		  general_info.config->mysql_pass,
 
		  general_info.config->mysql_database) )
 
    {
 
      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);
 

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

	
 
  distrend_listen_handler_add(general_info.config->listens, DISTREN_REQUEST_VERSION, &distrend_handle_version);
 
  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 */
 
  general_info.config->die = 0;
 
  while(!general_info.config->die)
 
    {
 
      int clientrequest = 0; /*< temporary example variable, will be replaced when we can handle messages */
 

	
 
      distrend_accept(general_info.config->listens);
 

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

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

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

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

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

	
 
  xmlcleanup();
 

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

	
 
  return 0;
 
}
 

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

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

	
 
  struct distren_request *newreq;
 

	
 
  if(client->state != DISTREND_CLIENT_PREVERSION)
 
    {
 
      distrend_send_disconnect(geninfo->config->listens, client, "You have already sent the VERSION command.");
 
    }
 
  if(strlen(PACKAGE_STRING) == req_len
 
     && !strncmp(PACKAGE_STRING, req_data, req_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.
 
      */
 
      client->state = DISTREND_CLIENT_PREAUTH;
 

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

	
 
      _distren_asprintf(&tmp_str, "You have tried to connect to a %s server when your client claims to be running %s. Bye ;-)\n", PACKAGE_STRING, fixedbuf);
 
      distrend_send_disconnect(geninfo->config->listens, client, tmp_str);
 
    }
 

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

	
 
  return 0;
 
}
 

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

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

	
 
  cfg_opt_t myopts_listen[] =
 
    {
 
      CFG_SIMPLE_STR("type", NULL),
 
      CFG_SIMPLE_STR("path", NULL),
 
      CFG_SIMPLE_INT("port", NULL),
 
      CFG_END()
 
    };
 
  cfg_opt_t myopts[] =
 
    {
 
      CFG_SEC("listen",  /* this must be imported into struct listens (which must still be declared) */
 
          myopts_listen,
 
          CFGF_MULTI),
 
      CFG_SIMPLE_STR("datadir", NULL),
 
      CFG_STR_LIST("render_types", NULL, CFGF_NONE),
 
      CFG_SIMPLE_STR("mysql_user", NULL),
 
      CFG_SIMPLE_STR("mysql_host", NULL),
 
      CFG_SIMPLE_STR("mysql_pass", NULL),
 
      CFG_SIMPLE_STR("mysql_database", NULL),
 
      CFG_END()
 
    };
 

	
 
  cfg_t *cfg_listen;
 

	
 
  fprintf(stderr, "%s:%d: running config\n", __FILE__, __LINE__);
 
  *config = malloc(sizeof(struct distrend_config));
 
  myopts[1].simple_value = &(*config)->datadir;
 
  myopts[3].simple_value = &(*config)->mysql_user;
 
  myopts[4].simple_value = &(*config)->mysql_host;
 
  myopts[5].simple_value = &(*config)->mysql_pass;
 
  myopts[6].simple_value = &(*config)->mysql_database;
 

	
 
  if(options_init(argc, argv, &(*config)->mycfg, myopts, "daemon", &(*config)->options))
 
    return 1;
 

	
 
  /**
src/server/listen.c
Show inline comments
 
@@ -239,96 +239,97 @@ int distrend_handleread(struct distrend_
 

	
 
	      client->state = DISTREND_CLIENT_DEAD;
 
	      return 1;
 
	    }
 
	  client->expectlen = req->len + sizeof(struct distren_request);
 
	  distren_request_free(req);
 
	}
 
    }
 
  if(client->expectlen
 
     && client->inlen >= client->expectlen)
 
    {
 
      /** essentially un-queue-ize the queue ;-) */
 
      distrend_packets_collapse(client->inmsgs, client->inlen);
 
      packet = q_front(client->inmsgs);
 

	
 
      if(distren_request_new_fromdata(&req, packet->data, packet->len))
 
	{
 
	  fprintf(stderr, "error handling data from client\n");
 
	  client->state = DISTREND_CLIENT_DEAD;
 
	  return 1;
 
	}
 

	
 
      if(packet->len - sizeof(struct distren_request) < req->len)
 
	{
 
	  fprintf(stderr, "error handling some data from client\n");
 
	  distren_request_free(req);
 
	  client->state = DISTREND_CLIENT_DEAD;
 
	  return 1;
 
	}
 

	
 
      reqdata = malloc(req->len);
 
      if(!reqdata)
 
	{
 
	  fprintf(stderr, "OOM\n");
 

	
 
	  distren_request_free(req);
 
	  return 1;
 
	}
 
      memcpy(reqdata, ((void *)packet->data) + sizeof(struct distren_request), req->len);
 
      memmove(packet->data,
 
	      ((void *)packet->data) + client->expectlen,
 
	      packet->len - client->expectlen);
 
      packet->len -= client->expectlen;
 

	
 
      client->inlen -= client->expectlen;
 
      client->expectlen = 0;
 

	
 
      distrend_dispatch_request(listens, client, req, reqdata);
 
      free(reqdata);
 
      distren_request_free(req);
 
    }
 
  return 0;
 
}
 

	
 
struct distrend_accept_client_proc_data
 
{
 
  struct distrend_listens *listens;
 
  time_t current_time;
 
};
 
int distrend_accept_client_proc(struct distrend_accept_client_proc_data *data,
 
				struct distrend_client *client)
 
{
 
  struct distrend_packet *packet;
 
  ssize_t written_amount;
 
  short revents;
 

	
 
  if(client->state == DISTREND_CLIENT_DEAD)
 
    return TRUE;
 

	
 
  /**
 
     Manage timing-out clients.
 
   */
 
  if(data->current_time > client->cleanup_time)
 
    switch(client->state)
 
      {
 
      case DISTREND_CLIENT_PREVERSION:
 
	distrend_send_disconnect(data->listens, client, "You have failed to present version information in a timely manner. Cya :-p");
 
	break;
 
      case DISTREND_CLIENT_PREAUTH:
 
	distrend_send_disconnect(data->listens, client, "You have failed to present authentication information in a timely manner. Cya ;-)");
 
	break;
 

	
 
      case DISTREND_CLIENT_GOOD:
 
	distrend_send_disconnect(data->listens, client, "Ping timeout :-p");
 
	break;
 

	
 
      case DISTREND_CLIENT_BAD:
 
	client->state = DISTREND_CLIENT_DEAD;
 
	return TRUE;
 

	
 
      default:
 
	break;
 
      }
 

	
 
  revents = data->listens->pollfds[client->sock.pollfd_offset].revents;
 
  if(revents & POLLRDNORM)
 
    /* handle reading */
0 comments (0 inline, 0 general)