Advertisement
Guest User

Untitled

a guest
Aug 31st, 2010
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.42 KB | None | 0 0
  1. /*
  2.  * main.c
  3.  *
  4.  *  Created on: Aug 28, 2010
  5.  *      Author: codeacula
  6.  */
  7.  
  8. #define BACKLOG 1024
  9. #define PORT "4400"
  10.  
  11. #include <arpa/inet.h>
  12. #include <netdb.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <sys/socket.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19.  
  20. // Server structure
  21. typedef struct {
  22.     struct addrinfo address;        // Address info
  23.     char buffer[1024];              // Read biffer
  24.     fd_set connections;             // Current connections
  25.     int connections_max;            // Max file descriptor
  26.     int listener;                   // Listener fd
  27.     int port;                       // The port for the server to listen on
  28.     struct addrinfo socket_hints;   // Server's socket hints
  29.     struct timeval socket_timeout;  // When should the socket timeout?
  30.     struct User *users;             // Currently connected users
  31. } Server;
  32.  
  33. // User structure
  34. typedef struct {
  35.     struct sockaddr_storage address;    // User's address
  36.     socklen_t address_length;           // Length of users address
  37.     int fs_id;                          // ID to the socket they belong to
  38.     char ip_address[INET6_ADDRSTRLEN];  // User's IP address
  39.     char *name;                         // Pointer to the user's name
  40.     struct User *nextUser;              // Next user in the list
  41. } User;
  42.  
  43. // Function prototypes
  44. void *get_address(struct sockaddr *);
  45. void handle_sockets(Server *);
  46. void initialize_server(Server *, char *, int);
  47.  
  48. /**
  49.  * Gets the IP address of the provided sockaddr
  50.  */
  51. void *get_address(struct sockaddr *address) {
  52.     if(address->sa_family == AF_INET) {
  53.         return &(((struct sockaddr_in*)address)->sin_addr);
  54.     }
  55.    
  56.     return &(((struct sockaddr_in6*)address)->sin6_addr);
  57. }
  58.  
  59. /**
  60.  * Handles sockets on the provided server
  61.  */
  62. void handle_sockets(Server *passed_server) {
  63.     int current_fd;             // Current file descriptor
  64.     int new_connection;         // Socket ID of new connections
  65.     fd_set read_sockets;        // Sockets to read from
  66.     FD_ZERO(&read_sockets);
  67.     struct timeval timeout;     // Sets the timeout for select
  68.    
  69.     // See if we have sockets to read
  70.     read_sockets = passed_server->connections;
  71.     timeout = passed_server->socket_timeout;
  72.     if(select(passed_server->connections_max+1, &read_sockets, NULL, NULL, &timeout) == -1) {
  73.         perror("Selecting sockets");
  74.         exit(1);
  75.     }
  76.    
  77.     // Loop through all of the sockets
  78.     for(current_fd = 0; current_fd <= passed_server->connections_max; current_fd++) {
  79.         if(!FD_ISSET(current_fd, &read_sockets)) {
  80.             continue;
  81.         }
  82.        
  83.         // Handle new connection
  84.         if(current_fd == passed_server->listener) {
  85.             User *new_user = malloc(sizeof *new_user);
  86.             memset(&new_user->address, 0, sizeof new_user->address);
  87.            
  88.             // Get the new address
  89.             new_user->address_length = sizeof new_user->address;
  90.             new_user->fs_id = accept(passed_server->listener, (struct sockaddr *)&new_user->address, &new_user->address_length);
  91.            
  92.             // Did we have an issue connecting?
  93.             if(new_user->fs_id == -1) {
  94.                 free(new_user);
  95.                 perror("Accepting new connection");
  96.                 continue;
  97.             }
  98.            
  99.             // Add the user socket to the master list
  100.             FD_SET(new_user->fs_id, &passed_server->connections);
  101.             if(new_user->fs_id > passed_server->connections_max) {
  102.                 passed_server->connections_max = new_user->fs_id;
  103.             }
  104.            
  105.             // Add the user to the list
  106.             if(passed_server->users == NULL) {
  107.                 passed_server->users = new_user;
  108.             } else {
  109.                 new_user->nextUser = passed_server->users;
  110.                 passed_server->users = new_user;
  111.             }
  112.            
  113.             // Let them know we got one!
  114.             printf("Server: New connection from %s on socket %d. Send hello.\n",
  115.                     inet_ntop(
  116.                             new_user->address.ss_family,
  117.                             get_address((struct sockaddr*)&new_user->address),
  118.                             new_user->ip_address,
  119.                             INET6_ADDRSTRLEN
  120.                     ),
  121.                     new_user->fs_id
  122.             );
  123.            
  124.             // Can we get to the user from the server?
  125.             //printf("Repeat, the IP address is %s\n", passed_server->users->ip_address);
  126.            
  127.             // Move on to the next file descriptor
  128.             continue;
  129.         }
  130.     }
  131. }
  132.  
  133. void initialize_server(Server *passed_server, char *port, int backlog) {
  134.     struct addrinfo *addresses; // Addresses the server can bind to
  135.     int status; // Get addrinfo status
  136.     int yes = 1; // Used for adding options to a socket
  137.    
  138.     // Clear out some fields
  139.     FD_ZERO(&passed_server->connections);
  140.     passed_server->users = NULL;
  141.    
  142.     passed_server->socket_timeout.tv_sec = 0;
  143.     passed_server->socket_timeout.tv_usec = 5000;
  144.    
  145.     // Set up the server hints
  146.     memset(&passed_server->socket_hints, 0, sizeof(passed_server->socket_hints));
  147.     passed_server->socket_hints.ai_family = AF_UNSPEC;
  148.     passed_server->socket_hints.ai_socktype = SOCK_STREAM;
  149.     passed_server->socket_hints.ai_flags = AI_PASSIVE;
  150.    
  151.     // Get a list of available places to connect
  152.     if((status = getaddrinfo(NULL, port, &passed_server->socket_hints, &addresses)) != 0) {
  153.         fprintf(stderr, "Error with getaddrinfo: %s\n", gai_strerror(status));
  154.     }
  155.    
  156.     // Go through returned addresses and attempt binding to one
  157.     for(; addresses != NULL; addresses = addresses->ai_next) {
  158.         // Try to create the socket
  159.         if((passed_server->listener = socket(addresses->ai_family, addresses->ai_socktype, addresses->ai_protocol)) == -1) {
  160.             perror("Creating server socket");
  161.             continue;
  162.         }
  163.        
  164.         // Set the socket option to reuse the address
  165.         if(setsockopt(passed_server->listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
  166.             perror("Setting socket option");
  167.             continue;
  168.         }
  169.        
  170.         // Bind the listener
  171.         if(bind(passed_server->listener, addresses->ai_addr, addresses->ai_addrlen) == -1) {
  172.             close(passed_server->listener);
  173.             perror("Binding server socket");
  174.             continue;
  175.         }
  176.        
  177.         break;
  178.     }
  179.    
  180.     // Did we fail to bind?
  181.     if(addresses == NULL) {
  182.         fprintf(stderr, "Server failed to bind socket to port %s", port);
  183.         exit(1);
  184.     } else {
  185.         puts("Socket bound. Setting listener.");
  186.     }
  187.    
  188.     // Free up addresses
  189.     freeaddrinfo(addresses);
  190.    
  191.     // Set the listener
  192.     if(listen(passed_server->listener, backlog) == -1) {
  193.         perror("Setting listener");
  194.         exit(1);
  195.     } else {
  196.         // Add the listener to the connection list
  197.         FD_SET(passed_server->listener, &passed_server->connections);
  198.         passed_server->connections_max = passed_server->listener;
  199.        
  200.         printf("Listener set! Listening on port %s.\n", port);
  201.     }
  202. }
  203.  
  204. int main(int argc, char** argv) {
  205.     // Set up socket stuff
  206.     Server *server = malloc(sizeof *server);
  207.    
  208.     if(server == NULL) {
  209.         fprintf(stderr, "Unable to allocate memory to the server instance!");
  210.     }
  211.     initialize_server(server, PORT, BACKLOG);
  212.  
  213.     // Enter main loop
  214.     for(;;) {
  215.         handle_sockets(server);
  216.     }
  217.     return (EXIT_SUCCESS);
  218. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement