telepathy: implement read side of transport
[siplcs.git] / src / telepathy / telepathy-transport.c
blobb1adf9758c776e3cd6e39a2766cbb13a2007df6e
1 /**
2 * @file telepathy-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2012 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <string.h>
29 #include <glib.h>
30 #include <gio/gio.h>
32 #include "sipe-backend.h"
33 #include "sipe-common.h"
34 #include "sipe-core.h"
35 #include "sipe-nls.h"
37 #include "telepathy-private.h"
39 struct sipe_transport_telepathy {
40 /* public part shared with core */
41 struct sipe_transport_connection public;
43 /* telepathy private part */
44 transport_connected_cb *connected;
45 transport_input_cb *input;
46 transport_error_cb *error;
47 struct sipe_backend_private *private;
48 GSocketConnection *socket;
49 GInputStream *istream;
50 GOutputStream *ostream;
53 #define TELEPATHY_TRANSPORT ((struct sipe_transport_telepathy *) conn)
54 #define SIPE_TRANSPORT_CONNECTION ((struct sipe_transport_connection *) transport)
56 #define BUFFER_SIZE_INCREMENT 4096
58 static void read_completed(GObject *stream,
59 GAsyncResult *result,
60 gpointer data)
62 struct sipe_transport_telepathy *transport = data;
63 struct sipe_transport_connection *conn = SIPE_TRANSPORT_CONNECTION;
65 if (conn->buffer_length < conn->buffer_used + BUFFER_SIZE_INCREMENT) {
66 conn->buffer_length += BUFFER_SIZE_INCREMENT;
67 conn->buffer = g_realloc(conn->buffer, conn->buffer_length);
68 SIPE_DEBUG_INFO("read_completed: new buffer length %" G_GSIZE_FORMAT,
69 conn->buffer_length);
72 /* callback result is valid */
73 if (result) {
74 GError *error = NULL;
75 gssize len = g_input_stream_read_finish(G_INPUT_STREAM(stream),
76 result,
77 &error);
79 if (len < 0) {
80 SIPE_DEBUG_ERROR("read error: %s", error->message);
81 transport->error(conn, error->message);
82 g_error_free(error);
83 return;
84 } else if (len == 0) {
85 SIPE_DEBUG_ERROR_NOFORMAT("Server has disconnected");
86 transport->error(conn, _("Server has disconnected"));
87 return;
90 /* Forward data to core */
91 conn->buffer_used += len;
92 conn->buffer[conn->buffer_used] = '\0';
93 transport->input(conn);
96 /* setup next read */
97 g_input_stream_read_async(G_INPUT_STREAM(stream),
98 conn->buffer + conn->buffer_used,
99 conn->buffer_length - conn->buffer_used - 1,
100 G_PRIORITY_DEFAULT,
101 NULL,
102 read_completed,
103 transport);
106 static void socket_connected(GObject *client,
107 GAsyncResult *result,
108 gpointer data)
110 struct sipe_transport_telepathy *transport = data;
111 GError *error = NULL;
113 transport->socket = g_socket_client_connect_finish(G_SOCKET_CLIENT(client),
114 result,
115 &error);
117 if (transport->socket) {
118 SIPE_DEBUG_INFO_NOFORMAT("socket_connected: success");
119 transport->istream = g_io_stream_get_input_stream(G_IO_STREAM(transport->socket));
120 transport->ostream = g_io_stream_get_output_stream(G_IO_STREAM(transport->socket));
121 /* this sets up the async read handler */
122 read_completed(G_OBJECT(transport->istream), NULL, transport);
123 transport->connected(SIPE_TRANSPORT_CONNECTION);
124 } else {
125 SIPE_DEBUG_ERROR("socket_connected: failed: %s", error->message);
126 transport->error(SIPE_TRANSPORT_CONNECTION, error->message);
130 struct sipe_transport_connection *sipe_backend_transport_connect(struct sipe_core_public *sipe_public,
131 const sipe_connect_setup *setup)
133 struct sipe_transport_telepathy *transport = g_new0(struct sipe_transport_telepathy, 1);
134 struct sipe_backend_private *telepathy_private = sipe_public->backend_private;
136 SIPE_DEBUG_INFO("sipe_backend_transport_connect - hostname: %s port: %d",
137 setup->server_name, setup->server_port);
139 transport->public.type = setup->type;
140 transport->public.user_data = setup->user_data;
141 transport->connected = setup->connected;
142 transport->input = setup->input;
143 transport->error = setup->error;
144 transport->private = telepathy_private;
146 if ((setup->type == SIPE_TRANSPORT_TLS) ||
147 (setup->type == SIPE_TRANSPORT_TCP)) {
148 GSocketClient *client = g_socket_client_new();
150 /* request TLS connection */
151 if (setup->type == SIPE_TRANSPORT_TLS) {
152 SIPE_DEBUG_INFO_NOFORMAT("using TLS");
153 g_socket_client_set_tls(client,
154 setup->type == SIPE_TRANSPORT_TLS);
155 /* @TODO certificate handling - now accept all*/
156 g_socket_client_set_tls_validation_flags(client, 0);
157 } else
158 SIPE_DEBUG_INFO_NOFORMAT("using TCP");
160 g_socket_client_connect_async(client,
161 g_network_address_new(setup->server_name,
162 setup->server_port),
163 NULL,
164 socket_connected,
165 transport);
166 g_object_unref(client);
167 } else {
168 setup->error(SIPE_TRANSPORT_CONNECTION,
169 "This should not happen...");
170 sipe_backend_transport_disconnect(SIPE_TRANSPORT_CONNECTION);
171 return(NULL);
174 /* the first connection is always to the server */
175 if (telepathy_private->transport == NULL)
176 telepathy_private->transport = transport;
178 return(SIPE_TRANSPORT_CONNECTION);
181 void sipe_backend_transport_disconnect(struct sipe_transport_connection *conn)
183 struct sipe_transport_telepathy *transport = TELEPATHY_TRANSPORT;
185 if (!transport) return;
187 if (transport->socket)
188 g_object_unref(transport->socket);
190 /* connection to the server dropped? */
191 if (transport->private->transport == transport)
192 transport->private->transport = NULL;
194 g_free(transport);
197 static void write_completed(GObject *stream,
198 GAsyncResult *result,
199 gpointer data)
201 struct sipe_transport_telepathy *transport = data;
202 GError *error = NULL;
204 g_output_stream_write_finish(G_OUTPUT_STREAM(stream), result, &error);
206 if (error) {
207 SIPE_DEBUG_ERROR("write error: %s", error->message);
208 transport->error(SIPE_TRANSPORT_CONNECTION, error->message);
209 g_error_free(error);
213 void sipe_backend_transport_message(struct sipe_transport_connection *conn,
214 const gchar *buffer)
216 struct sipe_transport_telepathy *transport = TELEPATHY_TRANSPORT;
217 g_output_stream_write_async(transport->ostream,
218 buffer,
219 strlen(buffer),
220 G_PRIORITY_DEFAULT,
221 NULL,
222 write_completed,
223 transport);
226 void sipe_backend_transport_flush(struct sipe_transport_connection *conn)
228 struct sipe_transport_telepathy *transport = TELEPATHY_TRANSPORT;
229 g_output_stream_flush(transport->ostream, NULL, NULL);
233 Local Variables:
234 mode: c
235 c-file-style: "bsd"
236 indent-tabs-mode: t
237 tab-width: 8
238 End: