8 Replies
      Latest reply: Sep 11, 2017 1:33 AM by eskimo RSS
      Alexandmrwh Level 1 Level 1 (0 points)

        The same code works fine with iOS10.1, but when I update it to 10.2, this problem arises.

        I used the bsd socket to send a UDP message to other devices.

        The 'sendto' function always fails with error code "operation not permitted" while it never happens with a 10.1 device.

        Any ideas why? Thank you very much.

        • Re: iOS 10.2 socket issue
          eskimo Apple Staff Apple Staff (7,505 points)

          “operation not permitted” is EPERM.  I’m not aware of any general problem with UDP sends generating this error on iOS 10.2.  You should use the debugger to look at the exact parameters you’re passing to sendto, paying specific attention to the address you’re passing in.

          If you can’t figure it out from that, post the relevant snippets of code and I can take a look.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: iOS 10.2 socket issue
              Alexandmrwh Level 1 Level 1 (0 points)

              If I bind a socket to a certain port and start listen to it, everything goes fine and I can receive the data. But I couldnt use the same socket to send data to others, it will tell me that operation is not permitted.

              If I create a new socket, I can just send data without any problem. So it seems to me that I cannot use the same socket to send and receive UDP data??

              It never occurred in 10.1, so I took it for granted that you guys blocked this function. But I still need to use one socket to send and recv, so would you please check on it??

                • Re: iOS 10.2 socket issue
                  eskimo Apple Staff Apple Staff (7,505 points)

                  So it seems to me that I cannot use the same socket to send and receive UDP data?

                  It’s not that simple.  Below you’ll find pasted in some simple UDP test code which will happily send and receive from the same socket.  In this example:

                  • The view controller manages a table view with two items, one to send and another to receive.

                  • I ran it on my iPhone, running 10.2, which was on my office Wi-Fi.

                  • 192.168.1.189 is the IP address of my Mac on the same Wi-Fi.

                  • 192.168.1.184 is the IP address of my iPhone.

                  • I tested the send and receive by running nc on my Mac, as shown below.


                  $ nc -u -l 12345
                  Hello Cruel World! 2016-12-21 10:09:34 +0000
                  Hello Cruel World! 2016-12-21 10:10:45 +0000
                  …
                  

                  $ nc -u 192.168.1.184 12345
                  Hello iPhone 1!
                  Hello again iPhone!   
                  …
                  

                  I recommend that you repeat my test and see if you get the same results.  If you do, you can then try to modify the test to reproduce the problem you’re seeing.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                  #import "MainViewController.h"
                  
                  #include <sys/socket.h>
                  #include <netinet/in.h>
                  #include <arpa/inet.h>
                  #include <netdb.h>
                  
                  @interface MainViewController ()
                  
                  @property (nonatomic, assign, readwrite) int sock;
                  
                  @end
                  
                  @implementation MainViewController
                  
                  - (void)viewDidLoad {
                      [super viewDidLoad];
                      self.sock = -1;
                  }
                  
                  - (void)sendTest {
                      struct sockaddr_in addr = {
                          .sin_len = sizeof(struct sockaddr),
                          .sin_family = AF_INET,
                          .sin_port = htons(12345),
                          .sin_addr.s_addr = inet_addr("192.168.1.189")
                      };
                  
                      NSString * message = [NSString stringWithFormat:@"Hello Cruel World! %@\r\n", [NSDate date]];
                      NSData * messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
                      ssize_t bytesSent = sendto(
                          self.sock,
                          messageData.bytes,
                          messageData.length,
                          0,
                          (const struct sockaddr *) &addr,
                          sizeof(addr)
                      );
                      if (bytesSent < 0) {
                          NSLog(@"send failed: %d", errno);
                      } else {
                          NSLog(@"sent %zd bytes", bytesSent);
                      }
                  }
                  
                  - (void)receiveTest {
                      struct sockaddr_storage addr;
                      socklen_t addrLen = sizeof(addr);
                      NSMutableData * bufferData = [[NSMutableData alloc] initWithLength:2048];
                      ssize_t bytesReceived = recvfrom(
                          self.sock,
                          bufferData.mutableBytes,
                          bufferData.length, 0,
                          (struct sockaddr *)
                          &addr,
                          &addrLen
                      );
                      if (bytesReceived < 0) {
                          if (errno == EAGAIN) {
                              NSLog(@"nothing to receive");
                          } else {
                              NSLog(@"received failed: %d", errno);
                          }
                      } else {
                          char host[NI_MAXHOST];
                          bufferData.length = (NSUInteger) bytesReceived;
                          BOOL success = getnameinfo(
                              (const struct sockaddr *) &addr,
                              addrLen,
                              host,
                              sizeof(host),
                              NULL,
                              0,
                              NI_NUMERICHOST | NI_NUMERICSERV
                          ) == 0;
                          assert(success);
                          NSLog(@"received %@ from %s", bufferData, host);
                      }
                  }
                  
                  - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
                      #pragma unused(tableView)
                      #pragma unused(indexPath)
                  
                      if (self.sock == -1) {
                          self.sock = socket(AF_INET, SOCK_DGRAM, 0);
                          assert(self.sock >= 0);
                  
                          BOOL success = fcntl(self.sock, F_SETFL, O_NONBLOCK) == 0;
                          assert(success);
                  
                          struct sockaddr_in addr = {
                              .sin_len = sizeof(struct sockaddr),
                              .sin_family = AF_INET,
                              .sin_port = htons(12345)
                          };
                          success = bind(self.sock, (const struct sockaddr *) &addr, sizeof(addr)) == 0;
                          assert(success);
                      }
                  
                      switch (indexPath.row) {
                          case 0: {
                              [self sendTest];
                          } break;
                          case 1: {
                              [self receiveTest];
                          } break;
                          default: {
                              abort();
                          } break;
                      }
                  
                      [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
                  }
                  
                  @end
                  
                    • Re: iOS 10.2 socket issue
                      ShaunMurphy Level 1 Level 1 (0 points)

                      We're seeing the same thing with our app but reading & writing via GCDAsyncSocket. It works fine in 10.1 but as soon as we upgrade a device to 10.2 our app is only able to communicate in one direction.

                      • Re: iOS 10.2 socket issue
                        PGMichael Level 1 Level 1 (0 points)

                        We are seeing an issue as well with 10.2. With out changing anything other than upgrading a device to 10.2 we are no longer able to communicate on a socket. Any device that we have tested with 10.1 or below is fine, but the moment we upgrade to 10.2 it no longer works. One thing of note is we are using only using ipv6, and we are seeing this with TCP sockets.

                          • Re: iOS 10.2 socket issue
                            eskimo Apple Staff Apple Staff (7,505 points)

                            ShaunMurphy wrote:

                            We're seeing the same thing with our app …

                            PGMichael wrote:

                            We are seeing an issue as well with 10.2.

                            I recommend you both repeat the test I described in my 21 Dec post and see what you get.

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: iOS 10.2 socket issue
                                hdx Level 1 Level 1 (0 points)

                                Hi, I use your code for test. The result is :

                                On my office Wi-Fi, iPad send to Simulator, both send and recv success, the iPad not link to iMac with cable.

                                On my office Wi-Fi, iPad send to iPad, both send and recv failure.

                                Use my phone hotspot, iPad send to Simulator, both send and recv success, the iPad not link to iMac with cable.

                                Use my phone hotspot, iPad send to iPad, both send and recv success.

                                 

                                Why iPad send to iPad failure when use Wi-Fi?

                                Can you give me some help?

                                Thank you very much!

                                  • Re: iOS 10.2 socket issue
                                    eskimo Apple Staff Apple Staff (7,505 points)

                                    On my office Wi-Fi, iPad send to iPad, both send and recv failure.

                                    There’s a variety of possibilities here, the most obvious being that your office Wi-Fi is blocking STA-to-STA traffic for iOS devices (be aware I’m using Wi-Fi specific terminology here; read Wi-Fi Fundamentals for the background to this).  However, that’s just one of many different possibilities and to get to the bottom of this you need to start dividing up the problem space.  To that end I recommend that you take a look at my Investigating Network Latency Problems post.  While the focus of that post is something different entirely, it describes how you can tap into the networking stack at each hop, and you can use that to track down where things are going wrong.

                                    Share and Enjoy

                                    Quinn “The Eskimo!”
                                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                    let myEmail = "eskimo" + "1" + "@apple.com"