Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
BoshSession.cs
1using System;
3using System.IO;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
9using Waher.Events;
16using Waher.Security;
17
19{
24 {
25 private readonly BoshWebClientResource webResource;
26 private HttpResponse waiting = null;
27 private readonly LinkedList<OutputRec> outputQueue = new LinkedList<OutputRec>();
28 private readonly LinkedList<(long, XmlElement, Stream, string)> inputQueue = new LinkedList<(long, XmlElement, Stream, string)>();
29 private MultiReadSingleWriteObject syncObjOutput;
30 private MultiReadSingleWriteObject syncObjInput;
31 private DateTime maxRidTimestamp = DateTime.MinValue;
32 private DateTime firstEmpty = DateTime.MinValue;
33 private Stream currentStream = null;
34 private readonly string sid;
35 private readonly CaseInsensitiveString from;
36 private readonly CaseInsensitiveString to;
37 private readonly string language;
38 private string key = null;
39 private string waitingEcho = null;
40 private readonly double version;
41 private long? waitingRid = null;
42 private long? lastRid = null;
43 private long maxRid = -1;
44 private readonly int hold;
45 private readonly int waitSeconds;
46 private readonly int pollingSeconds;
47 private readonly int requests;
48 private int nrEmpty = 0;
49 private readonly bool ack;
50 private readonly bool secure;
51 private bool terminated = false;
52 private string terminationCondition = null;
53
54 private readonly string remoteEndPoint = string.Empty;
55 private DateTime nextTimeout = DateTime.MinValue;
56 private bool removed = false;
57
78 public BoshSession(BoshWebClientResource WebResource, string Sid, long? Rid,
80 int PollingSeconds, int Requests, bool Ack, bool Secure, string RemoteEndPoint, string Key, XmppServer Server,
81 params ISniffer[] Sniffers)
82 : base(Server, XmppConnectionState.StreamNegotiation, Sniffers)
83 {
84 this.syncObjOutput = new MultiReadSingleWriteObject(this);
85 this.syncObjInput = new MultiReadSingleWriteObject(this);
86
87 this.webResource = WebResource;
88 this.sid = Sid;
89 this.lastRid = Rid;
90 this.version = Version;
91 this.from = From;
92 this.to = To;
93 this.language = Language;
94 this.hold = Hold;
95 this.waitSeconds = WaitSeconds;
96 this.pollingSeconds = PollingSeconds;
97 this.requests = Requests;
98 this.ack = Ack;
99 this.secure = Secure;
100 this.remoteEndPoint = RemoteEndPoint;
101 this.key = Key;
102 }
103
104 private class OutputRec
105 {
106 public string Payload;
107 public EventHandlerAsync<DeliveryEventArgs> Callback;
108 public object State;
109 }
110
114 public override string Binding => "BOSH";
115
119 public string Sid => this.sid;
120
124 public double Version => this.version;
125
129 public CaseInsensitiveString From => this.from;
130
134 public CaseInsensitiveString To => this.to;
135
139 public string Language => this.language;
140
144 public int Hold => this.hold;
145
149 public int WaitSeconds => this.waitSeconds;
150
154 public int PollingSeconds => this.pollingSeconds;
155
159 public int Requests => this.requests;
160
164 public bool Ack => this.ack;
165
169 public bool Secure => this.secure;
170
174 public bool Terminated
175 {
176 get => this.terminated;
177 internal set => this.terminated = value;
178 }
179
183 public bool IsBound
184 {
185 get => this.isBound;
186 internal set => this.isBound = value;
187 }
188
192 public string Key
193 {
194 get => this.key;
195 internal set => this.key = value;
196 }
197
198 internal bool Removed
199 {
200 get => this.removed;
201 set => this.removed = value;
202 }
203
207 public override string RemoteEndPoint => this.remoteEndPoint;
208
212 public override string Protocol => "XMPP (BOSH)";
213
217 public override async Task DisposeAsync()
218 {
219 if (!this.disposed)
220 {
221 await this.SetState(XmppConnectionState.Offline);
222
223 if (this.isBound && !(this.Server is null))
224 {
225 this.isBound = false;
226 await this.ProcessFragment("<presence type=\"unavailable\" xmlns=\"jabber:client\"/>", null);
227 this.Server?.ConnectionClosed(this);
228 }
229
230 if (!(this.waiting is null))
231 {
232 this.Error("Connection disposed.");
233 await this.webResource.BoshError(this.waiting, string.Empty);
234 this.waiting = null;
235 this.waitingRid = null;
236 this.waitingEcho = null;
237 }
238
239 this.terminated = true;
240
241 if (!this.removed)
242 {
243 this.removed = true;
244 BoshWebClientResource.Remove(this);
245 }
246
247 this.syncObjOutput?.Dispose();
248 this.syncObjOutput = null;
249
250 this.syncObjInput?.Dispose();
251 this.syncObjInput = null;
252
253 await base.DisposeAsync();
254 }
255 }
256
257 internal async Task RegisterForResponse(Scheduler Scheduler, long? Rid, HttpResponse Response, string Echo)
258 {
259 if (this.terminated)
260 {
261 this.Error(this.terminationCondition);
262 await this.webResource.BoshError(Response, this.terminationCondition);
263 return;
264 }
265
266 LinkedList<OutputRec> ToCall = null;
267 StringBuilder Xml = null;
268 bool RemoveTimeout = false;
269 bool ScheduleTimeout = false;
270
271 if (!await this.syncObjOutput.TryBeginWrite(10000))
272 throw new TimeoutException("Unable to get access to session.");
273
274 try
275 {
276 if (Rid.HasValue && Rid.Value <= this.maxRid)
277 {
278 await this.EmptyResponseLocked(Response, Rid, Echo);
279 return;
280 }
281
282 if (!(this.waiting is null))
283 {
284 if (this.waitingRid.HasValue && Rid.HasValue && Rid.Value < this.waitingRid.Value)
285 {
286 await this.EmptyResponseLocked(Response, Rid, Echo);
287 return;
288 }
289
290 try
291 {
292 await this.EmptyResponseLocked(this.waiting, this.waitingRid, this.waitingEcho);
293 }
294 catch (Exception)
295 {
296 // Ignore
297 }
298
299 RemoveTimeout = true;
300 this.waiting = null;
301 this.waitingRid = null;
302 this.waitingEcho = null;
303 }
304
305 if (this.outputQueue.First is null)
306 {
307 this.waitingRid = Rid;
308 this.waiting = Response;
309 this.waitingEcho = Echo;
310 ScheduleTimeout = true;
311 }
312 else
313 {
314 if (Xml is null)
315 Xml = new StringBuilder();
316 else
317 Xml.Clear();
318
319 Xml.Append("<body from='");
320 Xml.Append(XML.Encode(this.to));
321
322 if (Rid.HasValue)
323 {
324 Xml.Append("' ack='");
325 Xml.Append(Rid.Value.ToString());
326 this.RidReturnedLocked(Rid.Value);
327 }
328
329 if (!string.IsNullOrEmpty(Echo))
330 {
331 Xml.Append("' echo='");
332 Xml.Append(XML.Encode(Echo));
333 }
334
335 Xml.Append("' xmlns='");
336 Xml.Append(BoshWebClientResource.HttpBindNamespace);
337
338 if (this.State != XmppConnectionState.Active)
339 {
340 Xml.Append("' xmlns:stream='");
341 Xml.Append(StreamNamespace);
342 }
343
344 Xml.Append("'>");
345
346 foreach (OutputRec Fragment in this.outputQueue)
347 {
348 Xml.Append(Fragment.Payload);
349
350 if (!(Fragment.Callback is null))
351 {
352 ToCall ??= new LinkedList<OutputRec>();
353 ToCall.AddLast(Fragment);
354 }
355 }
356
357 Xml.Append("</body>");
358
359 this.outputQueue.Clear();
360
361 string Tx = Xml.ToString();
362 await this.webResource.Return(Response, Tx);
363 this.TransmitText(Tx);
364 }
365 }
366 finally
367 {
368 await this.syncObjOutput.EndWrite();
369 }
370
371 if ((RemoveTimeout || ScheduleTimeout) && this.nextTimeout != DateTime.MinValue)
372 {
373 Scheduler.Remove(this.nextTimeout);
374 this.nextTimeout = DateTime.MinValue;
375 }
376
377 if (ScheduleTimeout)
378 this.nextTimeout = Scheduler.Add(DateTime.Now.AddSeconds(this.waitSeconds), this.Timeout, null);
379
380 if (!(ToCall is null))
381 {
382 foreach (OutputRec Rec in ToCall)
383 await Rec.Callback.Raise(this, new DeliveryEventArgs(Rec.State, true));
384 }
385 }
386
387 private async Task EmptyResponseLocked(HttpResponse Response, long? Rid, string Echo)
388 {
389 StringBuilder Xml = new StringBuilder();
390
391 Xml.Append("<body from='");
392 Xml.Append(XML.Encode(this.to));
393
394 if (Rid.HasValue)
395 {
396 Xml.Append("' ack='");
397 Xml.Append(Rid.ToString());
398 this.RidReturnedLocked(Rid.Value);
399 }
400
401 if (!string.IsNullOrEmpty(Echo))
402 {
403 Xml.Append("' echo='");
404 Xml.Append(XML.Encode(Echo));
405 }
406
407 Xml.Append("' xmlns='");
408 Xml.Append(BoshWebClientResource.HttpBindNamespace);
409 Xml.Append("'/>");
410
411 string Tx = Xml.ToString();
412 await this.webResource.Return(Response, Tx);
413 this.TransmitText(Tx);
414 }
415
416 private async void Timeout(object P)
417 {
418 try
419 {
420 StringBuilder Xml;
421 HttpResponse Response;
422 LinkedList<OutputRec> ToCall = null;
423 long? Rid;
424 string Echo;
425
426 if (this.disposed || this.nextTimeout == DateTime.MinValue)
427 return;
428
429 this.nextTimeout = DateTime.MinValue;
430
431 try
432 {
433 if (!await this.syncObjOutput.TryBeginWrite(10000))
434 throw new TimeoutException("Unable to get access to session.");
435
436 try
437 {
438 if (this.waiting is null)
439 return;
440
441 Response = this.waiting;
442 Rid = this.waitingRid;
443 Echo = this.waitingEcho;
444 this.waiting = null;
445 this.waitingRid = null;
446 this.waitingEcho = null;
447
448 Xml = new StringBuilder();
449
450 Xml.Append("<body from='");
451 Xml.Append(XML.Encode(this.to));
452
453 if (Rid.HasValue)
454 {
455 Xml.Append("' ack='");
456 Xml.Append(Rid.Value.ToString());
457 this.RidReturnedLocked(Rid.Value);
458 }
459
460 if (!string.IsNullOrEmpty(Echo))
461 {
462 Xml.Append("' echo='");
463 Xml.Append(XML.Encode(Echo));
464 }
465
466 Xml.Append("' xmlns='");
467 Xml.Append(BoshWebClientResource.HttpBindNamespace);
468
469 if (this.State != XmppConnectionState.Active)
470 {
471 Xml.Append("' xmlns:stream='");
472 Xml.Append(XmppClientConnection.StreamNamespace);
473 }
474
475 if (this.outputQueue.First is null)
476 Xml.Append("'/>");
477 else
478 {
479 Xml.Append("'>");
480
481 foreach (OutputRec Fragment in this.outputQueue)
482 {
483 Xml.Append(Fragment);
484
485 if (!(Fragment.Callback is null))
486 {
487 if (!(ToCall is null))
488 ToCall = new LinkedList<OutputRec>();
489
490 ToCall.AddLast(Fragment);
491 }
492 }
493
494 Xml.Append("</body>");
495
496 this.outputQueue.Clear();
497 }
498 }
499 finally
500 {
501 await this.syncObjOutput.EndWrite();
502 }
503
504 string Tx = Xml.ToString();
505 await this.webResource.Return(Response, Tx);
506 this.TransmitText(Tx);
507 }
508 catch (Exception ex)
509 {
510 Log.Exception(ex);
511 // Ignore
512 }
513
514 if (!(ToCall is null))
515 {
516 foreach (OutputRec Rec in ToCall)
517 await Rec.Callback.Raise(this, new DeliveryEventArgs(Rec.State, false));
518 }
519 }
520 catch (Exception ex)
521 {
522 Log.Exception(ex);
523 }
524 }
525
526
533 public override async Task<bool> BeginWrite(string Xml, EventHandlerAsync<DeliveryEventArgs> Callback, object State)
534 {
535 if (this.disposed)
536 return false;
537
538 if (string.IsNullOrEmpty(Xml))
539 await Callback.Raise(this, new DeliveryEventArgs(State, true));
540 else
541 {
542 HttpResponse Response = null;
543 DateTime Now = DateTime.Now;
544 long? Rid;
545 string Echo;
546
547 this.nrEmpty = 0;
548
549 if (!await this.syncObjOutput.TryBeginWrite(10000))
550 throw new TimeoutException("Unable to get access to session.");
551
552 try
553 {
554 if (this.waiting is null)
555 {
556 this.outputQueue.AddLast(new OutputRec()
557 {
558 Payload = Xml,
559 Callback = Callback,
560 State = State
561 });
562 return true;
563 }
564
565 Response = this.waiting;
566 Rid = this.waitingRid;
567 Echo = this.waitingEcho;
568 this.waiting = null;
569 this.waitingRid = null;
570 this.waitingEcho = null;
571 }
572 finally
573 {
574 await this.syncObjOutput.EndWrite();
575 }
576
577 try
578 {
579 StringBuilder Xml2 = new StringBuilder();
580
581 Xml2.Append("<body from='");
582 Xml2.Append(XML.Encode(this.to));
583
584 if (Rid.HasValue)
585 {
586 Xml2.Append("' ack='");
587 Xml2.Append(Rid.Value.ToString());
588 this.RidReturnedLocked(Rid.Value);
589 }
590
591 if (!string.IsNullOrEmpty(Echo))
592 {
593 Xml2.Append("' echo='");
594 Xml2.Append(XML.Encode(Echo));
595 }
596
597 Xml2.Append("' xmlns='");
599
600 if (this.State != XmppConnectionState.Active)
601 {
602 Xml2.Append("' xmlns:stream='");
604 }
605
606 Xml2.Append("'>");
607 Xml2.Append(Xml);
608 Xml2.Append("</body>");
609
610 string Tx = Xml2.ToString();
611 await this.webResource.Return(Response, Tx);
612 this.TransmitText(Tx);
613 }
614 catch (Exception)
615 {
616 // Ignore
617
618 return false;
619 }
620
621 await Callback.Raise(this, new DeliveryEventArgs(State, true));
622 }
623
624 return true;
625 }
626
633 public override Task<bool> StreamError(string ErrorXml, string Reason)
634 {
635 return this.ToError("<stream:error>" + ErrorXml + "</stream:error>", Reason);
636 }
637
638 private async Task<bool> ToError(string ErrorXml, string Reason)
639 {
640 this.terminated = true;
641 this.removed = true;
642 BoshWebClientResource.Remove(this);
643
644 Log.Error("Terminating session. " + Reason, this.FullJid);
645
646 if (string.IsNullOrEmpty(ErrorXml))
647 {
648 await this.SetState(XmppConnectionState.Error);
649 return false;
650 }
651 else
652 {
653 return await this.BeginWrite(ErrorXml, async (Sender, e) =>
654 {
655 await this.SetState(XmppConnectionState.Error);
656 }, null);
657 }
658 }
659
660 private async Task<bool> ProcessFragment(string Xml, Stream Stream)
661 {
662 XmlDocument Doc;
663
664 try
665 {
666 if (!string.IsNullOrEmpty(this.fullJid))
667 this.server.TouchClientConnection(this.fullJid);
668
669 Doc = XML.ParseXml("<body xmlns='" + BoshWebClientResource.HttpBindNamespace + "'>" + Xml + "</body>", true);
670
671 return await this.ProcessStanzas(Doc.DocumentElement, Stream);
672 }
673 catch (Exception ex)
674 {
675 this.Exception(ex);
676 await this.StreamError("<bad-format xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>", ex.Message);
677
678 return false;
679 }
680 }
681
682 internal async Task<bool> ProcessStanzasInOrder(long Rid, XmlElement RootElement, Stream Stream, string Key)
683 {
684 bool Process = false;
685
686 if (this.terminated)
687 return false;
688
689 if (!await this.syncObjInput.TryBeginWrite(10000))
690 throw new TimeoutException("Unable to get access to session.");
691
692 try
693 {
694 if (!this.lastRid.HasValue || Rid == this.lastRid.Value + 1)
695 {
696 if (!this.CheckNextKey(Key))
697 return false;
698
699 this.lastRid = Rid;
700 Process = true;
701 }
702 else
703 {
704 if (this.inputQueue.Count >= this.hold || (Rid - this.lastRid.Value) > this.requests)
705 {
706 this.terminated = true;
707 this.terminationCondition = "item-not-found";
708 }
709 else
710 this.inputQueue.AddLast((Rid, RootElement, Stream, Key));
711
712 Process = false;
713 }
714 }
715 finally
716 {
717 await this.syncObjInput.EndWrite();
718 }
719
720 if (this.terminated)
721 Log.Error("Terminating session. Too many incoming requests.", this.fullJid);
722 else if (Process)
723 {
724 bool FirstElement = true;
725
726 do
727 {
728 if (FirstElement)
729 FirstElement = false;
730
731 XmlElement RootElement0 = RootElement;
732 Stream Stream0 = Stream;
733
734 LinkedListNode<(long, XmlElement, Stream, string)> First;
735 (long, XmlElement, Stream, string) Rec;
736
737 if (!await this.syncObjInput.TryBeginWrite(10000))
738 throw new TimeoutException("Unable to get access to session.");
739
740 try
741 {
742 if (!((First = this.inputQueue.First) is null) &&
743 (Rec = First.Value).Item1 == Rid + 1)
744 {
745 do
746 {
747 RootElement = Rec.Item2;
748 Stream = Rec.Item3;
749 Key = Rec.Item4;
750 this.inputQueue.RemoveFirst();
751
752 if (this.CheckNextKey(Key))
753 this.lastRid = Rid;
754 else
755 RootElement = null;
756 }
757 while (RootElement is null &&
758 !((First = this.inputQueue.First) is null) &&
759 (Rec = First.Value).Item1 == Rid + 1);
760
761 if (!(RootElement is null))
762 Rid++;
763 }
764 else
765 RootElement = null;
766 }
767 finally
768 {
769 await this.syncObjInput.EndWrite();
770 }
771
772 try
773 {
774 if (!await this.ProcessStanzas(RootElement0, Stream0))
775 return false;
776 }
777 catch (Exception ex)
778 {
779 this.Exception(ex);
780 }
781 }
782 while (!(RootElement is null));
783 }
784
785 return true;
786 }
787
788 internal bool CheckNextKey(string Key)
789 {
790 if (Key is null)
791 {
792 if (!(this.key is null))
793 return false;
794 }
795 else
796 {
797 string PrevKey = Hashes.ComputeSHA1HashString(Encoding.ASCII.GetBytes(Key));
798 int i, c = PrevKey.Length;
799
800 if (c != this.key.Length)
801 return false;
802
803 for (i = 0; i < c; i++)
804 {
805 if (PrevKey[i] != this.key[i])
806 return false;
807 }
808
809 this.key = Key;
810 }
811
812 return true;
813 }
814
819 protected override SslStream GetSslStream()
820 {
821 return this.currentStream as SslStream;
822 }
823
824 internal async Task<bool> ProcessStanzas(XmlElement RootElement, Stream Stream)
825 {
826 try
827 {
828 if (this.HasSniffers)
829 this.ReceiveText(RootElement.OuterXml);
830
831 int Count = 0;
832
833 foreach (XmlNode N in RootElement.ChildNodes)
834 {
835 if (N is XmlElement E)
836 {
837 Count++;
838
839 try
840 {
841 Stanza Stanza = new Stanza(RootElement, E, RootElement.InnerXml);
842
843 this.currentStream = Stream;
844 if (!await this.ProcessStanza(Stanza))
845 return false;
846 }
847 catch (Exception ex)
848 {
849 this.Exception(ex);
850 if (!await this.StreamError("<bad-format xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>", ex.Message))
851 return false;
852 }
853 }
854 }
855
856 if (Count == 0)
857 {
858 if (this.State != XmppConnectionState.Active)
859 {
860 StringBuilder Xml = new StringBuilder();
861 await this.InitStream(Xml, Stream as SslStream);
862 if (!await this.BeginWrite(Xml.ToString(), null, null))
863 return false;
864 }
865 else
866 {
867 DateTime Now = DateTime.Now;
868
869 if (this.nrEmpty == 0)
870 this.firstEmpty = Now;
871
872 this.nrEmpty++;
873 if (this.nrEmpty > 5)
874 {
875 double SecondsPerRequest = (Now - this.firstEmpty).TotalSeconds / this.nrEmpty;
876
877 if (SecondsPerRequest * 2 < this.pollingSeconds)
878 {
879 this.terminated = true;
880 this.terminationCondition = "policy-violation";
881 BoshWebClientResource.Remove(this);
882
883 Log.Error("Terminating session. Polling too quickly.", this.fullJid);
884 }
885 }
886 }
887 }
888 else
889 this.nrEmpty = 0;
890 }
891 catch (Exception ex)
892 {
893 Log.Exception(ex);
894 }
895
896 return true;
897 }
898
905 protected override async Task<bool> ProcessBindingSpecificStanza(Stanza Stanza, XmlElement StanzaElement)
906 {
907 return await this.StreamError("<unsupported-stanza-type xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>",
908 "Unrecognized stanza: " + StanzaElement.LocalName);
909 }
910
911 internal async Task InitStream(StringBuilder sb, SslStream SslStream)
912 {
913 sb.Append("<stream:features>");
914
915 if (!this.isAuthenticated)
916 {
917 await this.SetState(XmppConnectionState.Authenticating);
918
919 sb.Append("<mechanisms xmlns='" + XmppServer.SaslNamespace + "'>");
920
921 foreach (IAuthenticationMechanism Mechanism in XmppServer.mechanisms)
922 {
923 if (Mechanism.Allowed(SslStream))
924 {
925 sb.Append("<mechanism>");
926 sb.Append(Mechanism.Name);
927 sb.Append("</mechanism>");
928 }
929 }
930
931 sb.Append("</mechanisms>");
932
933 if (await this.server.CanRegister(this))
934 sb.Append("<register xmlns='http://jabber.org/features/iq-register'/>");
935 }
936 else if (!this.isBound)
937 {
938 await this.SetState(XmppConnectionState.Binding);
939
940 sb.Append("<bind xmlns='" + XmppClientConnection.BindNamespace + "'/>");
941 sb.Append("<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>");
942 }
943
944 sb.Append("</stream:features>");
945 }
946
947 internal void RidReturnedLocked(long Rid)
948 {
949 if (Rid > this.maxRid)
950 {
951 this.maxRid = Rid;
952 this.maxRidTimestamp = DateTime.Now;
953 }
954 }
955
960 public override bool CheckLive()
961 {
962 return !this.disposed && !this.removed && this.State != XmppConnectionState.Error && this.State != XmppConnectionState.Offline;
963 }
964
965 }
966}
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
static XmlDocument ParseXml(string Xml)
Parses an XML Document from its string representation.
Definition: XML.cs:713
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
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.
Definition: Log.cs:1657
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.
Definition: Log.cs:692
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.
Event arguments for delivery events.
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
CaseInsensitiveString From
From address
Definition: BoshSession.cs:129
override string RemoteEndPoint
Remote endpoint.
Definition: BoshSession.cs:207
override SslStream GetSslStream()
Returns the underlying encrypted stream.
Definition: BoshSession.cs:819
bool Terminated
If the session has been terminated.
Definition: BoshSession.cs:175
override string Binding
Binding method.
Definition: BoshSession.cs:114
int PollingSeconds
How rapidly resource can be polled (in seconds).
Definition: BoshSession.cs:154
override string Protocol
String representing protocol being used.
Definition: BoshSession.cs:212
bool IsBound
If the session is bound.
Definition: BoshSession.cs:184
override Task< bool > StreamError(string ErrorXml, string Reason)
Returns a stream error.
Definition: BoshSession.cs:633
override bool CheckLive()
Checks if the connection is live.
Definition: BoshSession.cs:960
int WaitSeconds
Maximum time (in seconds) to wait.
Definition: BoshSession.cs:149
override async Task DisposeAsync()
IDisposable.Dispose
Definition: BoshSession.cs:217
CaseInsensitiveString To
To address (domain)
Definition: BoshSession.cs:134
bool Secure
If connection is secure.
Definition: BoshSession.cs:169
bool Ack
If requests are acknowledged.
Definition: BoshSession.cs:164
override async Task< bool > BeginWrite(string Xml, EventHandlerAsync< DeliveryEventArgs > Callback, object State)
Starts sending an XML fragment to the client.
Definition: BoshSession.cs:533
int Requests
Number of simultaneous requests open.
Definition: BoshSession.cs:159
BoshSession(BoshWebClientResource WebResource, string Sid, long? Rid, double Version, CaseInsensitiveString From, CaseInsensitiveString To, string Language, int Hold, int WaitSeconds, int PollingSeconds, int Requests, bool Ack, bool Secure, string RemoteEndPoint, string Key, XmppServer Server, params ISniffer[] Sniffers)
BOSH Session
Definition: BoshSession.cs:78
override async Task< bool > ProcessBindingSpecificStanza(Stanza Stanza, XmlElement StanzaElement)
Processes a binding-specific stanza.
Definition: BoshSession.cs:905
const string HttpBindNamespace
http://jabber.org/protocol/httpbind
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.
const string StreamNamespace
http://etherx.jabber.org/streams
XmppServer Server
XMPP Server serving the client.
Contains information about a stanza.
Definition: Stanza.cs:9
const string SaslNamespace
urn:ietf:params:xml:ns:xmpp-sasl
Definition: XmppServer.cs:113
Represents a case-insensitive string.
static readonly CaseInsensitiveString Empty
Empty case-insensitive string
Represents an object that allows single concurrent writers but multiple concurrent readers....
virtual Task EndWrite()
Ends a writing session of the object. Must be called once for each call to BeginWrite or successful c...
virtual async Task< bool > TryBeginWrite(int Timeout)
Waits, at most Timeout milliseconds, until object ready for writing. Each successful call to TryBegi...
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
Definition: Scheduler.cs:14
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
Definition: Scheduler.cs:186
DateTime Add(DateTime When, Action< object > Callback, object State)
Adds an event.
Definition: Scheduler.cs:54
Contains methods for simple hash calculations.
Definition: Hashes.cs:57
static string ComputeSHA1HashString(byte[] Data)
Computes the SHA-1 hash of a block of binary data.
Definition: Hashes.cs:395
Interface for authentication mechanisms.
bool Allowed(SslStream SslStream)
Checks if a mechanism is allowed during the current conditions.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Definition: ISniffer.cs:10
XmppConnectionState
State of XMPP connection.