Line data Source code
1 : /*----------------------------------------------------------------------------*/
2 : /* CP2K: A general program to perform molecular dynamics simulations */
3 : /* Copyright 2000-2024 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.
65 : * \note Fortran passes an extra argument for the string length, but this is
66 : * ignored here for C compatibility.
67 : ******************************************************************************/
68 0 : void open_connect_socket(int *psockfd, int *inet, int *port, char *host) {
69 0 : int sockfd, ai_err;
70 :
71 0 : if (*inet > 0) { // creates an internet socket
72 :
73 : // fetches information on the host
74 0 : struct addrinfo hints, *res;
75 0 : char service[256];
76 :
77 0 : memset(&hints, 0, sizeof(hints));
78 0 : hints.ai_socktype = SOCK_STREAM;
79 0 : hints.ai_family = AF_INET;
80 0 : hints.ai_flags = AI_PASSIVE;
81 :
82 0 : sprintf(service, "%d", *port); // convert the port number to a string
83 0 : ai_err = getaddrinfo(host, service, &hints, &res);
84 0 : if (ai_err != 0) {
85 0 : perror("Error fetching host data. Wrong host name?");
86 0 : exit(-1);
87 : }
88 :
89 : // creates socket
90 0 : sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
91 0 : if (sockfd < 0) {
92 0 : perror("Error opening socket");
93 0 : exit(-1);
94 : }
95 :
96 : // makes connection
97 0 : if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
98 0 : perror("Error opening INET socket: wrong port or server unreachable");
99 0 : exit(-1);
100 : }
101 0 : freeaddrinfo(res);
102 : } else { // creates a unix socket
103 0 : struct sockaddr_un serv_addr;
104 :
105 : // fills up details of the socket address
106 0 : memset(&serv_addr, 0, sizeof(serv_addr));
107 0 : serv_addr.sun_family = AF_UNIX;
108 0 : strcpy(serv_addr.sun_path, "/tmp/qiskit_");
109 0 : strcpy(serv_addr.sun_path + 12, host);
110 :
111 : // creates the socket
112 0 : sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
113 :
114 : // connects
115 0 : if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
116 0 : perror(
117 : "Error opening UNIX socket: path unavailable, or already existing");
118 0 : exit(-1);
119 : }
120 : }
121 :
122 0 : *psockfd = sockfd;
123 0 : }
124 :
125 : /*******************************************************************************
126 : * \brief Opens and binds a socket.
127 : * \param psockfd The id of the socket that will be created.
128 : * \param inet An integer that determines whether the socket will be an inet
129 : * or unix domain socket. Gives unix if 0, inet otherwise.
130 : * \param port The port number for the socket to be created. Low numbers are
131 : * often reserved for important channels, so use of numbers of 4
132 : * or more digits is recommended.
133 : * \param host The name of the host server.
134 : * \note Fortran passes an extra argument for the string length, but this is
135 : * ignored here for C compatibility.
136 : ******************************************************************************/
137 0 : void open_bind_socket(int *psockfd, int *inet, int *port, char *host) {
138 0 : int sockfd, ai_err;
139 :
140 0 : if (*inet > 0) { // creates an internet socket
141 :
142 : // fetches information on the host
143 0 : struct addrinfo hints, *res;
144 0 : char service[256];
145 :
146 0 : memset(&hints, 0, sizeof(hints));
147 0 : hints.ai_socktype = SOCK_STREAM;
148 0 : hints.ai_family = AF_INET;
149 0 : hints.ai_flags = AI_PASSIVE;
150 :
151 0 : sprintf(service, "%d", *port); // convert the port number to a string
152 0 : ai_err = getaddrinfo(host, service, &hints, &res);
153 0 : if (ai_err != 0) {
154 0 : perror("Error fetching host data. Wrong host name?");
155 0 : exit(-1);
156 : }
157 :
158 : // creates socket
159 0 : sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
160 0 : if (sockfd < 0) {
161 0 : perror("Error opening socket");
162 0 : exit(-1);
163 : }
164 :
165 : // binds
166 0 : if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
167 0 : perror("Error binding INET socket: wrong port or server unreachable");
168 0 : exit(-1);
169 : }
170 0 : freeaddrinfo(res);
171 : } else { // creates a unix socket
172 0 : struct sockaddr_un serv_addr;
173 :
174 : // fills up details of the socket address
175 0 : memset(&serv_addr, 0, sizeof(serv_addr));
176 0 : serv_addr.sun_family = AF_UNIX;
177 0 : strcpy(serv_addr.sun_path, host);
178 :
179 : // creates the socket
180 0 : sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
181 :
182 0 : remove(serv_addr.sun_path);
183 :
184 : // binds
185 0 : if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
186 0 : perror(
187 : "Error binding UNIX socket: path unavailable, or already existing");
188 0 : exit(-1);
189 : }
190 : }
191 :
192 0 : *psockfd = sockfd;
193 0 : }
194 :
195 : /*******************************************************************************
196 : * \brief Writes to a socket.
197 : * \param psockfd The id of the socket that will be written to.
198 : * \param data The data to be written to the socket.
199 : * \param plen The length of the data in bytes.
200 : ******************************************************************************/
201 0 : void writebuffer(int *psockfd, char *data, int *plen) {
202 0 : int n;
203 0 : int sockfd = *psockfd;
204 0 : int len = *plen;
205 :
206 0 : n = write(sockfd, data, len);
207 0 : if (n < 0) {
208 0 : perror("Error writing to socket: server has quit or connection broke");
209 0 : exit(-1);
210 : }
211 0 : }
212 :
213 : /*******************************************************************************
214 : * \brief Reads from a socket.
215 : * \param psockfd The id of the socket that will be read from.
216 : * \param data The storage array for data read from the socket.
217 : * \param plen The length of the data in bytes.
218 : ******************************************************************************/
219 0 : void readbuffer(int *psockfd, char *data, int *plen) {
220 0 : int n, nr;
221 0 : int sockfd = *psockfd;
222 0 : int len = *plen;
223 :
224 0 : n = nr = read(sockfd, data, len);
225 :
226 0 : while (nr > 0 && n < len) {
227 0 : nr = read(sockfd, &data[n], len - n);
228 0 : n += nr;
229 : }
230 :
231 0 : if (n == 0) {
232 0 : perror("Error reading from socket: server has quit or connection broke");
233 0 : exit(-1);
234 : }
235 0 : }
236 :
237 : /*******************************************************************************
238 : * \brief Listens to a socket.
239 : * \param psockfd The id of the socket to listen.
240 : * \param n An integer that determines the number of requests that will
241 : * be queued before further requests are refused.
242 : ******************************************************************************/
243 0 : void listen_socket(int *psockfd, int *backlog) {
244 :
245 0 : if (listen(*psockfd, *backlog) < 0) {
246 0 : perror("Error listening socket");
247 0 : exit(-1);
248 0 : };
249 0 : }
250 :
251 : /*******************************************************************************
252 : * \brief Listens to a socket.
253 : * \param psockfd The id of the socket to listen.
254 : * \param pclientfd The id of the accepted socket.
255 : ******************************************************************************/
256 0 : void accept_socket(int *psockfd, int *pclientfd) {
257 :
258 0 : int client_fd = accept(*psockfd, NULL, NULL);
259 :
260 0 : *pclientfd = client_fd;
261 0 : }
262 :
263 : /*******************************************************************************
264 : * \brief Closes a socket.
265 : * \param psockfd The id of the socket to close.
266 : ******************************************************************************/
267 0 : void close_socket(int *psockfd) { close(*psockfd); }
268 :
269 : /*******************************************************************************
270 : * \brief Removes a socket file.
271 : * \param hostname The name of the socket file to remove.
272 : ******************************************************************************/
273 0 : void remove_socket_file(char *host) { remove(host); }
274 :
275 : /*******************************************************************************
276 : * \brief Mini-wrapper to nanosleep
277 : * \param dsec number of seconds to wait (float values accepted)
278 : ******************************************************************************/
279 0 : void uwait(double *dsec) {
280 0 : struct timespec wt, rem;
281 0 : wt.tv_sec = floor(*dsec);
282 0 : wt.tv_nsec = (*dsec - wt.tv_sec) * 1000000000;
283 0 : nanosleep(&wt, &rem);
284 0 : }
285 :
286 : #endif
|