Mercurial > geeqie.yaz
annotate src/remote.c @ 196:f6e307c7bad6
rename GQview -> Geeqie over the code
author | nadvornik |
---|---|
date | Sun, 23 Mar 2008 20:38:54 +0000 |
parents | 04ff0df3ad2f |
children | 9995c5fb202a |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
9 | 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; | |
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
55 guint termpos; |
9 | 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; | |
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
156 unsigned int alen; |
9 | 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 |