comparison src/remote.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children 04ff0df3ad2f
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * GQview
3 * (C) 2004 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12
13 #include "gqview.h"
14 #include "remote.h"
15
16
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
20 #include <signal.h>
21 #include <errno.h>
22
23
24 #define SERVER_MAX_CLIENTS 8
25
26 #define REMOTE_SERVER_BACKLOG 4
27
28
29 #ifndef UNIX_PATH_MAX
30 #define UNIX_PATH_MAX 108
31 #endif
32
33
34 typedef struct _RemoteClient RemoteClient;
35 struct _RemoteClient {
36 gint fd;
37 gint channel_id;
38 RemoteConnection *rc;
39 };
40
41
42 static gboolean remote_server_client_cb(GIOChannel *source, GIOCondition condition, gpointer data)
43 {
44 RemoteClient *client = data;
45 RemoteConnection *rc;
46
47 rc = client->rc;
48
49 if (condition & G_IO_IN)
50 {
51 GList *queue = NULL;
52 GList *work;
53 gchar *buffer = NULL;
54 GError *error = NULL;
55 gint termpos;
56
57 while (g_io_channel_read_line(source, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL)
58 {
59 if (buffer)
60 {
61 buffer[termpos] = '\0';
62
63 if (strlen(buffer) > 0)
64 {
65 queue = g_list_append(queue, buffer);
66 }
67 else
68 {
69 g_free(buffer);
70 }
71
72 buffer = NULL;
73 }
74 }
75
76 if (error)
77 {
78 printf("error reading socket: %s\n", error->message);
79 g_error_free(error);
80 }
81
82 work = queue;
83 while (work)
84 {
85 gchar *command = work->data;
86 work = work->next;
87
88 if (rc->read_func) rc->read_func(rc, command, rc->read_data);
89 g_free(command);
90 }
91
92 g_list_free(queue);
93 }
94
95 if (condition & G_IO_HUP)
96 {
97 rc->clients = g_list_remove(rc->clients, client);
98
99 if (debug)
100 {
101 printf("HUP detected, closing client.\n");
102 printf("client count %d\n", g_list_length(rc->clients));
103 }
104
105 g_source_remove(client->channel_id);
106 close(client->fd);
107 g_free(client);
108 }
109
110 return TRUE;
111 }
112
113 static void remote_server_client_add(RemoteConnection *rc, int fd)
114 {
115 RemoteClient *client;
116 GIOChannel *channel;
117
118 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS)
119 {
120 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS);
121 close(fd);
122 return;
123 }
124
125 client = g_new0(RemoteClient, 1);
126 client->rc = rc;
127 client->fd = fd;
128
129 channel = g_io_channel_unix_new(fd);
130 client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
131 remote_server_client_cb, client, NULL);
132 g_io_channel_unref(channel);
133
134 rc->clients = g_list_append(rc->clients, client);
135 if (debug) printf("client count %d\n", g_list_length(rc->clients));
136 }
137
138 static void remote_server_clients_close(RemoteConnection *rc)
139 {
140 while (rc->clients)
141 {
142 RemoteClient *client = rc->clients->data;
143
144 rc->clients = g_list_remove(rc->clients, client);
145
146 g_source_remove(client->channel_id);
147 close(client->fd);
148 g_free(client);
149 }
150 }
151
152 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data)
153 {
154 RemoteConnection *rc = data;
155 int fd;
156 int alen;
157
158 fd = accept(rc->fd, NULL, &alen);
159 if (fd == -1)
160 {
161 printf("error accepting socket: %s\n", strerror(errno));
162 return TRUE;
163 }
164
165 remote_server_client_add(rc, fd);
166
167 return TRUE;
168 }
169
170 static gint remote_server_exists(const gchar *path)
171 {
172 RemoteConnection *rc;
173
174 /* verify server up */
175 rc = remote_client_open(path);
176 remote_close(rc);
177
178 if (rc) return TRUE;
179
180 /* unable to connect, remove socket file to free up address */
181 unlink(path);
182 return FALSE;
183 }
184
185 RemoteConnection *remote_server_open(const gchar *path)
186 {
187 RemoteConnection *rc;
188 struct sockaddr_un addr;
189 gint sun_path_len;
190 int fd;
191 GIOChannel *channel;
192
193 if (remote_server_exists(path))
194 {
195 printf("Address already in use: %s\n", path);
196 return NULL;
197 }
198
199 fd = socket(PF_UNIX, SOCK_STREAM, 0);
200 if (fd == -1) return NULL;
201
202 addr.sun_family = AF_UNIX;
203 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
204 strncpy(addr.sun_path, path, sun_path_len);
205 if (bind(fd, &addr, sizeof(addr)) == -1 ||
206 listen(fd, REMOTE_SERVER_BACKLOG) == -1)
207 {
208 printf("error subscribing to socket: %s\n", strerror(errno));
209 close(fd);
210 return NULL;
211 }
212
213 rc = g_new0(RemoteConnection, 1);
214 rc->server = TRUE;
215 rc->fd = fd;
216 rc->path = g_strdup(path);
217
218 rc->read_func = NULL;
219 rc->read_data = NULL;
220
221 rc->clients = NULL;
222
223 channel = g_io_channel_unix_new(rc->fd);
224 rc->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN,
225 remote_server_read_cb, rc, NULL);
226 g_io_channel_unref(channel);
227
228 return rc;
229 }
230
231 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data)
232 {
233 if (!rc || !rc->server) return;
234
235 rc->read_func = func;
236 rc->read_data = data;
237 }
238
239
240 RemoteConnection *remote_client_open(const gchar *path)
241 {
242 RemoteConnection *rc;
243 struct stat st;
244 struct sockaddr_un addr;
245 gint sun_path_len;
246 int fd;
247
248 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL;
249
250 fd = socket(PF_UNIX, SOCK_STREAM, 0);
251 if (fd == -1) return NULL;
252
253 addr.sun_family = AF_UNIX;
254 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
255 strncpy(addr.sun_path, path, sun_path_len);
256 if (connect(fd, &addr, sizeof(addr)) == -1)
257 {
258 if (debug) printf("error connecting to socket: %s\n", strerror(errno));
259 close(fd);
260 return NULL;
261 }
262
263 rc = g_new0(RemoteConnection, 1);
264 rc->server = FALSE;
265 rc->fd = fd;
266 rc->path = g_strdup(path);
267
268 return rc;
269 }
270
271 static sig_atomic_t sigpipe_occured = FALSE;
272
273 static void sighandler_sigpipe(int sig)
274 {
275 sigpipe_occured = TRUE;
276 }
277
278 gint remote_client_send(RemoteConnection *rc, const gchar *text)
279 {
280 struct sigaction new_action, old_action;
281 gint ret = FALSE;
282
283 if (!rc || rc->server) return FALSE;
284 if (!text) return TRUE;
285
286 sigpipe_occured = FALSE;
287
288 new_action.sa_handler = sighandler_sigpipe;
289 sigemptyset (&new_action.sa_mask);
290 new_action.sa_flags = 0;
291
292 /* setup our signal handler */
293 sigaction (SIGPIPE, &new_action, &old_action);
294
295 if (write(rc->fd, text, strlen(text)) == -1 ||
296 write(rc->fd, "\n", 1) == -1)
297 {
298 if (sigpipe_occured)
299 {
300 printf("SIGPIPE writing to socket: %s\n", rc->path);
301 }
302 else
303 {
304 printf("error writing to socket: %s\n", strerror(errno));
305 }
306 ret = FALSE;;
307 }
308 else
309 {
310 ret = TRUE;
311 }
312
313 /* restore the original signal handler */
314 sigaction (SIGPIPE, &old_action, NULL);
315
316 return ret;
317 }
318
319 void remote_close(RemoteConnection *rc)
320 {
321 if (!rc) return;
322
323 if (rc->server)
324 {
325 remote_server_clients_close(rc);
326
327 g_source_remove(rc->channel_id);
328 unlink(rc->path);
329 }
330
331 close(rc->fd);
332
333 g_free(rc->path);
334 g_free(rc);
335 }
336
337