summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go')
-rw-r--r--Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go102
1 files changed, 102 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go b/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go
new file mode 100644
index 000000000..32e7f0f15
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/anachronistic/apns/feedback.go
@@ -0,0 +1,102 @@
+package apns
+
+import (
+ "bytes"
+ "crypto/tls"
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "net"
+ "strings"
+ "time"
+)
+
+// Wait at most this many seconds for feedback data from Apple.
+const FeedbackTimeoutSeconds = 5
+
+// FeedbackChannel will receive individual responses from Apple.
+var FeedbackChannel = make(chan (*FeedbackResponse))
+
+// If there's nothing to read, ShutdownChannel gets a true.
+var ShutdownChannel = make(chan bool)
+
+// FeedbackResponse represents a device token that Apple has
+// indicated should not be sent to in the future.
+type FeedbackResponse struct {
+ Timestamp uint32
+ DeviceToken string
+}
+
+// NewFeedbackResponse creates and returns a FeedbackResponse structure.
+func NewFeedbackResponse() (resp *FeedbackResponse) {
+ resp = new(FeedbackResponse)
+ return
+}
+
+// ListenForFeedback connects to the Apple Feedback Service
+// and checks for device tokens.
+//
+// Feedback consists of device tokens that should
+// not be sent to in the future; Apple *does* monitor that
+// you respect this so you should be checking it ;)
+func (client *Client) ListenForFeedback() (err error) {
+ var cert tls.Certificate
+
+ if len(client.CertificateBase64) == 0 && len(client.KeyBase64) == 0 {
+ // The user did not specify raw block contents, so check the filesystem.
+ cert, err = tls.LoadX509KeyPair(client.CertificateFile, client.KeyFile)
+ } else {
+ // The user provided the raw block contents, so use that.
+ cert, err = tls.X509KeyPair([]byte(client.CertificateBase64), []byte(client.KeyBase64))
+ }
+
+ if err != nil {
+ return err
+ }
+
+ gatewayParts := strings.Split(client.Gateway, ":")
+ conf := &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ ServerName: gatewayParts[0],
+ }
+
+ conn, err := net.Dial("tcp", client.Gateway)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetReadDeadline(time.Now().Add(FeedbackTimeoutSeconds * time.Second))
+
+ tlsConn := tls.Client(conn, conf)
+ err = tlsConn.Handshake()
+ if err != nil {
+ return err
+ }
+
+ var tokenLength uint16
+ buffer := make([]byte, 38, 38)
+ deviceToken := make([]byte, 32, 32)
+
+ for {
+ _, err := tlsConn.Read(buffer)
+ if err != nil {
+ ShutdownChannel <- true
+ break
+ }
+
+ resp := NewFeedbackResponse()
+
+ r := bytes.NewReader(buffer)
+ binary.Read(r, binary.BigEndian, &resp.Timestamp)
+ binary.Read(r, binary.BigEndian, &tokenLength)
+ binary.Read(r, binary.BigEndian, &deviceToken)
+ if tokenLength != 32 {
+ return errors.New("token length should be equal to 32, but isn't")
+ }
+ resp.DeviceToken = hex.EncodeToString(deviceToken)
+
+ FeedbackChannel <- resp
+ }
+
+ return nil
+}