win_crash_logger.cpp

Go to the documentation of this file.
00001 
00032 // win_crash_logger.cpp : Defines the entry point for the application.
00033 //
00034 
00035 // Must be first include, precompiled headers.
00036 #include "stdafx.h"
00037 
00038 #include "linden_common.h"
00039 #include "llcontrol.h"
00040 #include "resource.h"
00041 
00042 #include <direct.h>
00043 #include <sys/types.h>
00044 #include <sys/stat.h>
00045 #include <wininet.h>
00046 
00047 #include "indra_constants.h"    // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
00048 #include "llerror.h"
00049 #include "lltimer.h"
00050 #include "lldir.h"
00051 
00052 #include "llstring.h"
00053 #include "lldxhardware.h"
00054 
00055 LLControlGroup gCrashSettings;  // saved at end of session
00056 
00057 // Constants
00058 #define MAX_LOADSTRING 100
00059 const char* const SETTINGS_FILE_HEADER = "version";
00060 const S32 SETTINGS_FILE_VERSION = 101;
00061 
00062 // Functions
00063 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
00064 bool handle_button_click(WORD button_id);
00065 S32 load_crash_behavior_setting();
00066 bool save_crash_behavior_setting(S32 crash_behavior);
00067 void send_crash_report();
00068 void write_debug(const char *str);
00069 void write_debug(std::string& str);
00070 
00071 // Global Variables:
00072 HINSTANCE hInst= NULL;                                  // current instance
00073 TCHAR szTitle[MAX_LOADSTRING];                          /* Flawfinder: ignore */                // The title bar text
00074 TCHAR szWindowClass[MAX_LOADSTRING];            /* Flawfinder: ignore */                // The title bar text
00075 
00076 LLString gUserText;                     // User's description of the problem
00077 time_t gStartTime = 0;
00078 HWND gHwndReport = NULL;        // Send/Don't Send dialog
00079 HWND gHwndProgress = NULL;      // Progress window
00080 HCURSOR gCursorArrow = NULL;
00081 HCURSOR gCursorWait = NULL;
00082 BOOL gFirstDialog = TRUE;       // Are we currently handling the Send/Don't Send dialog?
00083 BOOL gCrashInPreviousExec = FALSE;
00084 FILE *gDebugFile = NULL;
00085 LLString gUserserver;
00086 WCHAR gProductName[512];
00087 
00088 //
00089 // Implementation
00090 //
00091 
00092 // Include product name in the window caption.
00093 void ProcessCaption(HWND hWnd)
00094 {
00095         TCHAR templateText[1024];               /* Flawfinder: ignore */
00096         TCHAR finalText[2048];          /* Flawfinder: ignore */
00097         GetWindowText(hWnd, templateText, sizeof(templateText));
00098         swprintf(finalText, templateText, gProductName);                /* Flawfinder: ignore */
00099         SetWindowText(hWnd, finalText);
00100 }
00101 
00102 
00103 // Include product name in the diaog item text.
00104 void ProcessDlgItemText(HWND hWnd, int nIDDlgItem)
00105 {
00106         TCHAR templateText[1024];               /* Flawfinder: ignore */
00107         TCHAR finalText[2048];          /* Flawfinder: ignore */
00108         GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText));
00109         swprintf(finalText, templateText, gProductName);                /* Flawfinder: ignore */
00110         SetDlgItemText(hWnd, nIDDlgItem, finalText);
00111 }
00112 
00113 int APIENTRY WinMain(HINSTANCE hInstance,
00114                      HINSTANCE hPrevInstance,
00115                      LPSTR     lpCmdLine,
00116                      int       nCmdShow)
00117 {
00118         llinfos << "Starting crash reporter" << llendl;
00119         // We assume that all the logs we're looking for reside on the current drive
00120         gDirUtilp->initAppDirs("SecondLife");
00121         
00122         // Default to the product name "Second Life" (this is overridden by the -name argument)
00123         swprintf(gProductName, L"Second Life");         /* Flawfinder: ignore */
00124 
00125         gCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes "
00126                 "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)");
00127 
00128         llinfos << "Loading crash behavior setting" << llendl;
00129         S32 crash_behavior = load_crash_behavior_setting();
00130 
00131         // In Win32, we need to generate argc and argv ourselves...
00132         // Note: GetCommandLine() returns a  potentially return a LPTSTR
00133         // which can resolve to a LPWSTR (unicode string).
00134         // (That's why it's different from lpCmdLine which is a LPSTR.)
00135         // We don't currently do unicode, so call the non-unicode version
00136         // directly.
00137         llinfos << "Processing command line" << llendl;
00138         LPSTR cmd_line_including_exe_name = GetCommandLineA();
00139 
00140         const S32       MAX_ARGS = 100;
00141         int argc = 0;
00142         char *argv[MAX_ARGS];           /* Flawfinder: ignore */
00143 
00144         char *token = NULL;
00145         if( cmd_line_including_exe_name[0] == '\"' )
00146         {
00147                 // Exe name is enclosed in quotes
00148                 token = strtok( cmd_line_including_exe_name, "\"" );
00149                 argv[argc++] = token;
00150                 token = strtok( NULL, " \t," );
00151         }
00152         else
00153         {
00154                 // Exe name is not enclosed in quotes
00155                 token = strtok( cmd_line_including_exe_name, " \t," );
00156         }
00157 
00158         while( (token != NULL) && (argc < MAX_ARGS) )
00159         {
00160                 argv[argc++] = token;
00161                 /* Get next token: */
00162                 if (*(token + strlen(token) + 1) == '\"')               /* Flawfinder: ignore */
00163                 {
00164                         token = strtok( NULL, "\"");
00165                 }
00166                 else
00167                 {
00168                         token = strtok( NULL, " \t," );
00169                 }
00170         }
00171 
00172         S32 i;
00173         for (i=0; i<argc; i++)
00174         {
00175                 if(!strcmp(argv[i], "-previous"))
00176                 {
00177                         llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl;
00178                         gCrashInPreviousExec = TRUE;
00179                 }
00180 
00181                 if(!strcmp(argv[i], "-dialog"))
00182                 {
00183                         llinfos << "Show the user dialog" << llendl;
00184                         crash_behavior = CRASH_BEHAVIOR_ASK;
00185                 }
00186 
00187                 if(!strcmp(argv[i], "-user"))
00188                 {
00189                         if ((i + 1) < argc)
00190                         {
00191                                 i++;
00192                                 gUserserver = argv[i];
00193                                 llinfos << "Got userserver " << gUserserver << llendl;
00194                         }
00195                 }
00196 
00197                 if(!strcmp(argv[i], "-name"))
00198                 {
00199                         if ((i + 1) < argc)
00200                         {
00201                                 i++;
00202                                 
00203                                 mbstowcs(gProductName, argv[i], sizeof(gProductName)/sizeof(gProductName[0]));
00204                                 gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0;
00205                                 llinfos << "Got product name " << argv[i] << llendl;
00206                         }
00207                 }
00208         }
00209 
00210         // If user doesn't want to send, bail out
00211         if (crash_behavior == CRASH_BEHAVIOR_NEVER_SEND)
00212         {
00213                 llinfos << "Crash behavior is never_send, quitting" << llendl;
00214                 return 0;
00215         }
00216 
00217         // Get the current time
00218         time(&gStartTime);
00219 
00220         llinfos << "Loading dialogs" << llendl;
00221 
00222         // Store instance handle in our global variable
00223         hInst = hInstance;
00224 
00225         // Initialize global strings
00226         LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
00227         LoadString(hInstance, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING);
00228 
00229         gCursorArrow = LoadCursor(NULL, IDC_ARROW);
00230         gCursorWait = LoadCursor(NULL, IDC_WAIT);
00231 
00232         // Register a window class that will be used by our dialogs
00233         WNDCLASS wndclass;
00234         wndclass.style = CS_HREDRAW | CS_VREDRAW;
00235         wndclass.lpfnWndProc = WndProc;
00236         wndclass.cbClsExtra = 0;
00237         wndclass.cbWndExtra = DLGWINDOWEXTRA;  // Required, since this is used for dialogs!
00238         wndclass.hInstance = hInst;
00239         wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) );
00240         wndclass.hCursor = gCursorArrow;
00241         wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
00242         wndclass.lpszMenuName = NULL;
00243         wndclass.lpszClassName = szWindowClass;
00244         RegisterClass( &wndclass );
00245 
00246         // Note: parent hwnd is 0 (the desktop).  No dlg proc.  See Petzold (5th ed) HexCalc example, Chapter 11, p529
00247         // win_crash_logger.rc has been edited by hand.
00248         // Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass)
00249 
00250         gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL);
00251         ProcessCaption(gHwndProgress);
00252         ShowWindow(gHwndProgress, SW_HIDE );
00253 
00254         if (crash_behavior == CRASH_BEHAVIOR_ALWAYS_SEND)
00255         {
00256                 ShowWindow(gHwndProgress, SW_SHOW );
00257                 send_crash_report();
00258                 return 0;
00259         }
00260 
00261         if (crash_behavior == CRASH_BEHAVIOR_ASK)
00262         {
00263                 gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_REPORT), 0, NULL);
00264 
00265                 // Include the product name in the caption and various dialog items.
00266                 ProcessCaption(gHwndReport);
00267                 ProcessDlgItemText(gHwndReport, IDC_STATIC_WHATINFO);
00268                 ProcessDlgItemText(gHwndReport, IDC_STATIC_MOTIVATION);
00269 
00270                 // Update the header to include whether or not we crashed on the last run.
00271                 WCHAR header[2048];
00272                 if (gCrashInPreviousExec)
00273                 {
00274                         swprintf(header, L"%s appears to have crashed or frozen the last time it ran.", gProductName);          /* Flawfinder: ignore */
00275                 }
00276                 else
00277                 {
00278                         swprintf(header, L"%s appears to have crashed.", gProductName);         /* Flawfinder: ignore */
00279                 }
00280                 SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header);
00281                 ShowWindow(gHwndReport, SW_SHOW );
00282                 
00283                 MSG msg;
00284                 while (GetMessage(&msg, NULL, 0, 0))
00285                 {
00286                         TranslateMessage(&msg);
00287                         DispatchMessage(&msg);
00288                 }
00289                 return msg.wParam;
00290         }
00291         else
00292         {
00293                 llwarns << "Unknown crash behavior " << crash_behavior << llendl;
00294                 return 1;
00295         }
00296 }
00297 
00298 
00299 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
00300 {
00301         switch( message )
00302         {
00303         case WM_CREATE:
00304                 return 0;
00305 
00306         case WM_COMMAND:
00307                 if( gFirstDialog )
00308                 {
00309                         WORD button_id = LOWORD(wParam);
00310                         bool handled = handle_button_click(button_id);
00311                         if (handled)
00312                         {
00313                                 return 0;
00314                         }
00315                 }
00316                 break;
00317 
00318         case WM_DESTROY:
00319                 // Closing the window cancels
00320                 PostQuitMessage(0);
00321                 return 0;
00322         }
00323 
00324         return DefWindowProc(hwnd, message, wParam, lParam);
00325 }
00326 
00327 
00328 bool handle_button_click(WORD button_id)
00329 {
00330         // Is this something other than Send or Don't Send?
00331         if (button_id != IDOK
00332                 && button_id != IDCANCEL)
00333         {
00334                 return false;
00335         }
00336 
00337         // See if "do this next time" is checked and save state
00338         S32 crash_behavior = CRASH_BEHAVIOR_ASK;
00339         LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0);
00340         if (result == BST_CHECKED)
00341         {
00342                 if (button_id == IDOK)
00343                 {
00344                         crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND;
00345                 }
00346                 else if (button_id == IDCANCEL)
00347                 {
00348                         crash_behavior = CRASH_BEHAVIOR_NEVER_SEND;
00349                 }
00350         }
00351         bool success = save_crash_behavior_setting(crash_behavior);
00352         if (!success)
00353         {
00354                 llwarns << "Failed to save crash settings" << llendl;
00355         }
00356 
00357         // We're done with this dialog.
00358         gFirstDialog = FALSE;
00359 
00360         // Send the crash report if requested
00361         if (button_id == IDOK)
00362         {
00363                 // Don't let users type anything.  They believe the reports
00364                 // get read by humans, and get angry when we don't respond. JC
00365                 //WCHAR wbuffer[20000];
00366                 //GetDlgItemText(gHwndReport, // handle to dialog box
00367                 //                              IDC_EDIT1,  // control identifier
00368                 //                              wbuffer, // pointer to buffer for text
00369                 //                              20000 // maximum size of string
00370                 //                              );
00371                 //gUserText = wstring_to_utf8str(utf16str_to_wstring(wbuffer)).c_str();
00372                 //llinfos << gUserText << llendl;
00373 
00374                 // Activate and show the window.
00375                 ShowWindow(gHwndProgress, SW_SHOW); 
00376                 // Try doing this second to make the progress window go frontmost.
00377                 ShowWindow(gHwndReport, SW_HIDE);
00378 
00379                 send_crash_report();
00380         }
00381 
00382         // Quit the app
00383         PostQuitMessage(0);
00384 
00385         return true;
00386 }
00387 
00388 
00389 class LLFileEncoder
00390 {
00391 public:
00392         LLFileEncoder(const char *formname, const char *filename);
00393         ~LLFileEncoder();
00394 
00395         BOOL isValid() const { return mIsValid; }
00396         LLString encodeURL(const S32 max_length = 0);
00397 public:
00398         BOOL mIsValid;
00399         LLString mFilename;
00400         LLString mFormname;
00401         S32 mBufLength;
00402         U8 *mBuf;
00403 };
00404 
00405 LLString encode_string(const char *formname, const LLString &str);
00406 
00407 void update_messages()
00408 {
00409         MSG msg;
00410         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
00411         {
00412                 if (msg.message == WM_QUIT)
00413                 {
00414                         exit(0);
00415                 }
00416                 TranslateMessage(&msg);
00417                 DispatchMessage(&msg);
00418         }
00419 }
00420 
00421 void sleep_and_pump_messages( U32 seconds )
00422 {
00423         const U32 CYCLES_PER_SECOND = 10;
00424         U32 cycles = seconds * CYCLES_PER_SECOND;
00425         while( cycles-- )
00426         {
00427                 update_messages();
00428                 ms_sleep(1000 / CYCLES_PER_SECOND);
00429         }
00430 }
00431 
00432 
00433 void show_progress(const char* message)
00434 {
00435         std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message));
00436         if (gHwndProgress)
00437         {
00438                 SendDlgItemMessage(gHwndProgress,       // handle to destination window 
00439                                                         IDC_LOG,
00440                                                         WM_SETTEXT,                     // message to send
00441                                                         FALSE,                          // undo option
00442                                                         (LPARAM)msg.c_str());
00443         }
00444 }
00445 
00446 
00447 void send_crash_report()
00448 {
00449         update_messages();
00450         show_progress("Starting up...");
00451         update_messages();
00452 
00453         const S32 SL_MAX_SIZE = 100000;                 // Maximum size of the Second Life log file.
00454 
00455         update_messages();
00456 
00457         // Lots of silly variable, replicated for each log file.
00458         std::string db_file_name; // debug.log
00459         std::string sl_file_name; // SecondLife.log
00460         std::string md_file_name; // minidump (SecondLife.dmp) file name
00461         std::string st_file_name; // stats.log file
00462         std::string si_file_name; // settings.ini file
00463         std::string ml_file_name; // message.log file
00464 
00465         LLFileEncoder *db_filep = NULL;
00466         LLFileEncoder *sl_filep = NULL;
00467         LLFileEncoder *st_filep = NULL;
00468         LLFileEncoder *md_filep = NULL;
00469         LLFileEncoder *si_filep = NULL;
00470         LLFileEncoder *ml_filep = NULL;
00471 
00472         // DX hardware probe blocks, so we can't cancel during it
00473         SetCursor(gCursorWait);
00474 
00475         // Need to do hardware detection before we grab the files, otherwise we don't send the debug log updates
00476         // to the server (including the list of hardware).
00477         update_messages();
00478         show_progress("Detecting hardware, please wait...");
00479         update_messages();
00480         gDXHardware.setWriteDebugFunc(write_debug);
00481         gDXHardware.getInfo(FALSE);
00482         update_messages();
00483         gDXHardware.dumpDevices();
00484         update_messages();
00485         fclose(gDebugFile);
00486         gDebugFile = NULL;
00487 
00488         // At this point we're responsive enough the user could click the close button
00489         SetCursor(gCursorArrow);
00490 
00492         //
00493         // We do the parsing for the debug_info file first, as that will
00494         // give us the location of the SecondLife.log file.
00495         //
00496 
00497         // Figure out the filename of the debug log
00498         db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
00499         db_filep = new LLFileEncoder("DB", db_file_name.c_str());
00500 
00501         // Get the filename of the SecondLife.log file
00502         // *NOTE: This buffer size is hard coded into scanf() below.
00503         char tmp_sl_name[256];          /* Flawfinder: ignore */
00504         tmp_sl_name[0] = '\0';
00505 
00506         update_messages();
00507         show_progress("Looking for files...");
00508         update_messages();
00509 
00510         // Look for it in the debug_info.log file
00511         if (db_filep->isValid())
00512         {
00513                 sscanf(
00514                         (const char*)db_filep->mBuf,
00515                         "SL Log: %255[^\r\n]",
00516                         tmp_sl_name);
00517         }
00518         else
00519         {
00520                 delete db_filep;
00521                 db_filep = NULL;
00522         }
00523 
00524         if (gCrashInPreviousExec)
00525         {
00526                 // If we froze, the crash log this time around isn't useful.  Use the
00527                 // old one.
00528                 sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old");
00529         }
00530         else if (tmp_sl_name[0])
00531         {
00532                 // If debug_info.log gives us a valid log filename, use that.
00533                 sl_file_name = tmp_sl_name;
00534                 llinfos << "Using log file from debug log " << sl_file_name << llendl;
00535         }
00536         else
00537         {
00538                 // Figure out the filename of the default second life log
00539                 sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
00540         }
00541 
00542         // Now we get the SecondLife.log file if it's there
00543         sl_filep = new LLFileEncoder("SL", sl_file_name.c_str());
00544         if (!sl_filep->isValid())
00545         {
00546                 delete sl_filep;
00547                 sl_filep = NULL;
00548         }
00549 
00550         update_messages();
00551         show_progress("Looking for stats file...");
00552         update_messages();
00553 
00554         st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
00555         st_filep = new LLFileEncoder("ST", st_file_name.c_str());
00556         if (!st_filep->isValid())
00557         {
00558                 delete st_filep;
00559                 st_filep = NULL;
00560         }
00561 
00562         si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini");
00563         si_filep = new LLFileEncoder("SI", si_file_name.c_str());
00564         if (!si_filep->isValid())
00565         {
00566                 delete si_filep;
00567                 si_filep = NULL;
00568         }
00569 
00570         // Now we get the minidump
00571         md_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.dmp");
00572         md_filep = new LLFileEncoder("MD", md_file_name.c_str());
00573         if (!md_filep->isValid())
00574         {               
00575                 delete md_filep;
00576                 md_filep = NULL;
00577         }
00578 
00579         // Now we get the message log
00580         ml_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"message.log");
00581         ml_filep = new LLFileEncoder("ML", ml_file_name.c_str());
00582         if (!ml_filep->isValid())
00583         {               
00584                 delete ml_filep;
00585                 ml_filep = NULL;
00586         }
00587 
00588         LLString post_data;
00589         LLString tmp_url_buf;
00590 
00591         // Append the userserver
00592         tmp_url_buf = encode_string("USER", gUserserver);
00593         post_data += tmp_url_buf;
00594         llinfos << "PostData:" << post_data << llendl;
00595 
00596         if (gCrashInPreviousExec)
00597         {
00598                 post_data.append(1, '&');
00599                 tmp_url_buf = encode_string("EF", "Y");
00600                 post_data += tmp_url_buf;
00601         }
00602 
00603         update_messages();
00604         show_progress("Encoding data");
00605         update_messages();
00606         if (db_filep)
00607         {
00608                 post_data.append(1, '&');
00609                 tmp_url_buf = db_filep->encodeURL();
00610                 post_data += tmp_url_buf;
00611                 llinfos << "Sending DB log file" << llendl;
00612         }
00613         else
00614         {
00615                 llinfos << "Not sending DB log file" << llendl;
00616         }
00617         show_progress("Encoding data.");
00618         update_messages();
00619 
00620         if (sl_filep)
00621         {
00622                 post_data.append(1, '&');
00623                 tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE);
00624                 post_data += tmp_url_buf;
00625                 llinfos << "Sending SL log file" << llendl;
00626         }
00627         else
00628         {
00629                 llinfos << "Not sending SL log file" << llendl;
00630         }
00631         show_progress("Encoding data..");
00632         update_messages();
00633 
00634         if (st_filep)
00635         {
00636                 post_data.append(1, '&');
00637                 tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE);
00638                 post_data += tmp_url_buf;
00639                 llinfos << "Sending stats log file" << llendl;
00640         }
00641         else
00642         {
00643                 llinfos << "Not sending stats log file" << llendl;
00644         }
00645         show_progress("Encoding data...");
00646         update_messages();
00647 
00648         if (md_filep)
00649         {
00650                 post_data.append(1, '&');
00651                 tmp_url_buf = md_filep->encodeURL();
00652                 post_data += tmp_url_buf;
00653                 llinfos << "Sending minidump log file" << llendl;
00654         }
00655         else
00656         {
00657                 llinfos << "Not sending minidump log file" << llendl;
00658         }
00659         show_progress("Encoding data....");
00660         update_messages();
00661 
00662         if (si_filep)
00663         {
00664                 post_data.append(1, '&');
00665                 tmp_url_buf = si_filep->encodeURL();
00666                 post_data += tmp_url_buf;
00667                 llinfos << "Sending settings log file" << llendl;
00668         }
00669         else
00670         {
00671                 llinfos << "Not sending settings.ini file" << llendl;
00672         }
00673         show_progress("Encoding data....");
00674         update_messages();
00675 
00676         if (ml_filep)
00677         {
00678                 post_data.append(1, '&');
00679                 tmp_url_buf = ml_filep->encodeURL(SL_MAX_SIZE);
00680                 post_data += tmp_url_buf;
00681                 llinfos << "Sending message log file" << llendl;
00682         }
00683         else
00684         {
00685                 llinfos << "Not sending message.log file" << llendl;
00686         }
00687         show_progress("Encoding data....");
00688         update_messages();
00689 
00690         if (gUserText.size())
00691         {
00692                 post_data.append(1, '&');
00693                 tmp_url_buf = encode_string("UN", gUserText);
00694                 post_data += tmp_url_buf;
00695         }
00696 
00697         delete db_filep;
00698         db_filep = NULL;
00699         delete sl_filep;
00700         sl_filep = NULL;
00701         delete md_filep;
00702         md_filep = NULL;
00703 
00704         // Post data to web server
00705         const S32 BUFSIZE = 65536;
00706         HINTERNET hinet, hsession, hrequest;
00707         char data[BUFSIZE];             /* Flawfinder: ignore */
00708         unsigned long bytes_read;
00709 
00710         llinfos << "Connecting to crash report server" << llendl;
00711         update_messages();
00712         show_progress("Connecting to server...");
00713         update_messages();
00714 
00715         // Init wininet subsystem
00716         hinet = InternetOpen(L"LindenCrashReporter", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
00717         if (hinet == NULL)
00718         {
00719                 llinfos << "Couldn't open connection" << llendl;
00720                 sleep_and_pump_messages( 5 );
00721 //              return FALSE;
00722         }
00723 
00724         hsession = InternetConnect(hinet,
00725                                                                 L"sl.daleglass.net",
00726                                                                 INTERNET_DEFAULT_HTTP_PORT,
00727                                                                 NULL,
00728                                                                 NULL,
00729                                                                 INTERNET_SERVICE_HTTP,
00730                                                                 NULL,
00731                                                                 NULL);
00732 
00733         if (!hsession)
00734         {
00735                 llinfos << "Couldn't talk to crash report server" << llendl;
00736         }
00737 
00738         hrequest = HttpOpenRequest(hsession, L"POST", L"/viewer_crash_reporter", NULL, L"", NULL, 0, 0);
00739         if (!hrequest)
00740         {
00741                 llinfos << "Couldn't open crash report URL!" << llendl;
00742         }
00743         
00744         llinfos << "Transmitting data" << llendl;
00745         llinfos << "Bytes: " << (post_data.size()) << llendl;
00746 
00747         update_messages();
00748         show_progress("Transmitting data...");
00749         update_messages();
00750 
00751         BOOL ok = HttpSendRequest(hrequest, NULL, 0, (void *)(post_data.c_str()), post_data.size());
00752         if (!ok)
00753         {
00754                 llinfos << "Error posting data!" << llendl;
00755                 sleep_and_pump_messages( 5 );
00756         }
00757 
00758         llinfos << "Response from crash report server:" << llendl;
00759         do
00760         {
00761                 if (InternetReadFile(hrequest, data, BUFSIZE, &bytes_read))
00762                 {
00763                         if (bytes_read == 0)
00764                         {
00765                                 // If InternetFileRead returns TRUE AND bytes_read == 0
00766                                 // we've successfully downloaded the entire file
00767                                 break;
00768                         }
00769                         else
00770                         {
00771                                 data[bytes_read] = 0;
00772                                 llinfos << data << llendl;
00773                         }
00774                 }
00775                 else
00776                 {
00777                         llinfos << "Couldn't read file!" << llendl;
00778                         sleep_and_pump_messages( 5 );
00779 //                      return FALSE;
00780                 }
00781         } while(TRUE);
00782 
00783         InternetCloseHandle(hrequest);
00784         InternetCloseHandle(hsession);
00785         InternetCloseHandle(hinet);
00786         update_messages();
00787         show_progress("Done.");
00788         sleep_and_pump_messages( 3 );
00789 //      return TRUE;
00790 }
00791 
00792 LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename)
00793 {
00794         mFormname = form_name;
00795         mFilename = filename;
00796         mIsValid = FALSE;
00797         mBuf = NULL;
00798 
00799         int res;
00800         
00801         llstat stat_data;
00802         res = LLFile::stat(mFilename.c_str(), &stat_data);
00803         if (res)
00804         {
00805                 llwarns << "File " << mFilename << " is missing!" << llendl;
00806                 return;
00807         }
00808 
00809         FILE *fp = NULL;
00810         S32 buf_size = 0;
00811         S32 count = 0;
00812         while (count < 5)
00813         {
00814                 buf_size = stat_data.st_size;
00815                 fp = LLFile::fopen(mFilename.c_str(), "rb");            /* Flawfinder: ignore */
00816                 if (!fp)
00817                 {
00818                         llwarns << "Can't open file " << mFilename << ", wait for a second" << llendl;
00819                         // Couldn't open the file, wait a bit and try again
00820                         count++;
00821                         ms_sleep(1000);
00822                 }
00823                 else
00824                 {
00825                         break;
00826                 }
00827         }
00828         if (!fp)
00829         {
00830                 return;
00831         }
00832         U8 *buf = new U8[buf_size + 1];
00833         fread(buf, 1, buf_size, fp);
00834         fclose(fp);
00835 
00836         mBuf = buf;
00837         mBufLength = buf_size;
00838 
00839         mIsValid = TRUE;
00840 }
00841 
00842 LLFileEncoder::~LLFileEncoder()
00843 {
00844         if (mBuf)
00845         {
00846                 delete mBuf;
00847                 mBuf = NULL;
00848         }
00849 }
00850 
00851 LLString LLFileEncoder::encodeURL(const S32 max_length)
00852 {
00853         LLString result = mFormname;
00854         result.append(1, '=');
00855 
00856         S32 i = 0;
00857 
00858         if (max_length)
00859         {
00860                 if (mBufLength > max_length)
00861                 {
00862                         i = mBufLength - max_length;
00863                 }
00864         }
00865 
00866         S32 url_buf_size = 3*mBufLength + 1;
00867         char *url_buf = new char[url_buf_size];
00868 
00869         S32 cur_pos = 0;
00870         for (; i < mBufLength; i++)
00871         {
00872                 S32 byte_val = mBuf[i];
00873                 sprintf(url_buf + cur_pos, "%%%02x", byte_val);
00874                 cur_pos += 3;
00875         }
00876         url_buf[i*3] = 0;
00877 
00878         result.append(url_buf);
00879         delete[] url_buf;
00880         return result;
00881 }
00882 
00883 LLString encode_string(const char *formname, const LLString &str)
00884 {
00885         LLString result = formname;
00886         result.append(1, '=');
00887         // Not using LLString because of bad performance issues
00888         S32 buf_size = str.size();
00889         S32 url_buf_size = 3*str.size() + 1;
00890         char *url_buf = new char[url_buf_size];
00891 
00892         S32 cur_pos = 0;
00893         S32 i;
00894         for (i = 0; i < buf_size; i++)
00895         {
00896                 sprintf(url_buf + cur_pos, "%%%02x", str[i]);
00897                 cur_pos += 3;
00898         }
00899         url_buf[i*3] = 0;
00900 
00901         result.append(url_buf);
00902         delete[] url_buf;
00903         return result;
00904 }
00905 
00906 void write_debug(const char *str)
00907 {
00908         if (!gDebugFile)
00909         {
00910                 std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
00911                 llinfos << "Opening debug file " << debug_filename << llendl;
00912                 gDebugFile = LLFile::fopen(debug_filename.c_str(), "a+");               /* Flawfinder: ignore */
00913         if (!gDebugFile)
00914         {
00915             fprintf(stderr, "Couldn't open %s: debug log to stderr instead.\n", debug_filename.c_str());
00916             gDebugFile = stderr;
00917         }
00918         }
00919         fprintf(gDebugFile, str);               /* Flawfinder: ignore */
00920         fflush(gDebugFile);
00921 }
00922 
00923 void write_debug(std::string& str)
00924 {
00925         write_debug(str.c_str());
00926 }
00927 
00928 S32 load_crash_behavior_setting()
00929 {
00930         std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
00931 
00932         gCrashSettings.loadFromFile(filename);
00933                 
00934         S32 value = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
00935         
00936         if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK;
00937 
00938         return value;
00939 }
00940 
00941 bool save_crash_behavior_setting(S32 crash_behavior)
00942 {
00943         if (crash_behavior < CRASH_BEHAVIOR_ASK) return false;
00944         if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false;
00945 
00946         gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior);
00947         std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
00948 
00949         gCrashSettings.saveToFile(filename, FALSE);
00950 
00951         return true;
00952 }

Generated on Thu Jul 1 06:10:03 2010 for Second Life Viewer by  doxygen 1.4.7