LCOV - code coverage report
Current view: top level - src - sockets.c (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 0.0 % 119 0
Test Date: 2026-10-15 00:55:44 Functions: 0.0 % 9 0

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

Generated by: LCOV version 2.0-1