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;
2using System.Collections.Generic;
3using System.IO;
4using System.Net.Security;
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 await 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 await 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 if (ToCall is null)
353 ToCall = new LinkedList<OutputRec>();
354
355 ToCall.AddLast(Fragment);
356 }
357 }
358
359 Xml.Append("</body>");
360
361 this.outputQueue.Clear();
362
363 string Tx = Xml.ToString();
364 await this.webResource.Return(Response, Tx);
365 await this.TransmitText(Tx);
366 }
367 }
368 finally
369 {
370 await this.syncObjOutput.EndWrite();
371 }
372
373 if ((RemoveTimeout || ScheduleTimeout) && this.nextTimeout != DateTime.MinValue)
374 {
375 Scheduler.Remove(this.nextTimeout);
376 this.nextTimeout = DateTime.MinValue;
377 }
378
379 if (ScheduleTimeout)
380 this.nextTimeout = Scheduler.Add(DateTime.Now.AddSeconds(this.waitSeconds), this.Timeout, null);
381
382 if (!(ToCall is null))
383 {
384 foreach (OutputRec Rec in ToCall)
385 await Rec.Callback.Raise(this, new DeliveryEventArgs(Rec.State, true));
386 }
387 }
388
389 private async Task EmptyResponseLocked(HttpResponse Response, long? Rid, string Echo)
390 {
391 StringBuilder Xml = new StringBuilder();
392
393 Xml.Append("<body from='");
394 Xml.Append(XML.Encode(this.to));
395
396 if (Rid.HasValue)
397 {
398 Xml.Append("' ack='");
399 Xml.Append(Rid.ToString());
400 this.RidReturnedLocked(Rid.Value);
401 }
402
403 if (!string.IsNullOrEmpty(Echo))
404 {
405 Xml.Append("' echo='");
406 Xml.Append(XML.Encode(Echo));
407 }
408
409 Xml.Append("' xmlns='");
410 Xml.Append(BoshWebClientResource.HttpBindNamespace);
411 Xml.Append("'/>");
412
413 string Tx = Xml.ToString();
414 await this.webResource.Return(Response, Tx);
415 await this.TransmitText(Tx);
416 }
417
418 private async void Timeout(object P)
419 {
420 try
421 {
422 StringBuilder Xml;
423 HttpResponse Response;
424 LinkedList<OutputRec> ToCall = null;
425 long? Rid;
426 string Echo;
427
428 if (this.disposed || this.nextTimeout == DateTime.MinValue)
429 return;
430
431 this.nextTimeout = DateTime.MinValue;
432
433 try
434 {
435 if (!await this.syncObjOutput.TryBeginWrite(10000))
436 throw new TimeoutException("Unable to get access to session.");
437
438 try
439 {
440 if (this.waiting is null)
441 return;
442
443 Response = this.waiting;
444 Rid = this.waitingRid;
445 Echo = this.waitingEcho;
446 this.waiting = null;
447 this.waitingRid = null;
448 this.waitingEcho = null;
449
450 Xml = new StringBuilder();
451
452 Xml.Append("<body from='");
453 Xml.Append(XML.Encode(this.to));
454
455 if (Rid.HasValue)
456 {
457 Xml.Append("' ack='");
458 Xml.Append(Rid.Value.ToString());
459 this.RidReturnedLocked(Rid.Value);
460 }
461
462 if (!string.IsNullOrEmpty(Echo))
463 {
464 Xml.Append("' echo='");
465 Xml.Append(XML.Encode(Echo));
466 }
467
468 Xml.Append("' xmlns='");
469 Xml.Append(BoshWebClientResource.HttpBindNamespace);
470
471 if (this.State != XmppConnectionState.Active)
472 {
473 Xml.Append("' xmlns:stream='");
474 Xml.Append(XmppClientConnection.StreamNamespace);
475 }
476
477 if (this.outputQueue.First is null)
478 Xml.Append("'/>");
479 else
480 {
481 Xml.Append("'>");
482
483 foreach (OutputRec Fragment in this.outputQueue)
484 {
485 Xml.Append(Fragment);
486
487 if (!(Fragment.Callback is null))
488 {
489 if (!(ToCall is null))
490 ToCall = new LinkedList<OutputRec>();
491
492 ToCall.AddLast(Fragment);
493 }
494 }
495
496 Xml.Append("</body>");
497
498 this.outputQueue.Clear();
499 }
500 }
501 finally
502 {
503 await this.syncObjOutput.EndWrite();
504 }
505
506 string Tx = Xml.ToString();
507 await this.webResource.Return(Response, Tx);
508 await this.TransmitText(Tx);
509 }
510 catch (Exception ex)
511 {
512 Log.Exception(ex);
513 // Ignore
514 }
515
516 if (!(ToCall is null))
517 {
518 foreach (OutputRec Rec in ToCall)
519 await Rec.Callback.Raise(this, new DeliveryEventArgs(Rec.State, false));
520 }
521 }
522 catch (Exception ex)
523 {
524 Log.Exception(ex);
525 }
526 }
527
528
535 public override async Task<bool> BeginWrite(string Xml, EventHandlerAsync<DeliveryEventArgs> Callback, object State)
536 {
537 if (this.disposed)
538 return false;
539
540 if (string.IsNullOrEmpty(Xml))
541 await Callback.Raise(this, new DeliveryEventArgs(State, true));
542 else
543 {
544 HttpResponse Response = null;
545 DateTime Now = DateTime.Now;
546 long? Rid;
547 string Echo;
548
549 this.nrEmpty = 0;
550
551 if (!await this.syncObjOutput.TryBeginWrite(10000))
552 throw new TimeoutException("Unable to get access to session.");
553
554 try
555 {
556 if (this.waiting is null)
557 {
558 this.outputQueue.AddLast(new OutputRec()
559 {
560 Payload = Xml,
561 Callback = Callback,
562 State = State
563 });
564 return true;
565 }
566
567 Response = this.waiting;
568 Rid = this.waitingRid;
569 Echo = this.waitingEcho;
570 this.waiting = null;
571 this.waitingRid = null;
572 this.waitingEcho = null;
573 }
574 finally
575 {
576 await this.syncObjOutput.EndWrite();
577 }
578
579 try
580 {
581 StringBuilder Xml2 = new StringBuilder();
582
583 Xml2.Append("<body from='");
584 Xml2.Append(XML.Encode(this.to));
585
586 if (Rid.HasValue)
587 {
588 Xml2.Append("' ack='");
589 Xml2.Append(Rid.Value.ToString());
590 this.RidReturnedLocked(Rid.Value);
591 }
592
593 if (!string.IsNullOrEmpty(Echo))
594 {
595 Xml2.Append("' echo='");
596 Xml2.Append(XML.Encode(Echo));
597 }
598
599 Xml2.Append("' xmlns='");
601
602 if (this.State != XmppConnectionState.Active)
603 {
604 Xml2.Append("' xmlns:stream='");
606 }
607
608 Xml2.Append("'>");
609 Xml2.Append(Xml);
610 Xml2.Append("</body>");
611
612 string Tx = Xml2.ToString();
613 await this.webResource.Return(Response, Tx);
614 await this.TransmitText(Tx);
615 }
616 catch (Exception)
617 {
618 // Ignore
619
620 return false;
621 }
622
623 await Callback.Raise(this, new DeliveryEventArgs(State, true));
624 }
625
626 return true;
627 }
628
635 public override Task<bool> StreamError(string ErrorXml, string Reason)
636 {
637 return this.ToError("<stream:error>" + ErrorXml + "</stream:error>", Reason);
638 }
639
640 private async Task<bool> ToError(string ErrorXml, string Reason)
641 {
642 this.terminated = true;
643 this.removed = true;
644 BoshWebClientResource.Remove(this);
645
646 Log.Error("Terminating session. " + Reason, this.FullJid);
647
648 if (string.IsNullOrEmpty(ErrorXml))
649 {
650 await this.SetState(XmppConnectionState.Error);
651 return false;
652 }
653 else
654 {
655 return await this.BeginWrite(ErrorXml, async (Sender, e) =>
656 {
657 await this.SetState(XmppConnectionState.Error);
658 }, null);
659 }
660 }
661
662 private async Task<bool> ProcessFragment(string Xml, Stream Stream)
663 {
664 XmlDocument Doc;
665
666 try
667 {
668 if (!string.IsNullOrEmpty(this.fullJid))
669 this.server.TouchClientConnection(this.fullJid);
670
671 Doc = new XmlDocument()
672 {
673 PreserveWhitespace = true
674 };
675 Doc.LoadXml("<body xmlns='" + BoshWebClientResource.HttpBindNamespace + "'>" + Xml + "</body>");
676
677 return await this.ProcessStanzas(Doc.DocumentElement, Stream);
678 }
679 catch (Exception ex)
680 {
681 await this.Exception(ex);
682 await this.StreamError("<bad-format xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>", ex.Message);
683
684 return false;
685 }
686 }
687
688 internal async Task<bool> ProcessStanzasInOrder(long Rid, XmlElement RootElement, Stream Stream, string Key)
689 {
690 bool Process = false;
691
692 if (this.terminated)
693 return false;
694
695 if (!await this.syncObjInput.TryBeginWrite(10000))
696 throw new TimeoutException("Unable to get access to session.");
697
698 try
699 {
700 if (!this.lastRid.HasValue || Rid == this.lastRid.Value + 1)
701 {
702 if (!this.CheckNextKey(Key))
703 return false;
704
705 this.lastRid = Rid;
706 Process = true;
707 }
708 else
709 {
710 if (this.inputQueue.Count >= this.hold || (Rid - this.lastRid.Value) > this.requests)
711 {
712 this.terminated = true;
713 this.terminationCondition = "item-not-found";
714 }
715 else
716 this.inputQueue.AddLast((Rid, RootElement, Stream, Key));
717
718 Process = false;
719 }
720 }
721 finally
722 {
723 await this.syncObjInput.EndWrite();
724 }
725
726 if (this.terminated)
727 Log.Error("Terminating session. Too many incoming requests.", this.fullJid);
728 else if (Process)
729 {
730 bool FirstElement = true;
731
732 do
733 {
734 if (FirstElement)
735 FirstElement = false;
736
737 XmlElement RootElement0 = RootElement;
738 Stream Stream0 = Stream;
739
740 LinkedListNode<(long, XmlElement, Stream, string)> First;
741 (long, XmlElement, Stream, string) Rec;
742
743 if (!await this.syncObjInput.TryBeginWrite(10000))
744 throw new TimeoutException("Unable to get access to session.");
745
746 try
747 {
748 if (!((First = this.inputQueue.First) is null) &&
749 (Rec = First.Value).Item1 == Rid + 1)
750 {
751 do
752 {
753 RootElement = Rec.Item2;
754 Stream = Rec.Item3;
755 Key = Rec.Item4;
756 this.inputQueue.RemoveFirst();
757
758 if (this.CheckNextKey(Key))
759 this.lastRid = Rid;
760 else
761 RootElement = null;
762 }
763 while (RootElement is null &&
764 !((First = this.inputQueue.First) is null) &&
765 (Rec = First.Value).Item1 == Rid + 1);
766
767 if (!(RootElement is null))
768 Rid++;
769 }
770 else
771 RootElement = null;
772 }
773 finally
774 {
775 await this.syncObjInput.EndWrite();
776 }
777
778 try
779 {
780 if (!await this.ProcessStanzas(RootElement0, Stream0))
781 return false;
782 }
783 catch (Exception ex)
784 {
785 await this.Exception(ex);
786 }
787 }
788 while (!(RootElement is null));
789 }
790
791 return true;
792 }
793
794 internal bool CheckNextKey(string Key)
795 {
796 if (Key is null)
797 {
798 if (!(this.key is null))
799 return false;
800 }
801 else
802 {
803 string PrevKey = Hashes.ComputeSHA1HashString(Encoding.ASCII.GetBytes(Key));
804 int i, c = PrevKey.Length;
805
806 if (c != this.key.Length)
807 return false;
808
809 for (i = 0; i < c; i++)
810 {
811 if (PrevKey[i] != this.key[i])
812 return false;
813 }
814
815 this.key = Key;
816 }
817
818 return true;
819 }
820
825 protected override SslStream GetSslStream()
826 {
827 return this.currentStream as SslStream;
828 }
829
830 internal async Task<bool> ProcessStanzas(XmlElement RootElement, Stream Stream)
831 {
832 try
833 {
834 if (this.HasSniffers)
835 await this.ReceiveText(RootElement.OuterXml);
836
837 int Count = 0;
838
839 foreach (XmlNode N in RootElement.ChildNodes)
840 {
841 if (N is XmlElement E)
842 {
843 Count++;
844
845 try
846 {
847 Stanza Stanza = new Stanza(RootElement, E, RootElement.InnerXml);
848
849 this.currentStream = Stream;
850 if (!await this.ProcessStanza(Stanza))
851 return false;
852 }
853 catch (Exception ex)
854 {
855 await this.Exception(ex);
856 if (!await this.StreamError("<bad-format xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>", ex.Message))
857 return false;
858 }
859 }
860 }
861
862 if (Count == 0)
863 {
864 if (this.State != XmppConnectionState.Active)
865 {
866 StringBuilder Xml = new StringBuilder();
867 await this.InitStream(Xml, Stream as SslStream);
868 if (!await this.BeginWrite(Xml.ToString(), null, null))
869 return false;
870 }
871 else
872 {
873 DateTime Now = DateTime.Now;
874
875 if (this.nrEmpty == 0)
876 this.firstEmpty = Now;
877
878 this.nrEmpty++;
879 if (this.nrEmpty > 5)
880 {
881 double SecondsPerRequest = (Now - this.firstEmpty).TotalSeconds / this.nrEmpty;
882
883 if (SecondsPerRequest * 2 < this.pollingSeconds)
884 {
885 this.terminated = true;
886 this.terminationCondition = "policy-violation";
887 BoshWebClientResource.Remove(this);
888
889 Log.Error("Terminating session. Polling too quickly.", this.fullJid);
890 }
891 }
892 }
893 }
894 else
895 this.nrEmpty = 0;
896 }
897 catch (Exception ex)
898 {
899 Log.Exception(ex);
900 }
901
902 return true;
903 }
904
911 protected override async Task<bool> ProcessBindingSpecificStanza(Stanza Stanza, XmlElement StanzaElement)
912 {
913 return await this.StreamError("<unsupported-stanza-type xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>",
914 "Unrecognized stanza: " + StanzaElement.LocalName);
915 }
916
917 internal async Task InitStream(StringBuilder sb, SslStream SslStream)
918 {
919 sb.Append("<stream:features>");
920
921 if (!this.isAuthenticated)
922 {
923 await this.SetState(XmppConnectionState.Authenticating);
924
925 sb.Append("<mechanisms xmlns='" + XmppServer.SaslNamespace + "'>");
926
927 foreach (IAuthenticationMechanism Mechanism in XmppServer.mechanisms)
928 {
929 if (Mechanism.Allowed(SslStream))
930 {
931 sb.Append("<mechanism>");
932 sb.Append(Mechanism.Name);
933 sb.Append("</mechanism>");
934 }
935 }
936
937 sb.Append("</mechanisms>");
938
939 if (await this.server.CanRegister(this))
940 sb.Append("<register xmlns='http://jabber.org/features/iq-register'/>");
941 }
942 else if (!this.isBound)
943 {
944 await this.SetState(XmppConnectionState.Binding);
945
946 sb.Append("<bind xmlns='" + XmppClientConnection.BindNamespace + "'/>");
947 sb.Append("<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>");
948 }
949
950 sb.Append("</stream:features>");
951 }
952
953 internal void RidReturnedLocked(long Rid)
954 {
955 if (Rid > this.maxRid)
956 {
957 this.maxRid = Rid;
958 this.maxRidTimestamp = DateTime.Now;
959 }
960 }
961
966 public override bool CheckLive()
967 {
968 return !this.disposed && !this.removed && this.State != XmppConnectionState.Error && this.State != XmppConnectionState.Offline;
969 }
970
971 }
972}
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
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:1647
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:682
Task Error(string Error)
Called to inform the viewer of an error state.
Task Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
Task TransmitText(string Text)
Called when text has been transmitted.
bool HasSniffers
If there are sniffers registered on the object.
Task ReceiveText(string Text)
Called when text has been received.
Event arguments for delivery events.
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:21
CaseInsensitiveString From
From address
Definition: BoshSession.cs:129
override SslStream GetSslStream()
Returns the underlying encrypted stream.
Definition: BoshSession.cs:825
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
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 Task< bool > StreamError(string ErrorXml, string Reason)
Returns a stream error.
Definition: BoshSession.cs:635
override bool CheckLive()
Checks if the connection is live.
Definition: BoshSession.cs:966
int WaitSeconds
Maximum time (in seconds) to wait.
Definition: BoshSession.cs:149
override async Task DisposeAsync()
IDisposable.Dispose
Definition: BoshSession.cs:217
override string RemoteEndpoint
Remote endpoint.
Definition: BoshSession.cs:207
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:535
int Requests
Number of simultaneous requests open.
Definition: BoshSession.cs:159
override async Task< bool > ProcessBindingSpecificStanza(Stanza Stanza, XmlElement StanzaElement)
Processes a binding-specific stanza.
Definition: BoshSession.cs:911
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:10
const string SaslNamespace
urn:ietf:params:xml:ns:xmpp-sasl
Definition: XmppServer.cs:108
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:26
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
Definition: Scheduler.cs:182
DateTime Add(DateTime When, ScheduledEventCallback Callback, object State)
Adds an event.
Definition: Scheduler.cs:66
Contains methods for simple hash calculations.
Definition: Hashes.cs:59
static string ComputeSHA1HashString(byte[] Data)
Computes the SHA-1 hash of a block of binary data.
Definition: Hashes.cs:274
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:11
XmppConnectionState
State of XMPP connection.