Simplified uniform GPU selection in CMake
[gromacs.git] / src / gromacs / imd / imdsocket.cpp
blob4b45b71c990f76731a54d2933ca7bfc8ad002656
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
5 * Copyright (c) 2019,2020, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
37 /*! \internal \file
39 * \brief
40 * Implements functions of imdsocket.h.
42 * This file re-implements vmdsock.c functions from original IMD API from scratch,
43 * see imdsocket.h for references to the IMD API.
45 * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
47 * \ingroup module_imd
50 #include "gmxpre.h"
52 #include "imdsocket.h"
54 #include "config.h"
56 #include <cerrno>
57 #include <cstring>
58 #include <ctime>
60 #include "gromacs/imd/imd.h"
61 #include "gromacs/utility/fatalerror.h"
62 #include "gromacs/utility/smalloc.h"
64 #if GMX_IMD
66 # if GMX_NATIVE_WINDOWS
68 # include <Windows.h>
69 # include <Winsock.h>
71 //! Constant for passing no flags
72 constexpr int c_noFlags = 0;
73 /*! \brief Define socklen type on Windows. */
74 typedef int socklen_t;
76 # else
78 # include <unistd.h>
79 # include <netinet/in.h>
80 # include <sys/select.h>
81 # include <sys/socket.h>
82 # include <sys/time.h>
84 # endif
86 #endif
88 namespace gmx
91 /*! \internal
93 * \brief
94 * IMD (interactive molecular dynamics) socket structure
97 struct IMDSocket
99 #if GMX_IMD
100 struct sockaddr_in address; /**< address of socket */
101 int sockfd; /**< socket file descriptor */
102 #endif
105 /*! \brief Define a function to initialize winsock. */
106 int imdsock_winsockinit()
108 #if GMX_IMD && GMX_NATIVE_WINDOWS
109 fprintf(stderr, "%s Initializing winsock.\n", IMDstr);
110 int ret = -1;
112 WSADATA wsd;
114 /* We use winsock 1.1 compatibility for now. Though I guess no one will try on Windows 95. */
115 ret = WSAStartup(MAKEWORD(1, 1), &wsd);
116 return ret;
117 #else
118 return 0;
119 #endif
123 /*! \brief Simple error handling. */
124 #if GMX_NATIVE_WINDOWS
125 # define ERR_ARGS __FILE__, __LINE__, NULL
126 #else
127 # define ERR_ARGS __FILE__, __LINE__, strerror(errno)
128 #endif
131 /*! \brief Currently only 1 client connection is supported. */
132 constexpr int c_maxConnections = 1;
135 /*! \brief Print a nice error message on UNIX systems, using errno.h. */
136 static void print_IMD_error(const char* file, int line, char* msg)
138 fprintf(stderr, "%s Error in file %s on line %d.\n", IMDstr, file, line);
140 if (nullptr != msg)
142 fprintf(stderr, "%s\n", msg);
147 IMDSocket* imdsock_create()
149 IMDSocket* sock = nullptr;
152 #if GMX_IMD
153 snew(sock, 1);
154 /* Try to create socket: */
155 if ((sock->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
157 print_IMD_error(ERR_ARGS);
158 sfree(sock);
160 return nullptr;
162 else
163 #endif
165 return sock;
169 void imd_sleep(unsigned int seconds)
171 #if GMX_IMD
172 # if GMX_NATIVE_WINDOWS
173 Sleep(seconds);
174 # else
175 sleep(seconds);
176 # endif
177 #else
178 GMX_UNUSED_VALUE(seconds);
179 #endif
183 int imdsock_bind(IMDSocket* sock, int port)
185 int ret;
188 #if GMX_IMD
189 memset(&(sock->address), 0, sizeof(sock->address));
190 sock->address.sin_family = PF_INET;
191 sock->address.sin_port = htons(port);
193 /* Try to bind to address and port ...*/
194 ret = bind(sock->sockfd, reinterpret_cast<struct sockaddr*>(&sock->address), sizeof(sock->address));
195 #else
196 GMX_UNUSED_VALUE(port);
197 GMX_UNUSED_VALUE(sock);
198 ret = -1;
199 #endif
201 if (ret)
203 print_IMD_error(ERR_ARGS);
206 return ret;
210 int imd_sock_listen(IMDSocket* sock)
212 int ret;
215 #if GMX_IMD
216 /* Try to set to listening state */
217 ret = listen(sock->sockfd, c_maxConnections);
218 #else
219 GMX_UNUSED_VALUE(c_maxConnections);
220 GMX_UNUSED_VALUE(sock);
221 ret = -1;
222 #endif
224 if (ret)
226 print_IMD_error(ERR_ARGS);
229 return ret;
233 IMDSocket* imdsock_accept(IMDSocket* sock)
236 #if GMX_IMD
237 socklen_t length = sizeof(sock->address);
238 int ret = accept(sock->sockfd, reinterpret_cast<struct sockaddr*>(&sock->address), &length);
240 /* successful, redirect to distinct clientsocket */
241 if (ret >= 0)
243 IMDSocket* newsock;
245 snew(newsock, 1);
246 newsock->address = sock->address;
247 newsock->sockfd = ret;
249 return newsock;
251 else
252 #else
253 GMX_UNUSED_VALUE(sock);
254 #endif
256 print_IMD_error(ERR_ARGS);
258 return nullptr;
263 int imdsock_getport(IMDSocket* sock, int* port)
265 int ret;
266 #if GMX_IMD
267 socklen_t len;
270 len = sizeof(struct sockaddr_in);
271 ret = getsockname(sock->sockfd, reinterpret_cast<struct sockaddr*>(&(sock->address)), &len);
272 if (ret)
274 fprintf(stderr, "%s getsockname failed with error %d.\n", IMDstr, ret);
275 print_IMD_error(ERR_ARGS);
277 else
279 *port = ntohs(sock->address.sin_port);
281 #else
282 GMX_UNUSED_VALUE(port);
283 GMX_UNUSED_VALUE(sock);
284 gmx_incons("imdsock_getport called without IMD support.");
285 ret = -1;
286 #endif
288 return ret;
292 int imd_htonl(int src)
294 #if GMX_IMD
295 return htonl(src);
296 #else
297 return src;
298 #endif
301 int imd_ntohl(int src)
303 #if GMX_IMD
304 return ntohl(src);
305 #else
306 return src;
307 #endif
310 int imdsock_write(IMDSocket* sock, const char* buffer, int length)
312 #if GMX_IMD
313 /* No read and write on windows, we have to use send and recv instead... */
314 # if GMX_NATIVE_WINDOWS
315 return send(sock->sockfd, (const char*)buffer, length, c_noFlags);
316 # else
317 return write(sock->sockfd, buffer, length);
318 # endif
319 #else
320 GMX_UNUSED_VALUE(buffer);
321 GMX_UNUSED_VALUE(length);
322 GMX_UNUSED_VALUE(sock);
323 return 0;
324 #endif
328 int imdsock_read(IMDSocket* sock, char* buffer, int length)
330 #if GMX_IMD
331 /* See above... */
332 # if GMX_NATIVE_WINDOWS
333 return recv(sock->sockfd, (char*)buffer, length, c_noFlags);
334 # else
335 return read(sock->sockfd, buffer, length);
336 # endif
337 #else
338 GMX_UNUSED_VALUE(buffer);
339 GMX_UNUSED_VALUE(length);
340 GMX_UNUSED_VALUE(sock);
341 return 0;
342 #endif
346 void imdsock_shutdown(IMDSocket* sock)
348 int ret = -1;
351 /* is the socket already NULL? */
352 if (sock == nullptr)
354 return;
357 #if GMX_IMD
358 /* If not, try to properly shut down. */
359 ret = shutdown(sock->sockfd, 1);
360 #endif
362 if (ret == -1)
364 fprintf(stderr, "%s Failed to shutdown socket. Did the client already disconnect?\n", IMDstr);
365 print_IMD_error(ERR_ARGS);
370 int imdsock_destroy(IMDSocket* sock)
372 int ret = -1;
375 if (sock == nullptr)
377 return 1;
380 #if GMX_IMD
381 # if GMX_NATIVE_WINDOWS
382 ret = closesocket(sock->sockfd);
383 # else
384 ret = close(sock->sockfd);
385 # endif
386 #endif
388 if (ret == -1)
390 sfree(sock);
391 print_IMD_error(ERR_ARGS);
393 return 0;
396 return 1;
400 int imdsock_tryread(IMDSocket* sock, int timeoutsec, int timeoutusec)
402 int ret = -1;
405 #if GMX_IMD
406 fd_set readfds;
407 /* Create new time structure with sec and usec. */
408 struct timeval* tval;
411 snew(tval, 1);
413 /* clear the set */
414 FD_ZERO(&readfds);
415 /* add the socket to the read set */
416 FD_SET(sock->sockfd, &readfds);
418 /* set the timeout */
419 tval->tv_sec = timeoutsec;
420 tval->tv_usec = timeoutusec;
423 /* check the set for read readiness. */
424 ret = select(sock->sockfd + 1, &readfds, nullptr, nullptr, tval);
425 /* 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