2 #include "smud_connections.h"
5 ConnectionPool::ConnectionPool()
7 pthread_mutex_init(&m_AddLock, NULL);
11 ConnectionPool::~ConnectionPool()
13 pthread_mutex_destroy(&m_AddLock);
16 void ConnectionPool::AddConnection( int fd )
18 smud_connection *connection = new smud_connection(fd);
20 pthread_mutex_lock(&m_AddLock);
21 m_AddQueue.push_back(connection);
22 pthread_mutex_unlock(&m_AddLock);
25 void ConnectionPool::Process( bool *terminate )
27 struct timespec ts_wait;
30 ts_wait.tv_nsec = 50000000; /* 50ms */
32 std::list<smud_connection *>::iterator iter;
33 smud_connection *con = NULL;
42 iter = m_Links.begin();
44 QueryResult result = QueryResult_Continue;
47 /* Add all connections that want processing to the sets */
48 while (iter != m_Links.end())
52 pollReturn = poll(&(con->pollData), 1, 0);
53 assert(pollReturn <= 1);
57 //Something went badly wrong or the connection closed.
58 result = QueryResult_Complete;
60 else if (pollReturn == 1)
62 //Poll returns the number of sockets available (which can only ever be 1)
63 result = ProcessConnection(con);
66 if (result == QueryResult_Complete)
68 iter = m_Links.erase(iter);
70 fprintf(stdout, "Closing socket %d\n", con->fd);
80 /* Add new items to process */
83 pthread_mutex_lock(&m_AddLock);
84 m_Links.splice(iter, m_AddQueue);
85 pthread_mutex_unlock(&m_AddLock);
87 nanosleep(&ts_wait, NULL);
91 QueryResult ConnectionPool::ProcessConnection( smud_connection *con )
95 case ConnectionState_ReadQueryHeader:
101 case ConnectionState_ReadQueryData:
103 ReadQueryContent(con);
107 case ConnectionState_ReplyQuery:
113 case ConnectionState_SendingFiles:
119 case ConnectionState_SendUnknownList:
121 SendUnknownList(con);
125 case ConnectionState_Complete:
131 if (con->state == ConnectionState_Complete)
133 printf("Ending connection because it marked itself as finished\n");
134 return QueryResult_Complete;
137 if (con->start + m_timeOut < time(NULL))
139 printf("Ending connection because it has passed maximum allowed time\n");
140 return QueryResult_Complete;
143 return QueryResult_Continue;
146 void ConnectionPool::ReadQueryHeader( smud_connection *con )
148 if (con->buffer == NULL)
150 con->buffer = new char[QUERY_HEADER_SIZE];
151 con->writtenCount = 0;
154 int bytesReceived = 0;
156 bytesReceived = recv(con->fd, con->buffer+con->writtenCount, QUERY_HEADER_SIZE-con->writtenCount, 0);
158 if (bytesReceived == -1)
160 if (errno != EAGAIN && errno != EWOULDBLOCK)
162 con->state = ConnectionState_Complete;
163 delete [] con->buffer;
165 con->writtenCount = 0;
171 con->writtenCount += bytesReceived;
173 assert(con->writtenCount <= QUERY_HEADER_SIZE);
175 if (con->writtenCount < QUERY_HEADER_SIZE)
177 /* Don't change the connection status, so next cycle we will come back to here and continue receiving data */
181 if (con->buffer[0] != 'A' || con->buffer[1] != 'G')
183 con->state = ConnectionState_Complete;
184 delete [] con->buffer;
186 con->writtenCount = 0;
190 //Ignore the next 8 bytes for the moment. Versioning data is currently unused
191 // uint16[4] - source version major/minor/something/rev
193 con->sentSums = con->buffer[10];
195 con->state = ConnectionState_ReadQueryData;
197 fprintf(stdout, "Query Header Read Complete, %i md5's expected\n", con->sentSums);
200 delete [] con->buffer;
202 con->writtenCount = 0;
205 void ConnectionPool::ReplyQuery(smud_connection *con)
211 data[2] = (char)Update_Unknown; //unused versioning crap
212 *(short *)&data[3] = 1;
213 *(short *)&data[5] = 0;
214 *(short *)&data[7] = 0;
215 *(short *)&data[9] = 3;
217 data[11] = (char)con->sendCount;
219 int bytesSent = send(con->fd, data+con->writtenCount, sizeof(data)-con->writtenCount, 0);
223 if (errno != EAGAIN && errno != EWOULDBLOCK)
225 con->state = ConnectionState_Complete;
226 con->writtenCount = 0;
232 con->writtenCount += bytesSent;
234 assert(con->writtenCount <= 12);
236 if (con->writtenCount < 12)
238 /** Still more data needs to be sent - Return so we come back here next cycle */
242 con->state = ConnectionState_SendingFiles;
243 con->writtenCount = 0;
245 printf("Query Reply Header Complete\n");
249 void ConnectionPool::ReadQueryContent( smud_connection *con )
251 if (con->buffer == NULL)
253 con->buffer = new char[QUERY_CONTENT_SIZE*con->sentSums];
254 con->writtenCount = 0;
257 int bytesReceived = 0;
259 bytesReceived = recv(con->fd, con->buffer+con->writtenCount, (QUERY_CONTENT_SIZE*con->sentSums)-con->writtenCount, 0);
261 if (bytesReceived == -1)
263 if (errno != EAGAIN && errno != EWOULDBLOCK)
265 con->state = ConnectionState_Complete;
266 delete [] con->buffer;
268 con->writtenCount = 0;
274 con->writtenCount += bytesReceived;
276 assert(con->writtenCount <= (QUERY_CONTENT_SIZE*con->sentSums));
278 if (con->writtenCount < (QUERY_CONTENT_SIZE*con->sentSums))
280 /* Don't change the connection status, so next cycle we will come back to here and continue receiving data */
284 con->shouldSend = new MD5Status[con->sentSums]();
285 con->fileLocation = new int[con->sentSums]();
286 con->headerSent = new bool[con->sentSums]();
288 for (int i=0; i<con->sentSums; i++)
290 con->fileLocation[i] = -1;
291 con->shouldSend[i] = GetMD5UpdateStatus(con->buffer + (QUERY_CONTENT_SIZE*i), con, i);
293 if (con->shouldSend[i] == MD5Status_NeedsUpdate)
296 fprintf(stdout, "File %i needs updating\n", i);
299 con->headerSent[i] = false;
303 if (con->shouldSend[i] == MD5Status_Unknown)
306 fprintf(stdout, "File %i is unknown\n", i);
312 con->state = ConnectionState_ReplyQuery;
313 con->pollData.events = POLLOUT;
314 delete [] con->buffer;
316 con->writtenCount = 0;
318 fprintf(stdout, "Query Data Read Complete\n");
322 MD5Status ConnectionPool::GetMD5UpdateStatus( const char *md5 , smud_connection *con, int fileNum)
324 //Try find a file with this name in some directory.
325 char path[100] = "./md5/";
327 char md5String[33] = "";
329 for (int i=0; i<16; i++)
331 snprintf(temp, sizeof(temp), "%02x", (unsigned char)md5[i]);
332 strcat(md5String, temp);
335 strcat(path, md5String);
338 fprintf(stdout, "checking for file \"%s\"\n", path);
341 FILE *file = fopen(path, "r");
345 printf("Couldn't find file!\n");
346 return MD5Status_Unknown;
350 fgets(latestMD5, 33, file);
352 fprintf(stdout, "Latest md5 is: %s\n", latestMD5);
355 if (strcmp(latestMD5, md5String) == 0)
358 return MD5Status_Current;
364 while (filename[0] == '\n')
366 fgets(filename, sizeof(filename), file);
369 if (filename[strlen(filename)-1] == '\n')
371 filename[strlen(filename)-1] = '\0';
377 fprintf(stdout, "Filename is %s\n", filename);
380 //We now need to match this filename with one of our mmap'd files in memory and store it until send gets called.
381 for (int i=0; i<NUM_FILES; i++)
383 if (strcmp(fileNames[i], filename) == 0)
385 con->fileLocation[fileNum] = i;
387 fprintf(stdout, "File %i mapped to local file %i\n", fileNum, i);
389 return MD5Status_NeedsUpdate;
393 return MD5Status_Unknown;
396 void ConnectionPool::SendFile( smud_connection *con )
398 //Find the next file to send.
399 while (con->writtenCount == 0 &&
400 con->currentFile < con->sentSums &&
401 con->shouldSend[con->currentFile] != MD5Status_NeedsUpdate)
406 //All files have been sent.
407 if (con->currentFile >= con->sentSums)
410 fprintf(stdout, "All files sent!\n");
412 con->state = ConnectionState_SendUnknownList;
413 con->writtenCount = 0;
417 void *file = fileLocations[con->fileLocation[con->currentFile]];
418 int filelength = fileLength[con->fileLocation[con->currentFile]];
421 fprintf(stdout, "Sending file of length %i\n", filelength);
423 "Current file index is: %i, maps to file index: %i\n",
425 con->fileLocation[con->currentFile]);
430 if (!con->headerSent[con->currentFile])
433 buffer[0] = con->currentFile;
434 *((int *)&buffer[1]) = filelength;
436 sentBytes = send(con->fd, buffer+con->writtenCount, 5-con->writtenCount, 0);
440 if (errno != EAGAIN && errno != EWOULDBLOCK)
442 con->state = ConnectionState_Complete;
443 con->writtenCount = 0;
449 con->writtenCount += sentBytes;
451 assert(con->writtenCount <= 5);
453 if (con->writtenCount < 5)
458 con->headerSent[con->currentFile] = true;
459 con->writtenCount = 0;
462 sentBytes = send(con->fd, (unsigned char *)file+con->writtenCount, filelength-con->writtenCount, 0);
466 if (errno != EAGAIN && errno != EWOULDBLOCK)
468 con->state = ConnectionState_Complete;
469 con->writtenCount = 0;
475 con->writtenCount += sentBytes;
477 assert(con->writtenCount <= filelength);
479 if (con->writtenCount < filelength)
485 con->writtenCount = 0;
487 fprintf(stdout, "Sent a file!: %s\n", fileNames[con->fileLocation[con->currentFile-1]]);
491 void ConnectionPool::SendUnknownList( smud_connection *con )
493 int size = con->unknownCount+1;
494 char *packet = new char[size]();
496 packet[0] = con->unknownCount;
499 fprintf(stdout, "%i Files are unknown\n", con->unknownCount);
504 for (int j=0; j<con->sentSums; j++)
506 if (con->shouldSend[j] == MD5Status_Unknown)
513 int sentBytes = send(con->fd, packet+con->writtenCount, size-con->writtenCount, 0);
517 if (errno != EAGAIN && errno != EWOULDBLOCK)
519 con->state = ConnectionState_Complete;
520 con->writtenCount = 0;
526 con->writtenCount += sentBytes;
528 assert(con->writtenCount <= size);
530 if (con->writtenCount < size)
535 con->state = ConnectionState_Complete;
536 con->writtenCount = 0;
538 fprintf(stdout, "Unknowns Sent\n");