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