added lpp
[libfirm] / ir / lpp / lpp_comm.c
1 /**
2  * @file   lpp_comm.c
3  * @date   21.07.2005
4  * @author Sebastian Hack
5  *
6  * Protocol stuff for lpp server
7  *
8  * Copyright (C) 2005 Universitaet Karlsruhe
9  * Released under the GPL
10  */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <assert.h>
15 #include <errno.h>
16
17 #ifdef _WIN32
18 #define WIN32_LEAN_AND_MEAN
19 #include <windows.h>
20 #include <winsock2.h>
21
22 #define vsnprintf _vsnprintf
23
24 #else
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #endif
29
30 #include "irtools.h"
31 #include "debug.h"
32
33 #include "lpp_comm.h"
34
35
36 /* undef to disable buffering socket i/o */
37 #define ENABLE_BUFFERING
38
39 /* undef to disable debugging */
40 #undef  ENABLE_DEBUGGING
41
42 struct _lpp_comm_t {
43         int fd;
44         size_t buf_size;
45         char *w_pos;
46         char *r_pos;
47         char *r_max;
48         char *w_buf;
49         char *r_buf;
50 };
51
52 static firm_dbg_module_t *dbg = NULL;
53
54 /**
55  * Try to read some bytes but block until a certain amount is read.
56  * @param fd The file descriptor.
57  * @param buf The buffer to read into.
58  * @param try The amount of bytes to try to read.
59  * @param at_least block until this many bytes are read.
60  * @return The number of bytes read or -1 on error.
61  */
62 static ssize_t secure_recv(int fd, void *buf, size_t try, size_t at_least)
63 {
64   ssize_t res;
65   size_t bytes_read = 0;
66   char *data = buf;
67
68   do {
69     res = recv(fd, &data[bytes_read], try - bytes_read, 0);
70     if(res <= 0) {
71       if(res == 0 || errno != EAGAIN)
72         return -1;
73       continue;
74     }
75
76     bytes_read += res;
77
78   } while(bytes_read < at_least);
79
80   return bytes_read;
81 }
82
83 static ssize_t secure_send(int fd, const void *buf, size_t n)
84 {
85   ssize_t res;
86   size_t bytes_written = 0;
87   const char *data = buf;
88
89   do {
90     res = send(fd, &data[bytes_written], n - bytes_written, 0);
91     if(res < 0) {
92       if(errno != EAGAIN)
93         return -1;
94       continue;
95     }
96
97     bytes_written += res;
98
99   } while(bytes_written < n);
100
101   return n;
102 }
103
104 #ifdef ENABLE_BUFFERING
105 ssize_t lpp_flush(lpp_comm_t *comm)
106 {
107         ssize_t res = 0;
108         if(comm->w_pos - comm->w_buf > 0) {
109                 DBG((dbg, LEVEL_1, "flushing %d bytes\n", comm->w_pos - comm->w_buf));
110                 res = secure_send(comm->fd, comm->w_buf, comm->w_pos - comm->w_buf);
111                 if(res < 0)
112                         return res;
113
114                 comm->w_pos = comm->w_buf;
115         }
116         return res;
117 }
118
119 static ssize_t lpp_write(lpp_comm_t *comm, const void *buf, size_t len)
120 {
121         assert(comm->w_pos - comm->w_buf >= 0);
122
123         DBG((dbg, LEVEL_1, "write of length %d\n", len));
124         if(len > 0) {
125                 size_t free = (comm->w_buf + comm->buf_size) - comm->w_pos;
126                 size_t copy = MIN(free, len);
127                 size_t rest = len - copy;
128                 const char *pos   = buf;
129
130                 DBG((dbg, LEVEL_1, "\tfree = %d, copy = %d, rest = %d\n", free, copy, rest));
131                 if(copy > 0) {
132                         memcpy(comm->w_pos, pos, copy);
133                         comm->w_pos += copy;
134                         pos         += copy;
135                 }
136
137                 /*
138                  * Not everything in buf fits into the buffer,
139                  * so flush the buffer and write the rest.
140                  */
141                 if(rest > 0) {
142                         size_t i;
143                         size_t n_direct = rest / comm->buf_size;
144                         size_t last_rest;
145
146                         if(lpp_flush(comm) < 0)
147                                 return -1;
148
149                         for(i = 0; i < n_direct; ++i) {
150                                 if(secure_send(comm->fd, pos, comm->buf_size) < 0)
151                                         return -1;
152
153                                 pos += comm->buf_size;
154                         }
155
156                         last_rest = ((const char *) buf + len) - pos;
157
158                         if(last_rest > 0) {
159                                 assert(last_rest < comm->buf_size);
160                                 assert(comm->w_pos == comm->w_buf);
161                                 memcpy(comm->w_pos, pos, last_rest);
162                                 comm->w_pos += last_rest;
163                         }
164                 }
165         }
166
167         return len;
168 }
169
170 static ssize_t lpp_read(lpp_comm_t *comm, void *buf, size_t len)
171 {
172         DBG((dbg, LEVEL_1, "read of length %d\n", len));
173         if(len > 0) {
174                 size_t left = comm->r_max - comm->r_pos;
175                 size_t copy = MIN(left, len);
176                 size_t rest = len - copy;
177                 char *pos   = buf;
178
179                 DBG((dbg, LEVEL_1, "\tleft = %d, copy = %d, rest = %d\n", left, copy, rest));
180                 if(copy > 0) {
181                         memcpy(pos, comm->r_pos, copy);
182                         pos         += copy;
183                         comm->r_pos += copy;
184                 }
185
186                 /* We want to read more than the buffer can provide. */
187                 if(rest > 0) {
188                         size_t bs = comm->buf_size;
189                         size_t n_direct = rest / comm->buf_size;
190                         size_t i;
191                         size_t last_rest;
192
193                         /*
194                          * The buffer is now completely read, so
195                          * reset the pointers.
196                          */
197                         comm->r_pos = comm->r_buf;
198                         comm->r_max = comm->r_buf;
199
200                         for(i = 0; i < n_direct; ++i) {
201                                 if(secure_recv(comm->fd, pos, bs, bs) < 0)
202                                         return -1;
203
204                                 pos += comm->buf_size;
205                         }
206
207                         last_rest = ((const char *) buf + len) - pos;
208
209                         if(last_rest > 0) {
210                                 ssize_t bytes_read = 0;
211
212                                 assert(last_rest < comm->buf_size);
213                                 assert(comm->r_pos == comm->r_buf);
214
215                                 bytes_read = secure_recv(comm->fd, comm->r_buf, bs, last_rest);
216                                 if(bytes_read < 0)
217                                         return -1;
218
219                                 memcpy(pos, comm->r_buf, last_rest);
220                                 comm->r_pos = comm->r_buf + last_rest;
221                                 comm->r_max = comm->r_buf + bytes_read;
222                         }
223                 }
224         }
225
226         return len;
227 }
228
229 #else /* ENABLE_BUFFERING */
230 ssize_t lpp_flush(lpp_comm_t *comm)
231 {
232         return 0;
233 }
234
235 static ssize_t lpp_write(lpp_comm_t *comm, const void *buf, size_t len)
236 {
237         return secure_send(comm->fd, buf, len);
238 }
239
240 static ssize_t lpp_read(lpp_comm_t *comm, void *buf, size_t len)
241 {
242         return secure_recv(comm->fd, buf, len, len);
243 }
244 #endif
245
246 lpp_comm_t *lpp_comm_new(int fd, size_t buf_size)
247 {
248         lpp_comm_t *res = malloc(sizeof(res[0]));
249
250         res->fd       = fd;
251         res->w_buf    = malloc(buf_size);
252         res->w_pos    = res->w_buf;
253         res->r_buf    = malloc(buf_size);
254         res->r_pos    = res->r_buf;
255         res->r_max    = res->r_buf;
256         res->buf_size = buf_size;
257
258         return res;
259 }
260
261 int lpp_comm_fileno(const lpp_comm_t *comm)
262 {
263         return comm->fd;
264 }
265
266 void lpp_comm_free(lpp_comm_t *comm)
267 {
268         free(comm->w_buf);
269         free(comm->r_buf);
270         free(comm);
271 }
272
273 void lpp_print_err(const char *fmt, ...)
274 {
275   va_list args;
276
277   va_start(args, fmt);
278   vfprintf(stderr, fmt, args);
279   va_end(args);
280 }
281
282 void lpp_writel(lpp_comm_t *comm, uint32_t x)
283 {
284   x = htonl(x);
285   ERRNO_CHECK(lpp_write(comm, &x, sizeof(x)), !=, sizeof(x));
286 }
287
288 void lpp_writed(lpp_comm_t *comm, double dbl)
289 {
290   ERRNO_CHECK(lpp_write(comm, &dbl, sizeof(dbl)), !=, sizeof(dbl));
291 }
292
293 void lpp_writes(lpp_comm_t *comm, const char *str)
294 {
295   size_t n = strlen(str);
296   lpp_writel(comm, n);
297   ERRNO_CHECK(lpp_write(comm, str, n), !=, (ssize_t) n);
298 }
299
300 uint32_t lpp_readl(lpp_comm_t *comm)
301 {
302   uint32_t res;
303
304   ERRNO_CHECK(lpp_read(comm, &res, sizeof(res)), !=, sizeof(res));
305   return ntohl(res);
306 }
307
308 int lpp_read_cmd(lpp_comm_t *comm)
309 {
310         uint32_t res = 0;
311         int retval;
312
313         for(;;) {
314                 retval = recv(comm->fd, (char *)&res, sizeof(res), 0);
315                 if(retval < 0) {
316                         if(errno != EAGAIN)
317                                 return -1;
318                 }
319
320                 else
321                         break;
322         }
323
324         return (int) ntohl(res);
325 }
326
327 double lpp_readd(lpp_comm_t *comm)
328 {
329   double res;
330   ERRNO_CHECK(lpp_read(comm, &res, sizeof(res)), !=, sizeof(res));
331   return res;
332 }
333
334 char *lpp_reads(lpp_comm_t *comm)
335 {
336   size_t len = lpp_readl(comm);
337   char *res = malloc(sizeof(char) * (len + 1));
338
339   ERRNO_CHECK(lpp_read(comm, res, len), !=, (ssize_t) len);
340   res[len] = '\0';
341   return res;
342 }
343
344 char *lpp_readbuf(lpp_comm_t *comm, char *buf, size_t buflen)
345 {
346   char dummy[1024];
347   size_t i;
348   size_t n         = buflen - 1;
349   size_t len       = lpp_readl(comm);
350   size_t max_read  = n < len ? n : len;
351   size_t rest      = len - max_read;
352
353   if(buflen > 0 && buf != NULL) {
354     ERRNO_CHECK(lpp_read(comm, buf, max_read), !=, (ssize_t) max_read);
355     buf[max_read] = '\0';
356   }
357   else
358     rest = len;
359
360   /* eat up data that didnt fit into the string */
361   for(i = 0, n = rest / sizeof(dummy); i < n; ++i)
362     ERRNO_CHECK(lpp_read(comm, dummy, sizeof(dummy)), !=, sizeof(dummy));
363
364   if(rest % sizeof(dummy) > 0)
365     ERRNO_CHECK(lpp_read(comm, dummy, rest % sizeof(dummy)), !=,
366                     (ssize_t) (rest % sizeof(dummy)) );
367
368   return buf;
369 }
370
371 int lpp_ack(lpp_comm_t *comm, char *buf, size_t buflen)
372 {
373   int res = 0;
374   int cmd = lpp_readl(comm);
375
376   switch(cmd) {
377     case LPP_CMD_OK:
378       res = 1;
379       break;
380     case LPP_CMD_BAD:
381       lpp_readbuf(comm, buf, buflen);
382     default:
383       res = 0;
384   }
385
386   return res;
387 }
388
389 void lpp_send_res(lpp_comm_t *comm, int ok, const char *fmt, ...)
390 {
391   if(!ok) {
392     char buf[1024];
393     va_list args;
394
395     va_start(args, fmt);
396     vsnprintf(buf, sizeof(buf), fmt, args);
397     va_end(args);
398
399     lpp_writel(comm, LPP_CMD_BAD);
400     lpp_writes(comm, buf);
401   }
402
403   else
404     lpp_writel(comm, LPP_CMD_OK);
405 }
406
407 void lpp_send_ack(lpp_comm_t *comm)
408 {
409   lpp_send_res(comm, 1, "");
410 }
411
412 const char *lpp_get_cmd_name(int cmd)
413 {
414   switch(cmd) {
415 #define LPP_CMD(x) case LPP_CMD_ ## x: return #x;
416 #include "lpp_cmd.def"
417 #undef LPP_CMD
418   }
419
420   return "<unknown>";
421 }