コード例 #1
0
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;
                        }
                    }
                }
            }
        }
    }
コード例 #2
0
ファイル: client1.c プロジェクト: LongJeongS/csc209
int main(int argc, char* argv[]) {
	int soc, len, err;
	unsigned char buf[128]; // payloads
	char temp;
	struct addrinfo *info, hints;
	struct sockaddr_in peer;
	memset (&hints, 0, sizeof (struct addrinfo));
	hints.ai_family = PF_INET;
	hints.ai_socktype = SOCK_STREAM;

	if ( argc != 4) {
		fprintf(stderr, "Usage: %s <hostname> <port> <filename>\n", argv[0]);
		exit(1);
	}
	if ((err = getaddrinfo(argv[1], argv[2], &hints, &info))) {
		fprintf (stderr, "%s\n", gai_strerror(err));
		exit (1);
	}

	FILE *fp = fopen(argv[3], "rb");
	if (!fp) {
		perror("fopen");
		exit(2);
	}

	peer = *(struct sockaddr_in *)(info->ai_addr);

	if ((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror ("socket");
		exit (1);
	}

	if (connect(soc, (struct sockaddr *)&peer, sizeof(peer)) == -1) {
		perror ("connect");
		exit (1);
	}

	int state = initial;
	int current_block, readblock;

	while (1) {
		if (state == initial) {
			write(soc, argv[3], strlen(argv[3]));
			write(soc, "\r\n", 2);
			current_block = 1;
			readblock = 1;
			state = handshake;
			printf("Client sent filename and entering handshake.\n");
		}

		if (state == handshake) {
			while ((len = read(soc, &temp, 1)) > 0) {
				if (temp == 'C') {
					printf("Client found C; entering send_block\n");
					state = send_block;
					break;
				}
			}
			if (len <= 0) {
				fprintf(stderr, "Server dropped client\n");
				exit(1);
			}
		}
		if (state == send_block) {
			if (readblock) {
				readblock = 0;
				len = fread(buf, 1, 128, fp);
				if (len == 0) {
					printf("Client got 0 fread; moving to finish.\n");
					state = finish;
					continue;
				}
				while (len < 128)
					buf[len++] = SUB;
			}
			unsigned char char_block = current_block;
			temp = SOH;
			printf("Client sending the block+overhead\n");
			write(soc, &temp, 1);
			printf("Sending block %d and inverse %d\n", char_block, 255-char_block);
			write(soc, &char_block, 1);
			char_block = 255 - char_block;
			write(soc, &char_block, 1);
			write(soc, buf, 128);
			unsigned short crc = crc_message(XMODEM_KEY, buf, 128);
			printf("Client wants to send crc %x\n", crc);
			char_block = crc >> 8;
			printf("Client sends crc first byte %x\n", char_block);
			write(soc, &char_block, 1);
			char_block = crc;
			printf("Client sends crc second byte %x\n", char_block);
			write(soc, &char_block, 1);
			printf("Client moving to wait_reply\n");
			state = wait_reply;
		}

		if (state == wait_reply) {
			while ((len = read(soc, &temp, 1)) > 0) {
				if (temp == NAK) {
					printf("Client received nak; moving back to send_block\n");
					state = send_block;
					break;
				}

				if (temp == ACK) {
					printf("Client received ack; moving to send_block for next block\n");
					state = send_block;
					readblock = 1;
					current_block++;
					if (current_block > 255) 
						current_block = 0;
					break;
				}
			}
		}

		if (state == finish) {
			temp = EOT;
			printf("Client sent eot, waiting for ack\n");
			write(soc, &temp, 1);
			while ((len = read(soc, &temp, 1)) > 0) {
				if (temp == NAK) {
					temp = EOT;
					write(soc, &temp, 1);
					printf("Client received nak to its EOT! Sending new EOT\n");
					break;
				}

				if (temp == ACK) {
					printf("Done!\n");
					exit(0);
				}
			}
		}
	}

	return 0;
}
コード例 #3
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;
            }

        }
    }

}
コード例 #4
0
ファイル: xmodemserver.c プロジェクト: dreamflyforever/easyxm
/* A helper function for processing a client. This functions covers all states
   except the finished state. This function takes in the argument toplist (the
   top of the linked list, and cl, the current client node/struct. */
int processclient(struct client *cl)
{
	/* Variable used for writing ACK, NAK, and other exciting control codes */
	char acker;

	switch (cl->state) {
	/* If client is in the initial state */
	case initial: 
	{	/* Variable to determine if network newline has been found */
		int readin = 0;

		/* Read in one byte at a time so that the read() call doesn't block, top when
		   network newline has been found and add a null terminator at the end of the
		   filename. */
		memset(cl->filename, 0, 20);
		if (read(cl->fd,  &cl->filename, 20) <= 0) {
			/*XXX*/
			return 0;
		}
		printf("%s:%d--->filename: %s\n", __func__, __LINE__, cl->filename);
		readin = 1;

		/* If filename is completely read in, use helper.c to generate the file
		   pointer for it, reset the buffer index, and transition to pre_block state */
		if ( readin == 1) {
			cl->fp = open_file_in_dir(cl->filename, "storage");
			cl->inbuf = 0;
			cl->state = pre_block;
		}

		/* Write "C" to the client so it can move on with its transfer, if write
		   fails, drop client by transitioning to finished block */
		if ( write(cl->fd, "C", 1) < 1) {
			perror("Writing C failed");
			cl->state = finished;
		}
	}
		break;
	/* If client is in the pre_block state */
	case pre_block:
	{	/* Temporary buffer to hold in any incoming control codes. 2048 is 
		   overkill, yes, however it can't hurt to be safe. */
		char prebuf[2048];

		/* Read in one byte at a time from the client */
		if (read(cl->fd, &prebuf[0], 1) == 1) {
			printf("*");

			/* If EOT is received, drop client by transitioning to finish state */
			if (prebuf[cl->inbuf] == EOT) {

				/* Close file pointer */
				fclose(cl->fp);

				/* Set acker to ACK control code and write it to the client */
				acker = ACK;
				printf("receiver successful\n");
				if (write(cl->fd, &acker, sizeof(char)) < 1) {
					perror("writing ACK for EOT in pre_block failed");
				}

				cl->state = finished;
			}

			/* If SOH block is received, set the expected blocksize on client to 128, 
			   and transition to get_block */
			if (prebuf[0] == SOH) {
				cl->blocksize = 128;
				cl->state = get_block;

			}

			/* If STX block is received, set the expected blocksize on client to 1024, 
			   and transition to get_block */
			if (prebuf[0] == STX) {
				cl->blocksize = 1024;
				cl->state = get_block;

			}
		} else {
			perror("pre_block read fail");

		}
	}
		break;
	/* If client is in the get_block state */
	case get_block:

		/* If server is expecting a SOH block */
		if (cl->blocksize == 128) {

			/* Read in one byte for current block number and store it in the client's
			   current_block attribute */
			if (read(cl->fd, &cl->current_block, 1) < 1) {
				perror("reading in current_block failed in SOH, get_block");
			}

			/* Read in one byte for inverse block number and store it in the client's
			   inverse_block attribute */
			if (read(cl->fd, &cl->inverse_block, 1) < 1) {
				perror("reading in inverse_block failed in SOH, get_block");
			}

			/* Read in the actual payload to the client's buf attribute, one byte at a
			   time */
			while (cl->inbuf < 128) {
				if (read(cl->fd, &cl->buf[cl->inbuf], 1) == 1) {
					cl->inbuf++;
				} else {
					perror("get_block_soh_read_failure\n");
				}

				/* Check if blocksize bytes have been read in, if so, caclculate CRC 
				   and store it in the client's CRC attributes. Transition to check_block. */
				if (cl->inbuf == cl->blocksize) {
					read(cl->fd, &cl->crca, 1);
					read(cl->fd, &cl->crcb, 1);
					cl->state = check_block;	
				}
			}

		}
		/* If server is expecting a STX block */
		if (cl->blocksize == 1024 ) {

			/* Read in one byte for current block number and store it in the client's
			   current_block attribute */
			if (read(cl->fd, &cl->current_block, 1) < 1) {
				perror("reading in current_block failed in STX, get_block");
			}

			/* Read in one byte for inverse block number and store it in the client's
			   inverse_block attribute */
			if (read(cl->fd, &cl->inverse_block, 1) < 1) {
				perror("reading in inverse_block failes in STX, get_block");
			}

			/* Read in the actual payload to the client's buf attribute, one byte at a
			   time */
			while (cl->inbuf < 1024) {
				if ( read(cl->fd, &cl->buf[cl->inbuf], 1) == 1) {
					cl->inbuf++;
				} else {
					perror("get_block_stx_read_failure");
				}
			}

			/* Check if blocksize bytes have been read in, if so, caclculate CRC 
			   and store it in the client's CRC attributes. Transition to check_block. */
			if (cl->inbuf == cl->blocksize) {
				read(cl->fd, &cl->crca, 1);
				read(cl->fd, &cl->crcb, 1);
				cl->state = check_block;
			}

		}
		break;

	case check_block:

		/* Reset buffer index after previous block */
		cl->inbuf = 0;

		/* If inverse block and current block don't corresond, write ACK and drop client */
		if ((255 - cl->inverse_block) != cl->current_block) {

			/* Set acker to the ACK control code and write it */
			acker = ACK;
			if (write(cl->fd, &acker, sizeof(char)) < 1) {
				perror("ACK failed to write in check_block for invalid inverse");
			}
			cl->state = finished;
		}

		/* If previous block and current block numbers are the same, ACK the second one */
		if (cl->previous_block == cl->current_block) {
			acker = ACK;
			if (write(cl->fd, &acker, sizeof(char)) < 1) {
				perror("ACK failed to write in check_block for duplicate blocks");
			}
		}

		/* If blocks are out of order, write ACK and drop client */
		if (cl->current_block != cl->previous_block + 1) {
			if ((cl->previous_block != 255) && (cl->current_block != 0)) {

				/* Set acker to the ACK control code and write it */
				acker = ACK;
				if (write(cl->fd, &acker, sizeof(char)) < 1) {
					perror("ACK failed to write in check_block for invalid block order");
				}
				cl->state = finished;
			}
		}

		/* If CRC's don't match up, send NAK */
		if (crc_message(XMODEM_KEY, cl->buf, cl->blocksize) != ((cl->crca << 8) + cl->crcb)) {

			/* Set acker to NAK and write it */
			acker = NAK;
			if (write(cl->fd, &acker, sizeof(char)) < 1) {
				perror("NAK failed to write in check_block for invalid CRC");
			}
		} else {
			/* If none of the above error checks are triggered */
			/* Set previous block to current, and account for wrapping at block number 
			   255 */
			cl->previous_block = cl->current_block;
			if ( cl->current_block > 255 ) {
				cl->current_block = 0;
			}
			/* Write the current payload in the client's buf attribute to the file */ 
			if (fwrite(&cl->buf, sizeof(char), cl->blocksize, cl->fp) < cl->blocksize) {
				perror("Writing payload to file failed"); 
			}

			/* Set acker to ACK and write it */
			acker = ACK;
			if (write(cl->fd, &acker, sizeof(char)) < 1) {
				perror("ACK failed to write in check_block file write stage");
			}

			/* Transition back to the pre_block */
			cl->state = pre_block;
		}
		break;
	case finished:
		cl->state = initial;
		break;
	
	default:
		printf("error status\n");
		break;
	}
	return 1;
}