Skip to content

Instantly share code, notes, and snippets.

@kalenpw
Created Mar 7, 2019
Embed
What would you like to do?
server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define Cache_Size 5
struct CachedItem{
char filename[256];
char content[8096];
struct tm date;
int sizeOfContent;
};
struct CachedItem Cache[Cache_Size];
char* serverHeader = "SimpleServer";
char* webroot = "./";
char* logFile = "./server.log";
int logLevel = 4;
void* handleConnection (void* ptr);
void cacheItem(struct CachedItem item);
struct CachedItem createCachedItem(char* filename, char* content, struct tm date, int sizeOfContent);
struct CachedItem getItemFromCache(char* filename);
struct tm getCurrentDate();
char* getFormattedDate(struct tm date);
void printCache();
void getConfig();
void log(char* message, int severity);
void getHeader(char* header);
void init();
void getHeader(char* header);
void parseHeaderForFile(char* header);
/**
* Entry point for program
*/
int main(int argc, char *argv[])
{
init();
memset (Cache, 0, sizeof (struct CachedItem) * Cache_Size);
int sockfd, newsockfd, portno, clilen, pid;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2)
{
log("ERROR no port provided", 0);
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
int option = 1;
if (sockfd < 0)
{
log("ERROR opening socket", 0);
error("ERROR opening socket");
}
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
log("ERROR on binding", 0);
error("ERROR on binding");
}
listen(sockfd,5);
clilen = sizeof(cli_addr);
while (1)
{
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
{
log("ERROR on accept socket", 0);
error("ERROR on accept");
}
//create a new thread
pthread_t thread_id;
pthread_create(&thread_id, NULL, handleConnection, (void*)newsockfd);
pthread_join(thread_id, NULL);
printCache();
}
return 0;
}
/**
* Load configuration
*/
void init()
{
printf("Starting server\n");
log("Starting server", 4);
getConfig();
}
void test(){
char header[288];
getHeader(header);
printf(header);
//header = getHeader(header);
exit(0);
// std::cout << "HELLO";
// char header[288];
// header = getHeader(header);
}
void getConfig()
{
FILE* file = fopen("server.config", "r");
char line[256];
while (fgets(line, sizeof(line), file))
{
char lineCopy[100];
memset(lineCopy, 100, 0);
strcpy(lineCopy, line);
char* token = strtok(lineCopy, ":");
char* directive = lineCopy;
char* value;
if(token != NULL)
{
value = strtok(NULL, ";");
if(value != NULL)
{
//check that we set right directives
if(!strcmp(directive, "logfile"))
{
char str[80];
strcpy(str, "Setting log file to: ");
strcat(str, value);
log(str, 4);
logFile = value;
}
if(!strcmp(directive, "loglevel"))
{
logLevel = atoi(value);
// printf("New log level: %d ", logLevel);
}
if(!strcmp(directive, "webroot"))
{
webroot = value;
// printf("Webroot: %s", webroot);
}
}
}
}
fclose(file);
}
void log(char* message, int severity)
{
if(severity <= logLevel)
{
FILE* file = fopen(logFile, "a");
time_t mytime = time(NULL);
char * time_str = ctime(&mytime);
time_str[strlen(time_str)-1] = '\0';
fprintf(file, time_str);
fprintf(file, " [%d] ", severity);
fprintf(file, "%s\n", message);
fclose(file);
}
}
struct tm getCurrentDate()
{
time_t t = time(NULL);
struct tm tm = *localtime(&t);
return tm;
}
void printCache()
{
printf("\n");
for(int i = 0; i < Cache_Size; i++)
{
printf("Item %d: '%s' '%s' '%d-%d-%d'\n", i, Cache[i].filename, Cache[i].content, Cache[i].date.tm_year + 1900,
Cache[i].date.tm_mon + 1, Cache[i].date.tm_mday);
}
printf("\n");
}
struct CachedItem getItemFromCache(char* filename)
{
for(int i = 0; i < Cache_Size; i++)
{
char* cacheFilename = Cache[i].filename;
if(!strcmp(cacheFilename, filename))
{
return Cache[i];
}
}
return createCachedItem("\0", "\0", getCurrentDate(), 0);
}
struct CachedItem createCachedItem(char* filename, char* content, struct tm date, int sizeOfContent)
{
struct CachedItem item;
strcpy(item.filename, filename);
strcpy(item.content, content);
item.date = date;
item.sizeOfContent = sizeOfContent;
return item;
}
void cacheItem(struct CachedItem item)
{
struct tm tempDate = getCurrentDate();
struct tm* tempPointer = &tempDate;
time_t earliestDate = mktime(tempPointer);
struct CachedItem earliestItem;
int earliestIndex = -1;
for(int i = 0; i < Cache_Size; i++)
{
//convert to longs to compare
struct tm* tempNewPointer = &Cache[i].date;
time_t cachedTime = mktime(tempNewPointer);
if(cachedTime < earliestDate)
{
earliestDate = cachedTime;
earliestIndex = i;
}
//todo better checking way
char* filename = Cache[i].filename;
//File of same name already in cache
if(!strcmp(filename, item.filename))
{
//file already in cache
return;
}
//strcmp returns 0 if strings are identical
else if(!strcmp(filename, ""))
{
Cache[i] = item;
return;
}
}
//item wasn't in cache
Cache[earliestIndex] = item;
}
void error(char *msg)
{
exit(1);
}
char* getFormattedDate(struct tm date)
{
int year = date.tm_year + 1900;
int month = date.tm_mon + 1;
int day = date.tm_mday;
printf("%d-%d-%d", year, month, day);
}
char* getFileName()
{
}
void* handleConnection (void* ptr)
{
int sock = (int) ptr;
int n;
char buffer[256];
char filename[256];
bzero(filename, 256);
bzero(buffer, 256);
n = read(sock,filename,255);
if (n < 0)
{
log("ERROR reading from socket", 0);
error("ERROR reading from socket");
close(sock);
}
removeTrailingNewline(filename);
struct CachedItem cachedFile = getItemFromCache(filename);
if(strcmp(cachedFile.filename, "\0"))
{
//we have file in cache
char str[80];
strcpy(str, "Found cached file: ");
strcat(str, cachedFile.filename);
log(str, 4);
n = write(sock, cachedFile.content, 255);
if(n < 0)
{
log("ERROR writing to socket", 0);
error("ERROR writing to socket");
}
}
else
{
char file[8096];
getFileContents(filename, file);
cacheItem(createCachedItem(filename, file, getCurrentDate(), 1));
n = write(sock, file, 8086);
if (n < 0)
{
log("ERROR writing to socket", 0);
error("ERROR writing to socket");
}
}
close(sock);
}
// remove new line from input
// https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
void removeTrailingNewline(char* filename)
{
char *pos;
if ((pos=strchr(filename, '\n')) != NULL)
{
*pos = '\0';
}
}
// reads file with name filename
// stores that in file
// https://stackoverflow.com/questions/11656532/returning-an-array-using-c
void getFileContents(char* filename, char* file)
{
FILE *fp;
printf("Opening file: %s\n", filename);
parseHeaderForFile(filename);
fp = fopen(filename, "r");
char wholeFile[8096] = "";
if(fp == NULL)
{
//TODO fix
printf("File pointer is NULL\n");
}
while (fgets(file, 8096, (FILE*)fp))
{
strcat(wholeFile, file);
}
char header[288];
getHeader(header);
strcat(header, wholeFile);
strcpy(file, header);
fclose(fp);
char str[80];
strcpy(str, "Client requested: ");
strcat(str, filename);
log(str, 4);
}
void parseHeaderForFile(char* header)
{
printf("hmmm");
printf("Header was: %s", header);
exit(0);
}
void getHeader(char* header){
printf("Loading header\n");
bzero(header, 288);
strcpy(header, "HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\nDate: 2019-02-28\nContent-Length: 4096\n\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment