LCOV - code coverage report
Current view: top level - src - sockets.c (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:e7e05ae) Lines: 0 105 0.0 %
Date: 2024-04-18 06:59:28 Functions: 0 9 0.0 %

          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

Generated by: LCOV version 1.15