first commit

This commit is contained in:
Jose Caban
2025-06-07 01:59:34 -04:00
commit 388ac241f0
3558 changed files with 9116289 additions and 0 deletions

View File

@@ -0,0 +1 @@
bin

View File

@@ -0,0 +1,10 @@
/.cvsignore/1.1/Tue Feb 28 00:47:31 2006//
/Makefile/1.2/Tue Feb 28 00:52:18 2006//
/TODO/1.4/Mon Mar 27 04:52:40 2006//
/tester.pl/1.2/Mon Mar 27 21:07:03 2006//
D/docs////
D/home////
D/results////
D/src////
D/urls////
D/vs////

View File

@@ -0,0 +1 @@
cs4210/proj2

View File

@@ -0,0 +1 @@
/usr/_CVS

View File

@@ -0,0 +1,32 @@
##############################################################################
#
# This file will recursively call client and server makefiles to build
# those.
#
# $Author: vurazov $
# $Date: 2006/02/28 00:52:18 $
# $Revision: 1.2 $
#
##############################################################################
BUILD_DIRS = common client server proxy
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
RM = /bin/rm -rf
.PHONY: all clean touch $(BUILD_DIRS)
all: $(BUILD_DIRS)
$(BUILD_DIRS):
$(MAKE) -C src/$@
clean:
for dir in $(BUILD_DIRS); do $(MAKE) -C $(SRC_DIR)/$$dir clean; $(RM) $(SRC_DIR)/$$dir/$(OBJ_DIR); done
$(RM) $(BIN_DIR)
touch:
for dir in $(BUILD_DIRS); do touch $(SRC_DIR)/$$dir/*.* $(SRC_DIR)/$$dir/Makefile; done

14
CS4210/cs4210/proj2/TODO Normal file
View File

@@ -0,0 +1,14 @@
TODO:
o Check what the proxy should return when it can't get the host addr
or can't connect to host.
o Figure out why read_line only reads one line and returns NULL for
subsequent reads (perhaps this is only true for files?)
Done:
+ Kill client socket after sending stuff.
+ Add the Host header field to requests from the proxy to the server.

View File

@@ -0,0 +1,8 @@
/Project 2 Report.doc/1.6/Tue Mar 28 01:48:42 2006/-kb/
/Project2.pdf/1.1/Tue Feb 28 00:32:47 2006/-kb/
/data.xls/1.1/Mon Mar 27 22:39:21 2006/-kb/
/report.pdf/1.1/Tue Mar 28 01:48:42 2006/-kb/
/shmIntro.pdf/1.1/Tue Feb 28 00:32:47 2006/-kb/
/sysVipc.pdf/1.1/Tue Feb 28 00:32:47 2006/-kb/
/sysVshm.pdf/1.1/Tue Feb 28 00:32:47 2006/-kb/
D

View File

@@ -0,0 +1 @@
cs4210/proj2/docs

View File

@@ -0,0 +1 @@
/usr/_CVS

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,7 @@
/big.html/1.1/Tue Feb 28 03:19:57 2006//
/file.html/1.1/Tue Feb 28 03:19:57 2006//
/file2.html/1.1/Tue Feb 28 03:19:57 2006//
/medium.html/1.1/Tue Feb 28 03:19:57 2006//
/small.html/1.1/Tue Feb 28 03:19:57 2006//
/tiny.html/1.1/Tue Feb 28 03:19:57 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj2/home

View File

@@ -0,0 +1 @@
/usr/_CVS

1058816
CS4210/cs4210/proj2/home/big.html Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
<html>
Hello, world!
</html>

View File

@@ -0,0 +1,3 @@
<html>
You shouldn't be seeing this.
</html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,69 @@
<html>
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
This is small file.
</html>

View File

@@ -0,0 +1,3 @@
<html>
Hello, world!
</html>

View File

@@ -0,0 +1,9 @@
/noshare_bigfile_16x16x16_1000/1.1/Mon Mar 27 04:52:40 2006//
/noshare_multifile_16x16x16_1000/1.1/Mon Mar 27 04:52:41 2006//
/noshare_multifile_16x16x16_1000_noproxy/1.2/Mon Mar 27 21:44:02 2006//
/noshare_multifile_16x16x16_1000_proxy/1.2/Mon Mar 27 21:44:02 2006//
/noshare_multifile_16x16x16_16000_noproxy/1.2/Mon Mar 27 21:44:02 2006//
/noshare_multifile_16x16x16_16000_proxy/1.2/Mon Mar 27 21:44:02 2006//
/share_multifile_16x16x16_1000_proxy/1.2/Mon Mar 27 21:32:49 2006//
/share_multifile_16x16x16_16000_proxy/1.2/Mon Mar 27 21:32:49 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj2/results

View File

@@ -0,0 +1 @@
/usr/_CVS

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
bin/client job-count=1000 thread-count=16 < urls/noproxy_all
[MAIN] Initialization Complete. Starting work.
[CONF] Overriding default job-count with value 1000
[CONF] Overriding default thread-count with value 16
[JOBM] Got URL "http://localhost:1337/tiny.html"
[JOBM] Got URL "http://localhost:1337/small.html"
[JOBM] Got URL "http://localhost:1337/medium.html"
[JOBM] Got URL "http://localhost:1337/big.html"
[JOBM] Processed 4 URLs from file
Time: 3103.137980 ms.
Received: 539984250 bytes.
Throughtput: 174012323.460963 bps.
Connection Latency Stats:
Min: 0.035000 Avg: 3.706151 Max: 2999.678000
Std Dev: 94.941249
Time Per Connection:
Min: 0.577000 Avg: 40.818842 Max: 371.570000
Std Dev: 65.811161

View File

@@ -0,0 +1,21 @@
bin/client job-count=1000 thread-count=16 < urls/proxy_all
[MAIN] Initialization Complete. Starting work.
[CONF] Overriding default job-count with value 1000
[CONF] Overriding default thread-count with value 16
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/tiny.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/small.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/medium.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/big.html"
[JOBM] Processed 4 URLs from file
Time: 8205.640949 ms.
Received: 539984250 bytes.
Throughtput: 65806468.177163 bps.
Connection Latency Stats:
Min: 0.031000 Avg: 0.709019 Max: 35.929000
Std Dev: 2.206118
Time Per Connection:
Min: 3.318000 Avg: 71.263182 Max: 5044.910000
Std Dev: 313.812547

View File

@@ -0,0 +1,21 @@
bin/client job-count=16000 thread-count=16 < urls/noproxy_all
[MAIN] Initialization Complete. Starting work.
[CONF] Overriding default job-count with value 16000
[CONF] Overriding default thread-count with value 16
[JOBM] Got URL "http://localhost:1337/tiny.html"
[JOBM] Got URL "http://localhost:1337/small.html"
[JOBM] Got URL "http://localhost:1337/medium.html"
[JOBM] Got URL "http://localhost:1337/big.html"
[JOBM] Processed 4 URLs from file
Time: 43870.857895 ms.
Received: 8639748000 bytes.
Throughtput: 196935925.455775 bps.
Connection Latency Stats:
Min: 0.032000 Avg: 0.882995 Max: 4057.165000
Std Dev: 39.946996
Time Per Connection:
Min: 0.471000 Avg: 42.815996 Max: 18844.962000
Std Dev: 196.279405

View File

@@ -0,0 +1,21 @@
bin/client job-count=16000 thread-count=16 < urls/proxy_all
[MAIN] Initialization Complete. Starting work.
[CONF] Overriding default job-count with value 16000
[CONF] Overriding default thread-count with value 16
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/tiny.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/small.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/medium.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/big.html"
[JOBM] Processed 4 URLs from file
Time: 68219.190889 ms.
Received: 8639748000 bytes.
Throughtput: 126646884.658937 bps.
Connection Latency Stats:
Min: 0.032000 Avg: 0.581400 Max: 56.414000
Std Dev: 1.324274
Time Per Connection:
Min: 2.775000 Avg: 65.302097 Max: 5287.693000
Std Dev: 358.539683

View File

@@ -0,0 +1,21 @@
bin/client job-count=1000 thread-count=16 < urls/proxy_all
[MAIN] Initialization Complete. Starting work.
[CONF] Overriding default job-count with value 1000
[CONF] Overriding default thread-count with value 16
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/tiny.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/small.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/medium.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/big.html"
[JOBM] Processed 4 URLs from file
Time: 10444.705084 ms.
Received: 539984250 bytes.
Throughtput: 51699329.531950 bps.
Connection Latency Stats:
Min: 0.038000 Avg: 0.125532 Max: 9.837000
Std Dev: 0.550453
Time Per Connection:
Min: 3.821000 Avg: 105.220233 Max: 5202.148000
Std Dev: 404.754399

View File

@@ -0,0 +1,21 @@
bin/client job-count=16000 thread-count=16 < urls/proxy_all
[MAIN] Initialization Complete. Starting work.
[CONF] Overriding default job-count with value 16000
[CONF] Overriding default thread-count with value 16
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/tiny.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/small.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/medium.html"
[JOBM] Got URL "http://localhost:8080/http://localhost:1337/big.html"
[JOBM] Processed 4 URLs from file
Time: 88404.746049 ms.
Received: 8639748000 bytes.
Throughtput: 97729458.950428 bps.
Connection Latency Stats:
Min: 0.031000 Avg: 0.152694 Max: 51.629000
Std Dev: 1.209885
Time Per Connection:
Min: 2.589000 Avg: 85.538297 Max: 5556.825000
Std Dev: 409.622779

View File

@@ -0,0 +1,6 @@
D/client////
D/common////
D/proxy////
D/server////
D/tests////
D/tools////

View File

@@ -0,0 +1 @@
cs4210/proj2/src

View File

@@ -0,0 +1 @@
/usr/_CVS

View File

@@ -0,0 +1 @@
obj

View File

@@ -0,0 +1,12 @@
/.cvsignore/1.1/Tue Feb 28 00:39:12 2006//
/Makefile/1.1/Tue Feb 28 00:39:12 2006//
/config.c/1.1/Tue Feb 28 00:39:12 2006//
/config.h/1.1/Tue Feb 28 00:39:12 2006//
/job_manager.c/1.4/Mon Mar 27 23:56:43 2006//
/job_manager.h/1.1/Tue Feb 28 00:39:12 2006//
/main.c/1.2/Tue Feb 28 03:24:08 2006//
/stat.c/1.2/Tue Feb 28 00:43:16 2006//
/stat.h/1.1/Tue Feb 28 00:39:12 2006//
/worker.c/1.5/Fri Mar 24 18:08:49 2006//
/worker.h/1.1/Tue Feb 28 00:39:12 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj2/src/client

View File

@@ -0,0 +1 @@
/usr/_CVS

View 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/28 00:39:12 $
# $Revision: 1.1 $
#
##############################################################################
########################### 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 = client
######################## 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 -lm
############################ 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

View File

@@ -0,0 +1,116 @@
#include <stdio.h>
#include <stdlib.h>
#include "common/util.h"
#include "config.h"
#define CONFIG_PNAME_JOBCOUNT "job-count"
#define CONFIG_PNAME_WORKERCOUNT "thread-count"
#define CONFIG_PNAME_URLFILE "url-file"
#define CONFIG_PNAME_CONFIGFILE "config-file"
#define CONFIG_DVALUE_JOBCOUNT 1
#define CONFIG_DVALUE_WORKERCOUNT 1
#define CONFIG_DVALUE_URLFILE stdin
static int m_job_count = 0;
static int m_worker_count = 0;
static FILE* m_url_file = NULL;
static int m_read_config_file = 0;
int record_parameter(const char* name, const char* value)
{
if (!strcmp(name, CONFIG_PNAME_JOBCOUNT))
{
/* Got job count: */
m_job_count = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_JOBCOUNT, m_job_count);
return 0;
}
else if(!strcmp(name, CONFIG_PNAME_WORKERCOUNT))
{
/* Got worker count: */
m_worker_count = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_WORKERCOUNT, m_worker_count);
return 0;
}
else if(!strcmp(name, CONFIG_PNAME_URLFILE))
{
/* Got url file: */
m_url_file = fopen(value, "r");
if (m_url_file)
{
printf("[CONF] Overriding default %s with value \"%s\"\n",
CONFIG_PNAME_URLFILE, value);
return 0;
}
else
{
fprintf(stderr, "[CONF] Could not open URL file \"%s\"\n", value);
return 1;
}
}
else if(!strcmp(name, CONFIG_PNAME_CONFIGFILE))
{
/* Got config file name: */
if (!m_read_config_file)
{
m_read_config_file = 1;
return parse_file_parameters(fopen(value, "r"), record_parameter);
}
else
{
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 number of requests to make to the server.\n"
"\t\tDefault value is %d.\n",
CONFIG_PNAME_JOBCOUNT, CONFIG_DVALUE_JOBCOUNT);
fprintf(out, "\t%s - the number of threads to start for making requests.\n"
"\t\tDefault value is %d.\n",
CONFIG_PNAME_WORKERCOUNT, CONFIG_DVALUE_WORKERCOUNT);
fprintf(out, "\t%s - the name of the file from which to read the list of\n"
"\t\tURLs to request.\n"
"\t\tDefault value is stdin.\n",
CONFIG_PNAME_URLFILE);
fprintf(out, "\t%s - the name of a configuration file.\n",
CONFIG_PNAME_CONFIGFILE);
fprintf(out, "\t\n");
}
int config_init(int argc, const char** argv)
{
/* Initialize default values: */
m_job_count = CONFIG_DVALUE_JOBCOUNT;
m_worker_count = CONFIG_DVALUE_WORKERCOUNT;
m_url_file = CONFIG_DVALUE_URLFILE;
return parse_command_parameters(argc, argv, record_parameter);
}
void config_free()
{
if (m_url_file)
{
fclose(m_url_file);
}
}
int config_get_jobcount() { return m_job_count; }
int config_get_workercount() { return m_worker_count; }
FILE* config_get_urlfile() { return m_url_file; }

View File

@@ -0,0 +1,23 @@
#ifndef _CLIENT_CONFIG_H_
#define _CLIENT_CONFIG_H_
#include <stdio.h>
/* Records the parameter with the given name and value. */
int record_parameter(const char* name, const char* value);
/* Given a stream, will print the list of supported parameters to the
* stream. */
void config_print_parameters(FILE* out);
/* 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();
int config_get_jobcount();
int config_get_workercount();
FILE* config_get_urlfile();
#endif/*_CLIENT_CONFIG_H_*/

View File

@@ -0,0 +1,176 @@
#include <stdlib.h>
#include "common/debug.h"
#include "common/networking.h"
#include "common/queue.h"
#include "common/threading.h"
#include "common/util.h"
#include "job_manager.h"
/* The queue of jobs still to be done. */
static queue_t m_jobs;
static queue_t m_finished_jobs;
static int m_job_count = 0;
static job_t* joblist = NULL;
/* Condition GO */
static pthread_mutex_t go_mutex;
static pthread_cond_t go_cond;
/* I don't have the inclination to wade through code and figure out
* why read_line returns NULL after only one read, so I created this
* quick 'n dirty fix. Reads a line and returns it the old fashioned
* way.
*/
char *my_read_line(FILE* url_file)
{
char *buf = NULL;
if (NULL == (buf = (char*) calloc(256, sizeof(char))))
{
printf("[JOBM] ran out of memory reading urlfile\n");
return NULL;
}
if (fgets(buf, 256, url_file) == NULL)
{
return NULL;
}
return buf;
}
/* Reads the list of URLs from the file and puts them in the queue. */
static void m_read_job_list(queue_t* queue, FILE* url_file)
{
char* url = NULL;
int count = 0;
while ((url = my_read_line(url_file)) != NULL)
{
char* newline = strchr(url, '\n');
sockaddress_t address;
char* path;
char* host;
port_t port;
if (newline) {
*newline = '\0';
}
if (strlen(url) < 1)
{
free(url);
continue;
}
if (parse_url(url, &host, &port, &path))
{
fprintf(stderr, "[JOBS] Got bad url \"%s\"\n", url);
free(url);
continue;
}
else if (net_get_hostaddr(&address, host, port))
{
fprintf(stderr, "[JOBS] Got bad url \"%s\"\n", url);
free(url);
continue;
}
else
{
queue_enqueue(queue, (void*) job_new(address, path));
}
printf("[JOBM] Got URL \"%s\"\n", url);
free(url);
free(host);
count++;
}
printf("[JOBM] Processed %d URLs from file\n", count);
}
void jobs_init(int job_count, FILE* url_file)
{
int i;
queue_t urls;
queue_iterator_t url_iter;
joblist = (job_t*) calloc(job_count, sizeof(job_t));
if (!joblist)
{
fprintf(stderr, "[JOBS] Could not allocate space for enough jobs.\n");
exit(1);
}
pthread_mutex_init(&go_mutex, NULL);
pthread_cond_init(&go_cond, NULL);
queue_initialize(&m_jobs);
queue_initialize(&m_finished_jobs);
queue_initialize(&urls);
m_read_job_list(&urls, url_file);
for (i = 0, iterator_initialize(&url_iter, &urls, 1); i < job_count; i++)
{
job_t* proto_job = (job_t*) iterator_next(&url_iter);
queue_enqueue(&m_jobs, job_init(joblist + i,
proto_job->address, proto_job->path));
}
m_job_count = job_count;
queue_free(&urls); /* TODO: Free the actual proto-jobs inside. */
}
int jobs_remaining()
{
return m_job_count;
}
job_t* jobs_get()
{
return (job_t*) queue_dequeue_nb(&m_jobs);
}
void jobs_complete_job(job_t* job)
{
queue_enqueue(&m_finished_jobs, job);
}
void jobs_clean()
{
}
queue_t* jobs_completed()
{
return &m_finished_jobs;
}
job_t* job_new(sockaddress_t address, char* path)
{
job_t* result = (job_t*) calloc(1, sizeof(job_t));
if (!result)
{
return NULL;
}
return job_init(result, address, path);
}
job_t* job_init(job_t* job, sockaddress_t address, char* path)
{
job->address = address;
job->path = path;
return job;
}
void jobs_wait_to_start()
{
pthread_cond_wait(&go_cond, &go_mutex);
}
void jobs_signal_start()
{
pthread_cond_broadcast(&go_cond);
}

View File

@@ -0,0 +1,54 @@
#ifndef _JOB_MANAGER_H_
#define _JOB_MANAGER_H_
#include <stdio.h>
#include "common/networking.h"
#include "common/queue.h"
typedef struct
{
sockaddress_t address;
char* path;
/* Number of milliseconds to establish connection. */
double connection_latency;
double data_time;
long bytes_received;
} job_t;
/* Initializes the job list. The job_count parameter is the number of jobs to
create, and the url_file is a file that contains the list of URLs, one per
line, to fetch. */
void jobs_init(int job_count, FILE* url_file);
/* Returns the number of jobs remaining to be completed. */
int jobs_remaining();
/* If there are more jobs to be completed, returns the job. Otherwise, returns
NULL. */
job_t* jobs_get();
/* Marks the job as complete. */
void jobs_complete_job(job_t* job);
queue_t* jobs_completed();
/* Frees the resources associated with the job manager. */
void jobs_clean();
/* Allocates a new job, and fills it in with the parameters specified. Returns
NULL, if there was an error. */
job_t* job_new(sockaddress_t address, char* path);
job_t* job_init(job_t* job, sockaddress_t address, char* path);
/* Calling this function will have the current thread wait untill we are ready
to start processing jobs. */
void jobs_wait_to_start();
/* Calling this function will broadcast to all threads that we are ready to
start processing the jobs. */
void jobs_signal_start();
#endif/*_JOB_MANAGER_H_*/

View File

@@ -0,0 +1,81 @@
#include <stdio.h>
#include <stdlib.h>
#include "common/threading.h"
#include "common/timer.h"
#include "common/util.h"
#include "config.h"
#include "job_manager.h"
#include "stat.h"
#include "worker.h"
double get_job_conn_latency(void* j)
{ return ((job_t*) j)->connection_latency; }
double get_job_data_latency(void* j)
{ return ((job_t*) j)->data_time; }
double get_job_bytes(void* j)
{ return ((job_t*) j)->bytes_received; }
int main(int argc, const char** argv) {
time_span_t total;
stat_t connstats;
stat_t datastats;
double total_time;
long long total_bytes;
/* Initialize configuration: */
if (config_init(argc, argv))
{
return 1;
}
/* Initialize network: */
if (net_initialize())
{
return 1;
}
jobs_init(config_get_jobcount(), config_get_urlfile());
if (workers_initialize(config_get_workercount()))
{
exit(1);
}
timer_start(&total);
fprintf(stderr, "[MAIN] Initialization Complete. Starting work.\n");
fflush(stderr);
jobs_signal_start();
wait_for_workers();
timer_stop(&total);
fflush(stdout);
fflush(stderr);
total_time = timer_span(&total);
total_bytes = stat_sum(jobs_completed(), get_job_bytes);
fprintf(stderr, "Time: %f ms.\n", total_time);
fprintf(stderr, "Received: %lld bytes.\n", (long long) total_bytes);
fprintf(stderr, "Throughtput: %f bps.\n", 1000 * total_bytes / total_time);
fprintf(stderr, "\n");
stat_compute(&connstats, jobs_completed(), get_job_conn_latency);
stat_compute(&datastats, jobs_completed(), get_job_data_latency);
fprintf(stderr, "Connection Latency Stats:\n");
stat_print(&connstats, stderr);
fprintf(stderr, "\n");
fprintf(stderr, "Time Per Connection:\n");
stat_print(&datastats, stderr);
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,74 @@
#include <math.h>
#include "stat.h"
static inline double min(double a, double b)
{
return (a < b) ? a : b;
}
static inline double max(double a, double b)
{
return (a > b) ? a : b;
}
void stat_compute(stat_t* s, queue_t* q, value_func v)
{
queue_iterator_t i;
void* item;
iterator_initialize(&i, q, 0);
item = iterator_next(&i);
if (item)
{
double c = v(item);
s->min = c;
s->mean = c;
s->stdev = c;
s->max = c;
s->count = 1;
}
else
{
s->min = 0.0;
s->mean = 0.0;
s->stdev = 0.0;
s->max = 0.0;
s->count = 0;
}
while ((item = iterator_next(&i)) != NULL)
{
double c = v(item);
s->min = min(s->min, c);
s->mean += c;
s->stdev += c * c;
s->max = max(s->max, c);
s->count ++;
}
s->mean /= s->count;
s->stdev = sqrt((s->stdev / s->count) - s->mean * s->mean);
}
long long stat_sum(queue_t* q, value_func v)
{
long long result = 0;
void* item;
queue_iterator_t i;
iterator_initialize(&i, q, 0);
while ((item = iterator_next(&i)) != NULL)
{
result += (long long) v(item);
}
return result;
}
void stat_print(stat_t* s, FILE* stream)
{
fprintf(stream, "Min: %f\tAvg: %f\tMax: %f\n", s->min, s->mean, s->max);
fprintf(stream, "Std Dev: %f\n", s->stdev);
}

View File

@@ -0,0 +1,28 @@
#ifndef _STAT_H_
#define _STAT_H_
#include <stdio.h>
#include "common/queue.h"
typedef struct
{
double min;
double mean;
double stdev;
double max;
int count;
} stat_t;
typedef double(*value_func)(void*);
/* Fills in the structure s with the statistics about the values gotten from each element of q with function v. */
void stat_compute(stat_t* s, queue_t* q, value_func v);
/* Returns a sum of values over the whole q. */
long long stat_sum(queue_t* q, value_func v);
void stat_print(stat_t* s, FILE* stream);
#endif/*_STAT_H_*/

View File

@@ -0,0 +1,160 @@
#include <stdlib.h>
#include "common/channel.h"
#include "common/debug.h"
#include "common/http.h"
#include "common/networking.h"
#include "common/timer.h"
#include "common/threading.h"
#include "common/util.h"
#include "job_manager.h"
#include "worker.h"
#define BUFFER_SIZE 256
static int m_worker_count;
static pthread_mutex_t worker_count_mutex;
static pthread_cond_t all_done_cond;
/* List of child threads. */
static pthread_t* m_children = NULL;
int workers_initialize(int thread_count)
{
int index;
int result;
m_worker_count = thread_count;
pthread_mutex_init(&worker_count_mutex, NULL);
pthread_cond_init(&all_done_cond, NULL);
/* Spawn children threads. */
m_children = (pthread_t*) calloc(thread_count, sizeof(pthread_t));
if (!m_children)
{
fprintf(stderr, "[WORK] Could not allocate memory.\n");
return 1;
}
for (index = 0; index < thread_count; index++)
{
result = pthread_create(m_children + index, NULL,
worker_run, NULL);
if (result)
{
fprintf(stderr, "[WORK] Could not create child thread.\n");
return result;
}
}
return 0;
}
static void m_read_response(job_t* job, socket_t sock)
{
char buffer[BUFFER_SIZE];
int bytes_received = 0;
time_span_t timer;
channel_t server;
ch_init_sock(&server, &sock);
timer_start(&timer);
/* First, send the header to the server: */
if (http_send_request_header(&server, HTTP_METHOD_GET, job->path, NULL))
{
job->data_time = -1;
return;
}
/* Now, receive stuff from the server: */
/* TODO: Check response status? */
do
{
bytes_received = ch_read(&server, buffer, BUFFER_SIZE);
job->bytes_received += bytes_received;
} while (bytes_received > 0);
timer_stop(&timer);
job->data_time = timer_span(&timer);
DEBUG_PRINTF(("[WORK] Job %p took %f ms.\n", job, job->data_time));
}
static socket_t m_establish_connection(job_t* job)
{
time_span_t connection_latency;
socket_t result = 0;
timer_start(&connection_latency);
result = net_open_data_socket(&(job->address));
timer_stop(&connection_latency);
if (IS_BAD_SOCKET(result))
{
/* Could not open socket: */
fprintf(stderr, "[WORK] Could not open socket to the server.\n");
job->connection_latency = -1;
}
else
{
job->connection_latency = timer_span(&connection_latency);
}
return result;
}
static void m_process_job(job_t* job)
{
socket_t sock = m_establish_connection(job);
if (IS_BAD_SOCKET(sock))
{
return;
}
m_read_response(job, sock);
net_close_socket(sock);
}
void* worker_run(void* p)
{
job_t* cjob = NULL;
DEBUG_PRINTF(("[WORK] Waiting for GO signal.\n"));
/* jobs_wait_to_start();*/
DEBUG_PRINTF(("[WORK] All systems GO.\n"));
while ((cjob = jobs_get()) != NULL)
{
DEBUG_PRINTF(("[WORK] Starting job %p\n", cjob));
m_process_job(cjob);
jobs_complete_job(cjob);
DEBUG_PRINTF(("[WORK] Finished job %p\n\n", cjob));
}
pthread_mutex_lock(&worker_count_mutex);
m_worker_count --;
if (m_worker_count < 1)
{
pthread_cond_broadcast(&all_done_cond);
}
pthread_mutex_unlock(&worker_count_mutex);
return NULL;
}
void wait_for_workers()
{
pthread_mutex_lock(&worker_count_mutex);
pthread_cond_wait(&all_done_cond, &worker_count_mutex);
pthread_mutex_unlock(&worker_count_mutex);
}

View File

@@ -0,0 +1,14 @@
#ifndef _WORKER_H_
#define _WORKER_H_
/* Initializes the number of workers specified. */
int workers_initialize(int thread_count);
/* The worker will attack the queue of jobs to completed and while there are
more jobs to be peformed will do them. */
void* worker_run(void* p);
/* This function will wait until all workers are done. */
void wait_for_workers();
#endif/*_WORKER_H_*/

View File

@@ -0,0 +1,22 @@
/Makefile/1.6/Mon Mar 27 21:07:03 2006//
/channel.c/1.4/Mon Mar 27 21:07:03 2006//
/channel.h/1.2/Wed Mar 22 00:10:57 2006//
/data.h/1.3/Thu Mar 23 19:37:19 2006//
/debug.h/1.3/Mon Mar 27 21:07:03 2006//
/dispatcher.c/1.3/Thu Mar 23 19:52:07 2006//
/dispatcher.h/1.1/Thu Mar 9 17:47:04 2006//
/http.c/1.14/Thu Mar 23 19:07:04 2006//
/http.h/1.10/Thu Mar 23 19:07:04 2006//
/networking.c/1.12/Thu Mar 23 19:07:04 2006//
/networking.h/1.7/Tue Mar 21 23:42:58 2006//
/queue.c/1.1/Tue Feb 28 00:39:12 2006//
/queue.h/1.1/Tue Feb 28 00:39:12 2006//
/semaphore.c/1.7/Tue Mar 21 18:43:11 2006//
/semaphore.h/1.5/Thu Mar 23 19:07:04 2006//
/shared_memory.c/1.20/Thu Mar 23 19:52:07 2006//
/shared_memory.h/1.8/Thu Mar 23 19:07:04 2006//
/threading.h/1.1/Tue Feb 28 00:39:12 2006//
/timer.h/1.1/Tue Feb 28 00:39:12 2006//
/util.c/1.4/Fri Mar 24 18:08:49 2006//
/util.h/1.7/Wed Mar 22 00:10:57 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj2/src/common

View File

@@ -0,0 +1 @@
/usr/_CVS

View File

@@ -0,0 +1,103 @@
##############################################################################
#
# Generic Makefile. Only need to modify the variables for src, obj,
# and bin directories, and the name of the executable.
#
# $Author: crono $
# $Date: 2006/03/27 21:07:03 $
# $Revision: 1.6 $
#
##############################################################################
########################### Directories and Target ###########################
# Source directory:
SRC_DIR = .
# Object directory:
OBJ_DIR = ./obj
# Executable directory:
BIN_DIR = ../../bin
# Name of the executable:
BIN_NAME = common
######################## Compiler and Linker Options #########################
# Compiler:
CC = gcc
# Linker:
LD = ar
# Preprocessor flags:
DFLAGS =
# Compiler flags:
CFLAGS = -Wall -pedantic -std=gnu99 -O2
# Linker flags:
LDFLAGS = rcs
############################ Other Programs Used #############################
# Dependency generator:
MDEPEND = $(CC) -M
# 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)/lib$(BIN_NAME).a
################################### Rules ####################################
# Top-level rule: compile everything
all: $(PROG)
# The program link rule:
$(PROG): $(OBDS) $(BIN_DIR)
$(LD) $(LDFLAGS) $(PROG) $(OBJS)
# 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

View File

@@ -0,0 +1,146 @@
#include "channel.h"
#include "debug.h"
#include "util.h"
#define BUFFER_SIZE 2048
/********************************** FILE **********************************/
static size_t m_file_read (void* channel, char* data, size_t length)
{
return fread(data, 1, length, (FILE*) channel);
}
static size_t m_file_write (void* channel, const char* data, size_t length)
{
return fwrite(data, 1, length, (FILE*) channel);
}
void ch_init_file(channel_t* ch, FILE* stream)
{
ch->channel = stream;
ch->read = m_file_read;
ch->write = m_file_write;
}
/********************************* SOCKET *********************************/
static size_t m_sock_read (void* channel, char* data, size_t length)
{
return recv(*((socket_t*) channel), data, (int) length, 0);
}
static size_t m_sock_write (void* channel, const char* data, size_t length)
{
return send(*((socket_t*) channel), data, (int) length, 0);
}
void ch_init_sock(channel_t* ch, socket_t* sock)
{
ch->channel = sock;
ch->read = m_sock_read;
ch->write = m_sock_write;
}
/******************************* SHARED MEM *******************************/
static size_t m_shmem_read (void* channel, char* data, size_t length)
{
return sharedmem_read((shared_memory_t*) channel, data, length);
}
static size_t m_shmem_write (void* channel, const char* data, size_t length)
{
return sharedmem_write((shared_memory_t*) channel, data, length);
}
void ch_init_shmem(channel_t* ch, shared_memory_t* shm)
{
ch->channel = shm;
ch->read = m_shmem_read;
ch->write = m_shmem_write;
}
/********************************* GENERIC ********************************/
size_t ch_route(channel_t* from, channel_t* to, size_t length)
{
char data[BUFFER_SIZE];
size_t bytes_read = 0;
size_t bytes_written = 0;
size_t result = 0;
/* If length is zero, make it infinity: */
if (length < 1) { length = ~0; }
/* Loop until we read the desired amount: */
while (result < length)
{
size_t to_read = length - result;
/* Read some data: */
bytes_read = ch_read(from, data, min(BUFFER_SIZE, to_read));
if (bytes_read < 1) break;
/* Write the data: */
bytes_written = 0;
while (bytes_written < bytes_read)
{
size_t wrote = ch_write(to, data, bytes_read);
if (wrote < 1) return result;
bytes_written += wrote;
result += wrote;
}
}
return result;
}
char* ch_read_until(channel_t* ch, const char* str)
{
char* result = NULL;
size_t bytes_read = 0;
char buffer[BUFFER_SIZE];
while ((bytes_read = ch_read(ch, buffer, BUFFER_SIZE - 1)) > 0)
{
char* sub = NULL;
/* Append read data: */
buffer[bytes_read] = '\0';
result = strcatd(result, buffer);
/* Look for terminating substring: */
sub = strstr(result, str);
if (sub)
{
sub[strlen(str)] = '\0';
break;
}
}
return result;
}
int ch_write_string(channel_t* ch, const char* str)
{
size_t to_write = strlen(str);
size_t written = 0;
DEBUG_PRINTF(("[CHN] Sending string:\n \"%s\"\n", str));
while(written < to_write)
{
size_t wrote = ch_write(ch, str, to_write - written);
if (wrote < 1) return 1;
written += wrote;
}
return 0;
}

View File

@@ -0,0 +1,69 @@
/* \file channel.h
* Here, we define an abstraction for communication channels. Essentially, we
* want to be able to read and write into files, sockets, and shared memory
* using the same interface. That's what the stuff in this header file is an
* interface for.
*/
#ifndef _CHANNEL_H_
#define _CHANNEL_H_
#include <stdio.h>
#include "networking.h"
#include "shared_memory.h"
/* Read from channel function type. */
typedef size_t (*read_func) (void* channel, char* data, size_t length);
/* Write to channel function type. */
typedef size_t (*write_func) (void* channel, const char* data, size_t length);
typedef struct
{
void* channel;
read_func read;
write_func write;
} channel_t;
/* Initializes a file channel. */
void ch_init_file(channel_t* ch, FILE* stream);
/* Initializes a socket channel. */
void ch_init_sock(channel_t* ch, socket_t* sock);
/* Initializes a shmem channel. */
void ch_init_shmem(channel_t* ch, shared_memory_t* shm);
/* Read data from the channel into data. At most length bytes are read. The
* number of bytes read is returned. */
static inline size_t ch_read(channel_t* ch, char* data, size_t length)
{
return ch->read(ch->channel, data, length);
}
/* Write data into the channel from the data pointer. At most length bytes are
* written. The number of bytes written is returned. Note that if the number
* of bytes written is less than the maximum, that does not indicate failure,
* but could be due to the limitations of the channel. Also, the output is not
* buffered, so if fewer than length bytes are written, the caller must handle
* it himself that no data is lost at the next write. */
static inline size_t ch_write(channel_t* ch, const char* data, size_t length)
{
return ch->write(ch->channel, data, length);
}
/* Routes data from channel from to channel to. At most length bytes are
* routed. If the length parameter is zero, then data is routed until we can't
* read from from any more (the read function returns zero for bytes
* read). Returns the total number of bytes transferred. */
size_t ch_route(channel_t* from, channel_t* to, size_t length);
/* Reads from the channel until the string passed in is encountered, or
* nothing more can be read. Returns the result in a newly allocated
* string. */
char* ch_read_until(channel_t* ch, const char* str);
/* Writes the string passed in to the channel. Returns 0 if the whole string
* was written successfully, and an error code if an error occured. */
int ch_write_string(channel_t* ch, const char* str);
#endif/*_CHANNEL_H_*/

View File

@@ -0,0 +1,13 @@
/* \file data.h
* Alright, so I caved in hardcoded some data shared by the server and proxy,
* for time reasons. So here it all is.
*/
#ifndef _SP_DATA_H_
#define _SP_DATA_H_
/* The name of the shared memory location which will be used by the server to
* tell people it is running. */
#define SHNAME_SERVER_RUNNING "5691582"
#endif/*_SP_DATA_H_*/

View File

@@ -0,0 +1,14 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef DEBUG
#undef DEBUG
#endif
#ifdef DEBUG
#define DEBUG_PRINTF(x) printf x
#else
#define DEBUG_PRINTF(x)
#endif
#endif/*__DEBUG_H__*/

View File

@@ -0,0 +1,141 @@
#include <stdio.h>
#include "debug.h"
#include "dispatcher.h"
#include "queue.h"
#include "threading.h"
/* The id of the listening socket. */
static socket_t m_listening_socket = -1;
/* The dispatcher thread. */
static pthread_t m_main_thread;
/* Worker count. */
static int m_worker_count = 0;
/* The worker function. */
static workerfunc m_worker_f;
/* List of worker threads. */
static pthread_t* m_workers = NULL;
/* The queue of waiting sockets. */
static queue_t m_waiting_sockets;
/* Dispatcher run function. This function loops infinitely and accepts
* connections, giving workers something to work with whenever someone
* connects on the socket. 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* m_dispatcher_run(void* p)
{
/* 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(("[DISP] 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,
"[DISP] Could not accept client on listening socket\n");
net_report_error();
continue;
}
DEBUG_PRINTF(("[DISP] Got client on port %d.\n", ntohs(caddr.sin_port)));
/* Enqueue socket to be picked up by a client thread. */
queue_enqueue(&m_waiting_sockets, (void*) client_socket);
}
return NULL;
}
int dispatcher_initialize(port_t port, int worker_count, workerfunc f)
{
m_worker_count = worker_count;
m_worker_f = f;
/* Make a listening socket: */
m_listening_socket = net_listen_on_port(port);
if (IS_BAD_SOCKET(m_listening_socket))
{
fprintf(stderr, "[DISP] Could not open listening socket.");
return 1;
}
/* Initialize the queue */
queue_initialize(&m_waiting_sockets);
/* Allocate children threads. */
m_workers = (pthread_t*) calloc(worker_count, sizeof(pthread_t));
if (!m_workers)
{
fprintf(stderr,
"[DISP] Could not allocate memory for worker threads.\n");
return 1;
}
return 0;
}
int dispatcher_start()
{
int index = 0;
int result = 0;
/* Start boss thread: */
result = pthread_create(&m_main_thread, NULL, m_dispatcher_run, NULL);
if (result)
{
fprintf(stderr, "[DISP] Could not start dispatcher thread.\n");
return result;
}
/* Start worker threads: */
for (index = 0; index < m_worker_count; index++)
{
result = pthread_create(m_workers + index, NULL,
m_worker_f, &m_waiting_sockets);
if (result)
{
fprintf(stderr, "[DISP] Could not start worker thread.\n");
return result;
}
}
return 0;
}
int dispatcher_stop()
{
int index;
int result;
/* Kill children */
for (index = 0; index < m_worker_count; index++)
{
DEBUG_PRINTF(("[DISP] Killing child #%d... ", index));
result = pthread_kill(m_workers[index], SIGINT);
DEBUG_PRINTF(("%s\n", (result) ? (perror("Error"),"") : ("Done")));
}
/* Kill self */
DEBUG_PRINTF(("[DISP] Killing boss... "));
result = pthread_kill(m_main_thread, SIGINT);
DEBUG_PRINTF(("%s\n", (result) ? (perror("Error"),"") : ("Done")));
free(m_workers);
return 0;
}

View File

@@ -0,0 +1,33 @@
/** \file dispatcher.h
* Contains the declarations for the dispatcher functionality. It is
* basically a separate thread that spins infinitely listening for
* connections on a specified port, and dispatching incoming
* connections to the specified worker threads.
*/
#ifndef _DISPATCHER_H_
#define _DISPATCHER_H_
#include "networking.h"
/* Worker function that the worker threads will be started with. */
typedef void*(*workerfunc)(void*);
/*
* Initializes the dispatcher. pnum is the port number on which we
* would like to start listening to connections. The worker_count
* parameter is the number of worker threads to spawn for handling
* requests. f is the run function for worker threads. Returns zero
* upon success and various numbers on failures.
*/
int dispatcher_initialize(port_t port, int worker_count, workerfunc f);
/* Starts up the dispatcher and worker threads. Returns zero on
* success, and error numbers on errors. */
int dispatcher_start();
/* Stops the dispatcher and worker threads and performs
* clean-up. Returns zero on success, and error numbers on errors. */
int dispatcher_stop();
#endif/*_DISPATCHER_H_*/

View File

@@ -0,0 +1,132 @@
#include <stdlib.h>
#include "debug.h"
#include "http.h"
#include "util.h"
char* http_read_header(channel_t* channel)
{
char* result = ch_read_until(channel, "\r\n\r\n");
DEBUG_PRINTF(("[HTTP] Got header:\n%s\n[HTTP] End header.\n", result));
return result;
}
char* http_get_requesturi(const char* header)
{
char* start = ((char*) strchr(header, ' ')) + 1;
if (start == NULL)
{
return NULL;
}
else
{
/* Count the length of the requested URI: */
char* ptr = NULL;
size_t count = 0;
for (ptr = start; *ptr != ' '; ptr++, count++)
{
/* Check if we've reached the end of the string without encountering
a second space: */
if (*ptr == '\0') return NULL;
}
return strncatd(NULL, start, count);
}
}
const char* http_get_method(const char* header)
{
/* If header starts with GET, then we have a GET request. */
if (strstr(header, HTTP_METHOD_GET) == header)
{
return HTTP_METHOD_GET;
}
else if (strstr(header, HTTP_METHOD_LOCAL_GET) == header)
{
return HTTP_METHOD_LOCAL_GET;
}
else
{
return NULL;
}
}
int http_get_status(const char* header)
{
const char* ind = strchr(header, ' ');
if (!ind) return 0;
else return atoi(ind + 1);
}
int http_send_canned_response(channel_t* channel, int status)
{
static const char* html1 = "<html>HTTP Status code ";
static const char* html2 = "</html>";
char buffer[8];
sprintf(buffer, "%d", status);
/* Send the appropriate header: */
if (http_send_response_header(channel, status)) { return 1; }
/* Send some HTML: */
if (ch_write_string(channel, html1)) { return 1; }
if (ch_write_string(channel, buffer)) { return 1; }
if (ch_write_string(channel, html2)) { return 1; }
return 0;
}
int http_send_request_header(channel_t* channel, const char* method,
const char* uri, const char* host)
{
char* header = NULL;
int result = 1;
header = strcatd(header, method);
header = strcatd(header, " ");
header = strcatd(header, uri);
header = strcatd(header, " HTTP/1.1\r\n");
if (host)
{
header = strcatd(header, "Host: ");
header = strcatd(header, host);
header = strcatd(header, "\r\n");
}
header = strcatd(header, "Connection: close\r\n");
header = strcatd(header, "\r\n");
result = ch_write_string(channel, header);
free(header);
return result;
}
int http_send_response_header(channel_t* channel, int status)
{
char buffer[32];
char* header = NULL;
int result = 1;
/* Make status line: */
sprintf(buffer, "HTTP/1.1 %d %d\r\n", status, status);
header = strcatd(header, buffer);
/* Add various other headers: */
header = strcatd(header, "Content-Type: text/html\r\n");
header = strcatd(header, "Server: CS4210P1/vlad,omar\r\n");
header = strcatd(header, "Connection: Close\r\n");
header = strcatd(header, "\r\n");
result = ch_write_string(channel, header);
free(header);
return result;
}

View File

@@ -0,0 +1,52 @@
#ifndef _HTTP_H_
#define _HTTP_H_
#include <stdio.h>
#include "channel.h"
/* Some useful request methods: */
#define HTTP_METHOD_GET "GET"
#define HTTP_METHOD_LOCAL_GET "LOCAL_GET"
/* Some useful response codes: */
#define HTTP_STATUS_OK 200
#define HTTP_STATUS_BADREQUEST 400
#define HTTP_STATUS_FORBIDDEN 403
#define HTTP_STATUS_NOTFOUND 404
#define HTTP_STATUS_INTERNALERROR 500
#define HTTP_STATUS_NOTIMPLEMENTED 501
/* Returns a newly allocated string containing the HTTP header read from the
* channel. */
char* http_read_header(channel_t* channel);
/* Returns a newly allocated string containing the requested URI from the
* header. */
char* http_get_requesturi(const char* header);
/* Given a request header, returns the type of request method that we have. If
* the method is unsupported, returns NULL. */
const char* http_get_method(const char* header);
/* Given a response header, returns the response status. The status is not
* guaranteed to be any of the http statuses enumerated in this header. It
* will be any ol' number found in the header, or 0 if we can't parse the
* number. */
int http_get_status(const char* header);
/* Sends an HTTP request header to the channel, using the HTTP method passed
* in, for the uri passed in. If host name is provided, also includes the host
* header field. Returns zero on success, and an error code on error. */
int http_send_request_header(channel_t* channel, const char* method,
const char* uri, const char* host);
/* Sends a response header to the channel, according to the status code passed
* in. Returns zero on success, and an error code on error. */
int http_send_response_header(channel_t* channel, int status);
/* Sends a hard-coded html response according to the status code passed
* in. Returns zero on success, and an error code on error. */
int http_send_canned_response(channel_t* channel, int status);
#endif/*_HTTP_H_*/

View File

@@ -0,0 +1,208 @@
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "networking.h"
/* These store the localhost and local named host socket addresses, which are
* used on requests coming in to see if they are for a local address. */
static sockaddress_t m_host_saddr;
static sockaddress_t m_localhost_saddr;
/* Returns true if the two addresses passed in are the same address, and false
* if they are not. */
static int m_is_same_saddr(sockaddress_t* a1, sockaddress_t* a2)
{
return a1->sin_addr.s_addr == a2->sin_addr.s_addr;
}
int net_initialize()
{
static const int buffer_len = 256;
int result = 0;
char hostname[buffer_len];
#ifdef WIN32
/* Have to initialize WinSock */
WSADATA uselessData;
result = WSAStartup(MAKEWORD(2, 2), &uselessData);
if (result)
{
fprintf(stderr, "[NET] Could not initialize WinSock.\n");
net_report_error();
return result;
}
#else
/* Linux needs no special network initialization. */
#endif
/* Get the local host addresses, so we can check against them to see if a
request comes in for local host. */
gethostname(hostname, buffer_len);
net_get_hostaddr(&m_localhost_saddr, "localhost", 0);
net_get_hostaddr(&m_host_saddr, hostname, 0);
return result;
}
int net_get_hostaddr(sockaddress_t* addr,
const char* hostname, const port_t port)
{
struct addrinfo hints;
struct addrinfo* result;
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
error = getaddrinfo(hostname, "http", &hints, &result);
if (error)
{
freeaddrinfo(result);
return error;
}
if (result->ai_addrlen != sizeof(sockaddress_t))
{
fprintf(stderr,
"[NET] getaddrinfo returned some weird sockaddr structure\n");
freeaddrinfo(result);
return 1;
}
/* Shallow copy should work right? Right?? */
*addr = *((sockaddress_t*) (result->ai_addr));
addr->sin_port = htons(port);
freeaddrinfo(result);
return 0;
}
int net_is_localhost(const char* host)
{
sockaddress_t remote_saddr;
net_get_hostaddr(&remote_saddr, host, 0);
return m_is_same_saddr(&remote_saddr, &m_localhost_saddr)
|| m_is_same_saddr(&remote_saddr, &m_host_saddr);
}
socket_t net_open_data_socket(sockaddress_t* addr)
{
int err = 0;
socket_t result = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (IS_BAD_SOCKET(result))
{
fprintf(stderr, "[NET] Could not open client socket.\n");
net_report_error();
return 1;
}
err = connect(result, (struct sockaddr*) addr, sizeof(*addr));
if (err)
{
fprintf(stderr, "[NET] Could not connect on socket.\n");
net_report_error();
return -1;
}
return result;
}
/*
* Creates and initializes a new listening socket, ready to accept
* connections.
*/
socket_t net_listen_on_port(port_t port)
{
int reuse = 1;
int error_code = 0;
socket_t socket_id = -1;
sockaddress_t sockinfo;
/* Initialize socket using the TCP/IP protocol: */
socket_id = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (IS_BAD_SOCKET(socket_id))
{
fprintf(stderr, "[NET] Could not open listening socket.\n");
net_report_error();
return -1;
}
/* Set socket options to release unused socket numbers: */
error_code = setsockopt(socket_id, SOL_SOCKET, SO_REUSEADDR,
(sockoption_t) &reuse, sizeof(reuse));
if (error_code)
{
fprintf(stderr, "[NET] Could not set socket options.\n");
net_report_error();
return -1;
}
/* Bind the socket: */
sockinfo.sin_family = AF_INET;
sockinfo.sin_port = htons(port);
sockinfo.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to all interfaces */
error_code = bind(socket_id, (struct sockaddr*) &sockinfo, sizeof(sockinfo));
if (error_code)
{
fprintf(stderr, "[NET] Could not bind socket.\n");
net_report_error();
return -1;
}
/* Start Listening: */
error_code = listen(socket_id, 8);
if (error_code)
{
fprintf(stderr, "[NET] Could not listen on socket.\n");
net_report_error();
return -1;
}
return socket_id;
}
int net_close_socket(socket_t socket)
{
int result = shutdown(socket, SHUT_RDWR);
if (result)
{
fprintf(stderr, "[NET] Could not shut down socket.\n");
net_report_error();
}
/* Curiously, the WinSock documentation says that shutdown does not actually
* close the socket, but tells the socket to stop accepting and sending
* data. Apparently, we also need to call this close socket deal. */
#ifdef WIN32
result = closesocket(socket);
#else
result = close(socket);
#endif
if (result)
{
fprintf(stderr, "[NET] Could not close socket.\n");
net_report_error();
}
return result;
}
void net_report_error()
{
#ifdef WIN32
int errcode = WSAGetLastError();
#else
int errcode = errno;
#endif
fprintf(stderr, "[NET] \tError #%d", errcode);
perror(" ");
fprintf(stderr, "\n\n");
}

View File

@@ -0,0 +1,106 @@
#ifndef _NETWORKING_H_
#define _NETWORKING_H_
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <stdlib.h>
#include <sys/types.h> /* header containing all basic data types */
#include <sys/socket.h> /* header containing socket data types and functions */
#include <netinet/in.h> /* IPv4 and IPv6 stuff */
#include <netdb.h> /* for DNS - gethostbyname() */
#include <unistd.h>
#endif
#include <errno.h> /* contains the error functions */
#ifdef WIN32
/* Apparently, this socklen_t business is not defined in Win. */
typedef int socklen_t;
#endif
/* The socket type. Typedef'ed to make the code more platform-independent. */
#ifdef WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
/* The setsockopt function takes different parameter type for the
* value of the option in Berkeley sockets and WinSock. */
#ifdef WIN32
typedef const char* sockoption_t;
#else
typedef const void* sockoption_t;
#endif
/* The port type. Typedef'ed in case we want to make this code
* platform-independent at some point and the ports on another
* platform are something other than this. */
typedef unsigned short port_t;
/* This is the struct we will be using for socket addresses. */
typedef struct sockaddr_in sockaddress_t;
/* The 'how' parameter to the shutdown function is different in
* Berkeley sockets and WinSock, too. */
#ifndef SHUT_RDWR
#define SHUT_RDWR SD_BOTH
#endif
/* Socket error is only defined in WIN32, but it's always -1. */
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
/* The ways to check for illegal socket in windows and Linux are different: */
#ifdef WIN32
#define IS_BAD_SOCKET(socket) (socket == INVALID_SOCKET)
#else
#define IS_BAD_SOCKET(socket) (socket < 0)
#endif
/* Initializes the networking stuff. This is needed in Windows. In
* Unix, the network does not really need to be initialized. Returns 0
* on success, and an error code if an error is encountered. */
int net_initialize();
/* Given a host name and a port number, fills in the sockaddress
* struct with the appropriate information for the host. This function
* will automagically work both if the host is a host name, or if it's
* an IP address in dotted notation.
* **WARNING** This function IS NOT mt-safe! */
int net_get_hostaddr(sockaddress_t* addr,
const char* hostname, const port_t port);
/* Returns true of the host name passed in points to the local machine. Can
return false negatives. */
int net_is_localhost(const char* host);
/* Opens a client socket on the specified address. */
socket_t net_open_data_socket(sockaddress_t* addr);
/*
* Creates a new listening socket on the specified port, sets up the
* correct options, binds and starts listening. Returns the id of the
* socket if all these operations were successful, and -1 if there was
* an error at any point. If there is an error, then also this
* function will print out to stderr what the error was. If a valid
* socket id is returned, then accept can be called on the socket to
* accept connections.
*/
socket_t net_listen_on_port(port_t port);
/*
* Shuts down the socket. Returns zero on success, and error code on
* failure. Also, on failure will print out the error to stderr.
*/
int net_close_socket(socket_t socket);
/*
* Reports the last error to stderr.
*/
void net_report_error();
#endif/*_NETWORKING_H_*/

View File

@@ -0,0 +1,162 @@
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
void queue_initialize(queue_t* q)
{
q->head = NULL;
q->tail = NULL;
pthread_mutex_init(&(q->mutex), NULL);
pthread_cond_init(&(q->has_stuff), NULL);
}
void queue_free(queue_t* q)
{
sllnode_t* cur = NULL;
pthread_mutex_lock(&(q->mutex));
cur = q->head;
q->head = NULL;
q->tail = NULL;
while (cur)
{
sllnode_t* next = cur->next;
cur->data = NULL;
cur->next = NULL;
free(cur);
cur = next;
}
pthread_mutex_unlock(&(q->mutex));
}
int queue_enqueue(queue_t* q, void* data)
{
/* Make a linked list node */
sllnode_t* node = (sllnode_t*) calloc(1, sizeof(sllnode_t));
if (!node)
{
fprintf(stderr,
"[QUE] Could not allocate memory for linked list node.\n");
return 1;
}
node->next = NULL;
node->data = data;
/* Add node to the end of the queue: */
pthread_mutex_lock(&q->mutex);
if (q->tail != NULL)
{
q->tail->next = node;
}
q->tail = node;
if (q->head == NULL)
{
q->head = node;
}
pthread_mutex_unlock(&(q->mutex));
pthread_cond_signal(&(q->has_stuff));
return 0;
}
void* queue_dequeue(queue_t* q)
{
sllnode_t* node;
void* result;
pthread_mutex_lock(&q->mutex);
while (q->head == NULL)
{
pthread_cond_wait(&(q->has_stuff), &(q->mutex));
}
node = q->head;
q->head = q->head->next;
if (q->head == NULL)
{
q->tail = NULL;
}
pthread_mutex_unlock(&(q->mutex));
node->next = NULL;
result = node->data;
free(node);
return result;
}
void* queue_dequeue_nb(queue_t* q)
{
sllnode_t* node = NULL;
void* result = NULL;
pthread_mutex_lock(&q->mutex);
if (q->head != NULL)
{
node = q->head;
q->head = q->head->next;
if (q->head == NULL)
{
q->tail = NULL;
}
}
pthread_mutex_unlock(&(q->mutex));
if (node != NULL)
{
node->next = NULL;
result = node->data;
free(node);
}
return result;
}
int queue_has_data(queue_t* q)
{
int result = 0;
pthread_mutex_lock(&q->mutex);
result = (q->head != NULL);
pthread_mutex_unlock(&(q->mutex));
return result;
}
void iterator_initialize(queue_iterator_t* iter, queue_t* q, int wrap)
{
iter->q = q;
iter->cur = q->head;
iter->wrap = wrap;
}
void* iterator_next(queue_iterator_t* iter)
{
void* result = NULL;
if (!iter->cur) return NULL;
pthread_mutex_lock(&(iter->q->mutex));
result = iter->cur->data;
iter->cur = iter->cur->next;
if (!iter->cur && iter->wrap) iter->cur = iter->q->head;
pthread_mutex_unlock(&(iter->q->mutex));
return result;
}

View File

@@ -0,0 +1,69 @@
/* queue.h
*
* Here we define a generic MT-safe queue data structure.
*/
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include "threading.h"
typedef struct tagSinglyLinkedList
{
struct tagSinglyLinkedList* next;
void* data;
} sllnode_t;
typedef struct
{
sllnode_t* head;
sllnode_t* tail;
pthread_mutex_t mutex;
pthread_cond_t has_stuff;
} queue_t;
typedef struct
{
queue_t* q;
sllnode_t* cur;
int wrap;
} queue_iterator_t;
/* Initializes the queue q. */
void queue_initialize(queue_t* q);
/* Frees the queue, and its associated structures, but not the data if
there is any in it. */
void queue_free(queue_t* q);
/* Adds a new thing to the end of the queue q. */
int queue_enqueue(queue_t* q, void* data);
/* Removes an item from the queue q, and returns a pointer to it. If the queue
does not contain any items, will wait till data is inserted. */
void* queue_dequeue(queue_t* q);
/* Removes an item from the queue q, and returns a pointer to it. If the queue
does not contain any items, returns null. */
void* queue_dequeue_nb(queue_t* q);
/* Returns true if queue has data, and false if it is empty. */
int queue_has_data(queue_t* q);
/* Initializes the iterator iter over the queue q. If next function is
called on the iterator after this, the head data will be
returned. The wrap parameter will determine whether the iterator will wrap
around to the bedinning of the queue when the end is reached. */
void iterator_initialize(queue_iterator_t* iter, queue_t* q, int wrap);
/* Returns whatever the iterator points to currently (would be the
head of the queue right after the initialize call), and moves the
iterator to the next position. Note that if the end of the queue is
reached, this function will whip around and start from the
beginning again. Note also that bad things may happen if the queue
is modified between calls to this function. */
void* iterator_next(queue_iterator_t* iter);
#endif/*_QUEUE_H_*/

View File

@@ -0,0 +1,134 @@
#include <stdio.h>
#include "semaphore.h"
#include "util.h"
int semaphore_create(semaphore_t* s, const char* name)
{
#ifdef WIN32
s->handle = CreateSemaphoreA(NULL, 0, 1, name);
if (s->handle == NULL)
{
fprintf(stderr, "[SEM] Could not create semaphore \"%s\" (%d).\n", name,
GetLastError());
return GetLastError();
}
#else
int count = 0;
s->handle = sem_open(name, O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0);
if (s->handle == SEM_FAILED)
{
fprintf(stderr,
"[SEM] Could not create semaphore \"%s\". \n", name);
perror("[SEM] create()");
return 1;
}
/* Make it so we have zero resources available: */
for (sem_getvalue(s->handle, &count); count > 0;
sem_getvalue(s->handle, &count))
{ sem_wait(s->handle); }
#endif
s->name = strdup(name);
return 0;
}
int semaphore_open(semaphore_t* s, const char* name)
{
#ifdef WIN32
s->handle = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, name);
if (s->handle == NULL)
{
fprintf(stderr, "[SEM] Could not open semaphore \"%s\" (%d).\n", name,
GetLastError());
return GetLastError();
}
#else
s->handle = sem_open(name, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0);
if (s->handle == SEM_FAILED)
{
fprintf(stderr,
"[SEM] Could not open semaphore \"%s\". \n", name);
return 1;
}
#endif
s->name = strdup(name);
return 0;
}
int semaphore_close(semaphore_t* s)
{
int result = 0;
#ifdef WIN32
result |= !CloseHandle(s->handle);
#else
result |= sem_close(s->handle);
#endif
free(s->name);
memset(s, 0, sizeof(semaphore_t));
return result;
}
int semaphore_unlink(semaphore_t* s)
{
int result = 0;
#ifdef WIN32
result |= !CloseHandle(s->handle);
#else
result |= sem_close(s->handle);
result |= sem_unlink(s->name);
#endif
free(s->name);
memset(s, 0, sizeof(semaphore_t));
return result;
}
int semaphore_wait(semaphore_t* s)
{
#ifdef WIN32
DWORD result = WaitForSingleObject(s->handle, INFINITE);
if (result != WAIT_OBJECT_0)
{
fprintf(stderr, "[SEM] Semaphore wait timed out.\n");
return 1;
}
#else
if (sem_wait(s->handle))
{
fprintf(stderr, "[SEM] Semaphore wait failed.\n");
return 1;
}
#endif
return 0;
}
int semaphore_signal(semaphore_t* s)
{
#ifdef WIN32
if (!ReleaseSemaphore(s->handle, 1, NULL))
{
fprintf(stderr,
"[SEM] Could not release semaphore (%d).\n", GetLastError());
return GetLastError();
}
#else
if (sem_post(s->handle))
{
fprintf(stderr, "[SEM] Could not release semaphore.\n");
}
#endif
return 0;
}

View File

@@ -0,0 +1,50 @@
#ifndef _MY_PROXY_SEMAPHORE_H_
#define _MY_PROXY_SEMAPHORE_H_
#ifdef WIN32
#define _WINSOCKAPI_ /* Have to do this, else windows.h and winsock2.h */
#include <windows.h>
#else
#include <fcntl.h>
#include <semaphore.h>
#include <sys/stat.h>
#endif
#ifdef WIN32
typedef HANDLE system_semaphore_t;
#else
typedef sem_t* system_semaphore_t;
#endif
typedef struct
{
system_semaphore_t handle;
char* name;
} semaphore_t;
/* Creates a named semaphore. The semaphore can have at most 1 thread using it
* at a time and starts out with zero available slots. Returns 0 on success,
* and something else on error. */
int semaphore_create(semaphore_t* s, const char* name);
/* Opens a named semaphore. Returns 0 on success, and something else on
* error. */
int semaphore_open(semaphore_t* s, const char* name);
/* Closes the semaphore. The semaphore will still be useful for other
* processes. Returns 0 on success, and something else on error. */
int semaphore_close(semaphore_t* s);
/* Cleans up the semaphore's system resources. The semaphore will not be
* useful for other processes. */
int semaphore_unlink(semaphore_t* s);
/* Waits on the semaphore. Returns 0 on success, and something else on
* error. */
int semaphore_wait(semaphore_t* s);
/* Signals the semaphore. Returns 0 on success, and something else on
* error. */
int semaphore_signal(semaphore_t* s);
#endif/*_MY_PROXY_SEMAPHORE_H_*/

View File

@@ -0,0 +1,323 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#define _WINSOCKAPI_ /* Have to do this, else windows.h and winsock2.h */
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "debug.h"
#include "shared_memory.h"
#include "util.h"
/* Given the memory segment structure, initializes a named semaphore for
* synchronized access to the shared memory. The name of the semaphore is
* generated by appending a _s to the name of the shared memory chunk, so this
* way the same memory will always be controlled by the same semaphore. If the
* create parameter is true, then the semaphore is created, otherwise it is
* just opened.*/
static int m_init_semaphore(shared_memory_t* sm, int create)
{
char* sem_name_r = NULL;
char* sem_name_w = NULL;
int result = 0;
sem_name_r = strcatd(sem_name_r, "/");
sem_name_r = strcatd(sem_name_r, sm->name);
sem_name_r = strcatd(sem_name_r, "_sr");
sem_name_w = strcatd(sem_name_w, "/");
sem_name_w = strcatd(sem_name_w, sm->name);
sem_name_w = strcatd(sem_name_w, "_sw");
if (create)
{
result = semaphore_create(&(sm->can_read), sem_name_r);
result |= semaphore_create(&(sm->can_write), sem_name_w);
if (result)
{
fprintf(stderr,
"[SHM] Could not create semaphore for shared mem.\n");
free(sem_name_r);
free(sem_name_w);
return result;
}
/* When initializing the semaphores, as opposed to opening them, we need
to start out with a single write resource. */
semaphore_signal(&(sm->can_write));
}
else
{
result = semaphore_open(&(sm->can_read), sem_name_r);
result |= semaphore_open(&(sm->can_write), sem_name_w);
if (result)
{
fprintf(stderr,
"[SHM] Could not open semaphore for shared mem.\n");
free(sem_name_r);
free(sem_name_w);
return result;
}
}
free(sem_name_r);
free(sem_name_w);
return result;
}
int sharedmem_create(shared_memory_t* mem, char* name, size_t length)
{
size_t total_shared_size = sizeof(memory_chunk_t) + length;
/* Do system-specific stuff to get at the memory: */
#ifdef WIN32
mem->file_handle =
CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, DWORD(total_shared_size), name);
if (mem->file_handle == NULL || mem->file_handle == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "[SHM] Could not create file mapping object (%d).\n",
GetLastError());
return GetLastError();
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
fprintf(stderr, "[SHM] Memory \"%s\" already exists.\n"
" Use function sharedmem_open instead.\n", name);
CloseHandle(mem->file_handle);
mem->file_handle = NULL;
return ERROR_ALREADY_EXISTS;
}
mem->memory = (memory_chunk_t*)
MapViewOfFile(mem->file_handle, FILE_MAP_READ | FILE_MAP_WRITE,
0, 0, total_shared_size);
if (mem->memory == NULL)
{
fprintf(stderr, "[SHM] Could not map view of file (%d).\n",
GetLastError());
CloseHandle(mem->file_handle);
mem->file_handle = NULL;
return GetLastError();
}
#else
mem->file_handle = shmget(atol(name), total_shared_size,
IPC_CREAT | IPC_EXCL | 0666);
if (mem->file_handle == -1)
{
fprintf(stderr, "[SHM] Could not create shared memory object %d.\n",
atol(name));
return 1;
}
DEBUG_PRINTF(("[SHM] Created memory chunk named \"%d\"\n", atol(name)));
mem->memory = (memory_chunk_t*) shmat(mem->file_handle, NULL, 0);
if (mem->memory == NULL)
{
fprintf(stderr, "[SHM] Could not map memory descriptor to pointer.\n");
shmctl(mem->file_handle, IPC_RMID, NULL);
close(mem->file_handle);
return 1;
}
DEBUG_PRINTF(("[SHM] Mapped memory descriptor to void*.\n"));
#endif
/* Initialize the structure contents: */
mem->name = strdup(name);
if (m_init_semaphore(mem, 1)) return 1;
mem->memory->maximum_bytes = length;
mem->memory->bytes_written = 0;
mem->data = (void*) (mem->memory + 1);
memset(mem->data, 0, length);
DEBUG_PRINTF(("[SHM] Initialization complete.\n"));
return 0;
}
int sharedmem_open(shared_memory_t* mem, char* name)
{
#ifdef WIN32
mem->file_handle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name);
if (mem->file_handle == NULL || mem->file_handle == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "[SHM] Could not open file mapping object (%d).\n",
GetLastError());
return GetLastError();
}
mem->memory = (memory_chunk_t*)
MapViewOfFile(mem->file_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (mem->memory == NULL)
{
fprintf(stderr, "[SHM] Could not map view of file (%d).\n",
GetLastError());
CloseHandle(mem->file_handle);
mem->file_handle = NULL;
return GetLastError();
}
#else
mem->file_handle = shmget(atol(name), sizeof(memory_chunk_t), 0666);
if (mem->file_handle == -1)
{
fprintf(stderr, "[SHM] Could not open shared memory object.\n");
return 1;
}
DEBUG_PRINTF(("[SHM] Opened memory chunk named \"%d\"\n", atol(name)));
mem->memory = (memory_chunk_t*) shmat(mem->file_handle, NULL, SHM_RND);
if (mem->memory == NULL)
{
fprintf(stderr, "[SHM] Could not map memory descriptor to pointer.\n");
shmctl(mem->file_handle, IPC_RMID, NULL);
close(mem->file_handle);
return 1;
}
DEBUG_PRINTF(("[SHM] Mapped memory descriptor to void*.\n"));
#endif
mem->name = strdup(name);
if (m_init_semaphore(mem, 0)) return 1;
mem->data = (void*) (mem->memory + 1);
return 0;
}
size_t sharedmem_write(shared_memory_t* mem, const void* data, size_t length)
{
size_t actual_length = 0;
if (semaphore_wait(&(mem->can_write)))
{
fprintf(stderr, "[SHM] Couldn't wait. Couldn't write.\n");
return 0;
}
actual_length = min(length, mem->memory->maximum_bytes);
memcpy(mem->data, data, actual_length);
mem->memory->bytes_written = actual_length;
semaphore_signal(&(mem->can_read));
DEBUG_PRINTF(("[SHM] Wrote %d bytes.\n", actual_length));
return actual_length;
}
static size_t m_sharedmem_read(shared_memory_t* mem, void* data,
size_t length, int synchronize)
{
size_t actual_length = 0;
if (synchronize && semaphore_wait(&(mem->can_read)))
{
fprintf(stderr, "[SHM] Couldn't read. And e11i73r4t3.\n");
return 0;
}
if (synchronize)
actual_length = min(length, mem->memory->bytes_written);
else
actual_length = min(length, mem->memory->maximum_bytes);
memcpy(data, mem->data, actual_length);
if (synchronize)
{
mem->memory->bytes_written -= actual_length;
if (mem->memory->bytes_written > 0)
{
memcpy(mem->data, ((char*) mem->data) + actual_length,
mem->memory->bytes_written);
semaphore_signal(&(mem->can_read));
}
else
{
semaphore_signal(&(mem->can_write));
}
}
DEBUG_PRINTF(("[SHM] Read %d bytes.\n", actual_length));
return actual_length;
}
size_t sharedmem_read(shared_memory_t* mem, void* data, size_t length)
{
return m_sharedmem_read(mem, data, length, 1);
}
size_t sharedmem_read_nb(shared_memory_t* mem, void* data, size_t length)
{
return m_sharedmem_read(mem, data, length, 0);
}
int sharedmem_close(shared_memory_t* mem)
{
int result = 0;
DEBUG_PRINTF(("[SHM] Closing shm: \"%s\"... ", mem->name));
#ifdef WIN32
result = !UnmapViewOfFile(mem->memory);
result |= !CloseHandle(mem->file_handle);
#else
result = shmdt(mem->memory);
/*result |= close(mem->file_handle);*/
#endif
semaphore_close(&(mem->can_read));
semaphore_close(&(mem->can_write));
free(mem->name);
DEBUG_PRINTF(("%s\n", (result) ? (perror("Error"),"") : ("Done")));
return result;
}
int sharedmem_unlink(shared_memory_t* mem)
{
int result = 0;
DEBUG_PRINTF(("[SHM] Unlinking shm: \"%s\"... ", mem->name));
#ifdef WIN32
result = !UnmapViewOfFile(mem->memory);
result |= !CloseHandle(mem->file_handle);
#else
result = shmdt(mem->memory);
result |= shmctl(mem->file_handle, IPC_RMID, NULL);
/*result |= close(mem->file_handle);*/
#endif
semaphore_unlink(&(mem->can_read));
semaphore_unlink(&(mem->can_write));
free(mem->name);
DEBUG_PRINTF(("%s\n", (result) ? (perror("Error"),"") : ("Done")));
return result;
}

View File

@@ -0,0 +1,78 @@
/** \file shared_memory.h
* Here we define the interface for the shared memory interactions. This is
* done to create a common interface for shared memory access for both POSIX
* shared memory objects and Windows virtual file mappings.
*/
#ifndef _SHARED_MEMORY_H_
#define _SHARED_MEMORY_H_
#ifdef WIN32
#else
#include <sys/shm.h> /* for shmget etc */
#endif
#include "semaphore.h"
#ifdef WIN32
typedef HANDLE file_handle_t;
#else
typedef int file_handle_t;
#endif
/* This is the struct that will be sitting in the shared memory and will allow
* synchronized access to the data. */
typedef struct
{
/* The maximum amount of data we can fit into the data chunk. */
size_t maximum_bytes;
/* The number of bytes written on the last IO operation. */
size_t bytes_written;
} memory_chunk_t;
/* This struct will be sitting in local memory and contain local unshared
* memory file descriptors for accessing the shared memory. */
typedef struct
{
memory_chunk_t* memory;
file_handle_t file_handle;
semaphore_t can_read;
semaphore_t can_write;
void* data;
char* name;
} shared_memory_t;
/* Creates a named shared memory segment. The mem_name specifies the unique
* memory segment name. The length parameter specifies how much data the
* shared memory chunk should be able to store. The function returns 0 on
* success and error codes on failure. One possible error is if the shared
* object with the same name already exists. */
int sharedmem_create(shared_memory_t* mem, char* mem_name, size_t length);
/* Opens a named shared memory segment. Returns 0 on success and an error code
* on failure, for example if the shared memory segment does not exist. */
int sharedmem_open(shared_memory_t* mem, char* name);
/* Performs a synrchronized write of at most length bytes from data to the
* memory. Returns the number of bytes written. */
size_t sharedmem_write(shared_memory_t* mem, const void* data, size_t length);
/* Performs a synchronized read of at most length bytes from shared memory to
* data. Returns the number of bytes read. */
size_t sharedmem_read(shared_memory_t* mem, void* data, size_t length);
/* Performs a non-blocking read of at most length bytes from shared memory to
* data. Returns the number of bytes read. */
size_t sharedmem_read_nb(shared_memory_t* mem, void* data, size_t length);
/* Closes the shared memory segment. This means that the shared memory object
* will not be usable by the current process. Other processes will still be
* able to use it, however. */
int sharedmem_close(shared_memory_t* mem);
/* Unlinks the shared memory segment. No process will be able to use this
* memory afterwards. */
int sharedmem_unlink(shared_memory_t* mem);
#endif/*_SHARED_MEMORY_H_*/

View File

@@ -0,0 +1,8 @@
#ifndef _THREADING_H_
#define _THREADING_H_
#include <pthread.h>
#include <signal.h>
#endif/*_THREADING_H_*/

View File

@@ -0,0 +1,85 @@
#ifndef _TIMER_H_
#define _TIMER_H_
/* In windows, we'll use QueryPerformanceCounter, and in everything
else, we will use gettimeofday (windows does not seem to support
that function. */
#ifdef WIN32
#define _WINSOCKAPI_ /* Have to do this, else windows.h and winsock2.h */
#include <windows.h> /* (from the networking module) start fighting,
as windows.h will include the old
winsock.h. */
#else
#include <sys/time.h>
#endif
/* The units of time we will be storing in our time span for the
beginning and end of the measurement period. */
#ifdef WIN32
typedef LARGE_INTEGER timestamp_t;
#else
typedef struct timeval timestamp_t;
#endif
/* The timespan structure, holding the beginning and ending times for
our measurements. */
typedef struct
{
timestamp_t start;
timestamp_t stop;
} time_span_t;
/* The function to start the timer. It is inlined for better performance. */
#ifdef WIN32
static inline void timer_start(time_span_t* s)
{
QueryPerformanceCounter(&(s->start));
}
#else
static inline void timer_start(time_span_t* s)
{
gettimeofday(&(s->start), NULL);
}
#endif
/* The function to stop the timer. */
#ifdef WIN32
static inline void timer_stop(time_span_t* s)
{
QueryPerformanceCounter(&(s->stop));
}
#else
static inline void timer_stop(time_span_t* s)
{
gettimeofday(&(s->stop), NULL);
}
#endif
/* The function to convert the time stamp to milliseconds. */
#ifdef WIN32
static inline double timer_millis(timestamp_t* value)
{
timestamp_t frequency;
double v, f;
QueryPerformanceFrequency(&frequency);
v = (double) (*value).LowPart;
f = (double) frequency.LowPart;
return 1000 * v / f;
}
#else
static inline double timer_millis(timestamp_t* v)
{
return (v->tv_sec * 1000.0) + (v->tv_usec / 1000.0);
}
#endif
/* The function to calculate the time span in milliseconds. */
static inline double timer_span(time_span_t* s)
{
return timer_millis(&(s->stop)) - timer_millis(&(s->start));
}
#endif/*_TIMER_H_*/

View File

@@ -0,0 +1,190 @@
#include <stdlib.h>
#include "util.h"
#define BUFFER_SIZE 256
char* strcatd(char* dest, const char* src)
{
return strncatd(dest, src, strlen(src));
}
char* strncatd(char* dest, const char* src, size_t len)
{
size_t dest_length = 0;
size_t total_length = 0;
char* result = NULL;
if (dest) { dest_length = strlen(dest); }
total_length = dest_length + len;
result = (char*) realloc(dest, (total_length + 1) * sizeof(char));
if (!result)
{
fprintf(stderr, "[UTIL] Could not allocate memory "
"for dynamic string concatenation.\n");
}
result[dest_length] = '\0';
strncat(result, src, len);
return result;
}
int parse_url(const char* url, char** host, port_t* port, char** path)
{
char* durl = strdup(url);
if (strstr(durl, "http://") != durl)
{
/* The URL does not start with http, it is malformed. */
*host = NULL;
*path = NULL;
free(durl);
return 1;
}
else
{
/* Separate the protocol from the rest: */
char* url_start = durl + strlen("http://");
/* Separate the port from the rest: */
char* port_start = strchr(url_start, ':');
/* Separate the host from the path: */
char* path_start = strchr(url_start, '/');
if (port_start)
{
port_start[0] = '\0';
port_start ++;
}
else
{
port_start = "80";
}
if (path_start)
{
path_start[0] = '\0';
path_start ++;
}
else
{
path_start = "";
}
*host = strdup(url_start);
*port = (port_t) atoi(port_start);
*path = NULL;
if (!strstr(path_start, "http://"))
{ /* We add a slash if the path does not start with http:// */
/* This is needed to support proxy urls of the form: */
/* http://proxy-uri/http://request-uri/ */
*path = strcatd(*path, "/");
}
*path = strcatd(*path, path_start);
return 0;
}
}
/* Tries to parse the parameter param. If succeeded, returns zero and
* puts the name of the parameter into opname, and the value of the
* parameter into opvalue. Note that the strings put into output
* parameters are dynamically allocated and need to be freed. */
int m_parse_parameter(const char* param, char** opname, char** opvalue)
{
char* parameter = strdup(param);
if (strstr(parameter, "help") || strstr(parameter, "?"))
{
*opname = strdup("help");
*opvalue = strdup(" ");
free(parameter);
return 0;
}
*opname = strtok(parameter, "=");
*opvalue = strtok(NULL, "=");
if (!*opname || !*opvalue)
{
*opname = NULL;
*opvalue = NULL;
}
else
{
*opname = strdup(*opname);
*opvalue = strdup(*opvalue);
}
free(parameter);
return (*opname == NULL);
}
int parse_command_parameters(int argc, const char** argv,
register_parameter_func f)
{
int i;
for (i = 0; i < argc; i++)
{
char* pname = NULL;
char* pvalue = NULL;
int result = 0;
/* Parse the curren parameter: */
if(m_parse_parameter(argv[i], &pname, &pvalue)) continue;
/* Record the parameter value: */
result = f(pname, pvalue);
free(pname);
free(pvalue);
if (result) return result;
}
return 0;
}
int parse_file_parameters(FILE* stream, register_parameter_func f)
{
char* current_line = NULL;
for (current_line = read_line(stream); current_line;
free(current_line), current_line = read_line(stream))
{
if (current_line[0] != '#')
{
char* pname = NULL;
char* pvalue = NULL;
int result = 0;
/* Parse the curren parameter: */
if(m_parse_parameter(current_line, &pname, &pvalue)) continue;
/* Record the parameter value: */
result = f(pname, pvalue);
free(pname);
free(pvalue);
if (result) break;
}
}
if (current_line)
{
free(current_line);
return 1;
}
else
{
return 0;
}
}

View File

@@ -0,0 +1,74 @@
#ifndef _UTIL_H_
#define _UTIL_H_
#include <stdio.h>
#include <string.h>
#include "channel.h"
#include "networking.h"
/* Windows and Linux have their own wierdness related to strdup. */
#ifdef WIN32
#define strdup _strdup
#else
/* Only forward-declare strdup, if there isn't a Macro defined already, which
is what gcc does with gnu99 standard and O2.*/
#ifndef strdup
char* strdup(const char* src);
#endif
#endif
/* A function with this signature can be used to register a
* parameter-name/value pair. It should return 0 if the parameter is valid and
* an error code if the parameter is invalid. */
typedef int (*register_parameter_func)(const char* pname, const char* pvalue);
/* Dynamic strcat. Given a dynamically allocated string dest, and a string
* src, will append src to the end of dest, while reallocating the string as
* necessary. If dest is NULL, will allocate a new string. If src is NULL,
* will crash. */
char* strcatd(char* dest, const char* src);
/* Dynamic strncat. Basically, the same as strcatd, but copies only len
* characters from src. */
char* strncatd(char* dest, const char* src, size_t len);
/* Given a url, parses it into the host name, the port, and the path. If the
* url does not have a host name and a path, or does not begin with "http://"
* protocol, then the url is malformed, host and path are set to NULL, and an
* error code is returned. Otherwise, the host and path are filled with newly
* allocated strings which will need to be freed, and zero is returned. Also,
* if the port is not present in the url, it will be filled in with 0. */
int parse_url(const char* url, char** host, port_t* port, char** path);
/* Parses the command-line parameters and registers them with function f. If
* an illegal parameter is encountered (according to the function f), then
* immediately stops parsing parameters and returns and error code.
* Otherwise, keeps parsing until runs out of the parameters, and then returns
* 0. */
int parse_command_parameters(int argc, const char** argv,
register_parameter_func f);
/* Parses the parameters from the file. If an illegal parameter is encountered
* (according to the function f), then immediately stops parsing parameters
* and returns an error code. Otherwise, keeps parsing until runs out of the
* parameters, and then returns 0. */
int parse_file_parameters(FILE* stream, register_parameter_func f);
/* We do a min inline function, because min macros, they are just evil. */
#ifdef min
#undef min
#endif
static inline size_t min(size_t a, size_t b) { return (a < b) ? (a) : (b); }
/* Reads until a newline or EOF is encountered in the stream and returns the
result in a newly allocated string. */
static inline char* read_line(FILE* stream)
{
channel_t fch;
ch_init_file(&fch, stream);
return ch_read_until(&fch, "\n");
}
#endif/*_UTIL_H_*/

View File

@@ -0,0 +1 @@
obj

View File

@@ -0,0 +1,10 @@
/.cvsignore/1.1/Tue Feb 28 00:39:12 2006//
/Makefile/1.4/Mon Mar 27 21:07:03 2006//
/config.c/1.5/Thu Mar 23 22:20:23 2006//
/config.h/1.4/Thu Mar 23 19:09:21 2006//
/main.c/1.7/Thu Mar 23 19:52:07 2006//
/proxy_memory_pool.c/1.3/Thu Mar 23 18:05:17 2006//
/proxy_memory_pool.h/1.1/Tue Mar 14 04:23:19 2006//
/worker.c/1.17/Mon Mar 27 21:07:03 2006//
/worker.h/1.2/Wed Mar 22 00:15:07 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj2/src/proxy

View File

@@ -0,0 +1 @@
/usr/_CVS

View 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: crono $
# $Date: 2006/03/27 21:07:03 $
# $Revision: 1.4 $
#
##############################################################################
########################### 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 = proxy
######################## Compiler and Linker Options #########################
# Compiler:
CC = gcc
# Linker:
LD = gcc
# Preprocessor flags:
DFLAGS =
# Compiler flags:
CFLAGS = -Wall -pedantic -I.. -std=gnu99 -O2
# 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

View File

@@ -0,0 +1,146 @@
#include <stdlib.h>
#include "common/util.h"
#include "config.h"
/* Some default values */
#define CONFIG_DVALUE_PORT 8080
#define CONFIG_DVALUE_POOLSIZE 16
#define CONFIG_DVALUE_USESHM 0
#define CONFIG_DVALUE_SHMCOUNT 4
#define CONFIG_DVALUE_SHMSIZE 256
#define CONFIG_DVALUE_SHMKEY 31337
/* Some parameter names */
#define CONFIG_PNAME_PORT "port"
#define CONFIG_PNAME_POOLSIZE "pool-size"
#define CONFIG_PNAME_USESHM "use-shm"
#define CONFIG_PNAME_SHMCOUNT "shm-count"
#define CONFIG_PNAME_SHMSIZE "shm-size"
#define CONFIG_PNAME_SHMKEY "shm-key"
/* The port number to run the proxy on. */
static port_t m_proxy_port = -1;
/* The number of child threads to create. */
static int m_pool_size = -1;
/* Whether or not we should use shared memory. */
static int m_use_shm = 0;
/* How many shared memory chunks we should pre-allocate. */
static size_t m_shm_count = 0;
/* The size of a single shared memory chunk in bytes. */
static size_t m_shm_size = 0;
/* The starting key to use for shared memory names. */
static unsigned int m_shm_key = 0;
/* 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_proxy_port = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_PORT, m_proxy_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_USESHM))
{
/* Got shmem use: */
m_use_shm = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_USESHM, m_use_shm);
return 0;
}
else if(!strcmp(name, CONFIG_PNAME_SHMCOUNT))
{
/* Got shmem count: */
m_shm_count = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_SHMCOUNT, m_shm_count);
return 0;
}
else if(!strcmp(name, CONFIG_PNAME_SHMSIZE))
{
/* Got shmem size: */
m_shm_size = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_SHMSIZE, m_shm_size);
return 0;
}
else if(!strcmp(name, CONFIG_PNAME_SHMKEY))
{
/* Got shmem key: */
m_shm_key = atoi(value);
printf("[CONF] Overriding default %s with value %d\n",
CONFIG_PNAME_SHMKEY, m_shm_key);
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 - whether or not we should use shared memory.\n"
"\t\tDefault value is %d.\n",
CONFIG_PNAME_USESHM, CONFIG_DVALUE_USESHM);
fprintf(out, "\t%s - if we use shared memory -"
" how many segments to allocate.\n"
"\t\tDefault value is %d.\n",
CONFIG_PNAME_SHMCOUNT, CONFIG_DVALUE_SHMCOUNT);
fprintf(out, "\t%s - how much memory to allocate in each segment.\n"
"\t\tDefault value is %d.\n",
CONFIG_PNAME_SHMSIZE, CONFIG_DVALUE_SHMSIZE);
fprintf(out, "\t%s - the shared memory segments will be named starting"
" with this number.\n"
"\t\tDefault value is %d.\n",
CONFIG_PNAME_SHMKEY, CONFIG_DVALUE_SHMKEY);
fprintf(out, "\t\n");
}
int config_init(int argc, const char** argv)
{
/* Initialize default values: */
m_proxy_port = CONFIG_DVALUE_PORT;
m_pool_size = CONFIG_DVALUE_POOLSIZE;
m_use_shm = CONFIG_DVALUE_USESHM;
m_shm_count = CONFIG_DVALUE_SHMCOUNT;
m_shm_size = CONFIG_DVALUE_SHMSIZE;
m_shm_key = CONFIG_DVALUE_SHMKEY;
return parse_command_parameters(argc, argv, record_parameter);
}
port_t config_get_port() { return m_proxy_port; }
int config_get_pool_size() { return m_pool_size; }
int config_get_use_shmem() { return m_use_shm; }
size_t config_get_shmem_count() { return m_shm_count; }
size_t config_get_shmem_size() { return m_shm_size; }
unsigned int config_get_shmem_key() { return m_shm_key; }

View File

@@ -0,0 +1,39 @@
#ifndef _PROXY_CONFIG_H_
#define _PROXY_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);
/* 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 proxy on. */
port_t config_get_port();
/* Returns the number of child threads to spawn for handling client
* requests. */
int config_get_pool_size();
/* Returns whether or not we should use shared memory. */
int config_get_use_shmem();
/* Returns how many shared memory chunks we should pre-allocate. */
size_t config_get_shmem_count();
/* Returns the size of a single shared memory chunk in bytes. */
size_t config_get_shmem_size();
/* Returns the number with which we start naming the shared memory
* segments. The first one will be named with this number, and all the
* consecutive ones will be named with incremented values of this number. */
unsigned int config_get_shmem_key();
#endif/*_PROXY_CONFIG_H_*/

View File

@@ -0,0 +1,107 @@
#include <stdio.h>
#include <stdlib.h>
#include "common/dispatcher.h"
#include "config.h"
#include "proxy_memory_pool.h"
#include "worker.h"
int main(int argc, const char** argv) {
int result;
/* Read configuration parameters: */
result = config_init(argc, argv);
if (result)
{
return EXIT_FAILURE;
}
/* Initialize the network system: */
result = net_initialize();
if (result)
{
return EXIT_FAILURE;
}
/* Initialize memory pool if needed: */
if (config_get_use_shmem())
{
result =
shp_initialize(config_get_shmem_count(), config_get_shmem_size());
if (result)
{
return EXIT_FAILURE;
}
}
/* Initialize the dispatcher: */
result = dispatcher_initialize(config_get_port(), config_get_pool_size(),
worker_run);
if (result)
{
if (config_get_use_shmem()) { shp_free(); }
return EXIT_FAILURE;
}
/* Run the dispatcher thread: */
result = dispatcher_start();
if (result)
{
fprintf(stderr, "[MAIN] Could not create dispatcher thread. "
"Error %d.\n\n", result);
dispatcher_stop();
if (config_get_use_shmem()) { shp_free(); }
return result;
}
printf("[MAIN] The proxy is now running.\n"
" Type q, and hit enter to kill the proxy.\n");
/* Wait for the user to q in the console to kill the thread: */
while ((result = getchar()) != 'q');
/* Clean memory pool if needed: */
if (config_get_use_shmem())
{
shp_free();
printf("[MAIN] Unlinked memory.\n");
}
/*
if (result)
{
fprintf(stderr, "[MAIN] Could not clean shmem. :(\n");
fprintf(stderr,
" All that shared memory is still sitting around.\n");
fprintf(stderr,
" You might want to reboot, or do whatever it is\n");
fprintf(stderr,
" people do to free shared memory.\n");
}
*/
/* If the user hit a key, means we should stop listening. Stop
* the dispatcher thread: */
printf("[MAIN] Killing dispatcher.\n");
result = dispatcher_stop();
if (result)
{
perror("[MAIN] Could not kill dispatcher thread. Error");
}
else
{
printf("[MAIN] Killed dispatcher.\n");
}
/* Done! */
if (result)
{
printf("[MAIN] Program terminated with errors.\n\n");
return EXIT_FAILURE;
}
else
{
printf("[MAIN] Program terminated cleanly.\n\n");
return EXIT_SUCCESS;
}
}

View File

@@ -0,0 +1,79 @@
#include <stdio.h>
#include <stdlib.h>
#include "common/queue.h"
#include "config.h"
#include "proxy_memory_pool.h"
static size_t m_chunk_count;
static shared_memory_t* m_memory_pool;
static queue_t m_free_memory;
int shp_initialize(size_t chunk_count, size_t chunk_size)
{
char buffer[16];
size_t i = 0;
m_chunk_count = chunk_count;
/* Initialize the queue */
queue_initialize(&m_free_memory);
/* Allocate the shared memory array: */
m_memory_pool =
(shared_memory_t*) calloc(chunk_count, sizeof(shared_memory_t));
if (m_memory_pool == NULL)
{
fprintf(stderr, "[SHP] Could not allocate pool.\n");
return 1;
}
/* Allocate each of the memory chunks: */
for (i = 0; i < chunk_count; i++)
{
shared_memory_t* current_chunk = m_memory_pool + i;
/* Come up with a fancy name: */
sprintf(buffer, "%d", i + config_get_shmem_key());
if (sharedmem_create(current_chunk, buffer, chunk_size))
{
fprintf(stderr, "[SHP] Could not allocate a shared memory thing.\n");
return 1;
}
/* Mark memory chunk as free. */
queue_enqueue(&m_free_memory, current_chunk);
}
return 0;
}
shared_memory_t* shp_borrow()
{
return (shared_memory_t*) queue_dequeue(&m_free_memory);
}
void shp_return(shared_memory_t* mem)
{
queue_enqueue(&m_free_memory, mem);
}
void shp_free()
{
size_t i = 0;
/* Clean the queue: */
queue_free(&m_free_memory);
/* Clean each shared memory chunk: */
for (i = 0; i < m_chunk_count; i++)
{
sharedmem_unlink(m_memory_pool + i);
}
/* Free array thing: */
free(m_memory_pool);
}

View File

@@ -0,0 +1,21 @@
#ifndef _PROXY_MEMORY_POOL_H_
#define _PROXY_MEMORY_POOL_H_
#include "common/shared_memory.h"
/* Initializes the shared memory pool. The chunk_count parameter is the number
* of memory chunks to pre-allocate. The parameter chunk_size is the size of the
* data section of every memory chunk allocated. */
int shp_initialize(size_t chunk_count, size_t chunk_size);
/* Borrows a shared memory chunk from the pool. You better give it back. Because
mallocing and not freeing is uncool.*/
shared_memory_t* shp_borrow();
/* Returns the shared memory chunk to the pool. */
void shp_return(shared_memory_t* mem);
/* Cleans stuff up. */
void shp_free();
#endif/*_PROXY_MEMORY_POOL_H_*/

View File

@@ -0,0 +1,237 @@
#include <stdlib.h>
#include <sys/stat.h>
#include "common/channel.h"
#include "common/data.h"
#include "common/debug.h"
#include "common/http.h"
#include "common/networking.h"
#include "common/queue.h"
#include "common/shared_memory.h"
#include "common/util.h"
#include "config.h"
#include "proxy_memory_pool.h"
#include "worker.h"
/* Returns whether or not we can use shared memory for a particular
transfer. */
static int m_can_use_shmem(const char* host, const port_t port)
{
shared_memory_t port_mem;
port_t sport;
if (!config_get_use_shmem()) return 0;
else return 1;
if (!net_is_localhost(host)) return 0;
/* Check that our own server is running. */
if (sharedmem_open(&port_mem, SHNAME_SERVER_RUNNING))
{
/* Could not open shared memory segment that normally the server will
create for us and put the port in. You know what that means, right?
RIGHT?! Well, if not, then it means either our own server is not
running, or that it was having problems with shared memory. Or, ya
know, *we* are having problems with shared memory. Any way, that
means we want to default to socket transfer. */
return 0;
}
if (sharedmem_read_nb(&port_mem, &sport, sizeof(port_t)) != sizeof(port_t))
{
/* Couldn't read port number from shmem. That would be a bad thing. */
sport = 0;
}
sharedmem_close(&port_mem);
DEBUG_PRINTF(("[WRK] Server running on %d; requested on %d\n\n",
sport, port));
return sport == port;
}
static int m_open_server_socket(socket_t* result,
const char* host, const port_t port)
{
sockaddress_t server_addr;
/* Get server address information */
if (net_get_hostaddr(&server_addr, host, port))
{
/* Could not resolve the url into an address. */
return 1;
}
/* Establish a connection to the server: */
*result = net_open_data_socket(&server_addr);
if (IS_BAD_SOCKET(*result))
{
/* Could not establish connection to the server: */
return 1;
}
return 0;
}
/* Transfers the file from the requested server to the client. */
static void m_transfer_file(channel_t* client, const char* host,
const port_t port, const char* path)
{
int result = 0;
int do_local = 0;
const char* method = NULL;
char* uri = NULL;
socket_t server_socket;
channel_t server_request_channel;
channel_t server_data_channel;
size_t bytes_transferred;
/* Open server socket: */
result = m_open_server_socket(&server_socket, host, port);
if (result)
{
http_send_canned_response(client, HTTP_STATUS_INTERNALERROR);
return;
}
ch_init_sock(&server_request_channel, &server_socket);
/* Check if we are doing a local or a remote transfer: */
do_local = m_can_use_shmem(host, port);
if (do_local)
{
shared_memory_t* memory = shp_borrow();
ch_init_shmem(&server_data_channel, memory);
method = HTTP_METHOD_LOCAL_GET;
uri = strcatd(uri, path);
uri = strcatd(uri, " ");
uri = strcatd(uri, memory->name);
}
else
{
ch_init_sock(&server_data_channel, &server_socket);
method = HTTP_METHOD_GET;
uri = strcatd(uri, path);
}
/* Send a request to the server: */
result = http_send_request_header(&server_request_channel, method,
uri, host);
if (result)
{
/* Could not send the request: */
http_send_canned_response(client, HTTP_STATUS_INTERNALERROR);
/* Good god... Is this one of the few valid uses of goto?! *gasp* */
goto transfer_done;
}
/* Transfer the file: */
bytes_transferred = ch_route(&server_data_channel, client, 0);
transfer_done:
/* Clean up: */
free(uri);
net_close_socket(server_socket);
if (do_local) shp_return((shared_memory_t*) (server_data_channel.channel));
DEBUG_PRINTF(("[WRK] Transfer done - %d bytes.\n", bytes_transferred));
}
/* 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, channel_t* client)
{
int result = 0;
char* req_uri = NULL;
char* req_host;
char* req_path;
port_t req_port;
/* Get the request method: */
const char* method = http_get_method(header);
if (strcmp(method, HTTP_METHOD_GET))
{
/* Unsupported method: */
fprintf(stderr, "[WRK] Unsupported method...\n"
" Expected (%p) \"%s\"\n"
" Got (%p) \"%s\"\n",
HTTP_METHOD_GET, HTTP_METHOD_GET, method, method);
http_send_canned_response(client, HTTP_STATUS_NOTIMPLEMENTED);
return;
}
/* Get the requested URI: */
req_uri = http_get_requesturi(header);
if (!req_uri)
{
/* Could not parse the name out of the header: */
http_send_canned_response(client, HTTP_STATUS_BADREQUEST);
return;
}
/* Parse the requested URI: */
result = parse_url(req_uri, &req_host, &req_port, &req_path);
if (result)
{
/* Could not parse the URL: */
http_send_canned_response(client, HTTP_STATUS_BADREQUEST);
free(req_uri);
return;
}
/* Transfer the file. */
m_transfer_file(client, req_host, req_port, req_path);
/* Clean up: */
free(req_uri);
free(req_host);
free(req_path);
}
static void m_handle_client(socket_t csocket)
{
channel_t client;
char* header;
ch_init_sock(&client, &csocket);
header = http_read_header(&client);
if (!header)
{
DEBUG_PRINTF(("[WRK] Did not get a header...\n"));
return;
}
/* Process the request: */
m_process_request(header, &client);
/* Free the header string: */
free(header);
}
void* worker_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);
/* Clean up the socket: */
DEBUG_PRINTF(("[WRK] Shutting down client socket.\n"));
net_close_socket(client);
}
}
return NULL;
}

View File

@@ -0,0 +1,14 @@
#ifndef _WORKER_H_
#define _WORKER_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* worker_run(void* p);
#endif/*_WORKER_H_*/

View File

@@ -0,0 +1 @@
obj

View File

@@ -0,0 +1,8 @@
/.cvsignore/1.1/Tue Feb 28 00:39:12 2006//
/Makefile/1.3/Mon Mar 27 21:07:03 2006//
/client.c/1.8/Wed Mar 22 00:13:14 2006//
/client.h/1.2/Wed Mar 22 00:13:14 2006//
/config.c/1.2/Wed Mar 22 00:13:14 2006//
/config.h/1.1/Tue Feb 28 00:39:12 2006//
/main.c/1.8/Thu Mar 23 19:37:19 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj2/src/server

View File

@@ -0,0 +1 @@
/usr/_CVS

View 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: crono $
# $Date: 2006/03/27 21:07:03 $
# $Revision: 1.3 $
#
##############################################################################
########################### 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=gnu99 -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

View File

@@ -0,0 +1,263 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "common/channel.h"
#include "common/debug.h"
#include "common/http.h"
#include "common/networking.h"
#include "common/queue.h"
#include "common/shared_memory.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;
}
/* Does the common output processing into the output channel. */
static void m_process_request(const char* header, channel_t* output)
{
char* requested_file = NULL;
char* local_file = NULL;
FILE* input = NULL;
/* Get the requested file: */
requested_file = http_get_requesturi(header);
if (!requested_file)
{
/* Could not parse the name out of the header: */
http_send_canned_response(output, 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(requested_file);
if (!local_file)
{
http_send_canned_response(output, HTTP_STATUS_BADREQUEST);
free(requested_file);
return;
}
/* Check whether the file exists: */
if (!m_file_exists(local_file))
{
http_send_canned_response(output, HTTP_STATUS_NOTFOUND);
free(requested_file);
free(local_file);
return;
}
/* Try to open the file: */
input = fopen(local_file, "r");
if (!input)
{
http_send_canned_response(output, HTTP_STATUS_FORBIDDEN);
free(requested_file);
free(local_file);
return;
}
/* Send the file: */
if (!http_send_response_header(output, HTTP_STATUS_OK))
{
/* Header got sent ok, can send the file: */
channel_t inc;
ch_init_file(&inc, input);
ch_route(&inc, output, 0);
}
/* Clean up: */
free(requested_file);
free(local_file);
fclose(input);
}
static char* m_get_memory_name(const char* header)
{
char* start = ((char*) strchr(header, ' ')) + 1;
if (start == NULL)
{
return NULL;
}
else
{
start = ((char*) strchr(start, ' ')) + 1;
if (start == NULL)
{
return NULL;
}
else
{
/* Count the length of the requested URI: */
char* ptr = NULL;
size_t count = 0;
for (ptr = start; *ptr != ' '; ptr++, count++)
{
/* Check if we've reached the end of the string without
encountering a second space: */
if (*ptr == '\0') return NULL;
}
return strncatd(NULL, start, count);
}
}
}
/* Handles a local request from our proxy. */
static void m_process_shared(const char* header, channel_t* channel_in)
{
channel_t channel_out;
shared_memory_t memory;
char* memory_name = NULL;
/* Get memory name: */
if ((memory_name = m_get_memory_name(header)) == NULL)
{
http_send_canned_response(channel_in, HTTP_STATUS_BADREQUEST);
return;
}
/* Open memory segment: */
if (sharedmem_open(&memory, memory_name))
{
fprintf(stderr,
"[CLI] Could not open memory \"%s\".\n", memory_name);
http_send_canned_response(channel_in, HTTP_STATUS_INTERNALERROR);
free(memory_name);
return;
}
/* Wrap channel around memory: */
ch_init_shmem(&channel_out, &memory);
/* Do the common processing: */
m_process_request(header, &channel_out);
/* HACK: Ok, so there is no way to signal feof in shmem
atm. So... yeah. This here works around that. */
sharedmem_write(&memory, "\0", 0);
/* Clean up: */
free(memory_name);
sharedmem_close(&memory);
}
/* Processes the request. This guy basically checks what kind of request this
is, and sets up the appropriate output channel. */
static void m_pick_dispatcher(const char* header, channel_t* channel_in)
{
/* Get the request method: */
const char* method = http_get_method(header);
if (strcmp(method, HTTP_METHOD_GET) == 0)
{
m_process_request(header, channel_in);
}
else if (strcmp(method, HTTP_METHOD_LOCAL_GET) == 0)
{
m_process_shared(header, channel_in);
}
else
{
/* Unsupported method: */
fprintf(stderr, "[CLI] Unsupported method %s\n", HTTP_METHOD_GET);
http_send_canned_response(channel_in, HTTP_STATUS_NOTIMPLEMENTED);
}
}
static void m_handle_client(socket_t csocket)
{
char* header = NULL;
channel_t channel_in;
/* Initialize the incoming channel: */
ch_init_sock(&channel_in, &csocket);
/* Read the header: */
header = http_read_header(&channel_in);
if (!header)
{
DEBUG_PRINTF(("[CLI] Did not get a header... No response to send.\n"));
return;
}
/* Process the request: */
m_pick_dispatcher(header, &channel_in);
/* Free the header string: */
free(header);
/* Clean up the socket: */
DEBUG_PRINTF(("[CLI] Shutting down client socket.\n"));
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;
}

View File

@@ -0,0 +1,14 @@
#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_*/

View 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; }

View 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_*/

View File

@@ -0,0 +1,109 @@
#include <stdio.h>
#include <stdlib.h>
#include "common/data.h"
#include "common/dispatcher.h"
#include "common/networking.h"
#include "common/shared_memory.h"
#include "config.h"
#include "client.h"
int main(int argc, const char** argv) {
int result;
shared_memory_t port_mem;
int started_memory;
/* Read configuration parameters: */
result = config_init(argc, argv);
if (result)
{
return EXIT_FAILURE;
}
/* Initialize the network system: */
result = net_initialize();
if (result)
{
config_free();
return EXIT_FAILURE;
}
/* Initialize the dispatcher: */
result = dispatcher_initialize(config_get_port(), config_get_pool_size(),
client_run);
if (result)
{
config_free();
return EXIT_FAILURE;
}
/* Open up the shared memory and put in the port number we are listening
on. */
result = sharedmem_create(&port_mem, SHNAME_SERVER_RUNNING, sizeof(port_t));
if (result)
{
/* Could not create shared memory... Oh well. */
fprintf(stderr,
"[MAIN] Could not open up shmem to tell people I am running.\n"
" Shared memory will not be used for file transfers.\n");
started_memory = 0;
}
else
{
port_t port = config_get_port();
sharedmem_write(&port_mem, &port, sizeof(port_t));
started_memory = 1;
}
/* Run the dispatcher thread: */
result = dispatcher_start();
if (result)
{
fprintf(stderr, "[MAIN] Could not create boss thread. "
"Error %d.\n\n", result);
dispatcher_stop();
config_free();
return result;
}
printf("[MAIN] The server is now running.\n"
" Type q, and hit enter to kill the server.\n");
/* Wait for the user to q in the console to kill the thread: */
while ((result = getchar()) != 'q');
/* Kill shared memory if needed: */
if (started_memory)
{
result = sharedmem_unlink(&port_mem);
if (result)
{
perror("[MAIN] Could not close shared memory");
fprintf(stderr,
"[MAIN] Run ipcs to hunt down stray memory chunks\n");
}
}
/* If the user hit a key, means we should stop listening. Kill the
* dispatcher thread: */
result = dispatcher_stop();
if (result)
{
fprintf(stderr, "[MAIN] Could not kill dispatcher thread. "
"Error %d.\n\n", result);
}
/* 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;
}
}

View File

@@ -0,0 +1,5 @@
/borrowed_test.c/1.2/Wed Mar 22 17:41:41 2006//
/host_test.c/1.2/Tue Mar 14 01:41:58 2006//
/sem_test.c/1.2/Sun Mar 12 04:36:56 2006//
/shm_test.c/1.3/Tue Mar 14 22:58:17 2006//
D

Some files were not shown because too many files have changed in this diff Show More