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