On Wed, May 2, 2018 at 7:32 PM, Neil Horman <nhorman@xxxxxxxxxxxxx> wrote: > On Tue, May 01, 2018 at 11:02:45PM +0800, Xin Long wrote: >> On Tue, May 1, 2018 at 9:59 PM, Neil Horman <nhorman@xxxxxxxxxxxxx> wrote: >> > 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. >> With the appropriate cmsglen, we can void the unncessary alloc by checking >> (!cmsglen). > You don't need to check !cmsglen, you just need to initalize it to zero (like > you already are, and assign it to control_len at the end of the function, if > its, zero, so be it. And yes, you have to still keep track of cmseglen, but you > can do so as you add data to the cmsg (assuming you've pre-allocated a maximum > sized buffer), and in so doing, avoid having that for loop in there at all. You're right, the code looks better with it now, will post v2. thanks. > > Neil > >> Otherwise we will have to check "!cmsglen && infotype != any of them", >> and also to count cmsglen in the 2nd "if-else if" to set the correct value >> for outmsg.msg_controllen. >> -- >> 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 >> -- 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