Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / imd / imdsocket.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 /*! \internal \file
37  *
38  * \brief
39  * Implements functions of imdsocket.h.
40  *
41  * This file re-implements vmdsock.c functions from original IMD API from scratch,
42  * see imdsocket.h for references to the IMD API.
43  *
44  * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
45  *
46  * \ingroup module_imd
47  */
48
49 #include "gmxpre.h"
50
51 #include "imdsocket.h"
52
53 #include "config.h"
54
55 #include <errno.h>
56 #include <string.h>
57
58 #include "gromacs/imd/imd.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/smalloc.h"
61
62 #ifdef GMX_NATIVE_WINDOWS
63 #ifdef GMX_HAVE_WINSOCK
64 /*! \brief Define socklen type on Windows. */
65 typedef int socklen_t;
66
67 /*! \brief Define a function to initialize winsock. */
68 extern int imdsock_winsockinit()
69 {
70     int ret = -1;
71
72
73     WSADATA wsd;
74
75     /* We use winsock 1.1 compatibility for now. Though I guess no one will try on Windows 95. */
76     ret = WSAStartup(MAKEWORD(1, 1), &wsd);
77     return ret;
78 }
79 #endif
80 #else
81 /* On UNIX, we can use nice errors from errno.h */
82 #include <unistd.h>
83 #endif
84
85
86 /*! \brief Simple error handling. */
87 #ifdef GMX_NATIVE_WINDOWS
88 #define ERR_ARGS __FILE__, __LINE__, NULL
89 #else
90 #define ERR_ARGS __FILE__, __LINE__, strerror(errno)
91 #endif
92
93
94 /*! \brief Currently only 1 client connection is supported. */
95 #define MAXIMDCONNECTIONS 1
96
97
98 /*! \brief Print a nice error message on UNIX systems, using errno.h. */
99 static void print_IMD_error(char *file, int line, char *msg)
100 {
101     fprintf(stderr, "%s Error in file %s on line %d.\n", IMDstr, file, line);
102
103     if (NULL != msg)
104     {
105         fprintf(stderr, "%s\n", msg);
106     }
107 }
108
109
110 extern IMDSocket* imdsock_create()
111 {
112     IMDSocket *sock = NULL;
113
114
115 #ifdef GMX_IMD
116     snew(sock, 1);
117     /* Try to create socket: */
118     if ((sock->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
119     {
120         print_IMD_error(ERR_ARGS);
121         sfree(sock);
122
123         return NULL;
124     }
125     else
126 #endif
127     {
128         return sock;
129     }
130 }
131
132
133 extern int imdsock_bind(IMDSocket *sock, int port)
134 {
135     int ret;
136
137
138 #ifdef GMX_IMD
139     memset(&(sock->address), 0, sizeof(sock->address));
140     sock->address.sin_family = PF_INET;
141     sock->address.sin_port   = htons(port);
142
143     /* Try to bind to address and port ...*/
144     ret = bind(sock->sockfd, (struct sockaddr *) &sock->address, sizeof(sock->address));
145 #else
146     ret = -1;
147 #endif
148
149     if (ret)
150     {
151         print_IMD_error(ERR_ARGS);
152     }
153
154     return ret;
155 }
156
157
158 extern int imd_sock_listen(IMDSocket *sock)
159 {
160     int ret;
161
162
163 #ifdef GMX_IMD
164     /* Try to set to listening state */
165     ret = listen(sock->sockfd, MAXIMDCONNECTIONS);
166 #else
167     ret = -1;
168 #endif
169
170     if (ret)
171     {
172         print_IMD_error(ERR_ARGS);
173     }
174
175     return ret;
176 }
177
178
179 extern IMDSocket* imdsock_accept(IMDSocket *sock)
180 {
181     int       ret;
182
183 #ifdef GMX_IMD
184     socklen_t length;
185
186
187     length = sizeof(sock->address);
188     ret    = accept(sock->sockfd, (struct sockaddr *) &sock->address, &length);
189
190     /* successful, redirect to distinct clientsocket */
191     if (ret >= 0)
192     {
193         IMDSocket *newsock;
194
195         snew(newsock, 1);
196         newsock->address    = sock->address;
197         newsock->sockfd     = ret;
198
199         return newsock;
200     }
201     else
202 #endif
203     {
204         print_IMD_error(ERR_ARGS);
205
206         return NULL;
207     }
208 }
209
210
211 extern int imdsock_getport(IMDSocket *sock, int *port)
212 {
213     int                ret;
214 #ifdef GMX_IMD
215     struct sockaddr_in sin;
216     socklen_t          len;
217
218
219     len = sizeof(sin);
220     ret = getsockname(sock->sockfd, (struct sockaddr *) &(sock->address), &len);
221     if (ret)
222     {
223         fprintf(stderr, "%s getsockname failed with error %d.\n", IMDstr, ret);
224         print_IMD_error(ERR_ARGS);
225     }
226     else
227     {
228         *port = ntohs(sock->address.sin_port);
229     }
230 #else
231     gmx_incons("imdsock_getport called without IMD support.");
232 #endif
233
234     return ret;
235 }
236
237
238 extern int imdsock_write(IMDSocket *sock, const char *buffer, int length)
239 {
240     /* No read and write on windows, we have to use send and recv instead... */
241 #ifdef GMX_NATIVE_WINDOWS
242 #ifdef GMX_HAVE_WINSOCK
243     return send(sock->sockfd, (const char *) buffer, length, NOFLAGS);
244 #else
245     return -1;
246 #endif
247 #else
248     return write(sock->sockfd, buffer, length);
249 #endif
250 }
251
252
253 extern int imdsock_read(IMDSocket *sock, char *buffer, int length)
254 {
255     /* See above... */
256 #ifdef GMX_NATIVE_WINDOWS
257 #ifdef GMX_HAVE_WINSOCK
258     return recv(sock->sockfd, (char *) buffer, length, NOFLAGS);
259 #else
260     return -1;
261 #endif
262 #else
263     return read(sock->sockfd, buffer, length);
264 #endif
265 }
266
267
268 extern void imdsock_shutdown(IMDSocket *sock)
269 {
270     int ret = -1;
271
272
273     /* is the socket already NULL? */
274     if (sock == NULL)
275     {
276         return;
277     }
278
279 #ifdef GMX_IMD
280     /* If not, try to properly shut down. */
281     ret = shutdown(sock->sockfd, 1);
282 #endif
283
284     if (ret == -1)
285     {
286         fprintf(stderr, "%s Failed to shutdown socket. Did the client already disconnect?\n", IMDstr);
287         print_IMD_error(ERR_ARGS);
288     }
289 }
290
291
292 extern int imdsock_destroy(IMDSocket *sock)
293 {
294     int ret = -1;
295
296
297     if (sock == NULL)
298     {
299         return 1;
300     }
301
302 #ifdef GMX_NATIVE_WINDOWS
303     /* On Windows, this function is called closesocket */
304 #ifdef GMX_HAVE_WINSOCK
305     ret = closesocket(sock->sockfd);
306 #endif
307 #else
308     ret = close(sock->sockfd);
309 #endif
310
311     if (ret == -1)
312     {
313         sfree(sock);
314         print_IMD_error(ERR_ARGS);
315
316         return 0;
317     }
318
319     return 1;
320 }
321
322
323 extern int imdsock_tryread(IMDSocket *sock, int timeoutsec, int timeoutusec)
324 {
325     int             ret = -1;
326
327
328 #ifdef GMX_IMD
329     fd_set          readfds;
330     /* Create new time structure with sec and usec. */
331     struct timeval *tval;
332
333
334     snew(tval, 1);
335
336     /* clear the set */
337     FD_ZERO(&readfds);
338     /* add the socket to the read set */
339     FD_SET(sock->sockfd, &readfds);
340
341     /* set the timeout */
342     tval->tv_sec  = timeoutsec;
343     tval->tv_usec = timeoutusec;
344     do
345     {
346         /* check the set for read readiness. */
347         ret = select(sock->sockfd + 1, &readfds, NULL, NULL, tval);
348         /* redo on system interrupt */
349     }
350     while (ret < 0 && errno == EINTR);
351
352     sfree(tval);
353 #endif
354
355     if (ret < 0)
356     {
357         print_IMD_error(ERR_ARGS);
358     }
359
360     return ret;
361 }