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 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



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

  Powered by Linux