private synchronized void sendMessage(ApnsNotification m, boolean fromBuffer) throws NetworkIOException {
        logger.debug("sendMessage {} fromBuffer: {}", m, fromBuffer);

        if (delegate instanceof StartSendingApnsDelegate) {
            ((StartSendingApnsDelegate) delegate).startSending(m, fromBuffer);
        }

        int attempts = 0;
        while (true) {
            try {
                attempts++;
                Socket socket = getOrCreateSocket(fromBuffer);
                socket.getOutputStream().write(m.marshall());
                socket.getOutputStream().flush();
                cacheNotification(m);

                delegate.messageSent(m, fromBuffer);

                //logger.debug("Message \"{}\" sent", m);
                attempts = 0;
                break;
            } catch (SSLHandshakeException e) {
                // No use retrying this, it's dead Jim
                throw new NetworkIOException(e);
            } catch (IOException e) {
                Utilities.close(socket);
                if (attempts >= RETRIES) {
                    logger.error("Couldn't send message after " + RETRIES + " retries." + m, e);
                    delegate.messageSendFailed(m, e);
                    Utilities.wrapAndThrowAsRuntimeException(e);
                }
                // The first failure might be due to closed connection (which in turn might be caused by
                // a message containing a bad token), so don't delay for the first retry.
                //
                // Additionally we don't want to spam the log file in this case, only after the second retry
                // which uses the delay.

                if (attempts != 1) {
                    logger.info("Failed to send message " + m + "... trying again after delay", e);
                    Utilities.sleep(DELAY_IN_MS);
                }
            }
        }
    }
Read a packet like in.readFully(bytes) does - but do not throw an exception and return false if nothing
could be read at all.
@param in the input stream
@param bytes the array to be filled with data
@return true if a packet as been read, false if the stream was at EOF right at the beginning.
@throws IOException When a problem occurs, especially EOFException when there's an EOF in the middle of the packet.
src/main/java/com/notnoop/apns/internal/ApnsConnectionImpl.java