Import of gamedata daemon. I love imported stuff.
--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402304
This commit is contained in:
parent
2c08bb3a96
commit
57bba6d83f
76
tools/daemon/Makefile
Normal file
76
tools/daemon/Makefile
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# (C)2004-2008 SourceMod Development Team
|
||||||
|
# Makefile written by David "BAILOPAN" Anderson
|
||||||
|
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
OBJECTS = smud.cpp smud_connections.cpp smud_threads.cpp
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||||
|
##############################################
|
||||||
|
|
||||||
|
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
|
||||||
|
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
|
||||||
|
C_GCC4_FLAGS = -fvisibility=hidden
|
||||||
|
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
|
||||||
|
CPP = gcc-4.1
|
||||||
|
|
||||||
|
BINARY = daemon
|
||||||
|
|
||||||
|
LINK += -lpthread -static-libgcc
|
||||||
|
|
||||||
|
INCLUDE += -I.
|
||||||
|
|
||||||
|
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||||
|
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror \
|
||||||
|
-Wno-uninitialized -mfpmath=sse -msse -DHAVE_STDINT_H -DSM_DEFAULT_THREADER -m32
|
||||||
|
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
|
||||||
|
|
||||||
|
################################################
|
||||||
|
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||||
|
################################################
|
||||||
|
|
||||||
|
ifeq "$(DEBUG)" "true"
|
||||||
|
BIN_DIR = Debug
|
||||||
|
CFLAGS += $(C_DEBUG_FLAGS)
|
||||||
|
else
|
||||||
|
BIN_DIR = Release
|
||||||
|
CFLAGS += $(C_OPT_FLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||||
|
ifeq "$(GCC_VERSION)" "4"
|
||||||
|
CFLAGS += $(C_GCC4_FLAGS)
|
||||||
|
CPPFLAGS += $(CPP_GCC4_FLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
OBJ_LINUX := $(OBJECTS:%vm_engine.cpp=$(BIN_DIR)/%vm_engine.o)
|
||||||
|
OBJ_LINUX := $(OBJ_LINUX:%.cpp=$(BIN_DIR)/%.o)
|
||||||
|
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
|
||||||
|
|
||||||
|
$(BIN_DIR)/%vm_engine.o: %vm_engine.cpp
|
||||||
|
$(CPP) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
$(BIN_DIR)/%.o: %.cpp
|
||||||
|
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
$(BIN_DIR)/%.o: %.c
|
||||||
|
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p $(BIN_DIR)
|
||||||
|
$(MAKE) -f Makefile sourcemod
|
||||||
|
|
||||||
|
sourcemod: $(OBJ_LINUX)
|
||||||
|
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -lstdc++ -o$(BIN_DIR)/$(BINARY)
|
||||||
|
|
||||||
|
debug:
|
||||||
|
$(MAKE) -f Makefile all DEBUG=true
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BIN_DIR)/$(BINARY)
|
130
tools/daemon/smud.cpp
Normal file
130
tools/daemon/smud.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#include "smud.h"
|
||||||
|
#include "smud_threads.h"
|
||||||
|
|
||||||
|
#define LISTEN_PORT 6500
|
||||||
|
#define LISTEN_QUEUE_LENGTH 6
|
||||||
|
|
||||||
|
char fileNames[NUM_FILES][30] = {
|
||||||
|
"core.games.txt",
|
||||||
|
"sdktools.games.txt",
|
||||||
|
"sdktools.games.ep2.txt",
|
||||||
|
"sm-cstrike.games.txt",
|
||||||
|
"sm-tf2.games.txt",
|
||||||
|
};
|
||||||
|
|
||||||
|
void *fileLocations[NUM_FILES];
|
||||||
|
int fileLength[NUM_FILES];
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
ThreadPool *pool;
|
||||||
|
struct protoent *pProtocol;
|
||||||
|
struct sockaddr_in serverAddress;
|
||||||
|
struct sockaddr_in clientAddress;
|
||||||
|
int serverSocket;
|
||||||
|
int clientSocket;
|
||||||
|
int addressLen;
|
||||||
|
int opts;
|
||||||
|
int file;
|
||||||
|
char filename[100];
|
||||||
|
struct stat sbuf;
|
||||||
|
|
||||||
|
printf("Loading Gamedata files into memory\n");
|
||||||
|
|
||||||
|
for (int i=0; i<NUM_FILES; i++)
|
||||||
|
{
|
||||||
|
snprintf(filename, sizeof(filename), "./md5/%s", fileNames[i]);
|
||||||
|
file = open(filename, O_RDWR);
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(filename, &sbuf) == -1)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fileLocations[i] = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, file, 0)) == (caddr_t)(-1))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileLength[i] = sbuf.st_size;
|
||||||
|
|
||||||
|
printf("Initialised file of %s of length %i\n", fileNames[i], fileLength[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Initializing Thread Pool\n");
|
||||||
|
|
||||||
|
pool = new ThreadPool();
|
||||||
|
|
||||||
|
if (!pool->Start())
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Create Server Socket\n");
|
||||||
|
|
||||||
|
memset(&serverAddress, 0, sizeof(serverAddress));
|
||||||
|
serverAddress.sin_family = AF_INET;
|
||||||
|
serverAddress.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
serverAddress.sin_port = htons(LISTEN_PORT);
|
||||||
|
|
||||||
|
pProtocol = getprotobyname("tcp");
|
||||||
|
|
||||||
|
if (pProtocol == NULL)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverSocket = socket(AF_INET, SOCK_STREAM, pProtocol->p_proto);
|
||||||
|
|
||||||
|
if (serverSocket < 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = 1;
|
||||||
|
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opts, sizeof(opts));
|
||||||
|
|
||||||
|
if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(serverSocket, LISTEN_QUEUE_LENGTH) < 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Entering Main Loop\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
addressLen = sizeof(clientAddress);
|
||||||
|
|
||||||
|
if ( (clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, (socklen_t *)&addressLen)) < 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = fcntl(clientSocket, F_GETFL, 0);
|
||||||
|
if (fcntl(clientSocket, F_SETFL, opts|O_NONBLOCK) < 0)
|
||||||
|
{
|
||||||
|
closesocket(clientSocket);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
printf("Connection Received!\n");
|
||||||
|
|
||||||
|
pool->AddConnection(clientSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
25
tools/daemon/smud.h
Normal file
25
tools/daemon/smud.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef _INCLUDE_SMUD_MAIN_H_
|
||||||
|
#define _INCLUDE_SMUD_MAIN_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define closesocket close
|
||||||
|
|
||||||
|
#define NUM_FILES 5
|
||||||
|
|
||||||
|
extern char fileNames[NUM_FILES][30];
|
||||||
|
extern void *fileLocations[NUM_FILES];
|
||||||
|
extern int fileLength[NUM_FILES];
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SMUD_MAIN_H_
|
396
tools/daemon/smud_connections.cpp
Normal file
396
tools/daemon/smud_connections.cpp
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
#include "smud_connections.h"
|
||||||
|
#include "smud.h"
|
||||||
|
|
||||||
|
ConnectionPool::ConnectionPool()
|
||||||
|
{
|
||||||
|
pthread_mutex_init(&m_AddLock, NULL);
|
||||||
|
m_timeOut = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionPool::~ConnectionPool()
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy(&m_AddLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::AddConnection( int fd )
|
||||||
|
{
|
||||||
|
smud_connection *connection = new smud_connection(fd);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&m_AddLock);
|
||||||
|
m_AddQueue.push_back(connection);
|
||||||
|
pthread_mutex_unlock(&m_AddLock);
|
||||||
|
|
||||||
|
printf("New Connection Added\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::Process( bool *terminate )
|
||||||
|
{
|
||||||
|
struct timespec ts_wait;
|
||||||
|
|
||||||
|
ts_wait.tv_sec = 0;
|
||||||
|
ts_wait.tv_nsec = 50000000; /* 50ms */
|
||||||
|
|
||||||
|
std::list<smud_connection *>::iterator iter;
|
||||||
|
smud_connection *con = NULL;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (*terminate)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = m_Links.begin();
|
||||||
|
|
||||||
|
QueryResult result = QueryResult_Continue;
|
||||||
|
int pollReturn = 0;
|
||||||
|
|
||||||
|
/* Add all connections that want processing to the sets */
|
||||||
|
while (iter != m_Links.end())
|
||||||
|
{
|
||||||
|
con = (smud_connection *)*iter;
|
||||||
|
|
||||||
|
pollReturn = poll(&(con->pollData), 1, 0);
|
||||||
|
|
||||||
|
if (pollReturn == -1)
|
||||||
|
{
|
||||||
|
//Something went badly wrong or the connection closed.
|
||||||
|
result = QueryResult_Complete;
|
||||||
|
}
|
||||||
|
else if (pollReturn == 1)
|
||||||
|
{
|
||||||
|
//Poll returns the number of sockets available (which can only ever be 1)
|
||||||
|
result = ProcessConnection(con);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == QueryResult_Complete)
|
||||||
|
{
|
||||||
|
iter = m_Links.erase(iter);
|
||||||
|
closesocket(con->fd);
|
||||||
|
delete con;
|
||||||
|
|
||||||
|
printf("Connection Completed!\n");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add new items to process */
|
||||||
|
|
||||||
|
iter = m_Links.end();
|
||||||
|
pthread_mutex_lock(&m_AddLock);
|
||||||
|
m_Links.splice(iter, m_AddQueue);
|
||||||
|
pthread_mutex_unlock(&m_AddLock);
|
||||||
|
|
||||||
|
nanosleep(&ts_wait, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult ConnectionPool::ProcessConnection( smud_connection *con )
|
||||||
|
{
|
||||||
|
switch (con->state)
|
||||||
|
{
|
||||||
|
case ConnectionState_ReadQueryHeader:
|
||||||
|
{
|
||||||
|
ReadQueryHeader(con);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ConnectionState_ReadQueryData:
|
||||||
|
{
|
||||||
|
ReadQueryContent(con);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ConnectionState_ReplyQuery:
|
||||||
|
{
|
||||||
|
ReplyQuery(con);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ConnectionState_SendingFiles:
|
||||||
|
{
|
||||||
|
SendFile(con);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ConnectionState_SendUnknownList:
|
||||||
|
{
|
||||||
|
SendUnknownList(con);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ConnectionState_Complete:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->state == ConnectionState_Complete)
|
||||||
|
{
|
||||||
|
printf("Ending connection because it marked itself as finished\n");
|
||||||
|
return QueryResult_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->start + m_timeOut < time(NULL))
|
||||||
|
{
|
||||||
|
printf("Ending connection because it has passed maximum allowed time\n");
|
||||||
|
return QueryResult_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QueryResult_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::ReadQueryHeader( smud_connection *con )
|
||||||
|
{
|
||||||
|
char data[11];
|
||||||
|
|
||||||
|
if (recv(con->fd, data, sizeof(data), 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[0] != 'A' || data[1] != 'G')
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ignore the next 8 bytes for the moment. Versioning data is currently unused
|
||||||
|
// uint16[4] - source version major/minor/something/rev
|
||||||
|
|
||||||
|
con->sentSums = data[10];
|
||||||
|
|
||||||
|
con->state = ConnectionState_ReadQueryData;
|
||||||
|
printf("Query Header Read Complete, %i md5's expected\n", con->sentSums);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::ReplyQuery(smud_connection *con)
|
||||||
|
{
|
||||||
|
char data[12];
|
||||||
|
data[0] = 'A';
|
||||||
|
data[1] = 'G';
|
||||||
|
|
||||||
|
data[2] = (char)Update_Unknown; //unused versioning crap
|
||||||
|
*(short *)&data[3] = 1;
|
||||||
|
*(short *)&data[5] = 0;
|
||||||
|
*(short *)&data[7] = 0;
|
||||||
|
*(short *)&data[9] = 3;
|
||||||
|
|
||||||
|
data[11] = (char)con->sendCount;
|
||||||
|
|
||||||
|
if (send(con->fd, data, sizeof(data), 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Now we need more send sub functions for all the damn files. Geh.
|
||||||
|
//Alternatively we could just send all at once here. Could make for a damn big query. 100k anyone?
|
||||||
|
|
||||||
|
con->state = ConnectionState_SendingFiles;
|
||||||
|
printf("Query Reply Header Complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::ReadQueryContent( smud_connection *con )
|
||||||
|
{
|
||||||
|
char *data = new char[16*(con->sentSums)]();
|
||||||
|
|
||||||
|
if (recv(con->fd, data, 16*(con->sentSums), 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->shouldSend = new MD5Status[con->sentSums]();
|
||||||
|
con->fileLocation = new int[con->sentSums]();
|
||||||
|
con->headerSent = new bool[con->sentSums]();
|
||||||
|
|
||||||
|
for (int i=0; i<con->sentSums; i++)
|
||||||
|
{
|
||||||
|
con->fileLocation[i] = -1;
|
||||||
|
con->shouldSend[i] = GetMD5UpdateStatus(data + (16*i), con, i);
|
||||||
|
|
||||||
|
if (con->shouldSend[i] == MD5Status_NeedsUpdate)
|
||||||
|
{
|
||||||
|
printf("File %i needs updating\n", i);
|
||||||
|
con->sendCount++;
|
||||||
|
con->headerSent[i] = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->shouldSend[i] == MD5Status_Unknown)
|
||||||
|
{
|
||||||
|
printf("File %i is unknown\n", i);
|
||||||
|
con->unknownCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
con->state = ConnectionState_ReplyQuery;
|
||||||
|
con->pollData.events = POLLOUT;
|
||||||
|
delete [] data;
|
||||||
|
printf("Query Data Read Complete\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5Status ConnectionPool::GetMD5UpdateStatus( const char *md5 , smud_connection *con, int fileNum)
|
||||||
|
{
|
||||||
|
//Try find a file with this name in some directory.
|
||||||
|
char path[100] = "./md5/";
|
||||||
|
char temp[4];
|
||||||
|
char md5String[33] = "";
|
||||||
|
|
||||||
|
for (int i=0; i<16; i++)
|
||||||
|
{
|
||||||
|
snprintf(temp, sizeof(temp), "%02x", (unsigned char)md5[i]);
|
||||||
|
strcat(md5String, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(path, md5String);
|
||||||
|
|
||||||
|
printf("checking for file \"%s\"\n", path);
|
||||||
|
|
||||||
|
FILE *file = fopen(path, "r");
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
{
|
||||||
|
printf("Couldn't find file!\n");
|
||||||
|
return MD5Status_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
char latestMD5[33];
|
||||||
|
fgets(latestMD5, 33, file);
|
||||||
|
printf("Latest md5 is: %s\n", latestMD5);
|
||||||
|
|
||||||
|
if (strcmp(latestMD5, md5String) == 0)
|
||||||
|
{
|
||||||
|
return MD5Status_Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
char filename[100];
|
||||||
|
fgets(filename, sizeof(filename), file);
|
||||||
|
if (filename[strlen(filename)-1] == '\n')
|
||||||
|
{
|
||||||
|
filename[strlen(filename)-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Filename is %s\n", filename);
|
||||||
|
|
||||||
|
//We now need to match this filename with one of our mmap'd files in memory and store it until send gets called.
|
||||||
|
for (int i=0; i<NUM_FILES; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(fileNames[i], filename) == 0)
|
||||||
|
{
|
||||||
|
con->fileLocation[fileNum] = i;
|
||||||
|
printf("File %i mapped to local file %i\n", fileNum, i);
|
||||||
|
return MD5Status_NeedsUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MD5Status_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::SendFile( smud_connection *con )
|
||||||
|
{
|
||||||
|
//Find the next file to send.
|
||||||
|
while (con->currentFile < con->sentSums &&
|
||||||
|
con->shouldSend[con->currentFile] != MD5Status_NeedsUpdate)
|
||||||
|
{
|
||||||
|
con->currentFile++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//All files have been sent.
|
||||||
|
if (con->currentFile >= con->sentSums)
|
||||||
|
{
|
||||||
|
printf("All files sent!\n");
|
||||||
|
con->state = ConnectionState_SendUnknownList;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *file = fileLocations[con->fileLocation[con->currentFile]];
|
||||||
|
int filelength = fileLength[con->fileLocation[con->currentFile]];
|
||||||
|
|
||||||
|
printf("Sending file of length %i\n", filelength);
|
||||||
|
printf("Current file index is: %i, maps to file index: %i\n", con->currentFile, con->fileLocation[con->currentFile]);
|
||||||
|
|
||||||
|
if (!con->headerSent[con->currentFile])
|
||||||
|
{
|
||||||
|
char buffer[5];
|
||||||
|
buffer[0] = con->currentFile;
|
||||||
|
*((int *)&buffer[1]) = filelength;
|
||||||
|
|
||||||
|
if (send(con->fd, buffer, 5, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->headerSent[con->currentFile] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send(con->fd, file, filelength, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->currentFile++;
|
||||||
|
printf("Sent a file!: %s\n", fileNames[con->fileLocation[con->currentFile-1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionPool::SendUnknownList( smud_connection *con )
|
||||||
|
{
|
||||||
|
int size = con->unknownCount+1;
|
||||||
|
char *packet = new char[size]();
|
||||||
|
|
||||||
|
packet[0] = con->unknownCount;
|
||||||
|
|
||||||
|
printf("%i Files are unknown\n", con->unknownCount);
|
||||||
|
|
||||||
|
int i=1;
|
||||||
|
|
||||||
|
for (int j=0; j<con->sentSums; j++)
|
||||||
|
{
|
||||||
|
if (con->shouldSend[j] == MD5Status_Unknown)
|
||||||
|
{
|
||||||
|
packet[i] = j;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send(con->fd, packet, size, 0) == -1)
|
||||||
|
{
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->state = ConnectionState_Complete;
|
||||||
|
printf("Unknown's Sent\n");
|
||||||
|
}
|
109
tools/daemon/smud_connections.h
Normal file
109
tools/daemon/smud_connections.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#ifndef _INCLUDE_SMUD_CONNECTION_H_
|
||||||
|
#define _INCLUDE_SMUD_CONNECTION_H_
|
||||||
|
|
||||||
|
#include "smud.h"
|
||||||
|
#include <list>
|
||||||
|
#include "poll.h"
|
||||||
|
|
||||||
|
enum ConnectionState
|
||||||
|
{
|
||||||
|
ConnectionState_ReadQueryHeader,
|
||||||
|
ConnectionState_ReadQueryData,
|
||||||
|
ConnectionState_ReplyQuery,
|
||||||
|
ConnectionState_SendingFiles,
|
||||||
|
ConnectionState_SendUnknownList,
|
||||||
|
ConnectionState_Complete,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum QueryResult
|
||||||
|
{
|
||||||
|
QueryResult_Continue,
|
||||||
|
QueryResult_Complete,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MD5Status
|
||||||
|
{
|
||||||
|
MD5Status_Unknown,
|
||||||
|
MD5Status_Current,
|
||||||
|
MD5Status_NeedsUpdate,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UpdateStatus
|
||||||
|
{
|
||||||
|
Update_Unknown = 0, /* Version wasn't recognised or version querying is unsupported */
|
||||||
|
Update_Current = 1, /* Server is running latest version */
|
||||||
|
Update_NewBuild = 2, /* Server is on a svn release and a newer version is available */
|
||||||
|
Update_MinorAvailable = 3, /* Server is on a release and a minor release has superceeded it */
|
||||||
|
Update_MajorAvailable = 4, /* Server is on a release and a major release has superceeded it */
|
||||||
|
Update_CriticalAvailable = 5, /* A critical update has been released (security fixes etc) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smud_connection
|
||||||
|
{
|
||||||
|
smud_connection(int fd)
|
||||||
|
{
|
||||||
|
shouldSend = NULL;
|
||||||
|
fileLocation = NULL;
|
||||||
|
headerSent = NULL;
|
||||||
|
sentSums = 0;
|
||||||
|
sendCount = 0;
|
||||||
|
currentFile = 0;
|
||||||
|
unknownCount = 0;
|
||||||
|
pollData.events = POLLIN;
|
||||||
|
start = time(NULL);
|
||||||
|
state = ConnectionState_ReadQueryHeader;
|
||||||
|
this->fd = fd;
|
||||||
|
pollData.fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
~smud_connection()
|
||||||
|
{
|
||||||
|
if (shouldSend != NULL)
|
||||||
|
delete [] shouldSend;
|
||||||
|
if (fileLocation != NULL)
|
||||||
|
delete [] fileLocation;
|
||||||
|
if (headerSent != NULL)
|
||||||
|
delete [] headerSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd; /** Socket file descriptor */
|
||||||
|
time_t start; /** The time this connection was received (for timeouts) */
|
||||||
|
ConnectionState state; /** How far through processing the connection we are */
|
||||||
|
uint8_t sentSums; /** Number of MD5 Sums sent from the client */
|
||||||
|
MD5Status *shouldSend; /** Arrays of statuses for each sum */
|
||||||
|
int *fileLocation; /** Array of indexes into the global file list for each sum (only valid if shouldSend[i] == MD5Status_NeedsUpdate) */
|
||||||
|
bool *headerSent; /** Has the header been sent yet for each sum? Header == file index and size */
|
||||||
|
int sendCount; /** Number of files that need to be sent */
|
||||||
|
int unknownCount; /** Number of files that were unknown */
|
||||||
|
int currentFile; /** Current file being sent (index into the above 3 arrays) */
|
||||||
|
pollfd pollData; /** Data to be passed into poll() */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectionPool();
|
||||||
|
~ConnectionPool();
|
||||||
|
public:
|
||||||
|
void AddConnection(int fd);
|
||||||
|
void Process(bool *terminate);
|
||||||
|
private:
|
||||||
|
QueryResult ProcessConnection(smud_connection *con);
|
||||||
|
void ReadQueryHeader(smud_connection *con);
|
||||||
|
void ReadQueryContent(smud_connection *con);
|
||||||
|
void ReplyQuery(smud_connection *con);
|
||||||
|
void SendFile(smud_connection *con);
|
||||||
|
void SendUnknownList(smud_connection *con);
|
||||||
|
|
||||||
|
MD5Status GetMD5UpdateStatus(const char *md5, smud_connection *con, int fileNum);
|
||||||
|
private:
|
||||||
|
std::list<smud_connection *> m_Links;
|
||||||
|
std::list<smud_connection *> m_AddQueue;
|
||||||
|
pthread_mutex_t m_AddLock;
|
||||||
|
time_t m_timeOut;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SMUD_CONNECTION_H_
|
||||||
|
|
86
tools/daemon/smud_threads.cpp
Normal file
86
tools/daemon/smud_threads.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "smud_threads.h"
|
||||||
|
|
||||||
|
ThreadPool::ThreadPool()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPool::~ThreadPool()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThreadPool::Start()
|
||||||
|
{
|
||||||
|
m_pWorker = new ThreadWorker();
|
||||||
|
|
||||||
|
if (!m_pWorker->Start())
|
||||||
|
{
|
||||||
|
delete m_pWorker;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPool::Stop()
|
||||||
|
{
|
||||||
|
m_pWorker->CancelAndWait();
|
||||||
|
delete m_pWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPool::AddConnection(int fd)
|
||||||
|
{
|
||||||
|
m_pWorker->AddConnection(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadWorker::ThreadWorker() : m_bShouldCancel(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadWorker::~ThreadWorker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThreadWorker::Start()
|
||||||
|
{
|
||||||
|
m_pPool = new ConnectionPool();
|
||||||
|
pthread_mutex_init(&m_NotifyLock, NULL);
|
||||||
|
pthread_cond_init(&m_Notify, NULL);
|
||||||
|
|
||||||
|
if (pthread_create(&m_Thread, NULL, ThreadCallback, this) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadWorker::CancelAndWait()
|
||||||
|
{
|
||||||
|
m_bShouldCancel = true;
|
||||||
|
|
||||||
|
pthread_join(m_Thread, NULL);
|
||||||
|
|
||||||
|
pthread_cond_destroy(&m_Notify);
|
||||||
|
pthread_mutex_destroy(&m_NotifyLock);
|
||||||
|
|
||||||
|
delete m_pPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadWorker::AddConnection( int fd )
|
||||||
|
{
|
||||||
|
m_pPool->AddConnection(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadWorker::Process()
|
||||||
|
{
|
||||||
|
m_pPool->Process(&m_bShouldCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ThreadCallback(void *data)
|
||||||
|
{
|
||||||
|
((ThreadWorker *)data)->Process();
|
||||||
|
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
41
tools/daemon/smud_threads.h
Normal file
41
tools/daemon/smud_threads.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef _INCLUDE_SMUD_H_
|
||||||
|
#define _INCLUDE_SMUD_H_
|
||||||
|
|
||||||
|
#include "smud.h"
|
||||||
|
#include "smud_connections.h"
|
||||||
|
|
||||||
|
void *ThreadCallback(void *data);
|
||||||
|
|
||||||
|
class ThreadWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThreadWorker();
|
||||||
|
~ThreadWorker();
|
||||||
|
public:
|
||||||
|
bool Start();
|
||||||
|
void CancelAndWait();
|
||||||
|
void AddConnection(int fd);
|
||||||
|
void Process();
|
||||||
|
private:
|
||||||
|
ConnectionPool *m_pPool;
|
||||||
|
pthread_t m_Thread;
|
||||||
|
pthread_mutex_t m_NotifyLock;
|
||||||
|
pthread_cond_t m_Notify;
|
||||||
|
bool m_bShouldCancel;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThreadPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThreadPool();
|
||||||
|
~ThreadPool();
|
||||||
|
public:
|
||||||
|
void AddConnection(int fd);
|
||||||
|
bool Start();
|
||||||
|
void Stop();
|
||||||
|
private:
|
||||||
|
ThreadWorker *m_pWorker;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SMUD_H_
|
||||||
|
|
Loading…
Reference in New Issue
Block a user