Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * main.c
- *
- * Created on: Aug 28, 2010
- * Author: codeacula
- */
- #define BACKLOG 1024
- #define PORT "4400"
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <unistd.h>
- // Server structure
- typedef struct {
- struct addrinfo address; // Address info
- char buffer[1024]; // Read biffer
- fd_set connections; // Current connections
- int connections_max; // Max file descriptor
- int listener; // Listener fd
- int port; // The port for the server to listen on
- struct addrinfo socket_hints; // Server's socket hints
- struct timeval socket_timeout; // When should the socket timeout?
- struct User *users; // Currently connected users
- } Server;
- // User structure
- typedef struct {
- struct sockaddr_storage address; // User's address
- socklen_t address_length; // Length of users address
- int fs_id; // ID to the socket they belong to
- char ip_address[INET6_ADDRSTRLEN]; // User's IP address
- char *name; // Pointer to the user's name
- struct User *nextUser; // Next user in the list
- } User;
- // Function prototypes
- void *get_address(struct sockaddr *);
- void handle_sockets(Server *);
- void initialize_server(Server *, char *, int);
- /**
- * Gets the IP address of the provided sockaddr
- */
- void *get_address(struct sockaddr *address) {
- if(address->sa_family == AF_INET) {
- return &(((struct sockaddr_in*)address)->sin_addr);
- }
- return &(((struct sockaddr_in6*)address)->sin6_addr);
- }
- /**
- * Handles sockets on the provided server
- */
- void handle_sockets(Server *passed_server) {
- int current_fd; // Current file descriptor
- int new_connection; // Socket ID of new connections
- fd_set read_sockets; // Sockets to read from
- FD_ZERO(&read_sockets);
- struct timeval timeout; // Sets the timeout for select
- // See if we have sockets to read
- read_sockets = passed_server->connections;
- timeout = passed_server->socket_timeout;
- if(select(passed_server->connections_max+1, &read_sockets, NULL, NULL, &timeout) == -1) {
- perror("Selecting sockets");
- exit(1);
- }
- // Loop through all of the sockets
- for(current_fd = 0; current_fd <= passed_server->connections_max; current_fd++) {
- if(!FD_ISSET(current_fd, &read_sockets)) {
- continue;
- }
- // Handle new connection
- if(current_fd == passed_server->listener) {
- User *new_user = malloc(sizeof *new_user);
- memset(&new_user->address, 0, sizeof new_user->address);
- // Get the new address
- new_user->address_length = sizeof new_user->address;
- new_user->fs_id = accept(passed_server->listener, (struct sockaddr *)&new_user->address, &new_user->address_length);
- // Did we have an issue connecting?
- if(new_user->fs_id == -1) {
- free(new_user);
- perror("Accepting new connection");
- continue;
- }
- // Add the user socket to the master list
- FD_SET(new_user->fs_id, &passed_server->connections);
- if(new_user->fs_id > passed_server->connections_max) {
- passed_server->connections_max = new_user->fs_id;
- }
- // Add the user to the list
- if(passed_server->users == NULL) {
- passed_server->users = new_user;
- } else {
- new_user->nextUser = passed_server->users;
- passed_server->users = new_user;
- }
- // Let them know we got one!
- printf("Server: New connection from %s on socket %d. Send hello.\n",
- inet_ntop(
- new_user->address.ss_family,
- get_address((struct sockaddr*)&new_user->address),
- new_user->ip_address,
- INET6_ADDRSTRLEN
- ),
- new_user->fs_id
- );
- // Can we get to the user from the server?
- //printf("Repeat, the IP address is %s\n", passed_server->users->ip_address);
- // Move on to the next file descriptor
- continue;
- }
- }
- }
- void initialize_server(Server *passed_server, char *port, int backlog) {
- struct addrinfo *addresses; // Addresses the server can bind to
- int status; // Get addrinfo status
- int yes = 1; // Used for adding options to a socket
- // Clear out some fields
- FD_ZERO(&passed_server->connections);
- passed_server->users = NULL;
- passed_server->socket_timeout.tv_sec = 0;
- passed_server->socket_timeout.tv_usec = 5000;
- // Set up the server hints
- memset(&passed_server->socket_hints, 0, sizeof(passed_server->socket_hints));
- passed_server->socket_hints.ai_family = AF_UNSPEC;
- passed_server->socket_hints.ai_socktype = SOCK_STREAM;
- passed_server->socket_hints.ai_flags = AI_PASSIVE;
- // Get a list of available places to connect
- if((status = getaddrinfo(NULL, port, &passed_server->socket_hints, &addresses)) != 0) {
- fprintf(stderr, "Error with getaddrinfo: %s\n", gai_strerror(status));
- }
- // Go through returned addresses and attempt binding to one
- for(; addresses != NULL; addresses = addresses->ai_next) {
- // Try to create the socket
- if((passed_server->listener = socket(addresses->ai_family, addresses->ai_socktype, addresses->ai_protocol)) == -1) {
- perror("Creating server socket");
- continue;
- }
- // Set the socket option to reuse the address
- if(setsockopt(passed_server->listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- perror("Setting socket option");
- continue;
- }
- // Bind the listener
- if(bind(passed_server->listener, addresses->ai_addr, addresses->ai_addrlen) == -1) {
- close(passed_server->listener);
- perror("Binding server socket");
- continue;
- }
- break;
- }
- // Did we fail to bind?
- if(addresses == NULL) {
- fprintf(stderr, "Server failed to bind socket to port %s", port);
- exit(1);
- } else {
- puts("Socket bound. Setting listener.");
- }
- // Free up addresses
- freeaddrinfo(addresses);
- // Set the listener
- if(listen(passed_server->listener, backlog) == -1) {
- perror("Setting listener");
- exit(1);
- } else {
- // Add the listener to the connection list
- FD_SET(passed_server->listener, &passed_server->connections);
- passed_server->connections_max = passed_server->listener;
- printf("Listener set! Listening on port %s.\n", port);
- }
- }
- int main(int argc, char** argv) {
- // Set up socket stuff
- Server *server = malloc(sizeof *server);
- if(server == NULL) {
- fprintf(stderr, "Unable to allocate memory to the server instance!");
- }
- initialize_server(server, PORT, BACKLOG);
- // Enter main loop
- for(;;) {
- handle_sockets(server);
- }
- return (EXIT_SUCCESS);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement