Changeset - f1fb3f3ed558
[Not reviewed]
default
0 4 0
Nathan Brink (binki) - 16 years ago 2010-01-23 15:26:03
ohnobinki@ohnopublishing.net
kill createJobFromXML(), fix distrenjob_unserialize(), kill distrenjob.email
4 files changed with 135 insertions and 96 deletions:
0 comments (0 inline, 0 general)
src/server/distrend.c
Show inline comments
 
@@ -245,43 +245,42 @@ int restoreJobState(struct distrenjob *j
 
      free(path_and_number);
 
    }
 

	
 
  return !isJobDone;
 
}
 

	
 
/**
 
   creates a structure from starting data, then calls another
 
   function to actually add that struct to the queue.
 

	
 
   Passed strings must be free()d by the caller.
 
*/
 
int prepare_distrenjob(struct general_info *geninfo, int type, char *name, char *submitter, char *email, int priority, int start_frame, int end_frame, int width, int height)
 
int prepare_distrenjob(struct general_info *geninfo, int type, char *name, char *submitter, int priority, int start_frame, int end_frame, int width, int height)
 
{
 
  int counter;
 
  int counter2;
 
  int tmp;
 
  char *serialfile;
 

	
 
  struct distrenjob *distrenjob;
 
  tmp = distrenjob_new(&distrenjob);
 
  if(tmp)
 
    return 1;
 

	
 
  geninfo->highest_jobnum ++;
 
  distrenjob->jobnum = geninfo->highest_jobnum;
 

	
 
  distrenjob->type = 1;
 
  distrenjob->name = strdup(name);
 
  distrenjob->submitter = strdup(submitter);
 
  distrenjob->email = strdup(email);
 
  distrenjob->priority = priority;
 
  distrenjob->width = width;
 
  distrenjob->height = height;
 
  /** sets the total number of frames in animation for status purposes */
 
  distrenjob->total_frames = (end_frame - start_frame + 1);
 
  distrenjob->frameset = malloc(sizeof(struct frameset) * distrenjob->total_frames);
 
  if(!distrenjob->frameset)
 
    {
 
      distrenjob_free(&distrenjob);
 
      fprintf(stderr, "OOM\n");
 
      
 
      return 1;
 
@@ -775,89 +774,41 @@ int import_general_info(struct general_i
 
  general_info->hibernate = 0;
 
  general_info->free_clients = 0;
 
  general_info->rendering_clients = 0;
 
  general_info->timestamp = 0;
 
  general_info->total_render_power = 0;
 
  general_info->total_priority_pieces = 0;
 

	
 
  xmlFreeDoc(doc);
 

	
 
  return 0;
 
}
 

	
 

	
 
// extracts data from the xml created by above function and creates a job from it
 
// it returns a pointer to the created job
 
struct distrenjob *createJobFromXML(struct general_info *geninfo, unsigned int jobnum)
 
/**
 
   determines path to the distenjob XML file and
 
   calls distrenjob_unserialize()
 
 */
 
int restore_distrenjob(struct general_info *geninfo, struct distrenjob **distrenjob, jobnum_t jobnum)
 
{
 
  xmlDocPtr doc;
 
  xmlNodePtr cur;
 
  int tmp;
 
  char *file_name;
 
  struct distrenjob *distrenjob;
 
  int start_frame;
 
  int counter;
 
  int counter2;
 

	
 
  job_getserialfilename(&file_name, geninfo, jobnum, 0);
 

	
 
  doc = xmlParseFile(file_name);
 
  if(!doc)
 
    return NULL;
 

	
 
  distrenjob_new(&distrenjob);
 

	
 
  cur = xmlDocGetRootElement(doc);
 

	
 
  distrenjob->name = (char*)xmlGetProp(cur, (xmlChar*)"name");
 
  distrenjob->submitter = (char*)xmlGetProp(cur, (xmlChar*)"submitter");
 
  distrenjob->priority = atoi((char*)xmlGetProp(cur, (xmlChar*)"priority"));
 

	
 
  cur = cur->xmlChildrenNode;
 
  distrenjob->width = atoi((char*)xmlGetProp(cur, (xmlChar*)"width"));
 
  distrenjob->height = atoi((char*)xmlGetProp(cur, (xmlChar*)"number"));
 

	
 
  cur = cur->next;
 
  start_frame = atoi((char*)xmlGetProp(cur, (xmlChar*)"start_frame"));
 
  distrenjob->total_frames = atoi((char*)xmlGetProp(cur, (xmlChar*)"end_frame")) - start_frame + 1;
 
  distrenjob->output_format = (char*)xmlGetProp(cur, (xmlChar*)"output_format");
 

	
 
  cur = cur->next;
 
  distrenjob->watchdog_forgiveness = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1));
 

	
 
  xmlFreeDoc(doc);
 

	
 
  /** load up stats.xml file to retrieve data */
 
  _distren_asprintf(&file_name, "stor/job%d/stats.xml", jobnum);
 

	
 
  doc = xmlParseFile(file_name);
 
  free(file_name);
 
  cur = xmlDocGetRootElement(doc);
 
  tmp = job_getserialfilename(&file_name, geninfo, jobnum, 0);
 
  if(tmp)
 
    return tmp;
 

	
 
  distrenjob->total_render_time = (time_t)atol((char*)xmlGetProp(cur, (xmlChar*)"total_render_time"));
 

	
 
  xmlFreeDoc(doc);
 

	
 
  distrenjob->frameset = malloc(sizeof(struct frameset) * distrenjob->total_frames);
 

	
 
  // change the status of all frames to "unassigned"
 
  counter2 = start_frame;
 
  for(counter = 0; counter <= distrenjob->total_frames; counter++){
 
    distrenjob->frameset[counter].num = counter2;
 
    distrenjob->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED;
 

	
 
    counter2++;
 
  }
 

	
 
  restoreJobState(distrenjob);
 
  return distrenjob;
 
  tmp = distrenjob_unserialize(distrenjob, file_name);
 
  free(file_name);
 
  
 
  return tmp;
 
}
 

	
 
int updateJobStatsXML(struct distrenjob *job)
 
{
 
	  xmlTextWriterPtr writer;
 
	  char *tmp;
 

	
 
	  _distren_asprintf(&tmp, "stor/job%d/stats.xml", job->jobnum);
 

	
 
	  /**
 
	     create xml document at the location tmp with no compression
 
	  */
 
@@ -1008,49 +959,48 @@ int createQueueFromXML(struct general_in
 
}
 

	
 
/**
 
   inserts jobs at front of queue, starting
 
   with the last job in the job_list xml file
 
   to preserve the order of the queue
 
*/
 
int reCreateQueueFromXML(struct general_info *geninfo, xmlDocPtr doc, xmlNodePtr current)
 
{
 
  struct distrenjob *holder; // holds the job that "was" after head, so that the new struct can be inserted after head
 
  struct distrenjob *job; // job to be added
 
  xmlChar *tmp;
 
  int job_num;
 
  jobnum_t job_num;
 
  if(current == NULL) // base case, if element doesn't exist then don't do anything
 
    return 0;
 

	
 
  /**
 
     recursively call itself so that the next job in
 
     the queue is added to the front before the current one
 
  */
 
  if(reCreateQueueFromXML(geninfo, doc, current->next))
 
    /**
 
       bail if failure recursevely
 
        ^-- is this the best thing to do in this case?
 
	@TODO bail-out cleanup
 
     */
 
    return 1;
 

	
 
  /** actual work is done now: add the job to the front of the queue */
 
  holder = geninfo->head.next;
 

	
 
  tmp = xmlNodeListGetString(doc, current->xmlChildrenNode, 1); // get job number
 
  job_num = atoi((char*)tmp);
 
  xmlFree(tmp);
 

	
 
  job = createJobFromXML(geninfo, job_num);
 
  if(job == NULL)
 
  if(restore_distrenjob(geninfo, &job, job_num))
 
    return 1;
 

	
 
  /**
 
     insert job at front of the queue
 
  */
 
  geninfo->head.next = job;
 
  job->next = holder;
 

	
 
  return 0;
 
}
 

	
 
/* ************************** Test Functions ************************* */
 
@@ -1087,27 +1037,26 @@ int printJob(struct distrenjob *job)
 
  fprintf(stderr, "frame_num: status\n");
 
  for(counter = 0; counter < job->total_frames; counter++)
 
    {
 
      printFrameInfo(&job->frameset[counter]);
 
    }
 

	
 
  return 1;
 
}
 

	
 
int printJobInfo(struct distrenjob *job)
 
{
 
  fprintf(stderr, "type: %d\n", job->type);
 
  fprintf(stderr, "name: %s\n", job->email);
 
  fprintf(stderr, "name: %s\n", job->name);
 
  fprintf(stderr, "submitter: %s\n", job->submitter);
 
  fprintf(stderr, "e-mail: %s\n", job->email);
 
  fprintf(stderr, "priority: %d\n", job->priority);
 
  fprintf(stderr, "completed: %d\n", job->completed_frames);
 
  fprintf(stderr, "assigned: %d\n", job->assigned_frames);
 
  fprintf(stderr, "total: %d\n", job->total_frames);
 
  fprintf(stderr, "watchdog: %d\n", job->watchdog_forgiveness);
 
  fprintf(stderr, "hibernate: %d\n", job->hibernate);
 
  fprintf(stderr, "prev_frame: %d\n", job->prev_frame_index);
 
  fprintf(stderr, "render power: %ld\n", job->assigned_render_power);
 

	
 
  return 1;
 
}
 

	
 
@@ -1189,26 +1138,26 @@ int main(int argc, char *argv[])
 

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

	
 
  if(start_data(&general_info))
 
    {
 
      fprintf(stderr, "%s:%d: start_data() failed\n", __FILE__, __LINE__);
 
      return 1;
 
    }
 

	
 
  /** pre-loaded jobs for testing */
 
  prepare_distrenjob(&general_info, 1, "awesome", "LordOfWar", "onlylordofwar@gmail.com", 8, 1, 100, 640, 480);
 
  prepare_distrenjob(&general_info, 1, "hamburger", "ohnobinki", "ohnobinki@ohnopublishing.net", 3, 1, 50, 1280, 720);
 
  prepare_distrenjob(&general_info, 1, "awesome", "LordOfWar", 8, 1, 100, 640, 480);
 
  prepare_distrenjob(&general_info, 1, "hamburger", "ohnobinki", 3, 1, 50, 1280, 720);
 

	
 
  while(test == 1)
 
  {
 
    fprintf(stderr, "Welcome to DistRen Alpha Interactive Test Mode\n\n");
 
    fprintf(stderr, "\t1 \tPrint all frames in a job\n");
 
    fprintf(stderr, "\t2 \tExamine certain job\n");
 
    fprintf(stderr, "\t3 \tGet a frame to render\n");
 
    fprintf(stderr, "\t4 \tAdd a job\n");
 
    fprintf(stderr, "\t5 \tDelete a job\n");
 
    fprintf(stderr, "\t6 \tPrint jobnums in queue\n");
 
    fprintf(stderr, "\t7 \tPrint general info\n");
 
    fprintf(stderr, "\t8 \tQuit\n");
 
@@ -1242,25 +1191,25 @@ int main(int argc, char *argv[])
 
      submitter = NULL;
 
      email = NULL;
 

	
 
      fprintf(stderr, "\nType: \n\t 1 \t blender\n\t 2 \t povray\n"); scanf("%d", &type);
 
      fprintf(stderr, "\nName: ");        scanf("\n"); getline(&name, &read_buf, stdin);
 
      fprintf(stderr, "\nSubmitter: ");                getline(&submitter, &read_buf, stdin);
 
      fprintf(stderr, "\nEmail: ");                    getline(&email, &read_buf, stdin);
 
      fprintf(stderr, "\nPriority: ");                 scanf("%d", &priority);
 
      fprintf(stderr, "\nStart frame: ");              scanf("%d", &start_frame);
 
      fprintf(stderr, "\nEnd frame: ");                scanf("%d", &end_frame);
 
      fprintf(stderr, "\nWidth: ");                    scanf("%d", &width);
 
      fprintf(stderr, "\nHeight: ");                   scanf("%d", &height);
 
      prepare_distrenjob(&general_info, type, name, submitter, email, priority, start_frame, end_frame, width, height);
 
      prepare_distrenjob(&general_info, type, name, submitter, priority, start_frame, end_frame, width, height);
 
      break;
 
    case 5:
 
      fprintf(stderr, "\nJob number: ");
 
      scanf("%d", &jobnum);
 
      distrenjob_remove(&general_info, distrenjob_get(&general_info.head, jobnum));
 
      break;
 
    case 6:
 
      printAllJobnums(&general_info.head);
 
      break;
 
    case 7:
 
      fprintf(stderr, "\nHighest job number: %d", general_info.highest_jobnum);
 
      fprintf(stderr, "\nJobs in queue: %d", general_info.jobs_in_queue);
src/server/distrenjob.c
Show inline comments
 
@@ -23,72 +23,108 @@
 

	
 
#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);
 
  xmlFree(dj->email);
 

	
 
  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->name = (char *)NULL;
 
  dj->submitter = (char *)NULL;
 
  dj->email = (char *)NULL;
 
  dj->jobnum = 0; /*< @todo there should be a central jobnum allocator and a way to save the maximum jobnumber allocated */
 
  dj->priority = 0;
 
  dj->width = 0;
 
  dj->height = 0;
 
  dj->completed_frames = 0;
 
  dj->assigned_frames = 0;
 
  dj->total_render_time = 0;
 
  dj->hibernate = 0;
 
  dj->prev_frame_index = -1;
 
  dj->assigned_render_power = 0;
 
  dj->watchdog_forgiveness = 3600; // initialize watchdog forgiveness at 1 hour
 
  dj->frameset = (struct frameset *)NULL; /*< @todo does frameset need to be initialized here? */
 

	
 
  return 0;
 
}
 

	
 
/**
 
   writes struct from xml
 
   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)
 
    return 1;
 

	
 
  *num = (unsigned int)strtoul((char *)string, (char **)NULL, 10);
 
#ifndef NDEBUG
 
  fprintf(stderr, "_distrenjob_xml_readuint(%zx, \"%s\", *(%zx)=%u): read %s=\"%d\"\n",
 
	  (size_t)xmlnode, propname, (size_t)num, *num, propname, *num);
 
#endif
 

	
 
  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;
 
@@ -100,68 +136,120 @@ int distrenjob_unserialize(struct distre
 
	 @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 *)"/distren/job");
 
  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 = _distren_asprintf((char **)&xmlchar, "/distren/submitters/submitter[attribute::name=\"%s\"]", dj->submitter);
 
  if(tmp <= 0
 
     || !xmlchar)
 
  tmp = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"priority", &dj->priority);
 
  if(tmp)
 
    {
 
      fprintf(stderr, "error using _distren_asprintf\n");
 
      distrenjob_free(distrenjob);
 
      return 6;
 
    }
 
  xmlnode = xml_quickxpath(xmlxpathcontext, xmlchar);
 
  free(xmlchar);
 
  dj->email = (char *)xmlGetProp(xmlnode, (xmlChar *)"email");
 
  if(!dj->email)
 
  
 
  dj->output_format = (char *)xmlGetProp(xmlnode, (xmlChar *)"output_format");
 
  if(!dj->output_format)
 
    {
 
      fprintf(stderr, "error getting email for user ``%s'' from ``%s''\n",
 
	      dj->submitter, pathtoxml);
 
      distrenjob_free(distrenjob);
 

	
 
      return 6;
 
    }
 

	
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/resolution");
 
  tmp = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"width"   , &dj->width   );
 
  tmp += _distrenjob_xml_readuint(xmlnode, (xmlChar *)"height"  , &dj->height  );
 

	
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/video");
 
  tmp += _distrenjob_xml_readuint(xmlnode, (xmlChar *)"start_frame", &start_frame);
 
  tmp += _distrenjob_xml_readuint(xmlnode, (xmlChar *)"end_frame", &end_frame);
 

	
 
  if(tmp)
 
    {
 
      fprintf(stderr, "distrenjob_unserialize(): error reading integer values from ``%s''\n",
 
	      pathtoxml);
 
      distrenjob_free(distrenjob);
 
      return 7;
 
    }
 

	
 
  /**
 
     total_render_time and watchdog stuff doesn't need error
 
     checking, just good defaults
 
  */
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/stats");
 
  dj->total_render_time = 0;
 
  xmlchar = xmlGetProp(xmlnode, (xmlChar *)"total_render_time");
 
  if(xmlchar)
 
    {
 
      if(strptime((char *)xmlchar, "%D %T", &tm))
 
	dj->total_render_time = mktime(&tm);
 
      xmlFree(xmlchar);
 
    }
 

	
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/watchdog");
 
  dj->watchdog_forgiveness = 3600;
 
  tmp =_distrenjob_xml_readuint(xmlnode, (xmlChar *)"forgiveness", &dj->watchdog_forgiveness);
 
  if(tmp)
 
    fprintf(stderr, "distrenjob_unserialize(): warning: watchdog forgiveness is unspecified in ``%s'', defaulting to 3600\n", pathtoxml);
 

	
 
  xmlXPathFreeContext(xmlxpathcontext);
 
  xmlFreeDoc(xmldoc);
 

	
 
  /**
 
     reconstruct the frameset
 
  */
 
  dj->total_frames = end_frame - start_frame + 1;
 
 dj->frameset = malloc(sizeof(struct frameset) * dj->total_frames);
 
 if(!dj->frameset)
 
   {
 
     fprintf(stderr, "OOM!\n");
 
     distrenjob_free(distrenjob);
 
     return 8;
 
   }
 
 fs = dj->frameset;
 
 for(counter = start_frame; counter <= end_frame; counter ++)
 
   {
 
     fs->num = counter;
 
     fs->status = FRAMESETSTATUS_UNASSIGNED; /*< @todo job partial completion and resumption support */
 

	
 
     fs ++;
 
   }
 

	
 
  return 0;
 
}
 

	
 
int distrenjob_serialize(struct distrenjob *job, char *outfile)
 
{
 
  xmlTextWriterPtr writer;
 
  char *tmp;
 
  char *tmpfile;
 
  int tmprtn;
 

	
 
  /**
 
     transactional FS access for POSIX systems...
src/server/distrenjob.h
Show inline comments
 
@@ -29,34 +29,33 @@
 

	
 
typedef unsigned int jobnum_t;
 

	
 
/**
 
   Stores Blender Job Info
 
*/
 
struct distrenjob
 
{
 
  struct distrenjob *next; /*< next will be NULL unless if there is another distrenjob */
 
  short int type; /*< 1:Blender, 2:something else */
 
  char *name;
 
  char *submitter;
 
  char *email; /*< This should be looked up based on the value of submitter, not stored in this struct */
 
  jobnum_t jobnum;
 
  int width; /*< width in pixels of the frames to be rendered */
 
  int height; /*< height in pixels of the frames to be rendered */
 
  int priority;  /*< 1 is lowest, 10 is highest, 0 means the job is done */
 
  int completed_frames; /*< number of completed frames for stats/etc */
 
  int assigned_frames; /*< number of assigned frames (that are not yet completed) for stats/etc */
 
  int total_frames; /*< how many frames are in the animation for stats/etc (unassigned frames) */
 
  int watchdog_forgiveness; /*< how many seconds till the frame is re-assigned (if client computer crashes etc); */
 
  short int hibernate;
 
  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) */
 
  unsigned int watchdog_forgiveness; /*< how many seconds 'til the frame is re-assigned (if client computer crashes etc); */
 
  short int hibernate; /*< @todo DOCUMENT THIS */
 
  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 */
 
  char *output_format; /*< currently is the file extension of the request output format. @todo make this mime-type based/not a string */
 
  unsigned long int assigned_render_power;
 
  struct frameset *frameset;
 
};
 

	
 

	
 

	
 
/**
 
   Frameset Structure
 
*/
src/server/slavefuncs.c
Show inline comments
 
@@ -82,25 +82,28 @@ int sendExtSignal(struct remoteio *rem, 
 
     return 0;
 

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

	
 

	
 

	
 
/**
 
 utility function for XPath-ish stuff:
 
   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;
0 comments (0 inline, 0 general)