source: trunk/athena/etc/xdm/misc/pc_bsd.c @ 8091

Revision 8091, 7.3 KB checked in by cfields, 29 years ago (diff)
add pc_destroy update code for NoListener.
Line 
1#include <unistd.h>
2#include <stdlib.h>
3#include <stdio.h>
4#include <sys/types.h>
5#include <bstring.h>
6#include <sys/time.h>
7#include <sys/socket.h>
8#include <sys/un.h>
9#include <syslog.h>
10#include <errno.h>
11#include "pc_bsd.h"
12
13long pc_init(pc_state **ps)
14{
15  pc_state *ret;
16
17  initialize_pc_error_table();
18
19  ret = malloc(sizeof(pc_state));
20  if (ret == NULL)
21    return PCerrNoMem;
22
23  ret->numports = 0;
24
25  ret->nfds = 0;
26  FD_ZERO(&(ret->readfds));
27  FD_ZERO(&(ret->writefds));
28
29  *ps = ret;
30  return 0L;
31}
32
33long pc_destroy(pc_state *ps)
34{
35  free(ps);
36  return 0L;
37}
38
39long pc_freemessage(pc_message *m)
40{
41  if (m == NULL)
42    return 0L;
43
44  if (m->type == PC_DATA)
45    free(m->data);
46
47  free(m);
48  return 0L;
49}
50
51/*
52 * Add a port to a state structure.
53 */
54long pc_addport(pc_state *s, pc_port *p)
55{
56  if (s == NULL || p == NULL)
57    return PCerrNullArg;
58
59  if (s->numports == PC_MAXPORTS)
60    return PCerrMaxPortsUsed;
61
62  s->ports[s->numports++] = p;
63
64  FD_SET(p->fd, &(s->readfds));
65  s->nfds = MAX(s->nfds, p->fd + 1);
66
67  return 0L;
68}
69
70long pc_removeport(pc_state *s, pc_port *p)
71{
72  int i;
73
74  if (s == NULL || p == NULL)
75    return PCerrNullArg;
76
77  for (i = 0; i < s->numports; i++)
78    if (s->ports[i] == p)
79      {
80        s->numports--;
81        for (; i < s->numports; i++)
82          s->ports[i] = s->ports[i+1];
83        FD_CLR(p->fd, &(s->readfds)); /* should adjust nfds someday */
84        return 0L;
85      }
86
87  return PCerrNoSuchPort;
88}
89
90long pc_addfd(pc_state *s, pc_fd *fd)
91{
92  if (s == NULL || fd == NULL)
93    return PCerrNullArg;
94
95  if (fd->events & PC_READ)
96    FD_SET(fd->fd, &(s->readfds));
97 
98  if (fd->events & PC_WRITE)
99    FD_SET(fd->fd, &(s->writefds));
100
101  if (fd->events & (PC_READ | PC_WRITE))
102    s->nfds = MAX(s->nfds, fd->fd + 1);
103
104  return 0L;
105}
106
107long pc_removefd(pc_state *s, pc_fd *fd)
108{
109  if (s == NULL || fd == NULL)
110    return PCerrNullArg;
111
112  if (fd->events & PC_READ)
113    FD_CLR(fd->fd, &(s->readfds));
114 
115  if (fd->events & PC_WRITE)
116    FD_CLR(fd->fd, &(s->writefds));
117
118  return 0L;
119}
120
121/* Should probably make it fail if chown or chmod fail. */
122long pc_makeport(pc_port **pp, char *name, int flags,
123                 uid_t owner, gid_t group, mode_t mode)
124{
125  pc_port *p;
126  struct sockaddr_un n;
127
128  if (pp == NULL || name == NULL)
129    return PCerrNullArg;
130
131  p = malloc(sizeof(pc_port));
132  if (p == NULL)
133    return PCerrNoMem;
134
135  p->parent = NULL;
136  p->type = PC_LISTENER;
137  p->path = malloc(strlen(name)+1);
138  if (p->path == NULL)
139    {
140      free(p);
141      return PCerrNoMem;
142    }
143  strcpy(p->path, name);
144
145  p->fd = socket(PF_UNIX, SOCK_STREAM, 0);
146  if (p->fd == -1)
147    {
148      free(p->path);
149      free(p);
150      return PCerrSocketFailed;
151    }
152
153  if (flags & PC_GRAB)
154    unlink(p->path);
155  n.sun_family = PF_UNIX;
156  strcpy(n.sun_path, p->path);
157  if (bind(p->fd, &n, sizeof(struct sockaddr_un)) == -1)
158    {
159      close(p->fd);
160      free(p->path);
161      free(p);
162      return PCerrBindFailed;
163    }
164
165  /* Does listening after the ch* avoid a hole for us? */
166  if (flags & PC_CHMOD)
167    chmod(p->path, mode);
168  if (flags & PC_CHOWN)
169    chown(p->path, owner, group);
170
171  listen(p->fd, 5);
172
173  *pp = p;
174  return 0L;
175}
176
177long pc_chprot(pc_port *p, uid_t owner, gid_t group, mode_t mode)
178{
179  if (p == NULL)
180    return PCerrNullArg;
181
182  if (p->type != PC_LISTENER)
183    return PCerrBadType;
184
185  chown(p->path, owner, group);
186  chmod(p->path, mode);
187
188  return 0L;
189}
190
191long pc_openport(pc_port **pp, char *name)
192{
193  pc_port *p;
194  struct sockaddr_un n;
195  int errcopy;
196
197  if (pp == NULL || name == NULL)
198    return PCerrNullArg;
199
200  p = malloc(sizeof(pc_port));
201  if (p == NULL)
202    return PCerrNoMem;
203
204  p->parent = NULL;
205  p->type = PC_REGULAR;
206  p->path = malloc(strlen(name)+1);
207  if (p->path == NULL)
208    {
209      free(p);
210      return PCerrNoMem;
211    }
212  strcpy(p->path, name);
213
214  p->fd = socket(PF_UNIX, SOCK_STREAM, 0);
215  if (p->fd == -1)
216    {
217      free(p->path);
218      free(p);
219      return PCerrSocketFailed;
220    }
221
222  n.sun_family = PF_UNIX;
223  strcpy(n.sun_path, p->path);
224
225  /* XXX Need to set an alarm here. If a nanny has run and died
226     (not ever observed) and leaves its socket lying about, under
227     Irix at least, this connect will block forever. Or several
228     minutes at least. */
229  if (connect(p->fd, &n, sizeof(struct sockaddr_un)) == -1)
230    {
231      errcopy = errno;
232      close(p->fd);
233      free(p->path);
234      free(p);
235      if (errcopy == EACCES)
236        return PCerrNotAllowed;
237      /* Hmmm. I've seen ECONNREFUSED when the listener has died.
238         If you can also get it when the listener is backed up,
239         we're screwed. */
240      if (errcopy == ENOENT || errcopy == ECONNREFUSED)
241        return PCerrNoListener;
242      syslog(LOG_ERR, "connect returned %d\n", errcopy);
243      return PCerrConnectFailed;
244    }
245
246  *pp = p;
247  return 0L;
248}
249
250long pc_close(pc_port *p)
251{
252  if (p == NULL)
253    return PCerrNullArg;
254
255  close(p->fd);
256  if (p->type == PC_LISTENER)
257    unlink(p->path);
258
259  if (p->path != NULL)
260    free(p->path);
261
262  free(p);
263
264  return 0L;
265}
266
267long pc_send(pc_message *m)
268{
269  int l = 0, r;
270
271  if (m == NULL)
272    return PCerrNullArg;
273
274  if (m->source == NULL)
275    return PCerrNoDestination;
276
277  if (m->data == NULL || m->length < 1)
278    return PCerrNoData;
279
280  while (l < m->length)
281    {
282      r = write(m->source->fd, m->data, m->length);
283      if (r == -1)
284        return PCerrWriteFailed;
285      l += r;
286    }
287
288  return 0L;
289}
290
291long pc_receive(pc_message **mm, pc_port *p)
292{
293  char buf[2048];
294  pc_message *m;
295  int len;
296
297  if (p == NULL || mm == NULL)
298    return PCerrNullArg;
299
300  m = malloc(sizeof(pc_message));
301  if (m == NULL)
302    return PCerrNoMem;
303
304  len = read(p->fd, buf, sizeof(buf) - 1);
305  if (len == -1)
306    {
307      free(m);
308      return PCerrReadFailed;
309    }
310
311  m->data = malloc(len + 1);
312  if (m->data == NULL)
313    {
314      free(m);
315      return PCerrNoMem;
316    }
317
318  m->type = PC_DATA;
319  m->source = p;
320  buf[len] = '\0';
321  memcpy(m->data, buf, len + 1);
322  m->length = len;
323
324  *mm = m;
325  return 0L;
326}
327
328static fd_print(fd_set *r)
329{
330  int i;
331
332  for (i = 0; i < FD_SETSIZE; i++)
333    if (FD_ISSET(i, r))
334      fprintf(stderr, "%d ", i);
335
336  printf("\n");
337}
338
339long pc_wait(pc_message **mm, pc_state *s)
340{
341  int i, j;
342  fd_set r, w;
343  int ret;
344  pc_message *m;
345  pc_port *p;
346
347  if (mm == NULL || s == NULL)
348    return PCerrNullArg;
349
350  r = s->readfds;
351  w = s->writefds;
352
353  m = malloc(sizeof(pc_message));
354  if (m == NULL)
355    return PCerrNoMem;
356
357  ret = select(s->nfds, &r, &w, NULL, NULL);
358  if (ret == -1)
359    {
360      if (errno == EINTR)
361        m->type = PC_SIGNAL;
362      else
363        m->type = PC_BROKEN;
364      *mm = m;
365      return 0L;
366    }
367
368  for (i = 0; i < s->nfds; i++)
369    if (FD_ISSET(i, &r) || FD_ISSET(i, &w))
370      {
371        for (j = 0; j < s->numports; j++)
372          if (i == s->ports[j]->fd)
373            {
374              if (s->ports[j]->type == PC_LISTENER)
375                {
376                  p = malloc(sizeof(pc_port));
377                  if (p == NULL)
378                    {
379                      free(m);
380                      return PCerrNoMem;
381                    }
382
383                  p->fd = accept(s->ports[j]->fd, NULL, 0);
384                  if (p->fd == -1)
385                    {
386                      free(m);
387                      free(p);
388                      return PCerrAcceptFailed;
389                    }
390                  p->parent = s->ports[j];
391                  p->type = PC_LISTENEE;
392                  p->path = NULL;
393
394                  m->type = PC_NEWCONN;
395                  m->source = s->ports[j];
396                  m->data = p;
397                  *mm = m;
398                  return 0L;
399                }
400              else
401                {
402                  free(m);
403                  return pc_receive(mm, s->ports[j]);
404                }
405            }
406
407        /* It isn't a network port, so it must be something the user
408           requested info on. */
409        m->type = PC_FD;
410        if (FD_ISSET(i, &r))
411          m->event = PC_READ;
412        else
413          m->event = PC_WRITE;
414        m->fd = i;
415        *mm = m;
416        return 0L;
417      }
418}
Note: See TracBrowser for help on using the repository browser.