1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/tools/daemon/smud_connections.cpp Sun Jul 06 04:49:55 2008 +0000
1.3 @@ -0,0 +1,404 @@
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 + filename[0] = '\n';
1.290 +
1.291 + while (filename[0] == '\n')
1.292 + {
1.293 + fgets(filename, sizeof(filename), file);
1.294 + }
1.295 +
1.296 + if (filename[strlen(filename)-1] == '\n')
1.297 + {
1.298 + filename[strlen(filename)-1] = '\0';
1.299 + }
1.300 +
1.301 +
1.302 +
1.303 + printf("Filename is %s\n", filename);
1.304 +
1.305 + //We now need to match this filename with one of our mmap'd files in memory and store it until send gets called.
1.306 + for (int i=0; i<NUM_FILES; i++)
1.307 + {
1.308 + if (strcmp(fileNames[i], filename) == 0)
1.309 + {
1.310 + con->fileLocation[fileNum] = i;
1.311 + printf("File %i mapped to local file %i\n", fileNum, i);
1.312 + return MD5Status_NeedsUpdate;
1.313 + }
1.314 + }
1.315 +
1.316 + return MD5Status_Unknown;
1.317 +}
1.318 +
1.319 +void ConnectionPool::SendFile( smud_connection *con )
1.320 +{
1.321 + //Find the next file to send.
1.322 + while (con->currentFile < con->sentSums &&
1.323 + con->shouldSend[con->currentFile] != MD5Status_NeedsUpdate)
1.324 + {
1.325 + con->currentFile++;
1.326 + }
1.327 +
1.328 + //All files have been sent.
1.329 + if (con->currentFile >= con->sentSums)
1.330 + {
1.331 + printf("All files sent!\n");
1.332 + con->state = ConnectionState_SendUnknownList;
1.333 + return;
1.334 + }
1.335 +
1.336 + void *file = fileLocations[con->fileLocation[con->currentFile]];
1.337 + int filelength = fileLength[con->fileLocation[con->currentFile]];
1.338 +
1.339 + printf("Sending file of length %i\n", filelength);
1.340 + printf("Current file index is: %i, maps to file index: %i\n", con->currentFile, con->fileLocation[con->currentFile]);
1.341 +
1.342 + if (!con->headerSent[con->currentFile])
1.343 + {
1.344 + char buffer[5];
1.345 + buffer[0] = con->currentFile;
1.346 + *((int *)&buffer[1]) = filelength;
1.347 +
1.348 + if (send(con->fd, buffer, 5, 0) == -1)
1.349 + {
1.350 + if (errno != EAGAIN && errno != EWOULDBLOCK)
1.351 + {
1.352 + con->state = ConnectionState_Complete;
1.353 + }
1.354 +
1.355 + return;
1.356 + }
1.357 +
1.358 + con->headerSent[con->currentFile] = true;
1.359 + }
1.360 +
1.361 + if (send(con->fd, file, filelength, 0) == -1)
1.362 + {
1.363 + if (errno != EAGAIN && errno != EWOULDBLOCK)
1.364 + {
1.365 + con->state = ConnectionState_Complete;
1.366 + }
1.367 +
1.368 + return;
1.369 + }
1.370 +
1.371 + con->currentFile++;
1.372 + printf("Sent a file!: %s\n", fileNames[con->fileLocation[con->currentFile-1]]);
1.373 +}
1.374 +
1.375 +void ConnectionPool::SendUnknownList( smud_connection *con )
1.376 +{
1.377 + int size = con->unknownCount+1;
1.378 + char *packet = new char[size]();
1.379 +
1.380 + packet[0] = con->unknownCount;
1.381 +
1.382 + printf("%i Files are unknown\n", con->unknownCount);
1.383 +
1.384 + int i=1;
1.385 +
1.386 + for (int j=0; j<con->sentSums; j++)
1.387 + {
1.388 + if (con->shouldSend[j] == MD5Status_Unknown)
1.389 + {
1.390 + packet[i] = j;
1.391 + i++;
1.392 + }
1.393 + }
1.394 +
1.395 + if (send(con->fd, packet, size, 0) == -1)
1.396 + {
1.397 + if (errno != EAGAIN && errno != EWOULDBLOCK)
1.398 + {
1.399 + con->state = ConnectionState_Complete;
1.400 + }
1.401 +
1.402 + return;
1.403 + }
1.404 +
1.405 + con->state = ConnectionState_Complete;
1.406 + printf("Unknown's Sent\n");
1.407 +}