0a785912931b71a95476136991971c46ddea598b
[libfirm] / ir / lpp / lpp_comm.c
1 /*
2  * Copyright (C) 2005-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Protocol stuff for lpp server
23  * @author  Sebastian Hack
24  */
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <errno.h>
31
32 #ifdef _WIN32
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35 #include <winsock2.h>
36 #else
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <arpa/inet.h>
41 #endif
42
43 #include "irtools.h"
44 #include "debug.h"
45
46 #include "lpp_comm.h"
47
48 struct _lpp_comm_t {
49         int fd;
50         size_t buf_size;
51         char *w_pos;
52         char *r_pos;
53         char *r_max;
54         char *w_buf;
55         char *r_buf;
56 };
57
58 DEBUG_ONLY(
59 static inline firm_dbg_module_t *get_dbg_module(void)
60 {
61         static firm_dbg_module_t *dbg = NULL;
62         if(!dbg) {
63                 dbg = firm_dbg_register("lpp.comm");
64         }
65
66         return dbg;
67 }
68
69 #define dbg get_dbg_module()
70 )
71
72 /**
73  * Try to read some bytes but block until a certain amount is read.
74  * @param fd The file descriptor.
75  * @param buf The buffer to read into.
76  * @param try_amount The amount of bytes to try to read.
77  * @param at_least block until this many bytes are read.
78  * @return The number of bytes read or -1 on error.
79  */
80 static ssize_t secure_recv(int fd, void *buf, size_t try_amount, size_t at_least)
81 {
82         ssize_t res;
83         size_t bytes_read = 0;
84         char *data = buf;
85
86         do {
87                 res = recv(fd, &data[bytes_read], try_amount - bytes_read, 0);
88                 if(res <= 0) {
89                         if(res == 0 || errno != EAGAIN)
90                                 return -1;
91                         continue;
92                 }
93
94                 bytes_read += res;
95
96         } while(bytes_read < at_least);
97
98         return bytes_read;
99 }
100
101 static ssize_t secure_send(int fd, const void *buf, size_t n)
102 {
103         ssize_t res;
104         size_t bytes_written = 0;
105         const char *data = buf;
106
107         do {
108                 res = send(fd, &data[bytes_written], n - bytes_written, 0);
109                 if(res < 0) {
110                         if(errno != EAGAIN)
111                                 return -1;
112                         continue;
113                 }
114
115                 bytes_written += res;
116
117         } while(bytes_written < n);
118
119         return n;
120 }
121
122 ssize_t lpp_flush(lpp_comm_t *comm)
123 {
124         ssize_t res = 0;
125         if(comm->w_pos - comm->w_buf > 0) {
126                 DBG((dbg, LEVEL_1, "flushing %d bytes\n", comm->w_pos - comm->w_buf));
127                 res = secure_send(comm->fd, comm->w_buf, comm->w_pos - comm->w_buf);
128                 if(res < 0)
129                         return res;
130
131                 comm->w_pos = comm->w_buf;
132         }
133         return res;
134 }
135
136 static ssize_t lpp_write(lpp_comm_t *comm, const void *buf, size_t len)
137 {
138         assert(comm->w_pos - comm->w_buf >= 0);
139
140         DBG((dbg, LEVEL_1, "write of length %d\n", len));
141         if(len > 0) {
142                 size_t free = (comm->w_buf + comm->buf_size) - comm->w_pos;
143                 size_t copy = MIN(free, len);
144                 size_t rest = len - copy;
145                 const char *pos   = buf;
146
147                 DBG((dbg, LEVEL_1, "\tfree = %d, copy = %d, rest = %d\n", free, copy, rest));
148                 if(copy > 0) {
149                         memcpy(comm->w_pos, pos, copy);
150                         comm->w_pos += copy;
151                         pos         += copy;
152                 }
153
154                 /*
155                  * Not everything in buf fits into the buffer,
156                  * so flush the buffer and write the rest.
157                  */
158                 if(rest > 0) {
159                         size_t i;
160                         size_t n_direct = rest / comm->buf_size;
161                         size_t last_rest;
162
163                         if(lpp_flush(comm) < 0)
164                                 return -1;
165
166                         for(i = 0; i < n_direct; ++i) {
167                                 if(secure_send(comm->fd, pos, comm->buf_size) < 0)
168                                         return -1;
169
170                                 pos += comm->buf_size;
171                         }
172
173                         last_rest = ((const char *) buf + len) - pos;
174
175                         if(last_rest > 0) {
176                                 assert(last_rest < comm->buf_size);
177                                 assert(comm->w_pos == comm->w_buf);
178                                 memcpy(comm->w_pos, pos, last_rest);
179                                 comm->w_pos += last_rest;
180                         }
181                 }
182         }
183
184         return len;
185 }
186
187 static ssize_t lpp_read(lpp_comm_t *comm, void *buf, size_t len)
188 {
189         DBG((dbg, LEVEL_1, "read of length %d\n", len));
190         if(len > 0) {
191                 size_t left = comm->r_max - comm->r_pos;
192                 size_t copy = MIN(left, len);
193                 size_t rest = len - copy;
194                 char *pos   = buf;
195
196                 DBG((dbg, LEVEL_1, "\tleft = %d, copy = %d, rest = %d\n", left, copy, rest));
197                 if(copy > 0) {
198                         memcpy(pos, comm->r_pos, copy);
199                         pos         += copy;
200                         comm->r_pos += copy;
201                 }
202
203                 /* We want to read more than the buffer can provide. */
204                 if(rest > 0) {
205                         size_t bs = comm->buf_size;
206                         size_t n_direct = rest / comm->buf_size;
207                         size_t i;
208                         size_t last_rest;
209
210                         /*
211                          * The buffer is now completely read, so
212                          * reset the pointers.
213                          */
214                         comm->r_pos = comm->r_buf;
215                         comm->r_max = comm->r_buf;
216
217                         for(i = 0; i < n_direct; ++i) {
218                                 if(secure_recv(comm->fd, pos, bs, bs) < 0)
219                                         return -1;
220
221                                 pos += comm->buf_size;
222                         }
223
224                         last_rest = ((const char *) buf + len) - pos;
225
226                         if(last_rest > 0) {
227                                 ssize_t bytes_read = 0;
228
229                                 assert(last_rest < comm->buf_size);
230                                 assert(comm->r_pos == comm->r_buf);
231
232                                 bytes_read = secure_recv(comm->fd, comm->r_buf, bs, last_rest);
233                                 if(bytes_read < 0)
234                                         return -1;
235
236                                 memcpy(pos, comm->r_buf, last_rest);
237                                 comm->r_pos = comm->r_buf + last_rest;
238                                 comm->r_max = comm->r_buf + bytes_read;
239                         }
240                 }
241         }
242
243         return len;
244 }
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)), !=, (ssize_t)sizeof(x));
286 }
287
288 void lpp_writed(lpp_comm_t *comm, double dbl)
289 {
290         ERRNO_CHECK(lpp_write(comm, &dbl, sizeof(dbl)), !=, (ssize_t)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)), !=, (ssize_t)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)), !=, (ssize_t)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)), !=, (ssize_t)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         } else {
402                 lpp_writel(comm, LPP_CMD_OK);
403         }
404 }
405
406 void lpp_send_ack(lpp_comm_t *comm)
407 {
408         lpp_send_res(comm, 1, "");
409 }
410
411 const char *lpp_get_cmd_name(int cmd)
412 {
413         switch(cmd) {
414         case LPP_CMD_BAD:       return "BAD";
415         case LPP_CMD_OK:        return "OK";
416         case LPP_CMD_PROBLEM:   return "PROBLEM";
417         case LPP_CMD_SOLUTION:  return "SOLUTION";
418         case LPP_CMD_SOLVER:    return "SOLVER";
419         case LPP_CMD_BYE:       return "BYE";
420         case LPP_CMD_SOLVERS:   return "SOLVERS";
421         case LPP_CMD_SET_DEBUG: return "SET_DEBUG";
422         case LPP_CMD_INFO:      return "INFO";
423         case LPP_CMD_LAST:
424                 break;
425         }
426
427         return "<unknown>";
428 }