268 lines
6.1 KiB
C++
268 lines
6.1 KiB
C++
/* remote_exec.c -- Written by Curtis Olson */
|
|
/* -- for CSci 5502 */
|
|
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <utmp.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h> // atoi()
|
|
#include <string.h> // bcopy()
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include <Bucket/newbucket.hxx>
|
|
|
|
|
|
#define MAXBUF 1024
|
|
#define BUSY_WAIT_TIME 30
|
|
|
|
|
|
string work_base = "";
|
|
string output_base = "";
|
|
|
|
|
|
// check if it is ok to run
|
|
void check_master_switch() {
|
|
string file = work_base + ".status/MASTER_ON";
|
|
|
|
FILE *fp = fopen( file.c_str(), "r" );
|
|
if ( fp == NULL ) {
|
|
cout << "MASTER_ON file not found ... exiting." << endl;
|
|
exit(0);
|
|
}
|
|
|
|
fclose( fp );
|
|
}
|
|
|
|
|
|
// check if the host system is free of interactive users
|
|
int system_free() {
|
|
struct utmp *uptr;
|
|
|
|
setutent();
|
|
|
|
while ( (uptr = getutent()) != NULL ) {
|
|
// cout << "NULL = " << NULL << " uptr = " << uptr << endl;
|
|
// cout << "user = ut_user = " << uptr->ut_user << endl;
|
|
// cout << "user = ut_type = " << uptr->ut_type << endl;
|
|
if (uptr->ut_type == USER_PROCESS) {
|
|
// found someone
|
|
endutent();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
endutent();
|
|
return 1;
|
|
}
|
|
|
|
|
|
int make_socket (char *host, unsigned short int port) {
|
|
int sock;
|
|
struct sockaddr_in name;
|
|
struct hostent *hp;
|
|
|
|
// Create the socket.
|
|
sock = socket (PF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0) {
|
|
perror ("socket");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
// specify address family
|
|
name.sin_family = AF_INET;
|
|
|
|
// get the hosts official name/info
|
|
hp = gethostbyname(host);
|
|
|
|
// Connect this socket to the host and the port specified on the
|
|
// command line
|
|
bcopy(hp->h_addr, &(name.sin_addr.s_addr), hp->h_length);
|
|
name.sin_port = htons(port);
|
|
|
|
if ( connect(sock, (struct sockaddr *) &name,
|
|
sizeof(struct sockaddr_in)) < 0 )
|
|
{
|
|
close(sock);
|
|
perror("Cannot connect to stream socket");
|
|
return -1;
|
|
}
|
|
|
|
return sock;
|
|
}
|
|
|
|
|
|
// connect to the server and get the next task
|
|
long int get_next_task( const string& host, int port, long int last_tile ) {
|
|
long int tile;
|
|
int sock, len;
|
|
fd_set ready;
|
|
char message[256];
|
|
|
|
// loop till we get a socket connection
|
|
while ( (sock = make_socket( host.c_str(), port )) < 0 ) {
|
|
// check if the master switch is on
|
|
check_master_switch();
|
|
|
|
sleep(1);
|
|
}
|
|
|
|
// build a command string from the argv[]'s
|
|
sprintf(message, "%ld", last_tile);
|
|
|
|
// send command and arguments to remote server
|
|
if ( write(sock, message, sizeof(message)) < 0 ) {
|
|
perror("Cannot write to stream socket");
|
|
}
|
|
|
|
// loop until remote program finishes
|
|
cout << "querying server for next task ..." << endl;
|
|
|
|
FD_ZERO(&ready);
|
|
FD_SET(sock, &ready);
|
|
|
|
// block until input from sock
|
|
select(32, &ready, 0, 0, NULL);
|
|
cout << " received reply" << endl;
|
|
|
|
if ( FD_ISSET(sock, &ready) ) {
|
|
/* input coming from socket */
|
|
if ( (len = read(sock, message, 1024)) > 0 ) {
|
|
message[len] = '\0';
|
|
tile = atoi(message);
|
|
cout << " tile to construct = " << tile << endl;
|
|
close(sock);
|
|
return tile;
|
|
} else {
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
|
|
// build the specified tile, return true if contruction completed
|
|
// successfully
|
|
bool construct_tile( const FGBucket& b, const string& result_file ) {
|
|
double angle = 10.0;
|
|
bool still_trying = true;
|
|
|
|
while ( still_trying ) {
|
|
still_trying = false;
|
|
char angle_str[256];
|
|
sprintf(angle_str, "%.0f", angle);
|
|
string command = "fgfs-construct ";
|
|
command += angle_str;
|
|
command += " " + work_base + " " + output_base + " "
|
|
+ b.gen_index_str() + " > " + result_file + " 2>&1";
|
|
cout << command << endl;
|
|
|
|
system( command.c_str() );
|
|
|
|
FILE *fp = fopen( result_file.c_str(), "r" );
|
|
char line[256];
|
|
while ( fgets( line, 256, fp ) != NULL ) {
|
|
string line_str = line;
|
|
line_str = line_str.substr(0, line_str.length() - 1);
|
|
// cout << line_str << endl;
|
|
if ( line_str == "[Finished successfully]" ) {
|
|
fclose(fp);
|
|
return true;
|
|
} else if
|
|
( (line_str.substr(0, 31) == "Error: Ran out of precision at")
|
|
|| (line_str.substr(0, 22) == "Error: Out of memory.")
|
|
|| (line_str.substr(0, 23) == "Error: Too many nodes.") ) {
|
|
if ( angle > 9.0 ) {
|
|
angle = 5.0;
|
|
still_trying = true;
|
|
} else if ( angle > 4.0 ) {
|
|
angle = 0.0;
|
|
still_trying = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
fclose(fp);
|
|
|
|
if ( !still_trying && ( angle > 0.0 ) ) {
|
|
// build died for some reason ... lets try one last time
|
|
// with an interior angle restriction of 0
|
|
angle = 0.0;
|
|
still_trying = true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
main(int argc, char *argv[]) {
|
|
long int tile, last_tile;
|
|
bool rude = false;
|
|
bool result;
|
|
|
|
// Check usage
|
|
if ( argc < 5 ) {
|
|
printf("Usage: %s remote_machine port work_base output_base [ -r ]\n",
|
|
argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
string host = argv[1];
|
|
int port = atoi( argv[2] );
|
|
work_base = argv[3];
|
|
output_base = argv[4];
|
|
|
|
if ( argc == 6 ) {
|
|
string option = argv[5];
|
|
if ( option == "-r" ) {
|
|
cout << "Running in RUDE mode!" << endl;
|
|
rude = true;
|
|
}
|
|
}
|
|
// get hostname and pid
|
|
char hostname[MAXBUF];
|
|
gethostname( hostname, MAXBUF );
|
|
pid_t pid = getpid();
|
|
|
|
char tmp[MAXBUF];
|
|
sprintf(tmp, "result.%s.%d", hostname, pid);
|
|
string result_file = work_base + ".status/" + tmp;
|
|
|
|
last_tile = 0;
|
|
|
|
// check if the master switch is on
|
|
check_master_switch();
|
|
|
|
while ( (tile = get_next_task( host, port, last_tile )) >= 0 ) {
|
|
result = construct_tile( FGBucket(tile), result_file );
|
|
if ( result ) {
|
|
last_tile = tile;
|
|
} else {
|
|
last_tile = -tile;
|
|
}
|
|
|
|
// check if the master switch is on
|
|
check_master_switch();
|
|
|
|
// niceness policy: This whole process should run niced. But
|
|
// additionally, if there is interactive use, we will sleep
|
|
// for 60 seconds between each tile to stagger out the load
|
|
// and impose less of an impact on the machine.
|
|
if ( !system_free() && !rude) {
|
|
cout << "System has interactive use, sleeping for "
|
|
<< BUSY_WAIT_TIME << " seconds..." << endl;
|
|
sleep( BUSY_WAIT_TIME );
|
|
}
|
|
}
|
|
}
|