a47756f2e56bf9e643c5e87a885c88f0a216c52b
[platform/upstream/dbus.git] / dbus / dbus-transport-unix.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport
3  *
4  * Copyright (C) 2002, 2003, 2004  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
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.
12  *
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.
17  * 
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <config.h>
25 #include "dbus-internals.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-transport-unix.h"
28 #include "dbus-transport-socket.h"
29 #include "dbus-transport-protected.h"
30 #include "dbus-watch.h"
31 #include "dbus-sysdeps-unix.h"
32
33 /**
34  * @defgroup DBusTransportUnix DBusTransport implementations for UNIX
35  * @ingroup  DBusInternals
36  * @brief Implementation details of DBusTransport on UNIX
37  *
38  * @{
39  */
40
41 /**
42  * Creates a new transport for the given Unix domain socket
43  * path. This creates a client-side of a transport.
44  *
45  * @todo once we add a way to escape paths in a dbus
46  * address, this function needs to do escaping.
47  *
48  * @param path the path to the domain socket.
49  * @param abstract #TRUE to use abstract socket namespace
50  * @param error address where an error can be returned.
51  * @returns a new transport, or #NULL on failure.
52  */
53 DBusTransport*
54 _dbus_transport_new_for_domain_socket (const char     *path,
55                                        dbus_bool_t     abstract,
56                                        DBusError      *error)
57 {
58   int fd;
59   DBusTransport *transport;
60   DBusString address;
61   
62   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
63
64   if (!_dbus_string_init (&address))
65     {
66       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
67       return NULL;
68     }
69
70   fd = -1;
71
72   if ((abstract &&
73        !_dbus_string_append (&address, "unix:abstract=")) ||
74       (!abstract &&
75        !_dbus_string_append (&address, "unix:path=")) ||
76       !_dbus_string_append (&address, path))
77     {
78       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
79       goto failed_0;
80     }
81   
82   fd = _dbus_connect_unix_socket (path, abstract, error);
83   if (fd < 0)
84     {
85       _DBUS_ASSERT_ERROR_IS_SET (error);
86       goto failed_0;
87     }
88
89   _dbus_verbose ("Successfully connected to unix socket %s\n",
90                  path);
91
92   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
93   if (transport == NULL)
94     {
95       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
96       goto failed_1;
97     }
98   
99   _dbus_string_free (&address);
100   
101   return transport;
102
103  failed_1:
104   _dbus_close_socket (fd, NULL);
105  failed_0:
106   _dbus_string_free (&address);
107   return NULL;
108 }
109
110 /**
111  * Opens platform specific transport types.
112  * 
113  * @param entry the address entry to try opening
114  * @param transport_p return location for the opened transport
115  * @param error error to be set
116  * @returns result of the attempt
117  */
118 DBusTransportOpenResult
119 _dbus_transport_open_platform_specific (DBusAddressEntry  *entry,
120                                         DBusTransport    **transport_p,
121                                         DBusError         *error)
122 {
123   const char *method;
124   
125   method = dbus_address_entry_get_method (entry);
126   _dbus_assert (method != NULL);
127
128   if (strcmp (method, "unix") == 0)
129     {
130       const char *path = dbus_address_entry_get_value (entry, "path");
131       const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
132       const char *abstract = dbus_address_entry_get_value (entry, "abstract");
133           
134       if (tmpdir != NULL)
135         {
136           _dbus_set_bad_address (error, NULL, NULL,
137                                  "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on");
138           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
139         }
140           
141       if (path == NULL && abstract == NULL)
142         {
143           _dbus_set_bad_address (error, "unix",
144                                  "path or abstract",
145                                  NULL);
146           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
147         }
148
149       if (path != NULL && abstract != NULL)
150         {
151           _dbus_set_bad_address (error, NULL, NULL,
152                                  "can't specify both \"path\" and \"abstract\" options in an address");
153           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
154         }
155
156       if (path)
157         *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE,
158                                                            error);
159       else
160         *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE,
161                                                            error);
162       if (*transport_p == NULL)
163         {
164           _DBUS_ASSERT_ERROR_IS_SET (error);
165           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
166         }
167       else
168         {
169           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
170           return DBUS_TRANSPORT_OPEN_OK;
171         }      
172     }
173 #ifdef DBUS_ENABLE_LAUNCHD
174   else if (strcmp (method, "launchd") == 0)
175     {
176       DBusError tmp_error = DBUS_ERROR_INIT;
177       const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
178       const char *launchd_socket;
179       DBusString socket_path;
180       dbus_bool_t valid_socket;
181
182       if (!_dbus_string_init (&socket_path))
183         {
184           _DBUS_SET_OOM (error);
185           return FALSE;
186         }
187
188       if (launchd_env_var == NULL)
189         {
190           _dbus_set_bad_address (error, "launchd", "env", NULL);
191           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
192         }
193
194       valid_socket = _dbus_lookup_launchd_socket (&socket_path, launchd_env_var, error);
195
196       if (dbus_error_is_set(error))
197         {
198           _dbus_string_free(&socket_path);
199           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
200         }
201
202       if (!valid_socket)
203         {
204           dbus_set_error(&tmp_error, DBUS_ERROR_BAD_ADDRESS,
205                          "launchd's env var %s does not exist", launchd_env_var);
206           dbus_error_free(error);
207           dbus_move_error(&tmp_error, error);
208           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
209         }
210
211       launchd_socket = _dbus_string_get_const_data(&socket_path);
212       *transport_p = _dbus_transport_new_for_domain_socket (launchd_socket, FALSE, error);
213
214       if (*transport_p == NULL)
215         {
216           _DBUS_ASSERT_ERROR_IS_SET (error);
217           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
218         }
219       else
220         {
221           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
222           return DBUS_TRANSPORT_OPEN_OK;
223         }
224     }
225 #endif
226   else
227     {
228       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
229       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
230     }
231 }
232
233 /** @} */