4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
18 #include <sys/types.h>
19 #include <sys/socket.h>
25 #define SERVER_MAX_CLIENTS 8
27 #define REMOTE_SERVER_BACKLOG 4
31 #define UNIX_PATH_MAX 108
35 typedef struct _RemoteClient RemoteClient;
36 struct _RemoteClient {
43 static gboolean remote_server_client_cb(GIOChannel *source, GIOCondition condition, gpointer data)
45 RemoteClient *client = data;
50 if (condition & G_IO_IN)
58 while (g_io_channel_read_line(source, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL)
62 buffer[termpos] = '\0';
64 if (strlen(buffer) > 0)
66 queue = g_list_append(queue, buffer);
79 printf("error reading socket: %s\n", error->message);
86 gchar *command = work->data;
89 if (rc->read_func) rc->read_func(rc, command, rc->read_data);
96 if (condition & G_IO_HUP)
98 rc->clients = g_list_remove(rc->clients, client);
102 printf("HUP detected, closing client.\n");
103 printf("client count %d\n", g_list_length(rc->clients));
106 g_source_remove(client->channel_id);
114 static void remote_server_client_add(RemoteConnection *rc, int fd)
116 RemoteClient *client;
119 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS)
121 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS);
126 client = g_new0(RemoteClient, 1);
130 channel = g_io_channel_unix_new(fd);
131 client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
132 remote_server_client_cb, client, NULL);
133 g_io_channel_unref(channel);
135 rc->clients = g_list_append(rc->clients, client);
136 if (debug) printf("client count %d\n", g_list_length(rc->clients));
139 static void remote_server_clients_close(RemoteConnection *rc)
143 RemoteClient *client = rc->clients->data;
145 rc->clients = g_list_remove(rc->clients, client);
147 g_source_remove(client->channel_id);
153 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data)
155 RemoteConnection *rc = data;
159 fd = accept(rc->fd, NULL, &alen);
162 printf("error accepting socket: %s\n", strerror(errno));
166 remote_server_client_add(rc, fd);
171 static gint remote_server_exists(const gchar *path)
173 RemoteConnection *rc;
175 /* verify server up */
176 rc = remote_client_open(path);
181 /* unable to connect, remove socket file to free up address */
186 RemoteConnection *remote_server_open(const gchar *path)
188 RemoteConnection *rc;
189 struct sockaddr_un addr;
194 if (remote_server_exists(path))
196 printf("Address already in use: %s\n", path);
200 fd = socket(PF_UNIX, SOCK_STREAM, 0);
201 if (fd == -1) return NULL;
203 addr.sun_family = AF_UNIX;
204 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
205 strncpy(addr.sun_path, path, sun_path_len);
206 if (bind(fd, &addr, sizeof(addr)) == -1 ||
207 listen(fd, REMOTE_SERVER_BACKLOG) == -1)
209 printf("error subscribing to socket: %s\n", strerror(errno));
214 rc = g_new0(RemoteConnection, 1);
217 rc->path = g_strdup(path);
219 rc->read_func = NULL;
220 rc->read_data = NULL;
224 channel = g_io_channel_unix_new(rc->fd);
225 rc->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN,
226 remote_server_read_cb, rc, NULL);
227 g_io_channel_unref(channel);
232 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data)
234 if (!rc || !rc->server) return;
236 rc->read_func = func;
237 rc->read_data = data;
241 RemoteConnection *remote_client_open(const gchar *path)
243 RemoteConnection *rc;
245 struct sockaddr_un addr;
249 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL;
251 fd = socket(PF_UNIX, SOCK_STREAM, 0);
252 if (fd == -1) return NULL;
254 addr.sun_family = AF_UNIX;
255 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
256 strncpy(addr.sun_path, path, sun_path_len);
257 if (connect(fd, &addr, sizeof(addr)) == -1)
259 if (debug) printf("error connecting to socket: %s\n", strerror(errno));
264 rc = g_new0(RemoteConnection, 1);
267 rc->path = g_strdup(path);
269 /* this might fix the freezes on freebsd, solaris, etc. - completely untested */
270 remote_client_send(rc, "\n");
275 static sig_atomic_t sigpipe_occured = FALSE;
277 static void sighandler_sigpipe(int sig)
279 sigpipe_occured = TRUE;
282 gint remote_client_send(RemoteConnection *rc, const gchar *text)
284 struct sigaction new_action, old_action;
287 if (!rc || rc->server) return FALSE;
288 if (!text) return TRUE;
290 sigpipe_occured = FALSE;
292 new_action.sa_handler = sighandler_sigpipe;
293 sigemptyset (&new_action.sa_mask);
294 new_action.sa_flags = 0;
296 /* setup our signal handler */
297 sigaction (SIGPIPE, &new_action, &old_action);
299 if (write(rc->fd, text, strlen(text)) == -1 ||
300 write(rc->fd, "\n", 1) == -1)
304 printf("SIGPIPE writing to socket: %s\n", rc->path);
308 printf("error writing to socket: %s\n", strerror(errno));
317 /* restore the original signal handler */
318 sigaction (SIGPIPE, &old_action, NULL);
323 void remote_close(RemoteConnection *rc)
329 remote_server_clients_close(rc);
331 g_source_remove(rc->channel_id);