first commit
This commit is contained in:
1
CS4210/cs4210/proj2/.cvsignore
Normal file
1
CS4210/cs4210/proj2/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
bin
|
||||
10
CS4210/cs4210/proj2/CVS/Entries
Normal file
10
CS4210/cs4210/proj2/CVS/Entries
Normal 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////
|
||||
1
CS4210/cs4210/proj2/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2
|
||||
1
CS4210/cs4210/proj2/CVS/Root
Normal file
1
CS4210/cs4210/proj2/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
32
CS4210/cs4210/proj2/Makefile
Normal file
32
CS4210/cs4210/proj2/Makefile
Normal 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
14
CS4210/cs4210/proj2/TODO
Normal 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.
|
||||
|
||||
8
CS4210/cs4210/proj2/docs/CVS/Entries
Normal file
8
CS4210/cs4210/proj2/docs/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/docs/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/docs/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/docs
|
||||
1
CS4210/cs4210/proj2/docs/CVS/Root
Normal file
1
CS4210/cs4210/proj2/docs/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
BIN
CS4210/cs4210/proj2/docs/Project 2 Report.doc
Normal file
BIN
CS4210/cs4210/proj2/docs/Project 2 Report.doc
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj2/docs/Project2.pdf
Normal file
BIN
CS4210/cs4210/proj2/docs/Project2.pdf
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj2/docs/data.xls
Normal file
BIN
CS4210/cs4210/proj2/docs/data.xls
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj2/docs/report.pdf
Normal file
BIN
CS4210/cs4210/proj2/docs/report.pdf
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj2/docs/shmIntro.pdf
Normal file
BIN
CS4210/cs4210/proj2/docs/shmIntro.pdf
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj2/docs/sysVipc.pdf
Normal file
BIN
CS4210/cs4210/proj2/docs/sysVipc.pdf
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj2/docs/sysVshm.pdf
Normal file
BIN
CS4210/cs4210/proj2/docs/sysVshm.pdf
Normal file
Binary file not shown.
7
CS4210/cs4210/proj2/home/CVS/Entries
Normal file
7
CS4210/cs4210/proj2/home/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/home/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/home/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/home
|
||||
1
CS4210/cs4210/proj2/home/CVS/Root
Normal file
1
CS4210/cs4210/proj2/home/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
1058816
CS4210/cs4210/proj2/home/big.html
Normal file
1058816
CS4210/cs4210/proj2/home/big.html
Normal file
File diff suppressed because it is too large
Load Diff
3
CS4210/cs4210/proj2/home/file.html
Normal file
3
CS4210/cs4210/proj2/home/file.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html>
|
||||
Hello, world!
|
||||
</html>
|
||||
3
CS4210/cs4210/proj2/home/file2.html
Normal file
3
CS4210/cs4210/proj2/home/file2.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html>
|
||||
You shouldn't be seeing this.
|
||||
</html>
|
||||
33
CS4210/cs4210/proj2/home/medium.html
Normal file
33
CS4210/cs4210/proj2/home/medium.html
Normal file
File diff suppressed because one or more lines are too long
69
CS4210/cs4210/proj2/home/small.html
Normal file
69
CS4210/cs4210/proj2/home/small.html
Normal 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>
|
||||
3
CS4210/cs4210/proj2/home/tiny.html
Normal file
3
CS4210/cs4210/proj2/home/tiny.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html>
|
||||
Hello, world!
|
||||
</html>
|
||||
9
CS4210/cs4210/proj2/results/CVS/Entries
Normal file
9
CS4210/cs4210/proj2/results/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/results/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/results/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/results
|
||||
1
CS4210/cs4210/proj2/results/CVS/Root
Normal file
1
CS4210/cs4210/proj2/results/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
9050
CS4210/cs4210/proj2/results/noshare_bigfile_16x16x16_1000
Normal file
9050
CS4210/cs4210/proj2/results/noshare_bigfile_16x16x16_1000
Normal file
File diff suppressed because it is too large
Load Diff
9053
CS4210/cs4210/proj2/results/noshare_multifile_16x16x16_1000
Normal file
9053
CS4210/cs4210/proj2/results/noshare_multifile_16x16x16_1000
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
6
CS4210/cs4210/proj2/src/CVS/Entries
Normal file
6
CS4210/cs4210/proj2/src/CVS/Entries
Normal file
@@ -0,0 +1,6 @@
|
||||
D/client////
|
||||
D/common////
|
||||
D/proxy////
|
||||
D/server////
|
||||
D/tests////
|
||||
D/tools////
|
||||
1
CS4210/cs4210/proj2/src/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/src/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/src
|
||||
1
CS4210/cs4210/proj2/src/CVS/Root
Normal file
1
CS4210/cs4210/proj2/src/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
1
CS4210/cs4210/proj2/src/client/.cvsignore
Normal file
1
CS4210/cs4210/proj2/src/client/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
obj
|
||||
12
CS4210/cs4210/proj2/src/client/CVS/Entries
Normal file
12
CS4210/cs4210/proj2/src/client/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/src/client/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/src/client/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/src/client
|
||||
1
CS4210/cs4210/proj2/src/client/CVS/Root
Normal file
1
CS4210/cs4210/proj2/src/client/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
106
CS4210/cs4210/proj2/src/client/Makefile
Normal file
106
CS4210/cs4210/proj2/src/client/Makefile
Normal file
@@ -0,0 +1,106 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Generic Makefile. Only need to modify the variables for src, obj,
|
||||
# and bin directories, and the name of the executable.
|
||||
#
|
||||
# $Author: vurazov $
|
||||
# $Date: 2006/02/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
|
||||
116
CS4210/cs4210/proj2/src/client/config.c
Normal file
116
CS4210/cs4210/proj2/src/client/config.c
Normal 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; }
|
||||
23
CS4210/cs4210/proj2/src/client/config.h
Normal file
23
CS4210/cs4210/proj2/src/client/config.h
Normal 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_*/
|
||||
176
CS4210/cs4210/proj2/src/client/job_manager.c
Normal file
176
CS4210/cs4210/proj2/src/client/job_manager.c
Normal 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);
|
||||
}
|
||||
54
CS4210/cs4210/proj2/src/client/job_manager.h
Normal file
54
CS4210/cs4210/proj2/src/client/job_manager.h
Normal 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_*/
|
||||
81
CS4210/cs4210/proj2/src/client/main.c
Normal file
81
CS4210/cs4210/proj2/src/client/main.c
Normal 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;
|
||||
}
|
||||
74
CS4210/cs4210/proj2/src/client/stat.c
Normal file
74
CS4210/cs4210/proj2/src/client/stat.c
Normal 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);
|
||||
}
|
||||
28
CS4210/cs4210/proj2/src/client/stat.h
Normal file
28
CS4210/cs4210/proj2/src/client/stat.h
Normal 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_*/
|
||||
160
CS4210/cs4210/proj2/src/client/worker.c
Normal file
160
CS4210/cs4210/proj2/src/client/worker.c
Normal 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);
|
||||
}
|
||||
14
CS4210/cs4210/proj2/src/client/worker.h
Normal file
14
CS4210/cs4210/proj2/src/client/worker.h
Normal 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_*/
|
||||
22
CS4210/cs4210/proj2/src/common/CVS/Entries
Normal file
22
CS4210/cs4210/proj2/src/common/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/src/common/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/src/common/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/src/common
|
||||
1
CS4210/cs4210/proj2/src/common/CVS/Root
Normal file
1
CS4210/cs4210/proj2/src/common/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
103
CS4210/cs4210/proj2/src/common/Makefile
Normal file
103
CS4210/cs4210/proj2/src/common/Makefile
Normal 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
|
||||
146
CS4210/cs4210/proj2/src/common/channel.c
Normal file
146
CS4210/cs4210/proj2/src/common/channel.c
Normal 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;
|
||||
}
|
||||
69
CS4210/cs4210/proj2/src/common/channel.h
Normal file
69
CS4210/cs4210/proj2/src/common/channel.h
Normal 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_*/
|
||||
13
CS4210/cs4210/proj2/src/common/data.h
Normal file
13
CS4210/cs4210/proj2/src/common/data.h
Normal 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_*/
|
||||
14
CS4210/cs4210/proj2/src/common/debug.h
Normal file
14
CS4210/cs4210/proj2/src/common/debug.h
Normal 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__*/
|
||||
141
CS4210/cs4210/proj2/src/common/dispatcher.c
Normal file
141
CS4210/cs4210/proj2/src/common/dispatcher.c
Normal 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;
|
||||
}
|
||||
33
CS4210/cs4210/proj2/src/common/dispatcher.h
Normal file
33
CS4210/cs4210/proj2/src/common/dispatcher.h
Normal 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_*/
|
||||
132
CS4210/cs4210/proj2/src/common/http.c
Normal file
132
CS4210/cs4210/proj2/src/common/http.c
Normal 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;
|
||||
}
|
||||
52
CS4210/cs4210/proj2/src/common/http.h
Normal file
52
CS4210/cs4210/proj2/src/common/http.h
Normal 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_*/
|
||||
208
CS4210/cs4210/proj2/src/common/networking.c
Normal file
208
CS4210/cs4210/proj2/src/common/networking.c
Normal 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");
|
||||
}
|
||||
106
CS4210/cs4210/proj2/src/common/networking.h
Normal file
106
CS4210/cs4210/proj2/src/common/networking.h
Normal 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_*/
|
||||
162
CS4210/cs4210/proj2/src/common/queue.c
Normal file
162
CS4210/cs4210/proj2/src/common/queue.c
Normal 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;
|
||||
}
|
||||
69
CS4210/cs4210/proj2/src/common/queue.h
Normal file
69
CS4210/cs4210/proj2/src/common/queue.h
Normal 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_*/
|
||||
134
CS4210/cs4210/proj2/src/common/semaphore.c
Normal file
134
CS4210/cs4210/proj2/src/common/semaphore.c
Normal 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;
|
||||
}
|
||||
50
CS4210/cs4210/proj2/src/common/semaphore.h
Normal file
50
CS4210/cs4210/proj2/src/common/semaphore.h
Normal 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_*/
|
||||
323
CS4210/cs4210/proj2/src/common/shared_memory.c
Normal file
323
CS4210/cs4210/proj2/src/common/shared_memory.c
Normal 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;
|
||||
}
|
||||
78
CS4210/cs4210/proj2/src/common/shared_memory.h
Normal file
78
CS4210/cs4210/proj2/src/common/shared_memory.h
Normal 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_*/
|
||||
8
CS4210/cs4210/proj2/src/common/threading.h
Normal file
8
CS4210/cs4210/proj2/src/common/threading.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _THREADING_H_
|
||||
#define _THREADING_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#endif/*_THREADING_H_*/
|
||||
|
||||
85
CS4210/cs4210/proj2/src/common/timer.h
Normal file
85
CS4210/cs4210/proj2/src/common/timer.h
Normal 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_*/
|
||||
190
CS4210/cs4210/proj2/src/common/util.c
Normal file
190
CS4210/cs4210/proj2/src/common/util.c
Normal 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;
|
||||
}
|
||||
}
|
||||
74
CS4210/cs4210/proj2/src/common/util.h
Normal file
74
CS4210/cs4210/proj2/src/common/util.h
Normal 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_*/
|
||||
1
CS4210/cs4210/proj2/src/proxy/.cvsignore
Normal file
1
CS4210/cs4210/proj2/src/proxy/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
obj
|
||||
10
CS4210/cs4210/proj2/src/proxy/CVS/Entries
Normal file
10
CS4210/cs4210/proj2/src/proxy/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/src/proxy/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/src/proxy/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/src/proxy
|
||||
1
CS4210/cs4210/proj2/src/proxy/CVS/Root
Normal file
1
CS4210/cs4210/proj2/src/proxy/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
106
CS4210/cs4210/proj2/src/proxy/Makefile
Normal file
106
CS4210/cs4210/proj2/src/proxy/Makefile
Normal file
@@ -0,0 +1,106 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Generic Makefile. Only need to modify the variables for src, obj,
|
||||
# and bin directories, and the name of the executable.
|
||||
#
|
||||
# $Author: 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
|
||||
146
CS4210/cs4210/proj2/src/proxy/config.c
Normal file
146
CS4210/cs4210/proj2/src/proxy/config.c
Normal 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; }
|
||||
39
CS4210/cs4210/proj2/src/proxy/config.h
Normal file
39
CS4210/cs4210/proj2/src/proxy/config.h
Normal 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_*/
|
||||
107
CS4210/cs4210/proj2/src/proxy/main.c
Normal file
107
CS4210/cs4210/proj2/src/proxy/main.c
Normal 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;
|
||||
}
|
||||
}
|
||||
79
CS4210/cs4210/proj2/src/proxy/proxy_memory_pool.c
Normal file
79
CS4210/cs4210/proj2/src/proxy/proxy_memory_pool.c
Normal 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);
|
||||
}
|
||||
|
||||
21
CS4210/cs4210/proj2/src/proxy/proxy_memory_pool.h
Normal file
21
CS4210/cs4210/proj2/src/proxy/proxy_memory_pool.h
Normal 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_*/
|
||||
237
CS4210/cs4210/proj2/src/proxy/worker.c
Normal file
237
CS4210/cs4210/proj2/src/proxy/worker.c
Normal 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;
|
||||
}
|
||||
14
CS4210/cs4210/proj2/src/proxy/worker.h
Normal file
14
CS4210/cs4210/proj2/src/proxy/worker.h
Normal 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_*/
|
||||
1
CS4210/cs4210/proj2/src/server/.cvsignore
Normal file
1
CS4210/cs4210/proj2/src/server/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
obj
|
||||
8
CS4210/cs4210/proj2/src/server/CVS/Entries
Normal file
8
CS4210/cs4210/proj2/src/server/CVS/Entries
Normal 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
|
||||
1
CS4210/cs4210/proj2/src/server/CVS/Repository
Normal file
1
CS4210/cs4210/proj2/src/server/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj2/src/server
|
||||
1
CS4210/cs4210/proj2/src/server/CVS/Root
Normal file
1
CS4210/cs4210/proj2/src/server/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
106
CS4210/cs4210/proj2/src/server/Makefile
Normal file
106
CS4210/cs4210/proj2/src/server/Makefile
Normal file
@@ -0,0 +1,106 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Generic Makefile. Only need to modify the variables for src, obj,
|
||||
# and bin directories, and the name of the executable.
|
||||
#
|
||||
# $Author: 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
|
||||
263
CS4210/cs4210/proj2/src/server/client.c
Normal file
263
CS4210/cs4210/proj2/src/server/client.c
Normal 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;
|
||||
}
|
||||
14
CS4210/cs4210/proj2/src/server/client.h
Normal file
14
CS4210/cs4210/proj2/src/server/client.h
Normal 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_*/
|
||||
96
CS4210/cs4210/proj2/src/server/config.c
Normal file
96
CS4210/cs4210/proj2/src/server/config.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* Some default values */
|
||||
#define CONFIG_DVALUE_PORT 1337
|
||||
#define CONFIG_DVALUE_POOLSIZE 16
|
||||
#define CONFIG_DVALUE_HOMEDIR "."
|
||||
|
||||
/* Some parameter names */
|
||||
#define CONFIG_PNAME_PORT "port"
|
||||
#define CONFIG_PNAME_POOLSIZE "pool-size"
|
||||
#define CONFIG_PNAME_HOMEDIR "home"
|
||||
|
||||
/* The port number to run the server on. */
|
||||
static port_t m_server_port = -1;
|
||||
|
||||
/* The number of child threads to create. */
|
||||
static int m_pool_size = -1;
|
||||
|
||||
/* The root directory for the server's files. */
|
||||
static char* m_home_dir = NULL;
|
||||
|
||||
/* Records the parameter. If the name is unknown, prints a warning out to the
|
||||
* console and usage, and returns an error code. */
|
||||
int record_parameter(const char* name, const char* value)
|
||||
{
|
||||
if (!strcmp(name, CONFIG_PNAME_PORT))
|
||||
{
|
||||
/* Got port number: */
|
||||
m_server_port = atoi(value);
|
||||
printf("[CONF] Overriding default %s with value %d\n",
|
||||
CONFIG_PNAME_PORT, m_server_port);
|
||||
return 0;
|
||||
}
|
||||
else if(!strcmp(name, CONFIG_PNAME_POOLSIZE))
|
||||
{
|
||||
/* Got pool size: */
|
||||
m_pool_size = atoi(value);
|
||||
printf("[CONF] Overriding default %s with value %d\n",
|
||||
CONFIG_PNAME_POOLSIZE, m_pool_size);
|
||||
return 0;
|
||||
}
|
||||
else if(!strcmp(name, CONFIG_PNAME_HOMEDIR))
|
||||
{
|
||||
/* Got home dir: */
|
||||
free(m_home_dir);
|
||||
m_home_dir = strdup(value);
|
||||
printf("[CONF] Overriding default %s with value \"%s\"\n",
|
||||
CONFIG_PNAME_HOMEDIR, m_home_dir);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown parameter: */
|
||||
fprintf(stderr, "[CONF] Unknown parameter \"%s\"\n", name);
|
||||
config_print_parameters(stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void config_print_parameters(FILE* out)
|
||||
{
|
||||
fprintf(out, "Supported parameters:\n");
|
||||
fprintf(out, "\t%s - the port to listen on. Default value is %d.\n",
|
||||
CONFIG_PNAME_PORT, CONFIG_DVALUE_PORT);
|
||||
fprintf(out, "\t%s - the number of threads to pre-create to handle\n"
|
||||
"\t\tclient requests.\n"
|
||||
"\t\tDefault value is %d.\n",
|
||||
CONFIG_PNAME_POOLSIZE, CONFIG_DVALUE_POOLSIZE);
|
||||
fprintf(out, "\t%s - the root directory for the server's files."
|
||||
"\n\t\tDefault value is \"%s\".\n",
|
||||
CONFIG_PNAME_HOMEDIR, CONFIG_DVALUE_HOMEDIR);
|
||||
fprintf(out, "\t\n");
|
||||
}
|
||||
|
||||
int config_init(int argc, const char** argv)
|
||||
{
|
||||
/* Initialize default values: */
|
||||
m_server_port = CONFIG_DVALUE_PORT;
|
||||
m_pool_size = CONFIG_DVALUE_POOLSIZE;
|
||||
m_home_dir = strdup(CONFIG_DVALUE_HOMEDIR);
|
||||
|
||||
return parse_command_parameters(argc, argv, record_parameter);
|
||||
}
|
||||
|
||||
void config_free()
|
||||
{
|
||||
free(m_home_dir);
|
||||
}
|
||||
|
||||
port_t config_get_port() { return m_server_port; }
|
||||
int config_get_pool_size() { return m_pool_size; }
|
||||
const char* config_get_home_dir() { return m_home_dir; }
|
||||
31
CS4210/cs4210/proj2/src/server/config.h
Normal file
31
CS4210/cs4210/proj2/src/server/config.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef _SERVER_CONFIG_H_
|
||||
#define _SERVER_CONFIG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/networking.h"
|
||||
|
||||
/* Records the parameter with the given name and value. */
|
||||
int record_parameter(const char* name, const char* value);
|
||||
|
||||
/* Initializes the configuration with the parameters specified. */
|
||||
int config_init(int argc, const char** argv);
|
||||
|
||||
/* Cleans up whatever resources the configuration consumed. */
|
||||
void config_free();
|
||||
|
||||
/* Given a stream, will print the list of supported parameters to the
|
||||
* stream. */
|
||||
void config_print_parameters(FILE* out);
|
||||
|
||||
/* Returns the port to start the server on. */
|
||||
port_t config_get_port();
|
||||
|
||||
/* Returns the number of child threads to spawn for handling client
|
||||
* requests. */
|
||||
int config_get_pool_size();
|
||||
|
||||
/* Returns the root directory for the server's files. */
|
||||
const char* config_get_home_dir();
|
||||
|
||||
#endif/*_SERVER_CONFIG_H_*/
|
||||
109
CS4210/cs4210/proj2/src/server/main.c
Normal file
109
CS4210/cs4210/proj2/src/server/main.c
Normal 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;
|
||||
}
|
||||
}
|
||||
5
CS4210/cs4210/proj2/src/tests/CVS/Entries
Normal file
5
CS4210/cs4210/proj2/src/tests/CVS/Entries
Normal 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
Reference in New Issue
Block a user