On Tue, May 01, 2018 at 06:24:07PM +0800, Xin Long wrote: > This patch is to implement sctp_sendv and sctp_recvv defined in > rfc6458#section-9.12 and 9.13. They provide an extensible way > for users to send or receive messages from a SCTP socket. > > Signed-off-by: Xin Long <lucien.xin@xxxxxxxxx> > --- > src/include/netinet/sctp.h | 43 ++++++++++++ > src/lib/Versions.map | 2 + > src/lib/recvmsg.c | 88 +++++++++++++++++++++++++ > src/lib/sendmsg.c | 161 +++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 294 insertions(+) > > diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h > index a0cd14c..701f091 100644 > --- a/src/include/netinet/sctp.h > +++ b/src/include/netinet/sctp.h > @@ -122,6 +122,49 @@ int sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from, > /* Return the address length for an address family. */ > int sctp_getaddrlen(sa_family_t family); > > + > +/* sendv infotype */ > +enum { > + SCTP_SENDV_NOINFO, > + SCTP_SENDV_SNDINFO, > + SCTP_SENDV_PRINFO, > + SCTP_SENDV_AUTHINFO, > + SCTP_SENDV_SPA > +}; > + > +/* sendv_flags */ > +#define SCTP_SEND_SNDINFO_VALID 0x1 > +#define SCTP_SEND_PRINFO_VALID 0x2 > +#define SCTP_SEND_AUTHINFO_VALID 0x4 > + > +struct sctp_sendv_spa { > + uint32_t sendv_flags; > + struct sctp_sndinfo sendv_sndinfo; > + struct sctp_prinfo sendv_prinfo; > + struct sctp_authinfo sendv_authinfo; > +}; > + > +int sctp_sendv(int s, const struct iovec *iov, int iovcnt, > + struct sockaddr *addrs, int addrcnt, void *info, > + socklen_t infolen, unsigned int infotype, int flags); > + > +/* recvv infotype */ > +enum { > + SCTP_RECVV_NOINFO, > + SCTP_RECVV_RCVINFO, > + SCTP_RECVV_NXTINFO, > + SCTP_RECVV_RN > +}; > + > +struct sctp_recvv_rn { > + struct sctp_rcvinfo recvv_rcvinfo; > + struct sctp_nxtinfo recvv_nxtinfo; > +}; > + > +int sctp_recvv(int s, const struct iovec *iov, int iovlen, > + struct sockaddr *from, socklen_t *fromlen, void *info, > + socklen_t *infolen, unsigned int *infotype, int *flags); > + > #ifdef __cplusplus > } > #endif > diff --git a/src/lib/Versions.map b/src/lib/Versions.map > index a3c5561..7faad5d 100644 > --- a/src/lib/Versions.map > +++ b/src/lib/Versions.map > @@ -10,7 +10,9 @@ VERS_1 { > sctp_opt_info; > sctp_peeloff; > sctp_recvmsg; > + sctp_recvv; > sctp_sendmsg; > + sctp_sendv; > sctp_send; > > local: > diff --git a/src/lib/recvmsg.c b/src/lib/recvmsg.c > index 4575788..7c1dcad 100644 > --- a/src/lib/recvmsg.c > +++ b/src/lib/recvmsg.c > @@ -99,3 +99,91 @@ int sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from, > > return (error); > } > + > +int sctp_recvv(int s, const struct iovec *iov, int iovlen, > + struct sockaddr *from, socklen_t *fromlen, void *info, > + socklen_t *infolen, unsigned int *infotype, int *flags) > +{ > + char incmsg[CMSG_SPACE(sizeof(struct sctp_rcvinfo) + > + sizeof(struct sctp_nxtinfo))]; > + int error, len, _infolen; > + struct cmsghdr *cmsg; > + struct msghdr inmsg; > + > + memset(&inmsg, 0, sizeof(inmsg)); > + > + /* set from and iov */ > + inmsg.msg_name = from; > + inmsg.msg_namelen = fromlen ? *fromlen : 0; > + inmsg.msg_iov = (struct iovec *)iov; > + inmsg.msg_iovlen = iovlen; > + inmsg.msg_control = incmsg; > + inmsg.msg_controllen = sizeof(incmsg); > + > + error = recvmsg(s, &inmsg, flags ? *flags : 0); > + if (error < 0) > + return error; > + > + /* set fromlen, frags */ > + if (fromlen) > + *fromlen = inmsg.msg_namelen; > + > + if (flags) > + *flags = inmsg.msg_flags; > + > + if (!info || !infotype || !infolen) > + return error; > + > + *infotype = SCTP_RECVV_NOINFO; > + _infolen = *infolen; > + > + /* set info and infotype */ > + for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL; > + cmsg = CMSG_NXTHDR(&inmsg, cmsg)) { > + if (cmsg->cmsg_level != IPPROTO_SCTP) > + continue; > + > + if (cmsg->cmsg_type == SCTP_RCVINFO) { > + len = sizeof(struct sctp_rcvinfo); > + if (*infotype == SCTP_RECVV_NOINFO) { > + if (_infolen < len) > + break; > + memcpy(info, CMSG_DATA(cmsg), len); > + *infotype = SCTP_RECVV_RCVINFO; > + *infolen = len; > + } else if (*infotype == SCTP_RECVV_NXTINFO) { > + if (_infolen < len + > + sizeof(struct sctp_nxtinfo)) > + break; > + memcpy(info + len, info, > + sizeof(struct sctp_nxtinfo)); > + memcpy(info, CMSG_DATA(cmsg), len); > + *infotype = SCTP_RECVV_RN; > + *infolen = len + sizeof(struct sctp_nxtinfo); > + } else { > + break; > + } > + } else if (cmsg->cmsg_type == SCTP_NXTINFO) { > + len = sizeof(struct sctp_nxtinfo); > + if (*infotype == SCTP_RECVV_NOINFO) { > + if (_infolen < len) > + break; > + memcpy(info, CMSG_DATA(cmsg), len); > + *infotype = SCTP_RECVV_NXTINFO; > + *infolen = len; > + } else if (*infotype == SCTP_RECVV_RCVINFO) { > + if (_infolen < len + > + sizeof(struct sctp_rcvinfo)) > + break; > + memcpy(info + sizeof(struct sctp_rcvinfo), > + CMSG_DATA(cmsg), len); > + *infotype = SCTP_RECVV_RN; > + *infolen = len + sizeof(struct sctp_rcvinfo); > + } else { > + break; > + } > + } > + } > + > + return error; > +} > diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c > index 9046174..cb75378 100644 > --- a/src/lib/sendmsg.c > +++ b/src/lib/sendmsg.c > @@ -19,7 +19,10 @@ > * Ardelle Fan <ardelle.fan@xxxxxxxxx> > */ > > +#include <errno.h> > #include <string.h> > +#include <stdlib.h> > +#include <netinet/in.h> > #include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */ > #include <netinet/sctp.h> > > @@ -104,3 +107,161 @@ sctp_send(int s, const void *msg, size_t len, > > return sendmsg(s, &outmsg, flags); > } > + > +static struct cmsghdr *sctp_sendv_store_cmsg(struct cmsghdr *cmsg, int *cmsglen, > + int type, int len, void *data) > +{ > + cmsg->cmsg_level = IPPROTO_SCTP; > + cmsg->cmsg_type = type; > + cmsg->cmsg_len = CMSG_LEN(len); > + memcpy(CMSG_DATA(cmsg), data, len); > + > + *cmsglen -= CMSG_SPACE(len); > + if (!*cmsglen) > + return NULL; > + > + return (struct cmsghdr *)((char *)cmsg + CMSG_SPACE(len)); > +} > + > +int sctp_sendv(int s, const struct iovec *iov, int iovcnt, > + struct sockaddr *addrs, int addrcnt, void *info, > + socklen_t infolen, unsigned int infotype, int flags) > +{ > + struct sockaddr *addr; > + struct msghdr outmsg; > + struct cmsghdr *cmsg; > + int type, len, i; > + int cmsglen = 0; > + char *addrbuf; > + > + /* set msg_iov, msg_iovlen, msg_flags */ > + memset(&outmsg, 0x00, sizeof(outmsg)); > + outmsg.msg_iov = (struct iovec *)iov; > + outmsg.msg_iovlen = iovcnt; > + outmsg.msg_flags = flags; > + > + /* set msg_name and msg_namelen */ > + if (addrs && addrcnt) { > + outmsg.msg_name = addrs; > + if (addrs->sa_family == AF_INET) > + outmsg.msg_namelen = sizeof(struct sockaddr_in); > + else if (addrs->sa_family == AF_INET6) > + outmsg.msg_namelen = sizeof(struct sockaddr_in6); > + else > + return -EINVAL; > + addrcnt -= 1; > + addrbuf = (char *)addrs; > + addrs = (struct sockaddr *)(addrbuf + outmsg.msg_namelen); > + } > + > + /* get the cmsg length it will need for addr info */ > + for (i = 0, addrbuf = (char *)addrs; i < addrcnt; i++) { > + addr = (struct sockaddr *)addrbuf; > + if (addr->sa_family == AF_INET) { > + len = sizeof(struct in_addr); > + cmsglen += CMSG_SPACE(len); > + addrbuf += sizeof(struct sockaddr_in); > + } else if (addr->sa_family == AF_INET6) { > + len = sizeof(struct in6_addr); > + cmsglen += CMSG_SPACE(len); > + addrbuf += sizeof(struct sockaddr_in6); > + } else { > + return -EINVAL; > + } > + } > + /* get the cmsg length it will need for snd/pr/auth info */ > + if (infotype == SCTP_SENDV_SPA) { > + struct sctp_sendv_spa *spa = info; > + > + if (spa->sendv_flags & SCTP_SEND_SNDINFO_VALID) > + cmsglen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); > + if (spa->sendv_flags & SCTP_SEND_PRINFO_VALID) > + cmsglen += CMSG_SPACE(sizeof(struct sctp_prinfo)); > + if (spa->sendv_flags & SCTP_SEND_AUTHINFO_VALID) > + cmsglen += CMSG_SPACE(sizeof(struct sctp_authinfo)); > + } else if (infotype == SCTP_SENDV_SNDINFO) { > + cmsglen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); > + } else if (infotype == SCTP_SENDV_PRINFO) { > + cmsglen += CMSG_SPACE(sizeof(struct sctp_prinfo)); > + } else if (infotype == SCTP_SENDV_AUTHINFO) { > + cmsglen += CMSG_SPACE(sizeof(struct sctp_authinfo)); > + } > + We're talkinag about less than 128 bytes of storage here. Instead of checking all the infotypes and allocating the appropriate cmsglen, why not just declare a cmsg buffer on the stack that is of the maximum possible size. It would eliminate a good deal of code here. Neil -- To unsubscribe from this list: send the line "unsubscribe linux-sctp" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html