1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport
4 * Copyright (C) 2002 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus-internals.h"
25 #include "dbus-connection-internal.h"
26 #include "dbus-transport-unix.h"
27 #include "dbus-transport-protected.h"
28 #include "dbus-watch.h"
29 #include <sys/types.h>
35 * @defgroup DBusTransportUnix DBusTransport implementations for UNIX
36 * @ingroup DBusInternals
37 * @brief Implementation details of DBusTransport on UNIX
43 * Opaque object representing a Unix file descriptor transport.
45 typedef struct DBusTransportUnix DBusTransportUnix;
48 * Implementation details of DBusTransportUnix. All members are private.
50 struct DBusTransportUnix
52 DBusTransport base; /**< Parent instance */
53 int fd; /**< File descriptor. */
54 DBusWatch *watch; /**< Watch for readability. */
55 DBusWatch *write_watch; /**< Watch for writability. */
57 int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
58 int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
60 int message_bytes_written; /**< Number of bytes of current
61 * outgoing message that have
64 DBusString encoded_message; /**< Encoded version of current
70 free_watches (DBusTransport *transport)
72 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
74 if (unix_transport->watch)
76 if (transport->connection)
77 _dbus_connection_remove_watch (transport->connection,
78 unix_transport->watch);
79 _dbus_watch_invalidate (unix_transport->watch);
80 _dbus_watch_unref (unix_transport->watch);
81 unix_transport->watch = NULL;
84 if (unix_transport->write_watch)
86 if (transport->connection)
87 _dbus_connection_remove_watch (transport->connection,
88 unix_transport->write_watch);
89 _dbus_watch_invalidate (unix_transport->write_watch);
90 _dbus_watch_unref (unix_transport->write_watch);
91 unix_transport->write_watch = NULL;
96 unix_finalize (DBusTransport *transport)
98 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
100 free_watches (transport);
102 _dbus_string_free (&unix_transport->encoded_message);
104 _dbus_transport_finalize_base (transport);
106 _dbus_assert (unix_transport->watch == NULL);
107 _dbus_assert (unix_transport->write_watch == NULL);
109 dbus_free (transport);
113 check_write_watch (DBusTransport *transport)
115 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
116 dbus_bool_t need_write_watch;
118 if (transport->connection == NULL)
121 _dbus_transport_ref (transport);
123 if (_dbus_transport_get_is_authenticated (transport))
124 need_write_watch = transport->messages_need_sending;
126 need_write_watch = transport->send_credentials_pending ||
127 _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
129 if (transport->disconnected)
130 need_write_watch = FALSE;
132 if (need_write_watch &&
133 unix_transport->write_watch == NULL)
135 unix_transport->write_watch =
136 _dbus_watch_new (unix_transport->fd,
137 DBUS_WATCH_WRITABLE);
139 /* we can maybe add it some other time, just silently bomb */
140 if (unix_transport->write_watch == NULL)
143 if (!_dbus_connection_add_watch (transport->connection,
144 unix_transport->write_watch))
146 _dbus_watch_invalidate (unix_transport->write_watch);
147 _dbus_watch_unref (unix_transport->write_watch);
148 unix_transport->write_watch = NULL;
151 else if (!need_write_watch &&
152 unix_transport->write_watch != NULL)
154 _dbus_connection_remove_watch (transport->connection,
155 unix_transport->write_watch);
156 _dbus_watch_invalidate (unix_transport->write_watch);
157 _dbus_watch_unref (unix_transport->write_watch);
158 unix_transport->write_watch = NULL;
161 _dbus_transport_unref (transport);
165 do_io_error (DBusTransport *transport)
167 _dbus_transport_ref (transport);
168 _dbus_transport_disconnect (transport);
169 _dbus_connection_transport_error (transport->connection,
170 DBUS_RESULT_DISCONNECTED);
171 _dbus_transport_unref (transport);
175 queue_messages (DBusTransport *transport)
177 DBusMessage *message;
179 /* Queue any messages */
180 while ((message = _dbus_message_loader_pop_message (transport->loader)))
182 _dbus_verbose ("queueing received message %p\n", message);
184 _dbus_connection_queue_received_message (transport->connection,
186 dbus_message_unref (message);
189 if (_dbus_message_loader_get_is_corrupted (transport->loader))
191 _dbus_verbose ("Corrupted message stream, disconnecting\n");
192 do_io_error (transport);
196 /* return value is whether we successfully read any new data. */
198 read_data_into_auth (DBusTransport *transport)
200 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
204 if (!_dbus_string_init (&buffer, _DBUS_INT_MAX))
206 /* just disconnect if we don't have memory
207 * to do an authentication
209 _dbus_verbose ("No memory for authentication\n");
210 do_io_error (transport);
214 bytes_read = _dbus_read (unix_transport->fd,
215 &buffer, unix_transport->max_bytes_read_per_iteration);
219 _dbus_verbose (" read %d bytes in auth phase\n", bytes_read);
221 if (_dbus_auth_bytes_received (transport->auth,
224 _dbus_string_free (&buffer);
225 return TRUE; /* We did read some data! woo! */
229 /* just disconnect if we don't have memory to do an
230 * authentication, don't fool with trying to save the buffer
231 * and who knows what.
233 _dbus_verbose ("No memory for authentication\n");
234 do_io_error (transport);
237 else if (bytes_read < 0)
239 /* EINTR already handled for us */
241 if (errno == EAGAIN ||
242 errno == EWOULDBLOCK)
243 ; /* do nothing, just return FALSE below */
246 _dbus_verbose ("Error reading from remote app: %s\n",
247 _dbus_strerror (errno));
248 do_io_error (transport);
251 else if (bytes_read == 0)
253 _dbus_verbose ("Disconnected from remote app\n");
254 do_io_error (transport);
257 _dbus_string_free (&buffer);
261 /* Return value is whether we successfully wrote any bytes */
263 write_data_from_auth (DBusTransport *transport)
265 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
267 const DBusString *buffer;
269 if (!_dbus_auth_get_bytes_to_send (transport->auth,
273 bytes_written = _dbus_write (unix_transport->fd,
275 0, _dbus_string_get_length (buffer));
277 if (bytes_written > 0)
279 _dbus_auth_bytes_sent (transport->auth, bytes_written);
282 else if (bytes_written < 0)
284 /* EINTR already handled for us */
286 if (errno == EAGAIN ||
287 errno == EWOULDBLOCK)
291 _dbus_verbose ("Error writing to remote app: %s\n",
292 _dbus_strerror (errno));
293 do_io_error (transport);
301 recover_unused_bytes (DBusTransport *transport)
304 if (_dbus_auth_needs_decoding (transport->auth))
306 DBusString plaintext;
311 if (!_dbus_string_init (&plaintext, _DBUS_INT_MAX))
314 if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
316 _dbus_string_free (&plaintext);
320 if (!_dbus_auth_get_unused_bytes (transport->auth,
323 _dbus_string_free (&plaintext);
324 _dbus_string_free (&encoded);
328 if (!_dbus_auth_decode_data (transport->auth,
329 &encoded, &plaintext))
331 _dbus_string_free (&plaintext);
332 _dbus_string_free (&encoded);
336 _dbus_message_loader_get_buffer (transport->loader,
339 orig_len = _dbus_string_get_length (buffer);
341 if (!_dbus_string_move (&plaintext, 0, buffer,
344 _dbus_string_free (&plaintext);
345 _dbus_string_free (&encoded);
349 _dbus_verbose (" %d unused bytes sent to message loader\n",
350 _dbus_string_get_length (buffer) -
353 _dbus_message_loader_return_buffer (transport->loader,
355 _dbus_string_get_length (buffer) -
358 _dbus_string_free (&plaintext);
359 _dbus_string_free (&encoded);
366 _dbus_message_loader_get_buffer (transport->loader,
369 orig_len = _dbus_string_get_length (buffer);
371 if (!_dbus_auth_get_unused_bytes (transport->auth,
375 _dbus_verbose (" %d unused bytes sent to message loader\n",
376 _dbus_string_get_length (buffer) -
379 _dbus_message_loader_return_buffer (transport->loader,
381 _dbus_string_get_length (buffer) -
385 queue_messages (transport);
390 _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
391 do_io_error (transport);
395 exchange_credentials (DBusTransport *transport,
396 dbus_bool_t do_reading,
397 dbus_bool_t do_writing)
399 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
401 if (do_writing && transport->send_credentials_pending)
403 if (_dbus_send_credentials_unix_socket (unix_transport->fd,
406 transport->send_credentials_pending = FALSE;
410 _dbus_verbose ("Failed to write credentials\n");
411 do_io_error (transport);
415 if (do_reading && transport->receive_credentials_pending)
417 if (_dbus_read_credentials_unix_socket (unix_transport->fd,
418 &transport->credentials,
421 transport->receive_credentials_pending = FALSE;
425 _dbus_verbose ("Failed to read credentials\n");
426 do_io_error (transport);
430 if (!(transport->send_credentials_pending ||
431 transport->receive_credentials_pending))
433 _dbus_auth_set_credentials (transport->auth,
434 &transport->credentials);
439 do_authentication (DBusTransport *transport,
440 dbus_bool_t do_reading,
441 dbus_bool_t do_writing)
443 _dbus_transport_ref (transport);
445 while (!_dbus_transport_get_is_authenticated (transport) &&
446 _dbus_transport_get_is_connected (transport))
448 exchange_credentials (transport, do_reading, do_writing);
450 if (transport->send_credentials_pending ||
451 transport->receive_credentials_pending)
453 _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n",
454 transport->send_credentials_pending,
455 transport->receive_credentials_pending);
459 switch (_dbus_auth_do_work (transport->auth))
461 case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
462 _dbus_verbose (" auth state: waiting for input\n");
463 if (!do_reading || !read_data_into_auth (transport))
467 case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
468 /* Screw it, just disconnect */
469 _dbus_verbose (" auth state: waiting for memory\n");
470 do_io_error (transport);
473 case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
474 _dbus_verbose (" auth state: bytes to send\n");
475 if (!do_writing || !write_data_from_auth (transport))
479 case DBUS_AUTH_STATE_NEED_DISCONNECT:
480 _dbus_verbose (" auth state: need to disconnect\n");
481 do_io_error (transport);
484 case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
485 _dbus_verbose (" auth state: auth with unused bytes\n");
486 recover_unused_bytes (transport);
489 case DBUS_AUTH_STATE_AUTHENTICATED:
490 _dbus_verbose (" auth state: authenticated\n");
496 check_write_watch (transport);
497 _dbus_transport_unref (transport);
501 do_writing (DBusTransport *transport)
504 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
506 /* No messages without authentication! */
507 if (!_dbus_transport_get_is_authenticated (transport))
510 if (transport->disconnected)
515 while (!transport->disconnected &&
516 _dbus_connection_have_messages_to_send (transport->connection))
519 DBusMessage *message;
520 const DBusString *header;
521 const DBusString *body;
522 int header_len, body_len;
523 int total_bytes_to_write;
525 if (total > unix_transport->max_bytes_written_per_iteration)
527 _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
528 total, unix_transport->max_bytes_written_per_iteration);
532 message = _dbus_connection_get_message_to_send (transport->connection);
533 _dbus_assert (message != NULL);
534 _dbus_message_lock (message);
536 _dbus_verbose ("writing message %p\n", message);
538 _dbus_message_get_network_data (message,
541 header_len = _dbus_string_get_length (header);
542 body_len = _dbus_string_get_length (body);
544 if (_dbus_auth_needs_encoding (transport->auth))
546 if (_dbus_string_get_length (&unix_transport->encoded_message) == 0)
548 if (!_dbus_auth_encode_data (transport->auth,
549 header, &unix_transport->encoded_message))
552 if (!_dbus_auth_encode_data (transport->auth,
553 body, &unix_transport->encoded_message))
555 _dbus_string_set_length (&unix_transport->encoded_message, 0);
560 total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_message);
562 _dbus_verbose ("encoded message is %d bytes\n",
563 total_bytes_to_write);
566 _dbus_write (unix_transport->fd,
567 &unix_transport->encoded_message,
568 unix_transport->message_bytes_written,
569 total_bytes_to_write - unix_transport->message_bytes_written);
573 total_bytes_to_write = header_len + body_len;
575 _dbus_verbose ("message is %d bytes\n",
576 total_bytes_to_write);
578 if (unix_transport->message_bytes_written < header_len)
581 _dbus_write_two (unix_transport->fd,
583 unix_transport->message_bytes_written,
584 header_len - unix_transport->message_bytes_written,
591 _dbus_write (unix_transport->fd,
593 (unix_transport->message_bytes_written - header_len),
595 (unix_transport->message_bytes_written - header_len));
599 if (bytes_written < 0)
601 /* EINTR already handled for us */
603 if (errno == EAGAIN ||
604 errno == EWOULDBLOCK)
608 _dbus_verbose ("Error writing to remote app: %s\n",
609 _dbus_strerror (errno));
610 do_io_error (transport);
616 _dbus_verbose (" wrote %d bytes of %d\n", bytes_written,
617 total_bytes_to_write);
619 total += bytes_written;
620 unix_transport->message_bytes_written += bytes_written;
622 _dbus_assert (unix_transport->message_bytes_written <=
623 total_bytes_to_write);
625 if (unix_transport->message_bytes_written == total_bytes_to_write)
627 unix_transport->message_bytes_written = 0;
628 _dbus_string_set_length (&unix_transport->encoded_message, 0);
630 _dbus_connection_message_sent (transport->connection,
637 return; /* I think some C compilers require a statement after a label */
641 do_reading (DBusTransport *transport)
643 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
648 /* No messages without authentication! */
649 if (!_dbus_transport_get_is_authenticated (transport))
656 if (total > unix_transport->max_bytes_read_per_iteration)
658 _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n",
659 total, unix_transport->max_bytes_read_per_iteration);
663 if (transport->disconnected)
666 if (_dbus_auth_needs_decoding (transport->auth))
670 if (!_dbus_string_init (&encoded, _DBUS_INT_MAX))
671 goto out; /* not enough memory for the moment */
673 bytes_read = _dbus_read (unix_transport->fd,
675 unix_transport->max_bytes_read_per_iteration);
681 _dbus_message_loader_get_buffer (transport->loader,
684 orig_len = _dbus_string_get_length (buffer);
686 if (!_dbus_auth_decode_data (transport->auth,
689 /* FIXME argh, we are really fucked here - nowhere to
690 * put "encoded" while we wait for more memory. Just
691 * screw it for now and disconnect. The failure may be
692 * due to badly-encoded data instead of lack of memory
695 _dbus_verbose ("Disconnected from remote app due to failure decoding data\n");
696 do_io_error (transport);
699 _dbus_message_loader_return_buffer (transport->loader,
701 _dbus_string_get_length (buffer) - orig_len);
704 _dbus_string_free (&encoded);
708 _dbus_message_loader_get_buffer (transport->loader,
711 bytes_read = _dbus_read (unix_transport->fd,
712 buffer, unix_transport->max_bytes_read_per_iteration);
714 _dbus_message_loader_return_buffer (transport->loader,
716 bytes_read < 0 ? 0 : bytes_read);
721 /* EINTR already handled for us */
723 if (errno == EAGAIN ||
724 errno == EWOULDBLOCK)
728 _dbus_verbose ("Error reading from remote app: %s\n",
729 _dbus_strerror (errno));
730 do_io_error (transport);
734 else if (bytes_read == 0)
736 _dbus_verbose ("Disconnected from remote app\n");
737 do_io_error (transport);
742 _dbus_verbose (" read %d bytes\n", bytes_read);
746 queue_messages (transport);
748 /* Try reading more data until we get EAGAIN and return, or
749 * exceed max bytes per iteration. If in blocking mode of
750 * course we'll block instead of returning.
756 return; /* I think some C compilers require a statement after a label */
760 unix_handle_watch (DBusTransport *transport,
764 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
766 _dbus_assert (watch == unix_transport->watch ||
767 watch == unix_transport->write_watch);
769 if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
771 _dbus_transport_disconnect (transport);
772 _dbus_connection_transport_error (transport->connection,
773 DBUS_RESULT_DISCONNECTED);
777 if (watch == unix_transport->watch &&
778 (flags & DBUS_WATCH_READABLE))
780 _dbus_verbose ("handling read watch\n");
781 do_authentication (transport, TRUE, FALSE);
782 do_reading (transport);
784 else if (watch == unix_transport->write_watch &&
785 (flags & DBUS_WATCH_WRITABLE))
787 _dbus_verbose ("handling write watch\n");
788 do_authentication (transport, FALSE, TRUE);
789 do_writing (transport);
794 unix_disconnect (DBusTransport *transport)
796 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
798 free_watches (transport);
800 close (unix_transport->fd);
801 unix_transport->fd = -1;
805 unix_connection_set (DBusTransport *transport)
807 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
810 _dbus_assert (unix_transport->watch == NULL);
812 watch = _dbus_watch_new (unix_transport->fd,
813 DBUS_WATCH_READABLE);
817 _dbus_transport_disconnect (transport);
821 if (!_dbus_connection_add_watch (transport->connection,
824 _dbus_transport_disconnect (transport);
825 _dbus_watch_unref (watch);
829 unix_transport->watch = watch;
831 check_write_watch (transport);
835 unix_messages_pending (DBusTransport *transport,
836 int messages_pending)
838 check_write_watch (transport);
841 /* FIXME use _dbus_poll(), not select() */
843 unix_do_iteration (DBusTransport *transport,
845 int timeout_milliseconds)
847 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
850 dbus_bool_t do_select;
852 /* "again" has to be up here because on EINTR the fd sets become
859 /* the passed in DO_READING/DO_WRITING flags indicate whether to
860 * read/write messages, but regardless of those we may need to block
861 * for reading/writing to do auth. But if we do reading for auth,
862 * we don't want to read any messages yet if not given DO_READING.
866 FD_ZERO (&write_set);
868 if (_dbus_transport_get_is_authenticated (transport))
870 if (flags & DBUS_ITERATION_DO_READING)
872 FD_SET (unix_transport->fd, &read_set);
877 if (flags & DBUS_ITERATION_DO_WRITING)
879 FD_SET (unix_transport->fd, &write_set);
885 DBusAuthState auth_state;
887 auth_state = _dbus_auth_do_work (transport->auth);
889 if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
891 FD_SET (unix_transport->fd, &read_set);
895 if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
897 FD_SET (unix_transport->fd, &write_set);
905 struct timeval timeout;
906 dbus_bool_t use_timeout;
909 FD_SET (unix_transport->fd, &err_set);
911 if (flags & DBUS_ITERATION_BLOCK)
913 if (timeout_milliseconds >= 0)
915 timeout.tv_sec = timeout_milliseconds / 1000;
916 timeout.tv_usec = (timeout_milliseconds % 1000) * 1000;
918 /* Always use timeout if one is passed in. */
923 use_timeout = FALSE; /* NULL timeout to block forever */
928 /* 0 timeout to not block */
934 if (select (unix_transport->fd + 1, &read_set, &write_set, &err_set,
935 use_timeout ? &timeout : NULL) >= 0)
937 if (FD_ISSET (unix_transport->fd, &err_set))
938 do_io_error (transport);
941 dbus_bool_t need_read = FD_ISSET (unix_transport->fd, &read_set);
942 dbus_bool_t need_write = FD_ISSET (unix_transport->fd, &write_set);
944 _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
945 need_read, need_write);
946 do_authentication (transport, need_read, need_write);
948 if (need_read && (flags & DBUS_ITERATION_DO_READING))
949 do_reading (transport);
950 if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
951 do_writing (transport);
954 else if (errno == EINTR)
958 _dbus_verbose ("Error from select(): %s\n",
959 _dbus_strerror (errno));
964 static DBusTransportVTable unix_vtable = {
969 unix_messages_pending,
974 * Creates a new transport for the given file descriptor. The file
975 * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
976 * make it so). This function is shared by various transports that
977 * boil down to a full duplex file descriptor.
979 * @param fd the file descriptor.
980 * @param server #TRUE if this transport is on the server side of a connection
981 * @returns the new transport, or #NULL if no memory.
984 _dbus_transport_new_for_fd (int fd,
987 DBusTransportUnix *unix_transport;
989 unix_transport = dbus_new0 (DBusTransportUnix, 1);
990 if (unix_transport == NULL)
993 if (!_dbus_string_init (&unix_transport->encoded_message,
996 dbus_free (unix_transport);
1000 if (!_dbus_transport_init_base (&unix_transport->base,
1004 _dbus_string_free (&unix_transport->encoded_message);
1005 dbus_free (unix_transport);
1009 unix_transport->fd = fd;
1010 unix_transport->message_bytes_written = 0;
1012 /* These values should probably be tunable or something. */
1013 unix_transport->max_bytes_read_per_iteration = 2048;
1014 unix_transport->max_bytes_written_per_iteration = 2048;
1016 check_write_watch ((DBusTransport*) unix_transport);
1018 return (DBusTransport*) unix_transport;
1022 * Creates a new transport for the given Unix domain socket
1025 * @param path the path to the domain socket.
1026 * @param server #TRUE if this transport is on the server side of a connection
1027 * @param result location to store reason for failure.
1028 * @returns a new transport, or #NULL on failure.
1031 _dbus_transport_new_for_domain_socket (const char *path,
1033 DBusResultCode *result)
1036 DBusTransport *transport;
1038 fd = _dbus_connect_unix_socket (path, result);
1042 _dbus_verbose ("Successfully connected to unix socket %s\n",
1045 transport = _dbus_transport_new_for_fd (fd, server);
1046 if (transport == NULL)
1048 dbus_set_result (result, DBUS_RESULT_NO_MEMORY);