/*
Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
This file is a part of DistRen.
DistRen is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DistRen is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with DistRen. If not, see .
*/
#include "distrenjob.h"
#include "slavefuncs.h"
#include "common/asprintf.h"
#include "common/execio.h"
#include "common/protocol.h"
#include "common/remoteio.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEBUG 0
/**
Grabs the xml DOM node reached by an XPath.
@param path an XPath that lead to DOM node
@return the first node associated with the path or NULL if there is no match
*/
xmlNodePtr xml_quickxpath(xmlXPathContextPtr xpathctxt, xmlChar *path)
{
xmlNodePtr toreturn;
xmlXPathObjectPtr xmlxpathobjptr;
xmlxpathobjptr = xmlXPathEval(path, xpathctxt);
if(!xmlxpathobjptr
|| !xmlxpathobjptr->nodesetval->nodeNr)
{
fprintf(stderr, "XPath resolution failed for ``%s'' in ``%s'' (``%s'')\n", path, xpathctxt->doc->name, xpathctxt->doc->URL);
return (xmlNodePtr)NULL;
}
toreturn = *(xmlxpathobjptr->nodesetval->nodeTab);
xmlXPathFreeObject(xmlxpathobjptr);
return toreturn;
}
/** Deletes job data from the disk. @TODO: add error checking! */
int delete_jobdata(int jobnum, char *datadir)
{
char *jobpath;
char *jobcont;
_distren_asprintf(&jobpath, "%s/%d", datadir, jobnum);
_distren_asprintf(&jobcont, "%s/%d/*", datadir, jobnum);
remove(jobcont);
rmdir(jobpath);
fprintf(stderr, "Removed files in %s/%d/ if everything was successful\n", jobpath, jobnum);
free(jobpath);
free(jobcont);
return 0;
}
/** Function referenced by curlget() to write data to disk. */
size_t curl_writetodisk(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
return fwrite(ptr, size, nmemb, stream);
}
/** Helper function for cURL's progress display */
int curl_progress(char *Bar, double t, double d, double ultotal, double ulnow)
{
fprintf(stderr,"Downloading: %f%% complete\r",d/t*100);
return 0;
}
/** Retrieves a URL with cURL and saves it to disk */
CURLcode curlget(char *url, char *out){
fprintf(stderr,"Preparing to download %s\n",url);
double *Bar; // Stores cURL progress display info
CURL *curl;
CURLcode res;
FILE *outfile;
res = CURLE_FAILED_INIT;
curl = curl_easy_init();
if(curl)
{
outfile = fopen(out, "w"); // Open where we're writing to
if(outfile == NULL)
return 2; // Output dir doesn't exist
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writetodisk); // this MUST be set for win32 compat.
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&curl_progress);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &Bar);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(outfile);
}
fprintf(stderr,"\n"); // Clears out he progressbar's carriage return
return res; // 0 is OK, 1 is 404 or other error
}
/** Posts a file to a url with cUrl */
CURLcode curlpost(char *filename, char *url, int jobnum, int framenum, int slavekey)
{
char *targetname = "uploadedfile"; // Name of the target in the php file on the server (Don't change me unless you have different PHP code)
CURL *curl;
CURLcode res;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
struct curl_slist *headerlist=NULL;
static const char buf[] = "Expect:";
char *sjobnum;
char *sframenum;
char *sslavekey;
if(DEBUG)
fprintf(stderr,"Uploading to %s\n", url);
_distren_asprintf(&sjobnum,"%d",jobnum);
_distren_asprintf(&sframenum,"%d",framenum);
_distren_asprintf(&sslavekey,"%d",slavekey);
curl_global_init(CURL_GLOBAL_ALL);
/* jobnum field... */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "jobnum",
CURLFORM_COPYCONTENTS, sjobnum, CURLFORM_END);
/* framenum field... */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "framenum",
CURLFORM_COPYCONTENTS, sframenum, CURLFORM_END);
/* slavekey field... */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "slavekey",
CURLFORM_COPYCONTENTS, sslavekey, CURLFORM_END);
/* upload field... */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, targetname,
CURLFORM_FILE, filename,
CURLFORM_END);
/* filename field... */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, filename,
CURLFORM_END);
/* submit field, not usually needed, just in case... */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);
res = CURLE_FAILED_INIT;
curl = curl_easy_init();
headerlist = curl_slist_append(headerlist, buf);
if(curl)
{
/* Setting the URL to get the post, and the contents of the post */
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
/* cleanup the formpost junk */
curl_formfree(formpost);
curl_slist_free_all (headerlist);
free(sjobnum);
free(sframenum);
free(sslavekey);
}
return res;
}
/** Replaces wordtoreplace with replacewith in conffile (relative to SYSCONFDIR) */
int conf_replace(char *conffile, char *wordtoreplace, char *replacewith){
int maxlinelen = 120;
char *fileOrig;
char *fileRepl;
_distren_asprintf(&fileOrig, "%s/%s", SYSCONFDIR, conffile);
_distren_asprintf(&fileRepl, "%s%s.edited", SYSCONFDIR, conffile);
char buffer[maxlinelen+2];
char *buff_ptr, *find_ptr;
FILE *fp1, *fp2;
size_t find_len = strlen(wordtoreplace);
fp1 = fopen(fileOrig,"r");
fp2 = fopen(fileRepl,"w");
if (fp1 ==NULL){
fprintf(stderr, "%s doesn't exist\n",fileOrig);
return 0;
}
else if(fp2 ==NULL){
fprintf(stderr, "Can't write a file to disk! Check permissions.\n");
return 0;
}
else{
while(fgets(buffer,maxlinelen+2,fp1))
{
buff_ptr = buffer;
while ((find_ptr = strstr(buff_ptr,wordtoreplace)))
{
while(buff_ptr < find_ptr)
fputc((int)*buff_ptr++,fp2);
fputs(replacewith,fp2);
buff_ptr += find_len;
}
fputs(buff_ptr,fp2);
}
rename(fileRepl, fileOrig);
}
fclose(fp2);
fclose(fp1);
fprintf(stderr,"Wrote conf file...\n");
return 1; // Success
}
/* Executors */
/** Executor function for Blender operations */
int exec_blender(char *input, char *output, int frame)
{
int ret;
char *frame_str;
_distren_asprintf(&frame_str, "%i", frame);
char *command = "blender"; // @TODO: We currently expect this to be in PATH
char *cmd[] = { command, "-b", input, "-o", output, "-f", frame_str, "-t", "0", (char *)NULL }; // arguments for blender
if(DEBUG)
fprintf(stderr,"Preparing to execute command: %s -b %s -o %s -f %s\n", command, input, output, frame_str);
char buf[20];
struct execio *testrem;
size_t readlen;
if(DEBUG)
fprintf(stderr,"Executing: %s\n", frame_str);
ret = execio_open(&testrem, command, cmd);
if(ret)
{
fprintf(stderr, "Error running blender\n");
return 1;
}
buf[19] = '\0';
while(!execio_read(testrem, buf, 19, &readlen))
{
buf[readlen] = '\0';
if(DEBUG)
fprintf(stderr, "read \"%s\"\n", buf);
}
execio_close(testrem);
free(frame_str);
return ret;
}
void xmlinit()
{
xmlInitParser();
xmlXPathInit();
}
void xmlcleanup()
{
xmlCleanupParser();
}
/** Creates directories recursively */
int distren_mkdir_recurse(char *dirname)
{
size_t counter;
char *nextdir;
nextdir = strdup(dirname);
for(counter = 0; nextdir[counter]; counter ++)
{
/** @TODO OS-portabalize the path-separators */
if(nextdir[counter] == '/')
{
nextdir[counter] = '\0';
mkdir(nextdir, S_IRWXU | S_IRGRP | S_IROTH);
nextdir[counter] = '/';
}
}
return 0;
}
/**
@TODO: Use for constructing path to job data locally and/or on data.distren.org
*/
int job_build_path(char *filename, unsigned int jobnum)
{
return 0;
}
int downloadTar(char *url, char *destinationPath){
// Prepare to download the job tar if it isn't present
struct stat buffer;
int fstatus = stat(destinationPath, &buffer);
if(fstatus == -1)
{
// Download the Tar
int ret = curlget(url, destinationPath);
if(ret == 0){
fprintf(stderr, "Job data retrieved successfully\n");
// free(url); @FIXME: causes doublefree! Curl must free the url?
return 0;
}
else if(ret == 1){
fprintf(stderr, "Downloading job data from %s failed. Check your network connection.\n",url);
free(url);
return 1; // Eventually make a retry loop
}
}
fprintf(stderr, "Tar at %s already exists! Download cancelled.\n", destinationPath);
return 2;
}
int uploadOutput(char *pathtoOutput, char *urltoOutput, int jobnum, int framenum, int slavekey){
//fprintf(stderr,"Uploading output %s to url %s for job %d and frame %d for slavekey %d", pathtoOutput, urltoOutput, jobnum, framenum, slavekey);
if( !curlpost(pathtoOutput, urltoOutput, jobnum, framenum, slavekey)) // Uploads output
{
if(DEBUG)
fprintf(stderr,"Upload successful, removing old output...\n");
else
fprintf(stderr,"Upload completed\n");
remove(pathtoOutput); // Delete the file after its uploaded
return 0;
}
else
{
fprintf(stderr,"Upload failed. Check your network connection. Retrying upload...\n");
int tries=1;
while(tries<=10 && curlpost(pathtoOutput, urltoOutput, jobnum, framenum, slavekey))
{
fprintf(stderr, "Upload failed. Trying again in 10 seconds... (attempt %d of 10)\n", tries);
tries++;
sleep(10);
}
return 1; // Upload failed after multiple tries
// @FUTURE: Keep track of files that we were unable to upload, and upload them later
}
}
void prepareJobPaths(int jobnum, int framenum, char *outputExt, char *datadir, char **urltoTar,char **pathtoTar,char **pathtoTardir,char **pathtoJob, char **pathtoJobfile, char **urltoJobfile, char **urltoOutput,char **pathtoOutput, char **pathtoRenderOutput, char **pathtoOutdir)
{
// Variable Preparation
char *jobdatapath;
_distren_asprintf(&jobdatapath, "job%d", jobnum);
_distren_asprintf(urltoTar, "http://data.distren.org/job%d/job%d.tar.gz", jobnum, jobnum); // Prepares URL to download from
_distren_asprintf(urltoJobfile, "http://data.distren.org/job%d/job.blend", jobnum); // Prepares URL to download from
_distren_asprintf(pathtoTar, "%s/%s/job%d.tar.gz", datadir, jobdatapath, jobnum); // Prepares destination to save to
_distren_asprintf(pathtoTardir, "%s/%s/", datadir, jobdatapath); // Prepares destination to save to
_distren_asprintf(pathtoJob, "%s/%s/", datadir, jobdatapath);
_distren_asprintf(pathtoJobfile, "%s/%s/job.blend", datadir, jobdatapath ); // Prepares the path to the jobfile
_distren_asprintf(urltoOutput, "http://dev.distren.org/slaveUpload.php?jobkey=%d&framekey=%d",jobnum,framenum); // Prepares the URL where output is posted
_distren_asprintf(pathtoRenderOutput, "%s/%s/output/job%d-frame#.%s", datadir, jobdatapath, jobnum, outputExt ); // Note: the # is for blender to put in framenum in output file
_distren_asprintf(pathtoOutput, "%s/%s/output/job%d-frame%d.%s", datadir, jobdatapath, jobnum, framenum, outputExt ); // Note: the # is for blender to put in framenum in output file
_distren_asprintf(pathtoOutdir, "%s/%s/output", datadir, jobdatapath);
free(jobdatapath);
}
int checkUsername(char *username)
{
if(username == NULL || strcmp(username, "!username") == 0 )
{
fprintf(stderr, "\nPlease ensure that your username is present in distrenslave.conf, or use the -u flag to set a username.\n");
return 1;
}
else
if( username != NULL || strcmp(username, "!username") != 0 )
{
// Log in the user
if(login_user(username) == 1){
// Logged in OK
return 0;
}
else
{
fprintf(stderr, "Login failed, please check your username. If you have not registered, please do so on the DistRen website.\n");
return 1;
}
}
else
{
fprintf(stderr, "Please check your distrenslave.conf, it appears to be incorrectly formatted.\n");
return 1;
}
}
void slaveTest(char *datadir)
{
int command;
int test = 1;
int jobnum = 0;
int framenum = 0;
int slavekey = 0;
fprintf(stderr,"Hello!\n");
char tmpString1[100] = "";
char tmpString2[100] = "";
char *uploadURL = "http://distren.org/slaveUpload.php";
while(test == 1)
{
fprintf(stderr, "Welcome to DistRenSlave Alpha Interactive Test Mode\n\n");
fprintf(stderr, "\t1 \tTest posting (uploading) data\n");
fprintf(stderr, "\t2 \tTest getting frame from server\n");
fprintf(stderr, "\t3 \tTest data downloading\n");
fprintf(stderr, "\t4 \tTest archive decompression\n");
fprintf(stderr, "\t5 \tQuit\n");
scanf("%d", &command);
switch(command)
{
case 1:
fprintf(stderr,"Path to output file to upload: ");
scanf("%99s", tmpString1);
fprintf(stderr,"Framenum that is being uploaded: ");
scanf("%d", &framenum);
fprintf(stderr,"Jobnum that frame belongs to: ");
scanf("%d", &jobnum);
fprintf(stderr,"Slavekey that rendered this output: ");
scanf("%d", &slavekey);
uploadOutput(tmpString1, uploadURL, jobnum, framenum, slavekey);
break;
case 2:
fprintf(stderr,"Remotio not implemented yet!\n");
break;
case 3:
fprintf(stderr,"URL to file: ");
scanf("%s", tmpString1);
fprintf(stderr,"Local save path (including filename): ");
scanf("%s", tmpString2);
if(downloadTar(tmpString1, tmpString2))
fprintf(stderr,"Error downloading!\n");
else
fprintf(stderr,"Success!\n");
break;
case 4:
fprintf(stderr,"Jobnum to decompress: ");
scanf("%d", &jobnum);
fprintf(stderr,"Path to compressed data: ");
scanf("%s", tmpString2);
unpackJob(datadir, tmpString1);
break;
case 5:
test = 0;
break;
default:
fprintf(stderr, "Invalid input, please try again.\n");
break;
}
}
}
/*
int runBenchmark(int slavekey, char *datadir){
// Execute blender
if(exec_blender(pathtoJobfile, pathtoOutput, framenum))
{
fprintf(stderr,"Error running Blender. Check your installation and/or your PATH.\n");
_web_resetframe(slavekey, password, jobnum, framenum); // Unassign the frame on the server so other slaves can render it
return 1;
}
free(pathtoJobfile);
struct stat buffer;
int fstatus = stat(pathtoOutput, &buffer);
if(fstatus == -1){
fprintf(stderr,"*** Frame was not rendered correctly! Scene may not have camera, or your blender installation is not working.\n");
_web_resetframe(slavekey, password, jobnum, framenum); // Unassign the frame on the server so other slaves can render it
return 1;
}
}
*/
/* simpleSlave functions */
/** Memory struct for curl */
struct _web_memorystruct {
char *memory;
size_t size;
};
void *_web_myrealloc(void *ptr, size_t size);
void *_web_myrealloc(void *ptr, size_t size)
{
/* There might be a realloc() out there that doesn't like reallocing
NULL pointers, so we take care of it here */
if(ptr)
return realloc(ptr, size);
else
return malloc(size);
}
size_t _web_writememorycallback(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct _web_memorystruct *mem = (struct _web_memorystruct *)data;
mem->memory = _web_myrealloc(mem->memory, mem->size + realsize + 1);
if (mem->memory) {
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
return realsize;
}
struct _web_memorystruct _web_getrequest(char *url){
// fprintf(stderr,"Preparing to get request at %s",url);
CURL *curl;
CURLcode res;
struct _web_memorystruct chunk;
chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
chunk.size = 0; /* no data at this point */
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _web_writememorycallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return chunk; // 0 is OK, 1 is 404 or other error
}
void _web_finishframe(int slavekey, char *slavepass, int jobnum, int framenum){
char *url;
_distren_asprintf(&url,"http://dev.distren.org/slave/act.php?mode=finishframe&slavekey=%d&slavepass=%s&jobnum=%d&framenum=%d", slavekey, slavepass, jobnum, framenum);
struct _web_memorystruct data = _web_getrequest(url);
free(url);
fprintf(stderr,"%s\n", data.memory);
if(data.memory)
free(data.memory);
}
void _web_resetframe(int slavekey, char *slavepass, int jobnum, int framenum){
fprintf(stderr,"Resetting frame %d in job %d on server... ",framenum,jobnum);
char *url;
_distren_asprintf(&url,"http://dev.distren.org/slave/act.php?mode=resetframe&slavekey=%d&slavepass=%s&jobnum=%d&framenum=%d", slavekey, slavepass, jobnum, framenum);
struct _web_memorystruct data = _web_getrequest(url);
free(url);
fprintf(stderr,"%s\n", data.memory);
if(data.memory)
free(data.memory);
}
void _web_startframe(int slavekey, char *slavepass, int jobnum, int framenum){
if(DEBUG)
fprintf(stderr,"Marking frame %d started on server... ",framenum);
char *url;
_distren_asprintf(&url,"http://dev.distren.org/slave/act.php?mode=startframe&slavekey=%d&slavepass=%s&jobnum=%d&framenum=%d", slavekey, slavepass, jobnum, framenum);
struct _web_memorystruct data = _web_getrequest(url);
free(url);
fprintf(stderr,"%s\n", data.memory);
if(data.memory)
free(data.memory);
}
int _web_getwork(int slavekey, char *slavepass, int *jobnum, int *framenum){
char *url;
_distren_asprintf(&url,"http://dev.distren.org/slave/act.php?mode=getwork&slavekey=%d&slavepass=%s", slavekey, slavepass);
struct _web_memorystruct data = _web_getrequest(url);
free(url);
if(!data.memory || !strcmp(data.memory,",")){
fprintf(stderr,"*** No work available on server! In other news, really weird things are happening. Check it out. You shouldn't be seeing this.\n");
return 0;
}
else if(!strcmp(data.memory, "ERROR_BADKEY")){
fprintf(stderr,"*** Slave %d does not exist!\n",slavekey);
free(data.memory);
return 0;
}
// Compare to PACKAGE_VERSION
else{
char *tmp;
char *serverversion;
tmp = strtok (data.memory,",,");
if(tmp != NULL){ // make sure work is available
*jobnum = atoi(tmp);
tmp = strtok (NULL, ",");
if(tmp == NULL)
return 0; // no work
*framenum = atoi(tmp);
tmp = strtok (NULL, ",");
if(tmp == NULL)
return 0; // no work
serverversion = tmp;
// @TODO: This should be called every time, not just on fail.
if(strcmp(PACKAGE_VERSION,serverversion)){
fprintf(stderr,"Your distren package is out of date! Please acquire a newer version. (%s local vs %s remote)\n", PACKAGE_VERSION, serverversion);
return 0;
}
if(DEBUG)
fprintf(stderr,"Software versions: %s local vs %s remote\n", PACKAGE_VERSION, serverversion);
free(data.memory);
return 1;
}
else
return 0; // error
}
}
void _web_setrenderpower(int slavekey, char *slavepass, int renderpower){
fprintf(stderr,"Setting render power on server... ");
char *url;
_distren_asprintf(&url,"http://dev.distren.org/slave/act.php?mode=setrenderpower&slavekey=%d&slavepass=%s&renderpower=%d", slavekey, slavepass, renderpower);
struct _web_memorystruct data = _web_getrequest(url);
free(url);
fprintf(stderr,"%s\n", data.memory);
if(data.memory)
free(data.memory);
}
int slaveBenchmark(char *datadir, int *benchmarkTime, int *renderPower){
int ret;
int frameToRender = 1;
char *frame_str;
_distren_asprintf(&frame_str, "%d", frameToRender); // Render frame 1
char *output;
_distren_asprintf(&output, "%s/benchmark#.jpg", datadir); // Where to save benchmark output
char *realOutput;
_distren_asprintf(&realOutput, "%s/benchmark%d.jpg", datadir, frameToRender); // Where to save benchmark output
char *input;
_distren_asprintf(&input, "%s/benchmark.blend", datadir); // Input file
fprintf(stderr,"Downloading benchmark data...\n");
curlget("http://data.distren.org/benchmark.blend", input); // Download to input file location
char *command = "blender"; // @TODO: We currently expect this to be in PATH
char *cmd[] = { command, "-b", input, "-o", output, "-f", frame_str, "-t", "0", (char *)NULL }; // arguments for blender
// fprintf(stderr,"Preparing to execute command: %s -b %s -o %s -f %s\n", command, input, output, frame_str);
fprintf(stderr,"Running benchmark...\n");
long startTime;
long endTime;
time(&startTime);
char buf[20];
struct execio *testrem;
size_t readlen;
ret = execio_open(&testrem, command, cmd);
if(ret)
{
fprintf(stderr, "Error executing blender\n");
return 1;
}
buf[19] = '\0';
while(!execio_read(testrem, buf, 19, &readlen))
{
buf[readlen] = '\0';
fprintf(stderr, "read \"%s\"\n", buf);
}
execio_close(testrem);
time(&endTime);
struct stat buffer;
int ostatus = stat(realOutput, &buffer);
if(ostatus == -1){
ret = 1; // Return error if output wasn't generated
}
else
remove(output);
*benchmarkTime = abs(difftime(startTime,endTime));
float tmp = *benchmarkTime;
tmp = (1/tmp) * 50000;
*renderPower = (int)tmp;
free(realOutput);
free(frame_str);
free(input);
free(output);
return ret;
}
/** *********************************************************************************************************/
/** Why hello ohnobinki! Normaldotcom has graciously prepared this portion of code for you to work on! Yay! */
/** *********************************************************************************************************/
/**
Extracts archive to the specified directory, creating this directory
if necessary (but this directory will not be recursively created).
@param outdir output directory
@param pathtoTar filename of the archive to extract
ohnobinki: please make me work :-\
*/
int unpackJob(char *outdir, char *pathtoTar)
{
int ret;
struct archive *a;
struct archive_entry *ae;
int astatus;
/* ignore return because directory may exist already */
mkdir(outdir, 0700);
ret = chdir(outdir);
if(ret == -1)
{
perror("chdir");
return 1;
}
a = archive_read_new();
ae = archive_entry_new();
archive_read_support_compression_all(a);
archive_read_support_format_raw(a);
astatus = archive_read_open_filename(a, pathtoTar, 8192);
if (astatus != ARCHIVE_OK)
{
fprintf(stderr, "Error opening archive!\n");
return 1;
}
for(astatus = ARCHIVE_OK;
astatus == ARCHIVE_OK
|| astatus == ARCHIVE_WARN;
)
{
astatus = archive_read_next_header2(a, ae);
if(astatus == ARCHIVE_WARN)
fprintf(stderr, "Encountered nonfatal read error somehow!\n");
if(astatus == ARCHIVE_OK
|| astatus == ARCHIVE_WARN)
astatus = archive_read_extract(a, ae,
ARCHIVE_EXTRACT_NO_OVERWRITE
| ARCHIVE_EXTRACT_SECURE_SYMLINKS
| ARCHIVE_EXTRACT_SECURE_NODOTDOT);
}
archive_entry_free(ae);
archive_read_finish(a);
if(astatus != ARCHIVE_EOF)
{
fprintf(stderr, "Error reading archive!\n");
return 1;
}
return 0;
}
/** Logs the user into the server after ensuring that keys exist
ohnobinki: I assume you could use this for remoteio, or just kill it
*/
int login_user(char *username)
{
// @TODO: Put some telnet-style auth code here unless this is obselete
return 1; // success
}
/**
* Sends the server a single request (see protocol.h)
* ohnobinki: This should hopefully work, maybe ;D
*
* @deprecated THIS FUNCTION SHOULD DIE VERY, VERY SOON!
* (and painfully :-p)
*/
int sendSignal(struct remoteio *rem, char signal)
{
remoteio_write(rem, &signal, 1);
/**
if remoteio_write returned 1, the connection
is probably dead or there was a real error
*/
return 1;
}
/**
* Sends the server an extended signal (request + data)
* ohnobinki: I have no clue how you really want to handle this. Please clarify/edit
* normaldotcom: I see more and more how clueless you are, I hope to get to his soon ;-)
*
* @deprecated lol
*/
int sendExtSignal(struct remoteio *rem, char signal, char *data)
{
size_t len;
char *ssignal;
/**
* Just append the data FIXME: We should do this differently
*/
_distren_asprintf(&ssignal, "%c%s", signal, data);
len = strlen(ssignal);
remoteio_write(rem, ssignal, len);
return 0;
}
/* Port of web functions for standard code
Currently, most functions are stubs due to lack
of socket reading code
ohnobinki: I can take care of a fair amount of this, but the remotio reading and writing is where you should really lay down some code.
*/
/** marks frame finished on server */
void finishframe(struct remoteio *rem, int jobnum, int framenum){
char* data;
_distren_asprintf(&data, "%d%d", jobnum, framenum);
sendExtSignal(rem, DISTREN_REQUEST_DONEFRAME, data);
}
/** resets frame to unassigned on server */
void resetframe(struct remoteio *rem, int jobnum, int framenum){
fprintf(stderr,"Resetting frame %d in job %d on server... ",framenum,jobnum);
char* data;
_distren_asprintf(&data, "%d%d", jobnum, framenum);
sendExtSignal(rem, DISTREN_REQUEST_RESETFRAME, data);
}
/** marks frame assigned on server */
void startframe(struct remoteio *rem, int jobnum, int framenum){
if(DEBUG)
fprintf(stderr,"Marking frame %d started on server... ",framenum);
char* data;
_distren_asprintf(&data, "%d%d", jobnum, framenum);
sendExtSignal(rem, DISTREN_REQUEST_RENDERFRAME, data);
}
/**
Greets the server.
We send PACKAGE_STRING as our version ping thing.
*/
int greet_server(struct remoteio *rem)
{
int err;
struct distren_request *req;
err = 0;
fprintf(stderr, "Saying hello to the server ;-)...\n");
err += distren_request_new(&req, strlen(PACKAGE_STRING), DISTREN_REQUEST_VERSION);
err += distren_request_send(rem, req, PACKAGE_STRING);
err += distren_request_free(req);
return err;
}
/** retrieves job from server */
int getwork(struct remoteio *rem, int *jobnum, int *framenum)
{
struct distren_request *req;
char *data;
int len; /*< asprintf() uses int, not size_t */
len = _distren_asprintf(&data, "%d.%d", jobnum, framenum);
//distren_request_new(&req,
sendExtSignal(rem, DISTREN_REQUEST_GETWORK, data);
return 0;
}
/** sets render power of slave on server */
void setrenderpower(struct remoteio *rem, int renderpower){
fprintf(stderr,"Setting render power on server... ");
char* data;
_distren_asprintf(&data, "%d", renderpower);
sendExtSignal(rem,DISTREN_REQUEST_SETRENDERPOWER, data);
}
/** retrieves render power of slave from server */
int getrenderpower(struct remoteio *rem){
sendSignal(rem, DISTREN_REQUEST_GETRENDERPOWER);
return 0;
}
/** compares slave software version with server software version */
int checkslaveversion(struct remoteio *rem){
sendSignal(rem, DISTREN_REQUEST_GETVERSION);
char* serverVersionFromRemotio = "9000";
if(!strcmp(PACKAGE_VERSION, serverVersionFromRemotio)) // compare versions
return 1;
return 0;
}