18129b745b5d76a65727a0ddfcae979b46943954
[svn42.git] / go / r3-netstatus / r3xmppbot / ping.go
1 // (c) Bernhard Tittelbach, 2013
2
3 package r3xmppbot
4
5 import (
6         "encoding/xml"
7         "time"
8
9         xmpp "code.google.com/p/goexmpp"
10 )
11
12 // XMPP Ping
13 type XMPPPing struct {
14         XMLName xml.Name `xml:"urn:xmpp:ping ping"`
15 }
16
17 func HandleServerToClientPing(iq *xmpp.Iq, xmppout chan<- xmpp.Stanza) bool {
18         ///<iq from='juliet@capulet.lit/balcony' to='capulet.lit' id='s2c1' type='result'/>
19         if iq.Type != "get" {
20                 return false
21         }
22         for _, ele := range iq.Nested {
23                 if _, ok := ele.(*XMPPPing); ok {
24                         xmppout <- &xmpp.Iq{Header: xmpp.Header{To: iq.From, From: iq.To, Id: iq.Id, Type: "result"}}
25                         return true
26                 }
27         }
28         return false
29 }
30
31 func (botdata *XmppBot) PingServer(timeout_ms time.Duration) (is_up bool) {
32         ///<iq from='juliet@capulet.lit/balcony' to='capulet.lit' id='c2s1' type='get'>
33         ///  <ping xmlns='urn:xmpp:ping'/>
34         ///</iq>
35         server_jid := new(xmpp.JID)
36         server_jid.Set(botdata.my_jid_)
37         iqping := &xmpp.Iq{Header: xmpp.Header{To: server_jid.Domain,
38                 From:   botdata.my_jid_,
39                 Id:     <-xmpp.Id,
40                 Type:   "get",
41                 Nested: []interface{}{XMPPPing{}}}}
42         pong := make(chan bool, 1)
43         defer close(pong)
44         f := func(v xmpp.Stanza) bool {
45                 defer recover() //recover from writing to possibly already closed chan
46                 let_others_handle_stanza := false
47                 iq, ok := v.(*xmpp.Iq)
48                 if !ok {
49                         Syslog_.Printf("response to iq ping wasn't iq: %s", v)
50                         pong <- false
51                         return true //let other handlers process reply
52                 }
53                 if iq.Type == "error" && iq.Error != nil && iq.Error.Type == "cancel" {
54                         Debug_.Printf("response to iq ping was cancel, server does not support ping")
55                         //server does not support ping, but at least we know server is still there
56                 } else if iq.Type != "result" {
57                         Syslog_.Printf("response to iq ping was not pong: %s", v)
58                         let_others_handle_stanza = true //let other handlers process reply
59                 }
60                 pong <- true
61                 return let_others_handle_stanza // return false so that Stanza v will not be appear in xmppclient_.Out()
62         }
63         botdata.xmppclient_.HandleStanza(iqping.Id, f)
64         botdata.xmppclient_.Out <- iqping
65         go func() {
66                 defer func() {
67                         if x := recover(); x == nil {
68                                 Syslog_.Printf("response to iq ping timed out !!")
69                         }
70                 }() //recover from writing to possibly already closed chan. If we did not need to recover, then Handler did not receive reply
71                 time.Sleep(timeout_ms * time.Millisecond)
72                 pong <- false //xmpp ping timed out
73         }()
74         return <-pong
75 }