void thread_error(int fd, const char *msg) { printf("thread error: %s\n", msg); perror(msg); removeclient(fd); pthread_exit((void*)1); }
/* select() said activity; check it out */ static void read_and_process(struct client *p) { char msg[MAXHANDLE + 2 + MAXMESSAGE + 2 + 1]; char *s = myreadline(p); if (!s) return; if (p->name[0]) { sprintf(msg, "%s: %s\r\n", p->name, s); broadcast(msg, strlen(msg)); } else { strncpy(p->name, s, MAXHANDLE); p->name[MAXHANDLE] = '\0'; cleanupstr(p->name); if (p->name[0]) { printf("fd %d is using handle '%s'\n", p->fd, p->name); sprintf(msg, "chatsvr: Welcome to our new participant, %s\r\n", p->name); broadcast(msg, strlen(msg)); } else { static char botchmsg[] = "chatsvr: protocol botch\r\n"; write(p->fd, botchmsg, sizeof botchmsg - 1); printf("Disconnecting fd %d because of protocol botch in handle registration\n", p->fd); fflush(stdout); close(p->fd); removeclient(p); } } }
static void broadcast(char *s, int size) { struct client *p, *nextp; for (p = top; p; p = nextp) { nextp = p->next; /* in case we remove this client because of error */ if (p->name[0]) { if (write(p->fd, s, size) != size) { perror("write()"); removeclient(p); } } } }
int main(void) { int h = 0; int f = 1; int clientfd, maxfd, nready, i, result; socklen_t len; struct sockaddr_in q; fd_set allset, rset; struct queue_list *clientlist = q_init(); //client fds struct queue_list *battlelist = q_init(); //battles struct queue_list *playerlist = q_init(); //players w/ stats, name etc. int listenfd = bindandlisten(); maxfd = listenfd; FD_ZERO(&allset); FD_SET(listenfd, &allset); while (1) { printf("server on %d iteration\n", h); h++; if (f == 1) { printf("server initialized! \n"); f++; } rset = allset; struct node *bb = battlelist->front; while (bb) { if (bb->content->status == 0) { battle_end(bb->content, playerlist, 0); } bb = bb->next; } printf("attempting to create matches: "); if (matchmaking(playerlist, battlelist) == 1)//find match for two clients each iteration { printf("Battle created with pid %d !\n", bid); bid = bid + 1; } nready = select(maxfd + 1, &rset, NULL, NULL, NULL); //check if there is any client active if (nready == 0) // if no client is active { continue; //go back to the beginning. } else if (nready == -1) //error { perror("select"); continue; } if (FD_ISSET(listenfd, &rset)) //check if listenfd active that connected by any client { printf("a new client is connecting\n"); len = sizeof(q); if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) //accept the client, *i think* it will reset listenfd to inactive { perror("accept"); exit(1); } FD_SET(clientfd, &allset); //add the client fd in to the set of fd write(clientfd, "What is your name?\r\n", 20); if (clientfd > maxfd) { maxfd = clientfd; //update max # of fd if needed } printf("connection from %s\n", inet_ntoa(q.sin_addr)); addclient(clientfd, q.sin_addr, clientlist); } struct node *p; for(i = 0; i <= maxfd; i++) //iterate through fd set and { if (FD_ISSET(i, &rset)) //check each connected client fd in the set of fd, if anyone becomes active. { for (p = clientlist->front; p != NULL; p = p->next) //TODO: change this for new data structure { if (p->content->fd == i) { result = handle(clientlist, playerlist, p->content); if (result == -1 || result == 5) { if (result == 5) { bid = battle_end(p->content->player, playerlist, 1); printf("battle %d drops due to client disconnected\n", bid); } int tmp_fd = p->fd; removeclient(p->content, clientlist); FD_CLR(tmp_fd, &allset); close(tmp_fd); } break; } } } } } }
int main (){ int maxfd, listenfd, connfd, nread, i; char c = 'C'; char temp; char *after; unsigned short block_crc; unsigned char char_block, crc_first, crc_second; char *dirname = "filestore"; struct client *top = malloc(sizeof (struct client)); top->fd = -1; top->next = NULL; struct client *p; fd_set allset; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; listenfd = Socket(PF_INET, SOCK_STREAM, 0); memset(&servaddr, '\0', sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(PORT); Bind (listenfd, (struct sockaddr *) &servaddr, sizeof (servaddr)); Listen (listenfd, LISTENQ); while(1){ fprintf(stderr, "Time to Select\n"); maxfd = listenfd; FD_ZERO (&allset); FD_SET(listenfd, &allset); //loop through the linked list of clients to refresh the allset for (p = top; p->fd >=0; p = p->next){ FD_SET (p->fd, &allset); if (p->fd > maxfd) maxfd = p->fd; //if the fd is larger than the maxfd, change maxfd. } Select(maxfd+1, &allset, NULL, NULL, NULL); //loop through the linked list until the fd corresponding to the client that is set is found for (p = top; p->fd >=0; p = p->next){ if (FD_ISSET(p->fd, &allset)) break; } //if it is our listening socket then a new client has come if (FD_ISSET(listenfd, &allset)){ newconnection(listenfd, &top); } // otherwise its one of our old clients else if(!p){ //if p is null, we have a problem fprintf(stderr,"uhoh\n"); exit(1); } // if p exists, then we go through the states else { if(p){ if (p->state == initial){ fprintf(stderr, "initial reading from client\n"); // read as many as you can up to 20 characters, leaving off where it last wrote nread = read(p->fd, &(p->buf[p->inbuf]), sizeof(char)*(20 - p->inbuf)); if(nread<0){ perror("read"); removeclient(p->fd, &top); } //use inbuf as an index of where to write next, and how much more can be written p->inbuf = p->inbuf + nread; //transfer stuff in buf to filename until a network newline is reached for (i = 0; i < 20; i++){ p->filename[i] = p->buf[i]; if (p->buf[i] == '\r'){ //once the network newline is found p->filename[i] = '\0';//place a null character to end the string p->state = pre_block; //change states p->fp = open_file_in_dir(p->filename, dirname); //open a file p->inbuf = 0;// reset inbuf to be 0, going to write over buf from 0 index if (write(p->fd, &c, 1)<0){ //send 'C' to client perror("write"); removeclient(p->fd, &top); } break; } } //if the network newline is not found in the 20 characters sent by client, error in filename, drop client if (p->inbuf == 20){ fprintf(stderr, "filename was not found. filename must be less than 20 characters\n"); removeclient(p->fd, &top); } } if (p->state == pre_block){ fprintf(stderr, "pre_block readering from client \n"); nread = read(p->fd, &temp, 1); //read a single character if(nread<0){ //if there was a problem with nread then drop the client perror("read"); removeclient(p->fd, &top); } if (temp== EOT){ temp = ACK; if (write(p->fd, &temp, 1)<0){ perror("write"); removeclient(p->fd, &top); } fprintf(stderr, "finished\n"); removeclient(p->fd, &top); } if (temp == SOH){ p->blocksize = 132; p->state = get_block; } if (temp == STX){ p->blocksize = 1028; p->state = get_block; } } if (p->state == get_block){ fprintf(stderr, "get_block readering from client \n"); /* reads into the buffer as much as it can upto the blocksize of the client * and continues writing where it left off*/ nread = read(p->fd, &(p->buf[p->inbuf]), p->blocksize - p->inbuf); if(nread < 0){ perror("read"); removeclient(p->fd, &top); } p->inbuf = p->inbuf + nread; //once the entire block is received, go to the next state; if (p->inbuf == p->blocksize) p->state = check_block; } if (p->state == check_block){ fprintf(stderr, "checking_block client \n"); char_block = p->current_block; /*removes client if block number and inverse don't match or block number is not * what was expected. however if the blocknum is a previously received block num, send ack*/ if (255 - p->buf[0] != p->buf[1]){ fprintf(stderr, "block number and inverse do not match\n"); removeclient(p->fd, &top); } else if (char_block > p->buf[0]){ temp = ACK; if(write(p->fd, &temp, 1)<0){ perror("write"); removeclient(p->fd, &top); } } else if (char_block != p->buf[0]){ fprintf(stderr, "char_block is not correct\n"); removeclient(p->fd, &top); } //otherwise, need to check crc else{ block_crc = crc_message (XMODEM_KEY, &(p->buf[2]), p->blocksize - 4); crc_first = block_crc>>8; crc_second = block_crc; if ((crc_first != p->buf[p->blocksize -2]) || (crc_second != p->buf[p->blocksize -1])){ fprintf(stderr, "crc does not match \n"); temp = NAK; if(write(p->fd, &temp, 1) < 0){ perror("write"); removeclient(p->fd, &top); } } else{ temp = ACK; fprintf(stderr, "writing to client ACK\n"); if (write (p->fd, &temp, 1)<0){ perror("write"); removeclient(p->fd, &top); } if(fwrite(&(p->buf[2]), p->blocksize-4, 1, p->fp)<0){ perror("write"); exit(1); } p->state = pre_block; p->current_block ++; p->inbuf = 0; if(p->current_block > 255) p->current_block = 1; } } } } } }
void* handle_client(void* fd) { int n; int oldtype; int clientfd; int nickLen; char buffer[256]; char *token; char usernick[256]; clientfd = (*(int*)fd); nickLen = 0; n = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); if (n < 0) thread_error(clientfd, "ERROR in setcanceltype"); addclientthread(clientfd, (pthread_t*)pthread_self()); sendusercount(clientfd); while (1) { printf("handle client %d\n", clientfd); memset(buffer, 0, 256); n = read(clientfd, buffer, 255); if (n <= 0) { thread_error(clientfd, "Client disconnected"); } if (nickLen == 0) { token = strtok(buffer, " "); if (token == NULL) thread_error(clientfd, "ERROR client protocol"); if (strcmp(token, USER) == 0) { token = strtok(NULL, " "); if (token == NULL) thread_error(clientfd, "ERROR reading client message"); nickLen = strlen(token); if (nickLen > 0 && nickLen <= 256) { strcpy(usernick, (const char*)token); addusernick(clientfd, (const char*)&usernick); } else { n = write(clientfd, ERROR, ERROR_LEN); } if (n < 0) { thread_error(clientfd, "ERROR writing to socket"); } } } else { sendmessagefrom(clientfd, buffer); } } removeclient(clientfd); pthread_exit(NULL); }
char *myreadline(struct client *p) { int nbytes; /* move the leftover data to the beginning of buf */ if (p->bytes_in_buf && p->nextpos) memmove(p->buf, p->nextpos, p->bytes_in_buf); /* If we've already got another whole line, return it without a read() */ if ((p->nextpos = extractline(p->buf, p->bytes_in_buf))) { p->bytes_in_buf -= (p->nextpos - p->buf); return(p->buf); } /* * Ok, try a read(). Note that we _never_ fill the buffer, so that there's * always room for a \0. */ nbytes = read(p->fd, p->buf + p->bytes_in_buf, sizeof p->buf - p->bytes_in_buf - 1); if (nbytes <= 0) { if (nbytes < 0) perror("read()"); if (p->name[0]) { char msg[MAXHANDLE + 40]; printf("Disconnecting fd %d, name %s\n", p->fd, p->name); fflush(stdout); sprintf(msg, "chatsvr: Goodbye, %s\r\n", p->name); removeclient(p); broadcast(msg, strlen(msg)); } else { printf("Disconnecting fd %d, no name\n", p->fd); fflush(stdout); removeclient(p); } } else { p->bytes_in_buf += nbytes; /* So, _now_ do we have a whole line? */ if ((p->nextpos = extractline(p->buf, p->bytes_in_buf))) { p->bytes_in_buf -= (p->nextpos - p->buf); return(p->buf); } /* * Don't do another read(), to avoid the possibility of blocking. * However, if we've hit the maximum message size, we should call * it all a line. */ if (p->bytes_in_buf >= MAXMESSAGE) { p->buf[p->bytes_in_buf] = '\0'; p->bytes_in_buf = 0; p->nextpos = NULL; return(p->buf); } } /* If we get to here, we don't have a full input line yet. */ return(NULL); }
int main(void) { int clientfd, maxfd, nready; struct client *p; struct client *head = NULL; socklen_t len; struct sockaddr_in q; struct timeval tv; fd_set allset; fd_set rset; srand (time(NULL)); int i; //Initialize a listening fd of the server. int listenfd = bindandlisten(); // initialize allset and add listenfd to the // set of file descriptors passed into select FD_ZERO(&allset); FD_SET(listenfd, &allset); // maxfd identifies how far into the set to search maxfd = listenfd; while (1) {//keep running // make a copy of the set before we pass it into select rset = allset; /* timeout in seconds (You may not need to use a timeout for * your assignment)*/ tv.tv_sec = 2; // change to 0 from 10 tv.tv_usec = 0; /* and microseconds */ nready = select(maxfd + 1, &rset, NULL, NULL, &tv); //Select a ready fd descriptor(client) to read. if (nready == 0) { printf("No response from clients in %ld seconds\n", tv.tv_sec); continue; } if (nready == -1) { perror("select"); continue; } if (FD_ISSET(listenfd, &rset)) { printf("a new client is connecting\n"); len = sizeof(q); if ((clientfd = accept(listenfd, (struct sockaddr *)&q, &len)) < 0) { perror("accept"); exit(1); } FD_SET(clientfd, &allset); if (clientfd > maxfd) { maxfd = clientfd; } printf("connection from %s\n", inet_ntoa(q.sin_addr)); //sprintf("what is your name?"); head = addclient(head, clientfd, q.sin_addr); } //Handle every client //printf("running\n"); for(i = 0; i <= maxfd; i++) { if (FD_ISSET(i, &rset)) { for (p = head; p != NULL; p = p->next) { if (p->fd == i) {// int result = handleclient(p, head); if (result == -1) { int tmp_fd = p->fd; head = removeclient(head, p->fd); FD_CLR(tmp_fd, &allset); close(tmp_fd); } break; } } } } } return 0; }