Re: [PATCH lksctp-tools 1/3] lib: add the core functions for sctp_sendv and sctp_recvv

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

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



[Index of Archives]     [Linux Networking Development]     [Linux OMAP]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux