Introduce SimulatorBuilder
[gromacs.git] / src / gromacs / imd / imdsocket.cpp
blob67e6abde81f6786b4b53e6b4b0bb50c0cba8517d
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2014,2015,2016,2017,2018,2019, 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.
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.
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.
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.
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.
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.
36 /*! \internal \file
38 * \brief
39 * Implements functions of imdsocket.h.
41 * This file re-implements vmdsock.c functions from original IMD API from scratch,
42 * see imdsocket.h for references to the IMD API.
44 * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
46 * \ingroup module_imd
49 #include "gmxpre.h"
51 #include "imdsocket.h"
53 #include "config.h"
55 #include <cerrno>
56 #include <cstring>
57 #include <ctime>
59 #include "gromacs/imd/imd.h"
60 #include "gromacs/utility/fatalerror.h"
61 #include "gromacs/utility/smalloc.h"
63 #if GMX_IMD
65 #if GMX_NATIVE_WINDOWS
67 #include <Windows.h>
68 #include <Winsock.h>
70 //! Constant for passing no flags
71 constexpr int c_noFlags = 0;
72 /*! \brief Define socklen type on Windows. */
73 typedef int socklen_t;
75 #else
77 #include <unistd.h>
78 #include <netinet/in.h>
79 #include <sys/select.h>
80 #include <sys/socket.h>
81 #include <sys/time.h>
83 #endif
85 #endif
87 namespace gmx
90 /*! \internal
92 * \brief
93 * IMD (interactive molecular dynamics) socket structure
96 struct IMDSocket
98 #if GMX_IMD
99 struct sockaddr_in address; /**< address of socket */
100 int sockfd; /**< socket file descriptor */
101 #endif
104 /*! \brief Define a function to initialize winsock. */
105 int imdsock_winsockinit()
107 #if GMX_IMD && GMX_NATIVE_WINDOWS
108 fprintf(stderr, "%s Initializing winsock.\n", IMDstr);
109 int ret = -1;
111 WSADATA wsd;
113 /* We use winsock 1.1 compatibility for now. Though I guess no one will try on Windows 95. */
114 ret = WSAStartup(MAKEWORD(1, 1), &wsd);
115 return ret;
116 #else
117 return 0;
118 #endif
122 /*! \brief Simple error handling. */
123 #if GMX_NATIVE_WINDOWS
124 #define ERR_ARGS __FILE__, __LINE__, NULL
125 #else
126 #define ERR_ARGS __FILE__, __LINE__, strerror(errno)
127 #endif
130 /*! \brief Currently only 1 client connection is supported. */
131 constexpr int c_maxConnections = 1;
134 /*! \brief Print a nice error message on UNIX systems, using errno.h. */
135 static void print_IMD_error(const char *file, int line, char *msg)
137 fprintf(stderr, "%s Error in file %s on line %d.\n", IMDstr, file, line);
139 if (nullptr != msg)
141 fprintf(stderr, "%s\n", msg);
146 IMDSocket* imdsock_create()
148 IMDSocket *sock = nullptr;
151 #if GMX_IMD
152 snew(sock, 1);
153 /* Try to create socket: */
154 if ((sock->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
156 print_IMD_error(ERR_ARGS);
157 sfree(sock);
159 return nullptr;
161 else
162 #endif
164 return sock;
168 void imd_sleep(unsigned int seconds)
170 #if GMX_IMD
171 #if GMX_NATIVE_WINDOWS
172 Sleep(seconds);
173 #else
174 sleep(seconds);
175 #endif
176 #else
177 GMX_UNUSED_VALUE(seconds);
178 #endif
182 int imdsock_bind(IMDSocket *sock, int port)
184 int ret;
187 #if GMX_IMD
188 memset(&(sock->address), 0, sizeof(sock->address));
189 sock->address.sin_family = PF_INET;
190 sock->address.sin_port = htons(port);
192 /* Try to bind to address and port ...*/
193 ret = bind(sock->sockfd, reinterpret_cast<struct sockaddr *>(&sock->address), sizeof(sock->address));
194 #else
195 GMX_UNUSED_VALUE(port);
196 GMX_UNUSED_VALUE(sock);
197 ret = -1;
198 #endif
200 if (ret)
202 print_IMD_error(ERR_ARGS);
205 return ret;
209 int imd_sock_listen(IMDSocket *sock)
211 int ret;
214 #if GMX_IMD
215 /* Try to set to listening state */
216 ret = listen(sock->sockfd, c_maxConnections);
217 #else
218 GMX_UNUSED_VALUE(c_maxConnections);
219 GMX_UNUSED_VALUE(sock);
220 ret = -1;
221 #endif
223 if (ret)
225 print_IMD_error(ERR_ARGS);
228 return ret;
232 IMDSocket* imdsock_accept(IMDSocket *sock)
235 #if GMX_IMD
236 socklen_t length = sizeof(sock->address);
237 int ret = accept(sock->sockfd, reinterpret_cast<struct sockaddr *>(&sock->address), &length);
239 /* successful, redirect to distinct clientsocket */
240 if (ret >= 0)
242 IMDSocket *newsock;
244 snew(newsock, 1);
245 newsock->address = sock->address;
246 newsock->sockfd = ret;
248 return newsock;
250 else
251 #else
252 GMX_UNUSED_VALUE(sock);
253 #endif
255 print_IMD_error(ERR_ARGS);
257 return nullptr;
262 int imdsock_getport(IMDSocket *sock, int *port)
264 int ret;
265 #if GMX_IMD
266 socklen_t len;
269 len = sizeof(struct sockaddr_in);
270 ret = getsockname(sock->sockfd, reinterpret_cast<struct sockaddr *>(&(sock->address)), &len);
271 if (ret)
273 fprintf(stderr, "%s getsockname failed with error %d.\n", IMDstr, ret);
274 print_IMD_error(ERR_ARGS);
276 else
278 *port = ntohs(sock->address.sin_port);
280 #else
281 GMX_UNUSED_VALUE(port);
282 GMX_UNUSED_VALUE(sock);
283 gmx_incons("imdsock_getport called without IMD support.");
284 ret = -1;
285 #endif
287 return ret;
291 int imd_htonl(int src)
293 #if GMX_IMD
294 return htonl(src);
295 #else
296 return src;
297 #endif
300 int imd_ntohl(int src)
302 #if GMX_IMD
303 return ntohl(src);
304 #else
305 return src;
306 #endif
309 int imdsock_write(IMDSocket *sock, const char *buffer, int length)
311 #if GMX_IMD
312 /* No read and write on windows, we have to use send and recv instead... */
313 #if GMX_NATIVE_WINDOWS
314 return send(sock->sockfd, (const char *) buffer, length, c_noFlags);
315 #else
316 return write(sock->sockfd, buffer, length);
317 #endif
318 #else
319 GMX_UNUSED_VALUE(buffer);
320 GMX_UNUSED_VALUE(length);
321 GMX_UNUSED_VALUE(sock);
322 return 0;
323 #endif
327 int imdsock_read(IMDSocket *sock, char *buffer, int length)
329 #if GMX_IMD
330 /* See above... */
331 #if GMX_NATIVE_WINDOWS
332 return recv(sock->sockfd, (char *) buffer, length, c_noFlags);
333 #else
334 return read(sock->sockfd, buffer, length);
335 #endif
336 #else
337 GMX_UNUSED_VALUE(buffer);
338 GMX_UNUSED_VALUE(length);
339 GMX_UNUSED_VALUE(sock);
340 return 0;
341 #endif
345 void imdsock_shutdown(IMDSocket *sock)
347 int ret = -1;
350 /* is the socket already NULL? */
351 if (sock == nullptr)
353 return;
356 #if GMX_IMD
357 /* If not, try to properly shut down. */
358 ret = shutdown(sock->sockfd, 1);
359 #endif
361 if (ret == -1)
363 fprintf(stderr, "%s Failed to shutdown socket. Did the client already disconnect?\n", IMDstr);
364 print_IMD_error(ERR_ARGS);
369 int imdsock_destroy(IMDSocket *sock)
371 int ret = -1;
374 if (sock == nullptr)
376 return 1;
379 #if GMX_IMD
380 #if GMX_NATIVE_WINDOWS
381 ret = closesocket(sock->sockfd);
382 #else
383 ret = close(sock->sockfd);
384 #endif
385 #endif
387 if (ret == -1)
389 sfree(sock);
390 print_IMD_error(ERR_ARGS);
392 return 0;
395 return 1;
399 int imdsock_tryread(IMDSocket *sock, int timeoutsec, int timeoutusec)
401 int ret = -1;
404 #if GMX_IMD
405 fd_set readfds;
406 /* Create new time structure with sec and usec. */
407 struct timeval *tval;
410 snew(tval, 1);
412 /* clear the set */
413 FD_ZERO(&readfds);
414 /* add the socket to the read set */
415 FD_SET(sock->sockfd, &readfds);
417 /* set the timeout */
418 tval->tv_sec = timeoutsec;
419 tval->tv_usec = timeoutusec;
422 /* check the set for read readiness. */
423 ret = select(sock->sockfd + 1, &readfds, nullptr, nullptr, tval);
424 /* redo on system interrupt */
426 while (ret < 0 && errno == EINTR);
428 sfree(tval);
429 #else
430 GMX_UNUSED_VALUE(sock);
431 GMX_UNUSED_VALUE(timeoutsec);
432 GMX_UNUSED_VALUE(timeoutusec);
433 #endif
435 if (ret < 0)
437 print_IMD_error(ERR_ARGS);
440 return ret;
443 } // namespace gmx