func (self *apnsPushService) singlePush(payload, token []byte, expiry uint32, mid uint32, pool *connpool.Pool) { conn, err := pool.Get() if err != nil { for i := 0; i < 3; i++ { conn, err = pool.Get() if err != nil { self.logChan <- NewInfof("singlePush pool get err:%v token:%v", err, hex.EncodeToString(token)) continue } break } if err != nil { clearRequest(self.pushRet, 3, mid, 0) self.logChan <- NewInfof("Alas helpless... err:%v token:%v", err, hex.EncodeToString(token)) return } } // Total size for each notification: // // - command: 1 // - identifier: 4 // - expiry: 4 // - device token length: 2 // - device token: 32 (vary) // - payload length: 2 // - payload: vary (256 max) // // In total, 301 bytes (max) var dataBuffer [2048]byte buffer := bytes.NewBuffer(dataBuffer[:0]) // command binary.Write(buffer, binary.BigEndian, uint8(1)) // transaction id binary.Write(buffer, binary.BigEndian, mid) // Expiry binary.Write(buffer, binary.BigEndian, expiry) // device token binary.Write(buffer, binary.BigEndian, uint16(len(token))) buffer.Write(token) // payload binary.Write(buffer, binary.BigEndian, uint16(len(payload))) buffer.Write(payload) pdu := buffer.Bytes() deadline := time.Now().Add(time.Duration(maxWaitTime) * time.Second) conn.SetWriteDeadline(deadline) err = writen(conn, pdu) //self.logChan <- NewInfof("writen token::%v err:%v LocalAddr:%v cid:%v mid:%v pdu:%v", hex.EncodeToString(token), err, conn.LocalAddr(), conn.Id(), mid, len(pdu)) //fmt.Println("writen token:", hex.EncodeToString(token), " err:", err, " LocalAddr:", conn.LocalAddr(), " cid", conn.Id(), " mid:", mid) sleepTime := time.Duration(maxWaitTime) * time.Second for nrRetries := 0; err != nil && nrRetries < 3; nrRetries++ { self.logChan <- NewInfof("error on connection with %v. Will retry within %v %v", err, sleepTime, hex.EncodeToString(token)) conn.Close() time.Sleep(sleepTime) // randomly wait more time sleepTime += time.Duration(rand.Int63n(int64(sleepTime))) // Let's try another connection to see if we can recover this error conn, err = pool.Get() if err != nil { self.logChan <- NewInfof("We are unable to get a connection: %v", err) if conn != nil { conn.Close() } return } deadline := time.Now().Add(sleepTime) conn.SetWriteDeadline(deadline) err = writen(conn, pdu) } if err != nil { clearRequest(self.pushRet, 3, mid, 0) self.logChan <- NewInfof("token send fail: %v err:%v LocalAddr:%v", hex.EncodeToString(token), err, conn.LocalAddr()) } else { clearRequest(self.pushRet, 1, mid, conn.Id()) } conn.SetWriteDeadline(time.Time{}) conn.Close() }