1 /* A minimal wrapper for socket communication.
2 
3 Copyright (C) 2013, Joshua More and Michele Ceriotti
4 
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12 
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 
25 Contains both the functions that transmit data to the socket and read the data
26 back out again once finished, and the function which opens the socket initially.
27 Can be linked to a FORTRAN code that does not support sockets natively.
28 
29 Functions:
30    error: Prints an error message and then exits.
31    open_socket_: Opens a socket with the required host server, socket type and
32       port number.
33    write_buffer_: Writes a string to the socket.
34    read_buffer_: Reads data from the socket.
35 */
36 #ifndef __NO_IPI_DRIVER
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <time.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <sys/un.h>
47 #include <netdb.h>
48 #include <math.h>
49 
open_socket(int * psockfd,int * inet,int * port,char * host)50 void open_socket(int *psockfd, int* inet, int* port, char* host)
51 /* Opens a socket.
52 
53 Note that fortran passes an extra argument for the string length, but this is
54 ignored here for C compatibility.
55 
56 Args:
57    psockfd: The id of the socket that will be created.
58    inet: An integer that determines whether the socket will be an inet or unix
59       domain socket. Gives unix if 0, inet otherwise.
60    port: The port number for the socket to be created. Low numbers are often
61       reserved for important channels, so use of numbers of 4 or more digits is
62       recommended.
63    host: The name of the host server.
64 */
65 
66 {
67    int sockfd, ai_err;
68 
69    if (*inet>0)
70    {  // creates an internet socket
71 
72       // fetches information on the host
73       struct addrinfo hints, *res;
74       char service[256];
75 
76       memset(&hints, 0, sizeof(hints));
77       hints.ai_socktype = SOCK_STREAM;
78       hints.ai_family = AF_INET;
79       hints.ai_flags = AI_PASSIVE;
80 
81       sprintf(service,"%d",*port); // convert the port number to a string
82       ai_err = getaddrinfo(host, service, &hints, &res);
83       if (ai_err!=0) { perror("Error fetching host data. Wrong host name?"); exit(-1); }
84 
85       // creates socket
86       sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
87       if (sockfd < 0) { perror("Error opening socket"); exit(-1); }
88 
89       // makes connection
90       if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) { perror("Error opening INET socket: wrong port or server unreachable"); exit(-1); }
91       freeaddrinfo(res);
92    }
93    else
94    {  // creates a unix socket
95       struct sockaddr_un serv_addr;
96 
97       // fills up details of the socket addres
98       memset(&serv_addr, 0, sizeof(serv_addr));
99       serv_addr.sun_family = AF_UNIX;
100       strcpy(serv_addr.sun_path, "/tmp/ipi_");
101       strcpy(serv_addr.sun_path+9, host);
102 
103       // creates the socket
104       sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
105 
106       // connects
107       if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("Error opening UNIX socket: path unavailable, or already existing"); exit(-1); }
108    }
109 
110 
111    *psockfd=sockfd;
112 }
113 
writebuffer(int * psockfd,char * data,int * plen)114 void writebuffer(int *psockfd, char *data, int* plen)
115 /* Writes to a socket.
116 
117 Args:
118    psockfd: The id of the socket that will be written to.
119    data: The data to be written to the socket.
120    plen: The length of the data in bytes.
121 */
122 
123 {
124    int n;
125    int sockfd=*psockfd;
126    int len=*plen;
127 
128    n = write(sockfd,data,len);
129    if (n < 0) { perror("Error writing to socket: server has quit or connection broke"); exit(-1); }
130 }
131 
132 
readbuffer(int * psockfd,char * data,int * plen)133 void readbuffer(int *psockfd, char *data, int* plen)
134 /* Reads from a socket.
135 
136 Args:
137    psockfd: The id of the socket that will be read from.
138    data: The storage array for data read from the socket.
139    plen: The length of the data in bytes.
140 */
141 
142 {
143    int n, nr;
144    int sockfd=*psockfd;
145    int len=*plen;
146 
147    n = nr = read(sockfd,data,len);
148 
149    while (nr>0 && n<len )
150    {  nr=read(sockfd,&data[n],len-n); n+=nr; }
151 
152    if (n == 0) { perror("Error reading from socket: server has quit or connection broke"); exit(-1); }
153 }
154 
uwait(double * dsec)155 void uwait(double *dsec)
156 /* mini-wrapper to nanosleep
157 
158    Args:
159      dsec:  number of seconds to wait (float values accepted)
160 */
161 {
162    int rn;
163    struct timespec wt, rem;
164    wt.tv_sec = floor(*dsec); wt.tv_nsec=(*dsec-wt.tv_sec)*1000000000;
165    rn = nanosleep(&wt, &rem);
166 }
167 
168 #endif
169 
170