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