Beispiel #1
0
void Server::run_clients() {
	for (int i = 0; i < m_maxclients; i++) {
		Client *client = &m_clients[i];

		if (!client->m_active) {
			continue;
		}

		if (!read_client_message(client)) {
			drop_client(client, false);
			continue;
		}

		if (!client->m_spawned) {
			memset(&client->m_cmd, 0, sizeof(client->m_cmd));
			continue;
		}

		if (!m_paused && (m_maxclients > 1)) {// || key_dest == key_game)) {
			client_think(client);
		}
	}
}
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;
            }

        }
    }

}
/*
 *  Loop forever handling clients as they come and go.
 *  Access to the framebuffer may be interleaved, if the user
 *  wants it that way.
 */
static void
main_loop(void)
{
    int	nopens = 0;
    int	ncloses = 0;

    while ( !fb_server_got_fb_free ) {
	long refresh_rate = 60000000; /* old default */
	fd_set infds;
	struct timeval tv;
	int	i;

	if (fb_server_fbp) {
	    if (fb_poll_rate(fb_server_fbp) > 0)
		refresh_rate = fb_poll_rate(fb_server_fbp);
	}

	infds = select_list;	/* struct copy */

	tv.tv_sec = 0L;
	tv.tv_usec = refresh_rate;
	if ((select( max_fd+1, &infds, (fd_set *)0, (fd_set *)0, (struct timeval *)&tv ) == 0)) {
	    /* Process fb events while waiting for client */
	    /*printf("select timeout waiting for client\n");*/
	    if (fb_server_fbp) {
		if (fb_poll(fb_server_fbp)) {
		    return;
		}
	    }
	    continue;
	}
	/* Handle any events from the framebuffer */
	if (fb_is_set_fd(fb_server_fbp, &infds)) {
	    fb_poll(fb_server_fbp);
	}

	/* Accept any new client connections */
	if (netfd > 0 && FD_ISSET(netfd, &infds)) {
	    new_client( pkg_getclient( netfd, fb_server_pkg_switch, comm_error, 0 ) );
	    nopens++;
	}

	/* Process arrivals from existing clients */
	/* First, pull the data out of the kernel buffers */
	for (i = MAX_CLIENTS-1; i >= 0; i--) {
	    if (clients[i] == NULL )  continue;
	    if (pkg_process( clients[i] ) < 0) {
		fprintf(stderr, "pkg_process error encountered (1)\n");
	    }
	    if (! FD_ISSET( clients[i]->pkc_fd, &infds )) continue;
	    if (pkg_suckin( clients[i] ) <= 0) {
		/* Probably EOF */
		drop_client( i );
		ncloses++;
		continue;
	    }
	}
	/* Second, process all the finished ones that we just got */
	for (i = MAX_CLIENTS-1; i >= 0; i--) {
	    if (clients[i] == NULL )  continue;
	    if (pkg_process( clients[i] ) < 0) {
		fprintf(stderr, "pkg_process error encountered (2)\n");
	    }
	}
	if (once_only && nopens > 1 && ncloses > 1)
	    return;
    }
}