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