#include "LineFinder.h" #include "Box.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define PRINTF //printf /********************************************************************************************** Network Communication implementation **********************************************************************************************/ int con_sock; int srv_port = 1234; /********************************************************************************************** Received a signal. Close the connection and quit. **********************************************************************************************/ void signal_handler(int n) { close(con_sock); exit(0); } /***************************************************************************************** Establish_connection() will do what its name suggests: makes a connection to the server. It will update the value of con_sock, which is the file descriptor of the socket used for communicating with the server. /****************************************************************************************/ void establish_connection(int srv_port, const char* host) { struct sockaddr_in name; struct hostent *hptr; int flag; // step (a) create a socket con_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // it is misconception to use "AF_INET" instead of "PF_INET" if (con_sock <= 0) { perror("Open socket failed"); exit(1); } name.sin_family = PF_INET; name.sin_port = htons(srv_port); // getting the host IP information if ((hptr = gethostbyname(host)) == NULL) { perror("gethostbyname"); exit(1); } bcopy(hptr->h_addr, (char *)&name.sin_addr.s_addr, hptr->h_length); PRINTF("Trying to contact %s...\n", host); // making connection flag = connect(con_sock, (struct sockaddr *) &name, sizeof(name)); if (flag < 0){ perror("No connection"); close(con_sock); exit(1); } PRINTF("Connected\n"); } extern int errno; // send a string to a socket already created void sendToSocket(int connectionSocket, char *toSend){ char buffToSend[8192]; int lg; sprintf(buffToSend, "%s\r\n", toSend); PRINTF("Sending %s", buffToSend); lg = write(connectionSocket, buffToSend, strlen(buffToSend)); /* If having any trouble with the socket, it means that the connection is closed somehow, quit the program. */ if (lg == -1 && errno == EBADF){ close(con_sock); exit(0); } } // send a float to a socket already created void sendToSocket(int connectionSocket, float toSend){ char buffToSend[8192]; int lg; sprintf(buffToSend, "%f\r\n", toSend); PRINTF("Sending %s", buffToSend); lg = write(connectionSocket, buffToSend, strlen(buffToSend)); /* If having any trouble with the socket, it means that the connection is closed somehow, quit the program. */ if (lg == -1 && errno == EBADF){ close(con_sock); exit(0); } } // reads from a socket and into a buffer - returns number of bytes read. int receiveSocket(int con_sock, char* buffer, int size){ int lg; int iWaiting = 0; do { if (iWaiting > 1000){ fprintf(stderr, "waiting...\n"); // exit(0); } iWaiting++; /* get response from the server. If there is error and it is EBADF, it means the connection might be closed, otherwise, try to read it again until we read it successfully. */ lg = read(con_sock, buffer, size); if (lg == -1 && errno == EBADF){ close(con_sock); return(0); } PRINTF("Receiving %s ", buffer); } while (lg <= 0); return(lg); } /********************************************************************************* The protocol is simple and clear. It could have be even easier but I wanted to make it real clear. The server will always wait for connection. After the connection is established, it will wait for one of two commands: either BOX or LINES. If the server receives LINES, it will expect to receive the the bounding box next (four floats: xmin, ymin, xmax, ymax). The protocol says that after each transmision, wait for an acknowledgement (ACK). The next step will be sending the lines out. The server will send a command LINE before each new line and the command POINT to signal that there is a new point of the line. After the transmission is completed, it sends the command END. The server will always wait for an acknowledge except when sending END. If the server receives BOX, it will transmit to the client the four coordinates of the bounding box. These are the limits of the box *********************************************************************************/ /********************************************************************************************** NetworkLineFinder Constructor implementation **********************************************************************************************/ NetworkLineFinder::NetworkLineFinder(string hostname, int port){ this->hostname = hostname; this->port = port; // Intercept some signals so we can quit the program // more gracefully when interrupted by such signals. signal(SIGTERM, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGINT, signal_handler); } /********************************************************************************************** NetworkLineFinder getBoundaries implementation. It will get the boundaries from the server **********************************************************************************************/ Box NetworkLineFinder::getBoundaries() { char buff[8192], req[8192]; char *c; int lg; float xmin, ymin, xmax, ymax, result_f; // Establish the connection to the server. It needs the port and // the host address (or name) of the server establish_connection(port, hostname.c_str()); sendToSocket(con_sock, "BOX"); // write everything to the network. receiveSocket(con_sock, buff, 5); // wait for acknowledge PRINTF("Ready to receive box...\n"); // Receive the coordinates of the bounding box // First, the server receive the coordinates of the bounding box for(int i = 0; i < 4; i++){ PRINTF("Receiving box coordinates...\n"); lg = receiveSocket(con_sock, req, 8192); // Check the ending characters of the protocol if (req[lg - 1] != '\n' || req[lg - 2] != '\r') { sendToSocket(con_sock, "Error: Unknown input"); break; } req[lg - 2] = '\0'; // Get rid of the trailing new line character and carriage return character. c = strtok(req, " "); // Get the first part of the line only. (Separated by space.) // Empty line if (c == NULL) { sendToSocket(con_sock, "Error: Unknown input"); break; } // A float-point number result_f = atof(c); switch(i){ case 0: xmin = result_f; break; case 1: ymin = result_f; break; case 2: xmax = result_f; break; case 3: ymax = result_f; break; } // Send some ACKNOWLEDGE sendToSocket(con_sock, "ACK"); } // End receiving coordinates. receiveSocket(con_sock, buff, 8192); // Receive END close(con_sock); // Get the points and return the Box Point2 bottomLeftCorner(xmin, ymin); Point2 upperRightCorner(xmax, ymax); return Box(bottomLeftCorner, upperRightCorner); } /********************************************************************************************** NetworkLineFinder findLines implementation. It will get the lines from the server **********************************************************************************************/ LineList *NetworkLineFinder::findLines(Box& box) { LineList *ll = new LineList(); Line *singleLine = NULL; Point2 min = box.min(); Point2 max = box.max(); char buff[8192], out[8192]; int lg; float xmin = min.x; float ymin = min.y; float xmax = max.x; float ymax = max.y; bool bFirstLine = true; char seps[] = " ,\t\n"; // log("finding candidates"); // Establish the connection to the server. It needs the port and // the host address (or name) of the server establish_connection(port, hostname.c_str()); sendToSocket(con_sock, "LINES"); // write everything to the network. receiveSocket(con_sock, buff, 5); // wait for acknowledge // First, send the bounding coordinates // Sending points out for (int i = 0; i < 4; i++){ switch(i){ case 0: sprintf(out, "%f", xmin); break; case 1: sprintf(out, "%f", ymin); break; case 2: sprintf(out, "%f", xmax); break; case 3: sprintf(out, "%f", ymax); break; } sendToSocket(con_sock, out); // write everything to the network. lg = receiveSocket(con_sock, buff, 5); // wait for acknowledge if (buff[lg - 1] != '\n' || buff[lg - 2] != '\r') { fprintf(stderr, "Error: Wrong format\r\n"); } // Remove \r\n and display the response to standard output buff[lg - 2] = '\0'; // if we receive "END" end the loop if (strncmp(buff, "END", 3) == 0) { close(con_sock); return ll; } }// End sending the bounding box // do until we receive END do{ lg = receiveSocket(con_sock, buff, 8192); if (lg == 0) return ll; if (buff[lg - 1] != '\n' || buff[lg - 2] != '\r') { fprintf(stderr, "Error: Wrong format\r\n"); } // Remove \r\n and display the response to standard output buff[lg - 2] = '\0'; // if we receive "END" end the loop if (strncmp(buff, "END", 3) == 0) { if (singleLine) { ll->push_back(singleLine); // put last line received also on the list } break; } sendToSocket(con_sock, "ACK"); // Send some ACKNOWLEDGE // if we receive "LINE", initialize a new line if (strncmp(buff, "LINE", 4) == 0){ PRINTF("New Line Starting \n"); // if this is not the first time, add the line to the line list if (!bFirstLine){ ll->push_back(singleLine); } bFirstLine = false; // creating a line singleLine = new Line(); // Get the new line //////////////////////////////////////////////////// // receive the line lg = receiveSocket(con_sock, buff, 8192); // Send some ACKNOWLEDGE sendToSocket(con_sock, "ACK"); if (lg == 0) return ll; if (buff[lg - 1] != '\n' || buff[lg - 2] != '\r') { fprintf(stderr, "Error: Wrong format\r\n"); } buff[lg - 2] = '\0'; // Remove \r\n and display the response to standard output char *token; token = strtok( buff, seps ); while( token != NULL ){ float X = atof(token); // Get next token, this is the Y token = strtok( NULL, seps ); float Y = atof(token); // PRINTF("X = %f, Y = %f\n", X, Y); // Add received point to the line Point2 pp(X, Y); singleLine->points.push_back(pp); // get next X token = strtok( NULL, seps ); } } else { fprintf(stderr, "Error in transmision\n"); exit(0); } } while (true); if (singleLine) { ll->push_back(singleLine); // put last line received also on the list } close(con_sock); // cerr << "found " << ll->size() << endl; return ll; }