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);
100 DEBUG_1("HUP detected, closing client.");
101 DEBUG_1("client count %d", g_list_length(rc->clients));
103 g_source_remove(client->channel_id);
111 static void remote_server_client_add(RemoteConnection *rc, int fd)
113 RemoteClient *client;
116 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS)
118 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS);
123 client = g_new0(RemoteClient, 1);
127 channel = g_io_channel_unix_new(fd);
128 client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
129 remote_server_client_cb, client, NULL);
130 g_io_channel_unref(channel);
132 rc->clients = g_list_append(rc->clients, client);
133 DEBUG_1("client count %d", g_list_length(rc->clients));
136 static void remote_server_clients_close(RemoteConnection *rc)
140 RemoteClient *client = rc->clients->data;
142 rc->clients = g_list_remove(rc->clients, client);
144 g_source_remove(client->channel_id);
150 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data)
152 RemoteConnection *rc = data;
156 fd = accept(rc->fd, NULL, &alen);
159 printf("error accepting socket: %s\n", strerror(errno));
163 remote_server_client_add(rc, fd);
168 static gint remote_server_exists(const gchar *path)
170 RemoteConnection *rc;
172 /* verify server up */
173 rc = remote_client_open(path);
178 /* unable to connect, remove socket file to free up address */
183 RemoteConnection *remote_server_open(const gchar *path)
185 RemoteConnection *rc;
186 struct sockaddr_un addr;
191 if (remote_server_exists(path))
193 printf("Address already in use: %s\n", path);
197 fd = socket(PF_UNIX, SOCK_STREAM, 0);
198 if (fd == -1) return NULL;
200 addr.sun_family = AF_UNIX;
201 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
202 strncpy(addr.sun_path, path, sun_path_len);
203 if (bind(fd, &addr, sizeof(addr)) == -1 ||
204 listen(fd, REMOTE_SERVER_BACKLOG) == -1)
206 printf("error subscribing to socket: %s\n", strerror(errno));
211 rc = g_new0(RemoteConnection, 1);
214 rc->path = g_strdup(path);
216 rc->read_func = NULL;
217 rc->read_data = NULL;
221 channel = g_io_channel_unix_new(rc->fd);
222 rc->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN,
223 remote_server_read_cb, rc, NULL);
224 g_io_channel_unref(channel);
229 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data)
231 if (!rc || !rc->server) return;
233 rc->read_func = func;
234 rc->read_data = data;
238 RemoteConnection *remote_client_open(const gchar *path)
240 RemoteConnection *rc;
242 struct sockaddr_un addr;
246 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL;
248 fd = socket(PF_UNIX, SOCK_STREAM, 0);
249 if (fd == -1) return NULL;
251 addr.sun_family = AF_UNIX;
252 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
253 strncpy(addr.sun_path, path, sun_path_len);
254 if (connect(fd, &addr, sizeof(addr)) == -1)
256 DEBUG_1("error connecting to socket: %s", strerror(errno));
261 rc = g_new0(RemoteConnection, 1);
264 rc->path = g_strdup(path);
266 /* this might fix the freezes on freebsd, solaris, etc. - completely untested */
267 remote_client_send(rc, "\n");
272 static sig_atomic_t sigpipe_occured = FALSE;
274 static void sighandler_sigpipe(int sig)
276 sigpipe_occured = TRUE;
279 gint remote_client_send(RemoteConnection *rc, const gchar *text)
281 struct sigaction new_action, old_action;
284 if (!rc || rc->server) return FALSE;
285 if (!text) return TRUE;
287 sigpipe_occured = FALSE;
289 new_action.sa_handler = sighandler_sigpipe;
290 sigemptyset (&new_action.sa_mask);
291 new_action.sa_flags = 0;
293 /* setup our signal handler */
294 sigaction (SIGPIPE, &new_action, &old_action);
296 if (write(rc->fd, text, strlen(text)) == -1 ||
297 write(rc->fd, "\n", 1) == -1)
301 printf("SIGPIPE writing to socket: %s\n", rc->path);
305 printf("error writing to socket: %s\n", strerror(errno));
314 /* restore the original signal handler */
315 sigaction (SIGPIPE, &old_action, NULL);
320 void remote_close(RemoteConnection *rc)
326 remote_server_clients_close(rc);
328 g_source_remove(rc->channel_id);