1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
31 #define WIN32_LEAN_AND_MEAN
35 #include "camel-msgport.h"
38 #define MP_CLOSE(socket) closesocket (socket)
39 #define MP_READ(socket, buf, nbytes) recv((socket), (buf), (nbytes), 0)
40 #define MP_WRITE(socket, buf, nbytes) send((socket), (buf), (nbytes), 0)
41 #define MP_IS_STATUS_INTR() 0 /* No WSAEINTR errors in WinSock2 */
43 #define MP_CLOSE(socket) close (socket)
44 #define MP_READ(socket, buf, nbytes) read((socket), (buf), (nbytes))
45 #define MP_WRITE(socket, buf, nbytes) write((socket), (buf), (nbytes))
46 #define MP_IS_STATUS_INTR() (errno == EINTR)
51 MSG_FLAG_SYNC_WITH_PIPE = 1 << 0,
52 MSG_FLAG_SYNC_WITH_PR_PIPE = 1 << 1
55 struct _CamelMsgPort {
57 gint pipe[2]; /* on Win32, actually a pair of SOCKETs */
58 PRFileDesc *prpipe[2];
62 msgport_pipe (gint *fds)
73 SOCKET temp, socket1 = -1, socket2 = -1;
74 struct sockaddr_in saddr;
77 fd_set read_set, write_set;
80 temp = socket (AF_INET, SOCK_STREAM, 0);
82 if (temp == INVALID_SOCKET) {
87 if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) {
91 memset (&saddr, 0, sizeof (saddr));
92 saddr.sin_family = AF_INET;
94 saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
96 if (bind (temp, (struct sockaddr *) &saddr, sizeof (saddr))) {
100 if (listen (temp, 1) == SOCKET_ERROR) {
104 len = sizeof (saddr);
105 if (getsockname (temp, (struct sockaddr *) &saddr, &len)) {
109 socket1 = socket (AF_INET, SOCK_STREAM, 0);
111 if (socket1 == INVALID_SOCKET) {
116 if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) {
120 if (connect (socket1, (struct sockaddr *) &saddr, len) != SOCKET_ERROR ||
121 WSAGetLastError () != WSAEWOULDBLOCK) {
126 FD_SET (temp, &read_set);
131 if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) {
135 if (!FD_ISSET (temp, &read_set)) {
139 socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
140 if (socket2 == INVALID_SOCKET) {
144 FD_ZERO (&write_set);
145 FD_SET (socket1, &write_set);
150 if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) {
154 if (!FD_ISSET (socket1, &write_set)) {
159 if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) {
164 if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) {
176 closesocket (socket2);
178 closesocket (socket1);
181 errno = EMFILE; /* FIXME: use the real syscall errno? */
192 msgport_prpipe (PRFileDesc **fds)
195 if (PR_NewTCPSocketPair (fds) != PR_FAILURE)
198 if (PR_CreatePipe (&fds[0], &fds[1]) != PR_FAILURE)
209 msgport_sync_with_pipe (gint fd)
214 if (MP_READ (fd, buffer, 1) > 0)
216 else if (!MP_IS_STATUS_INTR ()) {
218 "%s: Failed to read from pipe: %s",
219 G_STRFUNC, g_strerror (errno));
226 msgport_sync_with_prpipe (PRFileDesc *prfd)
230 while (prfd != NULL) {
231 if (PR_Read (prfd, buffer, 1) > 0)
233 else if (PR_GetError () != PR_PENDING_INTERRUPT_ERROR) {
234 gchar *text = g_alloca (PR_GetErrorTextLength ());
235 PR_GetErrorText (text);
237 "%s: Failed to read from NSPR pipe: %s",
250 camel_msgport_new (void)
252 CamelMsgPort *msgport;
254 msgport = g_slice_new (CamelMsgPort);
255 msgport->queue = g_async_queue_new ();
256 msgport->pipe[0] = -1;
257 msgport->pipe[1] = -1;
258 msgport->prpipe[0] = NULL;
259 msgport->prpipe[1] = NULL;
265 * camel_msgport_destroy:
270 camel_msgport_destroy (CamelMsgPort *msgport)
272 g_return_if_fail (msgport != NULL);
274 if (msgport->pipe[0] >= 0) {
275 MP_CLOSE (msgport->pipe[0]);
276 MP_CLOSE (msgport->pipe[1]);
278 if (msgport->prpipe[0] != NULL) {
279 PR_Close (msgport->prpipe[0]);
280 PR_Close (msgport->prpipe[1]);
283 g_async_queue_unref (msgport->queue);
284 g_slice_free (CamelMsgPort, msgport);
293 camel_msgport_fd (CamelMsgPort *msgport)
297 g_return_val_if_fail (msgport != NULL, -1);
299 g_async_queue_lock (msgport->queue);
300 fd = msgport->pipe[0];
301 if (fd < 0 && msgport_pipe (msgport->pipe) == 0)
302 fd = msgport->pipe[0];
303 g_async_queue_unlock (msgport->queue);
309 * camel_msgport_prfd:
314 camel_msgport_prfd (CamelMsgPort *msgport)
318 g_return_val_if_fail (msgport != NULL, NULL);
320 g_async_queue_lock (msgport->queue);
321 prfd = msgport->prpipe[0];
322 if (prfd == NULL && msgport_prpipe (msgport->prpipe) == 0)
323 prfd = msgport->prpipe[0];
324 g_async_queue_unlock (msgport->queue);
330 * camel_msgport_push:
335 camel_msgport_push (CamelMsgPort *msgport,
341 g_return_if_fail (msgport != NULL);
342 g_return_if_fail (msg != NULL);
344 g_async_queue_lock (msgport->queue);
348 fd = msgport->pipe[1];
350 if (MP_WRITE (fd, "E", 1) > 0) {
351 msg->flags |= MSG_FLAG_SYNC_WITH_PIPE;
353 } else if (!MP_IS_STATUS_INTR ()) {
355 "%s: Failed to write to pipe: %s",
356 G_STRFUNC, g_strerror (errno));
361 prfd = msgport->prpipe[1];
362 while (prfd != NULL) {
363 if (PR_Write (prfd, "E", 1) > 0) {
364 msg->flags |= MSG_FLAG_SYNC_WITH_PR_PIPE;
366 } else if (PR_GetError () != PR_PENDING_INTERRUPT_ERROR) {
367 gchar *text = g_alloca (PR_GetErrorTextLength ());
368 PR_GetErrorText (text);
370 "%s: Failed to write to NSPR pipe: %s",
376 g_async_queue_push_unlocked (msgport->queue, msg);
377 g_async_queue_unlock (msgport->queue);
386 camel_msgport_pop (CamelMsgPort *msgport)
390 g_return_val_if_fail (msgport != NULL, NULL);
392 g_async_queue_lock (msgport->queue);
394 msg = g_async_queue_pop_unlocked (msgport->queue);
396 g_assert (msg != NULL);
398 if (msg->flags & MSG_FLAG_SYNC_WITH_PIPE)
399 msgport_sync_with_pipe (msgport->pipe[0]);
400 if (msg->flags & MSG_FLAG_SYNC_WITH_PR_PIPE)
401 msgport_sync_with_prpipe (msgport->prpipe[0]);
403 g_async_queue_unlock (msgport->queue);
409 * camel_msgport_try_pop:
414 camel_msgport_try_pop (CamelMsgPort *msgport)
418 g_return_val_if_fail (msgport != NULL, NULL);
420 g_async_queue_lock (msgport->queue);
422 msg = g_async_queue_try_pop_unlocked (msgport->queue);
424 if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PIPE)
425 msgport_sync_with_pipe (msgport->pipe[0]);
426 if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PR_PIPE)
427 msgport_sync_with_prpipe (msgport->prpipe[0]);
429 g_async_queue_unlock (msgport->queue);
435 * camel_msgport_timeout_pop:
436 * @msgport: a #CamelMsgPort
437 * @timeout: number of microseconds to wait
442 camel_msgport_timeout_pop (CamelMsgPort *msgport,
447 g_return_val_if_fail (msgport != NULL, NULL);
449 g_async_queue_lock (msgport->queue);
451 msg = g_async_queue_timeout_pop_unlocked (msgport->queue, timeout);
453 if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PIPE)
454 msgport_sync_with_pipe (msgport->pipe[0]);
455 if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PR_PIPE)
456 msgport_sync_with_prpipe (msgport->prpipe[0]);
458 g_async_queue_unlock (msgport->queue);
464 * camel_msgport_reply:
469 camel_msgport_reply (CamelMsg *msg)
471 g_return_if_fail (msg != NULL);
474 camel_msgport_push (msg->reply_port, msg);