Repository: nanomsg/nng (c)

Issue:
macOS support for NNG_OPT_IPC_PEER_PID
## NNG & Platform details.

NNG 1.3.0, macOS 10.9+

## Expected Behavior

When using ipc protocol on macOS, `NNG_OPT_IPC_PEER_PID` should return the peer PID

## Actual Behavior

`NNG_OPT_IPC_PEER_PID` returns `NNG_ENOTSUP`

## Steps to Reproduce

```
#import <Foundation/Foundation.h>

#include "include/nng/nng.h"
#include "include/nng/protocol/pair1/pair.h"

void pipe_notify(nng_pipe pipe, nng_pipe_ev ev, void* ctx)
{
	uint64_t pid = 0, gid = 0, uid = 0;
	nng_pipe_getopt_uint64(pipe, NNG_OPT_IPC_PEER_PID, &pid);
	nng_pipe_getopt_uint64(pipe, NNG_OPT_IPC_PEER_GID, &gid);
	nng_pipe_getopt_uint64(pipe, NNG_OPT_IPC_PEER_UID, &uid);

	printf("pipe_notify: %llu\n %llu\n %llu\n", pid, gid, uid); // PID is 0 on macOS
}

int server(const char *url)
{
	nng_socket sock;

	nng_pair1_open(&sock);
	nng_pipe_notify(sock, NNG_PIPE_EV_ADD_POST, pipe_notify, nil);
	nng_listen(sock, url, NULL, 0);
	printf("listening...\n");

	for (;;) { }
}

int client(const char *url)
{
	nng_socket sock;

	nng_pair1_open(&sock);
	nng_dial(sock, url, NULL, 0);
	nng_close(sock);
	return 0;
}

int main(int argc, const char * argv[]) {
	@autoreleasepool {
		const char* url = "ipc://nng_test";

		if (!strcasecmp(argv[1], "server"))
			server(url);
		else
			client(url);
	}
	return 0;
}
```


Pull request description:
Support NNG_OPT_IPC_PEER_PID on modern macOS systems
fixes #1255 macOS support for NNG_OPT_IPC_PEER_PID

`ipc_peerid` in posix_ipcconn.c uses `getpeereid` even on systems with the `LOCAL_PEERCRED` socket option. If `LOCAL_PEERCRED` is available, use it instead and allow retrieving the peer PID if `LOCAL_PEERPID` is available.

`LOCAL_PEERPID` is documented on macOS since 10.8. 

We assume anyone building nng on a Mac is using >10.8. At runtime, the option may still be available in the kernel depending on the macOS version, but otherwise, the existing behaviour is retained (return `NNG_ENOTSUP`)

Finally, the check for `LOCAL_PEERID` is elevated into `NNG_HAVE_LOCALPEERPID` so we can check in the ipc unit test.


Patch:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 700a0e08..7125e572 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -341,6 +341,7 @@ else ()
     nng_check_sym(SO_PEERCRED sys/socket.h NNG_HAVE_SOPEERCRED)
     nng_check_struct_member(sockpeercred uid sys/socket.h NNG_HAVE_SOCKPEERCRED)
     nng_check_sym(LOCAL_PEERCRED sys/un.h NNG_HAVE_LOCALPEERCRED)
+    nng_check_sym(LOCAL_PEERPID sys/un.h NNG_HAVE_LOCALPEERPID)
     nng_check_sym(getpeerucred ucred.h NNG_HAVE_GETPEERUCRED)
     nng_check_sym(atomic_flag_test_and_set stdatomic.h NNG_HAVE_STDATOMIC)
 
diff --git a/src/platform/posix/posix_ipcconn.c b/src/platform/posix/posix_ipcconn.c
index e4d783f3..8dded3a3 100644
--- a/src/platform/posix/posix_ipcconn.c
+++ b/src/platform/posix/posix_ipcconn.c
@@ -318,7 +318,7 @@ ipc_peerid(ipc_conn *c, uint64_t *euid, uint64_t *egid, uint64_t *prid,
     uint64_t *znid)
 {
 	int fd = nni_posix_pfd_fd(c->pfd);
-#if defined(NNG_HAVE_GETPEEREID)
+#if defined(NNG_HAVE_GETPEEREID) && !defined(NNG_HAVE_LOCALPEERCRED)
 	uid_t uid;
 	gid_t gid;
 
@@ -373,7 +373,7 @@ ipc_peerid(ipc_conn *c, uint64_t *euid, uint64_t *egid, uint64_t *prid,
 	*egid = xu.cr_gid;
 	*prid = (uint64_t) -1;
 	*znid = (uint64_t) -1;
-#if defined(LOCAL_PEERPID) // present (undocumented) on macOS
+#if defined(NNG_HAVE_LOCALPEERPID) // documented on macOS since 10.8
 	{
 		pid_t pid;
 		if (getsockopt(fd, SOL_LOCAL, LOCAL_PEERPID, &pid, &len) ==
@@ -381,7 +381,7 @@ ipc_peerid(ipc_conn *c, uint64_t *euid, uint64_t *egid, uint64_t *prid,
 			*prid = (uint64_t) pid;
 		}
 	}
-#endif                     // LOCAL_PEERPID
+#endif                     // NNG_HAVE_LOCALPEERPID
 	return (0);
 #else
 	if (fd < 0) {


Test patch:
diff --git a/tests/ipc.c b/tests/ipc.c
index 2446cda1..8abff2f6 100644
--- a/tests/ipc.c
+++ b/tests/ipc.c
@@ -63,7 +63,8 @@ check_props(nng_msg *msg)
 	So(nng_pipe_getopt_uint64(p, NNG_OPT_IPC_PEER_GID, &id) == 0);
 	So(id == (uint64_t) getgid());
 
-#if defined(NNG_HAVE_SOPEERCRED) || defined(NNG_HAVE_GETPEERUCRED)
+#if defined(NNG_HAVE_SOPEERCRED) || defined(NNG_HAVE_GETPEERUCRED) || \
+    (defined(NNG_HAVE_LOCALPEERCRED) && defined(NNG_HAVE_LOCALPEERPID))
 	So(nng_pipe_getopt_uint64(p, NNG_OPT_IPC_PEER_PID, &id) == 0);
 	So(id == (uint64_t) getpid());
 #else