PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/loudmouth/lm-old-socket.c

https://github.com/mhallendal/loudmouth
C | 1064 lines | 791 code | 209 blank | 64 comment | 116 complexity | e3e3c30e6bdadb607f9401498fe882b4 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3. * Copyright (C) 2006-2008 Imendio AB
  4. * Copyright (C) 2006 Nokia Corporation. All rights reserved.
  5. * Copyright (C) 2007 Collabora Ltd.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this program; if not, see <https://www.gnu.org/licenses>
  19. */
  20. #include <config.h>
  21. #include <string.h>
  22. #include <sys/types.h>
  23. /* Needed on Mac OS X */
  24. #if HAVE_NETINET_IN_H
  25. #include <netinet/in.h>
  26. #endif
  27. /* Needed on Mac OS X */
  28. #if HAVE_ARPA_NAMESER_COMPAT_H
  29. #include <arpa/nameser_compat.h>
  30. #endif
  31. #include <arpa/inet.h>
  32. #include <arpa/nameser.h>
  33. #include <resolv.h>
  34. #include "lm-debug.h"
  35. #include "lm-error.h"
  36. #include "lm-internals.h"
  37. #include "lm-misc.h"
  38. #include "lm-proxy.h"
  39. #include "lm-resolver.h"
  40. #include "lm-ssl.h"
  41. #include "lm-ssl-internals.h"
  42. #include "lm-sock.h"
  43. #include "lm-old-socket.h"
  44. #define IN_BUFFER_SIZE 1024
  45. #define SRV_LEN 8192
  46. struct _LmOldSocket {
  47. LmConnection *connection;
  48. GMainContext *context;
  49. gchar *domain;
  50. gchar *server;
  51. guint port;
  52. LmSSL *ssl;
  53. gboolean ssl_started;
  54. LmProxy *proxy;
  55. GIOChannel *io_channel;
  56. GSource *watch_in;
  57. GSource *watch_err;
  58. GSource *watch_hup;
  59. LmOldSocketT fd;
  60. GSource *watch_connect;
  61. gboolean cancel_open;
  62. GSource *watch_out;
  63. GString *out_buf;
  64. LmConnectData *connect_data;
  65. IncomingDataFunc data_func;
  66. SocketClosedFunc closed_func;
  67. ConnectResultFunc connect_func;
  68. gpointer user_data;
  69. guint ref_count;
  70. LmResolver *resolver;
  71. };
  72. static void socket_free (LmOldSocket *socket);
  73. static gboolean socket_do_connect (LmConnectData *connect_data);
  74. static gboolean socket_connect_cb (GIOChannel *source,
  75. GIOCondition condition,
  76. LmConnectData *connect_data);
  77. static gboolean socket_in_event (GIOChannel *source,
  78. GIOCondition condition,
  79. LmOldSocket *socket);
  80. static gboolean socket_hup_event (GIOChannel *source,
  81. GIOCondition condition,
  82. LmOldSocket *socket);
  83. static gboolean socket_error_event (GIOChannel *source,
  84. GIOCondition condition,
  85. LmOldSocket *socket);
  86. static gboolean socket_buffered_write_cb (GIOChannel *source,
  87. GIOCondition condition,
  88. LmOldSocket *socket);
  89. static void socket_close_io_channel (GIOChannel *io_channel);
  90. static gboolean old_socket_output_is_buffered (LmOldSocket *socket,
  91. const gchar *buffer,
  92. gint len);
  93. static void old_socket_setup_output_buffer (LmOldSocket *socket,
  94. const gchar *buffer,
  95. gint len);
  96. static void
  97. socket_free (LmOldSocket *socket)
  98. {
  99. g_free (socket->server);
  100. g_free (socket->domain);
  101. if (socket->ssl) {
  102. lm_ssl_unref (socket->ssl);
  103. }
  104. if (socket->proxy) {
  105. lm_proxy_unref (socket->proxy);
  106. }
  107. if (socket->out_buf) {
  108. g_string_free (socket->out_buf, TRUE);
  109. }
  110. if (socket->resolver) {
  111. g_object_unref (socket->resolver);
  112. }
  113. g_free (socket);
  114. }
  115. static gint
  116. old_socket_do_write (LmOldSocket *socket, const gchar *buf, guint len)
  117. {
  118. gint b_written;
  119. if (socket->ssl_started) {
  120. b_written = _lm_ssl_send (socket->ssl, buf, len);
  121. } else {
  122. GIOStatus io_status = G_IO_STATUS_AGAIN;
  123. gsize bytes_written;
  124. while (io_status == G_IO_STATUS_AGAIN) {
  125. io_status = g_io_channel_write_chars (socket->io_channel,
  126. buf, len,
  127. &bytes_written,
  128. NULL);
  129. }
  130. b_written = bytes_written;
  131. if (io_status != G_IO_STATUS_NORMAL) {
  132. b_written = -1;
  133. }
  134. }
  135. return b_written;
  136. }
  137. gint
  138. lm_old_socket_write (LmOldSocket *socket, const gchar *buf, gint len)
  139. {
  140. gint b_written;
  141. if (old_socket_output_is_buffered (socket, buf, len)) {
  142. return len;
  143. }
  144. b_written = old_socket_do_write (socket, buf, len);
  145. if (b_written < len && b_written != -1) {
  146. old_socket_setup_output_buffer (socket,
  147. buf + b_written,
  148. len - b_written);
  149. return len;
  150. }
  151. return b_written;
  152. }
  153. static gboolean
  154. socket_read_incoming (LmOldSocket *socket,
  155. gchar *buf,
  156. gsize buf_size,
  157. gsize *bytes_read,
  158. gboolean *hangup,
  159. gint *reason)
  160. {
  161. GIOStatus status;
  162. *hangup = FALSE;
  163. if (socket->ssl_started) {
  164. status = _lm_ssl_read (socket->ssl,
  165. buf, buf_size - 1, bytes_read);
  166. } else {
  167. status = g_io_channel_read_chars (socket->io_channel,
  168. buf, buf_size - 1,
  169. bytes_read,
  170. NULL);
  171. }
  172. if (status != G_IO_STATUS_NORMAL) {
  173. switch (status) {
  174. case G_IO_STATUS_EOF:
  175. *reason = LM_DISCONNECT_REASON_HUP;
  176. break;
  177. case G_IO_STATUS_AGAIN:
  178. /* No data readable but we didn't hangup */
  179. return FALSE;
  180. break;
  181. case G_IO_STATUS_ERROR:
  182. *reason = LM_DISCONNECT_REASON_ERROR;
  183. break;
  184. default:
  185. *reason = LM_DISCONNECT_REASON_UNKNOWN;
  186. }
  187. /* Notify connection_in_event that we hangup the connection */
  188. *hangup = TRUE;
  189. return FALSE;
  190. }
  191. buf[*bytes_read] = '\0';
  192. /* There is more data to be read */
  193. return TRUE;
  194. }
  195. static gboolean
  196. socket_in_event (GIOChannel *source,
  197. GIOCondition condition,
  198. LmOldSocket *socket)
  199. {
  200. gchar buf[IN_BUFFER_SIZE];
  201. gsize bytes_read = 0;
  202. gboolean read_anything = FALSE;
  203. gboolean hangup = 0;
  204. gint reason = 0;
  205. if (!socket->io_channel) {
  206. return FALSE;
  207. }
  208. while (socket_read_incoming (socket, buf, IN_BUFFER_SIZE,
  209. &bytes_read, &hangup, &reason)) {
  210. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "\nRECV [%d]:\n",
  211. (int)bytes_read);
  212. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  213. "-----------------------------------\n");
  214. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "'%s'\n", buf);
  215. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  216. "-----------------------------------\n");
  217. lm_verbose ("Read: %d chars\n", (int)bytes_read);
  218. (socket->data_func) (socket, buf, socket->user_data);
  219. read_anything = TRUE;
  220. }
  221. /* If we have read something, delay the hangup so that the data can be
  222. * processed. */
  223. if (hangup && !read_anything) {
  224. (socket->closed_func) (socket, reason, socket->user_data);
  225. return FALSE;
  226. }
  227. return TRUE;
  228. }
  229. static gboolean
  230. socket_hup_event (GIOChannel *source,
  231. GIOCondition condition,
  232. LmOldSocket *socket)
  233. {
  234. lm_verbose ("HUP event: %d->'%s'\n",
  235. condition, lm_misc_io_condition_to_str (condition));
  236. if (!socket->io_channel) {
  237. return FALSE;
  238. }
  239. (socket->closed_func) (socket, LM_DISCONNECT_REASON_HUP,
  240. socket->user_data);
  241. return TRUE;
  242. }
  243. static gboolean
  244. socket_error_event (GIOChannel *source,
  245. GIOCondition condition,
  246. LmOldSocket *socket)
  247. {
  248. lm_verbose ("ERROR event: %d->'%s'\n",
  249. condition, lm_misc_io_condition_to_str (condition));
  250. if (!socket->io_channel) {
  251. return FALSE;
  252. }
  253. (socket->closed_func) (socket, LM_DISCONNECT_REASON_ERROR,
  254. socket->user_data);
  255. return TRUE;
  256. }
  257. static gboolean
  258. _lm_old_socket_ssl_init (LmOldSocket *socket, gboolean delayed)
  259. {
  260. GError *error = NULL;
  261. const gchar *ssl_verify_domain = NULL;
  262. lm_verbose ("Setting up SSL...\n");
  263. _lm_ssl_initialize (socket->ssl);
  264. #ifdef HAVE_GNUTLS
  265. /* GNU TLS requires the socket to be blocking */
  266. _lm_sock_set_blocking (socket->fd, TRUE);
  267. #endif
  268. /* If we're using StartTLS, the correct thing is to verify against
  269. * the domain. If we're using old SSL, we should verify against the
  270. * hostname. */
  271. if (delayed)
  272. ssl_verify_domain = socket->domain;
  273. else
  274. ssl_verify_domain = socket->server;
  275. if (!_lm_ssl_begin (socket->ssl, socket->fd, ssl_verify_domain, &error)) {
  276. lm_verbose ("Could not begin SSL\n");
  277. if (error) {
  278. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  279. "%s\n", error->message);
  280. g_error_free (error);
  281. }
  282. _lm_sock_shutdown (socket->fd);
  283. _lm_sock_close (socket->fd);
  284. if (!delayed && socket->connect_func) {
  285. (socket->connect_func) (socket, FALSE, socket->user_data);
  286. }
  287. return FALSE;
  288. }
  289. #ifdef HAVE_GNUTLS
  290. _lm_sock_set_blocking (socket->fd, FALSE);
  291. #endif
  292. socket->ssl_started = TRUE;
  293. return TRUE;
  294. }
  295. gboolean
  296. lm_old_socket_starttls (LmOldSocket *socket)
  297. {
  298. g_return_val_if_fail (lm_ssl_get_use_starttls (socket->ssl) == TRUE, FALSE);
  299. return _lm_old_socket_ssl_init (socket, TRUE);
  300. }
  301. void
  302. _lm_old_socket_succeeded (LmConnectData *connect_data)
  303. {
  304. LmOldSocket *socket;
  305. socket = connect_data->socket;
  306. if (socket->watch_connect) {
  307. g_source_destroy (socket->watch_connect);
  308. socket->watch_connect = NULL;
  309. }
  310. /* Need some way to report error/success */
  311. if (socket->cancel_open) {
  312. lm_verbose ("Cancelling connection...\n");
  313. if (socket->connect_func) {
  314. (socket->connect_func) (socket, FALSE, socket->user_data);
  315. }
  316. return;
  317. }
  318. socket->fd = connect_data->fd;
  319. socket->io_channel = connect_data->io_channel;
  320. g_object_unref (socket->resolver);
  321. socket->resolver = NULL;
  322. socket->connect_data = NULL;
  323. g_free (connect_data);
  324. /* old-style ssl should be started immediately */
  325. if (socket->ssl && (lm_ssl_get_use_starttls (socket->ssl) == FALSE)) {
  326. if (!_lm_old_socket_ssl_init (socket, FALSE)) {
  327. return;
  328. }
  329. }
  330. socket->watch_in =
  331. lm_misc_add_io_watch (socket->context,
  332. socket->io_channel,
  333. G_IO_IN,
  334. (GIOFunc) socket_in_event,
  335. socket);
  336. /* FIXME: if we add these, we don't get ANY
  337. * response from the server, this is to do with the way that
  338. * windows handles watches, see bug #331214.
  339. */
  340. #ifndef G_OS_WIN32
  341. socket->watch_err =
  342. lm_misc_add_io_watch (socket->context,
  343. socket->io_channel,
  344. G_IO_ERR,
  345. (GIOFunc) socket_error_event,
  346. socket);
  347. socket->watch_hup =
  348. lm_misc_add_io_watch (socket->context,
  349. socket->io_channel,
  350. G_IO_HUP,
  351. (GIOFunc) socket_hup_event,
  352. socket);
  353. #endif
  354. if (socket->connect_func) {
  355. (socket->connect_func) (socket, TRUE, socket->user_data);
  356. }
  357. }
  358. gboolean
  359. _lm_old_socket_failed_with_error (LmConnectData *connect_data, int error)
  360. {
  361. LmOldSocket *socket;
  362. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  363. "Connection failed: %s (error %d)\n",
  364. _lm_sock_get_error_str (error), error);
  365. socket = lm_old_socket_ref (connect_data->socket);
  366. connect_data->current_addr = lm_resolver_results_get_next (socket->resolver);
  367. if (socket->watch_connect) {
  368. g_source_destroy (socket->watch_connect);
  369. socket->watch_connect = NULL;
  370. }
  371. if (connect_data->io_channel != NULL) {
  372. socket_close_io_channel (connect_data->io_channel);
  373. connect_data->io_channel = NULL;
  374. }
  375. if (connect_data->current_addr == NULL) { /*Ran Out Of Addresses*/
  376. if (socket->connect_func) {
  377. (socket->connect_func) (socket, FALSE, socket->user_data);
  378. }
  379. /* if the user callback called connection_close(), this is already freed */
  380. if (socket->connect_data != NULL) {
  381. if (socket->resolver) {
  382. g_object_unref (socket->resolver);
  383. }
  384. socket->connect_data = NULL;
  385. g_free (connect_data);
  386. }
  387. } else {
  388. /* try to connect to the next host */
  389. return socket_do_connect (connect_data);
  390. }
  391. lm_old_socket_unref (socket);
  392. return FALSE;
  393. }
  394. gboolean
  395. _lm_old_socket_failed (LmConnectData *connect_data)
  396. {
  397. return _lm_old_socket_failed_with_error (connect_data,
  398. _lm_sock_get_last_error());
  399. }
  400. static gboolean
  401. socket_connect_cb (GIOChannel *source,
  402. GIOCondition condition,
  403. LmConnectData *connect_data)
  404. {
  405. LmOldSocket *socket;
  406. /* struct addrinfo *addr; */
  407. int err;
  408. socklen_t len;
  409. LmOldSocketT fd;
  410. gboolean result = FALSE;
  411. socket = lm_old_socket_ref (connect_data->socket);
  412. /* addr = connect_data->current_addr; */
  413. fd = g_io_channel_unix_get_fd (source);
  414. if (condition == G_IO_ERR) {
  415. len = sizeof (err);
  416. _lm_sock_get_error (fd, &err, &len);
  417. if (!_lm_sock_is_blocking_error (err)) {
  418. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
  419. "Connection failed.\n");
  420. /* error condition, but might be possible to recover
  421. * from it (by connecting to the next host) */
  422. if (!_lm_old_socket_failed_with_error (connect_data, err)) {
  423. socket->watch_connect = NULL;
  424. goto out;
  425. }
  426. }
  427. }
  428. #if 0
  429. if (_lm_connection_async_connect_waiting (socket->connection)) {
  430. gint res;
  431. fd = g_io_channel_unix_get_fd (source);
  432. res = _lm_sock_connect (fd, addr->ai_addr, (int)addr->ai_addrlen);
  433. if (res < 0) {
  434. err = _lm_sock_get_last_error ();
  435. if (_lm_sock_is_blocking_success (err)) {
  436. _lm_connection_set_async_connect_waiting (socket->connection, FALSE);
  437. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  438. "Connection success (1).\n");
  439. _lm_old_socket_succeeded (connect_data);
  440. }
  441. if (_lm_connection_async_connect_waiting (socket->connection) &&
  442. !_lm_sock_is_blocking_error (err)) {
  443. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  444. "Connection failed.\n");
  445. _lm_sock_close (connect_data->fd);
  446. _lm_old_socket_failed_with_error (connect_data, err);
  447. socket->watch_connect = NULL;
  448. goto out;
  449. }
  450. }
  451. } else {
  452. #endif
  453. {
  454. /* for blocking sockets, G_IO_OUT means we are connected */
  455. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
  456. "Connection success (2).\n");
  457. _lm_old_socket_succeeded (connect_data);
  458. }
  459. result = TRUE;
  460. out:
  461. lm_old_socket_unref(socket);
  462. return result;
  463. }
  464. static gboolean
  465. socket_do_connect (LmConnectData *connect_data)
  466. {
  467. LmOldSocket *socket;
  468. LmOldSocketT fd;
  469. int res, err;
  470. int port;
  471. char name[NI_MAXHOST];
  472. char portname[NI_MAXSERV];
  473. struct addrinfo *addr;
  474. socket = connect_data->socket;
  475. addr = connect_data->current_addr;
  476. if (socket->port == 0) {
  477. socket->port = 5222;
  478. }
  479. if (socket->proxy) {
  480. port = htons (lm_proxy_get_port (socket->proxy));
  481. } else {
  482. port = htons (socket->port);
  483. }
  484. ((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
  485. res = getnameinfo (addr->ai_addr,
  486. (socklen_t)addr->ai_addrlen,
  487. name, sizeof (name),
  488. portname, sizeof (portname),
  489. NI_NUMERICHOST | NI_NUMERICSERV);
  490. if (res < 0) {
  491. return _lm_old_socket_failed (connect_data);
  492. }
  493. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  494. "Trying %s port %s...\n", name, portname);
  495. fd = _lm_sock_makesocket (addr->ai_family,
  496. addr->ai_socktype,
  497. addr->ai_protocol);
  498. if (!_LM_SOCK_VALID (fd)) {
  499. g_print("invalid fd\n");
  500. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  501. "Failed making socket, error:%d...\n",
  502. _lm_sock_get_last_error ());
  503. return _lm_old_socket_failed (connect_data);
  504. }
  505. /* Even though it says _unix_new(), it is supported by glib on
  506. * win32 because glib does some cool stuff to find out if it
  507. * can treat it as a FD or a windows SOCKET.
  508. */
  509. connect_data->fd = fd;
  510. connect_data->io_channel = g_io_channel_unix_new (fd);
  511. g_io_channel_set_encoding (connect_data->io_channel, NULL, NULL);
  512. g_io_channel_set_buffered (connect_data->io_channel, FALSE);
  513. _lm_sock_set_blocking (connect_data->fd, FALSE);
  514. if (socket->proxy) {
  515. socket->watch_connect =
  516. lm_misc_add_io_watch (socket->context,
  517. connect_data->io_channel,
  518. G_IO_OUT|G_IO_ERR,
  519. (GIOFunc) _lm_proxy_connect_cb,
  520. connect_data);
  521. } else {
  522. socket->watch_connect =
  523. lm_misc_add_io_watch (socket->context,
  524. connect_data->io_channel,
  525. G_IO_OUT|G_IO_ERR,
  526. (GIOFunc) socket_connect_cb,
  527. connect_data);
  528. }
  529. res = _lm_sock_connect (connect_data->fd,
  530. addr->ai_addr, (int)addr->ai_addrlen);
  531. if (res < 0) {
  532. err = _lm_sock_get_last_error ();
  533. if (!_lm_sock_is_blocking_error (err)) {
  534. _lm_sock_close (connect_data->fd);
  535. g_print("unable to connect\n");
  536. return _lm_old_socket_failed_with_error (connect_data, err);
  537. }
  538. }
  539. return TRUE;
  540. }
  541. static gboolean
  542. old_socket_output_is_buffered (LmOldSocket *socket,
  543. const gchar *buffer,
  544. gint len)
  545. {
  546. if (socket->out_buf) {
  547. lm_verbose ("Appending %d bytes to output buffer\n", len);
  548. g_string_append_len (socket->out_buf, buffer, len);
  549. return TRUE;
  550. }
  551. return FALSE;
  552. }
  553. static void
  554. old_socket_setup_output_buffer (LmOldSocket *socket, const gchar *buffer, gint len)
  555. {
  556. lm_verbose ("OUTPUT BUFFER ENABLED\n");
  557. socket->out_buf = g_string_new_len (buffer, len);
  558. socket->watch_out =
  559. lm_misc_add_io_watch (socket->context,
  560. socket->io_channel,
  561. G_IO_OUT,
  562. (GIOFunc) socket_buffered_write_cb,
  563. socket);
  564. }
  565. static gboolean
  566. socket_buffered_write_cb (GIOChannel *source,
  567. GIOCondition condition,
  568. LmOldSocket *socket)
  569. {
  570. gint b_written;
  571. GString *out_buf;
  572. out_buf = socket->out_buf;
  573. if (!out_buf) {
  574. /* Should not be possible */
  575. return FALSE;
  576. }
  577. b_written = old_socket_do_write (socket, out_buf->str, out_buf->len);
  578. if (b_written < 0) {
  579. (socket->closed_func) (socket, LM_DISCONNECT_REASON_ERROR,
  580. socket->user_data);
  581. return FALSE;
  582. }
  583. g_string_erase (out_buf, 0, (gsize) b_written);
  584. if (out_buf->len == 0) {
  585. lm_verbose ("Output buffer is empty, going back to normal output\n");
  586. if (socket->watch_out) {
  587. g_source_destroy (socket->watch_out);
  588. socket->watch_out = NULL;
  589. }
  590. g_string_free (out_buf, TRUE);
  591. socket->out_buf = NULL;
  592. return FALSE;
  593. }
  594. return TRUE;
  595. }
  596. static void
  597. socket_close_io_channel (GIOChannel *io_channel)
  598. {
  599. gint fd;
  600. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
  601. "Freeing up IOChannel and file descriptor\n");
  602. fd = g_io_channel_unix_get_fd (io_channel);
  603. g_io_channel_unref (io_channel);
  604. _lm_sock_close (fd);
  605. }
  606. static void
  607. old_socket_resolver_host_cb (LmResolver *resolver,
  608. LmResolverResult result,
  609. gpointer user_data)
  610. {
  611. LmOldSocket *socket = (LmOldSocket *) user_data;
  612. char dispbuf[128];
  613. struct sockaddr_in *addr; /* FIXME:IPv6 */
  614. const char *converr;
  615. lm_verbose ("LmOldSocket::host_cb (result=%d)\n", result);
  616. if (result != LM_RESOLVER_RESULT_OK) {
  617. lm_verbose ("error while resolving, bailing out\n");
  618. if (socket->connect_func) {
  619. (socket->connect_func) (socket, FALSE, socket->user_data);
  620. }
  621. /*FIXME: Leaking Resolvers Until Clean Up Can Be Properly Handled
  622. g_object_unref (socket->resolver);
  623. socket->resolver = NULL;*/
  624. g_free (socket->connect_data);
  625. socket->connect_data = NULL;
  626. return;
  627. }
  628. socket->connect_data->current_addr =
  629. lm_resolver_results_get_next (resolver);
  630. if (socket->connect_data->current_addr) { /* FIXME:IPv6 */
  631. addr = (struct sockaddr_in *) (socket->connect_data->current_addr->ai_addr);
  632. converr = inet_ntop(AF_INET,&(addr->sin_addr),dispbuf,sizeof(dispbuf));
  633. if (converr) {
  634. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
  635. "Attempting Connection to %s\n",dispbuf);
  636. } else {
  637. g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
  638. "Attempting Connection (unable to convert address to presentable format)\n");
  639. };
  640. socket_do_connect (socket->connect_data);
  641. } else { /* FIXME: IPv6 Support? */
  642. g_log (LM_LOG_DOMAIN,G_LOG_LEVEL_ERROR,
  643. "Unable to locate server available over IPv4.\n");
  644. };
  645. /* FIXME: What do we do here? How to make the mainloop exit with an
  646. error, while having no ref to said mainloop */
  647. }
  648. /* FIXME: Need to have a way to only get srv reply and then decide if the
  649. * resolver should continue to look the host up.
  650. *
  651. * This is needed for the case when we do a SRV lookup to lookup the
  652. * real host of the service and then connect to it through a proxy.
  653. */
  654. static void
  655. old_socket_resolver_srv_cb (LmResolver *resolver,
  656. LmResolverResult result,
  657. gpointer user_data)
  658. {
  659. LmOldSocket *socket = (LmOldSocket *) user_data;
  660. const gchar *remote_addr;
  661. lm_verbose ("LmOldSocket::srv_cb (result=%d)\n", result);
  662. if (result != LM_RESOLVER_RESULT_OK) {
  663. lm_verbose ("SRV lookup failed, trying jid domain\n");
  664. socket->server = g_strdup (socket->domain);
  665. } else {
  666. g_object_get (resolver, "host", &socket->server, NULL);
  667. g_object_get (resolver, "port", &socket->port, NULL);
  668. }
  669. if (socket->proxy) {
  670. remote_addr = lm_proxy_get_server (socket->proxy);
  671. } else if (socket->server) {
  672. remote_addr = socket->server;
  673. }
  674. else {
  675. remote_addr = socket->domain;
  676. }
  677. g_object_unref (socket->resolver);
  678. socket->resolver =
  679. lm_resolver_new_for_host (remote_addr,
  680. old_socket_resolver_host_cb,
  681. socket);
  682. lm_resolver_lookup (socket->resolver);
  683. }
  684. LmOldSocket *
  685. lm_old_socket_create (GMainContext *context,
  686. IncomingDataFunc data_func,
  687. SocketClosedFunc closed_func,
  688. ConnectResultFunc connect_func,
  689. gpointer user_data,
  690. LmConnection *connection,
  691. const gchar *server,
  692. const gchar *domain,
  693. guint port,
  694. LmSSL *ssl,
  695. LmProxy *proxy,
  696. GError **error)
  697. {
  698. LmOldSocket *socket;
  699. LmConnectData *data;
  700. g_return_val_if_fail (domain != NULL, NULL);
  701. g_return_val_if_fail ((port >= LM_MIN_PORT && port <= LM_MAX_PORT), NULL);
  702. g_return_val_if_fail (data_func != NULL, NULL);
  703. g_return_val_if_fail (closed_func != NULL, NULL);
  704. g_return_val_if_fail (connect_func != NULL, NULL);
  705. socket = g_new0 (LmOldSocket, 1);
  706. socket->ref_count = 1;
  707. socket->connection = connection;
  708. socket->domain = g_strdup (domain);
  709. socket->server = g_strdup (server);
  710. socket->port = port;
  711. socket->cancel_open = FALSE;
  712. socket->ssl = ssl;
  713. socket->ssl_started = FALSE;
  714. socket->proxy = NULL;
  715. if (context) {
  716. socket->context = g_main_context_ref (context);
  717. }
  718. if (proxy) {
  719. socket->proxy = lm_proxy_ref (proxy);
  720. }
  721. data = g_new0 (LmConnectData, 1);
  722. data->socket = socket;
  723. data->connection = socket->connection;
  724. data->fd = -1;
  725. socket->connect_data = data;
  726. if (!server) {
  727. socket->resolver = lm_resolver_new_for_service (socket->domain,
  728. "xmpp-client",
  729. "tcp",
  730. old_socket_resolver_srv_cb,
  731. socket);
  732. } else {
  733. socket->resolver =
  734. lm_resolver_new_for_host (socket->server ? socket->server : socket->domain,
  735. old_socket_resolver_host_cb,
  736. socket);
  737. }
  738. if (socket->context) {
  739. g_object_set (socket->resolver, "context", context, NULL);
  740. }
  741. socket->data_func = data_func;
  742. socket->closed_func = closed_func;
  743. socket->connect_func = connect_func;
  744. socket->user_data = user_data;
  745. lm_resolver_lookup (socket->resolver);
  746. return socket;
  747. }
  748. void
  749. lm_old_socket_flush (LmOldSocket *socket)
  750. {
  751. g_return_if_fail (socket != NULL);
  752. g_return_if_fail (socket->io_channel != NULL);
  753. g_io_channel_flush (socket->io_channel, NULL);
  754. }
  755. void
  756. lm_old_socket_close (LmOldSocket *socket)
  757. {
  758. LmConnectData *data;
  759. g_return_if_fail (socket != NULL);
  760. if (socket->watch_connect) {
  761. g_source_destroy (socket->watch_connect);
  762. socket->watch_connect = NULL;
  763. }
  764. data = socket->connect_data;
  765. if (data) {
  766. if (data->io_channel) {
  767. socket_close_io_channel (data->io_channel);
  768. }
  769. socket->connect_data = NULL;
  770. g_free (data);
  771. }
  772. /* FIXME: Leaking Resolvers Until Clean Up Can Be Corrected
  773. if (socket->resolver) {
  774. g_object_unref (socket->resolver);
  775. socket->resolver = NULL;
  776. } */
  777. if (socket->io_channel) {
  778. if (socket->watch_in) {
  779. g_source_destroy (socket->watch_in);
  780. socket->watch_in = NULL;
  781. }
  782. if (socket->watch_err) {
  783. g_source_destroy (socket->watch_err);
  784. socket->watch_err = NULL;
  785. }
  786. if (socket->watch_hup) {
  787. g_source_destroy (socket->watch_hup);
  788. socket->watch_hup = NULL;
  789. }
  790. if (socket->watch_out) {
  791. g_source_destroy (socket->watch_out);
  792. socket->watch_out = NULL;
  793. }
  794. socket_close_io_channel (socket->io_channel);
  795. socket->io_channel = NULL;
  796. socket->fd = -1;
  797. }
  798. if (socket->ssl) {
  799. _lm_ssl_close (socket->ssl);
  800. }
  801. }
  802. gchar *
  803. lm_old_socket_get_local_host (LmOldSocket *socket)
  804. {
  805. return _lm_sock_get_local_host (socket->fd);
  806. }
  807. LmOldSocket *
  808. lm_old_socket_ref (LmOldSocket *socket)
  809. {
  810. g_return_val_if_fail (socket != NULL, NULL);
  811. socket->ref_count++;
  812. return socket;
  813. }
  814. void
  815. lm_old_socket_unref (LmOldSocket *socket)
  816. {
  817. g_return_if_fail (socket != NULL);
  818. socket->ref_count--;
  819. if (socket->ref_count <= 0) {
  820. socket_free (socket);
  821. }
  822. }
  823. gboolean
  824. lm_old_socket_set_keepalive (LmOldSocket *socket, int delay)
  825. {
  826. #ifdef USE_TCP_KEEPALIVES
  827. return _lm_sock_set_keepalive (socket->fd, delay);
  828. #else
  829. return FALSE;
  830. #endif /* USE_TCP_KEEPALIVES */
  831. }
  832. void
  833. lm_old_socket_asyncns_cancel (LmOldSocket *socket)
  834. {
  835. if (!socket->resolver) {
  836. return;
  837. }
  838. lm_resolver_cancel (socket->resolver);
  839. }
  840. gboolean
  841. lm_old_socket_get_use_starttls (LmOldSocket *socket)
  842. {
  843. if (!socket->ssl) {
  844. return FALSE;
  845. }
  846. return lm_ssl_get_use_starttls (socket->ssl);
  847. }
  848. gboolean
  849. lm_old_socket_get_require_starttls (LmOldSocket *socket)
  850. {
  851. if (!socket->ssl) {
  852. return FALSE;
  853. }
  854. return lm_ssl_get_require_starttls (socket->ssl);
  855. }