first commit
This commit is contained in:
1
CS4210/cs4210/proj3/.cvsignore
Normal file
1
CS4210/cs4210/proj3/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
bin
|
||||
9
CS4210/cs4210/proj3/CVS/Entries
Normal file
9
CS4210/cs4210/proj3/CVS/Entries
Normal file
@@ -0,0 +1,9 @@
|
||||
/.cvsignore/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/Makefile/1.3/Mon Apr 10 19:50:25 2006//
|
||||
/TODO/1.1/Thu Apr 13 23:27:01 2006//
|
||||
D/docs////
|
||||
D/home////
|
||||
D/results////
|
||||
D/src////
|
||||
D/urls////
|
||||
D/vs////
|
||||
1
CS4210/cs4210/proj3/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3
|
||||
1
CS4210/cs4210/proj3/CVS/Root
Normal file
1
CS4210/cs4210/proj3/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
32
CS4210/cs4210/proj3/Makefile
Normal file
32
CS4210/cs4210/proj3/Makefile
Normal file
@@ -0,0 +1,32 @@
|
||||
##############################################################################
|
||||
#
|
||||
# This file will recursively call client and server makefiles to build
|
||||
# those.
|
||||
#
|
||||
# $Author: vurazov $
|
||||
# $Date: 2006/04/10 19:50:25 $
|
||||
# $Revision: 1.3 $
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
BUILD_DIRS = common libjpeg client server proxy rpc_server
|
||||
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
|
||||
|
||||
4
CS4210/cs4210/proj3/TODO
Normal file
4
CS4210/cs4210/proj3/TODO
Normal file
@@ -0,0 +1,4 @@
|
||||
TODO:
|
||||
|
||||
o Handle the case where the rpc list file is not provided for the proxy.
|
||||
o Make sure everything compiles on helsinki.
|
||||
3
CS4210/cs4210/proj3/docs/CVS/Entries
Normal file
3
CS4210/cs4210/proj3/docs/CVS/Entries
Normal file
@@ -0,0 +1,3 @@
|
||||
/Project 3 Report.doc/1.1/Thu Apr 13 23:27:01 2006/-kb/
|
||||
/Project3.pdf/1.1/Tue Mar 21 16:42:15 2006/-kb/
|
||||
D
|
||||
1
CS4210/cs4210/proj3/docs/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/docs/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/docs
|
||||
1
CS4210/cs4210/proj3/docs/CVS/Root
Normal file
1
CS4210/cs4210/proj3/docs/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
BIN
CS4210/cs4210/proj3/docs/Project 3 Report.doc
Normal file
BIN
CS4210/cs4210/proj3/docs/Project 3 Report.doc
Normal file
Binary file not shown.
BIN
CS4210/cs4210/proj3/docs/Project3.pdf
Normal file
BIN
CS4210/cs4210/proj3/docs/Project3.pdf
Normal file
Binary file not shown.
10
CS4210/cs4210/proj3/home/CVS/Entries
Normal file
10
CS4210/cs4210/proj3/home/CVS/Entries
Normal file
@@ -0,0 +1,10 @@
|
||||
/big.html/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/big.jpg/1.1/Thu Apr 13 21:50:50 2006//
|
||||
/file.html/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/file2.html/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/medium.html/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/medium.jpg/1.1/Thu Apr 13 21:50:51 2006//
|
||||
/small.html/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/small.jpg/1.1/Thu Apr 13 21:50:51 2006//
|
||||
/tiny.html/1.1/Thu Apr 6 17:04:45 2006//
|
||||
D
|
||||
1
CS4210/cs4210/proj3/home/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/home/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/home
|
||||
1
CS4210/cs4210/proj3/home/CVS/Root
Normal file
1
CS4210/cs4210/proj3/home/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
1058816
CS4210/cs4210/proj3/home/big.html
Normal file
1058816
CS4210/cs4210/proj3/home/big.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
CS4210/cs4210/proj3/home/big.jpg
Normal file
BIN
CS4210/cs4210/proj3/home/big.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
3
CS4210/cs4210/proj3/home/file.html
Normal file
3
CS4210/cs4210/proj3/home/file.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html>
|
||||
Hello, world!
|
||||
</html>
|
||||
3
CS4210/cs4210/proj3/home/file2.html
Normal file
3
CS4210/cs4210/proj3/home/file2.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html>
|
||||
You shouldn't be seeing this.
|
||||
</html>
|
||||
33
CS4210/cs4210/proj3/home/medium.html
Normal file
33
CS4210/cs4210/proj3/home/medium.html
Normal file
File diff suppressed because one or more lines are too long
BIN
CS4210/cs4210/proj3/home/medium.jpg
Normal file
BIN
CS4210/cs4210/proj3/home/medium.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 393 KiB |
69
CS4210/cs4210/proj3/home/small.html
Normal file
69
CS4210/cs4210/proj3/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>
|
||||
BIN
CS4210/cs4210/proj3/home/small.jpg
Normal file
BIN
CS4210/cs4210/proj3/home/small.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
3
CS4210/cs4210/proj3/home/tiny.html
Normal file
3
CS4210/cs4210/proj3/home/tiny.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html>
|
||||
Hello, world!
|
||||
</html>
|
||||
20
CS4210/cs4210/proj3/results/1_rpc_servers_all
Normal file
20
CS4210/cs4210/proj3/results/1_rpc_servers_all
Normal file
@@ -0,0 +1,20 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 1
|
||||
[CONF] Overriding default url-file with value "../../urls/server_all"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/big.jpg"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/medium.jpg"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/small.jpg"
|
||||
[JOBM] Processed 3 URLs from file
|
||||
Time: 58881.685791 ms.
|
||||
Received: 10266896 bytes.
|
||||
Throughtput: 174364.844723 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.143066 Avg: 0.236472 Max: 0.337891
|
||||
Std Dev: 0.074686
|
||||
|
||||
Time Per Connection:
|
||||
Min: 5.130127 Avg: 588.550293 Max: 1668.711182
|
||||
Std Dev: 744.087160
|
||||
|
||||
18
CS4210/cs4210/proj3/results/1_rpc_servers_big
Normal file
18
CS4210/cs4210/proj3/results/1_rpc_servers_big
Normal file
@@ -0,0 +1,18 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 1
|
||||
[CONF] Overriding default url-file with value "../../urls/server_big"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/big.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
Time: 165643.837891 ms.
|
||||
Received: 28994000 bytes.
|
||||
Throughtput: 175038.204676 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.155029 Avg: 0.248618 Max: 0.427979
|
||||
Std Dev: 0.074619
|
||||
|
||||
Time Per Connection:
|
||||
Min: 1641.167969 Avg: 1656.152517 Max: 1761.429932
|
||||
Std Dev: nan
|
||||
|
||||
18
CS4210/cs4210/proj3/results/1_rpc_servers_medium
Normal file
18
CS4210/cs4210/proj3/results/1_rpc_servers_medium
Normal file
@@ -0,0 +1,18 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 1
|
||||
[CONF] Overriding default url-file with value "../../urls/server_medium"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/medium.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
Time: 7769.288818 ms.
|
||||
Received: 1162500 bytes.
|
||||
Throughtput: 149627.594903 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.147949 Avg: 0.209326 Max: 0.420166
|
||||
Std Dev: 0.074217
|
||||
|
||||
Time Per Connection:
|
||||
Min: 76.454102 Avg: 77.452068 Max: 112.973877
|
||||
Std Dev: nan
|
||||
|
||||
18
CS4210/cs4210/proj3/results/1_rpc_servers_small
Normal file
18
CS4210/cs4210/proj3/results/1_rpc_servers_small
Normal file
@@ -0,0 +1,18 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 1
|
||||
[CONF] Overriding default url-file with value "../../urls/server_small"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/small.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
Time: 565.555908 ms.
|
||||
Received: 76700 bytes.
|
||||
Throughtput: 135618.775947 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.160889 Avg: 0.244602 Max: 0.631836
|
||||
Std Dev: 0.081830
|
||||
|
||||
Time Per Connection:
|
||||
Min: 4.922852 Avg: 5.388359 Max: 21.858887
|
||||
Std Dev: nan
|
||||
|
||||
18
CS4210/cs4210/proj3/results/2_rpc_servers_big
Normal file
18
CS4210/cs4210/proj3/results/2_rpc_servers_big
Normal file
@@ -0,0 +1,18 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 3
|
||||
[CONF] Overriding default url-file with value "../../urls/server_big"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/big.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
Time: 83548.840088 ms.
|
||||
Received: 28994000 bytes.
|
||||
Throughtput: 347030.550867 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.149170 Avg: 0.606499 Max: 1.400879
|
||||
Std Dev: 0.390169
|
||||
|
||||
Time Per Connection:
|
||||
Min: 1645.946045 Avg: 2483.599607 Max: 3319.400879
|
||||
Std Dev: 523.884116
|
||||
|
||||
18
CS4210/cs4210/proj3/results/2_rpc_servers_medium
Normal file
18
CS4210/cs4210/proj3/results/2_rpc_servers_medium
Normal file
@@ -0,0 +1,18 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 3
|
||||
[CONF] Overriding default url-file with value "../../urls/server_medium"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/medium.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
Time: 3980.062988 ms.
|
||||
Received: 1162500 bytes.
|
||||
Throughtput: 292080.804606 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.187988 Avg: 0.743369 Max: 1.389160
|
||||
Std Dev: 0.274335
|
||||
|
||||
Time Per Connection:
|
||||
Min: 99.695068 Avg: 117.477622 Max: 191.903076
|
||||
Std Dev: 5.813423
|
||||
|
||||
18
CS4210/cs4210/proj3/results/2_rpc_servers_small
Normal file
18
CS4210/cs4210/proj3/results/2_rpc_servers_small
Normal file
@@ -0,0 +1,18 @@
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 3
|
||||
[CONF] Overriding default url-file with value "../../urls/server_small"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/small.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
Time: 275.562988 ms.
|
||||
Received: 76700 bytes.
|
||||
Throughtput: 278339.266381 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.179932 Avg: 0.381272 Max: 0.697021
|
||||
Std Dev: 0.150099
|
||||
|
||||
Time Per Connection:
|
||||
Min: 5.760986 Avg: 7.752185 Max: 17.416992
|
||||
Std Dev: 1.870732
|
||||
|
||||
16
CS4210/cs4210/proj3/results/3_rpc_servers_bigfile
Normal file
16
CS4210/cs4210/proj3/results/3_rpc_servers_bigfile
Normal file
@@ -0,0 +1,16 @@
|
||||
[CONF] Overriding default thread-count with value 3
|
||||
[CONF] Overriding default url-file with value "../../urls/server_big"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/big.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
Time: 68283.556885 ms.
|
||||
Received: 28025036 bytes.
|
||||
Throughtput: 410421.443735 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.158936 Avg: 0.993586 Max: 3.490967
|
||||
Std Dev: 0.837578
|
||||
|
||||
Time Per Connection:
|
||||
Min: 1621.567871 Avg: 2017.347012 Max: 3675.130859
|
||||
Std Dev: 743.604367
|
||||
17
CS4210/cs4210/proj3/results/3_rpc_servers_mediumfile
Normal file
17
CS4210/cs4210/proj3/results/3_rpc_servers_mediumfile
Normal file
@@ -0,0 +1,17 @@
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 3
|
||||
[CONF] Overriding default url-file with value "../../urls/server_medium"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/medium.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
Time: 3807.099121 ms.
|
||||
Received: 1150875 bytes.
|
||||
Throughtput: 302297.093770 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.145020 Avg: 2.773372 Max: 10.615967
|
||||
Std Dev: 2.458950
|
||||
|
||||
Time Per Connection:
|
||||
Min: 77.269775 Avg: 110.647954 Max: 231.712891
|
||||
Std Dev: 35.130389
|
||||
17
CS4210/cs4210/proj3/results/3_rpc_servers_multifile
Normal file
17
CS4210/cs4210/proj3/results/3_rpc_servers_multifile
Normal file
@@ -0,0 +1,17 @@
|
||||
[CONF] Overriding default url-file with value "../../urls/server_all"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/big.jpg"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/medium.jpg"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/small.jpg"
|
||||
[JOBM] Processed 3 URLs from file
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
Time: 26494.181152 ms.
|
||||
Received: 10211192 bytes.
|
||||
Throughtput: 385412.628580 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.135010 Avg: 0.595095 Max: 5.930908
|
||||
Std Dev: 0.847990
|
||||
|
||||
Time Per Connection:
|
||||
Min: 5.297119 Avg: 735.360203 Max: 3642.307129
|
||||
Std Dev: 1053.916789
|
||||
17
CS4210/cs4210/proj3/results/3_rpc_servers_smallfile
Normal file
17
CS4210/cs4210/proj3/results/3_rpc_servers_smallfile
Normal file
@@ -0,0 +1,17 @@
|
||||
[CONF] Overriding default job-count with value 100
|
||||
[CONF] Overriding default thread-count with value 3
|
||||
[CONF] Overriding default url-file with value "../../urls/server_small"
|
||||
[JOBM] Got URL "http://gandalf.cc.gatech.edu:8080/http://gandalf.cc.gatech.edu:1337/small.jpg"
|
||||
[JOBM] Processed 1 URLs from file
|
||||
[MAIN] Initialization Complete. Starting work.
|
||||
Time: 5221.895996 ms.
|
||||
Received: 76700 bytes.
|
||||
Throughtput: 14688.151594 bps.
|
||||
|
||||
Connection Latency Stats:
|
||||
Min: 0.164062 Avg: 0.347798 Max: 0.720947
|
||||
Std Dev: 0.145971
|
||||
|
||||
Time Per Connection:
|
||||
Min: 5.025146 Avg: 57.705647 Max: 5007.342041
|
||||
Std Dev: 497.484843
|
||||
13
CS4210/cs4210/proj3/results/CVS/Entries
Normal file
13
CS4210/cs4210/proj3/results/CVS/Entries
Normal file
@@ -0,0 +1,13 @@
|
||||
/1_rpc_servers_all/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/1_rpc_servers_big/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/1_rpc_servers_medium/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/1_rpc_servers_small/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/2_rpc_servers_big/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/2_rpc_servers_medium/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/2_rpc_servers_small/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/3_rpc_servers_bigfile/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/3_rpc_servers_mediumfile/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/3_rpc_servers_multifile/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/3_rpc_servers_smallfile/1.1/Thu Apr 13 22:55:51 2006//
|
||||
/data.xls/1.1/Thu Apr 13 23:44:40 2006/-kb/
|
||||
D
|
||||
1
CS4210/cs4210/proj3/results/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/results/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/results
|
||||
1
CS4210/cs4210/proj3/results/CVS/Root
Normal file
1
CS4210/cs4210/proj3/results/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
BIN
CS4210/cs4210/proj3/results/data.xls
Normal file
BIN
CS4210/cs4210/proj3/results/data.xls
Normal file
Binary file not shown.
8
CS4210/cs4210/proj3/src/CVS/Entries
Normal file
8
CS4210/cs4210/proj3/src/CVS/Entries
Normal file
@@ -0,0 +1,8 @@
|
||||
D/client////
|
||||
D/common////
|
||||
D/examples////
|
||||
D/libjpeg////
|
||||
D/proxy////
|
||||
D/rpc////
|
||||
D/rpc_server////
|
||||
D/server////
|
||||
1
CS4210/cs4210/proj3/src/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/src/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src
|
||||
1
CS4210/cs4210/proj3/src/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
1
CS4210/cs4210/proj3/src/client/.cvsignore
Normal file
1
CS4210/cs4210/proj3/src/client/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
obj
|
||||
12
CS4210/cs4210/proj3/src/client/CVS/Entries
Normal file
12
CS4210/cs4210/proj3/src/client/CVS/Entries
Normal file
@@ -0,0 +1,12 @@
|
||||
/.cvsignore/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/Makefile/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/config.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/config.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/job_manager.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/job_manager.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/main.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/stat.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/stat.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/worker.c/1.2/Thu Apr 6 17:06:03 2006//
|
||||
/worker.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
D
|
||||
1
CS4210/cs4210/proj3/src/client/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/src/client/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/client
|
||||
1
CS4210/cs4210/proj3/src/client/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/client/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
106
CS4210/cs4210/proj3/src/client/Makefile
Normal file
106
CS4210/cs4210/proj3/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/04/06 17:04:45 $
|
||||
# $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/proj3/src/client/config.c
Normal file
116
CS4210/cs4210/proj3/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/proj3/src/client/config.h
Normal file
23
CS4210/cs4210/proj3/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/proj3/src/client/job_manager.c
Normal file
176
CS4210/cs4210/proj3/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/proj3/src/client/job_manager.h
Normal file
54
CS4210/cs4210/proj3/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/proj3/src/client/main.c
Normal file
81
CS4210/cs4210/proj3/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/proj3/src/client/stat.c
Normal file
74
CS4210/cs4210/proj3/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/proj3/src/client/stat.h
Normal file
28
CS4210/cs4210/proj3/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/proj3/src/client/worker.c
Normal file
160
CS4210/cs4210/proj3/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 = (int) 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/proj3/src/client/worker.h
Normal file
14
CS4210/cs4210/proj3/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_*/
|
||||
18
CS4210/cs4210/proj3/src/common/CVS/Entries
Normal file
18
CS4210/cs4210/proj3/src/common/CVS/Entries
Normal file
@@ -0,0 +1,18 @@
|
||||
/Makefile/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/channel.c/1.4/Thu Apr 13 21:42:36 2006//
|
||||
/channel.h/1.3/Fri Apr 7 00:50:36 2006//
|
||||
/data.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/debug.h/1.3/Thu Apr 13 21:55:47 2006//
|
||||
/dispatcher.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/dispatcher.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/http.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/http.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/networking.c/1.2/Fri Apr 7 00:50:36 2006//
|
||||
/networking.h/1.2/Fri Apr 7 00:50:36 2006//
|
||||
/queue.c/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/queue.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/threading.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/timer.h/1.1/Thu Apr 6 17:04:45 2006//
|
||||
/util.c/1.2/Mon Apr 10 19:50:25 2006//
|
||||
/util.h/1.2/Mon Apr 10 19:50:25 2006//
|
||||
D
|
||||
1
CS4210/cs4210/proj3/src/common/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/src/common/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/common
|
||||
1
CS4210/cs4210/proj3/src/common/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/common/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
103
CS4210/cs4210/proj3/src/common/Makefile
Normal file
103
CS4210/cs4210/proj3/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: vurazov $
|
||||
# $Date: 2006/04/06 17:04:45 $
|
||||
# $Revision: 1.1 $
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
|
||||
########################### 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
|
||||
153
CS4210/cs4210/proj3/src/common/channel.c
Normal file
153
CS4210/cs4210/proj3/src/common/channel.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#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, MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
void ch_init_sock(channel_t* ch, socket_t* sock)
|
||||
{
|
||||
ch->channel = sock;
|
||||
ch->read = m_sock_read;
|
||||
ch->write = m_sock_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 - bytes_written);
|
||||
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];
|
||||
int char_count = 0;
|
||||
int found_char_count = 0;
|
||||
|
||||
while ((bytes_read = ch_read(ch, buffer + char_count, 1)) > 0)
|
||||
{
|
||||
if (buffer[char_count] == str[found_char_count])
|
||||
{
|
||||
found_char_count ++;
|
||||
if (str[found_char_count] == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
found_char_count = 0;
|
||||
}
|
||||
|
||||
char_count ++;
|
||||
if (char_count == BUFFER_SIZE)
|
||||
{
|
||||
result = strncatd(result, buffer, char_count);
|
||||
char_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (char_count > 0)
|
||||
{
|
||||
result = strncatd(result, buffer, char_count);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char* ch_read_everything(channel_t* ch)
|
||||
{
|
||||
char* result = NULL;
|
||||
char buffer[BUFFER_SIZE];
|
||||
size_t bytes_read = 0;
|
||||
|
||||
while ((bytes_read = ch_read(ch, buffer, BUFFER_SIZE - 1)) > 0)
|
||||
{
|
||||
result = strncatd(result, buffer, bytes_read);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
69
CS4210/cs4210/proj3/src/common/channel.h
Normal file
69
CS4210/cs4210/proj3/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"
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Reads from the channel until nothing more can be read and returns the
|
||||
result in a newly allocated buffer. */
|
||||
char* ch_read_everything(channel_t* ch);
|
||||
|
||||
#endif/*_CHANNEL_H_*/
|
||||
13
CS4210/cs4210/proj3/src/common/data.h
Normal file
13
CS4210/cs4210/proj3/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/proj3/src/common/debug.h
Normal file
14
CS4210/cs4210/proj3/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/proj3/src/common/dispatcher.c
Normal file
141
CS4210/cs4210/proj3/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/proj3/src/common/dispatcher.h
Normal file
33
CS4210/cs4210/proj3/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/proj3/src/common/http.c
Normal file
132
CS4210/cs4210/proj3/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/proj3/src/common/http.h
Normal file
52
CS4210/cs4210/proj3/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_*/
|
||||
230
CS4210/cs4210/proj3/src/common/networking.c
Normal file
230
CS4210/cs4210/proj3/src/common/networking.c
Normal file
@@ -0,0 +1,230 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
int net_open_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
110
CS4210/cs4210/proj3/src/common/networking.h
Normal file
110
CS4210/cs4210/proj3/src/common/networking.h
Normal file
@@ -0,0 +1,110 @@
|
||||
#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);
|
||||
|
||||
/* Opens a client socket for the specified host and port. */
|
||||
int net_open_socket(socket_t* result, const char* host, const port_t port);
|
||||
|
||||
|
||||
/*
|
||||
* 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/proj3/src/common/queue.c
Normal file
162
CS4210/cs4210/proj3/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/proj3/src/common/queue.h
Normal file
69
CS4210/cs4210/proj3/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_*/
|
||||
8
CS4210/cs4210/proj3/src/common/threading.h
Normal file
8
CS4210/cs4210/proj3/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/proj3/src/common/timer.h
Normal file
85
CS4210/cs4210/proj3/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_*/
|
||||
207
CS4210/cs4210/proj3/src/common/util.c
Normal file
207
CS4210/cs4210/proj3/src/common/util.c
Normal file
@@ -0,0 +1,207 @@
|
||||
#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 str_endswith(const char* str, const char* substr)
|
||||
{
|
||||
const char* last_str = NULL;
|
||||
int found = 0;
|
||||
int sub_len = strlen(substr);
|
||||
|
||||
while ((last_str = strstr(str, substr)) != NULL)
|
||||
{
|
||||
str = last_str + sub_len;
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (!found) return 0;
|
||||
|
||||
return (str[0] == '\0');
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
77
CS4210/cs4210/proj3/src/common/util.h
Normal file
77
CS4210/cs4210/proj3/src/common/util.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#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);
|
||||
|
||||
/* Returns true if str ends with substr, and false if it does not. */
|
||||
int str_endswith(const char* str, const char* substr);
|
||||
|
||||
/* 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_*/
|
||||
2
CS4210/cs4210/proj3/src/examples/CVS/Entries
Normal file
2
CS4210/cs4210/proj3/src/examples/CVS/Entries
Normal file
@@ -0,0 +1,2 @@
|
||||
D/jpeg////
|
||||
D/square////
|
||||
1
CS4210/cs4210/proj3/src/examples/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/src/examples/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/examples
|
||||
1
CS4210/cs4210/proj3/src/examples/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/examples/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
3
CS4210/cs4210/proj3/src/examples/jpeg/CVS/Entries
Normal file
3
CS4210/cs4210/proj3/src/examples/jpeg/CVS/Entries
Normal file
@@ -0,0 +1,3 @@
|
||||
/jpeg.x/1.1/Thu Apr 6 23:12:10 2006//
|
||||
D/client////
|
||||
D/server////
|
||||
1
CS4210/cs4210/proj3/src/examples/jpeg/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/src/examples/jpeg/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/examples/jpeg
|
||||
1
CS4210/cs4210/proj3/src/examples/jpeg/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/examples/jpeg/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
2
CS4210/cs4210/proj3/src/examples/jpeg/client/CVS/Entries
Normal file
2
CS4210/cs4210/proj3/src/examples/jpeg/client/CVS/Entries
Normal file
@@ -0,0 +1,2 @@
|
||||
/main.c/1.1/Thu Apr 6 23:12:10 2006//
|
||||
D
|
||||
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/examples/jpeg/client
|
||||
1
CS4210/cs4210/proj3/src/examples/jpeg/client/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/examples/jpeg/client/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
43
CS4210/cs4210/proj3/src/examples/jpeg/client/main.c
Normal file
43
CS4210/cs4210/proj3/src/examples/jpeg/client/main.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "jpeg.h"
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
CLIENT* cl;
|
||||
jpeg_in in;
|
||||
jpeg_out* out;
|
||||
|
||||
FILE* outfile;
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
printf("./main server in out");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outfile = fopen(argv[3], "w");
|
||||
if (!outfile)
|
||||
{
|
||||
perror("Can't open destination");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cl = clnt_create(argv[1], JPEG_PROG, JPEG_VERS, "tcp");
|
||||
if (!cl)
|
||||
{
|
||||
perror("Could not create client.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
in.file_name = argv[2];
|
||||
if ((out = jpegproc_1(&in, cl)) == NULL)
|
||||
{
|
||||
printf("%s", clnt_sperror(cl, argv[1]));
|
||||
}
|
||||
|
||||
|
||||
fwrite(out->data.data_val, out->data.data_len, 1, outfile);
|
||||
|
||||
fclose(outfile);
|
||||
}
|
||||
13
CS4210/cs4210/proj3/src/examples/jpeg/jpeg.x
Normal file
13
CS4210/cs4210/proj3/src/examples/jpeg/jpeg.x
Normal file
@@ -0,0 +1,13 @@
|
||||
struct jpeg_in {
|
||||
string file_name<>;
|
||||
};
|
||||
|
||||
struct jpeg_out {
|
||||
opaque data<>;
|
||||
};
|
||||
|
||||
program JPEG_PROG {
|
||||
version JPEG_VERS {
|
||||
jpeg_out JPEGPROC(jpeg_in) = 1;
|
||||
} = 1;
|
||||
} = 0x31231337;
|
||||
5
CS4210/cs4210/proj3/src/examples/jpeg/server/CVS/Entries
Normal file
5
CS4210/cs4210/proj3/src/examples/jpeg/server/CVS/Entries
Normal file
@@ -0,0 +1,5 @@
|
||||
/lowres-write.c/1.1/Thu Apr 6 23:12:10 2006//
|
||||
/lowres.c/1.1/Thu Apr 6 23:12:10 2006//
|
||||
/lowres.h/1.1/Thu Apr 6 23:12:10 2006//
|
||||
/server.c/1.1/Thu Apr 6 23:12:10 2006//
|
||||
D
|
||||
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/examples/jpeg/server
|
||||
1
CS4210/cs4210/proj3/src/examples/jpeg/server/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/examples/jpeg/server/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
202
CS4210/cs4210/proj3/src/examples/jpeg/server/lowres-write.c
Normal file
202
CS4210/cs4210/proj3/src/examples/jpeg/server/lowres-write.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/* Just a part of the lowres functionality. It has to be in a separate
|
||||
file, otherwise the data destination manager routines would conflict
|
||||
with the ones used for decompression. Someone needs to write an
|
||||
object-oriented extension for C. ;-)))
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "jinclude.h"
|
||||
#include "jpeglib.h"
|
||||
#include "jerror.h"
|
||||
|
||||
/* YANNIS: This _fine_ library wants me to define a data destination
|
||||
manager just to be able to write compressed data in memory. */
|
||||
typedef struct {
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
|
||||
size_t total_size;
|
||||
JOCTET * output; /* target stream */
|
||||
} my_destination_mgr;
|
||||
|
||||
typedef my_destination_mgr * my_dest_ptr;
|
||||
|
||||
METHODDEF(void)
|
||||
init_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr this_obj = (my_dest_ptr) cinfo->dest;
|
||||
|
||||
this_obj->total_size = cinfo->image_width * cinfo->input_components *
|
||||
cinfo->image_height;
|
||||
/* Probably too much space, but let's be conservative */
|
||||
this_obj->output = (JOCTET *) malloc(this_obj->total_size * sizeof(JOCTET));
|
||||
this_obj->pub.next_output_byte = this_obj->output;
|
||||
this_obj->pub.free_in_buffer = this_obj->total_size;
|
||||
}
|
||||
|
||||
/* The following routine contributed by Ilya Bagrak (Spring'03) */
|
||||
METHODDEF(boolean)
|
||||
empty_output_buffer (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
|
||||
unsigned char* ret;
|
||||
|
||||
ret = realloc(dest->output, dest->total_size + 1024);
|
||||
dest->output = ret;
|
||||
dest->total_size += 1024;
|
||||
dest->pub.next_output_byte = dest->output + dest->total_size - 1024;
|
||||
dest->pub.free_in_buffer = 1024;
|
||||
|
||||
fprintf(stderr, "ASSERTION FAILURE\n");
|
||||
return TRUE; /* This shouldn't happen */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Terminate destination --- called by jpeg_finish_compress
|
||||
* after all data has been written. Usually needs to flush buffer.
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
term_destination (j_compress_ptr cinfo)
|
||||
{
|
||||
return; /* No need to do anything */
|
||||
}
|
||||
|
||||
|
||||
GLOBAL(void)
|
||||
jpeg_mem_dest (j_compress_ptr cinfo)
|
||||
{
|
||||
my_dest_ptr dest;
|
||||
|
||||
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
SIZEOF(my_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (my_dest_ptr) cinfo->dest;
|
||||
dest->pub.init_destination = init_destination;
|
||||
dest->pub.empty_output_buffer = empty_output_buffer;
|
||||
dest->pub.term_destination = term_destination;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLOBAL(void)
|
||||
write_JPEG_file (JSAMPARRAY buffer, int image_width, int image_height,
|
||||
int color_comp, J_COLOR_SPACE color_space,
|
||||
int quality, JOCTET **output, int *output_size)
|
||||
{
|
||||
/* This struct contains the JPEG compression parameters and pointers to
|
||||
* working space (which is allocated as needed by the JPEG library).
|
||||
* It is possible to have several such structures, representing multiple
|
||||
* compression/decompression processes, in existence at once. We refer
|
||||
* to any one struct (and its associated working data) as a "JPEG object".
|
||||
*/
|
||||
struct jpeg_compress_struct cinfo;
|
||||
/* This struct represents a JPEG error handler. It is declared separately
|
||||
* because applications often want to supply a specialized error handler
|
||||
* (see the second half of this file for an example). But here we just
|
||||
* take the easy way out and use the standard error handler, which will
|
||||
* print a message on stderr and call exit() if compression fails.
|
||||
* Note that this struct must live as long as the main JPEG parameter
|
||||
* struct, to avoid dangling-pointer problems.
|
||||
*/
|
||||
struct jpeg_error_mgr jerr;
|
||||
/* More stuff */
|
||||
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
|
||||
int row_stride; /* physical row width in image buffer */
|
||||
|
||||
/* Step 1: allocate and initialize JPEG compression object */
|
||||
|
||||
/* We have to set up the error handler first, in case the initialization
|
||||
* step fails. (Unlikely, but it could happen if you are out of memory.)
|
||||
* This routine fills in the contents of struct jerr, and returns jerr's
|
||||
* address which we place into the link field in cinfo.
|
||||
*/
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
/* Now we can initialize the JPEG compression object. */
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
/* Step 2: set parameters for compression */
|
||||
|
||||
/* First we supply a description of the input image.
|
||||
* Four fields of the cinfo struct must be filled in:
|
||||
*/
|
||||
cinfo.image_width = image_width; /* image width and height, in pixels */
|
||||
cinfo.image_height = image_height;
|
||||
cinfo.input_components = color_comp; /* # of color components per pixel */
|
||||
cinfo.in_color_space = color_space; /* colorspace of input image */
|
||||
|
||||
/* Step 3: specify data destination (eg, a file) */
|
||||
|
||||
jpeg_mem_dest(&cinfo);
|
||||
|
||||
/* Now use the library's routine to set default compression parameters.
|
||||
* (You must set at least cinfo.in_color_space before calling this,
|
||||
* since the defaults depend on the source color space.)
|
||||
*/
|
||||
jpeg_set_defaults(&cinfo);
|
||||
/* Now you can set any non-default parameters you wish to.
|
||||
* Here we just illustrate the use of quality (quantization table) scaling:
|
||||
*/
|
||||
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
|
||||
|
||||
/* Step 4: Start compressor */
|
||||
|
||||
/* TRUE ensures that we will write a complete interchange-JPEG file.
|
||||
* Pass TRUE unless you are very sure of what you're doing.
|
||||
*/
|
||||
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
/* Step 5: while (scan lines remain to be written) */
|
||||
/* jpeg_write_scanlines(...); */
|
||||
|
||||
/* Here we use the library's state variable cinfo.next_scanline as the
|
||||
* loop counter, so that we don't have to keep track ourselves.
|
||||
* To keep things simple, we pass one scanline per call; you can pass
|
||||
* more if you wish, though.
|
||||
*/
|
||||
|
||||
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
/* jpeg_write_scanlines expects an array of pointers to scanlines.
|
||||
* Here the array is only one element long, but you could pass
|
||||
* more than one scanline at a time if that's more convenient.
|
||||
*/
|
||||
row_pointer[0] = buffer[cinfo.next_scanline];
|
||||
|
||||
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
/* Step 6: Finish compression */
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
|
||||
{
|
||||
my_dest_ptr this_obj = (my_dest_ptr) cinfo.dest;
|
||||
*output = this_obj->output;
|
||||
*output_size = this_obj->total_size - this_obj->pub.free_in_buffer;
|
||||
|
||||
/* We destroy that pointer so that it is not used to deallocate the
|
||||
output data */
|
||||
this_obj->output = NULL;
|
||||
}
|
||||
|
||||
/* Step 7: release JPEG compression object */
|
||||
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
/* And we're done! */
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
220
CS4210/cs4210/proj3/src/examples/jpeg/server/lowres.c
Normal file
220
CS4210/cs4210/proj3/src/examples/jpeg/server/lowres.c
Normal file
@@ -0,0 +1,220 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
/*
|
||||
* lowres.c
|
||||
*
|
||||
* Yannis Smaragdakis
|
||||
*
|
||||
* This file defines a routine that reads JPEG data from a socket and
|
||||
* creates a memory buffer with this data at much lower quality (to
|
||||
* reduce storage requirements).
|
||||
*
|
||||
* I have put a limit of two hours on the time I will work on this,
|
||||
* so this is not a mature piece of code. It should do the work,
|
||||
* though.
|
||||
*
|
||||
* Look at example.c and libjpeg.doc for more info on using the IJG code.
|
||||
*/
|
||||
|
||||
#define LOW_QUALITY 10
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* Include file for users of JPEG library.
|
||||
* You will need to have included system headers that define at least
|
||||
* the typedefs FILE and size_t before you can include jpeglib.h.
|
||||
* (stdio.h is sufficient on ANSI-conforming systems.)
|
||||
* You may also wish to include "jerror.h".
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "jpeglib.h"
|
||||
|
||||
/*
|
||||
* <setjmp.h> is used for the optional error recovery mechanism shown in
|
||||
* the second part of the example.
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
extern int write_JPEG_file(JSAMPARRAY, int,int, int, int, J_COLOR_SPACE,JOCTET **, int *);
|
||||
|
||||
/*
|
||||
* ERROR HANDLING:
|
||||
*
|
||||
* The JPEG library's standard error handler (jerror.c) is divided into
|
||||
* several "methods" which you can override individually. This lets you
|
||||
* adjust the behavior without duplicating a lot of code, which you might
|
||||
* have to update with each future release.
|
||||
*
|
||||
* Our example here shows how to override the "error_exit" method so that
|
||||
* control is returned to the library's caller when a fatal error occurs,
|
||||
* rather than calling exit() as the standard error_exit method does.
|
||||
*
|
||||
* We use C's setjmp/longjmp facility to return control. This means that the
|
||||
* routine which calls the JPEG library must first execute a setjmp() call to
|
||||
* establish the return point. We want the replacement error_exit to do a
|
||||
* longjmp(). But we need to make the setjmp buffer accessible to the
|
||||
* error_exit routine. To do this, we make a private extension of the
|
||||
* standard JPEG error handler object. (If we were using C++, we'd say we
|
||||
* were making a subclass of the regular error handler.)
|
||||
*
|
||||
* Here's the extended error handler struct:
|
||||
*/
|
||||
|
||||
struct my_error_mgr {
|
||||
struct jpeg_error_mgr pub; /* "public" fields */
|
||||
|
||||
jmp_buf setjmp_buffer; /* for return to caller */
|
||||
};
|
||||
|
||||
typedef struct my_error_mgr * my_error_ptr;
|
||||
|
||||
/*
|
||||
* Here's the routine that will replace the standard error_exit method:
|
||||
*/
|
||||
|
||||
METHODDEF(void)
|
||||
my_error_exit (j_common_ptr cinfo)
|
||||
{
|
||||
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
|
||||
my_error_ptr myerr = (my_error_ptr) cinfo->err;
|
||||
|
||||
/* Always display the message. */
|
||||
/* We could postpone this until after returning, if we chose. */
|
||||
(*cinfo->err->output_message) (cinfo);
|
||||
|
||||
/* Return control to the setjmp point */
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
#define MAX_LINESZ 200
|
||||
|
||||
/*
|
||||
* Sample routine for JPEG decompression. We assume that a socket
|
||||
* from which the source is read is passed in.
|
||||
* We want to return 1 on success, 0 on error.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int
|
||||
change_res_JPEG (int insocket, char ** output, int *output_size)
|
||||
{
|
||||
/* This struct contains the JPEG decompression parameters and pointers to
|
||||
* working space (which is allocated as needed by the JPEG library).
|
||||
*/
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
/* We use our private extension JPEG error handler.
|
||||
* Note that this struct must live as long as the main JPEG parameter
|
||||
* struct, to avoid dangling-pointer problems.
|
||||
*/
|
||||
struct my_error_mgr jerr;
|
||||
/* More stuff */
|
||||
JSAMPARRAY buffer; /* Output row buffer */
|
||||
int row_stride; /* physical row width in output buffer */
|
||||
FILE *infile = fdopen(insocket, "r");
|
||||
|
||||
/* Step 1: allocate and initialize JPEG decompression object */
|
||||
|
||||
/* We set up the normal JPEG error routines, then override error_exit. */
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
/* Establish the setjmp return context for my_error_exit to use. */
|
||||
if (setjmp(jerr.setjmp_buffer)) {
|
||||
/* If we get here, the JPEG code has signaled an error.
|
||||
* We need to clean up the JPEG object, close the input file, and return.
|
||||
*/
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
fclose(infile);
|
||||
return 0;
|
||||
}
|
||||
/* Now we can initialize the JPEG decompression object. */
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
/* Step 2: specify data source (eg, a file) */
|
||||
|
||||
jpeg_stdio_src(&cinfo, infile);
|
||||
|
||||
/* Step 3: read file parameters with jpeg_read_header() */
|
||||
|
||||
(void) jpeg_read_header(&cinfo, TRUE);
|
||||
/* We can ignore the return value from jpeg_read_header since
|
||||
* (a) suspension is not possible with the stdio data source, and
|
||||
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
|
||||
* See libjpeg.doc for more info.
|
||||
*/
|
||||
|
||||
/* Step 4: set parameters for decompression */
|
||||
|
||||
/* In this example, we don't need to change any of the defaults set by
|
||||
* jpeg_read_header(), so we do nothing here.
|
||||
*/
|
||||
|
||||
/* Step 5: Start decompressor */
|
||||
|
||||
(void) jpeg_start_decompress(&cinfo);
|
||||
/* We can ignore the return value since suspension is not possible
|
||||
* with the stdio data source.
|
||||
*/
|
||||
|
||||
/* We may need to do some setup of our own at this point before reading
|
||||
* the data. After jpeg_start_decompress() we have the correct scaled
|
||||
* output image dimensions available, as well as the output colormap
|
||||
* if we asked for color quantization.
|
||||
* In this example, we need to make an output work buffer of the right size.
|
||||
*/
|
||||
/* JSAMPLEs per row in output buffer */
|
||||
row_stride = cinfo.output_width * cinfo.output_components;
|
||||
|
||||
buffer = (*cinfo.mem->alloc_sarray)
|
||||
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, cinfo.output_height);
|
||||
|
||||
/* Step 6: while (scan lines remain to be read) */
|
||||
/* jpeg_read_scanlines(...); */
|
||||
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
/* jpeg_read_scanlines expects an array of pointers to scanlines.*/
|
||||
(void) jpeg_read_scanlines(&cinfo, &buffer[cinfo.output_scanline],
|
||||
cinfo.output_height);
|
||||
}
|
||||
|
||||
/* Perform the size reduction */
|
||||
write_JPEG_file(buffer, cinfo.output_width, cinfo.output_height,
|
||||
cinfo.output_components, cinfo.out_color_space,
|
||||
LOW_QUALITY, (JOCTET **)output, output_size);
|
||||
|
||||
/* Step 7: Finish decompression */
|
||||
|
||||
(void) jpeg_finish_decompress(&cinfo);
|
||||
/* YANNIS: What a deranged idea! Buffers allocated using the JPEG
|
||||
allocator are freed when the "jpeg_finish_decompress" routine is
|
||||
called, not when "jpeg_destroy_decompress" is called!
|
||||
*/
|
||||
|
||||
/* Step 8: Release JPEG decompression object */
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
/* After finish_decompress, we can close the input file.
|
||||
* Here we postpone it until after no more JPEG errors are possible,
|
||||
* so as to simplify the setjmp error logic above. (Actually, I don't
|
||||
* think that jpeg_destroy can do an error exit, but why assume anything...)
|
||||
*/
|
||||
fclose(infile);
|
||||
|
||||
/* At this point you may want to check to see whether any corrupt-data
|
||||
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
|
||||
*/
|
||||
|
||||
/* And we're done! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
16
CS4210/cs4210/proj3/src/examples/jpeg/server/lowres.h
Normal file
16
CS4210/cs4210/proj3/src/examples/jpeg/server/lowres.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/* Header file for the lowres functionality */
|
||||
|
||||
#ifndef _LOWRES_H
|
||||
#define _LOWRES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int change_res_JPEG (int insocket, char ** output, int *output_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ifndef _LOWRES_H */
|
||||
16
CS4210/cs4210/proj3/src/examples/jpeg/server/server.c
Normal file
16
CS4210/cs4210/proj3/src/examples/jpeg/server/server.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "jpeg.h"
|
||||
#include "lowres.h"
|
||||
|
||||
jpeg_out * jpegproc_1_svc(jpeg_in* in, struct svc_req* request)
|
||||
{
|
||||
static jpeg_out result;
|
||||
|
||||
int desc = open(in->file_name, O_RDONLY);
|
||||
if (desc < 0) return NULL;
|
||||
|
||||
change_res_JPEG(desc, &(result.data.data_val), &(result.data.data_len));
|
||||
|
||||
return &result;
|
||||
}
|
||||
3
CS4210/cs4210/proj3/src/examples/square/CVS/Entries
Normal file
3
CS4210/cs4210/proj3/src/examples/square/CVS/Entries
Normal file
@@ -0,0 +1,3 @@
|
||||
/square.x/1.1/Thu Apr 6 23:12:10 2006//
|
||||
D/client////
|
||||
D/server////
|
||||
1
CS4210/cs4210/proj3/src/examples/square/CVS/Repository
Normal file
1
CS4210/cs4210/proj3/src/examples/square/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/examples/square
|
||||
1
CS4210/cs4210/proj3/src/examples/square/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/examples/square/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
@@ -0,0 +1,2 @@
|
||||
/client.c/1.1/Thu Apr 6 23:12:10 2006//
|
||||
D
|
||||
@@ -0,0 +1 @@
|
||||
cs4210/proj3/src/examples/square/client
|
||||
1
CS4210/cs4210/proj3/src/examples/square/client/CVS/Root
Normal file
1
CS4210/cs4210/proj3/src/examples/square/client/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
30
CS4210/cs4210/proj3/src/examples/square/client/client.c
Normal file
30
CS4210/cs4210/proj3/src/examples/square/client/client.c
Normal file
@@ -0,0 +1,30 @@
|
||||
//#include "unpipc.h"
|
||||
#include "square.h"
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
CLIENT* cl;
|
||||
square_in in;
|
||||
square_out* out;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
exit(":(");
|
||||
}
|
||||
|
||||
cl = clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
|
||||
if (!cl)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
in.arg1 = atol(argv[2]);
|
||||
if ((out = squareproc_1(&in, cl)) == NULL)
|
||||
{
|
||||
printf("%s", clnt_sperror(cl, argv[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("result: %ld\n", out->res1);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user