1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-server-socket.c Server implementation for sockets 3 * 4 * Copyright (C) 2002, 2003, 2004, 2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include "dbus-internals.h" 25 #include "dbus-server-socket.h" 26 #include "dbus-transport-socket.h" 27 #include "dbus-connection-internal.h" 28 #include "dbus-string.h" 29 30 /** 31 * @defgroup DBusServerSocket DBusServer implementations for SOCKET 32 * @ingroup DBusInternals 33 * @brief Implementation details of DBusServer on SOCKET 34 * 35 * @{ 36 */ 37 /** 38 * 39 * Opaque object representing a Socket server implementation. 40 */ 41 typedef struct DBusServerSocket DBusServerSocket; 42 43 /** 44 * Implementation details of DBusServerSocket. All members 45 * are private. 46 */ 47 struct DBusServerSocket 48 { 49 DBusServer base; /**< Parent class members. */ 50 int fd; /**< File descriptor or -1 if disconnected. */ 51 DBusWatch *watch; /**< File descriptor watch. */ 52 char *socket_name; /**< Name of domain socket, to unlink if appropriate */ 53 }; 54 55 static void 56 socket_finalize (DBusServer *server) 57 { 58 DBusServerSocket *socket_server = (DBusServerSocket*) server; 59 60 _dbus_server_finalize_base (server); 61 62 if (socket_server->watch) 63 { 64 _dbus_watch_unref (socket_server->watch); 65 socket_server->watch = NULL; 66 } 67 68 dbus_free (socket_server->socket_name); 69 dbus_free (server); 70 } 71 72 /* Return value is just for memory, not other failures. */ 73 static dbus_bool_t 74 handle_new_client_fd_and_unlock (DBusServer *server, 75 int client_fd) 76 { 77 DBusConnection *connection; 78 DBusTransport *transport; 79 DBusNewConnectionFunction new_connection_function; 80 void *new_connection_data; 81 82 _dbus_verbose ("Creating new client connection with fd %d\n", client_fd); 83 84 HAVE_LOCK_CHECK (server); 85 86 if (!_dbus_set_fd_nonblocking (client_fd, NULL)) 87 { 88 SERVER_UNLOCK (server); 89 return TRUE; 90 } 91 92 transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL); 93 if (transport == NULL) 94 { 95 _dbus_close_socket (client_fd, NULL); 96 SERVER_UNLOCK (server); 97 return FALSE; 98 } 99 100 if (!_dbus_transport_set_auth_mechanisms (transport, 101 (const char **) server->auth_mechanisms)) 102 { 103 _dbus_transport_unref (transport); 104 SERVER_UNLOCK (server); 105 return FALSE; 106 } 107 108 /* note that client_fd is now owned by the transport, and will be 109 * closed on transport disconnection/finalization 110 */ 111 112 connection = _dbus_connection_new_for_transport (transport); 113 _dbus_transport_unref (transport); 114 transport = NULL; /* now under the connection lock */ 115 116 if (connection == NULL) 117 { 118 SERVER_UNLOCK (server); 119 return FALSE; 120 } 121 122 /* See if someone wants to handle this new connection, self-referencing 123 * for paranoia. 124 */ 125 new_connection_function = server->new_connection_function; 126 new_connection_data = server->new_connection_data; 127 128 _dbus_server_ref_unlocked (server); 129 SERVER_UNLOCK (server); 130 131 if (new_connection_function) 132 { 133 (* new_connection_function) (server, connection, 134 new_connection_data); 135 } 136 dbus_server_unref (server); 137 138 /* If no one grabbed a reference, the connection will die. */ 139 _dbus_connection_close_if_only_one_ref (connection); 140 dbus_connection_unref (connection); 141 142 return TRUE; 143 } 144 145 static dbus_bool_t 146 socket_handle_watch (DBusWatch *watch, 147 unsigned int flags, 148 void *data) 149 { 150 DBusServer *server = data; 151 DBusServerSocket *socket_server = data; 152 153 SERVER_LOCK (server); 154 155 _dbus_assert (watch == socket_server->watch); 156 157 _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); 158 159 if (flags & DBUS_WATCH_READABLE) 160 { 161 int client_fd; 162 int listen_fd; 163 164 listen_fd = dbus_watch_get_fd (watch); 165 166 client_fd = _dbus_accept (listen_fd); 167 168 if (client_fd < 0) 169 { 170 /* EINTR handled for us */ 171 172 if (errno == EAGAIN || errno == EWOULDBLOCK) 173 _dbus_verbose ("No client available to accept after all\n"); 174 else 175 _dbus_verbose ("Failed to accept a client connection: %s\n", 176 _dbus_strerror (errno)); 177 178 SERVER_UNLOCK (server); 179 } 180 else 181 { 182 _dbus_fd_set_close_on_exec (client_fd); 183 184 if (!handle_new_client_fd_and_unlock (server, client_fd)) 185 _dbus_verbose ("Rejected client connection due to lack of memory\n"); 186 } 187 } 188 189 if (flags & DBUS_WATCH_ERROR) 190 _dbus_verbose ("Error on server listening socket\n"); 191 192 if (flags & DBUS_WATCH_HANGUP) 193 _dbus_verbose ("Hangup on server listening socket\n"); 194 195 return TRUE; 196 } 197 198 static void 199 socket_disconnect (DBusServer *server) 200 { 201 DBusServerSocket *socket_server = (DBusServerSocket*) server; 202 203 HAVE_LOCK_CHECK (server); 204 205 if (socket_server->watch) 206 { 207 _dbus_server_remove_watch (server, 208 socket_server->watch); 209 _dbus_watch_unref (socket_server->watch); 210 socket_server->watch = NULL; 211 } 212 213 _dbus_close_socket (socket_server->fd, NULL); 214 socket_server->fd = -1; 215 216 if (socket_server->socket_name != NULL) 217 { 218 DBusString tmp; 219 _dbus_string_init_const (&tmp, socket_server->socket_name); 220 _dbus_delete_file (&tmp, NULL); 221 } 222 223 HAVE_LOCK_CHECK (server); 224 } 225 226 static const DBusServerVTable socket_vtable = { 227 socket_finalize, 228 socket_disconnect 229 }; 230 231 /** 232 * Creates a new server listening on the given file descriptor. The 233 * file descriptor should be nonblocking (use 234 * _dbus_set_fd_nonblocking() to make it so). The file descriptor 235 * should be listening for connections, that is, listen() should have 236 * been successfully invoked on it. The server will use accept() to 237 * accept new client connections. 238 * 239 * @param fd the file descriptor. 240 * @param address the server's address 241 * @returns the new server, or #NULL if no memory. 242 * 243 */ 244 DBusServer* 245 _dbus_server_new_for_socket (int fd, 246 const DBusString *address) 247 { 248 DBusServerSocket *socket_server; 249 DBusServer *server; 250 DBusWatch *watch; 251 252 socket_server = dbus_new0 (DBusServerSocket, 1); 253 if (socket_server == NULL) 254 return NULL; 255 256 watch = _dbus_watch_new (fd, 257 DBUS_WATCH_READABLE, 258 TRUE, 259 socket_handle_watch, socket_server, 260 NULL); 261 if (watch == NULL) 262 { 263 dbus_free (socket_server); 264 return NULL; 265 } 266 267 if (!_dbus_server_init_base (&socket_server->base, 268 &socket_vtable, address)) 269 { 270 _dbus_watch_unref (watch); 271 dbus_free (socket_server); 272 return NULL; 273 } 274 275 server = (DBusServer*) socket_server; 276 277 SERVER_LOCK (server); 278 279 if (!_dbus_server_add_watch (&socket_server->base, 280 watch)) 281 { 282 SERVER_UNLOCK (server); 283 _dbus_server_finalize_base (&socket_server->base); 284 _dbus_watch_unref (watch); 285 dbus_free (socket_server); 286 return NULL; 287 } 288 289 socket_server->fd = fd; 290 socket_server->watch = watch; 291 292 SERVER_UNLOCK (server); 293 294 return (DBusServer*) socket_server; 295 } 296 297 /** 298 * Creates a new server listening on the given hostname and port. 299 * If the hostname is NULL, listens on localhost. 300 * 301 * @param host the hostname to listen on. 302 * @param port the port to listen on. 303 * @param error location to store reason for failure. 304 * @returns the new server, or #NULL on failure. 305 */ 306 DBusServer* 307 _dbus_server_new_for_tcp_socket (const char *host, 308 dbus_uint32_t port, 309 DBusError *error) 310 { 311 DBusServer *server; 312 int listen_fd; 313 DBusString address; 314 DBusString host_str; 315 316 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 317 318 if (!_dbus_string_init (&address)) 319 { 320 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 321 return NULL; 322 } 323 324 if (host == NULL) 325 host = "localhost"; 326 327 _dbus_string_init_const (&host_str, host); 328 if (!_dbus_string_append (&address, "tcp:host=") || 329 !_dbus_address_append_escaped (&address, &host_str) || 330 !_dbus_string_append (&address, ",port=") || 331 !_dbus_string_append_int (&address, port)) 332 { 333 _dbus_string_free (&address); 334 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 335 return NULL; 336 } 337 338 listen_fd = _dbus_listen_tcp_socket (host, port, error); 339 _dbus_fd_set_close_on_exec (listen_fd); 340 341 if (listen_fd < 0) 342 { 343 _dbus_string_free (&address); 344 return NULL; 345 } 346 347 server = _dbus_server_new_for_socket (listen_fd, &address); 348 if (server == NULL) 349 { 350 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 351 _dbus_close_socket (listen_fd, NULL); 352 _dbus_string_free (&address); 353 return NULL; 354 } 355 356 _dbus_string_free (&address); 357 358 return server; 359 360 361 } 362 363 /** 364 * Tries to interpret the address entry for various socket-related 365 * addresses (well, currently only tcp). 366 * 367 * Sets error if the result is not OK. 368 * 369 * @param entry an address entry 370 * @param server_p a new DBusServer, or #NULL on failure. 371 * @param error location to store rationale for failure on bad address 372 * @returns the outcome 373 * 374 */ 375 DBusServerListenResult 376 _dbus_server_listen_socket (DBusAddressEntry *entry, 377 DBusServer **server_p, 378 DBusError *error) 379 { 380 const char *method; 381 382 *server_p = NULL; 383 384 method = dbus_address_entry_get_method (entry); 385 386 if (strcmp (method, "tcp") == 0) 387 { 388 const char *host = dbus_address_entry_get_value (entry, "host"); 389 const char *port = dbus_address_entry_get_value (entry, "port"); 390 DBusString str; 391 long lport; 392 dbus_bool_t sresult; 393 394 if (port == NULL) 395 { 396 _dbus_set_bad_address(error, "tcp", "port", NULL); 397 return DBUS_SERVER_LISTEN_BAD_ADDRESS; 398 } 399 400 _dbus_string_init_const (&str, port); 401 sresult = _dbus_string_parse_int (&str, 0, &lport, NULL); 402 _dbus_string_free (&str); 403 404 if (sresult == FALSE || lport <= 0 || lport > 65535) 405 { 406 _dbus_set_bad_address(error, NULL, NULL, 407 "Port is not an integer between 0 and 65535"); 408 return DBUS_SERVER_LISTEN_BAD_ADDRESS; 409 } 410 411 *server_p = _dbus_server_new_for_tcp_socket (host, lport, error); 412 413 if (*server_p) 414 { 415 _DBUS_ASSERT_ERROR_IS_CLEAR(error); 416 return DBUS_SERVER_LISTEN_OK; 417 } 418 else 419 { 420 _DBUS_ASSERT_ERROR_IS_SET(error); 421 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 422 } 423 } 424 else 425 { 426 _DBUS_ASSERT_ERROR_IS_CLEAR(error); 427 return DBUS_SERVER_LISTEN_NOT_HANDLED; 428 } 429 } 430 431 /** 432 * This is a bad hack since it's really unix domain socket 433 * specific. Also, the function weirdly adopts ownership 434 * of the passed-in string. 435 * 436 * @param server a socket server 437 * @param filename socket filename to report/delete 438 * 439 */ 440 void 441 _dbus_server_socket_own_filename (DBusServer *server, 442 char *filename) 443 { 444 DBusServerSocket *socket_server = (DBusServerSocket*) server; 445 446 socket_server->socket_name = filename; 447 } 448 449 450 /** @} */ 451 452