2using System.Net.Security;
4using System.Threading.Tasks;
23 private string language;
24 private double version;
26 private readonly
string remoteEndpoint =
string.
Empty;
27 internal string streamId =
null;
28 internal bool streamOpen =
false;
42 this.webSocketResource = WebSocketResource;
50 public override string Binding =>
"Web-Socket";
58 internal set => this.version = value;
67 internal set => this.from = value;
76 internal set => this.to = value;
85 internal set => this.language = value;
94 internal set => this.isBound = value;
118 this.isBound =
false;
119 await this.ProcessFragment(
"<presence type=\"unavailable\" xmlns=\"jabber:client\"/>");
120 this.
Server?.ConnectionClosed(
this);
123 this.webSocket?.
Close();
124 this.webSocket =
null;
126 await base.DisposeAsync();
136 public override async Task<bool>
BeginWrite(
string Xml, EventHandlerAsync<DeliveryEventArgs> Callback,
object State)
140 if (
string.IsNullOrEmpty(Xml))
142 else if (!(this.webSocket is
null))
144 await this.webSocket.
Send(Xml,
false, Callback,
State);
158 public override Task<bool>
StreamError(
string ErrorXml,
string Reason)
160 return this.ToError(
"<error xmlns=\"http://etherx.jabber.org/streams\">" + ErrorXml +
"</error>", Reason);
163 private async Task<bool> ToError(
string ErrorXml,
string Reason)
167 if (
string.IsNullOrEmpty(ErrorXml))
176 return await this.
BeginWrite(ErrorXml, async (Sender, e) =>
184 internal void TouchConnection()
188 if (!
string.IsNullOrEmpty(this.
fullJid))
197 internal async Task<bool> ProcessFragment(
string Xml)
203 if (!
string.IsNullOrEmpty(this.
fullJid))
208 if (Xml.StartsWith(
"</"))
210 await this.
Information(
"Terminating session on client request.");
212 return await this.
BeginWrite(
"</stream:stream>", async (Sender, e) =>
220 Doc =
new XmlDocument()
222 PreserveWhitespace =
true
224 Doc.LoadXml(
"<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">" +
225 Xml +
"</stream:stream>");
227 XmlElement Root = Doc.DocumentElement;
228 XmlElement StanzaElement =
null;
230 foreach (XmlNode N
in Root.ChildNodes)
232 if (N is XmlElement E)
239 if (!(StanzaElement is
null))
241 Stanza Stanza =
new Stanza(Root, StanzaElement, StanzaElement.InnerXml);
249 return await this.
StreamError(
"<bad-format xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>", ex.Message);
261 return this.webSocket.ClientConnection.Stream as SslStream;
272 switch (StanzaElement.LocalName)
278 await this.InitStream();
285 string Tx =
"<close xmlns='" + WebSocketClientResource.FramingNamespace +
"'/>";
287 this.webSocket?.
Send(Tx,
false, async (Sender, e) =>
296 if (!await this.
StreamError(
"<unsupported-stanza-type xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>",
"Unsupported stanza: " + StanzaElement.LocalName))
304 internal async Task InitStream()
306 StringBuilder sb =
new StringBuilder();
308 sb.Append(
"<features xmlns=\"http://etherx.jabber.org/streams\">");
316 SslStream SslStream = this.webSocket.ClientConnection.Stream as SslStream;
319 if (Mechanism.
Allowed(SslStream))
321 sb.Append(
"<mechanism>");
322 sb.Append(Mechanism.
Name);
323 sb.Append(
"</mechanism>");
327 sb.Append(
"</mechanisms>");
329 if (await this.
server.CanRegister(
this))
330 sb.Append(
"<register xmlns='http://jabber.org/features/iq-register'/>");
336 sb.Append(
"<bind xmlns='" + XmppClientConnection.BindNamespace +
"'/>");
337 sb.Append(
"<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>");
340 sb.Append(
"</features>");
342 string Tx = sb.ToString();
343 await this.webSocket.
Send(Tx);
353 return !this.disposed && this.State != XmppConnectionState.Error && this.State != XmppConnectionState.Offline && this.webSocket.
CheckLive();
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
Task Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
Task Information(string Comment)
Called to inform the viewer of something.
Task TransmitText(string Text)
Called when text has been transmitted.
Task ReceiveText(string Text)
Called when text has been received.
Event arguments for delivery events.
Class handling a web-socket.
Task Close()
Closes the connection.
async Task Send(string Payload, int MaxFrameLength)
Sends a text payload, possibly in multiple frames.
bool CheckLive()
Checks if the connection is live.
Abstract base class for XMPP client connections
bool isAuthenticated
If user is authenticated
XmppConnectionState State
Current state of connection.
async Task< bool > ProcessStanza(Stanza Stanza)
Processes an XMPP Stanza.
bool isBound
If user is bound
CaseInsensitiveString FullJid
Full JID
bool disposed
If connection is disposed
XmppServer Server
XMPP Server serving the client.
CaseInsensitiveString fullJid
Full JID
XmppServer server
XMPP Server
Task< bool > StreamErrorInvalidNamespace()
Sends Stream Error that namespace is invalid.
Contains information about a stanza.
Web Socket client interface
const string FramingNamespace
urn:ietf:params:xml:ns:xmpp-framing
bool IsBound
If the session is bound.
string Language
Default language
CaseInsensitiveString To
To address (domain)
override string Protocol
String representing protocol being used.
override SslStream GetSslStream()
Returns the underlying encrypted stream.
override async Task DisposeAsync()
IDisposable.Dispose
override bool CheckLive()
Checks if the connection is live.
override async Task< bool > ProcessBindingSpecificStanza(Stanza Stanza, XmlElement StanzaElement)
Processes a binding-specific stanza.
override Task< bool > StreamError(string ErrorXml, string Reason)
Returns a stream error.
override async Task< bool > BeginWrite(string Xml, EventHandlerAsync< DeliveryEventArgs > Callback, object State)
Starts sending an XML fragment to the client.
override string Binding
Binding method.
WebSocketSession(WebSocketClientResource WebSocketResource, WebSocket WebSocket, string RemoteEndpoint, XmppServer Server, params ISniffer[] Sniffers)
Web-socket Session
override string RemoteEndpoint
Remote endpoint.
double Version
BOSH protocol version
CaseInsensitiveString From
From address
const string SaslNamespace
urn:ietf:params:xml:ns:xmpp-sasl
Represents a case-insensitive string.
static readonly CaseInsensitiveString Empty
Empty case-insensitive string
Interface for authentication mechanisms.
bool Allowed(SslStream SslStream)
Checks if a mechanism is allowed during the current conditions.
string Name
Name of the mechanism.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
XmppConnectionState
State of XMPP connection.