Mercurial > geeqie
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 |