(git:24d69ee)
Loading...
Searching...
No Matches
sockets.c
Go to the documentation of this file.
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 ******************************************************************************/
71void open_connect_socket(int *psockfd, int *inet, int *port, char *host) {
72 int sockfd, ai_err;
73
74 if (*inet > 0) { // creates an internet socket
75
76 // fetches information on the host
77 struct addrinfo hints, *res;
78 char service[256];
79
80 memset(&hints, 0, sizeof(hints));
81 hints.ai_socktype = SOCK_STREAM;
82 hints.ai_family = AF_INET;
83 hints.ai_flags = AI_PASSIVE;
84
85 sprintf(service, "%d", *port); // convert the port number to a string
86 ai_err = getaddrinfo(host, service, &hints, &res);
87 if (ai_err != 0) {
88 perror("Error fetching host data. Wrong host name?");
89 exit(-1);
90 }
91
92 // creates socket
93 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
94 if (sockfd < 0) {
95 perror("Error opening socket");
96 exit(-1);
97 }
98
99 // makes connection
100 if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
101 perror("Error opening INET socket: wrong port or server unreachable");
102 exit(-1);
103 }
104 freeaddrinfo(res);
105 } else { // creates a unix socket
106 struct sockaddr_un serv_addr;
107
108 // fills up details of the socket address
109 memset(&serv_addr, 0, sizeof(serv_addr));
110 serv_addr.sun_family = AF_UNIX;
111 strcpy(serv_addr.sun_path, host);
112
113 // creates the socket
114 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
115
116 // connects
117 if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
118 perror(
119 "Error opening UNIX socket: path unavailable, or already existing");
120 exit(-1);
121 }
122 }
123
124 *psockfd = sockfd;
125}
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 ******************************************************************************/
139void open_bind_socket(int *psockfd, int *inet, int *port, char *host) {
140 int sockfd, ai_err;
141
142 if (*inet > 0) { // creates an internet socket
143
144 // fetches information on the host
145 struct addrinfo hints, *res;
146 char service[256];
147
148 memset(&hints, 0, sizeof(hints));
149 hints.ai_socktype = SOCK_STREAM;
150 hints.ai_family = AF_INET;
151 hints.ai_flags = AI_PASSIVE;
152
153 sprintf(service, "%d", *port); // convert the port number to a string
154 ai_err = getaddrinfo(host, service, &hints, &res);
155 if (ai_err != 0) {
156 perror("Error fetching host data. Wrong host name?");
157 exit(-1);
158 }
159
160 // creates socket
161 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
162 if (sockfd < 0) {
163 perror("Error opening socket");
164 exit(-1);
165 }
166
167 // binds
168 if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
169 perror("Error binding INET socket: wrong port or server unreachable");
170 exit(-1);
171 }
172 freeaddrinfo(res);
173 } else { // creates a unix socket
174 struct sockaddr_un serv_addr;
175
176 // fills up details of the socket address
177 memset(&serv_addr, 0, sizeof(serv_addr));
178 serv_addr.sun_family = AF_UNIX;
179 strcpy(serv_addr.sun_path, host);
180
181 // creates the socket
182 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
183
184 remove(serv_addr.sun_path);
185
186 // binds
187 if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
188 perror(
189 "Error binding UNIX socket: path unavailable, or already existing");
190 exit(-1);
191 }
192 }
193
194 *psockfd = sockfd;
195}
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 ******************************************************************************/
203void writebuffer(int *psockfd, char *data, int *plen) {
204 int n;
205 int sockfd = *psockfd;
206 int len = *plen;
207
208 n = write(sockfd, data, len);
209 if (n < 0) {
210 perror("Error writing to socket: server has quit or connection broke");
211 exit(-1);
212 }
213}
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 ******************************************************************************/
221void readbuffer(int *psockfd, char *data, int *plen) {
222 int n, nr;
223 int sockfd = *psockfd;
224 int len = *plen;
225
226 n = nr = read(sockfd, data, len);
227
228 while (nr > 0 && n < len) {
229 nr = read(sockfd, &data[n], len - n);
230 n += nr;
231 }
232
233 if (n == 0) {
234 perror("Error reading from socket: server has quit or connection broke");
235 exit(-1);
236 }
237}
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 ******************************************************************************/
245void listen_socket(int *psockfd, int *backlog) {
246
247 if (listen(*psockfd, *backlog) < 0) {
248 perror("Error listening socket");
249 exit(-1);
250 };
251}
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 ******************************************************************************/
258void accept_socket(int *psockfd, int *pclientfd) {
259
260 int client_fd = accept(*psockfd, NULL, NULL);
261
262 *pclientfd = client_fd;
263}
264
265/*******************************************************************************
266 * \brief Closes a socket.
267 * \param psockfd The id of the socket to close.
268 ******************************************************************************/
269void 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 ******************************************************************************/
275void 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 ******************************************************************************/
281void uwait(double *dsec) {
282 struct timespec wt, rem;
283 wt.tv_sec = floor(*dsec);
284 wt.tv_nsec = (*dsec - wt.tv_sec) * 1000000000;
285 nanosleep(&wt, &rem);
286}
287
288#endif
void open_bind_socket(int *psockfd, int *inet, int *port, char *host)
Opens and binds a socket.
Definition sockets.c:139
void open_connect_socket(int *psockfd, int *inet, int *port, char *host)
Opens and connects a socket.
Definition sockets.c:71
void writebuffer(int *psockfd, char *data, int *plen)
Writes to a socket.
Definition sockets.c:203
void accept_socket(int *psockfd, int *pclientfd)
Listens to a socket.
Definition sockets.c:258
void uwait(double *dsec)
Mini-wrapper to nanosleep.
Definition sockets.c:281
void close_socket(int *psockfd)
Closes a socket.
Definition sockets.c:269
void listen_socket(int *psockfd, int *backlog)
Listens to a socket.
Definition sockets.c:245
void readbuffer(int *psockfd, char *data, int *plen)
Reads from a socket.
Definition sockets.c:221
void remove_socket_file(char *host)
Removes a socket file.
Definition sockets.c:275