first commit
This commit is contained in:
1
CS4210/cs4210/proj1/src/server/.cvsignore
Normal file
1
CS4210/cs4210/proj1/src/server/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
obj
|
||||
10
CS4210/cs4210/proj1/src/server/CVS/Entries
Normal file
10
CS4210/cs4210/proj1/src/server/CVS/Entries
Normal file
@@ -0,0 +1,10 @@
|
||||
/.cvsignore/1.1/Tue Jan 24 02:28:52 2006//
|
||||
/Makefile/1.8/Sat Feb 18 02:10:09 2006//
|
||||
/boss.c/1.11/Mon Feb 20 23:05:47 2006//
|
||||
/boss.h/1.4/Thu Feb 16 01:13:54 2006//
|
||||
/client.c/1.27/Mon Feb 20 23:05:47 2006//
|
||||
/client.h/1.4/Thu Feb 16 01:13:54 2006//
|
||||
/config.c/1.11/Mon Feb 20 16:00:58 2006//
|
||||
/config.h/1.7/Sat Feb 18 23:49:55 2006//
|
||||
/main.c/1.15/Sat Feb 18 23:49:55 2006//
|
||||
D
|
||||
1
CS4210/cs4210/proj1/src/server/CVS/Repository
Normal file
1
CS4210/cs4210/proj1/src/server/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj1/src/server
|
||||
1
CS4210/cs4210/proj1/src/server/CVS/Root
Normal file
1
CS4210/cs4210/proj1/src/server/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
106
CS4210/cs4210/proj1/src/server/Makefile
Normal file
106
CS4210/cs4210/proj1/src/server/Makefile
Normal file
@@ -0,0 +1,106 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Generic Makefile. Only need to modify the variables for src, obj,
|
||||
# and bin directories, and the name of the executable.
|
||||
#
|
||||
# $Author: vurazov $
|
||||
# $Date: 2006/02/18 02:10:09 $
|
||||
# $Revision: 1.8 $
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
|
||||
########################### Directories and Target ###########################
|
||||
# Source directory:
|
||||
SRC_DIR = .
|
||||
|
||||
# Object directory:
|
||||
OBJ_DIR = ./obj
|
||||
|
||||
# Executable directory:
|
||||
BIN_DIR = ../../bin
|
||||
|
||||
# The static libraries to link with the code:
|
||||
STATIC_LIBS = ../../bin/libcommon.a
|
||||
|
||||
# Name of the executable:
|
||||
BIN_NAME = server
|
||||
|
||||
|
||||
|
||||
######################## Compiler and Linker Options #########################
|
||||
# Compiler:
|
||||
CC = gcc
|
||||
|
||||
# Linker:
|
||||
LD = gcc
|
||||
|
||||
# Preprocessor flags:
|
||||
DFLAGS =
|
||||
|
||||
# Compiler flags:
|
||||
CFLAGS = -std=c99 -Wall -pedantic -O2 -I..
|
||||
|
||||
# Linker flags:
|
||||
LDFLAGS = -lpthread #-lsocket
|
||||
|
||||
|
||||
|
||||
############################ Other Programs Used #############################
|
||||
# Dependency generator:
|
||||
MDEPEND = $(CC) -M -I..
|
||||
|
||||
# Make Dir command:
|
||||
MKDIR = /bin/mkdir -p
|
||||
|
||||
# Clean-up command:
|
||||
RM = /bin/rm -f
|
||||
|
||||
|
||||
|
||||
######################### Automatic Object Variables #########################
|
||||
# The list of source files:
|
||||
SRCS = $(wildcard $(SRC_DIR)/*.c)
|
||||
|
||||
# Generated object files:
|
||||
OBJS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS))
|
||||
OBDS = $(patsubst $(SRC_DIR)/%.c,%.o,$(SRCS))
|
||||
|
||||
# Look for .o files in obj dir:
|
||||
vpath %.o $(OBJ_DIR)
|
||||
|
||||
# Program file:
|
||||
PROG = $(BIN_DIR)/$(BIN_NAME)
|
||||
|
||||
|
||||
|
||||
################################### Rules ####################################
|
||||
# Top-level rule: compile everything
|
||||
all: $(PROG)
|
||||
|
||||
# The program link rule:
|
||||
$(PROG): $(OBDS) $(BIN_DIR)
|
||||
$(LD) $(LDFLAGS) -o $(PROG) $(OBJS) $(STATIC_LIBS)
|
||||
|
||||
# Meta rule for compiling ".c" files
|
||||
%.o: $(SRC_DIR)/%.c $(OBJ_DIR)
|
||||
$(CC) $(CFLAGS) $(DFLAGS) -c -o $(OBJ_DIR)/$@ $<
|
||||
|
||||
# Rules for obj and bin dirs:
|
||||
$(OBJ_DIR):
|
||||
$(MKDIR) $(OBJ_DIR)
|
||||
$(BIN_DIR):
|
||||
$(MKDIR) $(BIN_DIR)
|
||||
|
||||
# Rule for cleaning up before a recompile:
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) $(PROG) $(OBJS) .depend
|
||||
|
||||
# Rule for creating dependency lists and writing them into a dependency file:
|
||||
.depend: $(SRCS)
|
||||
$(MDEPEND) $(SRCS) > .depend
|
||||
|
||||
#Include dependency list:
|
||||
include .depend
|
||||
118
CS4210/cs4210/proj1/src/server/boss.c
Normal file
118
CS4210/cs4210/proj1/src/server/boss.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/threading.h"
|
||||
|
||||
#include "boss.h"
|
||||
#include "client.h"
|
||||
|
||||
/* The id of the listening socket. */
|
||||
static socket_t m_listening_socket = -1;
|
||||
|
||||
/* Child count */
|
||||
static int child_count = 0;
|
||||
|
||||
/* List of child threads. */
|
||||
static pthread_t* m_children = NULL;
|
||||
|
||||
/* The queue of client sockets. */
|
||||
static queue_t m_client_sockets;
|
||||
|
||||
int boss_initialize(port_t pnum, int thread_count)
|
||||
{
|
||||
int index = 0;
|
||||
int result = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
/* Have to also initialize WinSock */
|
||||
WSADATA uselessData;
|
||||
result = WSAStartup(MAKEWORD(2, 2), &uselessData);
|
||||
if (result)
|
||||
{
|
||||
fprintf(stderr, "[BOSS] Could not initialize WinSock.\n");
|
||||
net_report_error();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
child_count = thread_count;
|
||||
|
||||
/* Make a listening socket: */
|
||||
m_listening_socket = net_listen_on_port(pnum);
|
||||
if (IS_BAD_SOCKET(m_listening_socket))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize the queue */
|
||||
queue_initialize(&m_client_sockets);
|
||||
|
||||
/* Spawn children threads. */
|
||||
m_children = (pthread_t*) calloc(thread_count, sizeof(pthread_t));
|
||||
if (!m_children)
|
||||
{
|
||||
fprintf(stderr, "[BOSS] Could not allocate memory.\n");
|
||||
net_report_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (index = 0; index < thread_count; index++)
|
||||
{
|
||||
result = pthread_create(m_children + index, NULL,
|
||||
client_run, &m_client_sockets);
|
||||
if (result)
|
||||
{
|
||||
fprintf(stderr, "[BOSS] Could not create child thread.\n");
|
||||
net_report_error();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* boss_run(void* param)
|
||||
{
|
||||
/* Loop infinitely accepting connections: */
|
||||
while (1)
|
||||
{
|
||||
/* Accept connection */
|
||||
socket_t client_socket = -1;
|
||||
sockaddress_t caddr;
|
||||
socklen_t sizeof_caddr = sizeof(sockaddress_t);
|
||||
|
||||
DEBUG_PRINTF(("[BOSS] Waiting for a client connection...\n"));
|
||||
|
||||
client_socket = accept(m_listening_socket,
|
||||
(struct sockaddr*) &caddr, &sizeof_caddr);
|
||||
if (IS_BAD_SOCKET(client_socket))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[BOSS] Could not accept client on listening socket\n");
|
||||
net_report_error();
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_PRINTF(("[BOSS] Got client on port %d.\n", ntohs(caddr.sin_port)));
|
||||
|
||||
/* Enqueue socket to be picked up by a client thread. */
|
||||
queue_enqueue(&m_client_sockets, (void*) client_socket);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int boss_clean()
|
||||
{
|
||||
/* Kill children */
|
||||
int index;
|
||||
for (index = 0; index < child_count; index++)
|
||||
{
|
||||
pthread_kill(m_children[index], SIGINT);
|
||||
}
|
||||
|
||||
DEBUG_PRINTF(("[BOSS] Shutting down...\n\n"));
|
||||
return net_close_socket(m_listening_socket);
|
||||
}
|
||||
31
CS4210/cs4210/proj1/src/server/boss.h
Normal file
31
CS4210/cs4210/proj1/src/server/boss.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef _BOSS_H_
|
||||
#define _BOSS_H_
|
||||
|
||||
#include "common/networking.h"
|
||||
|
||||
/*
|
||||
* Initializes the boss thread. pnum is the port number on which we
|
||||
* would like to start listening to connections. Returns zero upon
|
||||
* success and various numbers on failures. The thread_count parameter
|
||||
* is the number of child threads to spawn for handling requests.
|
||||
*/
|
||||
int boss_initialize(port_t pnum, int thread_count);
|
||||
|
||||
/*
|
||||
* This function loops infinitely and accepts connections, spawning
|
||||
* worker threads any time somebody wants to connect. Again, the
|
||||
* function will loop *infinitely*. The thread it runs in needs to be
|
||||
* killed explicitly. This is because the accept connection function
|
||||
* is blocking, so there is no way to kill the thread any way, without
|
||||
* using extreme methods.
|
||||
*/
|
||||
void* boss_run(void* param);
|
||||
|
||||
/*
|
||||
* Performs necessary clean-up of the boss thread code after the
|
||||
* buss_run function has been killed. Namely, closes the listening
|
||||
* socket, and such.
|
||||
*/
|
||||
int boss_clean();
|
||||
|
||||
#endif/*_BOSS_H_*/
|
||||
173
CS4210/cs4210/proj1/src/server/client.c
Normal file
173
CS4210/cs4210/proj1/src/server/client.c
Normal file
@@ -0,0 +1,173 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/http.h"
|
||||
#include "common/networking.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "config.h"
|
||||
|
||||
/* Returns true if the file exists, and false if it does not. */
|
||||
static int m_file_exists(const char* name)
|
||||
{
|
||||
struct stat buf;
|
||||
int result = !stat(name, &buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Converts the requested URI to a local file path for the file to
|
||||
* serve. If the URI is malformed, returns NULL, else returns the
|
||||
* local file path in a newly allocated string, which needs to be
|
||||
* freed eventually. */
|
||||
static char* m_uri_to_local(const char* uri)
|
||||
{
|
||||
char* result = NULL;
|
||||
|
||||
/* We don't like people who try to go up the directory hierarchy: */
|
||||
if (strstr(uri, "/.."))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We also don't like people who try to get funky with form parameters: */
|
||||
if (strstr(uri, "?"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We also don't like people who provide illegal paths containing
|
||||
double slashes: */
|
||||
if (strstr(uri, "//"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We also don't like people who try funny business with backslashes: */
|
||||
if (strstr(uri, "\\"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we are still here, I suppose we got a well-behaved request. */
|
||||
result = strcatd(result, config_get_home_dir());
|
||||
result = strcatd(result, uri);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Processes the request. First, parses the header to check what type
|
||||
* it is, and if it's a GET request, sends out the correct file to the
|
||||
* client. If any sort of error occurs, will send the correct response
|
||||
* to the client. */
|
||||
static void m_process_request(const char* header, socket_t socket)
|
||||
{
|
||||
char* req_file = NULL;
|
||||
char* local_file = NULL;
|
||||
FILE* input = NULL;
|
||||
|
||||
/* Get the request method: */
|
||||
const char* method = http_get_method(header);
|
||||
if (strcmp(method, HTTP_METHOD_GET))
|
||||
{
|
||||
/* Unsupported method: */
|
||||
fprintf(stderr, "[CLI] Unsupported method...\n"
|
||||
" Expected (%p) \"%s\"\n"
|
||||
" Got (%p) \"%s\"\n",
|
||||
HTTP_METHOD_GET, HTTP_METHOD_GET, method, method);
|
||||
http_send_canned_response(socket, HTTP_STATUS_NOTIMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the requested file: */
|
||||
req_file = http_get_requesturi(header);
|
||||
if (!req_file)
|
||||
{
|
||||
/* Could not parse the name out of the header: */
|
||||
http_send_canned_response(socket, HTTP_STATUS_BADREQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update the file name so it is relative to the document root in
|
||||
the local system: */
|
||||
local_file = m_uri_to_local(req_file);
|
||||
if (!local_file)
|
||||
{
|
||||
http_send_canned_response(socket, HTTP_STATUS_BADREQUEST);
|
||||
free(req_file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check whether the file exists: */
|
||||
if (!m_file_exists(local_file))
|
||||
{
|
||||
http_send_canned_response(socket, HTTP_STATUS_NOTFOUND);
|
||||
free(req_file);
|
||||
free(local_file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to open the file: */
|
||||
input = fopen(local_file, "r");
|
||||
if (!input)
|
||||
{
|
||||
http_send_canned_response(socket, HTTP_STATUS_FORBIDDEN);
|
||||
free(req_file);
|
||||
free(local_file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send the file: */
|
||||
http_send_header(socket, HTTP_STATUS_OK);
|
||||
http_send_text_file(socket, input);
|
||||
|
||||
/* Clean up: */
|
||||
free(req_file);
|
||||
free(local_file);
|
||||
fclose(input);
|
||||
}
|
||||
|
||||
static void m_handle_client(socket_t csocket)
|
||||
{
|
||||
/* Read the header: */
|
||||
char* header = http_read_header(csocket);
|
||||
|
||||
if (!header)
|
||||
{
|
||||
DEBUG_PRINTF(("[CLI] Did not get a header...\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Process the request: */
|
||||
m_process_request(header, csocket);
|
||||
|
||||
/* Free the header string: */
|
||||
free(header);
|
||||
|
||||
/* Clean up the socket: */
|
||||
DEBUG_PRINTF(("[CLI%d] Shutting down client socket.\n", csocket));
|
||||
net_close_socket(csocket);
|
||||
}
|
||||
|
||||
void* client_run(void* p)
|
||||
{
|
||||
queue_t* q = (queue_t*) p;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* This here needs to be done, else we will sometimes crash on
|
||||
server exit, when the lock in dequeue is killed before the
|
||||
client thread itself, and hence handle_client was called with
|
||||
an illegal socket. */
|
||||
socket_t client = -1;
|
||||
client = (socket_t) queue_dequeue(q);
|
||||
if (IS_BAD_SOCKET(client)) break;
|
||||
else m_handle_client(client);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
15
CS4210/cs4210/proj1/src/server/client.h
Normal file
15
CS4210/cs4210/proj1/src/server/client.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _CLIENT_H_
|
||||
#define _CLIENT_H_
|
||||
|
||||
#include "common/threading.h"
|
||||
|
||||
/*
|
||||
* This function will be started in a new thread at the beginning of
|
||||
* the program and will be passed a queue of client sockets that will
|
||||
* be populated by the boss thread. This function will spin
|
||||
* indefinitely consuming the sockets from the queue.
|
||||
*
|
||||
*/
|
||||
void* client_run(void* p);
|
||||
|
||||
#endif/*_CLIENT_H_*/
|
||||
96
CS4210/cs4210/proj1/src/server/config.c
Normal file
96
CS4210/cs4210/proj1/src/server/config.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Some default values */
|
||||
#define CONFIG_DVALUE_PORT 1337
|
||||
#define CONFIG_DVALUE_POOLSIZE 16
|
||||
#define CONFIG_DVALUE_HOMEDIR "."
|
||||
|
||||
/* Some parameter names */
|
||||
#define CONFIG_PNAME_PORT "port"
|
||||
#define CONFIG_PNAME_POOLSIZE "pool-size"
|
||||
#define CONFIG_PNAME_HOMEDIR "home"
|
||||
|
||||
/* The port number to run the server on. */
|
||||
static port_t m_server_port = -1;
|
||||
|
||||
/* The number of child threads to create. */
|
||||
static int m_pool_size = -1;
|
||||
|
||||
/* The root directory for the server's files. */
|
||||
static char* m_home_dir = NULL;
|
||||
|
||||
/* Records the parameter. If the name is unknown, prints a warning out
|
||||
* to the console and usage, and returns an error code. */
|
||||
int record_parameter(const char* name, const char* value)
|
||||
{
|
||||
if (!strcmp(name, CONFIG_PNAME_PORT))
|
||||
{
|
||||
/* Got port number: */
|
||||
m_server_port = atoi(value);
|
||||
printf("[CONF] Overriding default %s with value %d\n",
|
||||
CONFIG_PNAME_PORT, m_server_port);
|
||||
return 0;
|
||||
}
|
||||
else if(!strcmp(name, CONFIG_PNAME_POOLSIZE))
|
||||
{
|
||||
/* Got pool size: */
|
||||
m_pool_size = atoi(value);
|
||||
printf("[CONF] Overriding default %s with value %d\n",
|
||||
CONFIG_PNAME_POOLSIZE, m_pool_size);
|
||||
return 0;
|
||||
}
|
||||
else if(!strcmp(name, CONFIG_PNAME_HOMEDIR))
|
||||
{
|
||||
/* Got home dir: */
|
||||
free(m_home_dir);
|
||||
m_home_dir = strdup(value);
|
||||
printf("[CONF] Overriding default %s with value \"%s\"\n",
|
||||
CONFIG_PNAME_HOMEDIR, m_home_dir);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown parameter: */
|
||||
fprintf(stderr, "[CONF] Unknown parameter \"%s\"\n", name);
|
||||
config_print_parameters(stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void config_print_parameters(FILE* out)
|
||||
{
|
||||
fprintf(out, "Supported parameters:\n");
|
||||
fprintf(out, "\t%s - the port to listen on. Default value is %d.\n",
|
||||
CONFIG_PNAME_PORT, CONFIG_DVALUE_PORT);
|
||||
fprintf(out, "\t%s - the number of threads to pre-create to handle\n"
|
||||
"\t\tclient requests.\n"
|
||||
"\t\tDefault value is %d.\n",
|
||||
CONFIG_PNAME_POOLSIZE, CONFIG_DVALUE_POOLSIZE);
|
||||
fprintf(out, "\t%s - the root directory for the server's files."
|
||||
"\n\t\tDefault value is \"%s\".\n",
|
||||
CONFIG_PNAME_HOMEDIR, CONFIG_DVALUE_HOMEDIR);
|
||||
fprintf(out, "\t\n");
|
||||
}
|
||||
|
||||
int config_init(int argc, const char** argv)
|
||||
{
|
||||
/* Initialize default values: */
|
||||
m_server_port = CONFIG_DVALUE_PORT;
|
||||
m_pool_size = CONFIG_DVALUE_POOLSIZE;
|
||||
m_home_dir = strdup(CONFIG_DVALUE_HOMEDIR);
|
||||
|
||||
return parse_command_parameters(argc, argv, record_parameter);
|
||||
}
|
||||
|
||||
void config_free()
|
||||
{
|
||||
free(m_home_dir);
|
||||
}
|
||||
|
||||
port_t config_get_port() { return m_server_port; }
|
||||
int config_get_pool_size() { return m_pool_size; }
|
||||
const char* config_get_home_dir() { return m_home_dir; }
|
||||
31
CS4210/cs4210/proj1/src/server/config.h
Normal file
31
CS4210/cs4210/proj1/src/server/config.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef _SERVER_CONFIG_H_
|
||||
#define _SERVER_CONFIG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/networking.h"
|
||||
|
||||
/* Records the parameter with the given name and value. */
|
||||
int record_parameter(const char* name, const char* value);
|
||||
|
||||
/* Initializes the configuration with the parameters specified. */
|
||||
int config_init(int argc, const char** argv);
|
||||
|
||||
/* Cleans up whatever resources the configuration consumed. */
|
||||
void config_free();
|
||||
|
||||
/* Given a stream, will print the list of supported parameters to the
|
||||
* stream. */
|
||||
void config_print_parameters(FILE* out);
|
||||
|
||||
/* Returns the port to start the server on. */
|
||||
port_t config_get_port();
|
||||
|
||||
/* Returns the number of child threads to spawn for handling client
|
||||
* requests. */
|
||||
int config_get_pool_size();
|
||||
|
||||
/* Returns the root directory for the server's files. */
|
||||
const char* config_get_home_dir();
|
||||
|
||||
#endif/*_SERVER_CONFIG_H_*/
|
||||
69
CS4210/cs4210/proj1/src/server/main.c
Normal file
69
CS4210/cs4210/proj1/src/server/main.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/threading.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "boss.h"
|
||||
#include "config.h"
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
pthread_t thread_id;
|
||||
int result;
|
||||
|
||||
/* 0. Read configuration parameters: */
|
||||
if (config_init(argc, argv))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* 1. Initialize the boss: */
|
||||
result = boss_initialize(config_get_port(), config_get_pool_size());
|
||||
if (result)
|
||||
{
|
||||
config_free();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* 2. Run the boss thread: */
|
||||
result = pthread_create(&thread_id, NULL, boss_run, NULL);
|
||||
if (result)
|
||||
{
|
||||
fprintf(stderr, "[MAIN] Could not create boss thread. "
|
||||
"Error %d.\n\n", result);
|
||||
boss_clean();
|
||||
config_free();
|
||||
return result;
|
||||
}
|
||||
|
||||
printf("[MAIN] The server is now running.\n"
|
||||
" Hit ENTER key to kill the server.\n");
|
||||
|
||||
/* 3. Wait for the user to hit a key in the console to kill the thread: */
|
||||
result = getchar();
|
||||
|
||||
/* 4. If the user hit a key, means we should stop listening. Kill
|
||||
* the boss thread: */
|
||||
result = pthread_kill(thread_id, SIGINT);
|
||||
if (result)
|
||||
{
|
||||
fprintf(stderr, "[MAIN] Could not kill boss thread. "
|
||||
"Error %d.\n\n", result);
|
||||
}
|
||||
|
||||
/* 5. Clean up after ourselves: */
|
||||
result = boss_clean();
|
||||
|
||||
/* 6. Done! */
|
||||
config_free();
|
||||
if (result)
|
||||
{
|
||||
printf("[MAIN] Program terminated with errors.\n\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[MAIN] Program terminated cleanly.\n\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user