blocxx

DescriptorUtils_noexcept.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Quest Software, Inc. All rights reserved.
00003 * Copyright (C) 2006, Novell, Inc. All rights reserved.
00004 * 
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 * 
00008 *     * Redistributions of source code must retain the above copyright notice,
00009 *       this list of conditions and the following disclaimer.
00010 *     * Redistributions in binary form must reproduce the above copyright
00011 *       notice, this list of conditions and the following disclaimer in the
00012 *       documentation and/or other materials provided with the distribution.
00013 *     * Neither the name of 
00014 *       Quest Software, Inc., 
00015 *       nor Novell, Inc., 
00016 *       nor the names of its contributors or employees may be used to 
00017 *       endorse or promote products derived from this software without 
00018 *       specific prior written permission.
00019 * 
00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030 * POSSIBILITY OF SUCH DAMAGE.
00031 *******************************************************************************/
00032 
00033 
00040 // THIS CODE MUST NOT THROW EXCEPTIONS.  IT IS ALSO HIGHLY PREFERRED THAT
00041 // IT NOT RELY ON ANY LIBRARY OTHER THAN STANDARD SYSTEM LIBRARIES AND THE
00042 // STANDARD C++ LIBRARY, AS IT IS USED IN libowcprivman, AND WE WANT TO AVOID
00043 // LINKING OTHER LIBRARIES IN WITH libowcprivman.
00044 
00045 #include "blocxx/BLOCXX_config.h"
00046 #include "blocxx/DescriptorUtils_noexcept.hpp"
00047 #include "blocxx/AutoDescriptor.hpp"
00048 
00049 #include <cstring>
00050 #include <sys/types.h>
00051 #ifdef BLOCXX_HAVE_SYS_SOCKET_H
00052 #include <sys/socket.h>
00053 #endif
00054 #ifndef BLOCXX_WIN32
00055 #include <sys/uio.h>
00056 #else
00057 #include "blocxx/WinProcessUtils.hpp"
00058 #endif
00059 
00060 namespace BLOCXX_NAMESPACE
00061 {
00062 
00063 namespace
00064 {
00065    char const MAGIC_CHAR = '\xa5';
00066 
00067    AutoDescriptor copy_error(char * dst, size_t dstsz, char const * src)
00068    {
00069       std::strncpy(dst, src, dstsz);
00070       dst[dstsz - 1] = '\0';
00071       return AutoDescriptor();
00072    }
00073 }
00074 
00075 
00076 #ifdef BLOCXX_WIN32
00077 
00078 int passDescriptor(Descriptor streamPipe, Descriptor descriptor, ProcId targetProcessHd)
00079 {
00080    if (streamPipe == BLOCXX_INVALID_HANDLE)
00081    {
00082       return -1;
00083    }
00084 
00085    DWORD targetProcessId = WinUtils::getProcessIdNT(targetProcessHd);
00086 
00087    DWORD rc = -1;
00088    HANDLE dupDescriptor = INVALID_HANDLE_VALUE;
00089    HANDLE hProcess = targetProcessId == 0 ? GetCurrentProcess() : OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcessId);
00090 
00091    BOOL fSuccess = DuplicateHandle(GetCurrentProcess(), descriptor,
00092       hProcess, &dupDescriptor, 0,
00093       FALSE, DUPLICATE_SAME_ACCESS);
00094 
00095    CloseHandle(hProcess);
00096 
00097    if (!fSuccess)
00098    {
00099       return -1;
00100    }
00101 
00102    OVERLAPPED ovl;
00103    ZeroMemory(&ovl, sizeof(OVERLAPPED));
00104    
00105    fSuccess = WriteFile(streamPipe, &dupDescriptor, sizeof(long), &rc, &ovl);
00106 
00107    if (!fSuccess)
00108    {
00109       DWORD lastError = GetLastError();
00110 
00111       if (lastError != ERROR_IO_INCOMPLETE && lastError != ERROR_IO_PENDING)
00112       {
00113          SetLastError(lastError);
00114          return -1;
00115       }
00116       else 
00117       {
00118          DWORD waitFlag = WaitForSingleObject(streamPipe, INFINITE);
00119 
00120          if (waitFlag == WAIT_OBJECT_0)
00121          {
00122             GetOverlappedResult(streamPipe, &ovl, &rc, FALSE);
00123          }
00124          else
00125          {
00126             return -1;
00127          }
00128       }
00129    }
00130 
00131    return rc;
00132 }
00133 
00134 AutoDescriptor receiveDescriptor(Descriptor streamPipe, char * errbuf, size_t bufsz)
00135 {
00136    long desc;
00137    DWORD rc = -1;
00138    BOOL bSuccess = FALSE;
00139 
00140    if (streamPipe != BLOCXX_INVALID_HANDLE)
00141    {
00142       OVERLAPPED ovl;
00143       ZeroMemory(&ovl, sizeof(OVERLAPPED));
00144 
00145       bSuccess = ReadFile(streamPipe, &desc, sizeof(long), &rc, &ovl);
00146 
00147       if (!bSuccess)
00148       {
00149          DWORD lastError = GetLastError();
00150 
00151          if (lastError != ERROR_IO_INCOMPLETE && lastError != ERROR_IO_PENDING)
00152          {
00153             SetLastError(lastError);
00154             return copy_error(errbuf, bufsz, "ReadFile() failed");
00155          }
00156          else
00157          {
00158             DWORD waitFlag = WaitForSingleObject(streamPipe, INFINITE);
00159 
00160             if (waitFlag == WAIT_OBJECT_0)
00161             {
00162                GetOverlappedResult(streamPipe, &ovl, &rc, FALSE);
00163             }
00164             else
00165             {
00166                return copy_error(errbuf, bufsz, "WaitForSingleObject() failed");
00167             }
00168          }
00169       }
00170 
00171       return AutoDescriptor(reinterpret_cast<HANDLE>(desc));
00172    }
00173 
00174    return copy_error(errbuf, bufsz, "receiveDescriptor() error");
00175 }
00176 
00177 #else
00178 
00179 int passDescriptor(Descriptor streamPipe, Descriptor descriptor, ProcId targetProcessId)
00180 {
00181    struct msghdr msg;
00182    ::memset(&msg, 0, sizeof(msg));
00183    struct iovec iov[1];
00184    ::memset(iov, 0, sizeof(iov[0]));
00185 
00186 #ifdef BLOCXX_HAVE_MSGHDR_MSG_CONTROL
00187 
00188 // We need the newer CMSG_LEN() and CMSG_SPACE() macros, but few
00189 // implementations support them today.  These two macros really need
00190 // an ALIGN() macro, but each implementation does this differently.
00191 #ifndef CMSG_LEN
00192 #define CMSG_LEN(size)      (sizeof(struct cmsghdr) + (size))
00193 #endif
00194 
00195 #ifndef CMSG_SPACE
00196 #define CMSG_SPACE(size)    (sizeof(struct cmsghdr) + (size))
00197 #endif
00198 
00199    union {
00200      struct cmsghdr cm;
00201      char control[CMSG_SPACE(sizeof(int))];
00202    } control_un;
00203    ::memset(&control_un, 0, sizeof(control_un));
00204    struct cmsghdr * cmptr;
00205 
00206    msg.msg_control = control_un.control;
00207    msg.msg_controllen = sizeof(control_un.control);
00208 
00209    cmptr = CMSG_FIRSTHDR(&msg);
00210    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
00211    cmptr->cmsg_level = SOL_SOCKET;
00212    cmptr->cmsg_type = SCM_RIGHTS;
00213    *(reinterpret_cast<int *>(CMSG_DATA(cmptr))) = descriptor;
00214 #else
00215 
00216 #ifdef BLOCXX_NCR
00217    void *temp_cast = &descriptor;
00218    msg.msg_accrights = static_cast<caddr_t>(temp_cast);
00219 #else
00220    msg.msg_accrights = static_cast<caddr_t>(&descriptor);
00221 #endif
00222 
00223    msg.msg_accrightslen = sizeof(int);
00224 #endif
00225 
00226    msg.msg_name = 0;
00227    msg.msg_namelen = 0;
00228 
00229    char dummy[1] = { MAGIC_CHAR };
00230    iov[0].iov_base = dummy;
00231    iov[0].iov_len = 1;
00232    msg.msg_iov = iov;
00233    msg.msg_iovlen = 1;
00234 
00235    return ::sendmsg(streamPipe, &msg, 0);
00236 }
00237 
00238 AutoDescriptor receiveDescriptor(Descriptor streamPipe, char * errbuf, size_t bufsz)
00239 {
00240    struct msghdr msg;
00241    struct iovec iov[1];
00242 
00243    msg = msghdr(); // zero-init to make valgrind happy
00244 #ifdef BLOCXX_HAVE_MSGHDR_MSG_CONTROL
00245    union {
00246      struct cmsghdr cm;
00247      char control[CMSG_SPACE(sizeof(int))];
00248    } control_un;
00249 
00250    msg.msg_control = control_un.control;
00251    msg.msg_controllen = sizeof(control_un.control);
00252 #else
00253    int   newfd = -1;
00254 
00255 #ifdef BLOCXX_NCR
00256    void *temp_cast = &newfd;
00257    msg.msg_accrights = static_cast<caddr_t>(temp_cast);
00258 #else
00259    msg.msg_accrights = static_cast<caddr_t>(&newfd);
00260 #endif
00261 
00262    msg.msg_accrightslen = sizeof(int);
00263 #endif
00264 
00265    msg.msg_name = 0;
00266    msg.msg_namelen = 0;
00267 
00268    char dummy[1] = { '\x7F' };
00269    iov[0].iov_base = dummy;
00270    iov[0].iov_len = 1;
00271    msg.msg_iov = iov;
00272    msg.msg_iovlen = 1;
00273 
00274    ssize_t  n = ::recvmsg(streamPipe, &msg, 0);
00275    if (n == 0)
00276    {
00277       return copy_error(errbuf, bufsz,
00278          "unexpected end of input when receiving handle");
00279    }
00280    if (n < 0)
00281    {
00282       return copy_error(errbuf, bufsz, "recvmsg() failed");
00283    }
00284    if (n != 1)
00285    {
00286       return copy_error(errbuf, bufsz, "received more than 1 byte.");
00287    }
00288    if (dummy[0] != MAGIC_CHAR)
00289    {
00290       return copy_error(errbuf, bufsz, "bad magic char when receiving handle");
00291    }
00292 
00293 
00294 #ifdef BLOCXX_HAVE_MSGHDR_MSG_CONTROL
00295    struct cmsghdr * cmptr = CMSG_FIRSTHDR(&msg);
00296    if (!cmptr)
00297    {
00298       return copy_error(errbuf, bufsz,
00299          "missing control message when receiving handle");
00300    }
00301    // as far as I can tell, HP-UX is just broken and sets cmptr->cmsg_len to 12. Things work anyway.
00302 #if !defined (BLOCXX_HPUX)
00303    if (cmptr->cmsg_len != CMSG_LEN(sizeof(int)))
00304    {
00305       return copy_error(errbuf, bufsz,
00306          "cmptr->cmsg_len != CMSG_LEN(sizeof(int)) when receiving handle");
00307    }
00308 #endif
00309    if (cmptr->cmsg_level != SOL_SOCKET)
00310    {
00311       return copy_error(errbuf, bufsz,
00312          "control level != SOL_SOCKET when receiving handle");
00313    }
00314    if (cmptr->cmsg_type != SCM_RIGHTS)
00315    {
00316       return copy_error(errbuf, bufsz,
00317          "control type != SCM_RIGHTS when receiving handle");
00318    }
00319    return AutoDescriptor(*(reinterpret_cast<int *>(CMSG_DATA(cmptr))));
00320 #else
00321    if (msg.msg_accrightslen != sizeof(int))
00322    {
00323       return copy_error(errbuf, bufsz,
00324          "bad control message when receiving handle");
00325    }
00326    return AutoDescriptor(newfd);
00327 #endif
00328 }
00329 
00330 #endif
00331 
00332 
00333 } // end namespace BLOCXX_NAMESPACE