4using System.Threading.Tasks;
24 private string language;
25 private double version;
27 private readonly
string remoteEndPoint =
string.
Empty;
28 internal string streamId =
null;
29 internal bool streamOpen =
false;
43 this.webSocketResource = WebSocketResource;
51 public override string Binding =>
"Web-Socket";
59 internal set => this.version = value;
68 internal set => this.from = value;
77 internal set => this.to = value;
86 internal set => this.language = value;
95 internal set => this.isBound = value;
119 this.isBound =
false;
120 await this.ProcessFragment(
"<presence type=\"unavailable\" xmlns=\"jabber:client\"/>");
121 this.
Server?.ConnectionClosed(
this);
124 this.webSocket?.
Close();
125 this.webSocket =
null;
127 await base.DisposeAsync();
137 public override async Task<bool>
BeginWrite(
string Xml, EventHandlerAsync<DeliveryEventArgs> Callback,
object State)
141 if (
string.IsNullOrEmpty(Xml))
143 else if (!(this.webSocket is
null))
145 await this.webSocket.
Send(Xml,
false, Callback,
State);
159 public override Task<bool>
StreamError(
string ErrorXml,
string Reason)
161 return this.ToError(
"<error xmlns=\"http://etherx.jabber.org/streams\">" + ErrorXml +
"</error>", Reason);
164 private async Task<bool> ToError(
string ErrorXml,
string Reason)
168 if (
string.IsNullOrEmpty(ErrorXml))
177 return await this.
BeginWrite(ErrorXml, async (Sender, e) =>
185 internal void TouchConnection()
189 if (!
string.IsNullOrEmpty(this.
fullJid))
198 internal async Task<bool> ProcessFragment(
string Xml)
204 if (!
string.IsNullOrEmpty(this.
fullJid))
209 if (Xml.StartsWith(
"</"))
211 this.
Information(
"Terminating session on client request.");
213 return await this.
BeginWrite(
"</stream:stream>", async (Sender, e) =>
221 Doc =
XML.
ParseXml(
"<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">" +
222 Xml +
"</stream:stream>",
true);
224 XmlElement Root = Doc.DocumentElement;
225 XmlElement StanzaElement =
null;
227 foreach (XmlNode N
in Root.ChildNodes)
229 if (N is XmlElement E)
236 if (!(StanzaElement is
null))
238 Stanza Stanza =
new Stanza(Root, StanzaElement, StanzaElement.InnerXml);
246 return await this.
StreamError(
"<bad-format xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>", ex.Message);
258 return this.webSocket.ClientConnection.Stream as SslStream;
269 switch (StanzaElement.LocalName)
275 await this.InitStream();
282 string Tx =
"<close xmlns='" + WebSocketClientResource.FramingNamespace +
"'/>";
284 await (this.webSocket?.Send(Tx,
false, async (Sender, e) =>
287 },
null) ?? Task.FromResult(
false));
293 if (!await this.
StreamError(
"<unsupported-stanza-type xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>",
"Unsupported stanza: " + StanzaElement.LocalName))
301 internal async Task InitStream()
303 StringBuilder sb =
new StringBuilder();
305 sb.Append(
"<features xmlns=\"http://etherx.jabber.org/streams\">");
313 SslStream SslStream = this.webSocket.ClientConnection.Stream as SslStream;
316 if (Mechanism.
Allowed(SslStream))
318 sb.Append(
"<mechanism>");
319 sb.Append(Mechanism.
Name);
320 sb.Append(
"</mechanism>");
324 sb.Append(
"</mechanisms>");
326 if (await this.
server.CanRegister(
this))
327 sb.Append(
"<register xmlns='http://jabber.org/features/iq-register'/>");
333 sb.Append(
"<bind xmlns='" + XmppClientConnection.BindNamespace +
"'/>");
334 sb.Append(
"<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>");
337 sb.Append(
"</features>");
339 string Tx = sb.ToString();
340 await this.webSocket.
Send(Tx);
350 return !this.disposed && this.State != XmppConnectionState.Error && this.State != XmppConnectionState.Offline && this.webSocket.
CheckLive();
Helps with common XML-related tasks.
static XmlDocument ParseXml(string Xml)
Parses an XML Document from its string representation.
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.
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.
void Information(string Comment)
Called to inform the viewer of something.
Event arguments for delivery events.
Class handling a web-socket.
Task Close()
Closes the connection.
async Task< bool > 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.
WebSocketSession(WebSocketClientResource WebSocketResource, WebSocket WebSocket, string RemoteEndPoint, XmppServer Server, params ISniffer[] Sniffers)
Web-socket Session
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 string RemoteEndPoint
Remote endpoint.
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.
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.