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!
19 #include <sys/types.h>
20 #include <sys/socket.h>
26 #define SERVER_MAX_CLIENTS 8
28 #define REMOTE_SERVER_BACKLOG 4
32 #define UNIX_PATH_MAX 108
36 typedef struct _RemoteClient RemoteClient;
37 struct _RemoteClient {
44 static gboolean remote_server_client_cb(GIOChannel *source, GIOCondition condition, gpointer data)
46 RemoteClient *client = data;
51 if (condition & G_IO_IN)
59 while (g_io_channel_read_line(source, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL)
63 buffer[termpos] = '\0';
65 if (strlen(buffer) > 0)
67 queue = g_list_append(queue, buffer);
80 printf("error reading socket: %s\n", error->message);
87 gchar *command = work->data;
90 if (rc->read_func) rc->read_func(rc, command, rc->read_data);
97 if (condition & G_IO_HUP)
99 rc->clients = g_list_remove(rc->clients, client);
101 DEBUG_1("HUP detected, closing client.");
102 DEBUG_1("client count %d", g_list_length(rc->clients));
104 g_source_remove(client->channel_id);
112 static void remote_server_client_add(RemoteConnection *rc, int fd)
114 RemoteClient *client;
117 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS)
119 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS);
124 client = g_new0(RemoteClient, 1);
128 channel = g_io_channel_unix_new(fd);
129 client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
130 remote_server_client_cb, client, NULL);
131 g_io_channel_unref(channel);
133 rc->clients = g_list_append(rc->clients, client);
134 DEBUG_1("client count %d", g_list_length(rc->clients));
137 static void remote_server_clients_close(RemoteConnection *rc)
141 RemoteClient *client = rc->clients->data;
143 rc->clients = g_list_remove(rc->clients, client);
145 g_source_remove(client->channel_id);
151 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data)
153 RemoteConnection *rc = data;
157 fd = accept(rc->fd, NULL, &alen);
160 printf("error accepting socket: %s\n", strerror(errno));
164 remote_server_client_add(rc, fd);
169 static gint remote_server_exists(const gchar *path)
171 RemoteConnection *rc;
173 /* verify server up */
174 rc = remote_client_open(path);
179 /* unable to connect, remove socket file to free up address */
184 RemoteConnection *remote_server_open(const gchar *path)
186 RemoteConnection *rc;
187 struct sockaddr_un addr;
192 if (remote_server_exists(path))
194 printf("Address already in use: %s\n", path);
198 fd = socket(PF_UNIX, SOCK_STREAM, 0);
199 if (fd == -1) return NULL;
201 addr.sun_family = AF_UNIX;
202 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
203 strncpy(addr.sun_path, path, sun_path_len);
204 if (bind(fd, &addr, sizeof(addr)) == -1 ||
205 listen(fd, REMOTE_SERVER_BACKLOG) == -1)
207 printf("error subscribing to socket: %s\n", strerror(errno));
212 rc = g_new0(RemoteConnection, 1);
215 rc->path = g_strdup(path);
217 rc->read_func = NULL;
218 rc->read_data = NULL;
222 channel = g_io_channel_unix_new(rc->fd);
223 rc->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN,
224 remote_server_read_cb, rc, NULL);
225 g_io_channel_unref(channel);
230 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data)
232 if (!rc || !rc->server) return;
234 rc->read_func = func;
235 rc->read_data = data;
239 RemoteConnection *remote_client_open(const gchar *path)
241 RemoteConnection *rc;
243 struct sockaddr_un addr;
247 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL;
249 fd = socket(PF_UNIX, SOCK_STREAM, 0);
250 if (fd == -1) return NULL;
252 addr.sun_family = AF_UNIX;
253 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
254 strncpy(addr.sun_path, path, sun_path_len);
255 if (connect(fd, &addr, sizeof(addr)) == -1)
257 DEBUG_1("error connecting to socket: %s", strerror(errno));
262 rc = g_new0(RemoteConnection, 1);
265 rc->path = g_strdup(path);
267 /* this might fix the freezes on freebsd, solaris, etc. - completely untested */
268 remote_client_send(rc, "\n");
273 static sig_atomic_t sigpipe_occured = FALSE;
275 static void sighandler_sigpipe(int sig)
277 sigpipe_occured = TRUE;
280 gint remote_client_send(RemoteConnection *rc, const gchar *text)
282 struct sigaction new_action, old_action;
285 if (!rc || rc->server) return FALSE;
286 if (!text) return TRUE;
288 sigpipe_occured = FALSE;
290 new_action.sa_handler = sighandler_sigpipe;
291 sigemptyset (&new_action.sa_mask);
292 new_action.sa_flags = 0;
294 /* setup our signal handler */
295 sigaction (SIGPIPE, &new_action, &old_action);
297 if (write(rc->fd, text, strlen(text)) == -1 ||
298 write(rc->fd, "\n", 1) == -1)
302 printf("SIGPIPE writing to socket: %s\n", rc->path);
306 printf("error writing to socket: %s\n", strerror(errno));
315 /* restore the original signal handler */
316 sigaction (SIGPIPE, &old_action, NULL);
321 void remote_close(RemoteConnection *rc)
327 remote_server_clients_close(rc);
329 g_source_remove(rc->channel_id);