Changeset 102060 in vbox for trunk/src/libs/xpcom18a4/ipc
- Timestamp:
- Nov 10, 2023 9:47:46 AM (15 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp
r101890 r102060 1 /* vim:set ts=2 sw=2 et cindent: */2 1 /* ***** BEGIN LICENSE BLOCK ***** 3 2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 … … 35 34 * 36 35 * ***** END LICENSE BLOCK ***** */ 37 38 #include "private/pprio.h" 39 #include "prerror.h" 40 #include "prio.h" 36 #define LOG_GROUP LOG_GROUP_IPC 37 #include <iprt/assert.h> 38 #include <iprt/critsect.h> 39 #include <iprt/err.h> 40 #include <iprt/env.h> 41 #include <iprt/mem.h> 42 #include <iprt/pipe.h> 43 #include <iprt/poll.h> 44 #include <iprt/socket.h> 45 #include <iprt/string.h> 46 #include <iprt/thread.h> 47 48 #include <VBox/log.h> 49 50 #include <unistd.h> 51 #include <errno.h> 52 #include <sys/types.h> 53 #include <sys/socket.h> 54 #include <sys/un.h> 55 #include <sys/stat.h> 56 #include <stdio.h> /* fprintf below */ 41 57 42 58 #include "ipcConnection.h" 43 59 #include "ipcMessageQ.h" 44 60 #include "ipcConfig.h" 45 #include "ipcLog.h" 46 47 #ifdef VBOX 48 # include <iprt/assert.h> 49 # include <iprt/critsect.h> 50 # include <iprt/err.h> 51 # include <iprt/env.h> 52 # include <iprt/log.h> 53 # include <iprt/mem.h> 54 # include <iprt/pipe.h> 55 # include <iprt/string.h> 56 # include <iprt/thread.h> 57 58 # include <stdio.h> 59 #endif 60 61 62 //----------------------------------------------------------------------------- 63 // NOTE: this code does not need to link with anything but NSPR. that is by 64 // design, so it can be easily reused in other projects that want to 65 // talk with mozilla's IPC daemon, but don't want to depend on xpcom. 66 // we depend at most on some xpcom header files, but no xpcom runtime 67 // symbols are used. 68 //----------------------------------------------------------------------------- 69 70 71 #include <unistd.h> 72 #include <sys/stat.h> 61 73 62 74 63 static PRStatus 75 DoSecurityCheck( PRFileDesc *fd, const char *path)64 DoSecurityCheck(int fd, const char *path) 76 65 { 77 66 // … … 84 73 // if these conditions aren't met then bail. 85 74 // 86 int unix_fd = PR_FileDesc2NativeHandle(fd);87 88 75 struct stat st; 89 if (fstat(unix_fd, &st) == -1) { 90 LOG(("stat failed")); 76 if (fstat(fd, &st) == -1) 77 { 78 LogFlowFunc(("stat failed")); 91 79 return PR_FAILURE; 92 80 } 93 81 94 if (st.st_uid != getuid() && st.st_uid != geteuid()) { 82 if (st.st_uid != getuid() && st.st_uid != geteuid()) 83 { 95 84 // 96 85 // on OSX 10.1.5, |fstat| has a bug when passed a file descriptor to … … 101 90 // 102 91 if (st.st_uid != 0) { 103 L OG(("userid check failed"));92 LogFlowFunc(("userid check failed")); 104 93 return PR_FAILURE; 105 94 } 106 95 if (stat(path, &st) == -1) { 107 L OG(("stat failed"));96 LogFlowFunc(("stat failed")); 108 97 return PR_FAILURE; 109 98 } 110 99 if (st.st_uid != getuid() && st.st_uid != geteuid()) { 111 L OG(("userid check failed"));100 LogFlowFunc(("userid check failed")); 112 101 return PR_FAILURE; 113 102 } … … 124 113 struct ipcCallback : public ipcListNode<ipcCallback> 125 114 { 126 ipcCallbackFunc func;127 void *arg;115 ipcCallbackFunc func; 116 void *arg; 128 117 }; 129 118 … … 134 123 struct ipcConnectionState 135 124 { 136 RTCRITSECT CritSect; 137 RTPIPE hWakeupPipeW; 138 PRPollDesc fds[2]; 139 ipcCallbackQ callback_queue; 140 ipcMessageQ send_queue; 141 PRUint32 send_offset; // amount of send_queue.First() already written. 142 ipcMessage *in_msg; 143 PRBool shutdown; 125 RTCRITSECT CritSect; 126 RTPIPE hWakeupPipeW; 127 RTPIPE hWakeupPipeR; 128 RTSOCKET hSockConn; 129 RTPOLLSET hPollSet; 130 ipcCallbackQ callback_queue; 131 ipcMessageQ send_queue; 132 PRUint32 send_offset; // amount of send_queue.First() already written. 133 ipcMessage *in_msg; 134 bool fShutdown; 144 135 }; 145 136 … … 149 140 static void ConnDestroy(ipcConnectionState *s) 150 141 { 151 if (RTCritSectIsInitialized(&s->CritSect))152 142 RTCritSectDelete(&s->CritSect); 153 154 if (s->fds[SOCK].fd) 155 PR_Close(s->fds[SOCK].fd); 156 157 if (s->fds[POLL].fd) 158 PR_Close(s->fds[POLL].fd); 159 160 if (s->in_msg) 161 delete s->in_msg; 162 163 s->send_queue.DeleteAll(); 164 RTMemFree(s); 165 } 166 167 static ipcConnectionState *ConnCreate(PRFileDesc *fd) 143 RTPollSetDestroy(s->hPollSet); 144 RTPipeClose(s->hWakeupPipeR); 145 RTPipeClose(s->hWakeupPipeW); 146 RTSocketClose(s->hSockConn); 147 148 if (s->in_msg) 149 delete s->in_msg; 150 151 s->send_queue.DeleteAll(); 152 RTMemFree(s); 153 } 154 155 static ipcConnectionState *ConnCreate(RTSOCKET hSockConn) 168 156 { 169 157 ipcConnectionState *s = (ipcConnectionState *)RTMemAllocZ(sizeof(*s)); … … 171 159 return NULL; 172 160 161 s->send_offset = 0; 162 s->in_msg = NULL; 163 s->fShutdown = false; 164 173 165 int vrc = RTCritSectInit(&s->CritSect); 174 166 if (RT_SUCCESS(vrc)) 175 167 { 176 RTPIPE hPipeR; 177 178 vrc = RTPipeCreate(&hPipeR, &s->hWakeupPipeW, 0 /*fFlags*/); 168 vrc = RTPollSetCreate(&s->hPollSet); 179 169 if (RT_SUCCESS(vrc)) 180 170 { 181 s->fds[SOCK].fd = NULL; 182 s->fds[POLL].fd = PR_AllocFileDesc((PRInt32)RTPipeToNative(hPipeR), PR_GetPipeMethods()); 183 s->send_offset = 0; 184 s->in_msg = NULL; 185 s->shutdown = PR_FALSE; 186 187 if (s->fds[POLL].fd) 188 { 189 /* NSPR has taken over the pipe. */ 190 vrc = RTPipeCloseEx(hPipeR, true /*fLeaveOpen*/); AssertRC(vrc); 191 192 // disable inheritance of the IPC socket by children started 193 // using non-NSPR process API 194 PRStatus status = PR_SetFDInheritable(fd, PR_FALSE); 195 if (status == PR_SUCCESS) 171 RTPIPE hPipeR; 172 173 vrc = RTPipeCreate(&s->hWakeupPipeR, &s->hWakeupPipeW, 0 /*fFlags*/); 174 if (RT_SUCCESS(vrc)) 175 { 176 vrc = RTPollSetAddSocket(s->hPollSet, hSockConn, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, SOCK); 177 if (RT_SUCCESS(vrc)) 196 178 { 197 // store this only if we are going to succeed. 198 s->fds[SOCK].fd = fd; 199 200 return s; 179 vrc = RTPollSetAddPipe(s->hPollSet, s->hWakeupPipeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, POLL); 180 if (RT_SUCCESS(vrc)) 181 { 182 vrc = RTSocketSetInheritance(hSockConn, false /*fInheritable*/); 183 if (RT_SUCCESS(vrc)) 184 { 185 s->hSockConn = hSockConn; 186 return s; 187 } 188 189 LogFlowFunc(("coudn't make IPC socket non-inheritable [err=%Rrc]\n", vrc)); 190 vrc = RTPollSetRemove(s->hPollSet, POLL); AssertRC(vrc); 191 } 192 193 vrc = RTPollSetRemove(s->hPollSet, SOCK); AssertRC(vrc); 201 194 } 202 195 203 PR_Close(s->fds[POLL].fd); 204 s->fds[POLL].fd = NULL; 205 LOG(("coudn't make IPC socket non-inheritable [err=%d]\n", PR_GetError())); 206 } 207 208 vrc = RTPipeClose(hPipeR); AssertRC(vrc); 209 vrc = RTPipeClose(s->hWakeupPipeW); AssertRC(vrc); 210 } 211 212 ConnDestroy(s); 196 vrc = RTPipeClose(s->hWakeupPipeR); AssertRC(vrc); 197 vrc = RTPipeClose(s->hWakeupPipeW); AssertRC(vrc); 198 } 199 200 vrc = RTPollSetDestroy(s->hPollSet); AssertRC(vrc); 201 } 202 203 RTCritSectDelete(&s->CritSect); 213 204 } 214 205 … … 216 207 } 217 208 218 static nsresult 219 ConnRead(ipcConnectionState *s) 220 { 221 char buf[1024]; 222 nsresult rv = NS_OK; 223 PRInt32 n; 224 225 do 226 { 227 n = PR_Read(s->fds[SOCK].fd, buf, sizeof(buf)); 228 if (n < 0) 229 { 230 PRErrorCode err = PR_GetError(); 231 if (err == PR_WOULD_BLOCK_ERROR) 232 { 233 // socket is empty... we need to go back to polling. 234 break; 235 } 236 LOG(("PR_Read returned failure [err=%d]\n", err)); 237 rv = NS_ERROR_UNEXPECTED; 238 } 239 else if (n == 0) 240 { 241 LOG(("PR_Read returned EOF\n")); 242 rv = NS_ERROR_UNEXPECTED; 243 } 244 else 245 { 246 const char *pdata = buf; 247 while (n) 248 { 249 PRUint32 bytesRead; 250 PRBool complete; 251 252 if (!s->in_msg) 253 { 254 s->in_msg = new ipcMessage; 255 if (!s->in_msg) 256 { 257 rv = NS_ERROR_OUT_OF_MEMORY; 209 static nsresult ConnRead(ipcConnectionState *s) 210 { 211 nsresult rv = NS_OK; 212 213 /* Read as much as possible. */ 214 for (;;) 215 { 216 char buf[_1K]; 217 size_t cbRead = 0; 218 int vrc = RTSocketReadNB(s->hSockConn, &buf[0], sizeof(buf), &cbRead); 219 if (RT_SUCCESS(vrc) && cbRead > 0) 220 { /* likely */ } 221 else if (vrc == VINF_TRY_AGAIN) 222 break; /* Socket is empty, go back to polling. */ 223 else if (RT_FAILURE(vrc)) 224 { 225 rv = NS_ERROR_UNEXPECTED; 258 226 break; 259 } 260 } 261 262 if (s->in_msg->ReadFrom(pdata, n, &bytesRead, &complete) != PR_SUCCESS) 263 { 264 LOG(("error reading IPC message\n")); 265 rv = NS_ERROR_UNEXPECTED; 266 break; 267 } 268 269 Assert(PRUint32(n) >= bytesRead); 270 n -= bytesRead; 271 pdata += bytesRead; 272 273 if (complete) 274 { 275 // protect against weird re-entrancy cases... 276 ipcMessage *m = s->in_msg; 277 s->in_msg = NULL; 278 279 IPC_OnMessageAvailable(m); 280 } 281 } 282 } 283 } 284 while (NS_SUCCEEDED(rv)); 285 286 return rv; 287 } 288 289 static nsresult 290 ConnWrite(ipcConnectionState *s) 291 { 292 nsresult rv = NS_OK; 293 294 RTCritSectEnter(&s->CritSect); 295 296 // write one message and then return. 297 if (s->send_queue.First()) 298 { 299 PRInt32 n = PR_Write(s->fds[SOCK].fd, 300 s->send_queue.First()->MsgBuf() + s->send_offset, 301 s->send_queue.First()->MsgLen() - s->send_offset); 302 if (n <= 0) 303 { 304 PRErrorCode err = PR_GetError(); 305 if (err == PR_WOULD_BLOCK_ERROR) 306 { 307 // socket is full... we need to go back to polling. 308 } 309 else 310 { 311 LOG(("error writing to socket [err=%d]\n", err)); 312 rv = NS_ERROR_UNEXPECTED; 313 } 314 } 315 else 316 { 317 s->send_offset += n; 318 if (s->send_offset == s->send_queue.First()->MsgLen()) 319 { 320 s->send_queue.DeleteFirst(); 321 s->send_offset = 0; 322 323 // if the send queue is empty, then we need to stop trying to write. 324 if (s->send_queue.IsEmpty()) 325 s->fds[SOCK].in_flags &= ~PR_POLL_WRITE; 326 } 327 } 328 } 329 330 RTCritSectLeave(&s->CritSect); 331 return rv; 227 } 228 else if (cbRead == 0) 229 { 230 LogFlowFunc(("RTSocketReadNB() returned EOF\n")); 231 rv = NS_ERROR_UNEXPECTED; 232 break; 233 } 234 235 const char *pdata = buf; 236 while (cbRead) 237 { 238 PRUint32 bytesRead; 239 PRBool fComplete = PR_FALSE; 240 241 /* No message frame available? Allocate a new one. */ 242 if (!s->in_msg) 243 { 244 s->in_msg = new ipcMessage; 245 if (RT_UNLIKELY(!s->in_msg)) 246 { 247 rv = NS_ERROR_OUT_OF_MEMORY; 248 break; 249 } 250 } 251 252 if (s->in_msg->ReadFrom(pdata, cbRead, &bytesRead, &fComplete) != PR_SUCCESS) 253 { 254 LogFlowFunc(("error reading IPC message\n")); 255 rv = NS_ERROR_UNEXPECTED; 256 break; 257 } 258 259 Assert(cbRead >= bytesRead); 260 cbRead -= bytesRead; 261 pdata += bytesRead; 262 263 if (fComplete) 264 { 265 // protect against weird re-entrancy cases... 266 ipcMessage *m = s->in_msg; 267 s->in_msg = NULL; 268 269 IPC_OnMessageAvailable(m); 270 } 271 } 272 } 273 274 return rv; 275 } 276 277 static nsresult ConnWrite(ipcConnectionState *s) 278 { 279 nsresult rv = NS_OK; 280 281 RTCritSectEnter(&s->CritSect); 282 283 // write one message and then return. 284 if (s->send_queue.First()) 285 { 286 size_t cbWritten = 0; 287 int vrc = RTSocketWriteNB(s->hSockConn, 288 s->send_queue.First()->MsgBuf() + s->send_offset, 289 s->send_queue.First()->MsgLen() - s->send_offset, 290 &cbWritten); 291 if (vrc == VINF_SUCCESS && cbWritten) 292 { 293 s->send_offset += cbWritten; 294 if (s->send_offset == s->send_queue.First()->MsgLen()) 295 { 296 s->send_queue.DeleteFirst(); 297 s->send_offset = 0; 298 299 /* if the send queue is empty, then we need to stop trying to write. */ 300 if (s->send_queue.IsEmpty()) 301 { 302 vrc = RTPollSetEventsChange(s->hPollSet, SOCK, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR); 303 AssertRC(vrc); 304 } 305 } 306 } 307 else if (vrc != VINF_TRY_AGAIN) 308 { 309 Assert(RT_FAILURE(vrc)); 310 LogFlowFunc(("error writing to socket [err=%Rrc]\n", vrc)); 311 rv = NS_ERROR_UNEXPECTED; 312 } 313 } 314 315 RTCritSectLeave(&s->CritSect); 316 return rv; 332 317 } 333 318 334 319 static DECLCALLBACK(int) ipcConnThread(RTTHREAD hSelf, void *pvArg) 335 320 { 336 RT_NOREF(hSelf); 337 338 PRInt32 num; 339 nsresult rv = NS_OK; 340 341 ipcConnectionState *s = (ipcConnectionState *)pvArg; 342 343 // we monitor two file descriptors in this thread. the first (at index 0) is 344 // the socket connection with the IPC daemon. the second (at index 1) is the 345 // pollable event we monitor in order to know when to send messages to the 346 // IPC daemon. 347 348 s->fds[SOCK].in_flags = PR_POLL_READ; 349 s->fds[POLL].in_flags = PR_POLL_READ; 350 351 while (NS_SUCCEEDED(rv)) 352 { 353 s->fds[SOCK].out_flags = 0; 354 s->fds[POLL].out_flags = 0; 355 356 // 357 // poll on the IPC socket and NSPR pollable event 358 // 359 num = PR_Poll(s->fds, 2, PR_INTERVAL_NO_TIMEOUT); 360 if (num > 0) 361 { 362 ipcCallbackQ cbs_to_run; 363 364 // check if something has been added to the send queue. if so, then 365 // acknowledge pollable event (wait should not block), and configure 366 // poll flags to find out when we can write. 367 368 if (s->fds[POLL].out_flags & PR_POLL_READ) 369 { 370 /* Drain wakeup pipe. */ 371 uint8_t buf[32]; 321 RT_NOREF(hSelf); 322 323 nsresult rv = NS_OK; 324 ipcConnectionState *s = (ipcConnectionState *)pvArg; 325 326 // we monitor two file descriptors in this thread. the first (at index 0) is 327 // the socket connection with the IPC daemon. the second (at index 1) is the 328 // pollable event we monitor in order to know when to send messages to the 329 // IPC daemon. 330 331 while (NS_SUCCEEDED(rv)) 332 { 333 // 334 // poll on the IPC socket and NSPR pollable event 335 // 336 uint32_t fEvents; 337 uint32_t idPoll; 338 int vrc = RTPoll(s->hPollSet, RT_INDEFINITE_WAIT, &fEvents, &idPoll); 339 if (RT_SUCCESS(vrc)) 340 { 341 if (idPoll == SOCK) 342 { 343 /* check if we can read... */ 344 if (fEvents & RTPOLL_EVT_READ) 345 rv = ConnRead(s); 346 347 /* check if we can write... */ 348 if (fEvents & RTPOLL_EVT_WRITE) 349 rv = ConnWrite(s); 350 } 351 else 352 { 353 Assert( idPoll == POLL 354 && (fEvents & RTPOLL_EVT_READ) 355 && !(fEvents & (RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR))); 356 357 uint8_t buf[32]; 358 ipcCallbackQ cbs_to_run; 359 360 // check if something has been added to the send queue. if so, then 361 // acknowledge pollable event (wait should not block), and configure 362 // poll flags to find out when we can write. 363 364 /* Drain wakeup pipe. */ 365 size_t cbRead = 0; 366 vrc = RTPipeRead(s->hWakeupPipeR, &buf[0], sizeof(buf), &cbRead); 367 Assert(RT_SUCCESS(vrc) && cbRead > 0); 368 372 369 #ifdef DEBUG 373 PRIntn i; 370 /* Make sure this is not written with something else. */ 371 for (uint32_t i = 0; i < cbRead; i++) 372 Assert(buf[i] == magicChar); 374 373 #endif 375 PRInt32 nBytes = PR_Read(s->fds[POLL].fd, buf, sizeof(buf)); 376 Assert(nBytes > 0); 377 378 #ifdef DEBUG 379 /* Make sure this is not written with something else. */ 380 for (i = 0; i < nBytes; i++) { 381 Assert(buf[i] == magicChar); 382 } 383 #endif 384 385 RTCritSectEnter(&s->CritSect); 386 387 if (!s->send_queue.IsEmpty()) 388 s->fds[SOCK].in_flags |= PR_POLL_WRITE; 389 390 if (!s->callback_queue.IsEmpty()) 391 s->callback_queue.MoveTo(cbs_to_run); 392 393 RTCritSectLeave(&s->CritSect); 394 } 395 396 // check if we can read... 397 if (s->fds[SOCK].out_flags & PR_POLL_READ) 398 rv = ConnRead(s); 399 400 // check if we can write... 401 if (s->fds[SOCK].out_flags & PR_POLL_WRITE) 402 rv = ConnWrite(s); 403 404 // check if we have callbacks to run 405 while (!cbs_to_run.IsEmpty()) 406 { 407 ipcCallback *cb = cbs_to_run.First(); 408 (cb->func)(cb->arg); 409 cbs_to_run.DeleteFirst(); 410 } 411 412 // check if we should exit this thread. delay processing a shutdown 413 // request until after all queued up messages have been sent and until 414 // after all queued up callbacks have been run. 415 RTCritSectEnter(&s->CritSect); 416 if (s->shutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty()) 417 rv = NS_ERROR_ABORT; 418 RTCritSectLeave(&s->CritSect); 419 } 420 else 421 { 422 LOG(("PR_Poll returned error %d (%s), os error %d\n", PR_GetError(), 423 PR_ErrorToName(PR_GetError()), PR_GetOSError())); 424 rv = NS_ERROR_UNEXPECTED; 425 } 426 } 427 428 // notify termination of the IPC connection 429 if (rv == NS_ERROR_ABORT) 430 rv = NS_OK; 431 IPC_OnConnectionEnd(rv); 432 433 LOG(("IPC thread exiting\n")); 434 return VINF_SUCCESS; 374 375 RTCritSectEnter(&s->CritSect); 376 377 if (!s->send_queue.IsEmpty()) 378 { 379 vrc = RTPollSetEventsChange(s->hPollSet, SOCK, RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR); 380 AssertRC(vrc); 381 } 382 383 if (!s->callback_queue.IsEmpty()) 384 s->callback_queue.MoveTo(cbs_to_run); 385 386 // check if we should exit this thread. delay processing a shutdown 387 // request until after all queued up messages have been sent and until 388 // after all queued up callbacks have been run. 389 if (s->fShutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty()) 390 rv = NS_ERROR_ABORT; 391 392 RTCritSectLeave(&s->CritSect); 393 394 // check if we have callbacks to run 395 while (!cbs_to_run.IsEmpty()) 396 { 397 ipcCallback *cb = cbs_to_run.First(); 398 (cb->func)(cb->arg); 399 cbs_to_run.DeleteFirst(); 400 } 401 } 402 } 403 else 404 { 405 LogFlowFunc(("RTPoll returned error %Rrc\n", vrc)); 406 rv = NS_ERROR_UNEXPECTED; 407 } 408 } 409 410 // notify termination of the IPC connection 411 if (rv == NS_ERROR_ABORT) 412 rv = NS_OK; 413 IPC_OnConnectionEnd(rv); 414 415 LogFlowFunc(("IPC thread exiting\n")); 416 return VINF_SUCCESS; 435 417 } 436 418 … … 446 428 #endif 447 429 448 static nsresult 449 TryConnect(PRFileDesc **result) 450 { 451 PRFileDesc *fd; 452 PRNetAddr addr; 453 PRSocketOptionData opt; 454 // don't use NS_ERROR_FAILURE as we want to detect these kind of errors 455 // in the frontend 456 nsresult rv = NS_ERROR_SOCKET_FAIL; 457 458 fd = PR_OpenTCPSocket(PR_AF_LOCAL); 459 if (!fd) 460 goto end; 461 462 addr.local.family = PR_AF_LOCAL; 463 IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path)); 464 465 // blocking connect... will fail if no one is listening. 466 if (PR_Connect(fd, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) 467 goto end; 468 469 #ifdef VBOX 470 if (RTEnvExist("TESTBOX_UUID")) 471 fprintf(stderr, "IPC socket path: %s\n", addr.local.path); 472 LogRel(("IPC socket path: %s\n", addr.local.path)); 430 static nsresult TryConnect(RTSOCKET *phSocket) 431 { 432 struct sockaddr_un addr; 433 memset(&addr, 0, sizeof(addr)); 434 addr.sun_family = AF_UNIX; 435 IPC_GetDefaultSocketPath(addr.sun_path, sizeof(addr.sun_path) - 1); 436 437 // don't use NS_ERROR_FAILURE as we want to detect these kind of errors 438 // in the frontend 439 nsresult rv = NS_ERROR_SOCKET_FAIL; 440 441 int fdSock = socket(PF_UNIX, SOCK_STREAM, 0); 442 if (fdSock != -1) 443 { 444 /* Connect to the local socket. */ 445 if (connect(fdSock, (struct sockaddr *)&addr, sizeof(addr)) == 0) 446 { 447 if (RTEnvExist("TESTBOX_UUID")) 448 fprintf(stderr, "IPC socket path: %s\n", addr.sun_path); 449 LogRel(("IPC socket path: %s\n", addr.sun_path)); 450 451 // do some security checks on connection socket... 452 if (DoSecurityCheck(fdSock, addr.sun_path) == PR_SUCCESS) 453 { 454 int vrc = RTSocketFromNative(phSocket, fdSock); 455 if (RT_SUCCESS(vrc)) 456 return NS_OK; 457 } 458 } 459 460 close(fdSock); 461 } 462 463 return rv; 464 } 465 466 nsresult IPC_Connect(const char *daemonPath) 467 { 468 // synchronous connect, spawn daemon if necessary. 469 nsresult rv = NS_ERROR_FAILURE; 470 471 if (gConnState) 472 return NS_ERROR_ALREADY_INITIALIZED; 473 474 // 475 // here's the connection algorithm: try to connect to an existing daemon. 476 // if the connection fails, then spawn the daemon (wait for it to be ready), 477 // and then retry the connection. it is critical that the socket used to 478 // connect to the daemon not be inherited (this causes problems on RH9 at 479 // least). 480 // 481 482 RTSOCKET hSockConn = NIL_RTSOCKET; 483 rv = TryConnect(&hSockConn); 484 if (NS_FAILED(rv)) 485 { 486 nsresult rv1 = IPC_SpawnDaemon(daemonPath); 487 if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL) 488 rv = rv1; 489 if (NS_SUCCEEDED(rv)) 490 rv = TryConnect(&hSockConn); 491 } 492 493 if (NS_SUCCEEDED(rv)) 494 { 495 // 496 // ok, we have a connection to the daemon! 497 // 498 499 // build connection state object 500 gConnState = ConnCreate(hSockConn); 501 if (RT_LIKELY(gConnState)) 502 { 503 hSockConn = NIL_RTSOCKET; // connection state now owns the socket 504 505 int vrc = RTThreadCreate(&gConnThread, ipcConnThread, gConnState, 0 /*cbStack*/, 506 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Ipc-Conn"); 507 if (RT_SUCCESS(vrc)) 508 { 509 #ifdef DEBUG 510 gMainThread = RTThreadSelf(); 473 511 #endif 474 475 // make socket non-blocking 476 opt.option = PR_SockOpt_Nonblocking; 477 opt.value.non_blocking = PR_TRUE; 478 PR_SetSocketOption(fd, &opt); 479 480 // do some security checks on connection socket... 481 if (DoSecurityCheck(fd, addr.local.path) != PR_SUCCESS) 482 goto end; 483 484 *result = fd; 485 return NS_OK; 486 487 end: 488 if (fd) 489 PR_Close(fd); 490 491 return rv; 492 } 493 494 nsresult 495 IPC_Connect(const char *daemonPath) 496 { 497 // synchronous connect, spawn daemon if necessary. 498 499 PRFileDesc *fd = NULL; 500 nsresult rv = NS_ERROR_FAILURE; 501 int vrc = VINF_SUCCESS; 502 503 if (gConnState) 504 return NS_ERROR_ALREADY_INITIALIZED; 505 506 // 507 // here's the connection algorithm: try to connect to an existing daemon. 508 // if the connection fails, then spawn the daemon (wait for it to be ready), 509 // and then retry the connection. it is critical that the socket used to 510 // connect to the daemon not be inherited (this causes problems on RH9 at 511 // least). 512 // 513 514 rv = TryConnect(&fd); 515 if (NS_FAILED(rv)) 516 { 517 nsresult rv1 = IPC_SpawnDaemon(daemonPath); 518 if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL) 519 rv = rv1; 520 if (NS_SUCCEEDED(rv)) 521 rv = TryConnect(&fd); 522 } 523 524 if (NS_FAILED(rv)) 525 goto end; 526 527 // 528 // ok, we have a connection to the daemon! 529 // 530 531 // build connection state object 532 gConnState = ConnCreate(fd); 533 if (!gConnState) 534 { 535 rv = NS_ERROR_OUT_OF_MEMORY; 536 goto end; 537 } 538 fd = NULL; // connection state now owns the socket 539 540 vrc = RTThreadCreate(&gConnThread, ipcConnThread, gConnState, 0 /*cbStack*/, 541 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Ipc-Conn"); 542 if (RT_FAILURE(vrc)) 543 { 544 rv = NS_ERROR_OUT_OF_MEMORY; 545 goto end; 546 } 547 548 #ifdef DEBUG 549 gMainThread = RTThreadSelf(); 550 #endif 551 return NS_OK; 552 553 end: 554 if (gConnState) 555 { 556 ConnDestroy(gConnState); 557 gConnState = NULL; 558 } 559 if (fd) 560 PR_Close(fd); 561 return rv; 562 } 563 564 nsresult 565 IPC_Disconnect() 512 return NS_OK; 513 } 514 else 515 rv = NS_ERROR_OUT_OF_MEMORY; 516 } 517 else 518 rv = NS_ERROR_OUT_OF_MEMORY; 519 } 520 521 if (gConnState) 522 { 523 ConnDestroy(gConnState); 524 gConnState = NULL; 525 } 526 527 if (hSockConn != NIL_RTSOCKET) 528 RTSocketClose(hSockConn); 529 530 return rv; 531 } 532 533 nsresult IPC_Disconnect() 566 534 { 567 535 // Must disconnect on same thread used to connect! … … 574 542 575 543 RTCritSectEnter(&gConnState->CritSect); 576 gConnState-> shutdown = PR_TRUE;544 gConnState->fShutdown = true; 577 545 size_t cbWrittenIgn = 0; 578 546 int vrc = RTPipeWrite(gConnState->hWakeupPipeW, &magicChar, sizeof(magicChar), &cbWrittenIgn); … … 591 559 } 592 560 593 nsresult 594 IPC_SendMsg(ipcMessage *msg) 561 nsresult IPC_SendMsg(ipcMessage *msg) 595 562 { 596 563 if (!gConnState || !gConnThread) … … 607 574 } 608 575 609 nsresult 610 IPC_DoCallback(ipcCallbackFunc func, void *arg) 576 nsresult IPC_DoCallback(ipcCallbackFunc func, void *arg) 611 577 { 612 578 if (!gConnState || !gConnThread)
Note:
See TracChangeset
for help on using the changeset viewer.