tools/daemon/smud_connections.cpp
changeset 2129 11d73bf97119
child 2140 7e34b2b2b05b
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/daemon/smud_connections.cpp	Mon Jun 30 02:34:21 2008 +0000
     1.3 @@ -0,0 +1,396 @@
     1.4 +#include "smud_connections.h"
     1.5 +#include "smud.h"
     1.6 +
     1.7 +ConnectionPool::ConnectionPool()
     1.8 +{
     1.9 +	pthread_mutex_init(&m_AddLock, NULL);
    1.10 +	m_timeOut = 1000;
    1.11 +}
    1.12 +
    1.13 +ConnectionPool::~ConnectionPool()
    1.14 +{
    1.15 +	pthread_mutex_destroy(&m_AddLock);
    1.16 +}
    1.17 +
    1.18 +void ConnectionPool::AddConnection( int fd )
    1.19 +{
    1.20 +	smud_connection *connection = new smud_connection(fd);
    1.21 +
    1.22 +	pthread_mutex_lock(&m_AddLock);
    1.23 +	m_AddQueue.push_back(connection);
    1.24 +	pthread_mutex_unlock(&m_AddLock);
    1.25 +
    1.26 +	printf("New Connection Added\n");
    1.27 +}
    1.28 +
    1.29 +void ConnectionPool::Process( bool *terminate )
    1.30 +{
    1.31 +	struct timespec ts_wait;
    1.32 +
    1.33 +	ts_wait.tv_sec = 0;
    1.34 +	ts_wait.tv_nsec = 50000000; /* 50ms */
    1.35 +
    1.36 +	std::list<smud_connection *>::iterator iter;
    1.37 +	smud_connection *con = NULL;
    1.38 +
    1.39 +	while (1)
    1.40 +	{
    1.41 +		if (*terminate)
    1.42 +		{
    1.43 +			return;
    1.44 +		}
    1.45 +
    1.46 +		iter = m_Links.begin();
    1.47 +
    1.48 +		QueryResult result = QueryResult_Continue;
    1.49 +		int pollReturn = 0;
    1.50 +
    1.51 +		/* Add all connections that want processing to the sets */
    1.52 +		while (iter != m_Links.end())
    1.53 +		{
    1.54 +			con = (smud_connection *)*iter;
    1.55 +
    1.56 +			pollReturn = poll(&(con->pollData), 1, 0);
    1.57 +
    1.58 +			if (pollReturn == -1)
    1.59 +			{
    1.60 +				//Something went badly wrong or the connection closed.
    1.61 +				result = QueryResult_Complete;
    1.62 +			}
    1.63 +			else if (pollReturn == 1)
    1.64 +			{
    1.65 +				//Poll returns the number of sockets available (which can only ever be 1)
    1.66 +				result = ProcessConnection(con);
    1.67 +			}
    1.68 +
    1.69 +			if (result == QueryResult_Complete)
    1.70 +			{
    1.71 +				iter = m_Links.erase(iter);
    1.72 +				closesocket(con->fd);
    1.73 +				delete con;
    1.74 +
    1.75 +				printf("Connection Completed!\n");
    1.76 +
    1.77 +				continue;
    1.78 +			}
    1.79 +
    1.80 +			iter++;
    1.81 +		}
    1.82 +
    1.83 +		/* Add new items to process */
    1.84 +
    1.85 +		iter = m_Links.end();
    1.86 +		pthread_mutex_lock(&m_AddLock);
    1.87 +		m_Links.splice(iter, m_AddQueue);
    1.88 +		pthread_mutex_unlock(&m_AddLock);
    1.89 +
    1.90 +		nanosleep(&ts_wait, NULL);
    1.91 +	}
    1.92 +}
    1.93 +
    1.94 +QueryResult ConnectionPool::ProcessConnection( smud_connection *con )
    1.95 +{
    1.96 +	switch (con->state)
    1.97 +	{
    1.98 +		case ConnectionState_ReadQueryHeader:
    1.99 +		{
   1.100 +			ReadQueryHeader(con);
   1.101 +			break;
   1.102 +		}
   1.103 +
   1.104 +		case ConnectionState_ReadQueryData:
   1.105 +		{
   1.106 +			ReadQueryContent(con);
   1.107 +			break;
   1.108 +		}
   1.109 +
   1.110 +		case ConnectionState_ReplyQuery:
   1.111 +		{
   1.112 +			ReplyQuery(con);
   1.113 +			break;
   1.114 +		}
   1.115 +
   1.116 +		case ConnectionState_SendingFiles:
   1.117 +		{
   1.118 +			SendFile(con);
   1.119 +			break;
   1.120 +		}
   1.121 +
   1.122 +		case ConnectionState_SendUnknownList:
   1.123 +		{
   1.124 +			SendUnknownList(con);
   1.125 +			break;
   1.126 +		}
   1.127 +
   1.128 +		case ConnectionState_Complete:
   1.129 +		{
   1.130 +			break;
   1.131 +		}
   1.132 +	}
   1.133 +
   1.134 +	if (con->state == ConnectionState_Complete)
   1.135 +	{
   1.136 +		printf("Ending connection because it marked itself as finished\n");
   1.137 +		return QueryResult_Complete;
   1.138 +	}
   1.139 +
   1.140 +	if (con->start + m_timeOut < time(NULL))
   1.141 +	{
   1.142 +		printf("Ending connection because it has passed maximum allowed time\n");
   1.143 +		return QueryResult_Complete;
   1.144 +	}
   1.145 +
   1.146 +	return QueryResult_Continue;
   1.147 +}
   1.148 +
   1.149 +void ConnectionPool::ReadQueryHeader( smud_connection *con )
   1.150 +{
   1.151 +	char data[11];
   1.152 +
   1.153 +	if (recv(con->fd, data, sizeof(data), 0) == -1)
   1.154 +	{
   1.155 +		if (errno != EAGAIN && errno != EWOULDBLOCK)
   1.156 +		{
   1.157 +			con->state = ConnectionState_Complete;
   1.158 +		}
   1.159 +
   1.160 +		return;
   1.161 +	}
   1.162 +
   1.163 +	if (data[0] != 'A' || data[1] != 'G')
   1.164 +	{
   1.165 +		con->state = ConnectionState_Complete;
   1.166 +		return;
   1.167 +	}
   1.168 +
   1.169 +	//Ignore the next 8 bytes for the moment. Versioning data is currently unused
   1.170 +	// uint16[4] - source version major/minor/something/rev
   1.171 +
   1.172 +	con->sentSums = data[10];
   1.173 +
   1.174 +	con->state = ConnectionState_ReadQueryData;
   1.175 +	printf("Query Header Read Complete, %i md5's expected\n", con->sentSums);
   1.176 +}
   1.177 +
   1.178 +void ConnectionPool::ReplyQuery(smud_connection *con)
   1.179 +{
   1.180 +	char data[12];
   1.181 +	data[0] = 'A';
   1.182 +	data[1] = 'G';
   1.183 +
   1.184 +	data[2] = (char)Update_Unknown; //unused versioning crap
   1.185 +	*(short *)&data[3] = 1;
   1.186 +	*(short *)&data[5] = 0;
   1.187 +	*(short *)&data[7] = 0;
   1.188 +	*(short *)&data[9] = 3;
   1.189 +
   1.190 +	data[11] = (char)con->sendCount;
   1.191 +
   1.192 +	if (send(con->fd, data, sizeof(data), 0) == -1)
   1.193 +	{
   1.194 +		if (errno != EAGAIN && errno != EWOULDBLOCK)
   1.195 +		{
   1.196 +			con->state = ConnectionState_Complete;
   1.197 +		}
   1.198 +
   1.199 +		return;
   1.200 +	}
   1.201 +	
   1.202 +	//Now we need more send sub functions for all the damn files. Geh.
   1.203 +	//Alternatively we could just send all at once here. Could make for a damn big query. 100k anyone?
   1.204 +
   1.205 +	con->state = ConnectionState_SendingFiles;
   1.206 +	printf("Query Reply Header Complete\n");
   1.207 +}
   1.208 +
   1.209 +void ConnectionPool::ReadQueryContent( smud_connection *con )
   1.210 +{
   1.211 +	char *data = new char[16*(con->sentSums)]();
   1.212 +
   1.213 +	if (recv(con->fd, data, 16*(con->sentSums), 0) == -1)
   1.214 +	{
   1.215 +		if (errno != EAGAIN && errno != EWOULDBLOCK)
   1.216 +		{
   1.217 +			con->state = ConnectionState_Complete;
   1.218 +		}
   1.219 +
   1.220 +		delete [] data;
   1.221 +		return;
   1.222 +	}
   1.223 +
   1.224 +	con->shouldSend = new MD5Status[con->sentSums]();
   1.225 +	con->fileLocation = new int[con->sentSums]();
   1.226 +	con->headerSent = new bool[con->sentSums]();
   1.227 +
   1.228 +	for (int i=0; i<con->sentSums; i++)
   1.229 +	{
   1.230 +		con->fileLocation[i] = -1;
   1.231 +		con->shouldSend[i] = GetMD5UpdateStatus(data + (16*i), con, i);
   1.232 +		
   1.233 +		if (con->shouldSend[i] == MD5Status_NeedsUpdate)
   1.234 +		{
   1.235 +			printf("File %i needs updating\n", i);
   1.236 +			con->sendCount++;
   1.237 +			con->headerSent[i] = false;
   1.238 +			continue;
   1.239 +		}
   1.240 +
   1.241 +		if (con->shouldSend[i] == MD5Status_Unknown)
   1.242 +		{
   1.243 +			printf("File %i is unknown\n", i);
   1.244 +			con->unknownCount++;
   1.245 +		}
   1.246 +	}
   1.247 +
   1.248 +	con->state = ConnectionState_ReplyQuery;
   1.249 +	con->pollData.events = POLLOUT;
   1.250 +	delete [] data;
   1.251 +	printf("Query Data Read Complete\n");
   1.252 +}
   1.253 +
   1.254 +MD5Status ConnectionPool::GetMD5UpdateStatus( const char *md5 , smud_connection *con, int fileNum)
   1.255 +{
   1.256 +	//Try find a file with this name in some directory.
   1.257 +	char path[100] = "./md5/";
   1.258 +	char temp[4];
   1.259 +	char md5String[33] = "";
   1.260 +
   1.261 +	for (int i=0; i<16; i++)
   1.262 +	{
   1.263 +		snprintf(temp, sizeof(temp), "%02x", (unsigned char)md5[i]);
   1.264 +		strcat(md5String, temp);
   1.265 +	}
   1.266 +
   1.267 +	strcat(path, md5String);
   1.268 +
   1.269 +	printf("checking for file \"%s\"\n", path);
   1.270 +	
   1.271 +	FILE *file = fopen(path, "r");
   1.272 +
   1.273 +	if (file == NULL)
   1.274 +	{
   1.275 +		printf("Couldn't find file!\n");
   1.276 +		return MD5Status_Unknown;
   1.277 +	}
   1.278 +
   1.279 +	char latestMD5[33];
   1.280 +	fgets(latestMD5, 33, file);
   1.281 +	printf("Latest md5 is: %s\n", latestMD5);
   1.282 +
   1.283 +	if (strcmp(latestMD5, md5String) == 0)
   1.284 +	{
   1.285 +		return MD5Status_Current;
   1.286 +	}
   1.287 +
   1.288 +	char filename[100];
   1.289 +	fgets(filename, sizeof(filename), file);
   1.290 +	if (filename[strlen(filename)-1] == '\n')
   1.291 +	{
   1.292 +		filename[strlen(filename)-1] = '\0';
   1.293 +	}
   1.294 +
   1.295 +	printf("Filename is %s\n", filename);
   1.296 +
   1.297 +	//We now need to match this filename with one of our mmap'd files in memory and store it until send gets called.
   1.298 +	for (int i=0; i<NUM_FILES; i++)
   1.299 +	{
   1.300 +		if (strcmp(fileNames[i], filename) == 0)
   1.301 +		{
   1.302 +			con->fileLocation[fileNum] = i;
   1.303 +			printf("File %i mapped to local file %i\n", fileNum, i);
   1.304 +			return MD5Status_NeedsUpdate;
   1.305 +		}
   1.306 +	}
   1.307 +
   1.308 +	return MD5Status_Unknown;
   1.309 +}
   1.310 +
   1.311 +void ConnectionPool::SendFile( smud_connection *con )
   1.312 +{
   1.313 +	//Find the next file to send.
   1.314 +	while (con->currentFile < con->sentSums &&
   1.315 +			con->shouldSend[con->currentFile] != MD5Status_NeedsUpdate)
   1.316 +	{
   1.317 +		con->currentFile++;
   1.318 +	}
   1.319 +
   1.320 +	//All files have been sent.
   1.321 +	if (con->currentFile >= con->sentSums)
   1.322 +	{
   1.323 +		printf("All files sent!\n");
   1.324 +		con->state = ConnectionState_SendUnknownList;
   1.325 +		return;
   1.326 +	}
   1.327 +
   1.328 +	void *file = fileLocations[con->fileLocation[con->currentFile]];
   1.329 +	int filelength = fileLength[con->fileLocation[con->currentFile]];
   1.330 +
   1.331 +	printf("Sending file of length %i\n", filelength);
   1.332 +	printf("Current file index is: %i, maps to file index: %i\n", con->currentFile, con->fileLocation[con->currentFile]);
   1.333 +
   1.334 +	if (!con->headerSent[con->currentFile])
   1.335 +	{
   1.336 +		char buffer[5];
   1.337 +		buffer[0] = con->currentFile;
   1.338 +		*((int *)&buffer[1]) = filelength;
   1.339 +
   1.340 +		if (send(con->fd, buffer, 5, 0) == -1)
   1.341 +		{
   1.342 +			if (errno != EAGAIN && errno != EWOULDBLOCK)
   1.343 +			{
   1.344 +				con->state = ConnectionState_Complete;
   1.345 +			}
   1.346 +
   1.347 +			return;
   1.348 +		}
   1.349 +
   1.350 +		con->headerSent[con->currentFile] = true;
   1.351 +	}
   1.352 +
   1.353 +	if (send(con->fd, file, filelength, 0) == -1)
   1.354 +	{
   1.355 +		if (errno != EAGAIN && errno != EWOULDBLOCK)
   1.356 +		{
   1.357 +			con->state = ConnectionState_Complete;
   1.358 +		}
   1.359 +
   1.360 +		return;
   1.361 +	}
   1.362 +
   1.363 +	con->currentFile++;
   1.364 +	printf("Sent a file!: %s\n", fileNames[con->fileLocation[con->currentFile-1]]);
   1.365 +}
   1.366 +
   1.367 +void ConnectionPool::SendUnknownList( smud_connection *con )
   1.368 +{
   1.369 +	int size = con->unknownCount+1;
   1.370 +	char *packet = new char[size]();
   1.371 +
   1.372 +	packet[0] = con->unknownCount;
   1.373 +
   1.374 +	printf("%i Files are unknown\n", con->unknownCount);
   1.375 +
   1.376 +	int i=1;
   1.377 +
   1.378 +	for (int j=0; j<con->sentSums; j++)
   1.379 +	{
   1.380 +		if (con->shouldSend[j] == MD5Status_Unknown)
   1.381 +		{
   1.382 +			packet[i] = j;
   1.383 +			i++;
   1.384 +		}
   1.385 +	}
   1.386 +
   1.387 +	if (send(con->fd, packet, size, 0) == -1)
   1.388 +	{
   1.389 +		if (errno != EAGAIN && errno != EWOULDBLOCK)
   1.390 +		{
   1.391 +			con->state = ConnectionState_Complete;
   1.392 +		}
   1.393 +
   1.394 +		return;
   1.395 +	}
   1.396 +
   1.397 +	con->state = ConnectionState_Complete;
   1.398 +	printf("Unknown's Sent\n");
   1.399 +}