EmuProxyZA / emuProxyZA.c

From TivoZA

Back to emuProxyZA.
Download source (You will need to rename it to: emuProxyZA.c)

To update the below source file, select Upload file and upload your new emuProxyZA.c file (there is no need to upload it as a .txt). If you do upload a new version, please add a brief description to the change log at the bottom of this page indicating what changes you made and why.

Source

  1. /*
  2. emuProxyZA is based on emuProxy2 (by Tim Kleingeld) and the tivodns
  3. library (by Christopher R. Wingert). The reason for the name change is
  4. I have made significant changes to emuProxy2. emuProxy2 (and emuProxy3)
  5. does not correctly send through the requests as it relies on their being
  6. a Content-length field which is only present in the mlog.cgi request,
  7. this has now been fixed as well as a couple of major features added as
  8. listed below.
  9. Features:
  10. * Use DNS addresses as well as static IP addresses
  11. * Allows limiting the number of guide days to download, nice for those
  12. on dial-up (only possible if your provider/emulator supports it). The
  13. TivoZA emulator supplies 30 days of guide data by default which even
  14. gzipped can be 2MB for the full download.
  15. * Fix mlog.cgi request, mlog.cgi requests previously failed when the
  16. svclog was too large (this also prevented guide downloads being available
  17. for long periods, such as a month)
  18. * Fix Series 1 LocationID problem (i.e. how to use shorter LocationID's)
  19. * Accessing the server/emulator through transparent proxies (part of emuProxy2)
  20. * HTTP header fix (added in emuProxy3 by Warren Toomey)
  21. * Allow full traces of the requests sent and the responses received, great
  22. for debugging
  23. This program is distributed in the hope that it will be useful,
  24. but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  26. For the latest version and more information please see:
  27. http://tivoza.nanfo.com
  28. Enjoy, regards
  29. TivoZA
  30. */
  31.  
  32. #include <stdio.h>
  33. #include <time.h>
  34. #include <sys/types.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <sys/signal.h>
  38. #include <sys/errno.h>
  39. #include <string.h>
  40. #include "tivodns.h"
  41. #include "base64.c"
  42. #include <fcntl.h>
  43.  
  44. #ifdef TIVO
  45. # include "bootpage.c"
  46. # include "mfs-utils/mfs.h"
  47. #endif
  48.  
  49.  
  50. #define VERSION "4.1.40"
  51.  
  52. #define BUFFER_SIZE 1024
  53. #define RESOLVCONF_FILE "/etc/resolv.conf"
  54. #define PORT 8000
  55. #define SERVERIP "204.176.49.2"
  56. #define SERVERPORT 80
  57. #define NTPIP "132.163.4.102" //"204.176.49.2"
  58. #define NTPPORT 37
  59. #define LISTENTO "0.0.0.0" // Useful for testing
  60. //#define LISTENTO "127.0.0.1" // Potentially more secure
  61. #define DEBUGPATH "/tmp/"
  62. #define CONFIG_FILE "/hack/etc/emuProxyZA.conf"
  63.  
  64. static char * argv_init[8+2];// = { NULL, };
  65. static char * envp_init[8+2];// = { NULL, };
  66.  
  67. char *emuconf = CONFIG_FILE;
  68. char *resolvconf = RESOLVCONF_FILE;
  69. int localport = PORT;
  70. char *serverip = SERVERIP;
  71. int serverport = SERVERPORT;
  72. char *ntpip;
  73. char *listento = LISTENTO;
  74. char *proxyip;
  75. char *proxyport;
  76. char *proxyAuth = NULL;
  77. char myHeaders[BUFFER_SIZE];
  78. char outBuffer[BUFFER_SIZE] = "";
  79. char debugClientPath[100] = DEBUGPATH;
  80. char debugServerPath[100] = DEBUGPATH;
  81. int debugClient;
  82. int debugServer;
  83. int debug;
  84. int outBufferLength = 0;
  85. int inited = 0;
  86. int gotAlarm;
  87. int count = 0;
  88. int rawSend = 0;
  89. int onScreenDisplay = 0;
  90. int tcInfo = 0;
  91. int timeOffset = 0;
  92. int forceUpdate = 2;
  93. int guideDays = 0;
  94. char *weekDays = "";
  95. int urlbase = 0;
  96. char locationID[50] = "";
  97. time_t timeWeekdayOverride = 0;
  98. int bGuidedSetup = -1;
  99. int altNTP = 0;
  100.  
  101. //Having flags to check if the following has been completed will save string comparison time
  102. int fixMlog;
  103. int fixHServer;
  104. int bodylength;
  105. int post;
  106. int addedHeaders;
  107. int headerComplete;
  108. int contentStarted;
  109. int totalRead;
  110.  
  111. /****************************************************************************************/
  112. void alarmHandler() {
  113. gotAlarm = 1;
  114. }
  115.  
  116. /****************************************************************************************/
  117. char *ltrim(char *buffer)
  118. {
  119. char *cp = buffer;
  120.  
  121. if (cp && *cp)
  122. {
  123. // find first non-whitespace character
  124. //while (_istspace(*cp))
  125. while (cp[0] == ' ')
  126. cp++;
  127.  
  128. if (cp != buffer)
  129. memcpy(buffer, cp, (strlen(cp)+1)*sizeof(char));
  130. }
  131.  
  132. return buffer;
  133. }
  134.  
  135. /****************************************************************************************/
  136. char *rtrim(char *buffer)
  137. {
  138. char *cp = buffer;
  139.  
  140. if (cp && *cp)
  141. {
  142. int bNonSpaceSeen = 0;
  143.  
  144. // check if string is blank
  145. while (*cp)
  146. {
  147. if (!(cp[0] == ' '))
  148. bNonSpaceSeen = 1;
  149. cp++;
  150. }
  151.  
  152. if (bNonSpaceSeen)
  153. {
  154. cp--;
  155.  
  156. // find last non-whitespace character
  157. while ( (cp >= buffer) && (cp[0] == ' ') )
  158. *cp-- = 0; //_T('\0');
  159. }
  160. else
  161. {
  162. // string contains only whitespace characters
  163. *buffer = 0; //_T('\0');
  164. }
  165. }
  166.  
  167. return buffer;
  168. }
  169.  
  170. /****************************************************************************************/
  171. char *trim(char *buffer)
  172. {
  173. return ltrim(rtrim(buffer));
  174. }
  175.  
  176. /****************************************************************************************/
  177. char *substr(const char* buffer, int count) {
  178. char *outS = strdup(buffer);
  179. outS[count] = 0;
  180. return outS;
  181. }
  182.  
  183. /****************************************************************************************/
  184. int chrpos(const char* buffer, const char find) {
  185. char *pos = strchr(buffer, find);
  186. if (pos == NULL)
  187. return -1;
  188. else
  189. return pos - buffer;
  190. }
  191.  
  192. /****************************************************************************************/
  193. int strpos(const char* buffer, const char* find) {
  194. char *pos = strstr(buffer, find);
  195. if (pos == NULL)
  196. return -1;
  197. else
  198. return pos - buffer;
  199. }
  200.  
  201. /****************************************************************************************/
  202. unsigned long getIPAddress(const char* serverAddr) {
  203. struct in4_addr *ipAddr;
  204. int fd;
  205. int b;
  206.  
  207. /* Convert a DNS address to an IP address */
  208. if ( sscanf( serverAddr , "%d.%d.%d.%d", &b, &b, &b, &b ) != 4 ) {
  209. if (debug == 2) fprintf(stderr, "DNS address detected (%s), attempting to resolve to an IP address\n", serverAddr);
  210.  
  211. /* Load resolv.conf to enable DNS lookups*/
  212. if (inited == 0) {
  213. fd = open( resolvconf, O_RDONLY );
  214. if ( fd < 0 ) {
  215. perror( "Failed to open resolv.conf" );
  216. return INADDR_NONE;
  217. }
  218. close(fd);
  219. tivodns_init(resolvconf);
  220. inited = 1;
  221. }
  222.  
  223. /* Convert the DNS address to an IP address */
  224. ipAddr = tivodns_resolveip4(serverAddr);
  225. if (!ipAddr) {
  226. perror("Failed to find server IP for given DNS!\n");
  227. return INADDR_NONE;
  228. }
  229. serverAddr = tivodns_ntoa4(ipAddr);
  230. } else if (debug == 2) fprintf(stderr, "IP address detected (%s), no DNS resolution required\n", serverAddr);
  231.  
  232. return inet_addr(serverAddr); /* Fill in the server address */
  233. }
  234.  
  235. /****************************************************************************************/
  236. void outSocket(int socket, char buffer[BUFFER_SIZE], int length, FILE *ofile) {
  237. //A similar function should be created for client out as this function relies on the specific
  238. //debugServer, outBufferLength & outBuffer variables
  239. if ((outBufferLength > 0) && ((length == -1) || (outBufferLength + length > BUFFER_SIZE)) ) {
  240. write(socket, outBuffer, outBufferLength);
  241. if (ofile)
  242. fwrite(outBuffer, outBufferLength, 1, ofile);
  243.  
  244. outBufferLength = 0;
  245. }
  246.  
  247. if (length > 0) {
  248. memcpy(outBuffer + outBufferLength, buffer, length);
  249. outBufferLength += length;
  250. }
  251.  
  252. /*if (length != -1) {
  253. write(socket, buffer, length);
  254. if (debugServer)
  255. fwrite(buffer, length, 1, ofile);
  256. } */
  257. }
  258.  
  259. /****************************************************************************************/
  260. void fixLocationID(int server, char buffer[BUFFER_SIZE], int length, FILE *ofile) {
  261. char newLocationID[100] = "IDB_LOCATIONID: ";
  262. char locID[50] = "";
  263. char *pos;
  264. char *posEnd;
  265. int onlySatellite = 0;
  266.  
  267. #ifdef TIVO
  268. //Load the current value stored in the MFS and replace it if necessary
  269. strcpy(locID, mfs_attr_get_str("/State/LocationConfig", "PostalCode"));
  270. if ( (strcmp(locationID, "0")) && (strcmp(locationID, locID)) ) {
  271. if (debug == 2) fprintf(stderr, "Update PostalCode to: %s\n", locationID);
  272. mfs_attr_set("/State/LocationConfig", "PostalCode", locationID);
  273. }
  274. #endif
  275.  
  276. pos = strchr(buffer, ':') + 2;
  277. onlySatellite = !strncmp(pos, "DBS", 3);
  278. if (!strcmp(locationID, "0")) { //Only determine the locationID if a fixed one was not specified
  279. if (onlySatellite) {
  280. fprintf(stderr,"EmuProxyZA Error: When only receiving satellite data you need to supply a LocationID, run emuProxyZA -h for more help!\n");
  281. exit(1);
  282. }
  283. strncpy(locID, pos, strchr(buffer, '-') - pos);
  284. } else
  285. strcpy(locID, locationID);
  286.  
  287. if (debug == 2) fprintf(stderr, "LocationID: %s\n", locID);
  288.  
  289. posEnd = strchr(pos, '~');
  290. if (onlySatellite) {
  291. //Handle just Satellite postal codes
  292. if (posEnd != NULL) {
  293. strncat(newLocationID, pos, posEnd - pos + 1);
  294. strncat(newLocationID, locID, 3);
  295. pos = strchr(pos, '-');
  296. }
  297. } else {
  298. //Handle Cable & Satellite postal codes
  299. strncat(newLocationID, locID, 4);
  300.  
  301. pos = strchr(pos, '-');
  302. if (posEnd != NULL) {
  303. //Handle Satellite part of request
  304. strncat(newLocationID, pos, posEnd - pos + 1);
  305. strncat(newLocationID, locID, 3);
  306. pos = strchr(pos + 1, '-');
  307. }
  308. }
  309.  
  310. posEnd = strchr(pos, '\n');
  311. strncat(newLocationID, pos, posEnd - pos);
  312. strcat(newLocationID, "\n");
  313.  
  314. outSocket(server, newLocationID, strlen(newLocationID), ofile);
  315. if (debug == 2) fprintf(stderr, "Location ID changed to: %s", newLocationID);
  316. }
  317.  
  318. /****************************************************************************************/
  319. void fixTcInfo(int server, char buffer[BUFFER_SIZE], int length, FILE *ofile) {
  320. //Only the ip address and port numbers will be changed the rest will remain as is
  321.  
  322. char newTcInfo[100];
  323. char *pos;
  324. char *posEnd;
  325.  
  326. sprintf(newTcInfo, "%s:%d", serverip, serverport);
  327. pos = strchr(buffer, ':') + 1; //Find the end of the IDB_TCINFO field
  328.  
  329. pos = strchr(pos, ':') + 1; //Find the second colon just before the ip address is passed
  330. outSocket(server, buffer, pos - buffer, ofile);
  331.  
  332. outSocket(server, newTcInfo, strlen(newTcInfo), ofile);
  333.  
  334. pos = strchr(pos, ':'); //Find the colon between the ip adrress and port number
  335. pos = strchr(pos + 1, ':'); //Find the colon after port number
  336. posEnd = strchr(pos, '\n'); //Find the end of the line
  337.  
  338. //Output the remiander of the IDB_TCINFO field
  339. outSocket(server, pos, posEnd - pos + 1, ofile);
  340.  
  341. if (debug == 2) fprintf(stderr, "IDB_TCINFO has been corrected");
  342. }
  343.  
  344. /****************************************************************************************/
  345. char *extractFileName(const char* buffer) {
  346. char *fileName = NULL;
  347.  
  348. fileName = strchr(buffer, ' ') + 1;
  349. fileName = substr(fileName, strpos(fileName, " "));
  350. fileName = strrchr(fileName, '/') + 1;
  351.  
  352. if (debug == 2) fprintf(stderr, "\nFileName: %s\n", fileName);
  353.  
  354. return fileName;
  355. }
  356.  
  357. /****************************************************************************************/
  358. int GuidedSetup() {
  359. if (bGuidedSetup < 0) {
  360.  
  361. //Check if TiVo is in Guided Setup mode
  362. #ifdef TIVO
  363. char *bootpg = bootpage("/dev/hda");
  364. bGuidedSetup = (bootpg != NULL) && (strstr(bootpg, "GS=1") != NULL); //Check if in Maintenance Mode
  365.  
  366. if (!bGuidedSetup)
  367. bGuidedSetup = mfs_attr_get_int("/State/GeneralConfig", "Complete") != 7; //Check if Guided Setup has been completed
  368. #endif
  369.  
  370. if (debug) fprintf(stderr, "Guided Setup: %d\n", bGuidedSetup);
  371. }
  372.  
  373. return bGuidedSetup;
  374. }
  375.  
  376. /****************************************************************************************/
  377. int GuideDataTo() {
  378. u32 fsid, count, i, ver, idx, sliceID;
  379. u32 maxVer = 0;
  380. char name[20];
  381. int arrOffset = time(NULL) / 86400 - 10; //Allows days in array to be populated from today - 10, no find required
  382. int days[100];
  383.  
  384. for(i=0; i < 100; i++)
  385. days[i] = 0;
  386.  
  387. fsid = mfs_fsid( "/Schedule" );
  388. if (fsid > 0) {
  389. struct mfs_dirent *dir = mfs_dir(fsid,&count);
  390. for(i=0; i < count; i++) {
  391. strcpy(name, strrchr(dir[i].name, ':') + 1);
  392. sliceID = atoi(name);
  393.  
  394. //Get date
  395. strcpy(name, strchr(dir[i].name, ':') + 1);
  396. strchr(name, ':')[0] = 0;
  397. idx = atoi(name) - arrOffset;
  398.  
  399. if (days[idx] != 1) {
  400. days[idx] = 1;
  401.  
  402. ver = query_int(sliceID, "ServerVersion");
  403. if (ver > maxVer)
  404. maxVer = ver;
  405.  
  406. //printf("%s: %d\n", name, ver);
  407. }
  408. }
  409. if (dir) mfs_dir_free(dir);
  410. }
  411.  
  412. return maxVer;
  413. }
  414.  
  415. /****************************************************************************************/
  416. void requestNTP(int server) {
  417. if (proxyip) {
  418. char strReq[100];
  419. FILE *ofile = NULL;
  420.  
  421. if (debug == 2) fprintf(stderr, "Performing NTP request via proxy.\n");
  422.  
  423. if (debugServer) {
  424. char filename[100];
  425. sprintf(filename, "%sep%dRequest.log", debugServerPath, count);
  426. ofile = fopen(filename, "w");
  427. }
  428.  
  429. sprintf(strReq, "GET http://%s:%d HTTP/1.0\r\n", ntpip, NTPPORT);
  430. outSocket(server, strReq, strlen(strReq), ofile);
  431.  
  432. if (proxyAuth) {
  433. char extraInfo[BUFFER_SIZE];
  434. sprintf(extraInfo, "Proxy-authorization: Basic %s\r\n", proxyAuth);
  435. outSocket(server, extraInfo, strlen(extraInfo), ofile);
  436. }
  437.  
  438. //Send end of request
  439. outSocket(server, "\r\n\r\n", 4, ofile);
  440.  
  441. outSocket(server, "", -1, ofile);
  442.  
  443.  
  444. if (debugServer)
  445. fclose(ofile);
  446. }
  447. }
  448.  
  449. /****************************************************************************************/
  450. void fixEpoch(int socket, char buffer[BUFFER_SIZE], int length, FILE *ofile) {
  451. int i;
  452. unsigned char val;
  453. unsigned long long int epoch = 0;
  454. unsigned long long int oldepoch = 0;
  455. char epochStr[10] = "";
  456. char currentStr[10];
  457.  
  458. if (debug == 2) fprintf(stderr, "\nNTP epoch time: %s\n", buffer);
  459.  
  460. for (i=0; i < length; i++) {
  461. val = buffer[i];
  462. epoch = epoch + val;
  463. if (i + 1 < length)
  464. epoch = epoch << 8;
  465. fprintf(stderr, "loop %d: %c = %d\n", i, val, val);
  466. }
  467.  
  468. epoch = epoch + (timeOffset * 60); //timeOffset need to be in minutes
  469.  
  470. while (epoch > 0) {
  471. oldepoch = epoch;
  472. epoch = epoch >> 8;
  473. val = oldepoch - (epoch << 8);
  474.  
  475. strcpy(currentStr, epochStr);
  476. sprintf(epochStr, "%c%s", val, currentStr);
  477. fprintf(stderr, "loop time: %c = %d, %s\n", val, val, epochStr);
  478. }
  479.  
  480. fprintf(stderr, "\nnew time: %s\n", epochStr);
  481.  
  482. outSocket(socket, epochStr, strlen(epochStr), ofile);
  483. }
  484.  
  485. /****************************************************************************************/
  486. void checkRequest(int socket, char buf[BUFFER_SIZE], int length, FILE *ofile) {
  487. char buffer[BUFFER_SIZE];
  488. char *http10; /* Pointer to occurrence of "HTTP/1.0 CR" */
  489.  
  490. strncpy(buffer, buf, length);
  491. buffer[length] = 0;
  492.  
  493. if ( (bodylength < 0) && strncasecmp(buffer, "Content-length:", 15) == 0) {
  494. if (!fixMlog) {
  495. bodylength = atoi(buffer+15);
  496. outSocket(socket, buffer, length, ofile);
  497. }
  498. } else if (fixMlog && headerComplete && !rawSend) {
  499. //No mlog content will be sent to the socket
  500. } else if (fixHServer && !rawSend && (strncasecmp(buffer, "IDB_SWDESC:", 11) == 0)) {
  501. if (debug == 2) fprintf(stderr, "Line removed: IDB_SWDESC\n");
  502. } else if (fixHServer && strcmp(locationID, "") && (strncasecmp(buffer, "IDB_LOCATIONID:", 15) == 0)) {
  503. fixLocationID(socket, buffer, length, ofile);
  504. } else if (fixHServer && forceUpdate && (strncasecmp(buffer, "IDB_ST_HIST:", 12) == 0)) {
  505. char strHist[BUFFER_SIZE] = "IDB_ST_HIST:\n";
  506. //Write the histry field
  507. #ifdef TIVO
  508. if ( (forceUpdate == 2) && (!GuidedSetup()) ) {
  509. if (debug == 2) fprintf(stderr, "Replacing IDB_ST_HIST with correct GuideDataTo\n");
  510. strncpy(strHist, buffer, strrchr(buffer, ':') - buffer + 1);
  511. sprintf(strHist, "%s%d-1\n", strHist, GuideDataTo() );
  512. } else
  513. #endif
  514. if (debug == 2) fprintf(stderr, "Removing known slices from IDB_ST_HIST\n");
  515. outSocket(socket, strHist, strlen(strHist), ofile);
  516. } else if (fixHServer && tcInfo && (strncasecmp(buffer, "IDB_TCINFO:", 11) == 0)) {
  517. fixTcInfo(socket, buffer, length, ofile);
  518. } else if (!addedHeaders && strstr(buffer, "HTTP/1") != NULL) {
  519.  
  520.  
  521. if (onScreenDisplay) osd_write( extractFileName(buffer) );
  522.  
  523. post = (!strncasecmp("POST", buffer, 4));
  524.  
  525. fixMlog = ((strstr(buffer, "mlog.cgi") != NULL) && !rawSend);
  526. fixHServer = (strstr(buffer, "HServer.cgi") != NULL);
  527.  
  528. /*None of this first condition should be here, the problem is the mlog.cgi has param gzip
  529. which causes it to fail. When using a proxy to proxy the line get duplicated due to the
  530. way in which each line is sent one by one, so this should be fixed!!!! Should probably
  531. buffer the data and only send it when the TiVo normally would send it, i.e. after the full
  532. read has completed???
  533. Add a param -S2 for series 2 mode, this would seperate each instruction by the & symbol rather
  534. than by a new line!*/
  535.  
  536. //Below test is needed for Series 2 units
  537. /*
  538. if (forceUpdate && fixMlog) {
  539. outSocket(socket, "POST /tivo-service/mlog.cgi HTTP/1.0\n", 37, ofile);
  540. fixMlog = 0;
  541. addedHeaders = 1;
  542. } else*/ if (rawSend == 2) {
  543. outSocket(socket, buffer, length, ofile);
  544. } else {
  545. //Write the corrected http request to the socket, Replace any "HTTP/1.0 CR" with " HTTP/1.0CR
  546. if ((http10 = strstr(buffer, "HTTP/1.0 \015")) != NULL)
  547. memcpy(http10, " HTTP/1.0\015", 10);
  548.  
  549. if (proxyip) {
  550. char *strReq;
  551. int idx = strchr(buffer, '/') - buffer;
  552. strncpy(strReq, buffer, idx);
  553. strReq[idx] = 0;
  554. sprintf(strReq, "%shttp://%s:%d%s", strReq, serverip, serverport, buffer + idx);
  555.  
  556. outSocket(socket, strReq, strlen(strReq), ofile);
  557.  
  558. if (proxyAuth) {
  559. char extraInfo[BUFFER_SIZE];
  560. sprintf(extraInfo, "Proxy-authorization: Basic %s\r\n", proxyAuth);
  561. outSocket(socket, extraInfo, strlen(extraInfo), ofile);
  562. }
  563. } else
  564. outSocket(socket, buffer, length, ofile);
  565.  
  566. //Add guide days, if set to the HServer.cgi request
  567. if (fixHServer && guideDays)
  568. sprintf(myHeaders, strcat(myHeaders, "GuideDays: %d\n"), guideDays);
  569.  
  570. // Append our headers after the HTTP/1.x line
  571. outSocket(socket, myHeaders, strlen(myHeaders), ofile);
  572.  
  573. if (fixHServer && !rawSend) {
  574. char extraInfo[BUFFER_SIZE];
  575. sprintf(extraInfo, "emuProxyZA: %s\n", VERSION);
  576. outSocket(socket, extraInfo, strlen(extraInfo), ofile);
  577. }
  578.  
  579. addedHeaders = 1;
  580. if (debug == 2) fprintf(stderr, "Send my headers\n");
  581. }
  582. } else {
  583. //Check if we are finished reading the header
  584. if (!headerComplete && (
  585. (buffer[0] == '\n') ||
  586. (buffer[0] == '\r') )) {
  587.  
  588. headerComplete = 1;
  589.  
  590. if (debug == 2) {
  591. fprintf(stderr, ", header complete: ");
  592. if (buffer[0] == '\r')
  593. fprintf(stderr, "Blank line found");
  594. else if (buffer[0] == '\n')
  595. fprintf(stderr, "Blank DOS line found");
  596. fprintf(stderr, "\n");
  597. }
  598.  
  599. contentStarted = 1;
  600.  
  601. //Add Content-length to the HServer.cgi request
  602. if (post && (bodylength < 0) )
  603. {
  604. bodylength = 0;
  605. outSocket(socket, "Content-length: 0\r\n\r\n", 21, ofile);
  606. } else
  607. outSocket(socket, buffer, length, ofile);
  608.  
  609. } else {
  610. //Write the buffer content to the socket
  611. outSocket(socket, buffer, length, ofile);
  612. }
  613. }
  614. }
  615.  
  616. /****************************************************************************************/
  617. void checkResponse(int socket, char buf[BUFFER_SIZE], int length, FILE *ofile) {
  618. char buffer[BUFFER_SIZE];
  619.  
  620. strncpy(buffer, buf, length);
  621. buffer[length] = 0;
  622.  
  623. if (fixHServer && altNTP && (strncasecmp(buffer, "TIME_SVC=", 9) == 0)) {
  624. char ntpInfo[BUFFER_SIZE];
  625.  
  626. //Get NTP server address
  627. if (!ntpip) {
  628. char strPad[100];
  629. char strNTP[100];
  630.  
  631. if ( sscanf( buffer , "%s -b %s ", &strPad, &strNTP) == 2)
  632. ntpip = strdup(strNTP);
  633. }
  634.  
  635. if (debug == 2) fprintf(stderr, "NTP server: %s", ntpip);
  636.  
  637. //If no ntpip is found, set it to the default
  638. if ((!ntpip) || (ntpip == ""))
  639. ntpip = NTPIP;
  640.  
  641. //Update sent NTP address
  642. sprintf(ntpInfo, "TIME_SVC=/bin/ntpdate -b %s\n", listento);
  643. outSocket(socket, ntpInfo, strlen(ntpInfo), ofile);
  644. } else {
  645. //Write the buffer content to the socket
  646. outSocket(socket, buffer, length, ofile);
  647. }
  648. }
  649.  
  650. /****************************************************************************************/
  651. int ProcessBuffer(int socket, char buffer[BUFFER_SIZE], int length, int readComplete, object_fn fnCheck, FILE *ofile) {
  652. int end = 0;
  653. int start = 0;
  654.  
  655. do {
  656. int newline = chrpos(buffer+start, '\n');
  657. if (newline < 0) {
  658. end = length - start;
  659. if (debug == 2) fprintf(stderr,"New line is NULL, Read: %d, Start: %d, End: %d\n", length, start, end);
  660.  
  661. if (readComplete || (end + 1 >= BUFFER_SIZE)) {
  662. fnCheck(socket, buffer+start, end, ofile);
  663. return 0;
  664. } else {
  665. memcpy(buffer, buffer+start, end);
  666. return end;
  667. }
  668. } else {
  669. end = newline + 1;
  670. if (debug == 2) fprintf(stderr,"Start: %d, End: %d", start, end);
  671.  
  672. fnCheck(socket, buffer+start, end, ofile);
  673. if (debug == 2) fprintf(stderr,", written\n");
  674. start += end;
  675. }
  676.  
  677. } while (start < length);
  678. return 0;
  679. }
  680.  
  681. /****************************************************************************************/
  682. void request(int server, int client) {
  683. char buffer[BUFFER_SIZE];
  684. int r = 0;
  685. int end = 0;
  686. int readComplete = 0;
  687. FILE *ofile = NULL;
  688. char filename[100];
  689.  
  690. if (debugServer) {
  691. sprintf(filename, "%sep%dRequest.log", debugServerPath, count);
  692. ofile = fopen(filename, "w");
  693. }
  694.  
  695. //Reset the flags
  696. addedHeaders = 0;
  697. headerComplete = 0;
  698. contentStarted = 0;
  699. bodylength = -1;
  700. post = 0;
  701. totalRead = 0;
  702.  
  703. // Pass out post data
  704. do {
  705. if (!readComplete) {
  706. //alarm(15); // Just in case
  707. r = read(client, buffer+end, (sizeof buffer) - end - 1);
  708. totalRead += r;
  709. readComplete = (r < (sizeof buffer) - end - 1);
  710. r += end;
  711. if (gotAlarm) {
  712. break;
  713. if (debug) fprintf(stderr,"Client read failed, got alarm!\n");
  714. }
  715. }
  716.  
  717. if (debug == 2) fprintf(stderr,"Request read count: %d, read complete: %d\n", r, readComplete);
  718.  
  719. if (r > 0) {
  720. buffer[r] = 0;
  721. end = 0;
  722.  
  723. if (contentStarted && !fixMlog && !fixHServer) {
  724. if (debug == 2) fprintf(stderr,"Direct stream output\n");
  725. outSocket(server, buffer, r, ofile);
  726. } else
  727. end = ProcessBuffer(server, buffer, r, readComplete, checkRequest, ofile);
  728.  
  729. }
  730. if (debug == 2) fprintf(stderr,"ReadComplete %d, HeaderComplete: %d, ContentStarted: %d\n", readComplete, headerComplete, contentStarted);
  731. readComplete = readComplete && headerComplete && contentStarted;
  732. readComplete = readComplete && (bodylength < 0 || totalRead >= (bodylength));
  733.  
  734. if (debug == 2) fprintf(stderr, "Bodylength: %d, TotalRead: %d\n", bodylength, totalRead);
  735.  
  736. if (!readComplete) {
  737. if (debug == 2) fprintf(stderr, "ReadComplete not true so not cheking for file end!\n");
  738. } else if (bodylength < 0 || totalRead >= bodylength) {
  739. if (debug == 2) fprintf(stderr, "Bodylength read complete!\n");
  740. } else if (strncasecmp(buffer + r - 2, "\n\n", 2) == 0) {
  741. if (debug == 2) fprintf(stderr, "End of transmission, double blank unix line found!\n");
  742. } else if (strncasecmp(buffer + r - 4, "\r\n\r\n", 4) == 0) {
  743. if (debug == 2) fprintf(stderr, "End of transmission, double blank dos line found!\n");
  744. } else
  745. readComplete = 0;
  746.  
  747. } while (!readComplete || !headerComplete || !contentStarted);
  748.  
  749. if (fixMlog && !rawSend)
  750. outSocket(server, "\nemuProxyZA\n", 12, ofile);
  751.  
  752. outSocket(server, "", -1, ofile);
  753.  
  754.  
  755. if (debugServer)
  756. fclose(ofile);
  757.  
  758. if (debug) fprintf(stderr,"Request finished!\n");
  759. }
  760.  
  761. /****************************************************************************************/
  762. void response(int server, int client, int port) {
  763. char buffer[BUFFER_SIZE];
  764. int r;
  765. FILE *ofile = NULL;
  766. char filename[100];
  767. int readComplete = 0;
  768. int end = 0;
  769.  
  770. //Reset the flags
  771. totalRead = 0;
  772.  
  773. if (debug) fprintf(stderr,"Response started:\n");
  774.  
  775. if (debugClient) {
  776. sprintf(filename, "%sep%dResponse.log", debugClientPath, count);
  777. ofile = fopen(filename, "w");
  778. }
  779.  
  780. if (debug) fprintf(stderr,"Response file created.\n");
  781.  
  782. // Pass back the reply
  783. do {
  784. if (!readComplete) {
  785. alarm(15); // Just in case
  786. r = read(server, buffer+end, (sizeof buffer) - end - 1);
  787.  
  788. totalRead += r;
  789. readComplete = (r <= 0); //(r < (sizeof buffer) - end - 1);
  790. r += end;
  791. if (gotAlarm) {
  792. break;
  793. if (debug) fprintf(stderr,"Server read failed, got alarm!\n");
  794. }
  795. }
  796.  
  797. if (debug == 2) fprintf(stderr,"Request read count: %d, read complete: %d\n", r, readComplete);
  798.  
  799. if (r > 0) {
  800. buffer[r] = 0;
  801. end = 0;
  802.  
  803. if ((timeOffset != 0) && (port == NTPPORT))
  804. fixEpoch(client, buffer, r, ofile);
  805. else if (fixHServer && altNTP)
  806. end = ProcessBuffer(client, buffer, r, readComplete, checkResponse, ofile);
  807. else
  808. outSocket(client, buffer, r, ofile);
  809. if (debug == 2) fprintf(stderr,", written");
  810. }
  811. if (debug == 2) fprintf(stderr,", done\n");
  812.  
  813. } while (!readComplete);
  814.  
  815. outSocket(client, "", -1, ofile);
  816.  
  817. if (debugClient)
  818. fclose(ofile);
  819.  
  820. if (debug) fprintf(stderr,"Response finished!\n");
  821. }
  822.  
  823. /****************************************************************************************/
  824. int handleConnection(int listener, const char* serverAddr, int port) {
  825.  
  826. int server = -1;
  827. int client;
  828.  
  829. struct sockaddr_in addr;
  830. time_t t0 = time(NULL);
  831. struct tm *tTm = localtime ( &t0 );
  832. char dayOfWeek[1];
  833. char *pos;
  834.  
  835. client = accept(listener, 0, 0);
  836. if (client < 0)
  837. return 1;
  838.  
  839. if (debug) fprintf(stderr, "\nAccepted connection on port: %d\nDate/Time: %s", port, asctime(tTm));
  840.  
  841. count++;
  842.  
  843. if (serverAddr == "") { //Need to be done before weekday check so weekday can be overriden
  844. close(client);
  845. return 0;
  846. }
  847.  
  848. if (debug) fprintf(stderr, "timeWeekdayOverride: %d, Difference: %d\n", timeWeekdayOverride, t0 - timeWeekdayOverride);
  849. if ((timeWeekdayOverride > 0) && (t0 - timeWeekdayOverride > 3600)) // 3600 = 60minutes x 60seconds
  850. timeWeekdayOverride = 0;
  851.  
  852. if ( (!timeWeekdayOverride) && (weekDays != "") && (!GuidedSetup()) ) { //Check to see if a call is allowed to be made today
  853. sprintf(dayOfWeek, "%ld", tTm->tm_wday);
  854.  
  855. pos = strstr(weekDays, dayOfWeek);
  856.  
  857. if (debug) fprintf(stderr, "Weekdays: %s, DayOfWeek: %s, pos: %d\n", weekDays, dayOfWeek, pos);
  858. if (pos == NULL) {
  859. if (debug) fprintf(stderr, "You have specified not to allow guide downloads on this day of the week.\n");
  860. close(client);
  861. return 0;
  862. }
  863. }
  864.  
  865. //Process request--------------------------------------------
  866. if (onScreenDisplay) osd_init();
  867.  
  868. server = socket(PF_INET, SOCK_STREAM, 0);
  869. if (server < 0) {
  870. perror("Could not create socket");
  871. close(client);
  872. return 0;
  873. } else if (debug == 2) fprintf(stderr, "Server socket created\n");
  874.  
  875. //Fill in the server address
  876. /* Moved the ip address assignment down here as this now allows for
  877. DNS addresses as well as dynamic DNS addresses which could have changed
  878. IP address between calls to the emulator */
  879. addr.sin_family = AF_INET;
  880. if (proxyip) {
  881. addr.sin_addr.s_addr = getIPAddress(proxyip);
  882. addr.sin_port = htons(proxyport);
  883. } else {
  884. addr.sin_addr.s_addr = getIPAddress(serverAddr); //serverip);
  885. addr.sin_port = htons(serverport);
  886. }
  887.  
  888.  
  889. if (addr.sin_addr.s_addr == INADDR_NONE)