get SSL Broken pipe error when try to make push notification
Asked Answered
T

3

19

We develop an iPhone app, and have push notification for development and ad hoc version working properly. But when we try to send push notification to real user devices in our database, we got SSL connection reset, then Broken pipe error. We think maybe there are too many devices in our database (more than 70000), so it is failed to send all messages at the same time. So we try to send messages to 1000 devices once, but still got this "Broken pipe" error for around 100 messages. And we are not sure whether the messages have been send. Any suggestion?

Towrope answered 12/4, 2010 at 23:11 Comment(1)
We're having the same issue; though with 100,000 users. As far as we can tell the notification will reach the first 100-or-so but then not after that. I can only assume there is a limit (either by count or time) on the notifications that are sent. Could really do with someone to confirm this?Resh
T
20

We have solved this problem. It is broken due to invalid tokens in our database table.And apple apns service will disconnect us if there is an invalid token. Since the connection is broken, it will have "Broken Pipe" error when you try to send messages again. Basic solution is to find whether writing to pipe is successful, if not, just disconnect and reconnect again after some delay.

Towrope answered 28/5, 2010 at 20:1 Comment(2)
I wish you had explained how you coded this – Mona Jun 14 at 23:52Favela
Usually it happen when i loop through all user's device token and if any of which fails, it breaks the chain kind of and shows same error, all we can do is sort the user with recent device token and do check length on our end, it worked after that. Thanks your answer helped me!~Decadent
R
11

emagic is correct, one reason for the "broken pipe" error can occur from invalid tokens. There are a few other reasons it can occur too. The following is from Apple Technical Note TN2265:

The most common problem is an invalid device token. If the token came from the sandbox environment, such as when you are testing a development build in house, you can't send it to the production push service. Each push environment will issue a different token for the same device or computer. If you do send a device token to the wrong environment, the push service will see that as an invalid token and discard the notification.

An invalid device token can also mean that the user has deleted your app from their device or computer. You should check the feedback service at least once a day for device tokens that are no longer valid.

Other possible issues might be sending a payload longer than 256 bytes, your payload might not be formatted correctly, or perhaps your JSON dictionary has incorrect syntax.

An occasional disconnect while your provider is idle is nothing to be concerned about; just re-establish the connection and carry on. If one of the push servers is down, the load balancing mechanism will transparently direct your new connection to another server assuming you connect by hostname and not by static IP address.

Roadblock answered 10/10, 2012 at 16:57 Comment(0)
R
2

Extending on emagic's answer, this is my php code snipplet:

private $fp;

private function connect(){ 
    $apnsHost      = 'gateway.push.apple.com'; 
    $apnsCert      = 'certs/cert.pem';
    $apnsPort      = 2195;
    $pass          = "blah";
    $streamContext = stream_context_create();

    stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
    stream_context_set_option($streamContext, 'ssl', 'passphrase', $pass);
    $this->fp = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $streamContext);
    if (!$this->fp) return("Failed to connect: $err $errstr<br>");
    echo 'Connected to APNS<hr />'; 
  }

private function send(){
  $this->connect();
  foreach($pushes as $push) {
    $payload['aps'] = array('alert' => $push->text, 'badge' => 0, 'sound' => 'default');
    $payload2 = json_encode($payload);
    $msg = chr(0) . pack('n', 32) . pack('H*', $push->token) . pack('n', strlen($payload2)) . $payload2;
    try {
      $result = fwrite($this->fp, $msg, strlen($msg));
    } 
    catch (\Exception $e) {
      fclose($this->fp);
      echo('Error sending payload: ' . $e->getMessage());
      sleep(5);
      $this->connect();
    }
  }
}
Reeducate answered 8/3, 2016 at 15:51 Comment(3)
I'm trying to use this but the try/catch doesn't seem to get triggered, even when fwrite() fails. I get console messages saying that it failed to write, but I never get the "Error sending payload" message to send. Are you sure that fwrite() actually throws exceptions?Carrick
Tried that, doesn't make a difference. The catch block is never called.Carrick
Adapted this method and it works great. Thanks for posting.Yuen

© 2022 - 2024 — McMap. All rights reserved.