1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2003-2006 Imendio AB
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
25 #include <sys/types.h>
33 #include "lm-internals.h"
34 #include "lm-ssl-internals.h"
35 #include "lm-parser.h"
37 #include "lm-connection.h"
40 #define IN_BUFFER_SIZE 1024
43 LmHandlerPriority priority;
44 LmMessageHandler *handler;
49 LmConnection *connection;
52 struct _LmConnection {
54 GMainContext *context;
66 GHashTable *id_handlers;
67 GSList *handlers[LM_MESSAGE_TYPE_UNKNOWN];
70 GIOChannel *io_channel;
75 guint io_watch_connect;
80 gboolean async_connect_waiting;
84 LmCallback *close_cb; /* unused */
86 LmCallback *register_cb; /* unused */
88 LmCallback *disconnect_cb;
90 GQueue *incoming_messages;
91 GSource *incoming_source;
93 LmConnectionState state;
95 guint keep_alive_rate;
101 LmConnectData *connect_data;
108 AUTH_TYPE_DIGEST = 2,
112 static void connection_free (LmConnection *connection);
115 static void connection_handle_message (LmConnection *connection,
118 static void connection_new_message_cb (LmParser *parser,
120 LmConnection *connection);
121 static gboolean connection_do_open (LmConnection *connection,
124 static void connection_do_close (LmConnection *connection);
125 static gint connection_do_write (LmConnection *connection,
129 static gboolean connection_in_event (GIOChannel *source,
130 GIOCondition condition,
131 LmConnection *connection);
132 static gboolean connection_error_event (GIOChannel *source,
133 GIOCondition condition,
134 LmConnection *connection);
135 static gboolean connection_hup_event (GIOChannel *source,
136 GIOCondition condition,
137 LmConnection *connection);
138 static gboolean connection_send (LmConnection *connection,
142 static LmMessage * connection_create_auth_req_msg (const gchar *username);
143 static LmMessage * connection_create_auth_msg (LmConnection *connection,
144 const gchar *username,
145 const gchar *password,
146 const gchar *resource,
148 static LmHandlerResult connection_auth_req_reply (LmMessageHandler *handler,
149 LmConnection *connection,
152 static int connection_check_auth_type (LmMessage *auth_req_rpl);
154 static LmHandlerResult connection_auth_reply (LmMessageHandler *handler,
155 LmConnection *connection,
159 static void connection_stream_received (LmConnection *connection,
162 static gint connection_handler_compare_func (HandlerData *a,
164 static gboolean connection_incoming_prepare (GSource *source,
166 static gboolean connection_incoming_check (GSource *source);
167 static gboolean connection_incoming_dispatch (GSource *source,
168 GSourceFunc callback,
170 static GSource * connection_create_source (LmConnection *connection);
171 static void connection_signal_disconnect (LmConnection *connection,
172 LmDisconnectReason reason);
174 static void connection_do_connect (LmConnectData *connect_data);
175 static guint connection_add_watch (LmConnection *connection,
177 GIOCondition condition,
180 static gboolean connection_send_keep_alive (LmConnection *connection);
181 static void connection_start_keep_alive (LmConnection *connection);
182 static void connection_stop_keep_alive (LmConnection *connection);
183 static gboolean connection_buffered_write_cb (GIOChannel *source,
184 GIOCondition condition,
185 LmConnection *connection);
186 static gboolean connection_output_is_buffered (LmConnection *connection,
189 static void connection_setup_output_buffer (LmConnection *connection,
193 static GSourceFuncs incoming_funcs = {
194 connection_incoming_prepare,
195 connection_incoming_check,
196 connection_incoming_dispatch,
201 connection_free (LmConnection *connection)
206 g_free (connection->server);
207 g_free (connection->jid);
208 g_free (connection->stream_id);
210 if (connection->parser) {
211 lm_parser_free (connection->parser);
215 for (i = 0; i < LM_MESSAGE_TYPE_UNKNOWN; ++i) {
218 for (l = connection->handlers[i]; l; l = l->next) {
219 HandlerData *hd = (HandlerData *) l->data;
221 lm_message_handler_unref (hd->handler);
225 g_slist_free (connection->handlers[i]);
228 g_hash_table_destroy (connection->id_handlers);
229 if (connection->state >= LM_CONNECTION_STATE_OPENING) {
230 connection_do_close (connection);
233 if (connection->open_cb) {
234 _lm_utils_free_callback (connection->open_cb);
237 if (connection->auth_cb) {
238 _lm_utils_free_callback (connection->auth_cb);
241 lm_connection_set_disconnect_function (connection, NULL, NULL, NULL);
243 while ((m = g_queue_pop_head (connection->incoming_messages)) != NULL) {
244 lm_message_unref (m);
247 if (connection->ssl) {
248 lm_ssl_unref (connection->ssl);
251 if (connection->proxy) {
252 lm_proxy_unref (connection->proxy);
255 g_queue_free (connection->incoming_messages);
257 if (connection->context) {
258 g_main_context_unref (connection->context);
261 if (connection->out_buf) {
262 g_string_free (connection->out_buf, TRUE);
269 connection_handle_message (LmConnection *connection, LmMessage *m)
271 LmMessageHandler *handler;
274 LmHandlerResult result = LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
276 lm_connection_ref (connection);
278 if (lm_message_get_type (m) == LM_MESSAGE_TYPE_STREAM) {
279 connection_stream_received (connection, m);
283 id = lm_message_node_get_attribute (m->node, "id");
286 handler = g_hash_table_lookup (connection->id_handlers, id);
288 result = _lm_message_handler_handle_message (handler,
291 g_hash_table_remove (connection->id_handlers, id);
295 if (result == LM_HANDLER_RESULT_REMOVE_MESSAGE) {
299 for (l = connection->handlers[lm_message_get_type (m)];
300 l && result == LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
302 HandlerData *hd = (HandlerData *) l->data;
304 result = _lm_message_handler_handle_message (hd->handler,
310 lm_connection_unref (connection);
316 connection_new_message_cb (LmParser *parser,
318 LmConnection *connection)
324 from = lm_message_node_get_attribute (m->node, "from");
329 lm_verbose ("New message with type=\"%s\" from: %s\n",
330 _lm_message_type_to_string (lm_message_get_type (m)),
333 g_queue_push_tail (connection->incoming_messages, m);
337 _lm_connection_succeeded (LmConnectData *connect_data)
339 LmConnection *connection;
341 gchar *server_from_jid;
344 connection = connect_data->connection;
346 if (connection->io_watch_connect != 0) {
349 source = g_main_context_find_source_by_id (connection->context,
350 connection->io_watch_connect);
352 g_source_destroy (source);
354 connection->io_watch_connect = 0;
357 /* Need some way to report error/success */
358 if (connection->cancel_open) {
359 lm_verbose ("Cancelling connection...\n");
363 connection->fd = connect_data->fd;
364 connection->io_channel = connect_data->io_channel;
366 freeaddrinfo (connect_data->resolved_addrs);
367 connection->connect_data = NULL;
368 g_free (connect_data);
370 if (connection->ssl) {
371 GError *error = NULL;
373 lm_verbose ("Setting up SSL...\n");
376 /* GNU TLS requires the socket to be blocking */
377 _lm_sock_set_blocking (connection->fd, TRUE);
380 if (!_lm_ssl_begin (connection->ssl, connection->fd,
383 lm_verbose ("Could not begin SSL\n");
386 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
387 "%s\n", error->message);
388 g_error_free (error);
391 _lm_sock_shutdown (connection->fd);
392 _lm_sock_close (connection->fd);
394 connection_do_close (connection);
400 _lm_sock_set_blocking (connection->fd, FALSE);
404 connection->io_watch_in =
405 connection_add_watch (connection,
406 connection->io_channel,
408 (GIOFunc) connection_in_event,
411 /* FIXME: if we add these, we don't get ANY
412 * response from the server, this is to do with the way that
413 * windows handles watches, see bug #331214.
416 connection->io_watch_err =
417 connection_add_watch (connection,
418 connection->io_channel,
420 (GIOFunc) connection_error_event,
423 connection->io_watch_hup =
424 connection_add_watch (connection,
425 connection->io_channel,
427 (GIOFunc) connection_hup_event,
431 /* FIXME: Set up according to XMPP 1.0 specification */
432 /* StartTLS and the like */
433 if (!connection_send (connection,
434 "<?xml version='1.0' encoding='UTF-8'?>", -1,
436 lm_verbose ("Failed to send xml version and encoding\n");
437 connection_do_close (connection);
442 if (connection->jid != NULL && (ch = strchr (connection->jid, '@')) != NULL) {
443 server_from_jid = ch + 1;
445 server_from_jid = connection->server;
448 m = lm_message_new (server_from_jid, LM_MESSAGE_TYPE_STREAM);
449 lm_message_node_set_attributes (m->node,
451 "http://etherx.jabber.org/streams",
452 "xmlns", "jabber:client",
455 lm_verbose ("Opening stream...");
457 if (!lm_connection_send (connection, m, NULL)) {
458 lm_verbose ("Failed to send stream information\n");
459 connection_do_close (connection);
462 lm_message_unref (m);
466 _lm_connection_failed_with_error (LmConnectData *connect_data, int error)
468 LmConnection *connection;
470 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
471 "Connection failed: %s (error %d)\n",
472 _lm_sock_get_error_str (error), error);
474 connection = connect_data->connection;
476 connect_data->current_addr = connect_data->current_addr->ai_next;
478 if (connection->io_watch_connect != 0) {
481 source = g_main_context_find_source_by_id (connection->context,
482 connection->io_watch_connect);
484 g_source_destroy (source);
487 connection->io_watch_connect = 0;
490 if (connect_data->io_channel != NULL) {
491 g_io_channel_unref (connect_data->io_channel);
492 /* FIXME: need to check for last unref and close the socket */
495 if (connect_data->current_addr == NULL) {
496 connection_do_close (connection);
497 if (connection->open_cb) {
498 LmCallback *cb = connection->open_cb;
500 connection->open_cb = NULL;
502 (* ((LmResultFunction) cb->func)) (connection, FALSE,
504 _lm_utils_free_callback (cb);
507 freeaddrinfo (connect_data->resolved_addrs);
508 connection->connect_data = NULL;
509 g_free (connect_data);
511 /* try to connect to the next host */
512 connection_do_connect (connect_data);
517 _lm_connection_failed (LmConnectData *connect_data)
519 _lm_connection_failed_with_error (connect_data,
520 _lm_sock_get_last_error());
524 connection_connect_cb (GIOChannel *source,
525 GIOCondition condition,
526 LmConnectData *connect_data)
528 LmConnection *connection;
529 struct addrinfo *addr;
534 connection = connect_data->connection;
535 addr = connect_data->current_addr;
536 fd = g_io_channel_unix_get_fd (source);
538 if (condition == G_IO_ERR) {
540 _lm_sock_get_error (fd, &err, &len);
541 if (!_lm_sock_is_blocking_error (err)) {
542 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
543 "Connection failed.\n");
545 _lm_connection_failed_with_error (connect_data, err);
547 connection->io_watch_connect = 0;
552 if (connection->async_connect_waiting) {
555 fd = g_io_channel_unix_get_fd (source);
557 res = _lm_sock_connect (fd, addr->ai_addr, (int)addr->ai_addrlen);
559 err = _lm_sock_get_last_error ();
560 if (_lm_sock_is_blocking_success (err)) {
561 connection->async_connect_waiting = FALSE;
563 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
564 "Connection success.\n");
566 _lm_connection_succeeded (connect_data);
569 if (connection->async_connect_waiting &&
570 !_lm_sock_is_blocking_error (err)) {
571 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
572 "Connection failed.\n");
574 _lm_sock_close (connect_data->fd);
575 _lm_connection_failed_with_error (connect_data, err);
577 connection->io_watch_connect = 0;
582 /* for blocking sockets, G_IO_OUT means we are connected */
583 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
584 "Connection success.\n");
586 _lm_connection_succeeded (connect_data);
593 connection_condition_to_str (GIOCondition condition)
595 static char buf[256];
599 if(condition & G_IO_ERR)
600 strcat(buf, "G_IO_ERR ");
601 if(condition & G_IO_HUP)
602 strcat(buf, "G_IO_HUP ");
603 if(condition & G_IO_NVAL)
604 strcat(buf, "G_IO_NVAL ");
605 if(condition & G_IO_IN)
606 strcat(buf, "G_IO_IN ");
607 if(condition & G_IO_OUT)
608 strcat(buf, "G_IO_OUT ");
614 connection_do_connect (LmConnectData *connect_data)
616 LmConnection *connection;
620 char name[NI_MAXHOST];
621 char portname[NI_MAXSERV];
622 struct addrinfo *addr;
624 connection = connect_data->connection;
625 addr = connect_data->current_addr;
627 if (connection->proxy) {
628 port = htons (lm_proxy_get_port (connection->proxy));
630 port = htons (connection->port);
633 ((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
635 res = getnameinfo (addr->ai_addr,
636 (socklen_t)addr->ai_addrlen,
638 portname, sizeof (portname),
639 NI_NUMERICHOST | NI_NUMERICSERV);
642 _lm_connection_failed (connect_data);
646 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
647 "Trying %s port %s...\n", name, portname);
649 fd = _lm_sock_makesocket (addr->ai_family,
653 if (!_LM_SOCK_VALID (fd)) {
654 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
655 "Failed making socket, error:%d...\n",
656 _lm_sock_get_last_error ());
658 _lm_connection_failed (connect_data);
663 /* Even though it says _unix_new(), it is supported by glib on
664 * win32 because glib does some cool stuff to find out if it
665 * can treat it as a FD or a windows SOCKET.
667 connect_data->fd = fd;
668 connect_data->io_channel = g_io_channel_unix_new (fd);
670 g_io_channel_set_encoding (connect_data->io_channel, NULL, NULL);
671 g_io_channel_set_buffered (connect_data->io_channel, FALSE);
673 _lm_sock_set_blocking (connect_data->fd,
674 connection->blocking);
676 if (connection->proxy) {
677 connection->io_watch_connect =
678 connection_add_watch (connection,
679 connect_data->io_channel,
681 (GIOFunc) _lm_proxy_connect_cb,
684 connection->io_watch_connect =
685 connection_add_watch (connection,
686 connect_data->io_channel,
688 (GIOFunc) connection_connect_cb,
692 connection->async_connect_waiting = !connection->blocking;
694 res = _lm_sock_connect (connect_data->fd,
695 addr->ai_addr, (int)addr->ai_addrlen);
697 err = _lm_sock_get_last_error ();
698 if (!_lm_sock_is_blocking_error (err)) {
699 _lm_sock_close (connect_data->fd);
700 _lm_connection_failed_with_error (connect_data, err);
708 connection_add_watch (LmConnection *connection,
710 GIOCondition condition,
717 g_return_val_if_fail (channel != NULL, 0);
719 source = g_io_create_watch (channel, condition);
721 g_source_set_callback (source, (GSourceFunc)func, user_data, NULL);
723 id = g_source_attach (source, connection->context);
725 g_source_unref (source);
731 connection_send_keep_alive (LmConnection *connection)
733 if (!connection_send (connection, " ", -1, NULL)) {
734 lm_verbose ("Error while sending keep alive package!\n");
741 connection_start_keep_alive (LmConnection *connection)
743 if (connection->keep_alive_id != 0) {
744 connection_stop_keep_alive (connection);
747 if (connection->keep_alive_rate > 0) {
748 connection->keep_alive_id =
749 g_timeout_add (connection->keep_alive_rate,
750 (GSourceFunc) connection_send_keep_alive,
756 connection_stop_keep_alive (LmConnection *connection)
758 if (connection->keep_alive_id != 0) {
759 g_source_remove (connection->keep_alive_id);
762 connection->keep_alive_id = 0;
766 connection_buffered_write_cb (GIOChannel *source,
767 GIOCondition condition,
768 LmConnection *connection)
772 /* FIXME: Do the writing */
774 out_buf = connection->out_buf;
776 /* Should not be possible */
780 b_written = connection_do_write (connection, out_buf->str, out_buf->len);
783 connection_error_event (connection->io_channel,
789 g_string_erase (out_buf, 0, (gsize) b_written);
790 if (out_buf->len == 0) {
791 lm_verbose ("Output buffer is empty, going back to normal output\n");
793 if (connection->io_watch_out != 0) {
796 source = g_main_context_find_source_by_id (connection->context,
797 connection->io_watch_out);
799 g_source_destroy (source);
802 connection->io_watch_out = 0;
805 g_string_free (out_buf, TRUE);
806 connection->out_buf = NULL;
814 connection_output_is_buffered (LmConnection *connection,
818 if (connection->out_buf) {
819 lm_verbose ("Appending %d bytes to output buffer\n", len);
820 g_string_append_len (connection->out_buf, buffer, len);
828 connection_setup_output_buffer (LmConnection *connection,
832 lm_verbose ("OUTPUT BUFFER ENABLED\n");
834 connection->out_buf = g_string_new_len (buffer, len);
836 connection->io_watch_out =
837 connection_add_watch (connection,
838 connection->io_channel,
840 (GIOFunc) connection_buffered_write_cb,
844 /* Returns directly */
845 /* Setups all data needed to start the connection attempts */
847 connection_do_open (LmConnection *connection, GError **error)
850 struct addrinfo *ans;
853 if (lm_connection_is_open (connection)) {
856 LM_ERROR_CONNECTION_NOT_OPEN,
857 "Connection is already open, call lm_connection_close() first");
861 if (!connection->server) {
864 LM_ERROR_CONNECTION_FAILED,
865 "You need to set the server hostname in the call to lm_connection_new()");
869 /* source thingie for messages and stuff */
870 connection->incoming_source = connection_create_source (connection);
871 g_source_attach (connection->incoming_source, connection->context);
873 lm_verbose ("Connecting to: %s:%d\n",
874 connection->server, connection->port);
876 memset (&req, 0, sizeof(req));
878 req.ai_family = AF_UNSPEC;
879 req.ai_socktype = SOCK_STREAM;
880 req.ai_protocol = IPPROTO_TCP;
882 connection->cancel_open = FALSE;
883 connection->state = LM_CONNECTION_STATE_OPENING;
884 connection->async_connect_waiting = FALSE;
886 if (connection->proxy) {
888 const gchar *proxy_server;
890 proxy_server = lm_proxy_get_server (connection->proxy);
892 /* Connect through proxy */
893 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
894 "Going to connect to proxy %s\n", proxy_server);
896 err = getaddrinfo (proxy_server, NULL, &req, &ans);
900 str = _lm_sock_addrinfo_get_error_str (err);
903 LM_ERROR_CONNECTION_FAILED,
910 /* Connect directly */
911 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
912 "Going to connect to %s\n",
915 err = getaddrinfo (connection->server,
920 str = _lm_sock_addrinfo_get_error_str (err);
923 LM_ERROR_CONNECTION_FAILED,
929 if (connection->ssl) {
930 _lm_ssl_initialize (connection->ssl);
933 /* Prepare and do the nonblocking connection */
934 data = g_new (LmConnectData, 1);
936 data->connection = connection;
937 data->resolved_addrs = ans;
938 data->current_addr = ans;
939 data->io_channel = NULL;
942 connection->connect_data = data;
944 connection_do_connect (data);
949 connection_do_close (LmConnection *connection)
954 connection_stop_keep_alive (connection);
956 if (connection->io_watch_connect != 0) {
958 source = g_main_context_find_source_by_id (connection->context,
959 connection->io_watch_connect);
962 g_source_destroy (source);
965 connection->io_watch_connect = 0;
968 data = connection->connect_data;
970 freeaddrinfo (data->resolved_addrs);
971 connection->connect_data = NULL;
975 if (connection->io_channel) {
976 if (connection->io_watch_in != 0) {
977 source = g_main_context_find_source_by_id (connection->context,
978 connection->io_watch_in);
980 g_source_destroy (source);
983 connection->io_watch_in = 0;
986 if (connection->io_watch_err != 0) {
987 source = g_main_context_find_source_by_id (connection->context,
988 connection->io_watch_err);
990 g_source_destroy (source);
993 connection->io_watch_err = 0;
996 if (connection->io_watch_hup != 0) {
997 source = g_main_context_find_source_by_id (connection->context,
998 connection->io_watch_hup);
1001 g_source_destroy (source);
1004 connection->io_watch_hup = 0;
1007 if (connection->io_watch_out != 0) {
1008 source = g_main_context_find_source_by_id (connection->context,
1009 connection->io_watch_out);
1012 g_source_destroy (source);
1015 connection->io_watch_out = 0;
1019 g_io_channel_unref (connection->io_channel);
1020 connection->io_channel = NULL;
1022 connection->fd = -1;
1025 if (connection->incoming_source) {
1026 g_source_destroy (connection->incoming_source);
1027 g_source_unref (connection->incoming_source);
1028 connection->incoming_source = NULL;
1031 if (!lm_connection_is_open (connection)) {
1032 /* lm_connection_is_open is FALSE for state OPENING as well */
1033 connection->state = LM_CONNECTION_STATE_CLOSED;
1034 connection->async_connect_waiting = FALSE;
1038 connection->state = LM_CONNECTION_STATE_CLOSED;
1039 connection->async_connect_waiting = FALSE;
1040 if (connection->ssl) {
1041 _lm_ssl_close (connection->ssl);
1046 connection_do_write (LmConnection *connection,
1052 if (connection->ssl) {
1053 b_written = _lm_ssl_send (connection->ssl, buf, len);
1055 GIOStatus io_status = G_IO_STATUS_AGAIN;
1056 gsize bytes_written;
1058 while (io_status == G_IO_STATUS_AGAIN) {
1059 io_status = g_io_channel_write_chars (connection->io_channel,
1065 b_written = bytes_written;
1067 if (io_status != G_IO_STATUS_NORMAL) {
1076 connection_read_incoming (LmConnection *connection,
1086 if (connection->ssl) {
1087 status = _lm_ssl_read (connection->ssl,
1088 buf, buf_size - 1, bytes_read);
1090 status = g_io_channel_read_chars (connection->io_channel,
1096 if (status != G_IO_STATUS_NORMAL || *bytes_read < 0) {
1100 case G_IO_STATUS_EOF:
1101 reason = LM_DISCONNECT_REASON_HUP;
1103 case G_IO_STATUS_AGAIN:
1104 /* No data readable but we didn't hangup */
1107 case G_IO_STATUS_ERROR:
1108 reason = LM_DISCONNECT_REASON_ERROR;
1111 reason = LM_DISCONNECT_REASON_UNKNOWN;
1114 connection_do_close (connection);
1115 connection_signal_disconnect (connection, reason);
1117 /* Notify connection_in_event that we hangup the connection */
1123 buf[*bytes_read] = '\0';
1125 /* There is more data to be read */
1130 connection_in_event (GIOChannel *source,
1131 GIOCondition condition,
1132 LmConnection *connection)
1134 gchar buf[IN_BUFFER_SIZE];
1138 if (connection->io_channel == NULL) {
1142 while (connection_read_incoming (connection, buf, IN_BUFFER_SIZE,
1143 &bytes_read, &hangup)) {
1144 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "\nRECV [%d]:\n",
1146 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
1147 "-----------------------------------\n");
1148 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "'%s'\n", buf);
1149 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
1150 "-----------------------------------\n");
1152 lm_verbose ("Read: %d chars\n", (int)bytes_read);
1154 lm_parser_parse (connection->parser, buf);
1165 connection_error_event (GIOChannel *source,
1166 GIOCondition condition,
1167 LmConnection *connection)
1169 lm_verbose ("Error event: %d->'%s'\n",
1170 condition, connection_condition_to_str (condition));
1172 if (!connection->io_channel) {
1176 connection_do_close (connection);
1177 connection_signal_disconnect (connection, LM_DISCONNECT_REASON_ERROR);
1183 connection_hup_event (GIOChannel *source,
1184 GIOCondition condition,
1185 LmConnection *connection)
1187 lm_verbose ("HUP event: %d->'%s'\n",
1188 condition, connection_condition_to_str (condition));
1190 if (!connection->io_channel) {
1194 connection_do_close (connection);
1195 connection_signal_disconnect (connection, LM_DISCONNECT_REASON_HUP);
1201 connection_send (LmConnection *connection,
1208 if (connection->state < LM_CONNECTION_STATE_OPENING) {
1209 g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
1210 "Connection is not open.\n");
1214 LM_ERROR_CONNECTION_NOT_OPEN,
1215 "Connection is not open, call lm_connection_open() first");
1223 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "\nSEND:\n");
1224 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
1225 "-----------------------------------\n");
1226 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "%s\n", str);
1227 g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
1228 "-----------------------------------\n");
1230 /* Check to see if there already is an output buffer, if so, add to the
1231 buffer and return */
1233 if (connection_output_is_buffered (connection, str, len)) {
1237 b_written = connection_do_write (connection, str, len);
1240 if (b_written < 0) {
1241 connection_error_event (connection->io_channel,
1247 if (b_written < len) {
1248 connection_setup_output_buffer (connection,
1263 auth_req_data_free (AuthReqData *data) {
1264 g_free (data->username);
1265 g_free (data->password);
1266 g_free (data->resource);
1271 connection_create_auth_req_msg (const gchar *username)
1274 LmMessageNode *q_node;
1276 m = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ,
1277 LM_MESSAGE_SUB_TYPE_GET);
1278 q_node = lm_message_node_add_child (m->node, "query", NULL);
1279 lm_message_node_set_attributes (q_node,
1280 "xmlns", "jabber:iq:auth",
1282 lm_message_node_add_child (q_node, "username", username);
1288 connection_create_auth_msg (LmConnection *connection,
1289 const gchar *username,
1290 const gchar *password,
1291 const gchar *resource,
1294 LmMessage *auth_msg;
1295 LmMessageNode *q_node;
1297 auth_msg = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ,
1298 LM_MESSAGE_SUB_TYPE_SET);
1300 q_node = lm_message_node_add_child (auth_msg->node, "query", NULL);
1302 lm_message_node_set_attributes (q_node,
1303 "xmlns", "jabber:iq:auth",
1306 lm_message_node_add_child (q_node, "username", username);
1308 if (auth_type & AUTH_TYPE_0K) {
1309 lm_verbose ("Using 0k auth (not implemented yet)\n");
1310 /* TODO: Should probably use this? */
1313 if (auth_type & AUTH_TYPE_DIGEST) {
1315 const gchar *digest;
1317 lm_verbose ("Using digest\n");
1318 str = g_strconcat (connection->stream_id, password, NULL);
1319 digest = lm_sha_hash (str);
1321 lm_message_node_add_child (q_node, "digest", digest);
1323 else if (auth_type & AUTH_TYPE_PLAIN) {
1324 lm_verbose ("Using plaintext auth\n");
1325 lm_message_node_add_child (q_node, "password", password);
1327 /* TODO: Report error somehow */
1330 lm_message_node_add_child (q_node, "resource", resource);
1335 static LmHandlerResult
1336 connection_auth_req_reply (LmMessageHandler *handler,
1337 LmConnection *connection,
1342 LmMessage *auth_msg;
1343 LmMessageHandler *auth_handler;
1344 AuthReqData *data = (AuthReqData *) user_data;
1347 auth_type = connection_check_auth_type (m);
1349 auth_msg = connection_create_auth_msg (connection,
1355 auth_handler = lm_message_handler_new (connection_auth_reply,
1357 result = lm_connection_send_with_reply (connection, auth_msg,
1358 auth_handler, NULL);
1359 lm_message_handler_unref (auth_handler);
1360 lm_message_unref (auth_msg);
1362 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
1366 connection_check_auth_type (LmMessage *auth_req_rpl)
1368 LmMessageNode *q_node;
1371 q_node = lm_message_node_get_child (auth_req_rpl->node, "query");
1374 return AUTH_TYPE_PLAIN;
1377 if (lm_message_node_get_child (q_node, "password")) {
1378 ret_val |= AUTH_TYPE_PLAIN;
1381 if (lm_message_node_get_child (q_node, "digest")) {
1382 ret_val |= AUTH_TYPE_DIGEST;
1385 if (lm_message_node_get_child (q_node, "sequence") &&
1386 lm_message_node_get_child (q_node, "token")) {
1387 ret_val |= AUTH_TYPE_0K;
1393 static LmHandlerResult
1394 connection_auth_reply (LmMessageHandler *handler,
1395 LmConnection *connection,
1400 gboolean result = TRUE;
1402 g_return_val_if_fail (connection != NULL,
1403 LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS);
1406 type = lm_message_node_get_attribute (m->node, "type");
1407 if (strcmp (type, "result") == 0) {
1409 connection->state = LM_CONNECTION_STATE_AUTHENTICATED;
1411 else if (strcmp (type, "error") == 0) {
1413 connection->state = LM_CONNECTION_STATE_OPEN;
1416 lm_verbose ("AUTH reply: %d\n", result);
1418 if (connection->auth_cb) {
1419 LmCallback *cb = connection->auth_cb;
1421 connection->auth_cb = NULL;
1424 (* ((LmResultFunction) cb->func)) (connection,
1425 result, cb->user_data);
1428 _lm_utils_free_callback (cb);
1431 return LM_HANDLER_RESULT_REMOVE_MESSAGE;
1436 connection_stream_received (LmConnection *connection, LmMessage *m)
1440 g_return_if_fail (connection != NULL);
1441 g_return_if_fail (m != NULL);
1443 connection->stream_id = g_strdup (lm_message_node_get_attribute (m->node,
1446 lm_verbose ("Stream received: %s\n", connection->stream_id);
1448 connection->state = LM_CONNECTION_STATE_OPEN;
1450 /* Check to see if the stream is correctly set up */
1453 connection_start_keep_alive (connection);
1455 if (connection->open_cb) {
1456 LmCallback *cb = connection->open_cb;
1458 connection->open_cb = NULL;
1461 (* ((LmResultFunction) cb->func)) (connection, result,
1465 _lm_utils_free_callback (connection->open_cb);
1470 connection_handler_compare_func (HandlerData *a, HandlerData *b)
1472 return b->priority - a->priority;
1476 connection_incoming_prepare (GSource *source, gint *timeout)
1478 LmConnection *connection;
1480 connection = ((LmIncomingSource *)source)->connection;
1482 return !g_queue_is_empty (connection->incoming_messages);
1486 connection_incoming_check (GSource *source)
1492 connection_incoming_dispatch (GSource *source,
1493 GSourceFunc callback,
1496 LmConnection *connection;
1499 connection = ((LmIncomingSource *) source)->connection;
1501 m = (LmMessage *) g_queue_pop_head (connection->incoming_messages);
1504 connection_handle_message (connection, m);
1505 lm_message_unref (m);
1512 connection_create_source (LmConnection *connection)
1516 source = g_source_new (&incoming_funcs, sizeof (LmIncomingSource));
1517 ((LmIncomingSource *) source)->connection = connection;
1523 connection_signal_disconnect (LmConnection *connection,
1524 LmDisconnectReason reason)
1526 if (connection->disconnect_cb && connection->disconnect_cb->func) {
1527 LmCallback *cb = connection->disconnect_cb;
1529 (* ((LmDisconnectFunction) cb->func)) (connection,
1536 * lm_connection_new:
1537 * @server: The hostname to the server for the connection.
1539 * Creates a new closed connection. To open the connection call
1540 * lm_connection_open(). @server can be #NULL but must be set before calling lm_connection_open().
1542 * Return value: A newly created LmConnection, should be unreffed with lm_connection_unref().
1545 lm_connection_new (const gchar *server)
1547 LmConnection *connection;
1551 _lm_sock_library_init ();
1553 connection = g_new0 (LmConnection, 1);
1556 connection->server = _lm_utils_hostname_to_punycode (server);
1558 connection->server = NULL;
1561 connection->context = NULL;
1562 connection->port = LM_CONNECTION_DEFAULT_PORT;
1563 connection->jid = NULL;
1564 connection->ssl = NULL;
1565 connection->proxy = NULL;
1566 connection->disconnect_cb = NULL;
1567 connection->incoming_messages = g_queue_new ();
1568 connection->cancel_open = FALSE;
1569 connection->state = LM_CONNECTION_STATE_CLOSED;
1570 connection->keep_alive_id = 0;
1571 connection->keep_alive_rate = 0;
1572 connection->out_buf = NULL;
1573 connection->connect_data = NULL;
1575 connection->id_handlers = g_hash_table_new_full (g_str_hash,
1578 (GDestroyNotify) lm_message_handler_unref);
1579 connection->ref_count = 1;
1581 for (i = 0; i < LM_MESSAGE_TYPE_UNKNOWN; ++i) {
1582 connection->handlers[i] = NULL;
1585 connection->parser = lm_parser_new
1586 ((LmParserMessageFunction) connection_new_message_cb,
1593 * lm_connection_new_with_context:
1594 * @server: The hostname to the server for the connection.
1595 * @context: The context this connection should be running in.
1597 * Creates a new closed connection running in a certain context. To open the
1598 * connection call #lm_connection_open. @server can be #NULL but must be set
1599 * before calling #lm_connection_open.
1601 * Return value: A newly created LmConnection, should be unreffed with lm_connection_unref().
1604 lm_connection_new_with_context (const gchar *server, GMainContext *context)
1606 LmConnection *connection;
1608 connection = lm_connection_new (server);
1609 connection->context = context;
1612 g_main_context_ref (connection->context);
1619 * lm_connection_open:
1620 * @connection: #LmConnection to open
1621 * @function: Callback function that will be called when the connection is open.
1622 * @user_data: User data that will be passed to @function.
1623 * @notify: Function for freeing that user_data, can be NULL.
1624 * @error: location to store error, or %NULL
1626 * An async call to open @connection. When the connection is open @function will be called.
1628 * Return value: #TRUE if everything went fine, otherwise #FALSE.
1631 lm_connection_open (LmConnection *connection,
1632 LmResultFunction function,
1634 GDestroyNotify notify,
1637 g_return_val_if_fail (connection != NULL, FALSE);
1639 connection->open_cb = _lm_utils_new_callback (function,
1641 connection->blocking = FALSE;
1643 return connection_do_open (connection, error);
1647 * lm_connection_open_and_block:
1648 * @connection: an #LmConnection to open
1649 * @error: location to store error, or %NULL
1651 * Opens @connection and waits until the stream is setup.
1653 * Return value: #TRUE if no errors where encountered during opening and stream setup successfully, #FALSE otherwise.
1656 lm_connection_open_and_block (LmConnection *connection, GError **error)
1659 LmConnectionState state;
1661 g_return_val_if_fail (connection != NULL, FALSE);
1663 connection->open_cb = NULL;
1664 connection->blocking = TRUE;
1666 result = connection_do_open (connection, error);
1668 if (result == FALSE) {
1672 while ((state = lm_connection_get_state (connection)) == LM_CONNECTION_STATE_OPENING) {
1673 if (g_main_context_pending (connection->context)) {
1674 g_main_context_iteration (connection->context, TRUE);
1676 /* Sleep for 1 millisecond */
1681 if (lm_connection_is_open (connection)) {
1682 connection_start_keep_alive (connection);
1686 /* Need to set the error here: LM-15 */
1689 LM_ERROR_CONNECTION_FAILED,
1690 "Opening the connection failed");
1696 * lm_connection_cancel_open:
1697 * @connection: an #LmConnection to cancel opening on
1699 * Cancels the open operation of a connection. The connection should be in the state #LM_CONNECTION_STATE_OPENING.
1702 lm_connection_cancel_open (LmConnection *connection)
1704 g_return_if_fail (connection != NULL);
1706 connection->cancel_open = TRUE;
1710 * lm_connection_close:
1711 * @connection: #LmConnection to close
1712 * @error: location to store error, or %NULL
1714 * A synchronous call to close the connection. When returning the connection is considered to be closed and can be opened again with lm_connection_open().
1716 * Return value: Returns #TRUE if no errors where detected, otherwise #FALSE.
1719 lm_connection_close (LmConnection *connection,
1722 gboolean no_errors = TRUE;
1724 g_return_val_if_fail (connection != NULL, FALSE);
1726 if (connection->state == LM_CONNECTION_STATE_CLOSED) {
1729 LM_ERROR_CONNECTION_NOT_OPEN,
1730 "Connection is not open, call lm_connection_open() first");
1734 lm_verbose ("Disconnecting from: %s:%d\n",
1735 connection->server, connection->port);
1737 if (lm_connection_is_open (connection)) {
1738 if (!connection_send (connection, "</stream:stream>", -1, error)) {
1742 g_io_channel_flush (connection->io_channel, NULL);
1745 connection_do_close (connection);
1746 connection_signal_disconnect (connection, LM_DISCONNECT_REASON_OK);
1752 * lm_connection_authenticate:
1753 * @connection: #LmConnection to authenticate.
1754 * @username: Username used to authenticate.
1755 * @password: Password corresponding to @username.
1756 * @resource: Resource used for this connection.
1757 * @function: Callback called when authentication is finished.
1758 * @user_data: Userdata passed to @function when called.
1759 * @notify: Destroy function to free the memory used by @user_data, can be NULL.
1760 * @error: location to store error, or %NULL
1762 * Tries to authenticate a user against the server. The #LmResult in the result callback @function will say whether it succeeded or not.
1764 * Return value: #TRUE if no errors where detected while sending the authentication message, #FALSE otherwise.
1767 lm_connection_authenticate (LmConnection *connection,
1768 const gchar *username,
1769 const gchar *password,
1770 const gchar *resource,
1771 LmResultFunction function,
1773 GDestroyNotify notify,
1777 LmMessageHandler *handler;
1781 g_return_val_if_fail (connection != NULL, FALSE);
1782 g_return_val_if_fail (username != NULL, FALSE);
1783 g_return_val_if_fail (password != NULL, FALSE);
1784 g_return_val_if_fail (resource != NULL, FALSE);
1786 if (!lm_connection_is_open (connection)) {
1789 LM_ERROR_CONNECTION_NOT_OPEN,
1790 "Connection is not open, call lm_connection_open() first");
1794 /* FIXME: Do SASL authentication here (if XMPP 1.0 is used) */
1796 connection->state = LM_CONNECTION_STATE_AUTHENTICATING;
1798 connection->auth_cb = _lm_utils_new_callback (function,
1802 m = connection_create_auth_req_msg (username);
1804 data = g_new0 (AuthReqData, 1);
1805 data->username = g_strdup (username);
1806 data->password = g_strdup (password);
1807 data->resource = g_strdup (resource);
1809 handler = lm_message_handler_new (connection_auth_req_reply,
1811 (GDestroyNotify) auth_req_data_free);
1812 result = lm_connection_send_with_reply (connection, m, handler, error);
1814 lm_message_handler_unref (handler);
1815 lm_message_unref (m);
1821 * lm_connection_authenticate_and_block:
1822 * @connection: an #LmConnection
1823 * @username: Username used to authenticate.
1824 * @password: Password corresponding to @username.
1825 * @resource: Resource used for this connection.
1826 * @error: location to store error, or %NULL
1828 * Tries to authenticate a user against the server. This function blocks until a reply to the authentication attempt is returned and returns whether it was successful or not.
1830 * Return value: #TRUE if no errors where detected and authentication was successful. #FALSE otherwise.
1833 lm_connection_authenticate_and_block (LmConnection *connection,
1834 const gchar *username,
1835 const gchar *password,
1836 const gchar *resource,
1841 LmMessageSubType type;
1843 g_return_val_if_fail (connection != NULL, FALSE);
1844 g_return_val_if_fail (username != NULL, FALSE);
1845 g_return_val_if_fail (password != NULL, FALSE);
1846 g_return_val_if_fail (resource != NULL, FALSE);
1848 if (!lm_connection_is_open (connection)) {
1851 LM_ERROR_CONNECTION_NOT_OPEN,
1852 "Connection is not open, call lm_connection_open() first");
1856 connection->state = LM_CONNECTION_STATE_AUTHENTICATING;
1858 m = connection_create_auth_req_msg (username);
1859 result = lm_connection_send_with_reply_and_block (connection, m, error);
1860 lm_message_unref (m);
1863 connection->state = LM_CONNECTION_STATE_OPEN;
1867 m = connection_create_auth_msg (connection,
1871 connection_check_auth_type (result));
1872 lm_message_unref (result);
1874 result = lm_connection_send_with_reply_and_block (connection, m, error);
1875 lm_message_unref (m);
1878 connection->state = LM_CONNECTION_STATE_OPEN;
1882 type = lm_message_get_sub_type (result);
1883 lm_message_unref (result);
1886 case LM_MESSAGE_SUB_TYPE_RESULT:
1887 connection->state = LM_CONNECTION_STATE_AUTHENTICATED;
1890 case LM_MESSAGE_SUB_TYPE_ERROR:
1891 connection->state = LM_CONNECTION_STATE_OPEN;
1894 LM_ERROR_AUTH_FAILED,
1895 "Authentication failed");
1899 g_assert_not_reached ();
1907 * lm_connection_set_keep_alive_rate:
1908 * @connection: #LmConnection to check if it is open.
1909 * @rate: Number of seconds between keep alive packages are sent.
1911 * Set the keep alive rate, in seconds. Set to 0 to prevent keep alive messages to be sent.
1912 * A keep alive message is a single space character.
1915 lm_connection_set_keep_alive_rate (LmConnection *connection, guint rate)
1917 g_return_if_fail (connection != NULL);
1919 connection_stop_keep_alive (connection);
1922 connection->keep_alive_id = 0;
1926 connection->keep_alive_rate = rate * 1000;
1928 if (lm_connection_is_open (connection)) {
1929 connection_start_keep_alive (connection);
1934 * lm_connection_is_open:
1935 * @connection: #LmConnection to check if it is open.
1937 * Check if the @connection is currently open.
1939 * Return value: #TRUE if connection is open and #FALSE if it is closed.
1942 lm_connection_is_open (LmConnection *connection)
1944 g_return_val_if_fail (connection != NULL, FALSE);
1946 return connection->state >= LM_CONNECTION_STATE_OPEN;
1950 * lm_connection_is_authenticated:
1951 * @connection: #LmConnection to check if it is authenticated
1953 * Check if @connection is authenticated.
1955 * Return value: #TRUE if connection is authenticated, #FALSE otherwise.
1958 lm_connection_is_authenticated (LmConnection *connection)
1960 g_return_val_if_fail (connection != NULL, FALSE);
1962 return connection->state >= LM_CONNECTION_STATE_AUTHENTICATED;
1966 * lm_connection_get_server:
1967 * @connection: an #LmConnection
1969 * Fetches the server address that @connection is using.
1971 * Return value: the server address
1974 lm_connection_get_server (LmConnection *connection)
1976 g_return_val_if_fail (connection != NULL, NULL);
1978 return connection->server;
1982 * lm_connection_set_server:
1983 * @connection: an #LmConnection
1984 * @server: Address of the server
1986 * Sets the server address for @connection to @server. Notice that @connection
1987 * can't be open while doing this.
1990 lm_connection_set_server (LmConnection *connection, const gchar *server)
1992 g_return_if_fail (connection != NULL);
1993 g_return_if_fail (server != NULL);
1995 if (lm_connection_is_open (connection)) {
1996 g_warning ("Can't change server address while connected");
2000 g_free (connection->server);
2001 connection->server = _lm_utils_hostname_to_punycode (server);
2005 * lm_connection_get_jid:
2006 * @connection: an #LmConnection
2008 * Fetches the jid set for @connection is using.
2010 * Return value: the jid
2013 lm_connection_get_jid (LmConnection *connection)
2015 g_return_val_if_fail (connection != NULL, NULL);
2017 return connection->jid;
2021 * lm_connection_set_jid:
2022 * @connection: an #LmConnection
2023 * @jid: JID to be used for @connection
2025 * Sets the JID to be used for @connection.
2028 lm_connection_set_jid (LmConnection *connection, const gchar *jid)
2030 g_return_if_fail (connection != NULL);
2032 if (lm_connection_is_open (connection)) {
2033 g_warning ("Can't change JID while connected");
2037 g_free (connection->jid);
2038 connection->jid = g_strdup (jid);
2042 * lm_connection_get_port:
2043 * @connection: an #LmConnection
2045 * Fetches the port that @connection is using.
2050 lm_connection_get_port (LmConnection *connection)
2052 g_return_val_if_fail (connection != NULL, 0);
2054 return connection->port;
2058 * lm_connection_set_port:
2059 * @connection: an #LmConnection
2060 * @port: server port
2062 * Sets the server port that @connection will be using.
2065 lm_connection_set_port (LmConnection *connection, guint port)
2067 g_return_if_fail (connection != NULL);
2069 if (lm_connection_is_open (connection)) {
2070 g_warning ("Can't change server port while connected");
2074 connection->port = port;
2078 * lm_connection_get_ssl:
2079 * @connection: an #LmConnection
2081 * Returns the SSL struct if the connection is using one.
2083 * Return value: The ssl struct or %NULL if no proxy is used.
2086 lm_connection_get_ssl (LmConnection *connection)
2088 g_return_val_if_fail (connection != NULL, NULL);
2090 return connection->ssl;
2094 * lm_connection_set_ssl:
2095 * @connection: An #LmConnection
2098 * Sets SSL struct or unset if @ssl is %NULL. If set @connection will use SSL to for the connection.
2101 lm_connection_set_ssl (LmConnection *connection, LmSSL *ssl)
2103 g_return_if_fail (connection != NULL);
2104 g_return_if_fail (lm_ssl_is_supported () == TRUE);
2106 if (connection->ssl) {
2107 lm_ssl_unref (connection->ssl);
2111 connection->ssl = lm_ssl_ref (ssl);
2113 connection->ssl = NULL;
2118 * lm_connection_get_proxy:
2119 * @connection: an #LmConnection
2121 * Returns the proxy if the connection is using one.
2123 * Return value: The proxy or %NULL if no proxy is used.
2126 lm_connection_get_proxy (LmConnection *connection)
2128 g_return_val_if_fail (connection != NULL, NULL);
2130 return connection->proxy;
2134 * lm_connection_set_proxy:
2135 * @connection: an #LmConnection
2136 * @proxy: an #LmProxy
2138 * Sets the proxy to use for this connection. To unset pass #NULL.
2142 lm_connection_set_proxy (LmConnection *connection, LmProxy *proxy)
2144 g_return_if_fail (connection != NULL);
2146 if (lm_connection_is_open (connection)) {
2147 g_warning ("Can't change server proxy while connected");
2151 if (connection->proxy) {
2152 lm_proxy_unref (connection->proxy);
2153 connection->proxy = NULL;
2156 if (proxy && lm_proxy_get_type (proxy) != LM_PROXY_TYPE_NONE) {
2157 connection->proxy = lm_proxy_ref (proxy);
2162 * lm_connection_send:
2163 * @connection: #LmConnection to send message over.
2164 * @message: #LmMessage to send.
2165 * @error: location to store error, or %NULL
2167 * Asynchronous call to send a message.
2169 * Return value: Returns #TRUE if no errors where detected while sending, #FALSE otherwise.
2172 lm_connection_send (LmConnection *connection,
2180 g_return_val_if_fail (connection != NULL, FALSE);
2181 g_return_val_if_fail (message != NULL, FALSE);
2183 xml_str = lm_message_node_to_string (message->node);
2184 if ((ch = strstr (xml_str, "</stream:stream>"))) {
2188 result = connection_send (connection, xml_str, -1, error);
2195 * lm_connection_send_with_reply:
2196 * @connection: #LmConnection used to send message.
2197 * @message: #LmMessage to send.
2198 * @handler: #LmMessageHandler that will be used when a reply to @message arrives
2199 * @error: location to store error, or %NULL
2201 * Send a #LmMessage which will result in a reply.
2203 * Return value: Returns #TRUE if no errors where detected while sending, #FALSE otherwise.
2206 lm_connection_send_with_reply (LmConnection *connection,
2208 LmMessageHandler *handler,
2213 g_return_val_if_fail (connection != NULL, FALSE);
2214 g_return_val_if_fail (message != NULL, FALSE);
2215 g_return_val_if_fail (handler != NULL, FALSE);
2217 if (lm_message_node_get_attribute (message->node, "id")) {
2218 id = g_strdup (lm_message_node_get_attribute (message->node,
2221 id = _lm_utils_generate_id ();
2222 lm_message_node_set_attributes (message->node, "id", id, NULL);
2225 g_hash_table_insert (connection->id_handlers,
2226 id, lm_message_handler_ref (handler));
2228 return lm_connection_send (connection, message, error);
2232 * lm_connection_send_with_reply_and_block:
2233 * @connection: an #LmConnection
2234 * @message: an #LmMessage
2235 * @error: Set if error was detected during sending.
2237 * Send @message and wait for return.
2239 * Return value: The reply
2242 lm_connection_send_with_reply_and_block (LmConnection *connection,
2247 LmMessage *reply = NULL;
2249 g_return_val_if_fail (connection != NULL, NULL);
2250 g_return_val_if_fail (message != NULL, NULL);
2252 if (connection->state < LM_CONNECTION_STATE_OPENING) {
2255 LM_ERROR_CONNECTION_NOT_OPEN,
2256 "Connection is not open, call lm_connection_open() first");
2261 if (lm_message_node_get_attribute (message->node, "id")) {
2262 id = g_strdup (lm_message_node_get_attribute (message->node,
2265 id = _lm_utils_generate_id ();
2266 lm_message_node_set_attributes (message->node, "id", id, NULL);
2269 g_source_remove (g_source_get_id (connection->incoming_source));
2270 g_source_unref (connection->incoming_source);
2271 connection->incoming_source = NULL;
2273 lm_connection_send (connection, message, error);
2279 g_main_context_iteration (connection->context, TRUE);
2281 if (g_queue_is_empty (connection->incoming_messages)) {
2285 for (n = 0; n < g_queue_get_length (connection->incoming_messages); n++) {
2288 m = (LmMessage *) g_queue_peek_nth (connection->incoming_messages, n);
2290 m_id = lm_message_node_get_attribute (m->node, "id");
2292 if (m_id && strcmp (m_id, id) == 0) {
2294 g_queue_pop_nth (connection->incoming_messages,
2302 connection->incoming_source = connection_create_source (connection);
2303 g_source_attach (connection->incoming_source, connection->context);
2309 * lm_connection_register_message_handler:
2310 * @connection: Connection to register a handler for.
2311 * @handler: Message handler to register.
2312 * @type: Message type that @handler will handle.
2313 * @priority: The priority in which to call @handler.
2315 * Registers a #LmMessageHandler to handle incoming messages of a certain type.
2316 * To unregister the handler call lm_connection_unregister_message_handler().
2319 lm_connection_register_message_handler (LmConnection *connection,
2320 LmMessageHandler *handler,
2322 LmHandlerPriority priority)
2326 g_return_if_fail (connection != NULL);
2327 g_return_if_fail (handler != NULL);
2328 g_return_if_fail (type != LM_MESSAGE_TYPE_UNKNOWN);
2330 hd = g_new0 (HandlerData, 1);
2331 hd->priority = priority;
2332 hd->handler = lm_message_handler_ref (handler);
2334 connection->handlers[type] = g_slist_insert_sorted (connection->handlers[type],
2336 (GCompareFunc) connection_handler_compare_func);
2340 * lm_connection_unregister_message_handler:
2341 * @connection: Connection to unregister a handler for.
2342 * @handler: The handler to unregister.
2343 * @type: What type of messages to unregister this handler for.
2345 * Unregisters a handler for @connection. @handler will no longer be called
2346 * when incoming messages of @type arrive.
2349 lm_connection_unregister_message_handler (LmConnection *connection,
2350 LmMessageHandler *handler,
2353 GSList *l, *prev = NULL;
2355 g_return_if_fail (connection != NULL);
2356 g_return_if_fail (handler != NULL);
2357 g_return_if_fail (type != LM_MESSAGE_TYPE_UNKNOWN);
2359 for (l = connection->handlers[type]; l; l = l->next) {
2360 HandlerData *hd = (HandlerData *) l->data;
2362 if (hd->handler == handler) {
2364 prev->next = l->next;
2366 connection->handlers[type] = l->next;
2370 lm_message_handler_unref (hd->handler);
2379 * lm_connection_set_disconnect_function:
2380 * @connection: Connection to register disconnect callback for.
2381 * @function: Function to be called when @connection is closed.
2382 * @user_data: User data passed to @function.
2383 * @notify: Function that will be called with @user_data when @user_data needs to be freed. Pass #NULL if it shouldn't be freed.
2385 * Set the callback that will be called when a connection is closed.
2388 lm_connection_set_disconnect_function (LmConnection *connection,
2389 LmDisconnectFunction function,
2391 GDestroyNotify notify)
2393 g_return_if_fail (connection != NULL);
2395 if (connection->disconnect_cb) {
2396 _lm_utils_free_callback (connection->disconnect_cb);
2400 connection->disconnect_cb = _lm_utils_new_callback (function,
2404 connection->disconnect_cb = NULL;
2409 * lm_connection_send_raw:
2410 * @connection: Connection used to send
2411 * @str: The string to send, the entire string will be sent.
2412 * @error: Set if error was detected during sending.
2414 * Asynchronous call to send a raw string. Useful for debugging and testing.
2416 * Return value: Returns #TRUE if no errors was detected during sending,
2420 lm_connection_send_raw (LmConnection *connection,
2424 g_return_val_if_fail (connection != NULL, FALSE);
2425 g_return_val_if_fail (str != NULL, FALSE);
2427 return connection_send (connection, str, -1, error);
2430 * lm_connection_get_state:
2431 * @connection: Connection to get state on
2433 * Returns the state of the connection.
2435 * Return value: The state of the connection.
2438 lm_connection_get_state (LmConnection *connection)
2440 g_return_val_if_fail (connection != NULL,
2441 LM_CONNECTION_STATE_CLOSED);
2443 return connection->state;
2447 * lm_connection_ref:
2448 * @connection: Connection to add a reference to.
2450 * Add a reference on @connection. To remove a reference call
2451 * lm_connection_unref().
2453 * Return value: Returns the same connection.
2456 lm_connection_ref (LmConnection *connection)
2458 g_return_val_if_fail (connection != NULL, NULL);
2460 connection->ref_count++;
2466 * lm_connection_unref:
2467 * @connection: Connection to remove reference from.
2469 * Removes a reference on @connection. If there are no references to
2470 * @connection it will be freed and shouldn't be used again.
2473 lm_connection_unref (LmConnection *connection)
2475 g_return_if_fail (connection != NULL);
2477 connection->ref_count--;
2479 if (connection->ref_count == 0) {
2480 connection_free (connection);