diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-01-24 19:26:31 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-01-24 19:42:43 -0800 |
| commit | e88f07b434dbcfdb57435a14e1beadcdae3cef0d (patch) | |
| tree | 79433ae3c4ed6d2501e4d63ad9ada5a621df3bd9 /src/nng_compat.c | |
| parent | 907a1eb392ca4b29c62b9cc3d2df1ad337695abf (diff) | |
| download | nng-e88f07b434dbcfdb57435a14e1beadcdae3cef0d.tar.gz nng-e88f07b434dbcfdb57435a14e1beadcdae3cef0d.tar.bz2 nng-e88f07b434dbcfdb57435a14e1beadcdae3cef0d.zip | |
Add endpoint tuning of maxrcv size. Fix cmsg API.
The CMSG handling was completely borked. This is fixed now, and
we stash the SP header size (ugh) in the CMSG contents to match what
nanomsg does. We now pass the cmsg validation test.
We also fixed handling of certain endpoint-related options, so that
endpoints can get options from the socket at initialization time.
This required a minor change to the transport API for endpoints.
Finally, we fixed a critical fault in the REP handling of RAW sockets,
which caused them to always return NNG_ESTATE in all cases. It should
now honor the actual socket option.
Diffstat (limited to 'src/nng_compat.c')
| -rw-r--r-- | src/nng_compat.c | 93 |
1 files changed, 83 insertions, 10 deletions
diff --git a/src/nng_compat.c b/src/nng_compat.c index fd43af29..04759e01 100644 --- a/src/nng_compat.c +++ b/src/nng_compat.c @@ -401,9 +401,12 @@ nn_recvmsg(int s, struct nn_msghdr *mh, int flags) char *cdata; size_t clen; size_t tlen; + size_t spsz; struct nn_cmsghdr *hdr; + unsigned char *ptr; - clen = NN_CMSG_SPACE(nng_msg_header_len(msg)); + spsz = nng_msg_header_len(msg); + clen = NN_CMSG_SPACE(sizeof (spsz) + spsz); if ((tlen = mh->msg_controllen) == NN_MSG) { // Ideally we'd use the same msg, but we would need @@ -429,13 +432,15 @@ nn_recvmsg(int s, struct nn_msghdr *mh, int flags) } if (clen <= tlen) { + ptr = NN_CMSG_DATA(cdata); hdr = (void *) cdata; - hdr->cmsg_len = nng_msg_header_len(msg); + hdr->cmsg_len = clen; hdr->cmsg_level = PROTO_SP; hdr->cmsg_type = SP_HDR; - memcpy(NN_CMSG_DATA(cdata), nng_msg_header(msg), - nng_msg_header_len(msg)); + memcpy(ptr, &spsz, sizeof (spsz)); + ptr += sizeof (spsz); + memcpy(ptr, nng_msg_header(msg), spsz); } } @@ -451,7 +456,7 @@ nn_sendmsg(int s, const struct nn_msghdr *mh, int flags) { nng_msg *msg = NULL; nng_msg *cmsg = NULL; - char *cdata = NULL; + char *cdata; int keep = 0; size_t sz; int rv; @@ -497,9 +502,16 @@ nn_sendmsg(int s, const struct nn_msghdr *mh, int flags) } // Now suck up the control data... + // This POSIX-inspired API is one of the most painful for + // usability we've ever seen. cmsg = NULL; if ((cdata = mh->msg_control) != NULL) { size_t clen; + size_t offs; + size_t spsz; + struct nn_cmsghdr *chdr; + unsigned char *data; + if ((clen = mh->msg_controllen) == NN_MSG) { // Underlying data is a message. This is awkward, // because we have to copy the data, but we should @@ -508,13 +520,42 @@ nn_sendmsg(int s, const struct nn_msghdr *mh, int flags) cdata = *(void **) cdata; cmsg = *(nng_msg **) (cdata - sizeof (cmsg)); clen = nng_msg_len(cmsg); + } else { + clen = mh->msg_controllen; } - if ((rv = nng_msg_append_header(msg, cdata, clen)) != 0) { - if (!keep) { - nng_msg_free(msg); + + offs = 0; + while ((offs + sizeof (NN_CMSG_LEN(0))) < clen) { + chdr = (void *) (cdata + offs); + if ((chdr->cmsg_level != PROTO_SP) || + (chdr->cmsg_type != SP_HDR)) { + offs += chdr->cmsg_len; } - nn_seterror(rv); - return (-1); + + // SP header in theory. Starts with size, then + // any backtrace details. + if (chdr->cmsg_len < sizeof (size_t)) { + offs += chdr->cmsg_len; + continue; + } + data = NN_CMSG_DATA(chdr); + memcpy(&spsz, data, sizeof (spsz)); + if ((spsz + sizeof (spsz)) > chdr->cmsg_len) { + // Truncated header? Ignore it. + offs += chdr->cmsg_len; + continue; + } + data += sizeof (spsz); + rv = nng_msg_append_header(msg, data, spsz); + if (rv != 0) { + if (!keep) { + nng_msg_free(msg); + } + nn_seterror(rv); + return (-1); + } + + break; } } @@ -654,3 +695,35 @@ nn_setsockopt(int s, int nnlevel, int nnopt, const void *valp, size_t sz) } return (0); } + + +struct nn_cmsghdr * +nn_cmsg_next(struct nn_msghdr *mh, struct nn_cmsghdr *first) +{ + size_t clen; + char *data; + + // We only support SP headers, so there can be at most one header. + if (first != NULL) { + return (NULL); + } + if ((clen = mh->msg_controllen) == NN_MSG) { + nng_msg *msg; + data = *((void **) (mh->msg_control)); + msg = *(nng_msg **) (data - sizeof (msg)); + clen = nng_msg_len(msg); + } else { + data = mh->msg_control; + } + + if (first == NULL) { + first = (void *) data; + } else { + first = first + first->cmsg_len; + } + + if (((char *) first + sizeof (*first)) > (data + clen)) { + return (NULL); + } + return (first); +} |
