Line data Source code
1 : /*----------------------------------------------------------------------------*/
2 : /* CP2K: A general program to perform molecular dynamics simulations */
3 : /* Copyright 2000-2026 CP2K developers group <https://cp2k.org> */
4 : /* */
5 : /* SPDX-License-Identifier: GPL-2.0-or-later */
6 : /*----------------------------------------------------------------------------*/
7 :
8 : /*----------------------------------------------------------------------------*/
9 : /* Copyright (C) 2013, Joshua More and Michele Ceriotti */
10 : /* */
11 : /* Permission is hereby granted, free of charge, to any person obtaining */
12 : /* a copy of this software and associated documentation files (the */
13 : /* "Software"), to deal in the Software without restriction, including */
14 : /* without limitation the rights to use, copy, modify, merge, publish, */
15 : /* distribute, sublicense, and/or sell copies of the Software, and to */
16 : /* permit persons to whom the Software is furnished to do so, subject to */
17 : /* the following conditions: */
18 : /* */
19 : /* The above copyright notice and this permission notice shall be included */
20 : /* in all copies or substantial portions of the Software. */
21 : /* */
22 : /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 : /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 : /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25 : /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 : /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 : /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 : /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 : /*----------------------------------------------------------------------------*/
30 :
31 : /*******************************************************************************
32 : * \brief A minimal wrapper for socket communication.
33 : * Contains both the functions that transmit data to the socket and read
34 : * the data back out again once finished, and the function which opens
35 : * the socket initially. Can be linked to a FORTRAN code that does not
36 : * support sockets natively.
37 : * \author Joshua More and Michele Ceriotti
38 : ******************************************************************************/
39 : #ifndef __NO_SOCKETS
40 :
41 : #define _POSIX_C_SOURCE 200809L
42 :
43 : #include <math.h>
44 : #include <netdb.h>
45 : #include <netinet/in.h>
46 : #include <stdio.h>
47 : #include <stdlib.h>
48 : #include <string.h>
49 : #include <sys/select.h>
50 : #include <sys/socket.h>
51 : #include <sys/types.h>
52 : #include <sys/un.h>
53 : #include <time.h>
54 : #include <unistd.h>
55 :
56 : /*******************************************************************************
57 : * \brief Opens and connects a socket.
58 : * \param psockfd The id of the socket that will be created.
59 : * \param inet An integer that determines whether the socket will be an inet
60 : * or unix domain socket. Gives unix if 0, inet otherwise.
61 : * \param port The port number for the socket to be created. Low numbers are
62 : * often reserved for important channels, so use of numbers of 4
63 : * or more digits is recommended.
64 : * \param host The name of the host server (inet socket), or the full path
65 : * of the UNIX socket file (unix socket). The caller is
66 : * responsible for building this path, e.g. by prepending a
67 : * prefix such as "/tmp/ipi_".
68 : * \note Fortran passes an extra argument for the string length, but this is
69 : * ignored here for C compatibility.
70 : ******************************************************************************/
71 0 : void open_connect_socket(int *psockfd, int *inet, int *port, char *host) {
72 0 : int sockfd, ai_err;
73 :
74 0 : if (*inet > 0) { // creates an internet socket
75 :
76 : // fetches information on the host
77 0 : struct addrinfo hints, *res;
78 0 : char service[256];
79 :
80 0 : memset(&hints, 0, sizeof(hints));
81 0 : hints.ai_socktype = SOCK_STREAM;
82 0 : hints.ai_family = AF_INET;
83 0 : hints.ai_flags = AI_PASSIVE;
84 :
85 0 : sprintf(service, "%d", *port); // convert the port number to a string
86 0 : ai_err = getaddrinfo(host, service, &hints, &res);
87 0 : if (ai_err != 0) {
88 0 : perror("Error fetching host data. Wrong host name?");
89 0 : exit(-1);
90 : }
91 :
92 : // creates socket
93 0 : sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
94 0 : if (sockfd < 0) {
95 0 : perror("Error opening socket");
96 0 : exit(-1);
97 : }
98 :
99 : // makes connection
100 0 : if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
101 0 : perror("Error opening INET socket: wrong port or server unreachable");
102 0 : exit(-1);
103 : }
104 0 : freeaddrinfo(res);
105 : } else { // creates a unix socket
106 0 : struct sockaddr_un serv_addr;
107 :
108 : // fills up details of the socket address
109 0 : memset(&serv_addr, 0, sizeof(serv_addr));
110 0 : serv_addr.sun_family = AF_UNIX;
111 0 : strcpy(serv_addr.sun_path, host);
112 :
113 : // creates the socket
114 0 : sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
115 :
116 : // connects
117 0 : if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
118 0 : perror(
119 : "Error opening UNIX socket: path unavailable, or already existing");
120 0 : exit(-1);
121 : }
122 : }
123 :
124 0 : *psockfd = sockfd;
125 0 : }
126 :
127 : /*******************************************************************************
128 : * \brief Opens and binds a socket.
129 : * \param psockfd The id of the socket that will be created.
130 : * \param inet An integer that determines whether the socket will be an inet
131 : * or unix domain socket. Gives unix if 0, inet otherwise.
132 : * \param port The port number for the socket to be created. Low numbers are
133 : * often reserved for important channels, so use of numbers of 4
134 : * or more digits is recommended.
135 : * \param host The name of the host server.
136 : * \note Fortran passes an extra argument for the string length, but this is
137 : * ignored here for C compatibility.
138 : ******************************************************************************/
139 0 : void open_bind_socket(int *psockfd, int *inet, int *port, char *host) {
140 0 : int sockfd, ai_err;
141 :
142 0 : if (*inet > 0) { // creates an internet socket
143 :
144 : // fetches information on the host
145 0 : struct addrinfo hints, *res;
146 0 : char service[256];
147 :
148 0 : memset(&hints, 0, sizeof(hints));
149 0 : hints.ai_socktype = SOCK_STREAM;
150 0 : hints.ai_family = AF_INET;
151 0 : hints.ai_flags = AI_PASSIVE;
152 :
153 0 : sprintf(service, "%d", *port); // convert the port number to a string
154 0 : ai_err = getaddrinfo(host, service, &hints, &res);
155 0 : if (ai_err != 0) {
156 0 : perror("Error fetching host data. Wrong host name?");
157 0 : exit(-1);
158 : }
159 :
160 : // creates socket
161 0 : sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
162 0 : if (sockfd < 0) {
163 0 : perror("Error opening socket");
164 0 : exit(-1);
165 : }
166 :
167 : // binds
168 0 : if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
169 0 : perror("Error binding INET socket: wrong port or server unreachable");
170 0 : exit(-1);
171 : }
172 0 : freeaddrinfo(res);
173 : } else { // creates a unix socket
174 0 : struct sockaddr_un serv_addr;
175 :
176 : // fills up details of the socket address
177 0 : memset(&serv_addr, 0, sizeof(serv_addr));
178 0 : serv_addr.sun_family = AF_UNIX;
179 0 : strcpy(serv_addr.sun_path, host);
180 :
181 : // creates the socket
182 0 : sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
183 :
184 0 : remove(serv_addr.sun_path);
185 :
186 : // binds
187 0 : if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
188 0 : perror(
189 : "Error binding UNIX socket: path unavailable, or already existing");
190 0 : exit(-1);
191 : }
192 : }
193 :
194 0 : *psockfd = sockfd;
195 0 : }
196 :
197 : /*******************************************************************************
198 : * \brief Writes to a socket.
199 : * \param psockfd The id of the socket that will be written to.
200 : * \param data The data to be written to the socket.
201 : * \param plen The length of the data in bytes.
202 : ******************************************************************************/
203 0 : void writebuffer(int *psockfd, char *data, int *plen) {
204 0 : int n;
205 0 : int sockfd = *psockfd;
206 0 : int len = *plen;
207 :
208 0 : n = write(sockfd, data, len);
209 0 : if (n < 0) {
210 0 : perror("Error writing to socket: server has quit or connection broke");
211 0 : exit(-1);
212 : }
213 0 : }
214 :
215 : /*******************************************************************************
216 : * \brief Reads from a socket.
217 : * \param psockfd The id of the socket that will be read from.
218 : * \param data The storage array for data read from the socket.
219 : * \param plen The length of the data in bytes.
220 : ******************************************************************************/
221 0 : void readbuffer(int *psockfd, char *data, int *plen) {
222 0 : int n, nr;
223 0 : int sockfd = *psockfd;
224 0 : int len = *plen;
225 :
226 0 : n = nr = read(sockfd, data, len);
227 :
228 0 : while (nr > 0 && n < len) {
229 0 : nr = read(sockfd, &data[n], len - n);
230 0 : n += nr;
231 : }
232 :
233 0 : if (n == 0) {
234 0 : perror("Error reading from socket: server has quit or connection broke");
235 0 : exit(-1);
236 : }
237 0 : }
238 :
239 : /*******************************************************************************
240 : * \brief Listens to a socket.
241 : * \param psockfd The id of the socket to listen.
242 : * \param n An integer that determines the number of requests that will
243 : * be queued before further requests are refused.
244 : ******************************************************************************/
245 0 : void listen_socket(int *psockfd, int *backlog) {
246 :
247 0 : if (listen(*psockfd, *backlog) < 0) {
248 0 : perror("Error listening socket");
249 0 : exit(-1);
250 0 : };
251 0 : }
252 :
253 : /*******************************************************************************
254 : * \brief Listens to a socket.
255 : * \param psockfd The id of the socket to listen.
256 : * \param pclientfd The id of the accepted socket.
257 : ******************************************************************************/
258 0 : void accept_socket(int *psockfd, int *pclientfd) {
259 :
260 0 : int client_fd = accept(*psockfd, NULL, NULL);
261 :
262 0 : *pclientfd = client_fd;
263 0 : }
264 :
265 : /*******************************************************************************
266 : * \brief Closes a socket.
267 : * \param psockfd The id of the socket to close.
268 : ******************************************************************************/
269 0 : void close_socket(int *psockfd) { close(*psockfd); }
270 :
271 : /*******************************************************************************
272 : * \brief Removes a socket file.
273 : * \param hostname The name of the socket file to remove.
274 : ******************************************************************************/
275 0 : void remove_socket_file(char *host) { remove(host); }
276 :
277 : /*******************************************************************************
278 : * \brief Mini-wrapper to nanosleep
279 : * \param dsec number of seconds to wait (float values accepted)
280 : ******************************************************************************/
281 0 : void uwait(double *dsec) {
282 0 : struct timespec wt, rem;
283 0 : wt.tv_sec = floor(*dsec);
284 0 : wt.tv_nsec = (*dsec - wt.tv_sec) * 1000000000;
285 0 : nanosleep(&wt, &rem);
286 0 : }
287 :
288 : #endif
|