3using System.Diagnostics;
5using System.Security.Authentication;
6using System.Security.Cryptography.X509Certificates;
8using System.Threading.Tasks;
37 private readonly
byte[] localHostName;
38 private readonly
byte[] appName;
39 private readonly
string host;
40 private readonly
int port;
41 private readonly
bool tls;
42 private X509Certificate clientCertificate;
65 this.localHostName = EncodeName(LocalHostName);
66 this.appName = EncodeName(AppName);
89 this.clientCertificate = ClientCertificate;
95 public string Host => this.host;
105 public bool Tls => this.tls;
118 return this.
Send(Event,
false);
128 bool ResendIfError =
true;
132 if (!(this.client is
null) && !this.client.
Connected)
134 this.
Warning(
"Disposing/Closing TCP client.");
140 if (this.client is
null)
142 this.
Information(
"Connecting to " + this.host +
":" + this.port.ToString());
145 this.client.OnDisconnected += this.Client_OnDisconnected;
146 this.client.OnError += this.Client_OnError;
147 this.client.OnReceived += this.Client_OnReceived;
149 await this.client.
ConnectAsync(this.host, this.port, this.tls);
151 this.
Information(
"Connected to " + this.host +
":" + this.port.ToString());
157 if (this.clientCertificate is
null)
170 int MessageLength = Message.Length;
173 switch (this.separation)
177 byte[] Prefix = Encoding.ASCII.GetBytes(MessageLength.ToString());
178 int PrefixLength = Prefix.Length;
179 Packet =
new byte[PrefixLength + MessageLength + 1];
180 Buffer.BlockCopy(Prefix, 0, Packet, 0, PrefixLength);
181 Packet[PrefixLength] = (byte)
' ';
182 Buffer.BlockCopy(Message, 0, Packet, PrefixLength + 1, MessageLength);
186 Packet =
new byte[MessageLength + 2];
187 Buffer.BlockCopy(Message, 0, Packet, 0, MessageLength);
188 Packet[MessageLength] = (byte)
'\r';
189 Packet[MessageLength + 1] = (byte)
'\n';
193 Packet =
new byte[MessageLength + 1];
194 Buffer.BlockCopy(Message, 0, Packet, 0, MessageLength);
195 Packet[MessageLength] = (byte)
'\n';
199 Packet =
new byte[MessageLength + 1];
200 Buffer.BlockCopy(Message, 0, Packet, 0, MessageLength);
201 Packet[MessageLength] = 0;
214 TaskCompletionSource<bool> Sent =
new TaskCompletionSource<bool>();
216 Ok = await this.client.
SendAsync(
true, Packet,
219 Sent.TrySetResult(e.Ok);
220 return Task.CompletedTask;
227 Ok = await this.client.
SendAsync(
true, Packet);
243 ResendIfError =
false;
248 throw new IOException(
"Unable to send message to Syslog server.");
253 private Task<bool> Client_OnReceived(
object Sender,
bool ConstantBuffer,
byte[] Buffer,
int Offset,
int Count)
257 this.
ReceiveText(Encoding.UTF8.GetString(Buffer, Offset, Count));
258 this.
Warning(
"Received unexpected data from Syslog server. Data ignored.");
261 return Task.FromResult(
true);
264 private Task Client_OnError(
object Sender, Exception e)
266 this.
Error(e.Message);
267 return Task.CompletedTask;
270 private Task Client_OnDisconnected(
object Sender, EventArgs e)
273 return Task.CompletedTask;
285 using MemoryStream ms =
new MemoryStream();
292 int Severity = Event.Type
switch
294 EventType.Emergency => 0,
295 EventType.Alert => 1,
296 EventType.Critical => 2,
297 EventType.Error => 3,
298 EventType.Warning => 4,
299 EventType.Notice => 5,
300 EventType.Debug => 7,
304 ms.WriteByte((
byte)
'<');
305 ms.Write(Encoding.ASCII.GetBytes((Facility * 8 + Severity).ToString()));
306 ms.WriteByte((
byte)
'>');
310 ms.WriteByte((
byte)
' ');
311 ms.WriteByte((
byte)
'1');
315 ms.WriteByte((
byte)
' ');
320 ms.WriteByte((
byte)
' ');
321 ms.Write(this.localHostName);
325 ms.WriteByte((
byte)
' ');
326 ms.Write(this.appName);
330 ms.WriteByte((
byte)
' ');
331 ms.Write(EncodeName(Process.GetCurrentProcess().Id.ToString()));
335 ms.WriteByte((
byte)
' ');
340 #region STRUCTURED-DATA
343 ms.Write(this.EncodeValue(
Event.
Type.ToString()));
344 ms.Write(eventLevel);
345 ms.Write(this.EncodeValue(
Event.
Level.ToString()));
349 ms.Write(eventObject);
355 ms.Write(eventActor);
361 ms.Write(eventFacility);
367 ms.Write(eventModule);
373 ms.Write(eventStackTrace);
379 foreach (KeyValuePair<string, object> Tag
in Event.
Tags)
381 ms.WriteByte((
byte)
'"');
382 ms.WriteByte((
byte)
' ');
383 ms.Write(EncodeName(Tag.Key));
384 ms.WriteByte((
byte)
'=');
385 ms.WriteByte((
byte)
'"');
386 ms.Write(this.EncodeValue(Tag.Value?.ToString() ??
string.Empty));
390 ms.WriteByte((
byte)
'"');
391 ms.WriteByte((
byte)
']');
395 ms.WriteByte((
byte)
' ');
398 ms.WriteByte((
byte)
'\r');
399 ms.WriteByte((
byte)
'\n');
404 private static byte[] EncodeName(
string s)
406 if (
string.IsNullOrEmpty(s))
409 return Encoding.ASCII.GetBytes(s.Replace(
' ',
'_'));
412 private byte[] EncodeValue(
string s)
414 s = s.Replace(
"\\",
"\\\\").Replace(
"\"",
"\\\"").Replace(
"]",
"\\]");
416 switch (this.separation)
420 s = s.Replace(
"\r",
"<CR>").Replace(
"\n",
"<LF>");
430 [Obsolete(
"Use DisposeAsync instead.")]
441 if (!(this.client is
null))
448 private static readonly
byte[] nil =
new byte[] { (byte)
'-' };
449 private static readonly
byte[] eventType = Encoding.ASCII.GetBytes(
" [Event Type=\"");
450 private static readonly
byte[] eventLevel = Encoding.ASCII.GetBytes(
"\" Level=\"");
451 private static readonly
byte[] eventObject = Encoding.ASCII.GetBytes(
"\" Object=\"");
452 private static readonly
byte[] eventActor = Encoding.ASCII.GetBytes(
"\" Actor=\"");
453 private static readonly
byte[] eventFacility = Encoding.ASCII.GetBytes(
"\" Facility=\"");
454 private static readonly
byte[] eventModule = Encoding.ASCII.GetBytes(
"\" Module=\"");
455 private static readonly
byte[] eventStackTrace = Encoding.ASCII.GetBytes(
"\" StackTrace=\"");
463 this.clientCertificate = Certificate;
Helps with common XML-related tasks.
static string Encode(string s)
Encodes a string for use in XML.
Class representing an event.
string Message
Free-text event message.
EventType Type
Type of event.
string Object
Object related to the event.
EventLevel Level
Event Level.
string Actor
Actor responsible for the action causing the event.
string Module
Module where the event is reported.
DateTime Timestamp
Timestamp of event.
KeyValuePair< string, object >[] Tags
Variable set of tags providing event-specific information.
string EventId
Computer-readable Event ID identifying type of even.
string Facility
Facility can be either a facility in the network sense or in the system sense.
string StackTrace
Stack Trace of event.
Syslog over TCP/IP client application, as defined in RFCs 5224, 5425, 6587: https://datatracker....
const int DefaultTlsPort
Default Syslog over TLS over TCP/IP port number (6514).
async Task Send(Event Event, bool WaitSent)
Sends an event to the syslog server.
int Port
Port number of the Syslog server.
const int DefaultPort
Default Syslog over TCP/IP port number (514).
Task Send(Event Event)
Sends an event to the syslog server.
string Host
Host name or address of the Syslog server.
void Dispose()
Disposes the syslog client.
void UpdateCertificate(X509Certificate Certificate)
Updates the certificate used in mTLS negotiation.
SyslogClient(string Host, int Port, bool Tls, string LocalHostName, string AppName, SyslogEventSeparation Separation, params ISniffer[] Sniffers)
Syslog over TCP/IP client application, as defined in RFCs 5224, 5425, 6587: https://datatracker....
SyslogClient(string Host, int Port, X509Certificate ClientCertificate, string LocalHostName, string AppName, SyslogEventSeparation Separation, params ISniffer[] Sniffers)
Syslog over TCP/IP client application, as defined in RFCs 5224, 5425, 6587: https://datatracker....
byte[] CreateMessage(Event Event)
Creates a binary Syslog message from an event.
async Task DisposeAsync()
Disposes the syslog client.
SyslogEventSeparation Separation
How events are separated in the event stream.
Implements a binary TCP Client, by encapsulating a TcpClient. It also makes the use of TcpClient safe...
Task UpgradeToTlsAsClient(SslProtocols Protocols)
Upgrades a client connection to TLS.
bool Connected
If the connection is open.
Task< bool > SendAsync(byte[] Packet)
Sends a binary packet.
void Continue()
Continues reading from the socket, if paused in an event handler.
virtual Task DisposeAsync()
Disposes of the object asynchronously. The underlying TcpClient is either disposed directly,...
Task< bool > ConnectAsync(string Host, int Port)
Connects to a host using TCP.
Simple base class for classes implementing communication protocols.
void TransmitText(string Text)
Called when text has been transmitted.
void Exception(Exception Exception)
Called to inform the viewer of an exception state.
void ReceiveText(string Text)
Called when text has been received.
ISniffer[] Sniffers
Registered sniffers.
bool HasSniffers
If there are sniffers registered on the object.
void Error(string Error)
Called to inform the viewer of an error state.
void Warning(string Warning)
Called to inform the viewer of a warning state.
void Information(string Comment)
Called to inform the viewer of something.
Static class managing binary representations of strings.
static Encoding Utf8WithBom
UTF-8 encoding with Byte Order Mark (BOM)
Interface for asynchronously disposable objects.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Interface for Mutual TLS (mTLS) Clients or TLS servers.
SyslogEventSeparation
How events are separated in the Syslog event stream.