Mercurial > geeqie
annotate src/remote.c @ 135:15c1925b3bfb
improved external delete command
| author | nadvornik |
|---|---|
| date | Thu, 16 Aug 2007 20:57:09 +0000 |
| parents | 04ff0df3ad2f |
| children | f6e307c7bad6 |
| rev | line source |
|---|---|
| 9 | 1 /* |
| 2 * GQview | |
| 3 * (C) 2004 John Ellis | |
| 4 * | |
| 5 * Author: John Ellis | |
| 6 * | |
| 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! | |
| 10 */ | |
| 11 | |
| 12 | |
| 13 #include "gqview.h" | |
| 14 #include "remote.h" | |
| 15 | |
| 16 | |
| 17 #include <sys/types.h> | |
| 18 #include <sys/socket.h> | |
| 19 #include <sys/un.h> | |
| 20 #include <signal.h> | |
| 21 #include <errno.h> | |
| 22 | |
| 23 | |
| 24 #define SERVER_MAX_CLIENTS 8 | |
| 25 | |
| 26 #define REMOTE_SERVER_BACKLOG 4 | |
| 27 | |
| 28 | |
| 29 #ifndef UNIX_PATH_MAX | |
| 30 #define UNIX_PATH_MAX 108 | |
| 31 #endif | |
| 32 | |
| 33 | |
| 34 typedef struct _RemoteClient RemoteClient; | |
| 35 struct _RemoteClient { | |
| 36 gint fd; | |
| 37 gint channel_id; | |
| 38 RemoteConnection *rc; | |
| 39 }; | |
| 40 | |
| 41 | |
| 42 static gboolean remote_server_client_cb(GIOChannel *source, GIOCondition condition, gpointer data) | |
| 43 { | |
| 44 RemoteClient *client = data; | |
| 45 RemoteConnection *rc; | |
| 46 | |
| 47 rc = client->rc; | |
| 48 | |
| 49 if (condition & G_IO_IN) | |
| 50 { | |
| 51 GList *queue = NULL; | |
| 52 GList *work; | |
| 53 gchar *buffer = NULL; | |
| 54 GError *error = NULL; | |
|
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
55 guint termpos; |
| 9 | 56 |
| 57 while (g_io_channel_read_line(source, &buffer, NULL, &termpos, &error) == G_IO_STATUS_NORMAL) | |
| 58 { | |
| 59 if (buffer) | |
| 60 { | |
| 61 buffer[termpos] = '\0'; | |
| 62 | |
| 63 if (strlen(buffer) > 0) | |
| 64 { | |
| 65 queue = g_list_append(queue, buffer); | |
| 66 } | |
| 67 else | |
| 68 { | |
| 69 g_free(buffer); | |
| 70 } | |
| 71 | |
| 72 buffer = NULL; | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 if (error) | |
| 77 { | |
| 78 printf("error reading socket: %s\n", error->message); | |
| 79 g_error_free(error); | |
| 80 } | |
| 81 | |
| 82 work = queue; | |
| 83 while (work) | |
| 84 { | |
| 85 gchar *command = work->data; | |
| 86 work = work->next; | |
| 87 | |
| 88 if (rc->read_func) rc->read_func(rc, command, rc->read_data); | |
| 89 g_free(command); | |
| 90 } | |
| 91 | |
| 92 g_list_free(queue); | |
| 93 } | |
| 94 | |
| 95 if (condition & G_IO_HUP) | |
| 96 { | |
| 97 rc->clients = g_list_remove(rc->clients, client); | |
| 98 | |
| 99 if (debug) | |
| 100 { | |
| 101 printf("HUP detected, closing client.\n"); | |
| 102 printf("client count %d\n", g_list_length(rc->clients)); | |
| 103 } | |
| 104 | |
| 105 g_source_remove(client->channel_id); | |
| 106 close(client->fd); | |
| 107 g_free(client); | |
| 108 } | |
| 109 | |
| 110 return TRUE; | |
| 111 } | |
| 112 | |
| 113 static void remote_server_client_add(RemoteConnection *rc, int fd) | |
| 114 { | |
| 115 RemoteClient *client; | |
| 116 GIOChannel *channel; | |
| 117 | |
| 118 if (g_list_length(rc->clients) > SERVER_MAX_CLIENTS) | |
| 119 { | |
| 120 printf("maximum remote clients of %d exceeded, closing connection\n", SERVER_MAX_CLIENTS); | |
| 121 close(fd); | |
| 122 return; | |
| 123 } | |
| 124 | |
| 125 client = g_new0(RemoteClient, 1); | |
| 126 client->rc = rc; | |
| 127 client->fd = fd; | |
| 128 | |
| 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); | |
| 133 | |
| 134 rc->clients = g_list_append(rc->clients, client); | |
| 135 if (debug) printf("client count %d\n", g_list_length(rc->clients)); | |
| 136 } | |
| 137 | |
| 138 static void remote_server_clients_close(RemoteConnection *rc) | |
| 139 { | |
| 140 while (rc->clients) | |
| 141 { | |
| 142 RemoteClient *client = rc->clients->data; | |
| 143 | |
| 144 rc->clients = g_list_remove(rc->clients, client); | |
| 145 | |
| 146 g_source_remove(client->channel_id); | |
| 147 close(client->fd); | |
| 148 g_free(client); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 static gboolean remote_server_read_cb(GIOChannel *source, GIOCondition condition, gpointer data) | |
| 153 { | |
| 154 RemoteConnection *rc = data; | |
| 155 int fd; | |
|
64
04ff0df3ad2f
Mon Aug 15 17:13:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
156 unsigned int alen; |
| 9 | 157 |
| 158 fd = accept(rc->fd, NULL, &alen); | |
| 159 if (fd == -1) | |
| 160 { | |
| 161 printf("error accepting socket: %s\n", strerror(errno)); | |
| 162 return TRUE; | |
| 163 } | |
| 164 | |
| 165 remote_server_client_add(rc, fd); | |
| 166 | |
| 167 return TRUE; | |
| 168 } | |
| 169 | |
| 170 static gint remote_server_exists(const gchar *path) | |
| 171 { | |
| 172 RemoteConnection *rc; | |
| 173 | |
| 174 /* verify server up */ | |
| 175 rc = remote_client_open(path); | |
| 176 remote_close(rc); | |
| 177 | |
| 178 if (rc) return TRUE; | |
| 179 | |
| 180 /* unable to connect, remove socket file to free up address */ | |
| 181 unlink(path); | |
| 182 return FALSE; | |
| 183 } | |
| 184 | |
| 185 RemoteConnection *remote_server_open(const gchar *path) | |
| 186 { | |
| 187 RemoteConnection *rc; | |
| 188 struct sockaddr_un addr; | |
| 189 gint sun_path_len; | |
| 190 int fd; | |
| 191 GIOChannel *channel; | |
| 192 | |
| 193 if (remote_server_exists(path)) | |
| 194 { | |
| 195 printf("Address already in use: %s\n", path); | |
| 196 return NULL; | |
| 197 } | |
| 198 | |
| 199 fd = socket(PF_UNIX, SOCK_STREAM, 0); | |
| 200 if (fd == -1) return NULL; | |
| 201 | |
| 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) | |
| 207 { | |
| 208 printf("error subscribing to socket: %s\n", strerror(errno)); | |
| 209 close(fd); | |
| 210 return NULL; | |
| 211 } | |
| 212 | |
| 213 rc = g_new0(RemoteConnection, 1); | |
| 214 rc->server = TRUE; | |
| 215 rc->fd = fd; | |
| 216 rc->path = g_strdup(path); | |
| 217 | |
| 218 rc->read_func = NULL; | |
| 219 rc->read_data = NULL; | |
| 220 | |
| 221 rc->clients = NULL; | |
| 222 | |
| 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); | |
| 227 | |
| 228 return rc; | |
| 229 } | |
| 230 | |
| 231 void remote_server_subscribe(RemoteConnection *rc, RemoteReadFunc *func, gpointer data) | |
| 232 { | |
| 233 if (!rc || !rc->server) return; | |
| 234 | |
| 235 rc->read_func = func; | |
| 236 rc->read_data = data; | |
| 237 } | |
| 238 | |
| 239 | |
| 240 RemoteConnection *remote_client_open(const gchar *path) | |
| 241 { | |
| 242 RemoteConnection *rc; | |
| 243 struct stat st; | |
| 244 struct sockaddr_un addr; | |
| 245 gint sun_path_len; | |
| 246 int fd; | |
| 247 | |
| 248 if (stat(path, &st) != 0 || !S_ISSOCK(st.st_mode)) return NULL; | |
| 249 | |
| 250 fd = socket(PF_UNIX, SOCK_STREAM, 0); | |
| 251 if (fd == -1) return NULL; | |
| 252 | |
| 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) | |
| 257 { | |
| 258 if (debug) printf("error connecting to socket: %s\n", strerror(errno)); | |
| 259 close(fd); | |
| 260 return NULL; | |
| 261 } | |
| 262 | |
| 263 rc = g_new0(RemoteConnection, 1); | |
| 264 rc->server = FALSE; | |
| 265 rc->fd = fd; | |
| 266 rc->path = g_strdup(path); | |
| 267 | |
| 268 return rc; | |
| 269 } | |
| 270 | |
| 271 static sig_atomic_t sigpipe_occured = FALSE; | |
| 272 | |
| 273 static void sighandler_sigpipe(int sig) | |
| 274 { | |
| 275 sigpipe_occured = TRUE; | |
| 276 } | |
| 277 | |
| 278 gint remote_client_send(RemoteConnection *rc, const gchar *text) | |
| 279 { | |
| 280 struct sigaction new_action, old_action; | |
| 281 gint ret = FALSE; | |
| 282 | |
| 283 if (!rc || rc->server) return FALSE; | |
| 284 if (!text) return TRUE; | |
| 285 | |
| 286 sigpipe_occured = FALSE; | |
| 287 | |
| 288 new_action.sa_handler = sighandler_sigpipe; | |
| 289 sigemptyset (&new_action.sa_mask); | |
| 290 new_action.sa_flags = 0; | |
| 291 | |
| 292 /* setup our signal handler */ | |
| 293 sigaction (SIGPIPE, &new_action, &old_action); | |
| 294 | |
| 295 if (write(rc->fd, text, strlen(text)) == -1 || | |
| 296 write(rc->fd, "\n", 1) == -1) | |
| 297 { | |
| 298 if (sigpipe_occured) | |
| 299 { | |
| 300 printf("SIGPIPE writing to socket: %s\n", rc->path); | |
| 301 } | |
| 302 else | |
| 303 { | |
| 304 printf("error writing to socket: %s\n", strerror(errno)); | |
| 305 } | |
| 306 ret = FALSE;; | |
| 307 } | |
| 308 else | |
| 309 { | |
| 310 ret = TRUE; | |
| 311 } | |
| 312 | |
| 313 /* restore the original signal handler */ | |
| 314 sigaction (SIGPIPE, &old_action, NULL); | |
| 315 | |
| 316 return ret; | |
| 317 } | |
| 318 | |
| 319 void remote_close(RemoteConnection *rc) | |
| 320 { | |
| 321 if (!rc) return; | |
| 322 | |
| 323 if (rc->server) | |
| 324 { | |
| 325 remote_server_clients_close(rc); | |
| 326 | |
| 327 g_source_remove(rc->channel_id); | |
| 328 unlink(rc->path); | |
| 329 } | |
| 330 | |
| 331 close(rc->fd); | |
| 332 | |
| 333 g_free(rc->path); | |
| 334 g_free(rc); | |
| 335 } | |
| 336 | |
| 337 |
