00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00040
00041
00042
00043
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
00189
00190
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();
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
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 }