f0ae59af9638ac9b33897f6af46cb52223602a2e
[libfirm] / ir / lpp / lpp_net.c
1 /**
2  * @file   lpp_net.c
3  * @date   19.07.2005
4  * @author Sebastian Hack
5  *
6  * A client for an lpp solving server.
7  *
8  * Copyright (C) 2005 Universitaet Karlsruhe
9  * Released under the GPL
10  */
11
12 #ifdef _WIN32
13 #include <winsock.h>
14 #include <io.h>
15
16 #else
17 #include <sys/time.h>
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <sys/resource.h>
21 #include <sys/wait.h>
22
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <unistd.h>
27
28 /* solaris fix */
29 #ifndef INADDR_NONE
30 #define INADDR_NONE (in_addr_t)(-1)
31 #endif
32
33 #endif
34
35
36 #include <signal.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "timing.h"
43
44 #include "lpp_net.h"
45 #include "lpp_t.h"
46 #include "lpp_comm.h"
47
48 #ifdef _WIN32
49 static int winsock_init(void)
50 {
51         WORD wVersionRequested;
52         WSADATA wsaData;
53         int err;
54
55         wVersionRequested = MAKEWORD( 2, 2 );
56
57         err = WSAStartup( wVersionRequested, &wsaData );
58         if ( err != 0 ) {
59                 /* Tell the user that we could not find a usable */
60                 /* WinSock DLL.                                  */
61                 return 0;
62         }
63
64         /* Confirm that the WinSock DLL supports 2.2.*/
65         /* Note that if the DLL supports versions greater    */
66         /* than 2.2 in addition to 2.2, it will still return */
67         /* 2.2 in wVersion since that is the version we      */
68         /* requested.                                        */
69
70         if ( LOBYTE( wsaData.wVersion ) != 2 ||
71                         HIBYTE( wsaData.wVersion ) != 2 ) {
72                 /* Tell the user that we could not find a usable */
73                 /* WinSock DLL.                                  */
74                 WSACleanup( );
75                 return 0;
76         }
77         return 1;
78 }
79 #endif
80
81 static int connect_tcp(const char *host, uint16_t port)
82 {
83         struct hostent     *phe;
84         struct protoent    *ppe;
85         struct sockaddr_in sin;
86         int s;
87
88 #ifdef _WIN32
89         winsock_init();
90 #endif
91
92         memset(&sin, 0, sizeof(sin));
93         sin.sin_family = AF_INET;
94         sin.sin_port   = htons(port);
95
96         if ((phe = gethostbyname(host)))
97                 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
98         else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
99                 lpp_print_err("cannot get host entry for %s", host);
100                 return -1;
101         }
102
103         ppe = getprotobyname("tcp");
104         ERRNO_CHECK_RETURN(s = socket(PF_INET, SOCK_STREAM, ppe->p_proto), <, 0, -1);
105         ERRNO_CHECK_RETURN(connect(s, (struct sockaddr *) &sin, sizeof(sin)), <, 0, -1);
106
107         return s;
108 }
109
110 char **lpp_get_solvers(const char *host)
111 {
112         int fd, n;
113         char **res = NULL;
114         lpp_comm_t *comm;
115
116         ERR_CHECK_RETURN(fd = connect_tcp(host, LPP_PORT), <, 0,
117                         ("could not connect to %s", host), NULL);
118
119         comm = lpp_comm_new(fd, LPP_BUFSIZE);
120
121         lpp_writel(comm, LPP_CMD_SOLVERS);
122         lpp_flush(comm);
123         n = lpp_readl(comm);
124         res = malloc((n + 1) * sizeof(res[0]));
125         res[n] = NULL;
126
127         if(n > 0) {
128                 int i;
129                 for(i = 0; i < n; ++i)
130                         res[i] = lpp_reads(comm);
131         }
132
133         lpp_writel(comm, LPP_CMD_BYE);
134         lpp_flush(comm);
135         lpp_comm_free(comm);
136         close(fd);
137         return res;
138 }
139
140 void lpp_set_dbg(const char *host, int mask)
141 {
142         int fd;
143         lpp_comm_t *comm;
144
145         ERR_CHECK_RETURN_VOID(fd = connect_tcp(host, LPP_PORT), <, 0, ("could not connect to %s", host));
146
147         comm = lpp_comm_new(fd, LPP_BUFSIZE);
148
149         lpp_writel(comm, LPP_CMD_SET_DEBUG);
150         lpp_writel(comm, mask);
151         lpp_flush(comm);
152         lpp_writel(comm, LPP_CMD_BYE);
153         lpp_flush(comm);
154         lpp_comm_free(comm);
155         close(fd);
156 }
157
158 void lpp_solve_net(lpp_t *lpp, const char *host, const char *solver)
159 {
160         char buf[1024];
161         int n, fd, ready;
162         lpp_comm_t *comm;
163         ir_timer_t *t_send, *t_recv;
164
165         ERR_CHECK_RETURN_VOID(fd = connect_tcp(host, LPP_PORT), <, 0,
166                 ("could not connect to %s", host));
167
168         comm = lpp_comm_new(fd, LPP_BUFSIZE);
169
170         /* Set the solver */
171         lpp_writel(comm, LPP_CMD_SOLVER);
172         lpp_writes(comm, solver);
173         lpp_flush(comm);
174
175 #if 0
176         ERR_CHECK_RETURN_VOID(lpp_ack(fd, sizeof(buf), buf), == 0,
177                 ("could not set solver: %s", solver));
178 #endif
179
180         t_send = ir_timer_new();
181         t_recv = ir_timer_new();
182
183         ir_timer_push(t_send);
184         lpp_writel(comm, LPP_CMD_PROBLEM);
185         lpp_serialize(comm, lpp, 1);
186         lpp_serialize_values(comm, lpp, lpp_value_start);
187         lpp_flush(comm);
188         ir_timer_pop();
189         lpp->send_time = ir_timer_elapsed_usec(t_send);
190
191         ready = 0;
192         while (! ready) {
193                 int cmd = lpp_readl(comm);
194                 switch(cmd) {
195                         case LPP_CMD_SOLUTION:
196                                 ir_timer_push(t_recv);
197                                 lpp_deserialize_stats(comm, lpp);
198                                 lpp_deserialize_values(comm, lpp, lpp_value_solution);
199                                 ir_timer_pop();
200                                 lpp->recv_time = ir_timer_elapsed_usec(t_recv);
201                                 ready = 1;
202                                 break;
203                         case LPP_CMD_INFO:
204                                 lpp_readbuf(comm, buf, sizeof(buf));
205                                 buf[sizeof(buf) - 1] = '\0';
206
207                                 if(lpp->log != NULL) {
208                                         fputs(buf, lpp->log);
209                                         n = strlen(buf);
210                                         if(buf[n - 1] != '\n')
211                                                 putc('\n', lpp->log);
212                                         fflush(lpp->log);
213                                 }
214                                 break;
215                         case LPP_CMD_BAD:
216                                 fprintf(stderr, "solver process died unexpectedly\n");
217                                 goto end;
218                         default:
219                                 fprintf(stderr, "invalid command: %s(%d)\n", lpp_get_cmd_name(cmd), cmd);
220                                 return;
221                 }
222         }
223
224         lpp_writel(comm, LPP_CMD_BYE);
225         lpp_flush(comm);
226
227 end:
228         lpp_comm_free(comm);
229 #ifdef _WIN32
230         closesocket(fd);
231 #else
232         close(fd);
233 #endif
234 }