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