Skip to main content

Porting MSG_MORE and MSG_NOSIGPIPE to OS X

·2 mins

I recently needed to port the following line of networking code in Ceph to OS X (Ceph is developed almost exclusively on Linux). The MSG_MORE flag is an optimization used to inform the networking layer that more data is going to be sent shortly. The MSG_NOSIGNAL flag is used to block SIGPIPE. Unfortunately both of these macros are not defined on OS X.

sendmsg(sd, msg, MSG_NOSIGNAL | (more ? MSG_MORE : 0));

First, since the MSG_MORE flag is an optimization, we can turn it off if it isn’t available (note that while reading about MSG_MORE, it seems that a solution based on TCP_CORK may be possible, but that is for another time).

#ifndef MSG_MORE
# define MSG_MORE 0
#endif

As for MSG_NOSIGNAL, luckily OS X has a mechanism for blocking SIGPIPE, but not nearly as convenient. First, we need to detect when MSG_NOSIGNAL is not defined, and provide a compatibility macro definition that won’t affect the bitmask flags.

#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
# ifdef SO_NOSIGPIPE
#  define CEPH_USE_SO_NOSIGPIPE
# else
#  error "Cannot block SIGPIPE!"
# endif
#endif

Finally, we can use the SO_NOSIGPIPE socket option to block SIGPIPE when MSG_NOSIGNAL is not defined. The socket option can be set right after the socket is initially opened.

#ifdef CEPH_USE_SO_NOSIGPIPE
int val = 1;
int r = setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val));
if (r) {
    r = -errno;
    ldout(msgr->cct,0) << "couldn't set SO_NOSIGPIPE: " << cpp_strerror(r) << dendl;
}
#endif