chiark / gitweb /
serialmgr: Look for things in /usr, not /usr/local
[sympathy.git] / src / symsocket.c
1 /* 
2  * symsocket.c:
3  *
4  * Copyright (c) 2008 James McKenzie <sympathy@madingley.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] =
10   "$Id: symsocket.c,v 1.13 2008/03/07 14:13:40 james Exp $";
11
12 /* 
13  * $Log: symsocket.c,v $
14  * Revision 1.13  2008/03/07 14:13:40  james
15  * *** empty log message ***
16  *
17  * Revision 1.12  2008/03/07 13:16:02  james
18  * *** empty log message ***
19  *
20  * Revision 1.11  2008/03/07 12:37:04  james
21  * *** empty log message ***
22  *
23  * Revision 1.10  2008/03/03 18:16:16  james
24  * *** empty log message ***
25  *
26  * Revision 1.9  2008/03/03 18:15:19  james
27  * *** empty log message ***
28  *
29  * Revision 1.8  2008/03/03 06:04:42  james
30  * *** empty log message ***
31  *
32  * Revision 1.7  2008/03/02 10:37:56  james
33  * *** empty log message ***
34  *
35  * Revision 1.6  2008/02/27 00:27:22  james
36  * *** empty log message ***
37  *
38  * Revision 1.5  2008/02/20 22:54:22  staffcvs
39  * *** empty log message ***
40  *
41  * Revision 1.4  2008/02/20 18:31:53  james
42  * *** empty log message ***
43  *
44  * Revision 1.3  2008/02/14 02:46:44  james
45  * *** empty log message ***
46  *
47  * Revision 1.2  2008/02/14 00:57:58  james
48  * *** empty log message ***
49  *
50  * Revision 1.1  2008/02/13 18:05:06  james
51  * *** empty log message ***
52  *
53  */
54
55 #include "project.h"
56 #include <sys/socket.h>
57 #include <sys/un.h>
58
59 #define BUF_SIZE 65536
60 #define MAX_TXN 4096
61
62 int
63 wrap_recv (int fd, void *buf, int len)
64 {
65   int red;
66
67   red = recv (fd, buf, len, 0);
68   if (!red)
69     return -1;
70
71   if ((red < 0) && (errno == EAGAIN))
72     red = 0;
73
74   return red;
75 }
76
77 int
78 wrap_send (int fd, void *buf, int len)
79 {
80   int writ;
81
82   errno = 0;
83
84   writ = send (fd, buf, len, MSG_NOSIGNAL);
85
86   if (!writ)
87     return -1;
88
89   if ((writ < 0) && (errno == EAGAIN))
90     writ = 0;
91
92   return writ;
93 }
94
95 void
96 socket_free (Socket * s)
97 {
98   if (!s)
99     return;
100   if (s->read_buf)
101     slide_free (s->read_buf);
102   if (s->write_buf)
103     slide_free (s->write_buf);
104   if (s->path_to_unlink) {
105     unlink (s->path_to_unlink);
106     free (s->path_to_unlink);
107   }
108   close (s->fd);
109   free (s);
110 }
111
112 void
113 socket_free_parent (Socket * s)
114 {
115   if (!s)
116     return;
117   if (s->read_buf)
118     slide_free (s->read_buf);
119   if (s->write_buf)
120     slide_free (s->write_buf);
121   if (s->path_to_unlink)
122     free (s->path_to_unlink);
123   close (s->fd);
124
125   free (s);
126 }
127
128
129 Socket *
130 socket_listen (char *path)
131 {
132   int fd;
133   struct sockaddr_un *sun;
134   Socket *ret;
135   int n;
136
137
138   unlink (path);
139
140   fd = socket (PF_UNIX, SOCK_STREAM, 0);
141
142   if (fd < 0)
143     return NULL;
144
145   n = strlen (path) + sizeof (struct sockaddr_un);
146   sun = (struct sockaddr_un *) xmalloc (n);
147   memset (sun, 0, n);
148
149   sun->sun_family = AF_UNIX;
150   strcpy (sun->sun_path, path);
151
152   if (bind (fd, (struct sockaddr *) sun, SUN_LEN (sun)) < 0) {
153     free (sun);
154     close (fd);
155     return NULL;
156   }
157
158   free (sun);
159
160   if (listen (fd, 5) < 0) {
161     close (fd);
162     return NULL;
163   }
164
165   set_nonblocking (fd);
166
167   ret = (Socket *) xmalloc (sizeof (Socket));
168   memset (ret, 0, sizeof (Socket));
169   ret->read_buf = NULL;
170   ret->write_buf = NULL;
171
172   ret->fd = fd;
173   ret->path_to_unlink = strdup (path);
174
175
176   return ret;
177 }
178
179 Socket *
180 socket_accept (Socket * l)
181 {
182   Socket *ret;
183   int len;
184   int fd;
185   struct sockaddr_un sun;
186
187   len = sizeof (struct sockaddr_un);
188
189   fd = accept (l->fd, (struct sockaddr *) &sun, &len);
190
191   if (fd < 0)
192     return NULL;
193
194
195   ret = (Socket *) xmalloc (sizeof (Socket));
196   memset (ret, 0, sizeof (Socket));
197
198   set_nonblocking (fd);
199
200   ret->fd = fd;
201   ret->read_buf = slide_new (BUF_SIZE);
202   ret->write_buf = slide_new (BUF_SIZE);
203   ret->msg = 0;
204
205   return ret;
206 }
207
208
209 /* Blocking for now */
210 Socket *
211 socket_connect (char *path)
212 {
213   int n;
214   int fd;
215   struct sockaddr_un *sun;
216   Socket *ret;
217
218
219   fd = socket (PF_UNIX, SOCK_STREAM, 0);
220
221   if (fd < 0)
222     return NULL;
223
224   n = strlen (path) + sizeof (struct sockaddr_un);
225   sun = (struct sockaddr_un *) xmalloc (n);
226   memset (sun, 0, n);
227
228   sun->sun_family = AF_UNIX;
229   strcpy (sun->sun_path, path);
230
231   if (connect (fd, (struct sockaddr *) sun, SUN_LEN (sun))) {
232     free (sun);
233     close (fd);
234     return NULL;
235   }
236
237   free (sun);
238
239   set_nonblocking (fd);
240
241   ret = (Socket *) xmalloc (sizeof (Socket));
242   memset (ret, 0, sizeof (Socket));
243
244   ret->fd = fd;
245   ret->read_buf = slide_new (BUF_SIZE);
246   ret->write_buf = slide_new (BUF_SIZE);
247   ret->msg = 0;
248
249   return ret;
250 }
251
252 void
253 socket_consume_msg (Socket * s)
254 {
255   int n;
256
257   if (!s->msg)
258     return;
259
260   ipc_consume_message_in_slide (s->read_buf);
261   s->msg = ipc_check_for_message_in_slide (s->read_buf);
262
263 }
264
265 void
266 socket_pre_select (Socket * s, fd_set * rfds, fd_set * wfds)
267 {
268   char buf[1024];
269   int n;
270
271   /* Server socket */
272   if (SOCKET_IS_LISTENER (s)) {
273     FD_SET (s->fd, rfds);
274     return;
275   }
276
277   if (!SLIDE_EMPTY (s->write_buf))
278     FD_SET (s->fd, wfds);
279
280   if (!SLIDE_FULL (s->read_buf))
281     FD_SET (s->fd, rfds);
282
283 }
284
285 int
286 socket_post_select (Socket * s, fd_set * rfds, fd_set * wfds)
287 {
288   char buf[1024];
289   int n;
290   int error = 0;
291
292
293   if ((!SLIDE_EMPTY (s->write_buf)) && FD_ISSET (s->fd, wfds)) {
294     n =
295       (SLIDE_BYTES (s->write_buf) >
296        MAX_TXN) ? MAX_TXN : SLIDE_BYTES (s->write_buf);
297     n = wrap_send (s->fd, SLIDE_RPTR (s->write_buf), n);
298     if (n > 0)
299       slide_consume (s->write_buf, n);
300     if (n < 0)
301       error = -1;
302   }
303
304   if (!SLIDE_FULL (s->read_buf) && FD_ISSET (s->fd, rfds)) {
305     n =
306       (SLIDE_SPACE (s->read_buf) >
307        MAX_TXN) ? MAX_TXN : SLIDE_SPACE (s->read_buf);
308     n = wrap_recv (s->fd, SLIDE_WPTR (s->read_buf), n);
309     if (n > 0)
310       slide_added (s->read_buf, n);
311     if (n < 0)
312       error = -1;
313   }
314
315   s->msg = ipc_check_for_message_in_slide (s->read_buf);
316
317   return error;
318
319 }
320
321
322 int
323 socket_write (Socket * s, void *buf, int len)
324 {
325   int n;
326
327   slide_expand (s->write_buf, len);
328   memcpy (SLIDE_WPTR (s->write_buf), buf, len);
329   slide_added (s->write_buf, len);
330
331   n =
332     (SLIDE_BYTES (s->write_buf) >
333      MAX_TXN) ? MAX_TXN : SLIDE_BYTES (s->write_buf);
334   n = wrap_send (s->fd, SLIDE_RPTR (s->write_buf), n);
335   {
336     uint8_t *c = SLIDE_RPTR (s->write_buf);
337   }
338
339   if (n > 0)
340     slide_consume (s->write_buf, n);
341
342   if (n < 0)
343     return -1;
344
345   return len;
346 }