becopyopt: Replace is_Reg_Phi() by just is_Phi().
[libfirm] / ir / lpp / lpp_comm.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief   Protocol stuff for lpp server
9  * @author  Sebastian Hack
10  */
11 #include "config.h"
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <errno.h>
17
18 #ifdef _WIN32
19 #define WIN32_LEAN_AND_MEAN
20 #include <windows.h>
21 #include <winsock2.h>
22 #include <BaseTsd.h>
23 typedef SSIZE_T ssize_t;
24 #else
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #endif
30
31 #include "xmalloc.h"
32 #include "util.h"
33 #include "debug.h"
34
35 #include "lpp_comm.h"
36
37 struct _lpp_comm_t {
38         int fd;
39         size_t buf_size;
40         char *w_pos;
41         char *r_pos;
42         char *r_max;
43         char *w_buf;
44         char *r_buf;
45 };
46
47 #ifdef DEBUG_libfirm
48 static inline firm_dbg_module_t *get_dbg_module(void)
49 {
50         static firm_dbg_module_t *dbg = NULL;
51         if(!dbg) {
52                 dbg = firm_dbg_register("lpp.comm");
53         }
54
55         return dbg;
56 }
57 #define dbg get_dbg_module()
58 #endif
59
60 /**
61  * Try to read some bytes but block until a certain amount is read.
62  * @param fd The file descriptor.
63  * @param buf The buffer to read into.
64  * @param try_amount The amount of bytes to try to read.
65  * @param at_least block until this many bytes are read.
66  * @return The number of bytes read or -1 on error.
67  */
68 static ssize_t secure_recv(int fd, void *buf, size_t try_amount, size_t at_least)
69 {
70         ssize_t res;
71         size_t bytes_read = 0;
72         char *data = (char*)buf;
73
74         do {
75                 res = recv(fd, &data[bytes_read], try_amount - bytes_read, 0);
76                 if(res <= 0) {
77                         if(res == 0 || errno != EAGAIN)
78                                 return -1;
79                         continue;
80                 }
81
82                 bytes_read += res;
83
84         } while(bytes_read < at_least);
85
86         return bytes_read;
87 }
88
89 static ssize_t secure_send(int fd, const void *buf, size_t n)
90 {
91         ssize_t res;
92         size_t bytes_written = 0;
93         const char *data = (const char*)buf;
94
95         do {
96                 res = send(fd, &data[bytes_written], n - bytes_written, 0);
97                 if(res < 0) {
98                         if(errno != EAGAIN)
99                                 return -1;
100                         continue;
101                 }
102
103                 bytes_written += res;
104
105         } while(bytes_written < n);
106
107         return n;
108 }
109
110 static ssize_t lpp_flush_(lpp_comm_t *comm)
111 {
112         ssize_t res = 0;
113         if(comm->w_pos - comm->w_buf > 0) {
114                 DBG((dbg, LEVEL_1, "flushing %d bytes\n", comm->w_pos - comm->w_buf));
115                 res = secure_send(comm->fd, comm->w_buf, comm->w_pos - comm->w_buf);
116                 if(res < 0)
117                         return res;
118
119                 comm->w_pos = comm->w_buf;
120         }
121         return res;
122 }
123
124 void lpp_flush(lpp_comm_t *comm)
125 {
126         lpp_flush_(comm);
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 = (const char*)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 = (char*)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 lpp_comm_t *lpp_comm_new(int fd, size_t buf_size)
240 {
241         lpp_comm_t *res = XMALLOCZ(lpp_comm_t);
242
243         res->fd       = fd;
244         res->w_buf    = XMALLOCN(char, buf_size);
245         res->w_pos    = res->w_buf;
246         res->r_buf    = XMALLOCN(char, buf_size);
247         res->r_pos    = res->r_buf;
248         res->r_max    = res->r_buf;
249         res->buf_size = buf_size;
250
251         return res;
252 }
253
254 int lpp_comm_fileno(const lpp_comm_t *comm)
255 {
256         return comm->fd;
257 }
258
259 void lpp_comm_free(lpp_comm_t *comm)
260 {
261         free(comm->w_buf);
262         free(comm->r_buf);
263         free(comm);
264 }
265
266 void lpp_print_err(const char *fmt, ...)
267 {
268         va_list args;
269
270         va_start(args, fmt);
271         vfprintf(stderr, fmt, args);
272         va_end(args);
273 }
274
275 void lpp_writel(lpp_comm_t *comm, uint32_t x)
276 {
277         x = htonl(x);
278         ERRNO_CHECK(lpp_write(comm, &x, sizeof(x)), !=, (ssize_t)sizeof(x));
279 }
280
281 void lpp_writed(lpp_comm_t *comm, double dbl)
282 {
283         ERRNO_CHECK(lpp_write(comm, &dbl, sizeof(dbl)), !=, (ssize_t)sizeof(dbl));
284 }
285
286 void lpp_writes(lpp_comm_t *comm, const char *str)
287 {
288         size_t n = strlen(str);
289         lpp_writel(comm, n);
290         ERRNO_CHECK(lpp_write(comm, str, n), !=, (ssize_t) n);
291 }
292
293 uint32_t lpp_readl(lpp_comm_t *comm)
294 {
295         uint32_t res;
296
297         ERRNO_CHECK(lpp_read(comm, &res, sizeof(res)), !=, (ssize_t)sizeof(res));
298         return ntohl(res);
299 }
300
301 int lpp_read_cmd(lpp_comm_t *comm)
302 {
303         uint32_t res = 0;
304         int retval;
305
306         for(;;) {
307                 retval = recv(comm->fd, (char *)&res, sizeof(res), 0);
308                 if(retval < 0) {
309                         if(errno != EAGAIN)
310                                 return -1;
311                 }
312
313                 else
314                         break;
315         }
316
317         return (int) ntohl(res);
318 }
319
320 double lpp_readd(lpp_comm_t *comm)
321 {
322         double res;
323         ERRNO_CHECK(lpp_read(comm, &res, sizeof(res)), !=, (ssize_t)sizeof(res));
324         return res;
325 }
326
327 char *lpp_reads(lpp_comm_t *comm)
328 {
329         size_t len = lpp_readl(comm);
330         char *res = XMALLOCN(char, len+1);
331
332         ERRNO_CHECK(lpp_read(comm, res, len), !=, (ssize_t) len);
333         res[len] = '\0';
334         return res;
335 }
336
337 char *lpp_readbuf(lpp_comm_t *comm, char *buf, size_t buflen)
338 {
339         char dummy[1024];
340         size_t i;
341         size_t n         = buflen - 1;
342         size_t len       = lpp_readl(comm);
343         size_t max_read  = n < len ? n : len;
344         size_t rest      = len - max_read;
345
346         if(buflen > 0 && buf != NULL) {
347                 ERRNO_CHECK(lpp_read(comm, buf, max_read), !=, (ssize_t) max_read);
348                 buf[max_read] = '\0';
349         }
350         else
351                 rest = len;
352
353         /* eat up data that didnt fit into the string */
354         for(i = 0, n = rest / sizeof(dummy); i < n; ++i)
355                 ERRNO_CHECK(lpp_read(comm, dummy, sizeof(dummy)), !=, (ssize_t)sizeof(dummy));
356
357         if(rest % sizeof(dummy) > 0)
358                 ERRNO_CHECK(lpp_read(comm, dummy, rest % sizeof(dummy)), !=,
359                                         (ssize_t) (rest % sizeof(dummy)) );
360
361         return buf;
362 }
363
364 int lpp_ack(lpp_comm_t *comm, char *buf, size_t buflen)
365 {
366         int res = 0;
367         int cmd = lpp_readl(comm);
368
369         switch(cmd) {
370         case LPP_CMD_OK:
371                 res = 1;
372                 break;
373         case LPP_CMD_BAD:
374                 lpp_readbuf(comm, buf, buflen);
375         default:
376                 res = 0;
377         }
378
379         return res;
380 }
381
382 void lpp_send_res(lpp_comm_t *comm, int ok, const char *fmt, ...)
383 {
384         if(!ok) {
385                 char buf[1024];
386                 va_list args;
387
388                 va_start(args, fmt);
389                 vsnprintf(buf, sizeof(buf), fmt, args);
390                 va_end(args);
391
392                 lpp_writel(comm, LPP_CMD_BAD);
393                 lpp_writes(comm, buf);
394         } else {
395                 lpp_writel(comm, LPP_CMD_OK);
396         }
397 }
398
399 void lpp_send_ack(lpp_comm_t *comm)
400 {
401         lpp_send_res(comm, 1, "");
402 }
403
404 const char *lpp_get_cmd_name(int cmd)
405 {
406         switch(cmd) {
407         case LPP_CMD_BAD:       return "BAD";
408         case LPP_CMD_OK:        return "OK";
409         case LPP_CMD_PROBLEM:   return "PROBLEM";
410         case LPP_CMD_SOLUTION:  return "SOLUTION";
411         case LPP_CMD_SOLVER:    return "SOLVER";
412         case LPP_CMD_BYE:       return "BYE";
413         case LPP_CMD_SOLVERS:   return "SOLVERS";
414         case LPP_CMD_SET_DEBUG: return "SET_DEBUG";
415         case LPP_CMD_INFO:      return "INFO";
416         case LPP_CMD_LAST:
417                 break;
418         }
419
420         return "<unknown>";
421 }