LCOV - code coverage report
Current view: top level - util/io - fd_share.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 46 46 100.0 %
Date: 2012-05-15 Functions: 2 2 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 19 26 73.1 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <cstring>
      16                 :            : #include <cstdlib>
      17                 :            : 
      18                 :            : #include <sys/types.h>
      19                 :            : #include <sys/socket.h>
      20                 :            : #include <sys/uio.h>
      21                 :            : #include <errno.h>
      22                 :            : #include <stdlib.h>             // for malloc and free
      23                 :            : #include <unistd.h>
      24                 :            : #include "fd_share.h"
      25                 :            : 
      26                 :            : namespace isc {
      27                 :            : namespace util {
      28                 :            : namespace io {
      29                 :            : 
      30                 :            : namespace {
      31                 :            : // Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
      32                 :            : // In order to ensure as much portability as possible, we provide wrapper
      33                 :            : // functions of these macros.
      34                 :            : // Note that cmsg_space() could run slow on OSes that do not have
      35                 :            : // CMSG_SPACE.
      36                 :            : inline socklen_t
      37                 :            : cmsg_len(const socklen_t len) {
      38                 :            : #ifdef CMSG_LEN
      39                 :            :     return (CMSG_LEN(len));
      40                 :            : #else
      41                 :            :     // Cast NULL so that any pointer arithmetic performed by CMSG_DATA
      42                 :            :     // is correct.
      43                 :            :     const uintptr_t hdrlen = (uintptr_t)CMSG_DATA(((struct cmsghdr*)NULL));
      44                 :            :     return (hdrlen + len);
      45                 :            : #endif
      46                 :            : }
      47                 :            : 
      48                 :            : inline socklen_t
      49                 :            : cmsg_space(const socklen_t len) {
      50                 :            : #ifdef CMSG_SPACE
      51                 :            :     return (CMSG_SPACE(len));
      52                 :            : #else
      53                 :            :     struct msghdr msg;
      54                 :            :     struct cmsghdr* cmsgp;
      55                 :            :     // XXX: The buffer length is an ad hoc value, but should be enough
      56                 :            :     // in a practical sense.
      57                 :            :     char dummybuf[sizeof(struct cmsghdr) + 1024];
      58                 :            : 
      59                 :            :     memset(&msg, 0, sizeof(msg));
      60                 :            :     msg.msg_control = dummybuf;
      61                 :            :     msg.msg_controllen = sizeof(dummybuf);
      62                 :            : 
      63                 :            :     cmsgp = (struct cmsghdr*)dummybuf;
      64                 :            :     cmsgp->cmsg_len = cmsg_len(len);
      65                 :            : 
      66                 :            :     cmsgp = CMSG_NXTHDR(&msg, cmsgp);
      67                 :            :     if (cmsgp != NULL) {
      68                 :            :         return ((char*)cmsgp - (char*)msg.msg_control);
      69                 :            :     } else {
      70                 :            :         return (0);
      71                 :            :     }
      72                 :            : #endif  // CMSG_SPACE
      73                 :            : }
      74                 :            : }
      75                 :            : 
      76                 :            : int
      77                 :         46 : recv_fd(const int sock) {
      78                 :            :     struct msghdr msghdr;
      79                 :            :     struct iovec iov_dummy;
      80                 :            :     unsigned char dummy_data;
      81                 :            : 
      82                 :         46 :     iov_dummy.iov_base = &dummy_data;
      83                 :         46 :     iov_dummy.iov_len = sizeof(dummy_data);
      84                 :         46 :     msghdr.msg_name = NULL;
      85                 :         46 :     msghdr.msg_namelen = 0;
      86                 :         46 :     msghdr.msg_iov = &iov_dummy;
      87                 :         46 :     msghdr.msg_iovlen = 1;
      88                 :         46 :     msghdr.msg_flags = 0;
      89                 :         46 :     msghdr.msg_controllen = cmsg_space(sizeof(int));
      90                 :         46 :     msghdr.msg_control = malloc(msghdr.msg_controllen);
      91         [ +  - ]:         46 :     if (msghdr.msg_control == NULL) {
      92                 :            :         return (FD_SYSTEM_ERROR);
      93                 :            :     }
      94                 :            : 
      95                 :         46 :     const int cc = recvmsg(sock, &msghdr, 0);
      96         [ +  + ]:         46 :     if (cc <= 0) {
      97                 :          2 :         free(msghdr.msg_control);
      98         [ +  - ]:          2 :         if (cc == 0) {
      99                 :          2 :             errno = ECONNRESET;
     100                 :            :         }
     101                 :            :         return (FD_SYSTEM_ERROR);
     102                 :            :     }
     103         [ +  + ]:         44 :     const struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
     104                 :         44 :     int fd = FD_OTHER_ERROR;
     105 [ +  + ][ +  - ]:         44 :     if (cmsg != NULL && cmsg->cmsg_len == cmsg_len(sizeof(int)) &&
         [ -  + ][ +  + ]
     106                 :            :         cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
     107                 :         42 :         std::memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
     108                 :            :     }
     109                 :         44 :     free(msghdr.msg_control);
     110                 :            :     // It is strange, but the call can return the same file descriptor as
     111                 :            :     // one returned previously, even if that one is not closed yet. So,
     112                 :            :     // we just re-number every one we get, so they are unique.
     113                 :         44 :     int new_fd(dup(fd));
     114                 :         44 :     int close_error(close(fd));
     115         [ +  + ]:         44 :     if (close_error == -1 || new_fd == -1) {
     116                 :            :         // We need to return an error, because something failed. But in case
     117                 :            :         // it was the previous close, we at least try to close the duped FD.
     118         [ -  + ]:          2 :         if (new_fd != -1) {
     119                 :         46 :             close(new_fd); // If this fails, nothing but returning error can't
     120                 :            :                            // be done and we are doing that anyway.
     121                 :            :         }
     122                 :            :         return (FD_SYSTEM_ERROR);
     123                 :            :     }
     124                 :            :     return (new_fd);
     125                 :            : }
     126                 :            : 
     127                 :            : int
     128                 :         51 : send_fd(const int sock, const int fd) {
     129                 :            :     struct msghdr msghdr;
     130                 :            :     struct iovec iov_dummy;
     131                 :         51 :     unsigned char dummy_data = 0;
     132                 :            : 
     133                 :         51 :     iov_dummy.iov_base = &dummy_data;
     134                 :         51 :     iov_dummy.iov_len = sizeof(dummy_data);
     135                 :         51 :     msghdr.msg_name = NULL;
     136                 :         51 :     msghdr.msg_namelen = 0;
     137                 :         51 :     msghdr.msg_iov = &iov_dummy;
     138                 :         51 :     msghdr.msg_iovlen = 1;
     139                 :         51 :     msghdr.msg_flags = 0;
     140                 :         51 :     msghdr.msg_controllen = cmsg_space(sizeof(int));
     141                 :         51 :     msghdr.msg_control = malloc(msghdr.msg_controllen);
     142         [ +  - ]:         51 :     if (msghdr.msg_control == NULL) {
     143                 :            :         return (FD_OTHER_ERROR);
     144                 :            :     }
     145                 :            : 
     146         [ +  - ]:         51 :     struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msghdr);
     147                 :         51 :     cmsg->cmsg_len = cmsg_len(sizeof(int));
     148                 :         51 :     cmsg->cmsg_level = SOL_SOCKET;
     149                 :         51 :     cmsg->cmsg_type = SCM_RIGHTS;
     150                 :         51 :     std::memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
     151                 :            : 
     152                 :         51 :     const int ret = sendmsg(sock, &msghdr, 0);
     153                 :         51 :     free(msghdr.msg_control);
     154         [ +  + ]:         51 :     return (ret >= 0 ? 0 : FD_SYSTEM_ERROR);
     155                 :            : }
     156                 :            : 
     157                 :            : } // End for namespace io
     158                 :            : } // End for namespace util
     159                 :            : } // End for namespace isc

Generated by: LCOV version 1.9