Skip to content

Commit 1753ec4

Browse files
Release 6.2.14 - 21 defect fixes, and settings you can actually find
Version bump to 6.2.14 (build 16) plus the README release notes. This release fixes the two issues the community reported, 21 defects found by an adversarial audit of the server, and the reason one of those issues was filed at all: a setting nobody could find. No database change (schema version 6005). Community reports: - #19 Backup would not start. The Control Panel called Save() on the backup settings, which that COM interface does not define, so both "Save settings" and "Start backup now" failed at runtime. The settings were already being persisted by the property assignments; only the start was blocked. Every other late-bound COM call in the Control Panel was audited at the same time. - #16 "Setting for days to keep logs" already existed but was filed on the "API & monitoring" page, so it could not be found. See the discoverability work below. Mail loss, corruption and crashes: - A failed message-file copy dereferenced a null handle in local delivery, forwarding, Sieve redirect and mirroring, killing the delivery task and leaving the message locked in the queue on every subsequent restart. - IMAP APPEND answered OK [APPENDUID] even when the message was never written to disk, silently losing Sent Items copies, drafts and migration uploads. - Every string SQL parameter on MS SQL and SQL CE was bound from a temporary that had already been destroyed - undefined behaviour on the default backend, on every query carrying a string. - A failed BeginTransaction leaked its pooled connection; once the pool was exhausted every SMTP, IMAP and POP3 operation blocked until restart. - A failed IMAP folder insert was reported as success, caching a folder with id 0 so messages filed into it had no database row. - IMAP CLOSE expunged without notifying other sessions, desyncing their sequence numbers. - A POP3 session refused the mailbox lock still released it on disconnect, handing away the owning session's lock. - POP3 RETR/TOP ignored the result of opening the message file, dropping the connection with no response and writing a minidump. - The message cache size accounting had its decrease branches inverted, so the size cap never applied as intended; Clear() now resets the accumulator too. Security: - DKIM test mode (t=y) converted a failed signature into Pass, which satisfied DMARC alignment - forged mail from a domain that left the flag in its key record was accepted. A failure in test mode is now Neutral (RFC 6376 3.6.1). - IMAP AUTHENTICATE PLAIN passwords and XOAUTH2/OAUTHBEARER tokens were written verbatim to the IMAP log; POP3 and SMTP already masked them. - Only the first TXT record at a DKIM selector was inspected, so a sender rotating its key had roughly half its mail fail verification. - Recipient batches after the first reused mutated delivery state, losing MTA-STS enforcement and MX failover and potentially carrying a STARTTLS downgrade between hosts. - The REST API bounds total request-read time and logs a rejected credential. - ES256 OAuth2 tokens are rejected with a clear message instead of a phantom signature failure: raw JWS R||S signatures were fed to a DER verifier, so the branch could never succeed. RS256/HS256 are unaffected. Protocol correctness: - IMAP RENAME compared against a hard-coded "." so a non-default hierarchy delimiter let a folder become its own parent and vanish from LIST. - SELECT/EXAMINE report a sequence number in [UNSEEN], not a UID (RFC 3501). - Expunged and moved messages are removed from the session's \Recent set. - BODY.PEEK no longer cancels a \Seen update requested by another item in the same FETCH. - POP3 answers -ERR, not the invalid +ERR, when the mailbox cannot be opened. - Reverse-DNS lookups for the Received header run on a dedicated thread pool, so slow lookups cannot delay message acknowledgements (completes 6.2.13). - Domain size used the wrong column on MS SQL, SQL CE and PostgreSQL; the account cache is cleared on server stop; TCP_NODELAY is set on every connection; an SNI failure reports the SNI error rather than a stale code. Finding settings: - Ctrl+K now searches all 227 settings by label and INI key, not just page names, and opens the page that owns the match. The index is generated from the page definitions by build/generate-settings-index.ps1 and a test fails if it falls behind, so a setting cannot become unsearchable. - Settings moved to where they are used: log level, line length, per-service files and JSON logging to Logging; SpamAssassin/ClamAV timeouts to their own scanner tabs; indexer cadence to Performance > Indexing; retry cadence, queue jitter and the per-destination outbound throttle to Delivery of e-mail, where the retry interval they modify is shown. - "Advanced hardening" is now "Advanced INI settings" under Maintenance: only four of its cards were security-related, and its warning subtitle discouraged admins from opening the page the rest of the settings were hiding on. - Signposts added for settings that correctly stay put: ManageSieve and OAuth2 from Protocols, MTA-STS publishing from the MTA-STS card, SRS/BATV from Delivery, and the message-store consistency scan from Diagnostics. - Multiple smart hosts (host1|host2, with failover) are documented at last, in the manual and on the relayer field itself. Deferred to 6.2.15: the remaining audit findings that need new navigation pages (OAuth2 and administrative access under Security, client autoconfig and DNS resolver under Network, a 2FA entry point), the IMAP sequence-set "*" rewrite, and three genuine gaps - no temp-folder cleanup, no backup scheduling in the GUI, and the consistency-check result never being surfaced. Verified at 6.2.14: - Server, tools and Control Panel build clean (server /WX, tools -warnaserror). - Full regression suite against the rebuilt service: 1026 of 1026 passing. - ControlPanel.Tests 24 of 24 passing, including the search-index drift test (verified to fail when the index is stale). - Binary and COM report 6.2.14 / 6.2.14-B16.
1 parent 9a71b35 commit 1753ec4

52 files changed

Lines changed: 1429 additions & 143 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ hMailServer is an open source email server for Microsoft Windows, implementing S
55

66
This repository is a modernized fork of the original project (which is no longer maintained upstream). It has been brought up to date with a current toolchain, current cryptography, and the transport-security standards expected of a mail server in 2026. It is maintained by Christopher Holloway / [Progressive Robot Ltd](https://www.progressiverobot.com).
77

8-
**Production status:** version **6.2.13** is released - [download the installer](https://github.com/Progressiverobot/hmailserver/releases/latest) (`hMailServer-6.2.13-x64.exe`). **6.2.13 is a community-feedback bug-fix release**: it fixes the issues testers reported on the forum against 6.2.11/6.2.12 - a SMTP DATA stall when relaying from Postfix/Proxmox Mail Gateway (a reverse-DNS lookup that blocked the network thread mid-message), the DBUpdater version labels, the Control Panel Diagnostics and service-restart, in-place upgrade settings/EventHandlers preservation, and a consistent Windows 10/2016 build target - and hardens the SMTP, IMAP FETCH and SpamAssassin paths against malformed input found while investigating. See *6.2.13* below. It is validated by the full regression suite: **1026 of 1026 tests passing, zero failures, zero inconclusive** - the complete suite, with live SpamAssassin and ClamAV (real EICAR detection), DMARC evaluation against live DNS, and TLS 1.2/1.3 handshakes end to end. Every test runs; nothing is skipped. The bundled administration GUI is the modern .NET 8 **Control Panel**.
8+
**Production status:** version **6.2.14** is released - [download the installer](https://github.com/Progressiverobot/hmailserver/releases/latest) (`hMailServer-6.2.14-x64.exe`). **6.2.14 is a correctness and usability release**: an adversarial audit of the server found and fixed **21 defects** - including failed message copies crashing delivery, IMAP APPEND reporting success for messages that were never written, string SQL parameters bound from freed memory on the default backend, a DKIM test-mode flag that turned a failed signature into a DMARC-aligned pass, and IMAP SASL passwords written to the log - plus the two issues reported by the community. The Control Panel's Ctrl+K palette now searches all 227 settings by label and INI key, and settings that were filed by how they are stored moved to the pages where they are used. See *6.2.14* below. It is validated by the full regression suite: **1026 of 1026 tests passing, zero failures, zero inconclusive** - the complete suite, with live SpamAssassin and ClamAV (real EICAR detection), DMARC evaluation against live DNS, and TLS 1.2/1.3 handshakes end to end. Every test runs; nothing is skipped. The bundled administration GUI is the modern .NET 8 **Control Panel**.
99

1010
What's new in 6.0
1111
=================
@@ -83,6 +83,64 @@ change until the new settings are turned on.
8383

8484
* SPDX + CycloneDX SBOMs (Syft) attached to every release, Dependabot CVE alerts + grouped update PRs, and a dependency-review PR gate.
8585

86+
6.2.14
87+
======
88+
89+
A correctness and usability release. Two community reports are fixed, an adversarial audit of the server found and fixed **21 defects** — several of which could lose or corrupt mail — and the Control Panel now lets you search for a setting instead of guessing which page it is on. No database change (schema version 6005).
90+
91+
Validated by the full regression suite: **1026 of 1026 passing, zero failures**, against the rebuilt 6.2.14 service.
92+
93+
## Reported by the community
94+
95+
- **Backup would not start** (#19). The Control Panel called a method that does not exist on the backup settings interface, so *Save settings* and *Start backup now* both failed with `'System.__ComObject' does not contain a definition for 'Save'`. The settings were in fact being saved; only the start was blocked. Every other late-bound call in the Control Panel was audited against the server's interface definitions at the same time.
96+
- **"Setting for days to keep logs"** (#16) already existed but was effectively unfindable. It — and the rest of the logging settings — now live together on the **Logging** page (see *Finding settings* below).
97+
98+
## Mail loss, corruption and crashes
99+
100+
- **Failed message copies crashed delivery.** When a message file could not be copied (full volume, file locked by antivirus or backup), local delivery, forwarding, Sieve redirect and mirroring dereferenced a null handle. The delivery task died and left the message locked in the queue, where it failed again on every restart.
101+
- **IMAP APPEND reported success for messages that were never written.** A full disk or a locked file produced `OK [APPENDUID …]`, so Sent Items copies, drafts and migration uploads were lost while the client showed them as saved. APPEND now fails cleanly and removes the partial file.
102+
- **Every string SQL parameter on MS SQL and SQL CE was bound from freed memory.** The value was built from a temporary that was destroyed before the parameter was used — undefined behaviour on the default database backend, on every query carrying a string.
103+
- **A failed database transaction start leaked its pooled connection.** After a few occurrences the pool was exhausted and every SMTP, IMAP and POP3 operation blocked until the service was restarted.
104+
- **A failed IMAP folder insert was reported as success**, caching a folder with no database row; messages filed into it were written to disk with nothing to find them by.
105+
- **IMAP CLOSE expunged without telling other sessions**, so a phone and a desktop on the same mailbox drifted out of step and the second client could act on the wrong message.
106+
- **A POP3 session that was refused the mailbox lock still released it on disconnect**, handing away the owning session's lock and letting two clients download concurrently.
107+
- **POP3 RETR and TOP ignored the result of opening the message file**, so an unreadable message dropped the connection with no response and wrote a minidump. Both now answer `-ERR`, and TOP recreates a missing file the way RETR already did.
108+
- **The message cache size accounting was inverted**, so the 512 MB cap never applied as intended; the accumulated size is also reset when the cache is cleared.
109+
110+
## Security
111+
112+
- **DKIM test mode (`t=y`) turned a failed signature into a pass**, which then satisfied DMARC alignment — so mail forging a domain whose key record still carried the rollout flag was accepted rather than rejected. A failure in test mode is now reported as *neutral*, per RFC 6376.
113+
- **IMAP SASL credentials were written to the log.** With IMAP logging enabled, `AUTHENTICATE PLAIN` passwords and XOAUTH2/OAUTHBEARER tokens were recorded verbatim; POP3 and SMTP already masked them.
114+
- **Only the first DKIM key record at a selector was examined**, so while a sender rotated its key roughly half of its mail failed verification and lost DMARC alignment — rejecting legitimate mail.
115+
- **MTA-STS enforcement and MX failover were lost for large recipient sets.** Recipients past the first batch reused mutated delivery state, so the policy of an MX host was looked up instead of the recipient domain's, and a STARTTLS fallback on one host could carry to the next.
116+
- The REST administration API now bounds how long one request may take to arrive, so a slow client cannot occupy the worker thread (or delay shutdown), and a rejected administrator credential is logged.
117+
- `ES256` OAuth2 tokens are now rejected with a clear message. The implementation fed a raw JWS signature to a verifier expecting DER, so it could never succeed; saying so beats a phantom "signature verification failed". `RS256` and `HS256` are unaffected.
118+
119+
## Protocol correctness
120+
121+
- IMAP `RENAME` no longer lets a folder become its own parent when the hierarchy delimiter is not `.` — which made the folder and its mail disappear from `LIST`.
122+
- `SELECT`/`EXAMINE` report a message sequence number in `[UNSEEN]`, as RFC 3501 requires, instead of a UID; clients that jump to the first unseen message no longer land on nothing.
123+
- Expunged and moved messages are removed from the session's `\Recent` set, so `RECENT` no longer claims new mail that no longer exists.
124+
- A `BODY.PEEK` item no longer cancels the `\Seen` update requested by another item in the same `FETCH`.
125+
- POP3 answers `-ERR` (not the invalid `+ERR`) when the mailbox cannot be opened, which some clients read as success.
126+
- Reverse-DNS lookups for the `Received` header now run on their own thread pool, so a burst of connections from addresses with unresponsive reverse DNS cannot delay message acknowledgements. This completes the fix that landed in 6.2.13.
127+
128+
## Finding settings
129+
130+
Settings had accumulated on whichever page matched how they were *stored* rather than what they *do*, so several real features looked missing. That is fixed in two ways.
131+
132+
- **The command palette (Ctrl+K) now searches settings, not just pages.** Type `delete logs`, `log level` or an INI key such as `LogDeleteDays` and you get the setting and the page that owns it. All 227 settings are indexed by label and key; the index is generated from the pages themselves and a test fails the build if it ever falls behind.
133+
- **Settings moved to where they are used.** Log level, maximum line length, per-service log files and JSON logging joined retention on **Logging**. SpamAssassin and ClamAV timeouts moved onto their own scanner tabs. Search-indexer cadence moved to **Performance → Indexing**. Retry cadence, queue jitter and the per-destination outbound throttle moved to **Delivery of e-mail** — the quick-retry setting silently overrides the retry interval shown there, so the two now sit together.
134+
- **"Advanced hardening" is now "Advanced INI settings"** and sits under Maintenance. Only four of its cards were security-related; the rest were operational settings that admins were not opening a page marked "change these only with a specific reason" to find.
135+
- Signposts were added where a setting correctly stays put but is easy to miss: ManageSieve and OAuth2 from the Protocols page, MTA-STS *publishing* from the MTA-STS card, SRS/BATV from Delivery, and the message-store consistency scan from Diagnostics.
136+
137+
## Also
138+
139+
- Multiple smart hosts are documented at last: put several hosts in the relayer field separated by `|` and delivery fails over to the next when one cannot be reached. This has always worked; nothing said so.
140+
- A domain's size was calculated from the wrong column on MS SQL, SQL CE and PostgreSQL.
141+
- The account cache is now cleared when the server stops, so edits made to the database while it is stopped are no longer ignored.
142+
- `TCP_NODELAY` is set on every connection, and an SNI failure now reports the SNI error rather than a stale success code.
143+
86144
6.2.13
87145
======
88146

build/generate-settings-index.ps1

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Regenerates the Control Panel's settings search index.
2+
#
3+
# The Ctrl+K palette searches page names AND individual settings, so an
4+
# administrator can type "log level" or "LogDeleteDays" and be taken to the page
5+
# that owns it, wherever that page happens to live. The index is generated from
6+
# the page definitions themselves so it cannot drift; ControlPanel.Tests fails
7+
# if the checked-in file no longer matches the sources.
8+
#
9+
# Usage: ./build/generate-settings-index.ps1
10+
#
11+
# Run it after adding, removing or relabelling any setting.
12+
13+
$ErrorActionPreference = 'Stop'
14+
15+
$repoRoot = (Get-Item $PSScriptRoot).Parent.FullName
16+
$cpRoot = Join-Path $repoRoot 'hmailserver\source\Tools\ControlPanel'
17+
$featurePath = Join-Path $cpRoot 'Views\FeatureSettingsView.xaml.cs'
18+
$serverPath = Join-Path $cpRoot 'Views\ServerSettingsView.xaml.cs'
19+
$outputPath = Join-Path $cpRoot 'Services\SettingsSearchIndex.g.cs'
20+
21+
# Section -> nav page key, matching MainWindow's page factories.
22+
$featurePages = @{ 'Security' = 'security'; 'Automation' = 'acme'; 'Integration' = 'api'; 'Hardening' = 'hardening' }
23+
$serverPages = @{ 'Protocols' = 'protocols'; 'Delivery' = 'delivery'; 'AntiSpam' = 'antispam'; 'AntiVirus' = 'antivirus';
24+
'Tls' = 'tls'; 'Logging' = 'logging'; 'Performance' = 'performance'; 'Advanced' = 'advanced' }
25+
26+
function Add-Entry($list, $label, $key, $page) {
27+
$label = $label.Trim()
28+
if ([string]::IsNullOrWhiteSpace($label)) { return }
29+
$list.Add([PSCustomObject]@{ Label = $label; Key = $key; Page = $page }) | Out-Null
30+
}
31+
32+
$entries = New-Object System.Collections.ArrayList
33+
34+
# --- INI-backed pages (FeatureSettingsView): "case Section.X:" blocks ---
35+
$featureText = Get-Content $featurePath -Raw
36+
$featureParts = [regex]::Split($featureText, 'case Section\.(\w+):')
37+
for ($i = 1; $i -lt $featureParts.Count; $i += 2) {
38+
$section = $featureParts[$i]
39+
$body = $featureParts[$i + 1]
40+
$page = $featurePages[$section]
41+
if (-not $page) { continue }
42+
43+
foreach ($m in [regex]::Matches($body, 'Key = "([^"]+)"[^}]*?Label = "([^"]*)"')) {
44+
Add-Entry $entries $m.Groups[2].Value $m.Groups[1].Value $page
45+
}
46+
}
47+
48+
# --- COM-backed pages (ServerSettingsView): "private void Build<Section>()" ---
49+
$serverText = Get-Content $serverPath -Raw
50+
foreach ($m in [regex]::Matches($serverText, '(?s)private void Build(\w+)\(\)\s*\{(.*?)\n \}')) {
51+
$section = $m.Groups[1].Value
52+
$body = $m.Groups[2].Value
53+
$page = $serverPages[$section]
54+
if (-not $page) { continue }
55+
56+
foreach ($s in [regex]::Matches($body, 'Path = "([^"]+)",\s*Label = "([^"]*)"')) {
57+
Add-Entry $entries $s.Groups[2].Value $s.Groups[1].Value $page
58+
}
59+
foreach ($s in [regex]::Matches($body, 'Label = "([^"]*)",\s*Path = "([^"]+)"')) {
60+
Add-Entry $entries $s.Groups[1].Value $s.Groups[2].Value $page
61+
}
62+
}
63+
64+
# Stable order so regeneration produces no spurious diffs.
65+
$sorted = $entries | Sort-Object Page, Label, Key -Unique
66+
67+
$sb = New-Object System.Text.StringBuilder
68+
[void]$sb.AppendLine('// <auto-generated>')
69+
[void]$sb.AppendLine('// Generated by build/generate-settings-index.ps1 from the settings page')
70+
[void]$sb.AppendLine('// definitions. Do not edit by hand - re-run the script instead.')
71+
[void]$sb.AppendLine('// </auto-generated>')
72+
[void]$sb.AppendLine()
73+
[void]$sb.AppendLine('namespace hMailServer.ControlPanel.Services')
74+
[void]$sb.AppendLine('{')
75+
[void]$sb.AppendLine(' public static partial class SettingsSearchIndex')
76+
[void]$sb.AppendLine(' {')
77+
[void]$sb.AppendLine(' /// <summary>Every setting on the settings pages: label, INI key or COM path, and the nav page that owns it.</summary>')
78+
[void]$sb.AppendLine(' public static readonly SettingEntry[] Entries =')
79+
[void]$sb.AppendLine(' {')
80+
81+
foreach ($e in $sorted) {
82+
# The captured text comes straight out of a C# string literal, so it is
83+
# already escaped; re-escaping it here would double the backslashes.
84+
[void]$sb.AppendLine(" new SettingEntry(`"$($e.Label)`", `"$($e.Key)`", `"$($e.Page)`"),")
85+
}
86+
87+
[void]$sb.AppendLine(' };')
88+
[void]$sb.AppendLine(' }')
89+
[void]$sb.AppendLine('}')
90+
91+
New-Item -ItemType Directory -Force -Path (Split-Path $outputPath) | Out-Null
92+
Set-Content -Path $outputPath -Value $sb.ToString() -Encoding UTF8 -NoNewline
93+
94+
Write-Host "Wrote $($sorted.Count) settings to $outputPath"
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[Setup]
2-
OutputBaseFilename=hMailServer-6.2.13-x64
3-
AppVerName=hMailServer 6.2.13-x64
2+
OutputBaseFilename=hMailServer-6.2.14-x64
3+
AppVerName=hMailServer 6.2.14-x64
44
ArchitecturesInstallIn64BitMode=x64
55
ArchitecturesAllowed=x64
6-
AppVersion=6.2.13
7-
VersionInfoVersion=6.2.13.0
6+
AppVersion=6.2.14
7+
VersionInfoVersion=6.2.14.0

hmailserver/source/Server/Common/AntiSpam/DKIM/DKIM.cpp

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,12 @@ namespace HM
427427
if (!ValidateBodyHash_(fileName, signatureParams, bodyCanonicalization))
428428
{
429429
LOG_DEBUG("DKIM: Validation of body hash failed.");
430-
return testMode ? Pass : PermFail;
430+
431+
// RFC 6376 3.6.1: t=y means the verifier must not treat a failure as a
432+
// failure - it does NOT mean the signature verified. Returning Pass here
433+
// granted DMARC alignment to mail whose signature was invalid, so a
434+
// domain that left the test flag in its key record could be spoofed.
435+
return testMode ? Neutral : PermFail;
431436
}
432437

433438
AnsiString tagH = signatureParams.GetValue("h");
@@ -452,7 +457,12 @@ namespace HM
452457

453458
Result result = VerifyHeaderHash_(canonicalizedHeader, tagA, tagB, publicKeyString);
454459

455-
return testMode ? Pass : result;
460+
// In test mode a failure is downgraded to "no assertion" rather than being
461+
// reported as a successful verification (see the body-hash case above).
462+
if (testMode && result != Pass)
463+
return Neutral;
464+
465+
return result;
456466
}
457467

458468
DKIM::Result
@@ -717,12 +727,31 @@ namespace HM
717727
JyM2IRZ8qSOCeQscnre5iVjwIDAQAB;
718728
*/
719729

720-
AnsiString result = results[0];
721-
730+
// A selector can legitimately hold more than one TXT record - most often
731+
// while a sender rotates its key. Inspecting only the first meant roughly
732+
// half of that sender's mail failed verification (and lost DMARC
733+
// alignment) until the rotation completed, so try each record and use the
734+
// first one that is usable for this signature.
722735
DKIMParameters dnsKeyParams;
723-
dnsKeyParams.Load(result);
736+
bool foundUsableKey = false;
737+
738+
for (const AnsiString &result : results)
739+
{
740+
// A fresh instance per record: Load merges into the existing values
741+
// rather than replacing them, so reusing one object would blend the
742+
// tags of several records together.
743+
DKIMParameters candidateParams;
744+
candidateParams.Load(result);
745+
746+
if (!ValidateDNSEntry_(candidateParams, signatureParams))
747+
continue;
748+
749+
dnsKeyParams = candidateParams;
750+
foundUsableKey = true;
751+
break;
752+
}
724753

725-
if (!ValidateDNSEntry_(dnsKeyParams, signatureParams))
754+
if (!foundUsableKey)
726755
{
727756
LOG_DEBUG("DKIM: Error when retrieving public key. Validation of DNS entry failed.");
728757
return PermFail;

hmailserver/source/Server/Common/Application/Application.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ namespace HM
7474
server_work_queue_("Server queue"),
7575
maintenance_queue_("Maintenance queue"),
7676
asynchronous_tasks_queue_("Asynchronous task queue"),
77+
name_lookup_queue_("Name lookup queue"),
7778
unique_id_(0)
7879
{
7980
version_ = Formatter::Format("{0}-B{1}", HMAILSERVER_VERSION, HMAILSERVER_BUILD);
@@ -154,9 +155,17 @@ namespace HM
154155
LOG_DEBUG("Application::InitInstance - Configuration loaded.");
155156

156157
// Start an asynch workqueue which processes asynchronous tasks from clients.
157-
WorkQueueManager::Instance()->CreateWorkQueue(Configuration::Instance()->GetAsynchronousThreads(),
158+
WorkQueueManager::Instance()->CreateWorkQueue(Configuration::Instance()->GetAsynchronousThreads(),
158159
asynchronous_tasks_queue_);
159160

161+
// Separate queue for blocking name lookups made on behalf of a live
162+
// session. These can stall for seconds on an address whose reverse zone
163+
// is unreachable, so they are kept off the asynchronous task queue that
164+
// finalizes (and acknowledges) received messages. Saturating this queue
165+
// only delays the lookups themselves, which degrade to "Unknown".
166+
WorkQueueManager::Instance()->CreateWorkQueue(Configuration::Instance()->GetAsynchronousThreads(),
167+
name_lookup_queue_);
168+
160169
return true;
161170
}
162171

@@ -241,6 +250,8 @@ namespace HM
241250

242251
WorkQueueManager::Instance()->RemoveQueue(asynchronous_tasks_queue_);
243252

253+
WorkQueueManager::Instance()->RemoveQueue(name_lookup_queue_);
254+
244255
// Backup manager is created by initinstance so should be destroyed here.
245256
if (backup_manager_)
246257
backup_manager_.reset();
@@ -666,6 +677,17 @@ namespace HM
666677
return pAsynchQueue;
667678
}
668679

680+
std::shared_ptr<WorkQueue>
681+
Application::GetNameLookupWorkQueue()
682+
{
683+
std::shared_ptr<WorkQueue> pQueue = WorkQueueManager::Instance()->GetQueue(name_lookup_queue_);
684+
685+
if (!pQueue)
686+
ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5118, "Application::GetNameLookupWorkQueue()", "Name lookup work queue not available.");
687+
688+
return pQueue;
689+
}
690+
669691
int
670692
Application::GetUniqueID()
671693
{

0 commit comments

Comments
 (0)