first commit
This commit is contained in:
13
CS4210/cs4210/proj1/src/common/CVS/Entries
Normal file
13
CS4210/cs4210/proj1/src/common/CVS/Entries
Normal file
@@ -0,0 +1,13 @@
|
||||
/Makefile/1.2/Sat Feb 18 02:10:09 2006//
|
||||
/debug.h/1.1/Tue Feb 21 00:58:27 2006//
|
||||
/http.c/1.4/Mon Feb 20 23:05:47 2006//
|
||||
/http.h/1.1/Thu Feb 16 01:12:25 2006//
|
||||
/networking.c/1.6/Mon Feb 20 23:05:47 2006//
|
||||
/networking.h/1.5/Sun Feb 19 08:35:24 2006//
|
||||
/queue.c/1.5/Sun Feb 19 19:35:47 2006//
|
||||
/queue.h/1.4/Sun Feb 19 19:35:47 2006//
|
||||
/threading.h/1.1/Thu Feb 16 01:12:25 2006//
|
||||
/timer.h/1.3/Sun Feb 19 07:27:08 2006//
|
||||
/util.c/1.7/Mon Feb 20 16:00:58 2006//
|
||||
/util.h/1.5/Sun Feb 19 01:42:40 2006//
|
||||
D
|
||||
1
CS4210/cs4210/proj1/src/common/CVS/Repository
Normal file
1
CS4210/cs4210/proj1/src/common/CVS/Repository
Normal file
@@ -0,0 +1 @@
|
||||
cs4210/proj1/src/common
|
||||
1
CS4210/cs4210/proj1/src/common/CVS/Root
Normal file
1
CS4210/cs4210/proj1/src/common/CVS/Root
Normal file
@@ -0,0 +1 @@
|
||||
/usr/_CVS
|
||||
103
CS4210/cs4210/proj1/src/common/Makefile
Normal file
103
CS4210/cs4210/proj1/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/02/18 02:10:09 $
|
||||
# $Revision: 1.2 $
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
|
||||
########################### 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 = -std=c99 -Wall -pedantic -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
|
||||
10
CS4210/cs4210/proj1/src/common/debug.h
Normal file
10
CS4210/cs4210/proj1/src/common/debug.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_PRINTF(x) printf x
|
||||
#else
|
||||
#define DEBUG_PRINTF(x)
|
||||
#endif
|
||||
|
||||
#endif/*__DEBUG_H__*/
|
||||
152
CS4210/cs4210/proj1/src/common/http.c
Normal file
152
CS4210/cs4210/proj1/src/common/http.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "http.h"
|
||||
#include "util.h"
|
||||
|
||||
/* The length of the buffer to read the stuff from the socket into. */
|
||||
#define BUFFER_LENGTH 256
|
||||
|
||||
char* http_read_header(socket_t csocket)
|
||||
{
|
||||
char* result = NULL;
|
||||
char buffer[BUFFER_LENGTH];
|
||||
int bytes_received = 0;
|
||||
|
||||
DEBUG_PRINTF(("[HTTP] Reading header.\n"));
|
||||
do
|
||||
{
|
||||
bytes_received = recv(csocket, buffer, BUFFER_LENGTH - 1, 0);
|
||||
if (bytes_received > 0)
|
||||
{
|
||||
char* substr = NULL;
|
||||
|
||||
buffer[bytes_received] = '\0';
|
||||
|
||||
/* Append buffer to result: */
|
||||
result = strcatd(result, buffer);
|
||||
|
||||
/* See if result now has two CRLFs in a row, to indicate the
|
||||
end of the header: */
|
||||
substr = strstr(result, "\r\n\r\n");
|
||||
if (substr)
|
||||
{
|
||||
substr[4] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (bytes_received > 0);
|
||||
|
||||
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
|
||||
{
|
||||
const char* stop = strchr(start, ' ');
|
||||
if (stop == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Count the length of the request: */
|
||||
char* ptr = NULL;
|
||||
size_t count = 0;
|
||||
for (ptr = start; ptr != stop; ptr++)
|
||||
{
|
||||
count ++;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void http_send_canned_response(socket_t socket, 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: */
|
||||
http_send_header(socket, status);
|
||||
|
||||
/* Send some HTML: */
|
||||
net_send_string(socket, html1, strlen(html1));
|
||||
net_send_string(socket, buffer, strlen(buffer));
|
||||
net_send_string(socket, html2, strlen(html2));
|
||||
}
|
||||
|
||||
void http_send_header(socket_t socket, int status)
|
||||
{
|
||||
char buffer[32];
|
||||
char* header = NULL;
|
||||
|
||||
/*
|
||||
static struct utsname *our_name = NULL;
|
||||
if (uname(our_name))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
our_name->nodename
|
||||
*/
|
||||
|
||||
/* 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");
|
||||
|
||||
net_send_string(socket, header, strlen(header));
|
||||
|
||||
free(header);
|
||||
}
|
||||
|
||||
void http_send_text_file(socket_t socket, FILE* f)
|
||||
{
|
||||
char buffer[BUFFER_LENGTH];
|
||||
size_t bytes_read = 0;
|
||||
|
||||
while (!feof(f))
|
||||
{
|
||||
bytes_read = fread(buffer, sizeof(char), BUFFER_LENGTH - 1, f);
|
||||
buffer[bytes_read] = '\0';
|
||||
|
||||
if (bytes_read > 0)
|
||||
{
|
||||
net_send_string(socket, buffer, bytes_read);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
CS4210/cs4210/proj1/src/common/http.h
Normal file
41
CS4210/cs4210/proj1/src/common/http.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef _HTTP_H_
|
||||
#define _HTTP_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "networking.h"
|
||||
|
||||
/* Some useful request methods: */
|
||||
#define HTTP_METHOD_GET "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 socket. */
|
||||
char* http_read_header(socket_t socket);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Sends a hard-coded html response according to the status code passed in. */
|
||||
void http_send_canned_response(socket_t socket, int status);
|
||||
|
||||
/* Sends a response header to the socket, according to the status code
|
||||
* passed in. */
|
||||
void http_send_header(socket_t socket, int status);
|
||||
|
||||
/* Sends the contents of the file as text through the socket. */
|
||||
void http_send_text_file(socket_t socket, FILE* f);
|
||||
|
||||
#endif/*_HTTP_H_*/
|
||||
164
CS4210/cs4210/proj1/src/common/networking.c
Normal file
164
CS4210/cs4210/proj1/src/common/networking.c
Normal file
@@ -0,0 +1,164 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "networking.h"
|
||||
|
||||
int net_get_hostaddr(sockaddress_t* addr,
|
||||
const char* hostname, const port_t port)
|
||||
{
|
||||
struct hostent* he = NULL;
|
||||
|
||||
if (isdigit(hostname[0]))
|
||||
{
|
||||
/* First character in host name is a digit... Could be an IP address */
|
||||
unsigned long address = inet_addr(hostname);
|
||||
if (address != INADDR_NONE)
|
||||
{
|
||||
he = gethostbyaddr((const char*) &address, 4, AF_INET);
|
||||
}
|
||||
}
|
||||
|
||||
if (he == NULL)
|
||||
{
|
||||
/* Well, the IP address bit didn't work. Try host name lookup: */
|
||||
he = gethostbyname(hostname);
|
||||
}
|
||||
|
||||
if (he == NULL)
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not get host information as IP address, nor by name.\n");
|
||||
net_report_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(port);
|
||||
addr->sin_addr = *((struct in_addr*) (he->h_addr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket_t net_open_data_socket(sockaddress_t* addr)
|
||||
{
|
||||
int err = 0;
|
||||
socket_t result = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (IS_BAD_SOCKET(result))
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not open client socket.\n");
|
||||
net_report_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = connect(result, (struct sockaddr*) addr, sizeof(*addr));
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not connect on socket.\n");
|
||||
net_report_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates and initializes a new listening socket, ready to accept connections.
|
||||
*/
|
||||
socket_t net_listen_on_port(port_t port)
|
||||
{
|
||||
int reuse = 1;
|
||||
int error_code = 0;
|
||||
socket_t socket_id = -1;
|
||||
sockaddress_t sockinfo;
|
||||
|
||||
/* Initialize socket using the TCP/IP protocol: */
|
||||
socket_id = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (IS_BAD_SOCKET(socket_id))
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not open listening socket.\n");
|
||||
net_report_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set socket options to release unused socket numbers: */
|
||||
error_code = setsockopt(socket_id, SOL_SOCKET, SO_REUSEADDR,
|
||||
(sockoption_t) &reuse, sizeof(reuse));
|
||||
if (error_code)
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not set socket options.\n");
|
||||
net_report_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Bind the socket: */
|
||||
sockinfo.sin_family = AF_INET;
|
||||
sockinfo.sin_port = htons(port);
|
||||
sockinfo.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to all interfaces */
|
||||
error_code = bind(socket_id, (struct sockaddr*) &sockinfo, sizeof(sockinfo));
|
||||
if (error_code)
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not bind socket.\n");
|
||||
net_report_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start Listening: */
|
||||
error_code = listen(socket_id, 8);
|
||||
if (error_code)
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not listen on socket.\n");
|
||||
net_report_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return socket_id;
|
||||
}
|
||||
|
||||
int net_send_string(socket_t socket, const char* data, size_t len)
|
||||
{
|
||||
if (send(socket, data, (int) len, 0) < (int) len)
|
||||
{
|
||||
fprintf(stderr, "[NET] Could not send data through socket.\n");
|
||||
net_report_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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.\n\n", errcode);
|
||||
}
|
||||
96
CS4210/cs4210/proj1/src/common/networking.h
Normal file
96
CS4210/cs4210/proj1/src/common/networking.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef _NETWORKING_H_
|
||||
#define _NETWORKING_H_
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#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>
|
||||
#include <arpa/inet.h> /* contains all inet_* functions */
|
||||
#endif
|
||||
|
||||
#include <errno.h> /* contains the error functions */
|
||||
|
||||
#if 0 /* TODO: Remove this stuff? */
|
||||
#include <fcntl.h> /* file control */
|
||||
#endif
|
||||
|
||||
#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 'how' parameter to the shutdown function is different in
|
||||
* Berkeley sockets and WinSock, too. */
|
||||
#ifndef SHUT_RDWR
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#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
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Opens a client socket on the specified address. */
|
||||
socket_t net_open_data_socket(sockaddress_t* addr);
|
||||
|
||||
/*
|
||||
* Creates a new listening socket on the specified port, sets up the
|
||||
* correct options, binds and starts listening. Returns the id of the
|
||||
* socket if all these operations were successful, and -1 if there was
|
||||
* an error at any point. If there is an error, then also this
|
||||
* function will print out to stderr what the error was. If a valid
|
||||
* socket id is returned, then accept can be called on the socket to
|
||||
* accept connections.
|
||||
*/
|
||||
socket_t net_listen_on_port(port_t port);
|
||||
|
||||
/* Sends the string through the socket. Returns 0 on success, and an
|
||||
* error code on failure. */
|
||||
int net_send_string(socket_t socket, const char* data, size_t len);
|
||||
|
||||
/*
|
||||
* 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/proj1/src/common/queue.c
Normal file
162
CS4210/cs4210/proj1/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/proj1/src/common/queue.h
Normal file
69
CS4210/cs4210/proj1/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/proj1/src/common/threading.h
Normal file
8
CS4210/cs4210/proj1/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/proj1/src/common/timer.h
Normal file
85
CS4210/cs4210/proj1/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_*/
|
||||
203
CS4210/cs4210/proj1/src/common/util.c
Normal file
203
CS4210/cs4210/proj1/src/common/util.c
Normal file
@@ -0,0 +1,203 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
/* TODO: Refactor with the HTTP Header Reading Code */
|
||||
char* read_line(FILE* stream)
|
||||
{
|
||||
char* result = NULL;
|
||||
char buffer[BUFFER_SIZE];
|
||||
buffer[0] = '\0';
|
||||
|
||||
while (!feof(stream))
|
||||
{
|
||||
fgets(buffer, BUFFER_SIZE, stream);
|
||||
result = strcatd(result, buffer);
|
||||
if (buffer[strlen(buffer) - 1] == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int parse_url(const char* url, char** host, port_t* port, char** path)
|
||||
{
|
||||
char* durl = strdup(url);
|
||||
|
||||
if (strstr(durl, "http://") != durl)
|
||||
{
|
||||
/* The URL does not start with http, it is malformed. */
|
||||
*host = NULL;
|
||||
*path = NULL;
|
||||
|
||||
free(durl);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Separate the protocol from the rest: */
|
||||
char* url_start = durl + strlen("http://");
|
||||
|
||||
/* Separate the port from the rest: */
|
||||
char* port_start = strchr(url_start, ':');
|
||||
|
||||
/* Separate the host from the path: */
|
||||
char* path_start = strchr(url_start, '/');
|
||||
|
||||
if (port_start)
|
||||
{
|
||||
port_start[0] = '\0';
|
||||
port_start ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
port_start = "0";
|
||||
}
|
||||
|
||||
if (path_start)
|
||||
{
|
||||
path_start[0] = '\0';
|
||||
path_start ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
path_start = "";
|
||||
}
|
||||
|
||||
*host = strdup(url_start);
|
||||
*port = (port_t) atoi(port_start);
|
||||
*path = strcatd(NULL, "/");
|
||||
*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;
|
||||
}
|
||||
}
|
||||
57
CS4210/cs4210/proj1/src/common/util.h
Normal file
57
CS4210/cs4210/proj1/src/common/util.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "networking.h"
|
||||
|
||||
/* Windows and Linux have their own wierdness related to strdup. */
|
||||
#ifdef WIN32
|
||||
#define strdup _strdup
|
||||
#else
|
||||
char* strdup(const char* src);
|
||||
#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);
|
||||
|
||||
/* Reads until a newline or EOF is encountered in the stream and returns the
|
||||
result in a newly allocated string. */
|
||||
char* read_line(FILE* stream);
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif/*_UTIL_H_*/
|
||||
Reference in New Issue
Block a user