packaging: Bump to 1.17
[platform/upstream/ofono.git] / gatchat / gatio.c
1 /*
2  *
3  *  AT chat library with GLib integration
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32
33 #include <glib.h>
34
35 #include "ringbuffer.h"
36 #include "gatio.h"
37 #include "gatutil.h"
38
39 struct _GAtIO {
40         gint ref_count;                         /* Ref count */
41         guint read_watch;                       /* GSource read id, 0 if no */
42         guint write_watch;                      /* GSource write id, 0 if no */
43         GIOChannel *channel;                    /* comms channel */
44         GAtDisconnectFunc user_disconnect;      /* user disconnect func */
45         gpointer user_disconnect_data;          /* user disconnect data */
46         struct ring_buffer *buf;                /* Current read buffer */
47         guint max_read_attempts;                /* max reads / select */
48         GAtIOReadFunc read_handler;             /* Read callback */
49         gpointer read_data;                     /* Read callback userdata */
50         gboolean use_write_watch;               /* Use write select */
51         GAtIOWriteFunc write_handler;           /* Write callback */
52         gpointer write_data;                    /* Write callback userdata */
53         GAtDebugFunc debugf;                    /* debugging output function */
54         gpointer debug_data;                    /* Data to pass to debug func */
55         GAtDisconnectFunc write_done_func;      /* tx empty notifier */
56         gpointer write_done_data;               /* tx empty data */
57         gboolean destroyed;                     /* Re-entrancy guard */
58 };
59
60 static void read_watcher_destroy_notify(gpointer user_data)
61 {
62         GAtIO *io = user_data;
63
64         ring_buffer_free(io->buf);
65         io->buf = NULL;
66
67         io->debugf = NULL;
68         io->debug_data = NULL;
69
70         io->read_watch = 0;
71         io->read_handler = NULL;
72         io->read_data = NULL;
73
74         io->channel = NULL;
75
76         if (io->destroyed)
77                 g_free(io);
78         else if (io->user_disconnect)
79                 io->user_disconnect(io->user_disconnect_data);
80 }
81
82 static gboolean received_data(GIOChannel *channel, GIOCondition cond,
83                                 gpointer data)
84 {
85         unsigned char *buf;
86         GAtIO *io = data;
87         GIOStatus status;
88         gsize rbytes;
89         gsize toread;
90         gsize total_read = 0;
91         guint read_count = 0;
92
93         if (cond & G_IO_NVAL)
94                 return FALSE;
95
96         /* Regardless of condition, try to read all the data available */
97         do {
98                 toread = ring_buffer_avail_no_wrap(io->buf);
99
100                 if (toread == 0)
101                         break;
102
103                 rbytes = 0;
104                 buf = ring_buffer_write_ptr(io->buf, 0);
105
106                 status = g_io_channel_read_chars(channel, (char *) buf,
107                                                         toread, &rbytes, NULL);
108                 g_at_util_debug_chat(TRUE, (char *)buf, rbytes,
109                                         io->debugf, io->debug_data);
110
111                 read_count++;
112
113                 total_read += rbytes;
114
115                 if (rbytes > 0)
116                         ring_buffer_write_advance(io->buf, rbytes);
117
118         } while (status == G_IO_STATUS_NORMAL && rbytes > 0 &&
119                                         read_count < io->max_read_attempts);
120
121         if (total_read > 0 && io->read_handler)
122                 io->read_handler(io->buf, io->read_data);
123
124         if (cond & (G_IO_HUP | G_IO_ERR))
125                 return FALSE;
126
127         if (read_count > 0 && rbytes == 0 && status != G_IO_STATUS_AGAIN)
128                 return FALSE;
129
130         /* We're overflowing the buffer, shutdown the socket */
131         if (ring_buffer_avail(io->buf) == 0)
132                 return FALSE;
133
134         return TRUE;
135 }
136
137 gsize g_at_io_write(GAtIO *io, const gchar *data, gsize count)
138 {
139         GIOStatus status;
140         gsize bytes_written;
141
142         status = g_io_channel_write_chars(io->channel, data,
143                                                 count, &bytes_written, NULL);
144
145         if (status != G_IO_STATUS_NORMAL) {
146                 g_source_remove(io->read_watch);
147                 return 0;
148         }
149
150         g_at_util_debug_chat(FALSE, data, bytes_written,
151                                 io->debugf, io->debug_data);
152
153         return bytes_written;
154 }
155
156 static void write_watcher_destroy_notify(gpointer user_data)
157 {
158         GAtIO *io = user_data;
159
160         io->write_watch = 0;
161         io->write_handler = NULL;
162         io->write_data = NULL;
163
164         if (io->write_done_func) {
165                 io->write_done_func(io->write_done_data);
166                 io->write_done_func = NULL;
167                 io->write_done_data = NULL;
168         }
169 }
170
171 static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
172                                 gpointer data)
173 {
174         GAtIO *io = data;
175
176         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
177                 return FALSE;
178
179         if (io->write_handler == NULL)
180                 return FALSE;
181
182         return io->write_handler(io->write_data);
183 }
184
185 static GAtIO *create_io(GIOChannel *channel, GIOFlags flags)
186 {
187         GAtIO *io;
188
189         if (channel == NULL)
190                 return NULL;
191
192         io = g_try_new0(GAtIO, 1);
193         if (io == NULL)
194                 return io;
195
196         io->ref_count = 1;
197         io->debugf = NULL;
198
199         if (flags & G_IO_FLAG_NONBLOCK) {
200                 io->max_read_attempts = 3;
201                 io->use_write_watch = TRUE;
202         } else {
203                 io->max_read_attempts = 1;
204                 io->use_write_watch = FALSE;
205         }
206
207         io->buf = ring_buffer_new(8192);
208
209         if (!io->buf)
210                 goto error;
211
212         if (!g_at_util_setup_io(channel, flags))
213                 goto error;
214
215         io->channel = channel;
216         io->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
217                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
218                                 received_data, io,
219                                 read_watcher_destroy_notify);
220
221         return io;
222
223 error:
224         if (io->buf)
225                 ring_buffer_free(io->buf);
226
227         g_free(io);
228
229         return NULL;
230 }
231
232 GAtIO *g_at_io_new(GIOChannel *channel)
233 {
234         return create_io(channel, G_IO_FLAG_NONBLOCK);
235 }
236
237 GAtIO *g_at_io_new_blocking(GIOChannel *channel)
238 {
239         return create_io(channel, 0);
240 }
241
242 GIOChannel *g_at_io_get_channel(GAtIO *io)
243 {
244         if (io == NULL)
245                 return NULL;
246
247         return io->channel;
248 }
249
250 gboolean g_at_io_set_read_handler(GAtIO *io, GAtIOReadFunc read_handler,
251                                         gpointer user_data)
252 {
253         if (io == NULL)
254                 return FALSE;
255
256         io->read_handler = read_handler;
257         io->read_data = user_data;
258
259         if (read_handler && ring_buffer_len(io->buf) > 0)
260                 read_handler(io->buf, user_data);
261
262         return TRUE;
263 }
264
265 static gboolean call_blocking_read(gpointer user_data)
266 {
267         GAtIO *io = user_data;
268
269         while (can_write_data(io->channel, G_IO_OUT, io) == TRUE);
270         write_watcher_destroy_notify(io);
271
272         return FALSE;
273 }
274
275 gboolean g_at_io_set_write_handler(GAtIO *io, GAtIOWriteFunc write_handler,
276                                         gpointer user_data)
277 {
278         if (io == NULL)
279                 return FALSE;
280
281         if (io->write_watch > 0) {
282                 if (write_handler == NULL) {
283                         g_source_remove(io->write_watch);
284                         return TRUE;
285                 }
286
287                 return FALSE;
288         }
289
290         if (write_handler == NULL)
291                 return FALSE;
292
293         io->write_handler = write_handler;
294         io->write_data = user_data;
295
296         if (io->use_write_watch == TRUE)
297                 io->write_watch = g_io_add_watch_full(io->channel,
298                                 G_PRIORITY_HIGH,
299                                 G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
300                                 can_write_data, io,
301                                 write_watcher_destroy_notify);
302         else
303                 io->write_watch = g_idle_add(call_blocking_read, io);
304
305         return TRUE;
306 }
307
308 GAtIO *g_at_io_ref(GAtIO *io)
309 {
310         if (io == NULL)
311                 return NULL;
312
313         g_atomic_int_inc(&io->ref_count);
314
315         return io;
316 }
317
318 static gboolean io_shutdown(GAtIO *io)
319 {
320         /* Don't trigger user disconnect on shutdown */
321         io->user_disconnect = NULL;
322         io->user_disconnect_data = NULL;
323
324         if (io->read_watch > 0)
325                 g_source_remove(io->read_watch);
326
327         if (io->write_watch > 0)
328                 g_source_remove(io->write_watch);
329
330         return TRUE;
331 }
332
333 void g_at_io_unref(GAtIO *io)
334 {
335         gboolean is_zero;
336
337         if (io == NULL)
338                 return;
339
340         is_zero = g_atomic_int_dec_and_test(&io->ref_count);
341
342         if (is_zero == FALSE)
343                 return;
344
345         io_shutdown(io);
346
347         /* glib delays the destruction of the watcher until it exits, this
348          * means we can't free the data just yet, even though we've been
349          * destroyed already.  We have to wait until the read_watcher
350          * destroy function gets called
351          */
352         if (io->read_watch > 0)
353                 io->destroyed = TRUE;
354         else
355                 g_free(io);
356 }
357
358 gboolean g_at_io_set_disconnect_function(GAtIO *io,
359                         GAtDisconnectFunc disconnect, gpointer user_data)
360 {
361         if (io == NULL)
362                 return FALSE;
363
364         io->user_disconnect = disconnect;
365         io->user_disconnect_data = user_data;
366
367         return TRUE;
368 }
369
370 gboolean g_at_io_set_debug(GAtIO *io, GAtDebugFunc func, gpointer user_data)
371 {
372         if (io == NULL)
373                 return FALSE;
374
375         io->debugf = func;
376         io->debug_data = user_data;
377
378         return TRUE;
379 }
380
381 void g_at_io_set_write_done(GAtIO *io, GAtDisconnectFunc func,
382                                 gpointer user_data)
383 {
384         if (io == NULL)
385                 return;
386
387         io->write_done_func = func;
388         io->write_done_data = user_data;
389 }
390
391 void g_at_io_drain_ring_buffer(GAtIO *io, guint len)
392 {
393         ring_buffer_drain(io->buf, len);
394 }