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
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <sys/un.h>
45 #include <netdb.h>
46
open_socket(int * psockfd,int * inet,int * port,const char * host)47 void open_socket(int *psockfd, int* inet, int* port, const char* host)
48 /* Opens a socket.
49
50 Note that fortran passes an extra argument for the string length, but this is
51 ignored here for C compatibility.
52
53 Args:
54 psockfd: The id of the socket that will be created.
55 inet: An integer that determines whether the socket will be an inet or unix
56 domain socket. Gives unix if 0, inet otherwise.
57 port: The port number for the socket to be created. Low numbers are often
58 reserved for important channels, so use of numbers of 4 or more digits is
59 recommended.
60 host: The name of the host server.
61 */
62
63 {
64 int sockfd, ai_err;
65
66 if (*inet>0)
67 { // creates an internet socket
68
69 // fetches information on the host
70 struct addrinfo hints, *res;
71 char service[256];
72
73 memset(&hints, 0, sizeof(hints));
74 hints.ai_socktype = SOCK_STREAM;
75 hints.ai_family = AF_UNSPEC;
76 hints.ai_flags = AI_PASSIVE;
77
78 sprintf(service,"%d",*port); // convert the port number to a string
79 ai_err = getaddrinfo(host, service, &hints, &res);
80 if (ai_err!=0) { perror("Error fetching host data. Wrong host name?"); exit(-1); }
81
82 // creates socket
83 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
84 if (sockfd < 0) { perror("Error opening socket"); exit(-1); }
85
86 // makes connection
87 if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0)
88 { perror("Error opening INET socket: wrong port or server unreachable"); exit(-1); }
89 freeaddrinfo(res);
90 }
91 else
92 {
93 struct sockaddr_un serv_addr;
94
95 // fills up details of the socket addres
96 memset(&serv_addr, 0, sizeof(serv_addr));
97 serv_addr.sun_family = AF_UNIX;
98 strcpy(serv_addr.sun_path, "/tmp/ipi_");
99 strcpy(serv_addr.sun_path+9, host);
100 // creates a unix socket
101
102 // creates the socket
103 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
104
105 // connects
106 if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
107 { perror("Error opening UNIX socket: path unavailable, or already existing"); exit(-1); }
108 }
109
110 *psockfd=sockfd;
111 }
112
create_socket(int * psockfd,int * inet,int * port,const char * host)113 void create_socket(int *psockfd, int* inet, int* port, const char* host)
114 /* Creates a server socket.
115
116 Note that fortran passes an extra argument for the string length, but this is
117 ignored here for C compatibility.
118
119 Args:
120 psockfd: The id of the socket that will be created.
121 inet: An integer that determines whether the socket will be an inet or unix
122 domain socket. Gives unix if 0, inet otherwise.
123 port: The port number for the socket to be created. Low numbers are often
124 reserved for important channels, so use of numbers of 4 or more digits is
125 recommended.
126 host: The name of the host server.
127 */
128
129 {
130 int sockfd, srvsockfd, ai_err;
131
132 if (*inet>0)
133 { // creates an internet socket
134
135 // fetches information on the host
136 struct addrinfo hints, *res;
137 char service[256];
138
139 memset(&hints, 0, sizeof(hints));
140 hints.ai_socktype = SOCK_STREAM;
141 hints.ai_family = AF_UNSPEC;
142 hints.ai_flags = AI_PASSIVE;
143
144 sprintf(service,"%d",*port); // convert the port number to a string
145 ai_err = getaddrinfo(host, service, &hints, &res);
146 if (ai_err!=0) { perror("Error fetching host data. Wrong host name?"); exit(-1); }
147
148 // creates listening socket
149 srvsockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
150 if (srvsockfd < 0) { perror("Error creating socket"); exit(-1); }
151
152 if (bind(srvsockfd, res->ai_addr, res->ai_addrlen) < 0)
153 { perror("Error binding to INET server socket."); }
154
155 freeaddrinfo(res);
156
157 listen(srvsockfd,5);
158 struct sockaddr_storage their_addr; // connector's address information
159 socklen_t sin_size;
160 sin_size = sizeof their_addr;
161
162 // makes connection and return the socket on which communication occurs
163 sockfd = accept(srvsockfd, (struct sockaddr *)&their_addr, &sin_size);
164 if (sockfd < 0)
165 { perror("Error creating INET communication socket: wrong port or server unreachable"); exit(-1); }
166 }
167 else
168 {
169 struct sockaddr_un serv_addr;
170
171
172 // creates the socket
173 srvsockfd = socket(AF_UNIX, SOCK_STREAM, 0);
174
175 // fills up details of the socket addres
176 memset(&serv_addr, 0, sizeof(serv_addr));
177 serv_addr.sun_family = AF_UNIX;
178 strcpy(serv_addr.sun_path, "/tmp/ipi_");
179 strcpy(serv_addr.sun_path+9, host);
180 // binds the socket to the descriptor
181 bind(srvsockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
182 if (srvsockfd < 0)
183 { perror("Error creating UNIX socket: path unavailable, or already existing"); exit(-1); }
184
185 // listens on the server socket
186 listen(srvsockfd,5);
187
188 // accepts an incoming connection
189 struct sockaddr_un their_addr; socklen_t their_size=sizeof(their_addr);
190 sockfd = accept(srvsockfd, (struct sockaddr *) &their_addr, &their_size);
191
192 if (sockfd < 0)
193 { perror("Error establishing UNIX socket connection"); exit(-1); }
194 }
195
196 *psockfd=sockfd;
197 }
198
writebuffer(int * psockfd,const char * data,int * plen)199 void writebuffer(int *psockfd, const char *data, int* plen)
200 /* Writes to a socket.
201
202 Args:
203 psockfd: The id of the socket that will be written to.
204 data: The data to be written to the socket.
205 plen: The length of the data in bytes.
206 */
207
208 {
209 int n;
210 int sockfd=*psockfd;
211 int len=*plen;
212
213 n = write(sockfd,data,len);
214 if (n < 0) { perror("Error writing to socket: server has quit or connection broke"); exit(-1); }
215 }
216
readbuffer(int * psockfd,char * data,int * plen)217 void readbuffer(int *psockfd, char *data, int* plen)
218 /* Reads from a socket.
219
220 Args:
221 psockfd: The id of the socket that will be read from.
222 data: The storage array for data read from the socket.
223 plen: The length of the data in bytes.
224 */
225
226 {
227 int n, nr;
228 int sockfd=*psockfd;
229 int len=*plen;
230
231 n = nr = read(sockfd,data,len);
232
233 while (nr>0 && n<len )
234 { nr=read(sockfd,&data[n],len-n); n+=nr; }
235
236 if (n == 0) { perror("Error reading from socket: server has quit or connection broke"); exit(-1); }
237 }
238
close_socket(int * psockfd)239 void close_socket(int *psockfd)
240 /* Destroys a server socket.
241
242 Args:
243 psockfd: The id of the socket that will be closed
244 */
245
246 {
247 if (close(*psockfd)!=0) { perror("Error closing socket"); exit(-1); }
248 }
249
250
251