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.\nclient count %d\n", g_list_length(rc->clients));
102 g_source_remove(client->channel_id);
110 static void remote_server_client_add(RemoteConnection *rc, int fd)
112 RemoteClient *client;
115 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS)
117 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS);
122 client = g_new0(RemoteClient, 1);
126 channel = g_io_channel_unix_new(fd);
127 client->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP,
128 remote_server_client_cb, client, NULL);
129 g_io_channel_unref(channel);
131 rc->clients = g_list_append(rc->clients, client);
132 DEBUG_1("client count %d\n", g_list_length(rc->clients));
135 static void remote_server_clients_close(RemoteConnection *rc)
139 RemoteClient *client = rc->clients->data;
141 rc->clients = g_list_remove(rc->clients, client);
143 g_source_remove(client->channel_id);
149 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data)
151 RemoteConnection *rc = data;
155 fd = accept(rc->fd, NULL, &alen);
158 printf("error accepting socket: %s\n", strerror(errno));
162 remote_server_client_add(rc, fd);
167 static gint remote_server_exists(const gchar *path)
169 RemoteConnection *rc;
171 /* verify server up */
172 rc = remote_client_open(path);
177 /* unable to connect, remove socket file to free up address */
182 RemoteConnection *remote_server_open(const gchar *path)
184 RemoteConnection *rc;
185 struct sockaddr_un addr;
190 if (remote_server_exists(path))
192 printf("Address already in use: %s\n", path);
196 fd = socket(PF_UNIX, SOCK_STREAM, 0);
197 if (fd == -1) return NULL;
199 addr.sun_family = AF_UNIX;
200 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
201 strncpy(addr.sun_path, path, sun_path_len);
202 if (bind(fd, &addr, sizeof(addr)) == -1 ||
203 listen(fd, REMOTE_SERVER_BACKLOG) == -1)
205 printf("error subscribing to socket: %s\n", strerror(errno));
210 rc = g_new0(RemoteConnection, 1);
213 rc->path = g_strdup(path);
215 rc->read_func = NULL;
216 rc->read_data = NULL;
220 channel = g_io_channel_unix_new(rc->fd);
221 rc->channel_id = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, G_IO_IN,
222 remote_server_read_cb, rc, NULL);
223 g_io_channel_unref(channel);
228 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data)
230 if (!rc || !rc->server) return;
232 rc->read_func = func;
233 rc->read_data = data;
237 RemoteConnection *remote_client_open(const gchar *path)
239 RemoteConnection *rc;
241 struct sockaddr_un addr;
245 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL;
247 fd = socket(PF_UNIX, SOCK_STREAM, 0);
248 if (fd == -1) return NULL;
250 addr.sun_family = AF_UNIX;
251 sun_path_len = MIN(strlen(path) + 1, UNIX_PATH_MAX);
252 strncpy(addr.sun_path, path, sun_path_len);
253 if (connect(fd, &addr, sizeof(addr)) == -1)
255 DEBUG_1("error connecting to socket: %s\n", strerror(errno));
260 rc = g_new0(RemoteConnection, 1);
263 rc->path = g_strdup(path);
265 /* this might fix the freezes on freebsd, solaris, etc. - completely untested */
266 remote_client_send(rc, "\n");
271 static sig_atomic_t sigpipe_occured = FALSE;
273 static void sighandler_sigpipe(int sig)
275 sigpipe_occured = TRUE;
278 gint remote_client_send(RemoteConnection *rc, const gchar *text)
280 struct sigaction new_action, old_action;
283 if (!rc || rc->server) return FALSE;
284 if (!text) return TRUE;
286 sigpipe_occured = FALSE;
288 new_action.sa_handler = sighandler_sigpipe;
289 sigemptyset (&new_action.sa_mask);
290 new_action.sa_flags = 0;
292 /* setup our signal handler */
293 sigaction (SIGPIPE, &new_action, &old_action);
295 if (write(rc->fd, text, strlen(text)) == -1 ||
296 write(rc->fd, "\n", 1) == -1)
300 printf("SIGPIPE writing to socket: %s\n", rc->path);
304 printf("error writing to socket: %s\n", strerror(errno));
313 /* restore the original signal handler */
314 sigaction (SIGPIPE, &old_action, NULL);
319 void remote_close(RemoteConnection *rc)
325 remote_server_clients_close(rc);
327 g_source_remove(rc->channel_id);