source: neercs/trunk/src/attach.c @ 3324

Last change on this file since 3324 was 3324, checked in by Pascal Terjan, 12 years ago
  • Move attaching logic to a separate function
  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1#include <errno.h>
2#include <fcntl.h>
3#include <glob.h>
4#include <limits.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8
9#include <sys/socket.h>
10#include <sys/un.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13
14#include <caca.h>
15
16#include "config.h"
17#include "neercs.h"
18
19char * build_socket_path(char *socket_dir, char *session_name, enum socket_type socktype)
20{
21    char *path, *dir;
22    path = (char *)malloc(PATH_MAX+1);
23    dir = socket_dir;
24    if(!dir)
25        dir = getenv("NEERCSDIR");
26    if(!dir)
27        dir = getenv("TMPDIR");
28    if(!dir)
29        dir = "/tmp";
30    if(path)
31        snprintf(path, PATH_MAX+1, "%s/neercs.%s%s.sock", dir, session_name, socktype?"":".srv");
32    return path;
33}
34
35int create_socket(struct screen_list* screen_list, enum socket_type socktype)
36{
37    int sock;
38    struct sockaddr_un myaddr;
39
40    sock = socket(AF_UNIX, SOCK_DGRAM, 0);
41
42    if(sock < 0)
43    {
44        perror("create_socket:socket");
45        return errno;
46    }
47
48    memset(&myaddr, 0, sizeof(struct sockaddr_un));
49
50    myaddr.sun_family = AF_UNIX;
51    strncpy(myaddr.sun_path, screen_list->socket_path[socktype], sizeof(myaddr.sun_path) - 1);
52
53    unlink(screen_list->socket_path[socktype]);
54
55    if(bind(sock, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_un)) < 0)
56    {
57        free(screen_list->socket_path[socktype]);
58        screen_list->socket_path[socktype] = NULL;
59        close(sock);
60        perror("create_socket:bind");
61        return errno;
62    }
63    fcntl(sock, F_SETFL, O_NONBLOCK);
64
65    debug("Listening on %s (%d)", screen_list->socket_path[socktype], sock);
66
67    screen_list->socket[socktype] = sock;
68
69    return 0;
70}
71
72char ** list_sockets(char *socket_dir, char *session_name)
73{
74    char *pattern, *dir;
75    glob_t globbuf;
76
77    globbuf.gl_pathv = NULL;
78
79    pattern = (char *)malloc(PATH_MAX+1);
80
81    dir = socket_dir;
82    if(!dir)
83        dir = getenv("NEERCSDIR");
84    if(!dir)
85        dir = getenv("TMPDIR");
86    if(!dir)
87        dir = "/tmp";
88
89    if(!pattern)
90        return globbuf.gl_pathv;
91
92    if(session_name && strlen(session_name)+strlen(dir)+13<PATH_MAX)
93        sprintf(pattern, "%s/neercs.%s.srv.sock", dir, session_name);
94    else
95        snprintf(pattern, PATH_MAX, "%s/neercs.*.srv.sock", dir);
96    pattern[PATH_MAX] = '\0';
97
98    debug("Looking for sockets in the form %s", pattern);
99
100    glob(pattern, 0, NULL, &globbuf);
101
102    free(pattern);
103
104    return globbuf.gl_pathv;
105}
106
107char * connect_socket(struct screen_list* screen_list, enum socket_type socktype)
108{
109    int sock;
110    struct sockaddr_un addr;
111    char *p, *s;
112
113    debug("Connecting to %s", screen_list->socket_path[socktype]);
114
115    /* Open the socket */
116    if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
117        perror("connect_server:socket");
118        return NULL;
119    }
120
121    memset(&addr,0,sizeof(addr));
122    addr.sun_family = AF_UNIX;
123    strcpy(addr.sun_path,screen_list->socket_path[socktype]);
124    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
125    {
126        fprintf(stderr, "Failed to connect to %s: %s\n", screen_list->socket_path[socktype], strerror(errno));
127        close(sock);
128        return NULL;
129    }
130    fcntl(sock, F_SETFL, O_NONBLOCK);
131
132    screen_list->socket[socktype] = sock;
133
134    if(socktype == SOCK_SERVER)
135    {
136        p = strrchr(screen_list->socket_path[socktype], '/');
137        p+=8; /* skip neercs. */
138        s = strdup(p);
139        p = strrchr(s, '.');
140        *p = '\0'; /* drop .sock */
141        p = strrchr(s, '.');
142        *p = '\0'; /* drop .srv */
143        p = strdup(s);
144        free(s);
145        return p;
146    }
147    else
148        return NULL;
149}
150
151int request_attach(struct screen_list* screen_list)
152{
153    char buf[32];
154    int bytes;
155
156    bytes = snprintf(buf, sizeof(buf)-1, "ATTACH %10d%c%10d",
157                     caca_get_canvas_width(screen_list->cv),
158                     ' ',
159                     caca_get_canvas_height(screen_list->cv));
160    buf[bytes] = '\0';
161    debug("Requesting attach: %s", buf);
162    return write(screen_list->socket[SOCK_SERVER], buf, strlen(buf)) <= 0;
163}
164
165void attach(struct screen_list* screen_list)
166{
167    char **sockets;
168    int i;
169
170    sockets = list_sockets(screen_list->socket_dir, screen_list->session_name);
171    if(sockets && sockets[0])
172    {
173        char *session;
174        for(i=0; sockets[i]; i++);
175        i--;
176        screen_list->socket_path[SOCK_SERVER] = strdup(sockets[i]);
177        session = connect_socket(screen_list, SOCK_SERVER);
178        while(!session && i > 0)
179        {
180            free(screen_list->socket_path[SOCK_SERVER]);
181            i--;
182            screen_list->socket_path[SOCK_SERVER] = strdup(sockets[i]);
183            session = connect_socket(screen_list, SOCK_SERVER);
184        }
185        debug("Connected to session %s", session);
186        if(session)
187        {
188            /* Create main canvas and associated caca window */
189            screen_list->cv = caca_create_canvas(0, 0);
190            screen_list->dp = caca_create_display(screen_list->cv);
191            if(!screen_list->dp)
192                return;
193            caca_set_cursor(screen_list->dp, 1);
194
195            screen_list->socket_path[SOCK_CLIENT] =
196                build_socket_path(screen_list->socket_dir, session, SOCK_CLIENT);
197            create_socket(screen_list, SOCK_CLIENT);
198            request_attach(screen_list);
199            if(screen_list->session_name)
200                free(screen_list->session_name);
201            screen_list->session_name = session;
202        }
203        else
204        {
205            fprintf(stderr, "Failed to attach!\n");
206            free(screen_list->socket_path[SOCK_SERVER]);
207            screen_list->socket_path[SOCK_SERVER] = NULL;
208            screen_list->attach = 0;
209        }
210        for(i=0; sockets[i]; i++)
211            free(sockets[i]);
212        free(sockets);
213    }
214    else
215    {
216        fprintf(stderr, "No socket found!\n");
217        screen_list->attach = 0;
218    }
219}
220
221int send_event(caca_event_t ev, struct screen_list* screen_list)
222{
223    enum caca_event_type t;
224
225    t = caca_get_event_type(&ev);
226
227    if(t & CACA_EVENT_KEY_PRESS)
228    {
229        char buf[16];
230        int bytes;
231        bytes = snprintf(buf, sizeof(buf)-1, "KEY %d", caca_get_event_key_ch(&ev));
232        buf[bytes] = '\0';
233        debug("Sending key press to server: %s", buf);
234        return write(screen_list->socket[SOCK_SERVER], buf, strlen(buf)) <= 0;
235    }
236    else if(t & CACA_EVENT_RESIZE)
237    {
238        char buf[32];
239        int bytes;
240        bytes = snprintf(buf, sizeof(buf)-1, "RESIZE %10d%c%10d",
241                         caca_get_event_resize_width(&ev),
242                         ' ',
243                         caca_get_event_resize_height(&ev));
244        buf[bytes] = '\0';
245        debug("Sending resize to server: %s", buf);
246        return write(screen_list->socket[SOCK_SERVER], buf, strlen(buf)) <= 0;
247    }
248    else if(t & CACA_EVENT_QUIT)
249        return write(screen_list->socket[SOCK_SERVER], "QUIT", strlen("QUIT")) <= 0;
250
251    return 0;
252}
253
Note: See TracBrowser for help on using the repository browser.