// function to test threads // This function will run concurrently. void* avatar(void* ptr) { // Initial variables int sockfd = 0; struct sockaddr_in servaddr; avatarInfo a = *((avatarInfo *) ptr); fprintf(a.pLog, "\n\nTHREAD FOR %i", a.avID); ///////////////////////// create socket //Create a socket for the client //If sockfd<0 there was an error in the creation of the socket if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <0) { perror("Problem in creating the socket"); exit(2); } //Creation of the socket memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr= inet_addr(a.ip); servaddr.sin_port = htons(a.MazePort); //convert to big-endian order //Connection of the client to the socket int connected = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); if (connected <0) { perror("Problem in connecting to the server"); exit(3); } fprintf(a.pLog, "Avatar %d connected to socket: %i\n", a.avID, connected); //////////////////////////// send initial message AM_Message *ready = calloc(1, sizeof(AM_Message)); if (!ready) { perror("No memory\n"); exit(4); } ready->type = htonl(AM_AVATAR_READY); ready->avatar_ready.AvatarId = htonl(a.avID); //send ready message to server int sent = send(sockfd, ready, sizeof(AM_Message), 0); fprintf(a.pLog, "Avatar ready message sent: %i, for av %i\n", sent, a.avID); free(ready); sleep(1); ////////////////////////// initialize a move message and a rec message AM_Message *rec_message = calloc(1, sizeof(AM_Message)); if(!rec_message) { perror("\nNo memory"); exit(4); } ////////////////////////////////// listen to server while (1) { memset(rec_message, 0, sizeof(AM_Message)); //printf("\n thread %i, socket %i", a.avID, sockfd); int x = recv(sockfd, rec_message, sizeof(AM_Message), 0); if ( x== 0) { //error: server terminated prematurely //printf("\n server error"); return NULL; } ///////////////////////////////////////// if turnID matches avID, make a move if(ntohl(rec_message->type) == AM_AVATAR_TURN) { pthread_mutex_lock(&turn_lock); // if turn id is my id int move = -1; if(ntohl(rec_message->avatar_turn.TurnId) == a.avID) { // write board to the log fprintf(a.pLog, "\n\nits my turn: %i", a.avID); fprintf(a.pLog, "\nCurrent board:"); XYPos pos; //look through the positions received from the server and add them to the Avatars, if they aren't there, or use them to update the maze based on the last move for(int b = 0; b < a.nAvatars; b++) { pos.x = ntohl(rec_message->avatar_turn.Pos[b].x); pos.y = ntohl(rec_message->avatar_turn.Pos[b].y); fprintf(a.pLog, "\nPosition of avatar %i - x: %i y: %i", b,pos.x, pos.y); //printf("\nCurrent position of avatar %i - x: %i y: %i", b,pos.x, pos.y); //printf("\nAvatar %d: pos.x: %i, pos.y: %i, direction: %d, last_move: %d \n", b, Avatars[b].pos.x, Avatars[b].pos.y, Avatars[b].direction, Avatars[b].last_move); if (Avatars[b].last_move == -1) { //if the avatar doesn't have a position yet Avatars[b].pos = pos; Avatars[b].last_move = M_NULL_MOVE; } else if (Avatars[b].last_move != M_NULL_MOVE) { if ((pos.x == Avatars[b].pos.x) && (pos.y == Avatars[b].pos.y)) { fprintf(a.pLog, "Avatar %d encountered a wall and did not move.", b); AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 1); Avatars[b].last_move = M_NULL_MOVE; } else { fprintf(a.pLog, "Avatar %d moved successfully.", b); switch(Avatars[b].last_move) { case M_NORTH: if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].north_wall != 2) { AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0); } break; case M_SOUTH: if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].south_wall != 2) { AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0); } break; case M_EAST: if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].east_wall != 2) { AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0); } break; case M_WEST: if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].west_wall != 2) { AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0); } break; default: AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0); break; } Avatars[b].pos = pos; Avatars[b].direction = Avatars[b].last_move; Avatars[b].last_move = M_NULL_MOVE; } } } ////////////////graphics//////////////// //initscr(); clear(); raw(); //start_color(); create_border(maze->num_col, maze->num_row); draw_inside(maze); //draw_fakes(maze); int f; for (f = 0; f<a.nAvatars; f++) { draw_avatar(2*Avatars[f].pos.y+1, 2*Avatars[f].pos.x+1); } //unsigned int microseconds; //microseconds = 200; //usleep(microseconds); refresh(); /* Determine the direction of the move for the current Avatar */ /* Avatar 0 has a fixed location - it never moves */ if (a.avID == 0) { if(!final_destination) { final_destination = (XYPos *) calloc(1, sizeof(XYPos)); final_destination->x = Avatars[a.avID].pos.x; final_destination->y = Avatars[a.avID].pos.y; } move = M_NULL_MOVE; } // if(!final_destination){ // for(int i = 0; i < a.nAvatars; i++){ // if (i == a.avID) continue; // //if the Avatar is in the same place as another Avatar, save position as final_destination // if((Avatars[i].pos.x == Avatars[a.avID].pos.x) && (Avatars[i].pos.y == Avatars[a.avID].pos.y)){ // final_destination = (XYPos *) calloc(1, sizeof(XYPos)); // final_destination->x = Avatars[a.avID].pos.x; // final_destination->y = Avatars[a.avID].pos.y; // move = M_NULL_MOVE; // break; // } // } // } /* Determine the direction of the move for Avatars that aren't Avatar 0 */ //if Avatar is at final_destination, it should not move if((final_destination) && (Avatars[a.avID].pos.x == final_destination->x) && (Avatars[a.avID].pos.y == final_destination ->y)) { move = M_NULL_MOVE; } else { //if the Avatar is alone, use the rightHandRule to determine the next move move = rightHandRule(Avatars[a.avID]); } //temporary fix to diagnose the initial -1 rightHandRule return if(move == -1) { ClearFakeWalls(Avatars[a.avID].pos.y, Avatars[a.avID].pos.x); move = rightHandRule(Avatars[a.avID]); move = (move == -1) ? M_NULL_MOVE : move; } Avatars[a.avID].last_move = move; //int move = rand() % 4; // write move to the log fprintf(a.pLog, "\nMove: %i", move); //printf("\nMove: %i", move); //send a move message for the current avatar AM_Message *ready = calloc(1, sizeof(AM_Message)); if (!ready) { perror("No memory\n"); exit(4); } ready->type = htonl(AM_AVATAR_MOVE); ready->avatar_move.AvatarId = htonl(a.avID); ready->avatar_move.Direction =htonl(move); //send ready message to server int sent = send(sockfd, ready, sizeof(AM_Message), 0); fprintf(a.pLog, "\nAvatar move message sent: %i, for av %i", sent, a.avID); free(ready); //sleep(1); } pthread_mutex_unlock(&turn_lock); } // else if the message is success, break else if(ntohl(rec_message->type) == AM_MAZE_SOLVED) { pthread_mutex_lock(&solved_lock); if(!thread_return) { time_t myTime; char buff[100]; thread_return = (char *) calloc(100, sizeof(char)); myTime = time(NULL); strftime(buff, 100, "%a %d %Y, %H:%M", localtime(&myTime)); //printf("%s\n", buff); sprintf(thread_return, "\nMaze Solved on %s!\n", buff); //printf("\nSolved!\n"); //free(rec_message); //free(ptr); } //stop at solution, wait for an input to end graphics //refresh(); //sleep(1); //clear(); //printw("Maze solved!"); //getch(); //clear(); //endwin(); //delwin(stdscr); if(a.avID == 0) { //stop at solution, wait for an input to end graphics refresh(); sleep(1); clear(); printw("Maze solved!"); getch(); clear(); //endwin(); } pthread_mutex_unlock(&solved_lock); break; } else if(ntohl(rec_message->type) == AM_TOO_MANY_MOVES) { pthread_mutex_lock(&too_many_moves_lock); printf("\nToo many moves! You lose.\n"); //fprintf(a.pLog,"\nToo many moves! You lose.\n"); thread_return = "\nToo many moves! You lose.\n"; //free(rec_message); //free(ptr); pthread_mutex_unlock(&too_many_moves_lock); break; } else if(IS_AM_ERROR(ntohl(rec_message->type))) { pthread_mutex_lock(&error_lock); thread_return = (char *) calloc(100, sizeof(char)); printf("\nReceived Error code\n"); sprintf(thread_return, "\nReceived Error code: %u\n", ntohl(rec_message->type)); //free(rec_message); //free(ptr); pthread_mutex_unlock(&error_lock); break; } } //CleanupMaze(); free(rec_message); free(ptr); pthread_exit(thread_return); }
/* move * * @param id - The ID number of the avatar we want to move * @param out_socket - The socket we are writing to * @param fileName - The name of the log file * @param nAvs - The number of avatars * * Return: Returns failure for various errors, success when all the avatars * find each other. * * Psuedocode: * 1. Initalize variables by setting up positions, directions, moves, etc. * 2. Enter move loop - keep moving until all the avatars find each other * 3. Error checking within the loop for connection or errors from the server * 4. The avatars have left hand move, the masters have right hand move, if a * master finds an avatar, then the avatar will move with the master and also * use right hand rule. * 5. Free memory * 6. Error checking */ int move(int id, int out_socket, char *fileName, int nAvs, int height, int width) { int res; // Check connection AM_Message move; // The move mesasge you get from the server AM_Message next_move; // The move message you send to the server int move_num; // The number of moves we've tried int direction; // The direction we are facing int moving_right; // 1: avatar using right hand rule int seen_avatar; // 0: haven't found XYPos *curr; // current position XYPos *prev; // previous position XYPos *M_curr; // current master position XYPos *M_prev; // previous master position int moves_attempted; // number of moves tried in one position int M_moves_attempted; // number of masters tried by master int M_direction; // direction master is facing int total_moves; // tracks how many moves we made // ID 0 is always master if(id == 0) { moving_right = 1; // master is always moving right } // set up current and previous positions total_moves = 0; move_num = 0; direction = 0; moving_right = 0; seen_avatar = 0; curr = calloc(1, sizeof(XYPos)); prev = calloc(1, sizeof(XYPos)); prev->x = -1; prev->y = -1; curr->x = -1; curr->y = -1; moves_attempted = 0; M_prev = calloc(1, sizeof(XYPos)); M_prev->x = 0; M_prev->y = 0; M_moves_attempted = 0; M_direction = 0; for(;;) { memset(&next_move, 0, sizeof(next_move)); res = recv(out_socket, &move, sizeof(move), 0); // check connection if(res == 0) { break; } // check message for error if (IS_AM_ERROR(ntohl(move.type))) { break; } // if success, we solved it! if(ntohl(move.type) == AM_MAZE_SOLVED) { break; } // if we met the master, start moving right if(ntohl(curr->x) == ntohl(move.avatar_turn.Pos[0].x) && ntohl(curr->y) == ntohl(move.avatar_turn.Pos[0].y)) { moving_right = 1; } if(ntohl(move.avatar_turn.TurnId) == 0) { // tracking the master, on the master's turn. M_curr = &(move.avatar_turn.Pos[0]); if(ntohl(M_prev->x) != ntohl(M_curr->x) || ntohl(M_prev->y) != ntohl(M_curr->y)) { M_moves_attempted = 0; M_direction = getDirectionChange(M_prev, M_curr); } else { M_moves_attempted++; } M_prev->x = M_curr->x; M_prev->y = M_curr->y; } // if it's not our turn, don't worry. if(ntohl(move.avatar_turn.TurnId) != id) { continue; } // get the current location curr = &(move.avatar_turn.Pos[id]); // set up our next move next_move.type = htonl(AM_AVATAR_MOVE); next_move.avatar_move.AvatarId = htonl(id); // check if we moved, and if so, reset direction if(ntohl(prev->x) != ntohl(curr->x) || ntohl(prev->y) != ntohl(curr->y)) { moves_attempted = 0; direction = getDirectionChange(prev, curr); } else { moves_attempted++; } // get next move for left hand move_num = getNextMoveL(direction, moves_attempted); // update our previous pointer prev->x = curr->x; prev->y = curr->y; // if we are moving right, overwrite the left hand with right hand if(moving_right) { move_num = getNextMoveR(M_direction, M_moves_attempted); } // testing, print information about yourself //printf("%i, %i, %i, %i\n", id, direction, ntohl(curr->x), ntohl(curr->y)); //fflush(stdout); if(!seen_avatar && moving_right) { seen_avatar = 1; move_num = 8; } // set direction and move total_moves++; next_move.avatar_move.Direction = htonl(move_num); send(out_socket, &next_move, sizeof(next_move), 0); } // free our dynamically allocated memory free(M_prev); free(prev); if(res == 0) { fprintf(stderr, "Connection timed out!"); return EXIT_FAILURE; } // determine why we exited the for loop. switch(ntohl(move.type)) { case AM_MAZE_SOLVED: if(id == 0) { printSuccess(fileName, move, total_moves, nAvs); } return EXIT_SUCCESS; case AM_TOO_MANY_MOVES: fprintf(stderr, "Max moves exceeded."); return EXIT_FAILURE; case AM_SERVER_DISK_QUOTA: fprintf(stderr, "Server disk quota reached."); return EXIT_FAILURE; case AM_SERVER_OUT_OF_MEM: fprintf(stderr, "Server out of memory."); return EXIT_FAILURE; default: fprintf(stderr, "Unknown error."); return EXIT_FAILURE; } }
int main(int argc, char *argv[]) { VERBOSE = 0; GRAPHICS = 0; validate(argc, argv); int avatarID = atoi(argv[1]); FILE *logFile; logFile = fopen(argv[6], "a+"); char *IP = (char*)calloc(strlen(argv[4]) + 1, sizeof(char)); MALLOC_CHECK(stderr, IP); strncpy(IP, argv[4], strlen(argv[4])); myAvatar *avatar; int slobAvatar = 0; // the one who doesn't move in maze solver int mazePort = atoi(argv[5]); int width = atoi(argv[7]); int height = atoi(argv[8]); int shmID = atoi(argv[9]); char *maze = (char*) shmat(shmID, 0, 0); if (maze == (void *)-1 && errno == EACCES) { fprintf(stderr, "shmat failed EACCES\n"); exit(1); } if (maze == (void *)-1 && errno == EINVAL) { fprintf(stderr, "shmat failed EINVAL\n"); exit(1); } if (maze == (void *)-1 && errno == ENOMEM) { fprintf(stderr, "shmat failed ENOMEM\n"); exit(1); } // Server connection stuff int sockfd; struct sockaddr_in servaddr; // Create and check status of server sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { free(IP); fprintf(stderr, "Could not create socket.\n"); return 0; // false } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(IP); servaddr.sin_port = htons(mazePort); // Connect to server if (connect(sockfd, (struct sockaddr*) &servaddr, \ sizeof(servaddr)) < 0) { fprintf(stderr, "Unable to connect to server. Exiting.\n"); free(IP); return 0; // false } // Fire off initial AM_AVATAR_READY AM_Message *sendmsg = (AM_Message*)calloc(1, sizeof(AM_Message)); MALLOC_CHECK(stderr, sendmsg); sendmsg->type = htonl(AM_AVATAR_READY); sendmsg->avatar_ready.AvatarId = htonl(avatarID); // pack information // Send ready message to server containing avatar ID send(sockfd, sendmsg, sizeof(AM_Message), 0); // Make a message to get back from server AM_Message *receivemsg = (AM_Message*)calloc(1, sizeof(AM_Message)); MALLOC_CHECK(stderr, receivemsg); int firstMove = 1; int turn = -1; // Start while loop that checks all server messages and updates // the avatar's position until either error message or AM_SOLVED received for ( ;; ) { // Zero out the message pointers so they can be re-used memset(receivemsg, 0, sizeof(AM_Message)); memset(sendmsg, 0, sizeof(AM_Message)); // Receive the message and make sure it's not empty if (recv(sockfd, receivemsg, sizeof(AM_Message), 0) == 0) { fprintf(stderr, "Server terminated early.\n"); OUTPUT(logFile, "Empty message type. Exiting...\n"); break; } // Check for server error if (IS_AM_ERROR(receivemsg->type)) { fprintf(stderr, "Error mask detected error.\n"); } // Following if statements will check for all possible server errors // In all cases, print to stderr, log the error to output file // and break to free resources and return if (ntohl(receivemsg->type) == AM_UNKNOWN_MSG_TYPE) { fprintf(stderr, "AM_UNKNOWN_MSG_TYPE\n"); OUTPUT(logFile, "Unknown message type. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_NO_SUCH_AVATAR) { fprintf(stderr, "AM_NO_SUCH_AVATAR\n"); OUTPUT(logFile, "No such avatar error. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_UNEXPECTED_MSG_TYPE) { fprintf(stderr, "AM_UNEXPECTED_MSG_TYPE\n"); OUTPUT(logFile, "Unexpected message type. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_AVATAR_OUT_OF_TURN) { fprintf(stderr, "AM_AVATAR_OUT_OF_TURN\n"); OUTPUT(logFile, "Avatar out of turns message type. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_TOO_MANY_MOVES) { fprintf(stderr, "AM_AVATAR_TOO_MANY_MOVES\n"); OUTPUT(logFile, "Avatar too many moves message type. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_SERVER_TIMEOUT) { fprintf(stderr, "AM_SERVER_TIMEOUT\n"); OUTPUT(logFile, "Server timeout message type. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_SERVER_DISK_QUOTA) { fprintf(stderr, "AM_SERVER_DISK_QUOTA\n"); OUTPUT(logFile, "Server disk quota message type. Exiting...\n"); break; } if (ntohl(receivemsg->type) == AM_SERVER_OUT_OF_MEM) { fprintf(stderr, "AM_SERVER_OUT_OF_MEM\n"); OUTPUT(logFile, "Server out of mem message type. Exiting...\n"); break; } // Huzzah! Output success to log file. if (ntohl(receivemsg->type) == AM_MAZE_SOLVED) { // Only output this stuff once. if (avatarID == slobAvatar) { fprintf(stdout, "SOLVED!!!\n"); fprintf(logFile, "Maze solved with %d avatars on %d" " difficulty in %d moves. The Hash key is: %d.\n", ntohl(receivemsg->maze_solved.nAvatars),\ ntohl(receivemsg->maze_solved.Difficulty), ntohl(receivemsg->maze_solved.\ nMoves), ntohl(receivemsg->maze_solved.Hash)); } break; } if (ntohl(receivemsg->type) == AM_AVATAR_TURN) { // Only look at messages from the relevant reply messages if (ntohl(receivemsg->avatar_turn.TurnId) == avatarID) { if (firstMove) { // Initialize the avatar. avatar = (myAvatar*)calloc(1, sizeof(myAvatar)); MALLOC_CHECK(stderr, avatar); avatar->fd = avatarID; avatar->lastMoveDir = M_NORTH; // everyone goes north initially // Initially, avatar's previous position and current position // are the same. Retrieve these from server. avatar->pos.x = ntohl(receivemsg->avatar_turn.Pos[avatarID].x); avatar->pos.y = ntohl(receivemsg->avatar_turn.Pos[avatarID].y); // No previous initially. // Send the avatar north. sendmsg->type = htonl(AM_AVATAR_MOVE); sendmsg->avatar_move.AvatarId = htonl(avatarID); sendmsg->avatar_move.Direction = htonl(M_NORTH); if (VERBOSE) { fprintf(stdout, "Avatar %d: Initial pos (%d, %d) moved NORTH\n", avatarID,\ avatar->pos.x, avatar->pos.y); } // Send ready message to server containing avatar ID send(sockfd, sendmsg, sizeof(AM_Message), 0); turn = 1; firstMove = 0; if (GRAPHICS) { //initialize graphics AddAvatar(maze,avatar,width); PrintMaze(maze, width, height); } continue; } else { // not first move // If it's the avatar standing still, arbitrarily picked as // avatar with ID = 0, then always stand still. if (avatarID == slobAvatar) { sendmsg->type = htonl(AM_AVATAR_MOVE); sendmsg->avatar_move.AvatarId = htonl(avatarID); // should be 0 sendmsg->avatar_move.Direction = htonl(M_NULL_MOVE); send(sockfd, sendmsg, sizeof(AM_Message), 0); turn++; continue; } // Make the previous the current position avatar->prev.x = avatar->pos.x; avatar->prev.y = avatar->pos.y; turn++; // Make current position the new one from the server int newX = ntohl(receivemsg->avatar_turn.Pos[avatarID].x); int newY = ntohl(receivemsg->avatar_turn.Pos[avatarID].y); avatar->pos.x = newX; avatar->pos.y = newY; // See if the slob and the current avatar are on the same spot. int deltaX = avatar->pos.x - ntohl(receivemsg->avatar_turn.Pos[slobAvatar].x); int deltaY = avatar->pos.y - ntohl(receivemsg->avatar_turn.Pos[slobAvatar].y); int checkSameCell = 0; if ((deltaY == 0) && (deltaX == 0)) { checkSameCell = 1; } // If avatar is on same spot as slob, slob has been found. // Don't move the other avatar. if (checkSameCell) { sendmsg->type = htonl(AM_AVATAR_MOVE); sendmsg->avatar_move.AvatarId = htonl(avatarID); sendmsg->avatar_move.Direction = htonl(M_NULL_MOVE); send(sockfd, sendmsg, sizeof(AM_Message), 0); turn++; continue; } // Avatar is not slob and has not yet met slob. else { // See if the last move was productive int lastMove = checkLastMove(avatar); avatar->lastMoveSuccess = lastMove; //update graphics based on last move if(!lastMove){ AddWall(maze,avatar,width); } else{ //DelAvatar(maze,avatar,width);//comment out to see history if(!AddMark(maze,avatar,width))//blocks square if test passes AddAvatar(maze,avatar,width); } if (GRAPHICS) { PrintMaze(maze,width,height); } //prep next move int nextMove = getMove(avatar); avatar->lastMoveDir = nextMove; while(isKnown(maze, avatar, width)){ avatar->lastMoveSuccess = false; nextMove = getMove(avatar); avatar->lastMoveDir = nextMove; } turn++; sendmsg->type = htonl(AM_AVATAR_MOVE); sendmsg->avatar_move.AvatarId = htonl(avatarID); sendmsg->avatar_move.Direction = htonl(nextMove); if (VERBOSE) { fprintf(stdout, "======== Turn %d ========\n", turn); if (nextMove == M_NORTH) { fprintf(stdout, "Avatar %d: Moved NORTH from (%d, %d).\n", avatarID,\ avatar->pos.x, avatar->pos.y); } if (nextMove == M_SOUTH) { fprintf(stdout, "Avatar %d: Moved SOUTH from (%d, %d).\n", avatarID,\ avatar->pos.x, avatar->pos.y); } if (nextMove == M_WEST) { fprintf(stdout, "Avatar %d: Moved WEST from (%d, %d).\n", avatarID,\ avatar->pos.x, avatar->pos.y); } if (nextMove == M_EAST) { fprintf(stdout, "Avatar %d: Moved EAST from (%d, %d).\n", avatarID,\ avatar->pos.x, avatar->pos.y); } fprintf(stdout, "\n"); } send(sockfd, sendmsg, sizeof(AM_Message), 0); } } } } } shmctl(shmID, IPC_RMID, NULL); free(sendmsg); free(receivemsg); free(IP); free(avatar); fclose(logFile); close(sockfd); return 1; }
void* AvatarFun(void* arg) { int sockfd; struct sockaddr_in servaddr; AvatarData* data = (AvatarData*) arg; struct timespec tim, tim2; tim.tv_sec = 0; tim.tv_nsec = 50000; // Create a socket for the client // If sockfd<0 there was an error in the creation of the socket if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror("Problem in creating the socket"); exit(2); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(data->IPadd); servaddr.sin_port = htons(data->MazePort); //convert to big-endian order // Connection of the client to the socket if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("Problem in connecting to the server"); exit(4); } // Send AM_AVATAR_READY msg for each avatar struct AM_Message readymsg, recvmsg; readymsg.type = htonl(AM_AVATAR_READY); readymsg.avatar_ready.AvatarID = htonl(data->AvatarID); send(sockfd, &readymsg, sizeof(readymsg), 0); int old_dir = -1, new_dir = -1; int blocked = 0; XYPos* old_pos = (XYPos*) calloc(1, sizeof(XYPos)); XYPos* new_pos = (XYPos*) calloc(1, sizeof(XYPos)); int exitvalue = 6; // receive the first message from the server recv(sockfd, &recvmsg, sizeof(recvmsg), 0); old_pos->x = -1; old_pos->y = -1; new_pos->x = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].x); new_pos->y = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].y); int turnId = ntohl(recvmsg.avatar_turn.TurnId); // set goal vertex if (data->AvatarID == 0) { goalx = new_pos->x; goaly = new_pos->y; } while (1) { // if it's this avatar's turn if (data->AvatarID == turnId) { if(pthread_mutex_trylock(&avatar_mutex) != 0) nanosleep(&tim , &tim2); if (new_pos->x == goalx && new_pos->y == goaly) { new_dir = M_NULL_MOVE; } else { // figure out how to move new_dir = whereToTurn(old_dir, blocked, new_pos, data->MazeMap->map); } // ask to move int ask = askToMoveAvatar(sockfd, new_dir, data->AvatarID); if (ask == 0) { cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(9); } numMoves++; } // Receive response from Server if (recv(sockfd, &recvmsg, sizeof(recvmsg), 0) < 0) { fprintf(stderr, "error receiving message from server.\n"); exit (14); } if (ntohl(recvmsg.type) == AM_MAZE_SOLVED) { // solved the maze for (int i = 0; i < data->nAvatars; i++) { new_pos->x = goalx; new_pos->y = goaly; updateLocations(data->locations, new_pos, turnId); } if (data->AvatarID == 0) { printMapToConsole(data->MazeMap->width, data->MazeMap->height, data->locations, data->nAvatars, numMoves); printf("Maze Solved!\n"); char *solved = (char*) calloc(100, sizeof(char)); sprintf(solved, "Maze solved for %d avatars and %d " "difficulty in %d moves.\n", ntohl(recvmsg.maze_solved.nAvatars), ntohl(recvmsg.maze_solved.Difficulty), ntohl(recvmsg.maze_solved.nMoves)); int writesolved = writeToLog(data->filename, solved); free(solved); if (writesolved == 0) { cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(10); } char *success = (char*) calloc(50, sizeof(char)); sprintf(success, "Success code: %u\n", ntohl(recvmsg.maze_solved.Hash)); int writesuccess = writeToLog(data->filename, success); free(success); if (writesuccess == 0) { cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(11); } } cleanup(old_pos, new_pos, data, sockfd, exitvalue); return NULL; } else if (ntohl(recvmsg.type) == AM_TOO_MANY_MOVES) { // too many moves if (data->AvatarID == 0) { printf("Ran out of moves :(\n"); int writemoves = writeToLog(data->filename, "Ran out of moves\n"); if (writemoves == 0) { cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(12); } } cleanup(old_pos, new_pos, data, sockfd, exitvalue); return NULL; } else if (ntohl(recvmsg.type) == AM_AVATAR_TURN) { // regular turn old_pos->x = new_pos->x; old_pos->y = new_pos->y; new_pos->x = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].x); new_pos->y = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].y); updateLocations(data->locations, new_pos, data->AvatarID); } else if (!IS_AM_ERROR(ntohl(recvmsg.type))) { // error message if (data->AvatarID == 0) { fprintf(stderr, "Error: message type.\n"); int writeerror = writeToLog(data->filename, "Error reading message type.\n"); if (writeerror == 0) { cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(13); } } cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(6); } else { printf("this is the recvmsg type: %u\n", ntohl(recvmsg.type)); fprintf(stderr, "Undefined error receiving turn message from server.\n"); cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(6); } if (data->AvatarID == turnId) { int check = updateLog(data->filename, data->AvatarID, new_dir, data->nAvatars, data->locations); if (check == 0) { cleanup(old_pos, new_pos, data, sockfd, exitvalue); exit(8); } // update blocked if (new_pos->x == old_pos->x && new_pos->y == old_pos->y) { blocked = 1; } else { blocked = 0; } data->MazeMap = updateMazeMap(data->MazeMap, old_pos, new_pos, new_dir); if (!(data->MazeMap)) { fprintf(stderr, "Error updating the MazeMap.\n"); exit(7); } printMapToConsole(data->MazeMap->width, data->MazeMap->height, data->locations, data->nAvatars, numMoves); } turnId = ntohl(recvmsg.avatar_turn.TurnId); old_dir = new_dir; pthread_mutex_unlock(&avatar_mutex); } }
/* * avatarMake * * Function: Initialize each avatar and send move messages during their respective turns * * Input: @id - current avatar's ID * */ void *avatarMake (void *id){ int avatarID = (intptr_t)id; // Creating ready message AM_Message am_ready; memset(&am_ready, 0, sizeof(AM_Message)); am_ready.type = htonl(AM_AVATAR_READY); am_ready.avatar_ready.AvatarId = htonl(avatarID); // Creting socket for the avatar int sockId; if ((sockId = socket(AF_INET, SOCK_STREAM, 0)) < 0){ fprintf(stderr, "ERROR IN SOCKET 2"); fprintf(logFile, "ERROR IN SOCKET"); exit(1); } // Connect the client to socket if (connect(sockId, (struct sockaddr *) &maze_address, sizeof(maze_address)) < 0) { fprintf(stderr, "There was a problem connecting client to the socket 2\n"); fprintf(logFile, "There was a problem connecting client to the socket\n"); exit(1); } // Sending message to our server send(sockId,&am_ready,sizeof(am_ready),0); // Receiving and checking reply from server AM_Message receiveMessage; if (recv(sockId,&receiveMessage,sizeof(receiveMessage),0) == 0){ fprintf(stderr,"The server connection was closed 2\n"); fprintf(logFile,"The server connection was closed\n"); exit(1); } if (ntohl(receiveMessage.type) != AM_AVATAR_TURN){ fprintf(stderr,"Initialization failed 2"); fprintf(logFile,"Initialization failed"); exit(1); } // initialize avatar position pthread_mutex_lock(&init_mutex); avatarGroup[avatarID]->currpos->x = ntohl(receiveMessage.avatar_turn.Pos[avatarID].x); avatarGroup[avatarID]->currpos->y = ntohl(receiveMessage.avatar_turn.Pos[avatarID].y); avatarGroup[avatarID]->prevpos->x = avatarGroup[avatarID]->currpos->x; avatarGroup[avatarID]->prevpos->y = avatarGroup[avatarID]->currpos->y; pthread_mutex_unlock(&init_mutex); avFlag++; while(avFlag != avatarNum){ sleep(1); } int move; while(1){ // enters only on the avatar's specified turn if(ntohl(receiveMessage.avatar_turn.TurnId) == avatarID){ pthread_mutex_lock(&turn_mutex); totalMoves++; fprintf(logFile,"\nMOVE #%d\n",totalMoves); fprintf(logFile,"avatar %d is at position (%d,%d)\n",avatarID,avatarGroup[avatarID]->currpos->x,avatarGroup[avatarID]->currpos->y); turnID = avatarID; setTarget(); // figure out what move to make (FIX NESW) move = nextMove(avatarID, avatarGroup[avatarID]->currpos,avatarGroup[avatarID]->prevpos); if (move == -1){ fprintf(stderr, "Maze node null\n"); fprintf(logFile,"Maze node null\n"); exit(1); } // print to file saying what move the avatar is trying to make fprintf(logFile,"Avatar %d is trying to move %s \n",avatarID,translateDirection(move)); // Create move message AM_Message moveMessage; memset(&moveMessage,0,sizeof(AM_Message)); moveMessage.type = htonl(AM_AVATAR_MOVE); moveMessage.avatar_move.Direction = htonl(move); moveMessage.avatar_move.AvatarId = htonl(avatarID); // Sending move message send(sockId,&moveMessage,sizeof(moveMessage),0); //receive and check message while (ntohl(receiveMessage.avatar_turn.TurnId) == avatarID){ if (recv(sockId,&receiveMessage,sizeof(receiveMessage),0) == 0){ fprintf(stderr,"The server connection was closed 3\n"); fprintf(logFile,"The server connection was closed\n"); exit(1); } if( totalMoves == (AM_MAX_MOVES*(difficulty+1)*avatarNum)){ if(terminate == 0){ fprintf(stderr,"Exceeded the max number of moves\n"); fprintf(logFile,"\nEXCEEDED THE MAX NUMBER OF MOVES"); terminate = 1; } exit (1); } if(ntohl(receiveMessage.type) == AM_MAZE_SOLVED){ DrawMaze(height, width, avatarGroup, maze, avatarID, avatarNum, filename); if (terminate == 0 ){ printf("solved"); fprintf(logFile,"\nMAZE SOLVED!"); terminate = 1; } return 0; } if(IS_AM_ERROR(ntohl(receiveMessage.type))){ fprintf(stderr,"Error from the server 3"); fprintf(logFile,"Error from the server"); exit(1); } } if (move != M_NULL_MOVE){ XYPos *tmp = (XYPos *)malloc(sizeof(XYPos)); tmp->x = ntohl(receiveMessage.avatar_turn.Pos[avatarID].x); tmp->y = ntohl(receiveMessage.avatar_turn.Pos[avatarID].y); if (avatarMoved(avatarID, avatarGroup[avatarID]->currpos, tmp, move) == 1){ // if the avatar moved, update its previous and current positions avatarGroup[avatarID]->prevpos->x = avatarGroup[avatarID]->currpos->x; avatarGroup[avatarID]->prevpos->y = avatarGroup[avatarID]->currpos->y; avatarGroup[avatarID]->currpos->x = tmp->x; avatarGroup[avatarID]->currpos->y = tmp->y; } free(tmp); } // update the maze graphic DrawMaze(height, width, avatarGroup, maze, avatarID, avatarNum, filename); pthread_mutex_unlock(&turn_mutex); } // when it's not an avatar's turn, it continues to check server messages else{ //receive and check message if (recv(sockId,&receiveMessage,sizeof(receiveMessage),0) == 0){ if(terminate == 0 ){ fprintf(stderr,"The server connection was closed 3\n"); fprintf(logFile,"The server connection was closed\n"); terminate = 1; } exit(1); } if( totalMoves == (AM_MAX_MOVES*(difficulty+1)*avatarNum) ){ if(terminate == 0){ fprintf(stderr,"Exceeded the max number of moves\n"); fprintf(logFile,"\nEXCEEDED MAX NUMBER OF MOVES"); terminate = 1; } exit (1); } if(ntohl(receiveMessage.type) == AM_MAZE_SOLVED){ DrawMaze(height, width, avatarGroup, maze, avatarID, avatarNum, filename); if(terminate == 0){ printf("solved"); fprintf(logFile,"\nMAZE SOLVED!"); terminate = 1; } return 0; } if(IS_AM_ERROR(ntohl(receiveMessage.type))){ if(terminate == 0){ fprintf(stderr,"Error from the server 3"); fprintf(logFile,"Error from the server"); terminate = 1; } exit(1); } } } return 0; }
int main(int argc, char **argv){ //General parameter checks if (argc != 4){ fprintf(stdout, "Error: Incorrect number of paramters."); exit(1); } int numAvatars= atoi(argv[1]); if ((numAvatars < 1) || (numAvatars > 10)){ fprintf(stdout, "Error: Number of avatars must be from 1 to 10."); exit(1); } int difficulty= atoi(argv[2]); if ((difficulty < 0) || (difficulty > 9)){ fprintf(stdout, "Error: Difficulty must be from 0 to 9."); exit(1); } char *hostName= argv[3]; if (strcmp(hostName, "flume.cs.dartmouth.edu") != 0){ fprintf(stdout, "Error: hostname must be flume.cs.dartmouth.edu"); exit(1); } //Get the ip address of the hostname char ip[200]; //ip definitely won't be longer than 200 characters getIP(hostName, ip); fprintf(stdout, "Host %s resolved to %s\n", hostName, ip); //Start the log file now char *userName = getlogin(); char *fileLog = (char*)malloc(sizeof(char)*(strlen("Amazing_")+strlen(userName)+ \ strlen(argv[1])+strlen(argv[2])+strlen("__.log")+1)); if (fileLog == NULL){ fprintf(stdout, "Error: Memory allocation error."); exit(1); } sprintf(fileLog, "Amazing_%s_%s_%s.log", userName, argv[1], argv[2]); /* Adapted from echoClient.c example */ int sockfd; struct sockaddr_in servaddr; AM_Message *send_signal = (struct AM_Message*)malloc(sizeof(AM_Message)); AM_Message *receive_signal = (struct AM_Message*)malloc(sizeof(AM_Message)); //Create a socket for the client //If sockfd<0 there was an error in the creation of the socket if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0) { perror("Problem in creating the socket"); exit(2); } //Creation of the socket memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr= inet_addr(ip); // flume.cs.dartmouth.edu IP servaddr.sin_port = htons(atoi(AM_SERVER_PORT)); //convert to big-endian order //Connection of the client to the socket if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) { perror("Problem in connecting to the server"); exit(3); } printf("Connection Succesful.\n"); // If we got here, connection didnt fail // Create AM_INIT signal send_signal->type = htonl(AM_INIT); send_signal->init.nAvatars = htonl(numAvatars); send_signal->init.Difficulty = htonl(difficulty); // Send initial signal to server send(sockfd, send_signal, sizeof(*send_signal), 0); // Receive from server if (recv(sockfd, receive_signal, sizeof(*receive_signal),0) == 0){ //error: server terminated prematurely perror("The server terminated prematurely"); exit(4); } if (IS_AM_ERROR(ntohl(receive_signal->type))){ printf("Error on return signal.\n"); exit(1); } printf("REC TYPE:%d\n",ntohl(receive_signal->type)); if(receive_signal->type == AM_INIT_FAILED){ printf("Received AM_INIT_OK\n\n"); } int mazePort = ntohl(receive_signal->init_ok.MazePort); int mazeWidth = ntohl(receive_signal->init_ok.MazeWidth); int mazeHeight = ntohl(receive_signal->init_ok.MazeHeight); printf("INIT_OK SIGNAL RECEIVED:\n"); printf("MazePort: %d\n", mazePort); printf("MazeWidth: %d\n", mazeWidth); printf("MazeHeight: %d\n", mazeHeight); //Start the avatar program with appropriate arguments //Need to add memory allocation failure errors for the following //and free as appropriate int numWidthInts= snprintf(NULL, 0, "%d", mazeWidth); char *widthString = (char*)malloc(numWidthInts+1); sprintf(widthString, "%d", mazeWidth); int numHeightInts= snprintf(NULL, 0, "%d", mazeHeight); char *heightString = (char*)malloc(numHeightInts+1); sprintf(heightString, "%d", mazeHeight); int numInts= snprintf(NULL, 0, "%d", mazePort); char *mazePortString= (char*)malloc(numInts+1); sprintf(mazePortString, "%d", mazePort); execl("./avatar", "./avatar", argv[1], argv[2], ip, mazePortString, fileLog, widthString, heightString, NULL); perror("execl() failure!\n\n"); //May have to move the location of this stuff shutdown(sockfd, 2); free(send_signal); free(receive_signal); free(widthString); free(heightString); free(mazePortString); free(fileLog); exit(0); }
/*====================================================================*/ int agent(int curAvatar, int nAvatars, int xlen, int ylen, char *hostname, key_t k, uint32_t port, int algo) { int shmid; int s; char *outstring; WorldMap *globalmap; AM_Message outMessage; AM_Message inMessage; XYPos pos[AM_MAX_AVATAR]; Direction movdir; int iterations = 0; int i; bool firstMove = true; int fd_log; LogMessage lmsg; float pknown; /* makes named pipe to logger */ if (mkfifo(FIFO_NAME, 0666) == -1) { if (errno != EEXIST) { perror("mkfifo"); return -1; } } fd_log = open(FIFO_NAME, O_WRONLY); if (fd_log == -1) { fprintf(stderr, "Failed to connect to log process\n"); perror("open"); return -1; } LOG(lmsg, fd_log, LVL_VERB, "%d connected to server", curAvatar); /* start with nonsense values to pos so we never assume we have a wall in front * of us on the first turn */ for (i = 0; i < nAvatars; i++) { pos[i].x = AM_MAX_GRID_SIZE + 1; pos[i].y = AM_MAX_GRID_SIZE + 1; } /* start facing North */ movdir = N; /* get shared memory */ if ((shmid = shmget(k, sizeof(WorldMap), 0644 | IPC_CREAT)) == -1) { perror("shmget"); LOG(lmsg, fd_log, LVL_FATAL, "Could not get id for shared memory: %s",\ strerror(errno)); } /* attach to the segment and get a pointer to it */ globalmap = shmat(shmid, (void *)0, 0); if (globalmap == (WorldMap *)(-1)) { perror("shmat"); shmctl(shmid, IPC_RMID, NULL); fprintf(stderr, "Could not attach to shared memory\n"); return (-1); } /* Avatar 0 initialize global map */ if (curAvatar == 0) { LOG(lmsg, fd_log, LVL_VERB, "initializing global worldmap%s", ""); globalmap->xlen = xlen; globalmap->ylen = ylen; initWorldMap(globalmap); } else { sleep(1); /* allow time for the log file to be initialized */ } /* connect to the server and send avatar ready message */ s = connectToServer(hostname, port); if (s < 0) { LOG(lmsg, fd_log, LVL_INFO, "Avatar %d Could not connect to server", curAvatar+1); shmctl(shmid, IPC_RMID, NULL); return -1; } memset(&outMessage, 0, sizeof(outMessage)); outMessage.type = AM_AVATAR_READY; outMessage.avatar_ready.AvatarId = curAvatar; sendAMMessage(s, outMessage); /* main agent loop */ do { /* Get the next message from the server */ inMessage = receiveAMMessage(s); if (IS_AM_ERROR(inMessage.type)) { if (inMessage.type & AM_AVATAR_OUT_OF_TURN) continue; printAMError(fd_log, inMessage.type); shmctl(shmid, IPC_RMID, NULL); return -1; } /* if the message is not the right type */ if (!(inMessage.type & AM_AVATAR_TURN)) continue; /* if it is our turn */ if (inMessage.avatar_turn.TurnId == curAvatar) { pthread_mutex_lock(&globalmap->mapMutex); /* Get our next move */ movdir = getNextMove(*globalmap, inMessage.avatar_turn.Pos, movdir, pos[curAvatar], nAvatars, curAvatar, algo); /* initialize outMessage */ memset(&outMessage, 0, sizeof(outMessage)); outMessage.type = AM_AVATAR_MOVE; outMessage.avatar_move.AvatarId = curAvatar; outMessage.avatar_move.Direction = dirToMoveDir(movdir); sendAMMessage(s, outMessage); iterations++; /* Avatar 0 counts iterations */ if (curAvatar == 0) { fprintf(stdout, "\033[2J\033[1;1H"); printf("iteration %d\n", iterations); outstring = serializeWorldMap(*globalmap, nAvatars, inMessage.avatar_turn.Pos); /* Print to stdout */ fprintf(stdout, "%s\n", outstring); free(outstring); if (algo == 2) { if (!(connectedToAll(*globalmap, pos[0], nAvatars))) { pknown = percentKnown(*globalmap, nAvatars); } fprintf(stdout, "percent known %.1f %%\n", pknown*100); } for (i = 0; i < nAvatars; i++) { LOG(lmsg, fd_log, LVL_INFO, "avatar %d (% 3d,% 3d) -> " "(% 3d,% 3d)", i+1, (int)pos[i].x, (int)pos[i].y, (int)inMessage.avatar_turn.Pos[i].x, (int)inMessage.avatar_turn.Pos[i].y); } } /* Update our position */ for (i = 0; i < nAvatars; i++) pos[i] = inMessage.avatar_turn.Pos[i]; } else if (inMessage.avatar_turn.TurnId == (curAvatar + 1)%nAvatars && !firstMove) { /* Update with results of previous move */ if (inMessage.type & AM_AVATAR_TURN) updateWorldMap(globalmap, pos[curAvatar], movdir, inMessage, curAvatar, nAvatars, algo); pthread_mutex_unlock(&globalmap->mapMutex); } firstMove = false; } while (!(inMessage.type & AM_MAZE_SOLVED) && !(inMessage.type == AM_TOO_MANY_MOVES)); /* Detach and (if no other process is connected) deallocate shared memory */ shmctl(shmid, IPC_RMID, NULL); close(s); if (curAvatar == 0) { if (inMessage.type & AM_MAZE_SOLVED) { printf("Moves to solve: %" PRIu32, inMessage.maze_solved.nMoves); printf("\n"); printf("Size = %dx%d\n", xlen, ylen); printf("Algorithm = %d\n", algo); printf("# of Avatars = %d\n", nAvatars); /* print to log */ LOG(lmsg, fd_log, LVL_INFO, "Moves to Solve: %" PRIu32, inMessage.maze_solved.nMoves); LOG(lmsg, fd_log, LVL_INFO, "Hash: %" PRIu32, inMessage.maze_solved.Hash); } else { LOG(lmsg, fd_log, LVL_INFO, "Maze not solved after ~%d moves", iterations * nAvatars); memset(&lmsg, 0, sizeof(lmsg)); } } sleep(1); close(fd_log); unlink(FIFO_NAME); pthread_mutex_destroy(&globalmap->mapMutex); return 0; }