first commit

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

View File

@@ -0,0 +1 @@
bin

View File

@@ -0,0 +1,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////

View File

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

View File

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

View File

@@ -0,0 +1,32 @@
##############################################################################
#
# This file will recursively call client and server makefiles to build
# those.
#
# $Author: vurazov $
# $Date: 2006/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
View 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.

View 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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

View 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

View File

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

View File

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

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

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

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

View File

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

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

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

View File

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

Binary file not shown.

View File

@@ -0,0 +1,8 @@
D/client////
D/common////
D/examples////
D/libjpeg////
D/proxy////
D/rpc////
D/rpc_server////
D/server////

View File

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

View File

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

View File

@@ -0,0 +1 @@
obj

View 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

View File

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

View File

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

View File

@@ -0,0 +1,106 @@
##############################################################################
#
# Generic Makefile. Only need to modify the variables for src, obj,
# and bin directories, and the name of the executable.
#
# $Author: vurazov $
# $Date: 2006/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

View File

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

View File

@@ -0,0 +1,23 @@
#ifndef _CLIENT_CONFIG_H_
#define _CLIENT_CONFIG_H_
#include <stdio.h>
/* Records the parameter with the given name and value. */
int record_parameter(const char* name, const char* value);
/* Given a stream, will print the list of supported parameters to the
* stream. */
void config_print_parameters(FILE* out);
/* Initializes the configuration with the parameters specified. */
int config_init(int argc, const char** argv);
/* Cleans up whatever resources the configuration consumed. */
void config_free();
int config_get_jobcount();
int config_get_workercount();
FILE* config_get_urlfile();
#endif/*_CLIENT_CONFIG_H_*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,160 @@
#include <stdlib.h>
#include "common/channel.h"
#include "common/debug.h"
#include "common/http.h"
#include "common/networking.h"
#include "common/timer.h"
#include "common/threading.h"
#include "common/util.h"
#include "job_manager.h"
#include "worker.h"
#define BUFFER_SIZE 256
static int m_worker_count;
static pthread_mutex_t worker_count_mutex;
static pthread_cond_t all_done_cond;
/* List of child threads. */
static pthread_t* m_children = NULL;
int workers_initialize(int thread_count)
{
int index;
int result;
m_worker_count = thread_count;
pthread_mutex_init(&worker_count_mutex, NULL);
pthread_cond_init(&all_done_cond, NULL);
/* Spawn children threads. */
m_children = (pthread_t*) calloc(thread_count, sizeof(pthread_t));
if (!m_children)
{
fprintf(stderr, "[WORK] Could not allocate memory.\n");
return 1;
}
for (index = 0; index < thread_count; index++)
{
result = pthread_create(m_children + index, NULL,
worker_run, NULL);
if (result)
{
fprintf(stderr, "[WORK] Could not create child thread.\n");
return result;
}
}
return 0;
}
static void m_read_response(job_t* job, socket_t sock)
{
char buffer[BUFFER_SIZE];
int bytes_received = 0;
time_span_t timer;
channel_t server;
ch_init_sock(&server, &sock);
timer_start(&timer);
/* First, send the header to the server: */
if (http_send_request_header(&server, HTTP_METHOD_GET, job->path, NULL))
{
job->data_time = -1;
return;
}
/* Now, receive stuff from the server: */
/* TODO: Check response status? */
do
{
bytes_received = (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);
}

View File

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

View File

@@ -0,0 +1,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

View File

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

View File

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

View File

@@ -0,0 +1,103 @@
##############################################################################
#
# Generic Makefile. Only need to modify the variables for src, obj,
# and bin directories, and the name of the executable.
#
# $Author: 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

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

View File

@@ -0,0 +1,69 @@
/* \file channel.h
* Here, we define an abstraction for communication channels. Essentially, we
* want to be able to read and write into files, sockets, and shared memory
* using the same interface. That's what the stuff in this header file is an
* interface for.
*/
#ifndef _CHANNEL_H_
#define _CHANNEL_H_
#include <stdio.h>
#include "networking.h"
/* 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_*/

View File

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

View File

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

View File

@@ -0,0 +1,141 @@
#include <stdio.h>
#include "debug.h"
#include "dispatcher.h"
#include "queue.h"
#include "threading.h"
/* The id of the listening socket. */
static socket_t m_listening_socket = -1;
/* The dispatcher thread. */
static pthread_t m_main_thread;
/* Worker count. */
static int m_worker_count = 0;
/* The worker function. */
static workerfunc m_worker_f;
/* List of worker threads. */
static pthread_t* m_workers = NULL;
/* The queue of waiting sockets. */
static queue_t m_waiting_sockets;
/* Dispatcher run function. This function loops infinitely and accepts
* connections, giving workers something to work with whenever someone
* connects on the socket. Again, the function will loop
* *infinitely*. The thread it runs in needs to be killed
* explicitly. This is because the accept connection function is
* blocking, so there is no way to kill the thread any way, without
* using extreme methods. */
void* m_dispatcher_run(void* p)
{
/* Loop infinitely accepting connections: */
while (1)
{
/* Accept connection */
socket_t client_socket = -1;
sockaddress_t caddr;
socklen_t sizeof_caddr = sizeof(sockaddress_t);
DEBUG_PRINTF(("[DISP] Waiting for a client connection...\n"));
client_socket = accept(m_listening_socket,
(struct sockaddr*) &caddr, &sizeof_caddr);
if (IS_BAD_SOCKET(client_socket))
{
fprintf(stderr,
"[DISP] Could not accept client on listening socket\n");
net_report_error();
continue;
}
DEBUG_PRINTF(("[DISP] Got client on port %d.\n", ntohs(caddr.sin_port)));
/* Enqueue socket to be picked up by a client thread. */
queue_enqueue(&m_waiting_sockets, (void*) client_socket);
}
return NULL;
}
int dispatcher_initialize(port_t port, int worker_count, workerfunc f)
{
m_worker_count = worker_count;
m_worker_f = f;
/* Make a listening socket: */
m_listening_socket = net_listen_on_port(port);
if (IS_BAD_SOCKET(m_listening_socket))
{
fprintf(stderr, "[DISP] Could not open listening socket.");
return 1;
}
/* Initialize the queue */
queue_initialize(&m_waiting_sockets);
/* Allocate children threads. */
m_workers = (pthread_t*) calloc(worker_count, sizeof(pthread_t));
if (!m_workers)
{
fprintf(stderr,
"[DISP] Could not allocate memory for worker threads.\n");
return 1;
}
return 0;
}
int dispatcher_start()
{
int index = 0;
int result = 0;
/* Start boss thread: */
result = pthread_create(&m_main_thread, NULL, m_dispatcher_run, NULL);
if (result)
{
fprintf(stderr, "[DISP] Could not start dispatcher thread.\n");
return result;
}
/* Start worker threads: */
for (index = 0; index < m_worker_count; index++)
{
result = pthread_create(m_workers + index, NULL,
m_worker_f, &m_waiting_sockets);
if (result)
{
fprintf(stderr, "[DISP] Could not start worker thread.\n");
return result;
}
}
return 0;
}
int dispatcher_stop()
{
int index;
int result;
/* Kill children */
for (index = 0; index < m_worker_count; index++)
{
DEBUG_PRINTF(("[DISP] Killing child #%d... ", index));
result = pthread_kill(m_workers[index], SIGINT);
DEBUG_PRINTF(("%s\n", (result) ? (perror("Error"),"") : ("Done")));
}
/* Kill self */
DEBUG_PRINTF(("[DISP] Killing boss... "));
result = pthread_kill(m_main_thread, SIGINT);
DEBUG_PRINTF(("%s\n", (result) ? (perror("Error"),"") : ("Done")));
free(m_workers);
return 0;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,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");
}

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,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;
}
}

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

View File

@@ -0,0 +1,2 @@
D/jpeg////
D/square////

View File

@@ -0,0 +1 @@
cs4210/proj3/src/examples

View File

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

View File

@@ -0,0 +1,3 @@
/jpeg.x/1.1/Thu Apr 6 23:12:10 2006//
D/client////
D/server////

View File

@@ -0,0 +1 @@
cs4210/proj3/src/examples/jpeg

View File

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

View File

@@ -0,0 +1,2 @@
/main.c/1.1/Thu Apr 6 23:12:10 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj3/src/examples/jpeg/client

View File

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

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

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

View 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

View File

@@ -0,0 +1 @@
cs4210/proj3/src/examples/jpeg/server

View File

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

View 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

View 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

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

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

View File

@@ -0,0 +1,3 @@
/square.x/1.1/Thu Apr 6 23:12:10 2006//
D/client////
D/server////

View File

@@ -0,0 +1 @@
cs4210/proj3/src/examples/square

View File

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

View File

@@ -0,0 +1,2 @@
/client.c/1.1/Thu Apr 6 23:12:10 2006//
D

View File

@@ -0,0 +1 @@
cs4210/proj3/src/examples/square/client

View File

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

View 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