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