int main(void) { int listenfd; int fd, nbytes; int inbuf; int room; char *after; struct sockaddr_in client; socklen_t socklen; char buf[30]; listenfd = setup(); while (1) { socklen = sizeof(client); if ((fd = accept(listenfd, (struct sockaddr *)&peer, &socklen)) < 0) { perror("accept"); } else { printf("New connection on port %d\n", ntohs(client.sin_port)); // Receive messages inbuf = 0; // empty buffer room = sizeof(buf); // whole buffer is room after = buf; while ((nbytes = read(fd, after, room)) > 0) { inbuf = inbuf + nbytes; int where = find_network_newline(buf, inbuf); while (where >= 0) { buf[where - 1] = '\n'; buf[where] = '\0'; printf ("Next message: %s", buf); where++; inbuf = inbuf - where; memmove(buf, buf + where, inbuf); // possibly the last read completed more than 1 line where = find_network_newline(buf, inbuf); } room = sizeof(buf) - inbuf; after = buf + inbuf; } close (fd); } } }
/** * Process 's' battle command where client p is attacking and wants to speak. */ int speak(struct client *p) { char buf[256]; //buffer for client data (reading from client) char outbuf[512]; //buffer for output to client int nbytes; int inbuf = 0; // buffer is empty; has no bytes int room = sizeof(buf); // room == capacity of the whole buffer char *after = buf; // start writing at beginning of buf while (((nbytes = read(p->fd, after, room)) > 0)) { inbuf += nbytes; /* Check for buffer overflow */ if (inbuf >= sizeof(buf)) { sprintf(outbuf, "\nServer cant handle this lengthy message..\r\n"); write(p->fd, outbuf, strlen(outbuf)); return -1; } int where = find_network_newline(buf, inbuf); if (where >= 0) { // OK. we have a full line buf[where] = '\0'; buf[where+1] = '\0'; printf("Next message: %s", buf); sprintf(outbuf, "You speak:%s\r\n\n", buf); write(p->fd, outbuf, strlen(outbuf)); /* Write the message to opponent */ sprintf(outbuf, "%s takes a break to tell you:\n%s\r\n\n", (p->partner)->name, buf); write((p->partner)->fd, outbuf, strlen(outbuf)); inbuf -= (where+2); int i; for (i=0; i< where; i++) { buf[i] = '\0'; } memmove(buf,buf+where+2,inbuf); break; } after = &buf[inbuf]; room = sizeof(buf) - inbuf; } if (nbytes == 0) { //Socket closed during speak return -1; //To be removed by removeclient } return 0; }
int main() { int listenfd, clientfd, maxfd; fd_set cset, rset; Client *clients = NULL; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; int one = 1; unsigned char temp_block_num, temp_block_inverse; unsigned short temp_crc, block_crc; char temp = 'C'; /*If a client disconnects while we are writing an ACK/NAK to them it sends * a SIGPIPE which needs to be taken care of */ signal(SIGPIPE, SIG_IGN); //Setup the main listening socket listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORT); if ((setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int))) == -1) { perror("setsockopt"); } Bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); Listen(listenfd, 5); FD_ZERO(&cset); FD_SET(listenfd, &cset); maxfd = listenfd; while (1) { /* * Accept any clients that want to connect. */ rset = cset; Select(maxfd + 1, &rset, NULL, NULL, 0); // Check for new clients. if (FD_ISSET(listenfd, &rset)) { printf("New Client Connected\n"); Client *temp = Malloc(sizeof(Client)); clilen = sizeof(cliaddr); clientfd = Accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); FD_SET(clientfd, &cset); if (clientfd > maxfd) { maxfd = clientfd; } // Populate the client struct with default starter data. temp->fd = clientfd; temp->inbuf = 0; temp->state = initial; temp->next = start; temp->prev = NULL; if (start) { start->prev = temp; } start = temp; continue; } /* * Loop through all the clients in the linked list, * checking their file descriptors for activity. */ clients = start; while (clients) { clientfd = clients->fd; if (FD_ISSET(clientfd, &rset)) { /* * Using switch statement for states is too messy in terms of proper flow control * so just using if statements instead; they're cleaner and easier to follow. */ if (clients->state == initial) { // Read name of the file being sent. clients->inbuf += Read(clientfd, &(clients->filename)[clients->inbuf], 20 - clients->inbuf); if (find_network_newline(clients->filename, clients->inbuf) > 0) { clients->filename[clients->inbuf - 2] = '\0'; // Open/create a file with the name. clients->fp = open_file_in_dir(clients->filename, FILE_DIR); // Assign defaults to client struct. clients->state = pre_block; clients->inbuf = 0; clients->current_block = 1; // Let the client know that the server is ready for the data. temp = 'C'; Write(clientfd, &temp, 1); } } if (clients->state == pre_block) { // Find out what state the client is in. Read(clientfd, (clients->buf), 1); switch (clients->buf[0]) { case EOT: clients->state = finished; break; case SOH: clients->state = get_block; clients->blocksize = 132; break; case STX: clients->state = get_block; clients->blocksize = 1028; break; default: temp = NAK; Write(clientfd, &temp, 1); } } if (clients->state == get_block) { // Keep getting more of the payload till you have the required minimum amount. clients->inbuf += Read(clientfd, (clients->buf) + (clients->inbuf), clients->blocksize - clients->inbuf); if (clients->inbuf == clients->blocksize) { clients->state = check_block; } } if (clients->state == check_block) { // Fetch block numbers from the packet. temp_block_num = (clients->buf)[0]; temp_block_inverse = (clients->buf)[1]; // Make sure the block numbers are correct - drop the client if they're not. if ((temp_block_num != (255 - temp_block_inverse) || (temp_block_num > clients->current_block))) { FD_CLR(clientfd, &cset); clients = drop_client(clients); /* * Since drop_client gives us the client after the one we dropped, * we use continue to go back to start of the loop. */ break; } // Fetch and assemble the CRC given by client for the payload recieved. temp_crc = 0; temp_crc = (unsigned char)(clients->buf)[(clients->blocksize) - 2]; temp_crc <<= 8; temp_crc |= (unsigned char)((clients->buf)[(clients->blocksize) - 1]); // Calculate the actual CRC for the payload recieved. block_crc = crc_message(XMODEM_KEY, (unsigned char *)((clients->buf) + 2), (clients->blocksize) - 4); // Compare the given and calculated CRC to ensure payload integrity. if ((temp_block_num == clients->current_block) && (temp_crc == block_crc)) { printf("File: %s \t Block:%d Successfully recieved\n", clients->filename, clients->current_block); // Write the payload to file if CRCs match if (fwrite((clients->buf) + 2, 1, ((clients->blocksize) - 4), clients->fp) == 0) { perror("Write to File error"); exit(-1); } // Send the client an ACK temp = ACK; Write(clientfd, &temp, 1); // Increment service side block number counter and prepare for next block. clients->state = pre_block; clients->current_block += 1; // Deal w/ wrap around when block number hits 255. if (clients->current_block == 256) { clients->current_block = 0; } // Reset the buffer position. clients->inbuf = 0; } else if (temp_crc != block_crc) { printf("File: %s \t Block:%d CRC mismatch.\nExpected:%x, Got %x\n", clients->filename, clients->current_block, temp_crc, block_crc); // Sent the client a NAK if the CRCs didn't match and prepare for repeat block. temp = NAK; Write(clientfd, &temp, 1); clients->state = pre_block; clients->inbuf = 0; } else if (temp_block_num < clients->current_block) { // If we got a repeat block, just send the client an ACK. temp = ACK; Write(clientfd, &temp, 1); } } if (clients->state == finished) { printf("File Transfer Finished: %s\n", clients->filename); // Cleanup after the client when transfer is finished. // Send the client a final ACK. temp = ACK; Write(clientfd, &temp, 1); // Remove the client and their socket from our list/set of clients. FD_CLR(clientfd, &cset); clients = drop_client(clients); } } // Move on to the next client in the list (if any). if (clients) { clients = clients->next; } } } }
int handleclient(struct client *p, struct client *top) { char outbuf[512]; struct client *oppo; int len; //New client, ask the name. if (p->name == NULL) { //Ask the name int inbuf = 0; int where; // buffer is empty; has no bytes int room = sizeof(p->name_buf); // room == capacity of the whole buffer char *after; after = p->name_buf; //Return number of bytes read //nbytes = len while (( len = read(p->fd, after, sizeof(p->name_buf) - 1)) > 0) { inbuf += len; where = find_network_newline(p->name_buf, inbuf); if (where >= 0) { // OK. we have a full line p->name_buf[where] = '\0'; p->name_buf[where+1] = '\0'; inbuf -= where + 2 ; break; } room = sizeof(p->name_buf) - inbuf; after = p->name_buf + inbuf; } p->name = p->name_buf; //Tell the world someone joined. sprintf(outbuf, "\r\n**%s joined the area.**\r\n", p->name); broadcast(top, outbuf, strlen(outbuf)); sprintf(outbuf, "Welcome, %s! Awaiting opponent...\n", p->name); write(p->fd, outbuf, strlen(outbuf)); } //Start matching. if(p->opponent == NULL) { for (oppo = top; oppo != NULL; oppo = oppo->next) { if(oppo != p) { if(oppo->opponent == NULL && oppo->lastplayed != p) { p->opponent = oppo; p->hitpoints = rand() % 11 + 20; p->powermoves = rand() % 3 + 1; p->status = 1;//Attacking first oppo->opponent = p; oppo->hitpoints = rand() % 11 + 20; oppo->powermoves = rand() % 3 + 1; oppo->status = -1;//Defend first. sprintf(outbuf, "You engage %s!\n", p->opponent->name); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "You engage %s!\n", p->name); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nReady for battle?(Please type 'y')\n"); write(p->fd, outbuf, strlen(outbuf)); } } } return 0; } len = read(p->fd, p->buf, sizeof(p->buf) - 1); //Handle battle. if(p->opponent) { if (p->status == 1) { sprintf(outbuf, "Your hitpoints:%d\nYour powermoves: %d\n\n%s's hitpoints:%d\n\n", p->hitpoints, p->powermoves, p->opponent->name, p->opponent->hitpoints); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "Your hitpoints:%d\nYour powermoves: %d\n\n%s's hitpoints:%d\n\n", p->opponent->hitpoints, p->opponent->powermoves, p->name, p->hitpoints); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "(a)ttack\n(p)owermove\n(s)peak something\n"); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "Waiting for %s to strike...\n", p->name); write(p->opponent->fd, outbuf, strlen(outbuf)); len = read(p->fd, p->buf, sizeof(p->buf) - 1); p->status = -1; p->opponent->status = 1; } else if(p->status == -1) { return 0; } if (len > 0) { if(p->buf[0] == 'a') { p->buf[0] = '\0'; int damage; damage = rand() % 5 + 2; p->opponent->hitpoints -= damage; sprintf(outbuf, "\nYou hit %s for %d damage!\n", p->opponent->name, damage); write(p->fd, outbuf, strlen(outbuf));//write outbuf to every client in top. sprintf(outbuf, "\n%s hits you for %d damage!\n", p->name, damage); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nReady for attacking/speaking?(Please say 'y')\n"); write(p->opponent->fd, outbuf, strlen(outbuf)); if(p->opponent->hitpoints <= 0) { sprintf(outbuf, "\n%s gives up. You win!\n", p->opponent->name); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nYou are no match for %s. You scurry away...\n", p->name); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "Awaiting opponent...\n"); write(p->fd, outbuf, strlen(outbuf)); write(p->opponent->fd, outbuf, strlen(outbuf)); p->lastplayed = p->opponent; p->opponent->lastplayed = p; moveToEnd(top, p); moveToEnd(top, p->opponent); p->opponent->opponent = NULL; p->opponent = NULL; } return 0; } else if(p->buf[0] == 'p') { p->buf[0] = '\0'; int possibility; int damage; possibility = rand() % 2 + 0; p->powermoves -= 1; if(possibility == 0) { //Miss it; sprintf(outbuf, "\nYou missed %s!\n", p->opponent->name); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\n%s missed you!\n", p->name); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nReady for attacking/speaking?(Please say 'y')\n"); write(p->opponent->fd, outbuf, strlen(outbuf)); return 0; } else { damage = 3 * (rand() % 5 + 2); p->opponent->hitpoints -= damage; sprintf(outbuf, "\nYou powermoves %s for %d damage!\n", p->opponent->name, damage); write(p->fd, outbuf, strlen(outbuf));//write outbuf to every client in top. sprintf(outbuf, "\n%s powermoves you for %d damage!\n", p->name, damage); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nReady for attacking/speaking?(Please say 'y')\n"); write(p->opponent->fd, outbuf, strlen(outbuf)); if(p->opponent->hitpoints <= 0) { sprintf(outbuf, "\n%s gives up. You win!\n", p->opponent->name); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nYou are no match for %s. You scurry away...\n", p->name); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "Awaiting opponent...\n"); write(p->fd, outbuf, strlen(outbuf)); write(p->opponent->fd, outbuf, strlen(outbuf)); p->lastplayed = p->opponent; p->opponent->lastplayed = p; moveToEnd(top, p); moveToEnd(top, p->opponent); p->opponent->opponent = NULL; p->opponent = NULL; } return 0; } } else if(p->buf[0] == 's') { p->buf[0] = '\0'; sprintf(outbuf, "Speak:"); write(p->fd, outbuf, strlen(outbuf)); int inbuf = 0; int where; int room = sizeof(p->buf); char *after; //char name_buf[256]; p->buf[0] = '\0'; after = p->buf; while (( len = read(p->fd, after, sizeof(p->buf) - 1)) > 0) { inbuf += len; where = find_network_newline(p->buf, inbuf); if (where >= 0) { // OK. we have a full line p->buf[where] = '\0'; p->buf[where+1] = '\0'; inbuf -= where + 2 ; break; } room = sizeof(p->buf) - inbuf; after = p->buf + inbuf; } sprintf(outbuf, "You spoke:%s\n", p->buf); write(p->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "%s spoke:%s\n", p->name, p->buf); write(p->opponent->fd, outbuf, strlen(outbuf)); sprintf(outbuf, "\nReady for attacking/speaking?(Please say 'y')\n"); write(p->opponent->fd, outbuf, strlen(outbuf)); return 0; } } else if (len == 0) {//nothing in client p's fd // socket is closed printf("active\n"); sprintf(outbuf, "Awaiting opponent...\n"); write(p->opponent->fd, outbuf, strlen(outbuf)); p->opponent->opponent = NULL; sprintf(outbuf, "--%s dropped. You win!\n", p->name); write(p->opponent->fd, outbuf, strlen(outbuf)); printf("Disconnect from %s\n", inet_ntoa(p->ipaddr)); return -1; } else { // shouldn't happen perror("read"); return -1; } } return -1; }