source: trunk/tools/neercs/old/mini-socket.c @ 1642

Last change on this file since 1642 was 1642, checked in by sam, 7 years ago

neercs: import files from the (unfinished) old neercs code.

  • Property svn:keywords set to Id
File size: 7.4 KB
Line 
1/*
2 *  neercs        console-based window manager
3 *  Copyright (c) 2006-2011 Sam Hocevar <sam@hocevar.net>
4 *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
5 *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
6 *                All Rights Reserved
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15#if defined HAVE_CONFIG_H
16#   include "config.h"
17#endif
18
19#include <stdio.h> /* perror() */
20#include <stdlib.h> /* malloc(), free() */
21#include <unistd.h> /* unlink() */
22#include <fcntl.h> /* fcntl() */
23#include <string.h> /* memcpy() */
24#include <sys/select.h> /* select() */
25#include <sys/types.h> /* bind(), connect() */
26#include <sys/socket.h> /* bind(), connect() */
27#include <sys/stat.h>  /* stat(), struct stat */
28#include <sys/un.h> /* AF_UNIX */
29#include <errno.h> /* AF_UNIX */
30#include <time.h> /* time */
31
32#include "mini-neercs.h"
33#include "mini-socket.h"
34
35#define SIZEOF_SUN_PATH (sizeof(((struct sockaddr_un *)NULL)->sun_path))
36
37#define offsetof(s, f) ((int)(intptr_t)((s *)NULL)->f)
38
39struct nrx_socket
40{
41#if 1
42    /* Linux sockets */
43    int fd;
44    int server;
45    int connected;
46    char path[SIZEOF_SUN_PATH];
47#else
48#   error No socket implementation
49#endif
50};
51
52#define QLEN 10
53
54int
55serv_listen(const char *name)
56{
57    int                 fd, len, err, rval;
58    struct sockaddr_un  un;
59
60    /* create a UNIX domain stream socket */
61    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
62       return(-1);
63    unlink(name);   /* in case it already exists */
64
65    /* fill in socket address structure */
66    memset(&un, 0, sizeof(un));
67    un.sun_family = AF_UNIX;
68    strcpy(un.sun_path, name);
69    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
70
71    /* bind the name to the descriptor */
72    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
73        rval = -2;
74        goto errout;
75    }
76    if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */
77        rval = -3;
78        goto errout;
79    }
80    return(fd);
81
82errout:
83    err = errno;
84    close(fd);
85    errno = err;
86    return(rval);
87}
88
89#define STALE   30  /* client's name can't be older than this (sec) */
90
91/*
92 * Wait for a client connection to arrive, and accept it.
93 * We also obtain the client's user ID from the pathname
94 * that it must bind before calling us.
95 * Returns new fd if all OK, <0 on error
96 */
97int
98serv_accept(int listenfd, uid_t *uidptr)
99{
100    int                 clifd, len, err, rval;
101    time_t              staletime;
102    struct sockaddr_un  un;
103    struct stat         statbuf;
104
105    len = sizeof(un);
106    if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
107        return(-1);     /* often errno=EINTR, if signal caught */
108
109    /* obtain the client's uid from its calling address */
110    len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
111    un.sun_path[len] = 0;           /* null terminate */
112
113    if (stat(un.sun_path, &statbuf) < 0) {
114        rval = -2;
115        goto errout;
116    }
117#ifdef S_ISSOCK     /* not defined for SVR4 */
118    if (S_ISSOCK(statbuf.st_mode) == 0) {
119        rval = -3;      /* not a socket */
120        goto errout;
121    }
122#endif
123    if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
124        (statbuf.st_mode & S_IRWXU) != S_IRWXU) {
125          rval = -4;     /* is not rwx------ */
126          goto errout;
127    }
128
129    staletime = time(NULL) - STALE;
130    if (statbuf.st_atime < staletime ||
131        statbuf.st_ctime < staletime ||
132        statbuf.st_mtime < staletime) {
133          rval = -5;    /* i-node is too old */
134          goto errout;
135    }
136    if (uidptr != NULL)
137        *uidptr = statbuf.st_uid;   /* return uid of caller */
138    unlink(un.sun_path);        /* we're done with pathname now */
139    return(clifd);
140
141errout:
142    err = errno;
143    close(clifd);
144    errno = err;
145    return(rval);
146}
147
148#define CLI_PATH    "/var/tmp/"      /* +5 for pid = 14 chars */
149#define CLI_PERM    S_IRWXU          /* rwx for user only */
150
151/*
152 * Create a client endpoint and connect to a server.
153 * Returns fd if all OK, <0 on error.
154 */
155int
156cli_conn(const char *name)
157{
158    int                fd, len, err, rval;
159    struct sockaddr_un un;
160
161    /* create a UNIX domain stream socket */
162    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
163        return(-1);
164
165    /* fill socket address structure with our address */
166    memset(&un, 0, sizeof(un));
167    un.sun_family = AF_UNIX;
168    sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
169    len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
170
171    unlink(un.sun_path);        /* in case it already exists */
172    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
173        rval = -2;
174        goto errout;
175    }
176    if (chmod(un.sun_path, CLI_PERM) < 0) {
177        rval = -3;
178        goto errout;
179    }
180    /* fill socket address structure with server's address */
181    memset(&un, 0, sizeof(un));
182    un.sun_family = AF_UNIX;
183    strcpy(un.sun_path, name);
184    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
185    if (connect(fd, (struct sockaddr *)&un, len) < 0) {
186        rval = -4;
187        goto errout;
188    }
189    return(fd);
190
191errout:
192    err = errno;
193    close(fd);
194    errno = err;
195    return(rval);
196}
197
198nrx_socket_t * socket_open(char const *path, int server)
199{
200    nrx_socket_t * sock;
201    struct sockaddr_un addr;
202    int ret, fd;
203
204#if 0
205    fd = socket(AF_UNIX, SOCK_STREAM, 0);
206    //fd = socket(AF_UNIX, SOCK_DGRAM, 0);
207    if (fd < 0)
208    {
209        perror("socket creation");
210        return NULL;
211    }
212
213    memset(&addr, 0, sizeof(struct sockaddr_un));
214    addr.sun_family = AF_UNIX;
215    strncpy(addr.sun_path, path, SIZEOF_SUN_PATH - 1);
216
217    if (server)
218    {
219        unlink(path);
220        ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
221    }
222    else
223    {
224        ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
225    }
226
227    if (ret < 0)
228    {
229        perror(server ? "socket binding" : "socket connection");
230        close(fd);
231        return NULL;
232    }
233
234    fcntl(fd, F_SETFL, O_NONBLOCK);
235#endif
236if (server)
237    fd = serv_listen(path);
238else
239    fd = cli_conn(path);
240if (fd < 0) return NULL;
241
242    sock = malloc(sizeof(*sock));
243    sock->fd = fd;
244    sock->server = server;
245    sock->connected = 0;
246    strncpy(sock->path, path, SIZEOF_SUN_PATH - 1);
247
248    return sock;
249}
250
251int socket_select(nrx_socket_t *sock, int usecs)
252{
253    fd_set rfds;
254    struct timeval tv;
255    int ret;
256
257    FD_ZERO(&rfds);
258    FD_SET(sock->fd, &rfds);
259
260    tv.tv_sec = usecs / 1000000;
261    tv.tv_usec = usecs % 1000000;
262
263    ret = select(sock->fd + 1, &rfds, NULL, NULL, &tv);
264    if (ret < 0)
265        return -1;
266
267    if (FD_ISSET(sock->fd, &rfds))
268        return 1;
269
270    return 0;
271}
272
273int socket_puts(nrx_socket_t *sock, char const *str)
274{
275    int ret;
276fprintf(stderr, "pid %i sending %i bytes on %s: %s\n", getpid(), (int)strlen(str), sock->path, str);
277    ret = write(sock->fd, str, strlen(str));
278    return ret;
279}
280
281ssize_t socket_read(nrx_socket_t *sock, void *buf, size_t count)
282{
283    int ret;
284    ret = read(sock->fd, buf, count);
285if (ret >= 0) ((char *)buf)[ret] = 0;
286if (ret >= 0) fprintf(stderr, "pid %i recving %i bytes on %s: %s\n", getpid(), ret, sock->path, (char *)buf);
287    return ret;
288}
289
290void socket_close(nrx_socket_t *sock)
291{
292    close(sock->fd);
293    if (sock->server)
294        unlink(sock->path);
295    free(sock);
296}
297
Note: See TracBrowser for help on using the repository browser.