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