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