private static void HandleSignal(int signal) { Logger.Log.Debug("Handling signal {0} ({1})", signal, (Mono.Unix.Native.Signum)signal); // Pass the signals to the helper too. GLib.Idle.Add(new GLib.IdleHandler(delegate() { RemoteIndexer.SignalRemoteIndexer((Mono.Unix.Native.Signum)signal); return(false); })); // If we get SIGUSR1, turn the debugging level up. if ((Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR1) { LogLevel old_level = Log.Level; Log.Level = LogLevel.Debug; Log.Debug("Moving from log level {0} to Debug", old_level); return; } else if ((Mono.Unix.Native.Signum)signal == Mono.Unix.Native.Signum.SIGUSR2) { // Debugging hook for beagled QueryDriver.DebugHook(); LuceneCommon.DebugHook(); return; } Logger.Log.Debug("Initiating shutdown in response to signal."); Shutdown.BeginShutdown(); }
internal void WorkerFinished(object o) { lock (this) { Debug.Assert(workers > 0, "Too many calls to WorkerFinished"); --workers; DateTime now = DateTime.Now; //DateTime then = (DateTime) per_worker_started_time [o]; //Logger.Log.Debug ("{0} finished in {1:0.00}s", o, (now - then).TotalSeconds); per_worker_started_time.Remove(o); if (workers == 0) { finished_time = now; //Logger.Log.Debug ("Last worker finished {0:0.00}s after start", //(finished_time - started_time).TotalSeconds); if (FinishedEvent != null) { FinishedEvent(this); } Monitor.Pulse(this); } } Shutdown.WorkerFinished(o); }
private void RunInThread() { try { this.Run(); } catch (ThreadAbortException) { Thread.ResetAbort(); Log.Debug("Breaking out of UnixListener -- shutdown requested"); Shutdown.WorkerFinished(this); } }
private static int BeagleXIOErrorHandler(IntPtr display) { Logger.Log.Debug("Lost our connection to the X server! Trying to shut down gracefully"); if (!Shutdown.ShutdownRequested) { Shutdown.BeginShutdown(); } Logger.Log.Debug("Xlib is forcing us to exit!"); ExceptionHandlingThread.SpewLiveThreads(); // Returning will cause xlib to exit immediately. return(0); }
private void Run() { this.unix_listener.Start(); if (!Shutdown.WorkerStart(this, String.Format("server '{0}'", socket_path))) { return; } while (this.running) { UnixClient client; try { // This will block for an incoming connection. // FIXME: But not really, it'll only wait a second. // see the FIXME in UnixListener for more info. client = this.unix_listener.AcceptUnixClient(); } catch (SocketException) { // If the listener is stopped while we // wait for a connection, a // SocketException is thrown. break; } // FIXME: This is a hack to work around a mono // bug. See the FIXMEs in UnixListener.cs for // more info, but client should never be null, // because AcceptUnixClient() should be // throwing a SocketException when the // listener is shut down. So when that is // fixed, remove the if conditional. // If client is null, the socket timed out. if (client != null) { ConnectionHandler handler = new UnixConnectionHandler(client); lock (live_handlers) live_handlers [handler] = handler; ExceptionHandlingThread.Start(new ThreadStart(handler.HandleConnection)); } } Shutdown.WorkerFinished(this); Logger.Log.Debug("Server '{0}' shut down", this.socket_path); }
private static void LogMemoryUsage() { while (!Shutdown.ShutdownRequested) { SystemInformation.LogMemoryUsage(); int vm_rss = SystemInformation.VmRss; if (arg_heap_shot && arg_heap_shot_snapshots) { MaybeSendSigprof(vm_rss, GC.GetTotalMemory(false)); } if (vm_rss > 300 * 1024) { Logger.Log.Debug("VmRss too large --- shutting down"); Shutdown.BeginShutdown(); } Thread.Sleep(5000); } }
private bool WorkerStartNoLock(object o) { if (!Shutdown.WorkerStart(o)) { return(false); } DateTime now = DateTime.Now; per_worker_started_time [o] = now; ++workers; if (workers == 1) { started_time = now; if (StartedEvent != null) { StartedEvent(this); } } return(true); }
private void DoShutdown() { Shutdown.BeginShutdown(); }
static void DoMain(string [] args) { SystemInformation.SetProcessName("beagle-build-index"); if (args.Length < 2) { PrintUsage(); } ArrayList allowed_patterns = new ArrayList(); ArrayList denied_patterns = new ArrayList(); int i = 0; while (i < args.Length) { string arg = args [i]; ++i; string next_arg = i < args.Length ? args [i] : null; switch (arg) { case "-h": case "--help": PrintUsage(); break; case "--tag": if (next_arg != null) { arg_tag = next_arg; } ++i; break; case "-r": case "--recursive": arg_recursive = true; break; case "--enable-deletion": arg_delete = true; break; case "--disable-directories": arg_disable_directories = true; break; case "--enable-text-cache": arg_cache_text = true; break; case "--target": if (next_arg != null) { arg_output = Path.IsPathRooted(next_arg) ? next_arg : Path.GetFullPath(next_arg); } ++i; break; case "--disable-filtering": arg_disable_filtering = true; break; case "--disable-on-battery": arg_disable_on_battery = true; break; case "--allow-pattern": if (next_arg == null) { break; } if (next_arg.IndexOf(',') != -1) { foreach (string pattern in next_arg.Split(',')) { allowed_patterns.Add(pattern); } } else { allowed_patterns.Add(next_arg); } ++i; break; case "--deny-pattern": if (next_arg == null) { break; } if (next_arg.IndexOf(',') != -1) { foreach (string pattern in next_arg.Split(',')) { denied_patterns.Add(pattern); } } else { denied_patterns.Add(next_arg); } ++i; break; case "--disable-restart": arg_disable_restart = true; break; case "--source": if (next_arg == null) { break; } arg_source = next_arg; ++i; break; case "--removable": arg_removable = true; break; default: if (arg.StartsWith("-") || arg.StartsWith("--")) { PrintUsage(); } string path = Path.IsPathRooted(arg) ? arg : Path.GetFullPath(arg); if (path != "/" && path.EndsWith("/")) { path = path.TrimEnd('/'); } if (Directory.Exists(path)) { pending_directories.Enqueue(new DirectoryInfo(path)); } else if (File.Exists(path)) { pending_files.Enqueue(new FileInfo(path)); } break; } } ///////////////////////////////////////////////////////// if (arg_output == null) { Logger.Log.Error("--target must be specified"); Environment.Exit(1); } // Set the storage dir, this should be used to store log messages // and filterver.dat PathFinder.StorageDir = arg_output; foreach (FileSystemInfo info in pending_directories) { if (Path.GetFullPath(arg_output) == info.FullName) { Logger.Log.Error("Target directory cannot be one of the source paths."); Environment.Exit(1); } } foreach (FileSystemInfo info in pending_files) { if (Path.GetFullPath(arg_output) == info.FullName) { Logger.Log.Error("Target directory cannot be one of the source paths."); Environment.Exit(1); } } if (!Directory.Exists(Path.GetDirectoryName(arg_output))) { Logger.Log.Error("Index directory not available for construction: {0}", arg_output); Environment.Exit(1); } // Be *EXTRA PARANOID* about the contents of the target // directory, because creating an indexing driver will // nuke it. if (Directory.Exists(arg_output)) { foreach (FileInfo info in DirectoryWalker.GetFileInfos(arg_output)) { if (Array.IndexOf(allowed_files, info.Name) == -1) { Logger.Log.Error("{0} doesn't look safe to delete: non-Beagle file {1} was found", arg_output, info.FullName); Environment.Exit(1); } } foreach (DirectoryInfo info in DirectoryWalker.GetDirectoryInfos(arg_output)) { if (Array.IndexOf(allowed_dirs, info.Name) == -1) { Logger.Log.Error("{0} doesn't look safe to delete: non-Beagle directory {1} was found", arg_output, info.FullName); Environment.Exit(1); } } } string config_file_path = Path.Combine(arg_output, "StaticIndex.xml"); string prev_source = null; if (File.Exists(config_file_path)) { Config static_index_config = Conf.LoadFrom(config_file_path); if (static_index_config == null) { Log.Error("Invalid configuation file {0}", config_file_path); Environment.Exit(1); } prev_source = static_index_config.GetOption("Source", null); if (arg_source != null && prev_source != arg_source) { Log.Error("Source already set to {0} for existing static index. Cannot set source to {1}.", prev_source, arg_source); Environment.Exit(1); } bool prev_removable = static_index_config.GetOption("Removable", false); if (arg_removable != prev_removable) { Log.Error("Index previously created for {0}-removable path", (prev_removable ? "" : "non")); Environment.Exit(1); } else { volume_label = static_index_config.GetOption("VolumeLabel", null); } // If arg_source is not given, and prev_source is present, use prev_source // as the arg_source. This is useful for re-running build-index without // giving --arg_source for already existing static index arg_source = prev_source; } // Removable media related options if (arg_removable) { if (pending_files.Count > 0) { Log.Error("Indexing individual files is not allowed for removable media."); Environment.Exit(1); } else if (pending_directories.Count > 1) { Log.Error("Indexing multiple root directories is not allowed for removable media."); Environment.Exit(1); } mnt_dir = ((DirectoryInfo)pending_directories.Peek()).FullName; if (mnt_dir.Length != 1) { mnt_dir = mnt_dir.TrimEnd('/'); } // compute volume label // (1) directory name if block.is_volume is false // (2) hal volume.label if set // (3) hal volume.uuid if set Hal.Manager manager = new Hal.Manager(new Hal.Context()); Hal.Device mnt_device = null; foreach (Hal.Device device in manager.FindDeviceStringMatch("volume.mount_point", mnt_dir)) { mnt_device = device; } string new_volume_label = null; if (mnt_device != null) { new_volume_label = mnt_device.GetPropertyString("volume.label"); if (String.IsNullOrEmpty(new_volume_label)) { new_volume_label = mnt_device.GetPropertyString("volume.uuid"); } } if (new_volume_label == null) { new_volume_label = ((DirectoryInfo)pending_directories.Peek()).Name; } // Sanity check // Volume label is part of the URI, so cannot be changed once set if (volume_label == null) { volume_label = new_volume_label; } else if (volume_label != new_volume_label) { Log.Error("Volume label (earlier '{0}') changed (to '{1}')! You need to create a new index.", volume_label, new_volume_label); Environment.Exit(1); } } if (arg_source == null) { DirectoryInfo dir = new DirectoryInfo(StringFu.SanitizePath(arg_output)); arg_source = dir.Name; } if (!BatteryMonitor.UsingAC && arg_disable_on_battery) { Log.Always("Indexer is disabled when on battery power (--disable-on-battery)"); Environment.Exit(0); } string global_files_config = Path.Combine(PathFinder.ConfigDataDir, "config-files"); global_files_config = Path.Combine(global_files_config, Conf.Names.FilesQueryableConfig + ".xml"); if (!File.Exists(global_files_config)) { Log.Error("Global configuration file not found {0}", global_files_config); Environment.Exit(0); } // Setup regexes for allowed/denied patterns if (allowed_patterns.Count > 0) { allowed_regex = StringFu.GetPatternRegex(allowed_patterns); } else { // Read the exclude values from config // For system-wide indexes, only the global config value will be used Config config = Conf.Get(Conf.Names.FilesQueryableConfig); List <string[]> values = config.GetListOptionValues(Conf.Names.ExcludePattern); if (values != null) { foreach (string[] exclude in values) { denied_patterns.Add(exclude [0]); } } if (denied_patterns.Count > 0) { denied_regex = StringFu.GetPatternRegex(denied_patterns); } } Log.Always("Starting beagle-build-index (pid {0}) at {1}", Process.GetCurrentProcess().Id, DateTime.Now); // Set system priorities so we don't slow down the system SystemPriorities.ReduceIoPriority(); SystemPriorities.SetSchedulerPolicyBatch(); SystemPriorities.Renice(19); driver = new LuceneIndexingDriver(arg_output, MINOR_VERSION, false); driver.TextCache = (arg_cache_text) ? new TextCache(arg_output) : null; if (driver.TextCache != null) { driver.TextCache.WorldReadable = true; } backing_fa_store = new FileAttributesStore_Sqlite(driver.TopDirectory, driver.Fingerprint); fa_store = new FileAttributesStore(backing_fa_store); // Set up signal handlers #if MONO_1_9 Shutdown.SetupSignalHandlers(delegate(int signal) { if (signal == (int)Mono.Unix.Native.Signum.SIGINT || signal == (int)Mono.Unix.Native.Signum.SIGTERM) { Shutdown.BeginShutdown(); } }); #else SetupSignalHandlers(); #endif Thread monitor_thread = null; Stopwatch watch = new Stopwatch(); watch.Start(); if (!arg_disable_restart) { // Start the thread that monitors memory usage. monitor_thread = ExceptionHandlingThread.Start(new ThreadStart(MemoryMonitorWorker)); } // Start indexworker to do the crawling and indexing IndexWorker(); // Join any threads so that we know that we're the only thread still running if (monitor_thread != null) { monitor_thread.Join(); } watch.Stop(); Logger.Log.Debug("Elapsed time {0}.", watch); // Write this after indexing is done. This is because, if creating a new index, // LuceneIndexingDriver.Create() is called which purges the entire directory. if (prev_source == null) { Config static_index_config = Conf.LoadNew("StaticIndex.xml"); // Write StaticIndex.xml containing: // The name of the source static_index_config.SetOption("Source", arg_source); static_index_config ["Source"].Description = "Source of the static index"; if (arg_removable) { static_index_config.SetOption("VolumeLabel", volume_label); static_index_config ["VolumeLabel"].Description = "Volume label of the removable source"; static_index_config.SetOption("Removable", true); static_index_config ["Removable"].Description = "Removable source"; } Conf.SaveTo(static_index_config, config_file_path); } if (restart) { Logger.Log.Debug("Restarting beagle-build-index"); Process p = new Process(); p.StartInfo.UseShellExecute = false; // FIXME: Maybe this isn't the right way to do things? It should be ok, // the PATH is inherited from the shell script which runs mono itself. p.StartInfo.FileName = "mono"; p.StartInfo.Arguments = String.Join(" ", Environment.GetCommandLineArgs()); p.Start(); } Log.Always("Exiting beagle-build-index (pid {0}) at {1}", Process.GetCurrentProcess().Id, DateTime.Now); }
public static void DoMain(string[] args) { SystemInformation.InternalCallInitializer.Init(); SystemInformation.SetProcessName("beagled"); // Process the command-line arguments bool arg_debug = false; bool arg_debug_memory = false; bool arg_fg = false; int i = 0; while (i < args.Length) { string arg = args [i]; ++i; string next_arg = i < args.Length ? args [i] : null; switch (arg) { case "-h": case "--help": PrintUsage(); Environment.Exit(0); break; case "--mdb": case "--mono-debug": // Silently ignore these arguments: they get handled // in the wrapper script. break; case "--list-backends": Console.WriteLine("Current available backends:"); Console.Write(QueryDriver.ListBackends()); Environment.Exit(0); break; case "--fg": case "--foreground": arg_fg = true; break; case "--bg": case "--background": arg_fg = false; break; case "--replace": arg_replace = true; break; case "--debug": arg_debug = true; break; case "--heap-shot": arg_heap_shot = true; arg_debug = true; arg_debug_memory = true; break; case "--no-snapshots": case "--no-snapshot": arg_heap_shot_snapshots = false; break; case "--heap-buddy": case "--debug-memory": arg_debug = true; arg_debug_memory = true; break; case "--indexing-test-mode": arg_indexing_test_mode = true; arg_fg = true; break; case "--backend": if (next_arg == null) { Console.WriteLine("--backend requires a backend name"); Environment.Exit(1); break; } if (next_arg.StartsWith("--")) { Console.WriteLine("--backend requires a backend name. Invalid name '{0}'", next_arg); Environment.Exit(1); break; } if (next_arg [0] != '+' && next_arg [0] != '-') { QueryDriver.OnlyAllow(next_arg); } else { if (next_arg [0] == '+') { QueryDriver.Allow(next_arg.Substring(1)); } else { QueryDriver.Deny(next_arg.Substring(1)); } } ++i; // we used next_arg break; case "--add-static-backend": if (next_arg != null) { QueryDriver.AddStaticQueryable(next_arg); } ++i; break; case "--disable-scheduler": arg_disable_scheduler = true; break; case "--indexing-delay": if (next_arg != null) { try { QueryDriver.IndexingDelay = Int32.Parse(next_arg); } catch { Console.WriteLine("'{0}' is not a valid number of seconds", next_arg); Environment.Exit(1); } } ++i; break; case "--autostarted": // FIXME: This option is deprecated and will be removed in a future release. break; case "--disable-text-cache": disable_textcache = true; break; case "--version": VersionFu.PrintVersion(); Environment.Exit(0); break; default: Console.WriteLine("Unknown argument '{0}'", arg); Environment.Exit(1); break; } } if (Environment.GetEnvironmentVariable("SABAYON_SESSION_RUNNING") == "yes") { Console.WriteLine("Beagle is running underneath Sabayon, exiting."); Environment.Exit(0); } if (arg_indexing_test_mode) { LuceneQueryable.OptimizeRightAway = true; } // Bail out if we are trying to run as root if (Environment.UserName == "root" && Environment.GetEnvironmentVariable("SUDO_USER") != null) { Console.WriteLine("You appear to be running beagle using sudo. This can cause problems with"); Console.WriteLine("permissions in your .beagle and .wapi directories if you later try to run"); Console.WriteLine("as an unprivileged user. If you need to run beagle as root, please use"); Console.WriteLine("'su -c' instead."); Environment.Exit(-1); } if (Environment.UserName == "root" && !Conf.Daemon.GetOption(Conf.Names.AllowRoot, false)) { Console.WriteLine("You can not run beagle as root. Beagle is designed to run from your own"); Console.WriteLine("user account. If you want to create multiuser or system-wide indexes, use"); Console.WriteLine("the beagle-build-index tool."); Console.WriteLine(); Console.WriteLine("You can override this setting using the beagle-config or beagle-settings tools."); Environment.Exit(-1); } try { string tmp = PathFinder.HomeDir; } catch (Exception e) { Console.WriteLine("Unable to start the daemon: {0}", e.Message); Environment.Exit(-1); } MainLoopThread = Thread.CurrentThread; Log.Initialize(PathFinder.LogDir, "Beagle", arg_debug ? LogLevel.Debug : LogLevel.Warn, arg_fg); Log.Always("Starting Beagle Daemon (version {0})", ExternalStringsHack.Version); Log.Always("Running on {0}", SystemInformation.MonoRuntimeVersion); Log.Always("Command Line: {0}", Environment.CommandLine != null ? Environment.CommandLine : "(null)"); if (!ExtendedAttribute.Supported) { Logger.Log.Warn("Extended attributes are not supported on this filesystem. " + "Performance will suffer as a result."); } if (disable_textcache) { Log.Warn("Running with text-cache disabled!"); Log.Warn("*** Snippets will not be returned for documents indexed in this session."); } // Check if global configuration files are installed if (!Conf.CheckGlobalConfig()) { Console.WriteLine("Global configuration files not found in '{0}'", PathFinder.ConfigDataDir); Environment.Exit(-1); } // Start our memory-logging thread if (arg_debug_memory) { ExceptionHandlingThread.Start(new ThreadStart(LogMemoryUsage)); } // Do BEAGLE_EXERCISE_THE_DOG_HARDER-related processing. ExerciseTheDogHarder(); // Initialize GObject type system g_type_init(); if (SystemInformation.XssInit()) { Logger.Log.Debug("Established a connection to the X server"); } else { Logger.Log.Debug("Unable to establish a connection to the X server"); } XSetIOErrorHandler(BeagleXIOErrorHandler); // Lower our CPU priority SystemPriorities.Renice(7); QueryDriver.Init(); Server.Init(); #if MONO_1_9 Shutdown.SetupSignalHandlers(new Shutdown.SignalHandler(HandleSignal)); #else SetupSignalHandlers(); #endif Shutdown.ShutdownEvent += OnShutdown; main_loop = new MainLoop(); Shutdown.RegisterMainLoop(main_loop); // Defer all actual startup until the main loop is // running. That way shutdowns during the startup // process work correctly. GLib.Idle.Add(new GLib.IdleHandler(StartupProcess)); // Start our event loop. main_loop.Run(); // We're out of the main loop now, join all the // running threads so we can exit cleanly. ExceptionHandlingThread.JoinAllThreads(); // If we placed our sockets in a temp directory, try to clean it up // Note: this may fail because the helper is still running if (PathFinder.GetRemoteStorageDir(false) != PathFinder.StorageDir) { try { Directory.Delete(PathFinder.GetRemoteStorageDir(false)); } catch (IOException) { } } Log.Always("Beagle daemon process shut down cleanly."); }
private static void OnEmptySchedulerQueue() { Logger.Log.Debug("Scheduler queue is empty: terminating immediately"); Shutdown.BeginShutdown(); Environment.Exit(0); // Ugly work-around: We need to call Exit here to avoid deadlocking. }
private void HttpRun() { http_listener = new HttpListener(); string prefix = null; int port = 4000; bool success = false; string host = "localhost"; if (enable_network_svc) { host = "*"; } do { prefix = String.Format("http://{0}:{1}/", host, port); success = true; try { http_listener.Prefixes.Add(prefix); http_listener.Start(); } catch (SocketException) { http_listener.Prefixes.Remove(prefix); success = false; port++; } } while (!success); Shutdown.WorkerStart(this.http_listener, String.Format("HTTP Server '{0}'", prefix)); Log.Always("HTTP Server: Listening on {0}", prefix); while (this.running) { HttpListenerContext context = null; try { context = http_listener.GetContext(); } catch (Exception e) { // Log a warning if not due to shutdown if (!this.running || (!this.enable_network_svc && !this.webinterface)) { break; } Logger.Log.Warn(e, "HTTP Server: Exception while getting context:"); } if (context == null) { continue; } if (context.Request.HttpMethod == "GET") { try { WebServer.HandleStaticPages(context); } catch (IOException ex1) { // Socket was shut down Log.Debug("Exception while serving static page: " + ex1.Message); // FIXME: Should anything be done here to free "context" ? This context seems to remain in http_listener's ctxt table } catch (SocketException ex2) { // Socket is not connected anymore Log.Debug("Exception while serving static page: " + ex2.Message); } continue; } if (context.Request.HttpMethod != "POST") { // FIXME: Send better HTTP error ? context.Response.StatusCode = 404; context.Response.Close(); continue; } if (context.Request.RawUrl == "/") { // We have received a new query request Guid guid = Guid.NewGuid(); HttpItemHandler item_handler = new HttpItemHandler(); item_handlers [guid] = item_handler; ConnectionHandler handler = new HttpConnectionHandler(guid, context, item_handler); lock (live_handlers) live_handlers [handler] = handler; ExceptionHandlingThread.Start(new ThreadStart(handler.HandleConnection)); } else { // We have received a hit request Uri uri = context.Request.Url; string path = null; // Second Uri segment contains the Guid string g = uri.Segments [1]; if (g [g.Length - 1] == '/') { g = g.Remove(g.Length - 1, 1); } Guid guid = Guid.Empty; try { guid = new Guid(g); } catch (FormatException) { // FIXME: return HTTP error Logger.Log.Debug("HTTP Server: Invalid query guid '{0}'", g); context.Response.Close(); continue; } if (uri.Query.Length > 0) { path = uri.Query.Remove(0, 1); } else { // FIXME: return HTTP error Logger.Log.Debug("HTTP Server: Empty query string in item request"); context.Response.Close(); continue; } System.Uri item_uri = new Uri(path); HttpItemHandler handler = (HttpItemHandler)item_handlers [guid]; if (handler == null) { // FIXME: return HTTP error Logger.Log.Debug("HTTP Server: Query ({0}) does not exist", g); context.Response.Close(); } else { Logger.Log.Debug("HTTP Server: Asked for item '{0}' on query '{1}'", path, g); handler.HandleRequest(context, item_uri); } } } Shutdown.WorkerFinished(http_listener); Logger.Log.Info("HTTP Server: '{0}' shut down...", prefix); http_listener = null; }
public override void HandleConnection() { this.thread = Thread.CurrentThread; bool force_close_connection = false; // Read the data off the socket and store it in a // temporary memory buffer. Once the end-of-message // character has been read, discard remaining data // and deserialize the request. byte[] network_data = new byte [4096]; MemoryStream buffer_stream = new MemoryStream(); int bytes_read, total_bytes = 0, end_index = -1; // We use the network_data array as an object to represent this worker. Shutdown.WorkerStart(network_data, String.Format("HandleConnection ({0})", ++connection_count)); do { bytes_read = 0; try { lock (this.blocking_read_lock) this.in_blocking_read = true; lock (this.client_lock) { // The connection may have been closed within this loop. if (this.client != null) { bytes_read = this.client.GetStream().Read(network_data, 0, 4096); } } lock (this.blocking_read_lock) this.in_blocking_read = false; } catch (Exception e) { // Aborting the thread mid-read will // cause an IOException to be thorwn, // which sets the ThreadAbortException // as its InnerException.MemoryStream if (!(e is IOException || e is ThreadAbortException)) { throw; } // Reset the unsightly ThreadAbortException Thread.ResetAbort(); Logger.Log.Debug("Bailing out of HandleConnection -- shutdown requested"); this.thread = null; Server.MarkHandlerAsKilled(this); Shutdown.WorkerFinished(network_data); return; } total_bytes += bytes_read; if (bytes_read > 0) { // 0xff signifies end of message end_index = Array.IndexOf <byte> (network_data, (byte)0xff); buffer_stream.Write(network_data, 0, end_index == -1 ? bytes_read : end_index); } } while (bytes_read > 0 && end_index == -1); // Something just connected to our socket and then // hung up. The IndexHelper (among other things) does // this to check that a server is still running. It's // no big deal, so just clean up and close without // running any handlers. if (total_bytes == 0) { force_close_connection = true; goto cleanup; } buffer_stream.Seek(0, SeekOrigin.Begin); HandleConnection(buffer_stream); cleanup: buffer_stream.Close(); if (force_close_connection) { Close(); } else { SetupWatch(); } Server.MarkHandlerAsKilled(this); Shutdown.WorkerFinished(network_data); }
public override void HandleConnection() { //Logger.Log.Debug ("HTTP Server: Serving request for {0}", context.Request.Url); // Query request: read content and forward to base.HandleConnection for processing context.Response.KeepAlive = true; context.Response.ContentType = "text/txt; charset=utf-8"; context.Response.SendChunked = true; Shutdown.WorkerStart(this.context.Request.InputStream, String.Format("HandleConnection ({0})", ++connection_count)); // Read the data off the socket and store it in a // temporary memory buffer. Once the end-of-message // character has been read, discard remaining data // and deserialize the request. byte[] network_data = new byte [4096]; MemoryStream buffer_stream = new MemoryStream(); int bytes_read, total_bytes = 0, end_index = -1; do { bytes_read = 0; try { lock (this.blocking_read_lock) this.in_blocking_read = true; lock (this.client_lock) { // The connection may have been closed within this loop. if (this.context != null) { bytes_read = this.context.Request.InputStream.Read(network_data, 0, 4096); } } lock (this.blocking_read_lock) this.in_blocking_read = false; } catch (Exception e) { // Aborting the thread mid-read will // cause an IOException to be thorwn, // which sets the ThreadAbortException // as its InnerException.MemoryStream if (!(e is IOException || e is ThreadAbortException)) { throw; } // Reset the unsightly ThreadAbortException Thread.ResetAbort(); Logger.Log.Debug("Bailing out of HandleConnection -- shutdown requested"); this.thread = null; Server.MarkHandlerAsKilled(this); Shutdown.WorkerFinished(context.Request.InputStream); return; } total_bytes += bytes_read; if (bytes_read > 0) { // 0xff signifies end of message end_index = Array.IndexOf <byte> (network_data, (byte)0xff); buffer_stream.Write(network_data, 0, end_index == -1 ? bytes_read : end_index); } } while (bytes_read > 0 && end_index == -1); //Logger.Log.Debug ("HTTP Server: Handling received request message"); // The 0xff bytes from a remote beagled comes in a separate http request // and causes havoc by creating empty messages. HTTP streams do not behave // like a continous stream like UnixStream if (total_bytes > 0) { buffer_stream.Seek(0, SeekOrigin.Begin); base.HandleConnection(buffer_stream); } Server.MarkHandlerAsKilled(this); Shutdown.WorkerFinished(context.Request.InputStream); }