// remote_server.c -- Written by Curtis Olson // -- for CSci 5502 #include #include #include // for stat() #include #include // bind #include #include #include #include #include #include #define MAXBUF 1024 static double lat = 0.0; static double lon = 0.0; static double dy = 0.0; static int pass = 0; static bool first_time = false; int make_socket (unsigned short int* port) { int sock; struct sockaddr_in name; int length; // Create the socket. sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); exit (EXIT_FAILURE); } // Give the socket a name. name.sin_family = AF_INET; name.sin_addr.s_addr = INADDR_ANY; name.sin_port = 0 /* htons (port) */; name.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) { perror ("bind"); exit (EXIT_FAILURE); } // Find the assigned port number length = sizeof(struct sockaddr_in); if ( getsockname(sock, (struct sockaddr *) &name, &length) ) { perror("Cannot get socket's port number"); } *port = ntohs(name.sin_port); return sock; } // return true if file exists static bool file_exists( const string& file ) { struct stat buf; if ( stat( file.c_str(), &buf ) == 0 ) { return true; } else { return false; } } // check if the specified tile has data defined for it static bool has_data( const string& path, const FGBucket& b ) { string dem_file = path + ".dem" + "/Scenery/" + b.gen_base_path() + "/" + b.gen_index_str() + ".dem"; if ( file_exists( dem_file ) ) { return true; } dem_file += ".gz"; if ( file_exists( dem_file ) ) { return true; } return false; } // initialize the tile counting system void init_tile_count() { // pre-pass pass = 0; // initial bogus value lat = 100; // determine tile height FGBucket tmp1( 0.0, 0.0 ); dy = tmp1.get_height(); } // return the next tile long int get_next_tile( const string& work_base ) { FGBucket b; static double shift_over = 0.0; static double shift_up = 0.0; // cout << "lon = " << lon << " lat = " << lat << endl; if ( lat > 90.0 ) { ++pass; if ( pass == 1 ) { shift_over = 0.0; shift_up = 0.0; } else if ( pass == 2 ) { shift_over = 1.0; shift_up = 0.0; } else if ( pass == 3 ) { shift_over = 0.0; shift_up = 1.0; } else if ( pass == 4 ) { shift_over = 1.0; shift_up = 1.0; } else { return -1; } // reset lat // lat = -89.0 + (shift_up*dy) - (dy*0.5); // lat = 27.0 + (0*dy) + (dy*0.5); if ( first_time ) { first_time = false; lat = 54.0 + (dy*0.5); } else { lat = 15.0 + (shift_up*dy) + (dy*0.5); } // reset lon FGBucket tmp( 0.0, lat ); double dx = tmp.get_width(); // lon = -82 + (shift_over*dx) + (dx*0.5); lon = -180 + (shift_over*dx) + (dx*0.5); cout << "starting pass = " << pass << " with lat = " << lat << " lon = " << lon << endl; } // if ( ! start_lon ) { // lon = -180 + dx * 0.5; // } else { // start_lon = false; // } if ( lon > 180.0 ) { // increment to next row // skip every other row (to avoid two clients working on // adjacent tiles) lat += 2.0 * dy; FGBucket tmp( 0.0, lat ); double dx = tmp.get_width(); lon = -180 + (shift_over*dx) + (dx*0.5); } b = FGBucket( lon, lat ); // increment to next tile FGBucket tmp( 0.0, lat ); double dx = tmp.get_width(); // skip every other column (to avoid two clients working on // adjacent tiles) lon += 2.0 * dx; return b.gen_index(); } // log a pending tile (has been given out as a taks for some client) void log_pending_tile( const string& path, long int tile ) { FGBucket b(tile); string pending_file = path + "/" + b.gen_index_str() + ".pending"; string command = "touch " + pending_file; system( command.c_str() ); } // a tile is finished (removed the .pending file) void log_finished_tile( const string& path, long int tile ) { FGBucket b(tile); string finished_file = path + "/" + b.gen_index_str() + ".pending"; // cout << "unlinking " << finished_file << endl; unlink( finished_file.c_str() ); } // make note of a failed tile void log_failed_tile( const string& path, long int tile ) { FGBucket b(tile); string failed_file = path + "/" + b.gen_index_str() + ".failed"; string command = "touch " + failed_file; system( command.c_str() ); cout << "logged bad tile = " << tile << endl; } // display usage and exit void usage( const string name ) { cout << "Usage: " << name << " " << endl; exit(-1); } int main( int argc, char **argv ) { long int next_tile; int sock, msgsock, length, pid; fd_set ready; short unsigned int port; // quick argument sanity check if ( argc < 3 ) { usage( argv[0] ); } string work_base = argv[1]; string output_base = argv[2]; // initialize tile counter / incrementer init_tile_count(); // create the status directory string status_dir = work_base + ".status"; string command = "mkdir -p " + status_dir; system( command.c_str() ); // setup socket to listen on sock = make_socket( &port ); cout << "socket is connected to port = " << port << endl; // Specify the maximum length of the connection queue listen(sock, 10); for ( ;; ) { FD_ZERO(&ready); FD_SET(sock, &ready); // block until we get some input on sock select(32, &ready, 0, 0, NULL); if ( FD_ISSET(sock, &ready) ) { // printf("%d %d Incomming message --> ", getpid(), pid); // get the next tile to work on next_tile = get_next_tile( work_base ); while ( ! has_data( work_base, FGBucket(next_tile) ) ) { next_tile = get_next_tile( work_base ); } cout << "Bucket = " << FGBucket(next_tile) << " (" << pass << ")" << endl; log_pending_tile( status_dir, next_tile ); // cout << "next tile = " << next_tile << endl;; msgsock = accept(sock, 0, 0); // cout << "msgsock = " << msgsock << endl; // spawn a child pid = fork(); if ( pid < 0 ) { // error perror("Cannot fork child process"); exit(-1); } else if ( pid > 0 ) { // This is the parent close(msgsock); // clean up all of our zombie children int status; while ( (pid = waitpid( WAIT_ANY, &status, WNOHANG )) > 0 ) { // cout << "waitpid(): pid = " << pid // << " status = " << status << endl; } } else { // This is the child // cout << "new process started to handle new connection for " // << next_tile << endl; // Read client's message (which is the status of the // last scenery creation task.) char buf[MAXBUF]; if ( (length = read(msgsock, buf, MAXBUF)) < 0) { perror("Cannot read command"); exit(-1); } buf[length] = '\0'; long int returned_tile = atoi(buf); cout << "client returned = " << returned_tile << endl; // record status if ( returned_tile < 0 ) { // failure log_failed_tile( status_dir, -returned_tile ); log_finished_tile( status_dir, -returned_tile ); } else { // success log_finished_tile( status_dir, returned_tile ); } // reply to the client char message[MAXBUF]; sprintf(message, "%ld", next_tile); length = strlen(message); if ( write(msgsock, message, length) < 0 ) { perror("Cannot write to stream socket"); } close(msgsock); // cout << "process for " << next_tile << " ended" << endl; exit(0); } } } }