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!
17 #include <sys/types.h>
18 #include <sys/socket.h>
24 #define SERVER_MAX_CLIENTS 8
26 #define REMOTE_SERVER_BACKLOG 4
30 #define UNIX_PATH_MAX 108
34 typedef struct _RemoteClient RemoteClient;
35 struct _RemoteClient {
42 static gboolean remote_server_client_cb(GIOChannel *source, GIOCondition condition, gpointer data)
44 RemoteClient *client = data;
49 if (condition & G_IO_IN)
57 while (g_io_channel_read_line(source, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL)
61 buffer[termpos] = '\0';
63 if (strlen(buffer) > 0)
65 queue = g_list_append(queue, buffer);
78 printf("error reading socket: %s\n", error->message);
85 gchar *command = work->data;
88 if (rc->read_func) rc->read_func(rc, command, rc->read_data);
95 if (condition & G_IO_HUP)
97 rc->clients = g_list_remove(rc->clients, client);
101 printf("HUP detected, closing client.\n");
102 printf("client count %d\n", g_list_length(rc->clients));
105 g_source_remove(client->channel_id);
113 static void remote_server_client_add(RemoteConnection *rc, int fd)
115 RemoteClient *client;
118 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS)
120 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS);
125 client = g_new0(RemoteClient, 1);
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);
134 rc->clients = g_list_append(rc->clients, client);
135 if (debug) printf("client count %d\n", g_list_length(rc->clients));
138 static void remote_server_clients_close(RemoteConnection *rc)
142 RemoteClient *client = rc->clients->data;
144 rc->clients = g_list_remove(rc->clients, client);
146 g_source_remove(client->channel_id);
152 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data)
154 RemoteConnection *rc = data;
158 fd = accept(rc->fd, NULL, &alen);
161 printf("error accepting socket: %s\n", strerror(errno));
165 remote_server_client_add(rc, fd);
170 static gint remote_server_exists(const gchar *path)
172 RemoteConnection *rc;
174 /* verify server up */
175 rc = remote_client_open(path);
180 /* unable to connect, remove socket file to free up address */
185 RemoteConnection *remote_server_open(const gchar *path)
187 RemoteConnection *rc;
188 struct sockaddr_un addr;
193 if (remote_server_exists(path))
195 printf("Address already in use: %s\n", path);
199 fd = socket(PF_UNIX, SOCK_STREAM, 0);
200 if (fd == -1) return NULL;
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)
208 printf("error subscribing to socket: %s\n", strerror(errno));
213 rc = g_new0(RemoteConnection, 1);
216 rc->path = g_strdup(path);
218 rc->read_func = NULL;
219 rc->read_data = NULL;
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);
231 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data)
233 if (!rc || !rc->server) return;
235 rc->read_func = func;
236 rc->read_data = data;
240 RemoteConnection *remote_client_open(const gchar *path)
242 RemoteConnection *rc;
244 struct sockaddr_un addr;
248 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL;
250 fd = socket(PF_UNIX, SOCK_STREAM, 0);
251 if (fd == -1) return NULL;
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)
258 if (debug) printf("error connecting to socket: %s\n", strerror(errno));
263 rc = g_new0(RemoteConnection, 1);
266 rc->path = g_strdup(path);
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);