tools/daemon/smud_connections.cpp
author Matt Woodrow <pred@alliedmods.net>
Tue Jul 01 09:29:02 2008 +0000 (2008-07-01)
changeset 2140 7e34b2b2b05b
parent 2129 11d73bf97119
child 2141 0a5b3e37dfe0
permissions -rw-r--r--
More changes to support the shell script.
pred@2129
     1
#include "smud_connections.h"
pred@2129
     2
#include "smud.h"
pred@2129
     3
pred@2129
     4
ConnectionPool::ConnectionPool()
pred@2129
     5
{
pred@2129
     6
	pthread_mutex_init(&m_AddLock, NULL);
pred@2129
     7
	m_timeOut = 1000;
pred@2129
     8
}
pred@2129
     9
pred@2129
    10
ConnectionPool::~ConnectionPool()
pred@2129
    11
{
pred@2129
    12
	pthread_mutex_destroy(&m_AddLock);
pred@2129
    13
}
pred@2129
    14
pred@2129
    15
void ConnectionPool::AddConnection( int fd )
pred@2129
    16
{
pred@2129
    17
	smud_connection *connection = new smud_connection(fd);
pred@2129
    18
pred@2129
    19
	pthread_mutex_lock(&m_AddLock);
pred@2129
    20
	m_AddQueue.push_back(connection);
pred@2129
    21
	pthread_mutex_unlock(&m_AddLock);
pred@2129
    22
pred@2129
    23
	printf("New Connection Added\n");
pred@2129
    24
}
pred@2129
    25
pred@2129
    26
void ConnectionPool::Process( bool *terminate )
pred@2129
    27
{
pred@2129
    28
	struct timespec ts_wait;
pred@2129
    29
pred@2129
    30
	ts_wait.tv_sec = 0;
pred@2129
    31
	ts_wait.tv_nsec = 50000000; /* 50ms */
pred@2129
    32
pred@2129
    33
	std::list<smud_connection *>::iterator iter;
pred@2129
    34
	smud_connection *con = NULL;
pred@2129
    35
pred@2129
    36
	while (1)
pred@2129
    37
	{
pred@2129
    38
		if (*terminate)
pred@2129
    39
		{
pred@2129
    40
			return;
pred@2129
    41
		}
pred@2129
    42
pred@2129
    43
		iter = m_Links.begin();
pred@2129
    44
pred@2129
    45
		QueryResult result = QueryResult_Continue;
pred@2129
    46
		int pollReturn = 0;
pred@2129
    47
pred@2129
    48
		/* Add all connections that want processing to the sets */
pred@2129
    49
		while (iter != m_Links.end())
pred@2129
    50
		{
pred@2129
    51
			con = (smud_connection *)*iter;
pred@2129
    52
pred@2129
    53
			pollReturn = poll(&(con->pollData), 1, 0);
pred@2129
    54
pred@2129
    55
			if (pollReturn == -1)
pred@2129
    56
			{
pred@2129
    57
				//Something went badly wrong or the connection closed.
pred@2129
    58
				result = QueryResult_Complete;
pred@2129
    59
			}
pred@2129
    60
			else if (pollReturn == 1)
pred@2129
    61
			{
pred@2129
    62
				//Poll returns the number of sockets available (which can only ever be 1)
pred@2129
    63
				result = ProcessConnection(con);
pred@2129
    64
			}
pred@2129
    65
pred@2129
    66
			if (result == QueryResult_Complete)
pred@2129
    67
			{
pred@2129
    68
				iter = m_Links.erase(iter);
pred@2129
    69
				closesocket(con->fd);
pred@2129
    70
				delete con;
pred@2129
    71
pred@2129
    72
				printf("Connection Completed!\n");
pred@2129
    73
pred@2129
    74
				continue;
pred@2129
    75
			}
pred@2129
    76
pred@2129
    77
			iter++;
pred@2129
    78
		}
pred@2129
    79
pred@2129
    80
		/* Add new items to process */
pred@2129
    81
pred@2129
    82
		iter = m_Links.end();
pred@2129
    83
		pthread_mutex_lock(&m_AddLock);
pred@2129
    84
		m_Links.splice(iter, m_AddQueue);
pred@2129
    85
		pthread_mutex_unlock(&m_AddLock);
pred@2129
    86
pred@2129
    87
		nanosleep(&ts_wait, NULL);
pred@2129
    88
	}
pred@2129
    89
}
pred@2129
    90
pred@2129
    91
QueryResult ConnectionPool::ProcessConnection( smud_connection *con )
pred@2129
    92
{
pred@2129
    93
	switch (con->state)
pred@2129
    94
	{
pred@2129
    95
		case ConnectionState_ReadQueryHeader:
pred@2129
    96
		{
pred@2129
    97
			ReadQueryHeader(con);
pred@2129
    98
			break;
pred@2129
    99
		}
pred@2129
   100
pred@2129
   101
		case ConnectionState_ReadQueryData:
pred@2129
   102
		{
pred@2129
   103
			ReadQueryContent(con);
pred@2129
   104
			break;
pred@2129
   105
		}
pred@2129
   106
pred@2129
   107
		case ConnectionState_ReplyQuery:
pred@2129
   108
		{
pred@2129
   109
			ReplyQuery(con);
pred@2129
   110
			break;
pred@2129
   111
		}
pred@2129
   112
pred@2129
   113
		case ConnectionState_SendingFiles:
pred@2129
   114
		{
pred@2129
   115
			SendFile(con);
pred@2129
   116
			break;
pred@2129
   117
		}
pred@2129
   118
pred@2129
   119
		case ConnectionState_SendUnknownList:
pred@2129
   120
		{
pred@2129
   121
			SendUnknownList(con);
pred@2129
   122
			break;
pred@2129
   123
		}
pred@2129
   124
pred@2129
   125
		case ConnectionState_Complete:
pred@2129
   126
		{
pred@2129
   127
			break;
pred@2129
   128
		}
pred@2129
   129
	}
pred@2129
   130
pred@2129
   131
	if (con->state == ConnectionState_Complete)
pred@2129
   132
	{
pred@2129
   133
		printf("Ending connection because it marked itself as finished\n");
pred@2129
   134
		return QueryResult_Complete;
pred@2129
   135
	}
pred@2129
   136
pred@2129
   137
	if (con->start + m_timeOut < time(NULL))
pred@2129
   138
	{
pred@2129
   139
		printf("Ending connection because it has passed maximum allowed time\n");
pred@2129
   140
		return QueryResult_Complete;
pred@2129
   141
	}
pred@2129
   142
pred@2129
   143
	return QueryResult_Continue;
pred@2129
   144
}
pred@2129
   145
pred@2129
   146
void ConnectionPool::ReadQueryHeader( smud_connection *con )
pred@2129
   147
{
pred@2129
   148
	char data[11];
pred@2129
   149
pred@2129
   150
	if (recv(con->fd, data, sizeof(data), 0) == -1)
pred@2129
   151
	{
pred@2129
   152
		if (errno != EAGAIN && errno != EWOULDBLOCK)
pred@2129
   153
		{
pred@2129
   154
			con->state = ConnectionState_Complete;
pred@2129
   155
		}
pred@2129
   156
pred@2129
   157
		return;
pred@2129
   158
	}
pred@2129
   159
pred@2129
   160
	if (data[0] != 'A' || data[1] != 'G')
pred@2129
   161
	{
pred@2129
   162
		con->state = ConnectionState_Complete;
pred@2129
   163
		return;
pred@2129
   164
	}
pred@2129
   165
pred@2129
   166
	//Ignore the next 8 bytes for the moment. Versioning data is currently unused
pred@2129
   167
	// uint16[4] - source version major/minor/something/rev
pred@2129
   168
pred@2129
   169
	con->sentSums = data[10];
pred@2129
   170
pred@2129
   171
	con->state = ConnectionState_ReadQueryData;
pred@2129
   172
	printf("Query Header Read Complete, %i md5's expected\n", con->sentSums);
pred@2129
   173
}
pred@2129
   174
pred@2129
   175
void ConnectionPool::ReplyQuery(smud_connection *con)
pred@2129
   176
{
pred@2129
   177
	char data[12];
pred@2129
   178
	data[0] = 'A';
pred@2129
   179
	data[1] = 'G';
pred@2129
   180
pred@2129
   181
	data[2] = (char)Update_Unknown; //unused versioning crap
pred@2129
   182
	*(short *)&data[3] = 1;
pred@2129
   183
	*(short *)&data[5] = 0;
pred@2129
   184
	*(short *)&data[7] = 0;
pred@2129
   185
	*(short *)&data[9] = 3;
pred@2129
   186
pred@2129
   187
	data[11] = (char)con->sendCount;
pred@2129
   188
pred@2129
   189
	if (send(con->fd, data, sizeof(data), 0) == -1)
pred@2129
   190
	{
pred@2129
   191
		if (errno != EAGAIN && errno != EWOULDBLOCK)
pred@2129
   192
		{
pred@2129
   193
			con->state = ConnectionState_Complete;
pred@2129
   194
		}
pred@2129
   195
pred@2129
   196
		return;
pred@2129
   197
	}
pred@2129
   198
	
pred@2129
   199
	//Now we need more send sub functions for all the damn files. Geh.
pred@2129
   200
	//Alternatively we could just send all at once here. Could make for a damn big query. 100k anyone?
pred@2129
   201
pred@2129
   202
	con->state = ConnectionState_SendingFiles;
pred@2129
   203
	printf("Query Reply Header Complete\n");
pred@2129
   204
}
pred@2129
   205
pred@2129
   206
void ConnectionPool::ReadQueryContent( smud_connection *con )
pred@2129
   207
{
pred@2129
   208
	char *data = new char[16*(con->sentSums)]();
pred@2129
   209
pred@2129
   210
	if (recv(con->fd, data, 16*(con->sentSums), 0) == -1)
pred@2129
   211
	{
pred@2129
   212
		if (errno != EAGAIN && errno != EWOULDBLOCK)
pred@2129
   213
		{
pred@2129
   214
			con->state = ConnectionState_Complete;
pred@2129
   215
		}
pred@2129
   216
pred@2129
   217
		delete [] data;
pred@2129
   218
		return;
pred@2129
   219
	}
pred@2129
   220
pred@2129
   221
	con->shouldSend = new MD5Status[con->sentSums]();
pred@2129
   222
	con->fileLocation = new int[con->sentSums]();
pred@2129
   223
	con->headerSent = new bool[con->sentSums]();
pred@2129
   224
pred@2129
   225
	for (int i=0; i<con->sentSums; i++)
pred@2129
   226
	{
pred@2129
   227
		con->fileLocation[i] = -1;
pred@2129
   228
		con->shouldSend[i] = GetMD5UpdateStatus(data + (16*i), con, i);
pred@2129
   229
		
pred@2129
   230
		if (con->shouldSend[i] == MD5Status_NeedsUpdate)
pred@2129
   231
		{
pred@2129
   232
			printf("File %i needs updating\n", i);
pred@2129
   233
			con->sendCount++;
pred@2129
   234
			con->headerSent[i] = false;
pred@2129
   235
			continue;
pred@2129
   236
		}
pred@2129
   237
pred@2129
   238
		if (con->shouldSend[i] == MD5Status_Unknown)
pred@2129
   239
		{
pred@2129
   240
			printf("File %i is unknown\n", i);
pred@2129
   241
			con->unknownCount++;
pred@2129
   242
		}
pred@2129
   243
	}
pred@2129
   244
pred@2129
   245
	con->state = ConnectionState_ReplyQuery;
pred@2129
   246
	con->pollData.events = POLLOUT;
pred@2129
   247
	delete [] data;
pred@2129
   248
	printf("Query Data Read Complete\n");
pred@2129
   249
}
pred@2129
   250
pred@2129
   251
MD5Status ConnectionPool::GetMD5UpdateStatus( const char *md5 , smud_connection *con, int fileNum)
pred@2129
   252
{
pred@2129
   253
	//Try find a file with this name in some directory.
pred@2129
   254
	char path[100] = "./md5/";
pred@2129
   255
	char temp[4];
pred@2129
   256
	char md5String[33] = "";
pred@2129
   257
pred@2129
   258
	for (int i=0; i<16; i++)
pred@2129
   259
	{
pred@2129
   260
		snprintf(temp, sizeof(temp), "%02x", (unsigned char)md5[i]);
pred@2129
   261
		strcat(md5String, temp);
pred@2129
   262
	}
pred@2129
   263
pred@2129
   264
	strcat(path, md5String);
pred@2129
   265
pred@2129
   266
	printf("checking for file \"%s\"\n", path);
pred@2129
   267
	
pred@2129
   268
	FILE *file = fopen(path, "r");
pred@2129
   269
pred@2129
   270
	if (file == NULL)
pred@2129
   271
	{
pred@2129
   272
		printf("Couldn't find file!\n");
pred@2129
   273
		return MD5Status_Unknown;
pred@2129
   274
	}
pred@2129
   275
pred@2129
   276
	char latestMD5[33];
pred@2129
   277
	fgets(latestMD5, 33, file);
pred@2129
   278
	printf("Latest md5 is: %s\n", latestMD5);
pred@2129
   279
pred@2129
   280
	if (strcmp(latestMD5, md5String) == 0)
pred@2129
   281
	{
pred@2129
   282
		return MD5Status_Current;
pred@2129
   283
	}
pred@2129
   284
pred@2129
   285
	char filename[100];
pred@2140
   286
	filename[0] = '\n';
pred@2140
   287
pred@2140
   288
	while (filename[0] == '\n')
pred@2129
   289
	{
pred@2140
   290
		fgets(filename, sizeof(filename), file);
pred@2140
   291
		if (filename[strlen(filename)-1] == '\n')
pred@2140
   292
		{
pred@2140
   293
			filename[strlen(filename)-1] = '\0';
pred@2140
   294
		}
pred@2129
   295
	}
pred@2129
   296
pred@2140
   297
pred@2129
   298
	printf("Filename is %s\n", filename);
pred@2129
   299
pred@2129
   300
	//We now need to match this filename with one of our mmap'd files in memory and store it until send gets called.
pred@2129
   301
	for (int i=0; i<NUM_FILES; i++)
pred@2129
   302
	{
pred@2129
   303
		if (strcmp(fileNames[i], filename) == 0)
pred@2129
   304
		{
pred@2129
   305
			con->fileLocation[fileNum] = i;
pred@2129
   306
			printf("File %i mapped to local file %i\n", fileNum, i);
pred@2129
   307
			return MD5Status_NeedsUpdate;
pred@2129
   308
		}
pred@2129
   309
	}
pred@2129
   310
pred@2129
   311
	return MD5Status_Unknown;
pred@2129
   312
}
pred@2129
   313
pred@2129
   314
void ConnectionPool::SendFile( smud_connection *con )
pred@2129
   315
{
pred@2129
   316
	//Find the next file to send.
pred@2129
   317
	while (con->currentFile < con->sentSums &&
pred@2129
   318
			con->shouldSend[con->currentFile] != MD5Status_NeedsUpdate)
pred@2129
   319
	{
pred@2129
   320
		con->currentFile++;
pred@2129
   321
	}
pred@2129
   322
pred@2129
   323
	//All files have been sent.
pred@2129
   324
	if (con->currentFile >= con->sentSums)
pred@2129
   325
	{
pred@2129
   326
		printf("All files sent!\n");
pred@2129
   327
		con->state = ConnectionState_SendUnknownList;
pred@2129
   328
		return;
pred@2129
   329
	}
pred@2129
   330
pred@2129
   331
	void *file = fileLocations[con->fileLocation[con->currentFile]];
pred@2129
   332
	int filelength = fileLength[con->fileLocation[con->currentFile]];
pred@2129
   333
pred@2129
   334
	printf("Sending file of length %i\n", filelength);
pred@2129
   335
	printf("Current file index is: %i, maps to file index: %i\n", con->currentFile, con->fileLocation[con->currentFile]);
pred@2129
   336
pred@2129
   337
	if (!con->headerSent[con->currentFile])
pred@2129
   338
	{
pred@2129
   339
		char buffer[5];
pred@2129
   340
		buffer[0] = con->currentFile;
pred@2129
   341
		*((int *)&buffer[1]) = filelength;
pred@2129
   342
pred@2129
   343
		if (send(con->fd, buffer, 5, 0) == -1)
pred@2129
   344
		{
pred@2129
   345
			if (errno != EAGAIN && errno != EWOULDBLOCK)
pred@2129
   346
			{
pred@2129
   347
				con->state = ConnectionState_Complete;
pred@2129
   348
			}
pred@2129
   349
pred@2129
   350
			return;
pred@2129
   351
		}
pred@2129
   352
pred@2129
   353
		con->headerSent[con->currentFile] = true;
pred@2129
   354
	}
pred@2129
   355
pred@2129
   356
	if (send(con->fd, file, filelength, 0) == -1)
pred@2129
   357
	{
pred@2129
   358
		if (errno != EAGAIN && errno != EWOULDBLOCK)
pred@2129
   359
		{
pred@2129
   360
			con->state = ConnectionState_Complete;
pred@2129
   361
		}
pred@2129
   362
pred@2129
   363
		return;
pred@2129
   364
	}
pred@2129
   365
pred@2129
   366
	con->currentFile++;
pred@2129
   367
	printf("Sent a file!: %s\n", fileNames[con->fileLocation[con->currentFile-1]]);
pred@2129
   368
}
pred@2129
   369
pred@2129
   370
void ConnectionPool::SendUnknownList( smud_connection *con )
pred@2129
   371
{
pred@2129
   372
	int size = con->unknownCount+1;
pred@2129
   373
	char *packet = new char[size]();
pred@2129
   374
pred@2129
   375
	packet[0] = con->unknownCount;
pred@2129
   376
pred@2129
   377
	printf("%i Files are unknown\n", con->unknownCount);
pred@2129
   378
pred@2129
   379
	int i=1;
pred@2129
   380
pred@2129
   381
	for (int j=0; j<con->sentSums; j++)
pred@2129
   382
	{
pred@2129
   383
		if (con->shouldSend[j] == MD5Status_Unknown)
pred@2129
   384
		{
pred@2129
   385
			packet[i] = j;
pred@2129
   386
			i++;
pred@2129
   387
		}
pred@2129
   388
	}
pred@2129
   389
pred@2129
   390
	if (send(con->fd, packet, size, 0) == -1)
pred@2129
   391
	{
pred@2129
   392
		if (errno != EAGAIN && errno != EWOULDBLOCK)
pred@2129
   393
		{
pred@2129
   394
			con->state = ConnectionState_Complete;
pred@2129
   395
		}
pred@2129
   396
pred@2129
   397
		return;
pred@2129
   398
	}
pred@2129
   399
pred@2129
   400
	con->state = ConnectionState_Complete;
pred@2129
   401
	printf("Unknown's Sent\n");
pred@2129
   402
}