1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
5
6 /**
7 * \file spipe.c
8 * \brief Implements socket-pipes
9 *
10 */
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <assert.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <yaz/xmalloc.h>
20 #include <yaz/nmem.h>
21 #include <yaz/log.h>
22 #include <yaz/spipe.h>
23
24 #if HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #ifdef WIN32
29 #include <winsock2.h>
30 #define YAZ_INVALID_SOCKET INVALID_SOCKET
31 #else
32 #define YAZ_INVALID_SOCKET -1
33 #include <fcntl.h>
34 #endif
35
36 #if HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
39 #if HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42 #if HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45 #if HAVE_NETINET_TCP_H
46 #include <netinet/tcp.h>
47 #endif
48 #if HAVE_SYS_SELECT_H
49 #include <sys/select.h>
50 #endif
51 #if HAVE_SYS_SOCKET_H
52 #include <sys/socket.h>
53 #endif
54
55 #if HAVE_NETINET_IN_H
56 #include <netinet/in.h>
57 #endif
58 #if HAVE_NETDB_H
59 #include <netdb.h>
60 #endif
61 #if HAVE_ARPA_INET_H
62 #include <arpa/inet.h>
63 #endif
64 #if HAVE_NETINET_TCP_H
65 #include <netinet/tcp.h>
66 #endif
67
68 #ifndef YAZ_SOCKLEN_T
69 #define YAZ_SOCKLEN_T int
70 #endif
71
72 struct yaz_spipe {
73 int m_fd[2];
74 int m_socket;
75 };
76
yaz_spipe_close(int * fd)77 static void yaz_spipe_close(int *fd)
78 {
79 #ifdef WIN32
80 if (*fd != YAZ_INVALID_SOCKET)
81 closesocket(*fd);
82 #else
83 if (*fd != YAZ_INVALID_SOCKET)
84 close(*fd);
85 #endif
86 *fd = YAZ_INVALID_SOCKET;
87 }
88
nonblock(int s)89 static int nonblock(int s)
90 {
91 #ifdef WIN32
92 unsigned long tru = 1;
93 if (ioctlsocket(s, FIONBIO, &tru))
94 return -1;
95 #else
96 if (fcntl(s, F_SETFL, O_NONBLOCK))
97 return -1;
98 #endif
99 return 0;
100 }
101
yaz_spipe_create(int port_to_use,WRBUF * err_msg)102 yaz_spipe_t yaz_spipe_create(int port_to_use, WRBUF *err_msg)
103 {
104 yaz_spipe_t p = xmalloc(sizeof(*p));
105
106 #ifdef WIN32
107 {
108 WSADATA wsaData;
109 WORD wVersionRequested = MAKEWORD(2, 0);
110 if (WSAStartup( wVersionRequested, &wsaData))
111 {
112 if (err_msg)
113 wrbuf_printf(*err_msg, "WSAStartup failed");
114 xfree(p);
115 return 0;
116 }
117 }
118 #endif
119 p->m_fd[0] = p->m_fd[1] = YAZ_INVALID_SOCKET;
120 p->m_socket = YAZ_INVALID_SOCKET;
121
122 if (port_to_use)
123 {
124 struct sockaddr_in add;
125 struct sockaddr *addr = 0;
126 unsigned int tmpadd;
127 struct sockaddr caddr;
128 YAZ_SOCKLEN_T caddr_len = sizeof(caddr);
129 fd_set write_set;
130
131 /* create server socket */
132 p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
133 if (p->m_socket == YAZ_INVALID_SOCKET)
134 {
135 if (err_msg)
136 wrbuf_printf(*err_msg, "socket call failed");
137 yaz_spipe_destroy(p);
138 return 0;
139 }
140 #ifndef WIN32
141 {
142 unsigned long one = 1;
143 if (setsockopt(p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)
144 &one, sizeof(one)))
145 {
146 if (err_msg)
147 wrbuf_printf(*err_msg, "setsockopt call failed");
148 yaz_spipe_destroy(p);
149 return 0;
150 }
151 }
152 #endif
153 /* bind server socket */
154 add.sin_family = AF_INET;
155 add.sin_port = htons(port_to_use);
156 add.sin_addr.s_addr = INADDR_ANY;
157 addr = ( struct sockaddr *) &add;
158
159 if (bind(p->m_socket, addr, sizeof(struct sockaddr_in)))
160 {
161 if (err_msg)
162 wrbuf_printf(*err_msg, "could not bind to socket");
163 yaz_spipe_destroy(p);
164 return 0;
165 }
166
167 if (listen(p->m_socket, 3) < 0)
168 {
169 if (err_msg)
170 wrbuf_printf(*err_msg, "could not listen on socket");
171 yaz_spipe_destroy(p);
172 return 0;
173 }
174
175 /* client socket */
176 tmpadd = (unsigned) inet_addr("127.0.0.1");
177 if (!tmpadd)
178 {
179 if (err_msg)
180 wrbuf_printf(*err_msg, "inet_addr failed");
181 yaz_spipe_destroy(p);
182 return 0;
183 }
184
185 memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
186 p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
187 if (p->m_fd[1] == YAZ_INVALID_SOCKET)
188 {
189 if (err_msg)
190 wrbuf_printf(*err_msg, "socket call failed (2)");
191 yaz_spipe_destroy(p);
192 return 0;
193 }
194 nonblock(p->m_fd[1]);
195
196 if (connect(p->m_fd[1], addr, sizeof(*addr)))
197 {
198 if (
199 #ifdef WIN32
200 WSAGetLastError() != WSAEWOULDBLOCK
201 #else
202 errno != EINPROGRESS
203 #endif
204 )
205 {
206 if (err_msg)
207 wrbuf_printf(*err_msg, "connect call failed");
208 yaz_spipe_destroy(p);
209 return 0;
210 }
211 }
212
213 /* server accept */
214 p->m_fd[0] = accept(p->m_socket, &caddr, &caddr_len);
215 if (p->m_fd[0] == YAZ_INVALID_SOCKET)
216 {
217 if (err_msg)
218 wrbuf_printf(*err_msg, "accept failed");
219 yaz_spipe_destroy(p);
220 return 0;
221 }
222
223 /* complete connect */
224 FD_ZERO(&write_set);
225 FD_SET(p->m_fd[1], &write_set);
226 if (select(p->m_fd[1]+1, 0, &write_set, 0, 0) != 1)
227 {
228 if (err_msg)
229 wrbuf_printf(*err_msg, "could not complete connect");
230 yaz_spipe_destroy(p);
231 return 0;
232 }
233 yaz_spipe_close(&p->m_socket);
234 }
235 else
236 {
237 #ifdef WIN32
238 yaz_spipe_destroy(p);
239 return 0;
240 #else
241 if (pipe(p->m_fd))
242 {
243 if (err_msg)
244 wrbuf_printf(*err_msg, "pipe call failed");
245 yaz_spipe_destroy(p);
246 return 0;
247 }
248 assert(p->m_fd[0] != YAZ_INVALID_SOCKET);
249 assert(p->m_fd[1] != YAZ_INVALID_SOCKET);
250 #endif
251 }
252
253 return p;
254 }
255
yaz_spipe_destroy(yaz_spipe_t p)256 void yaz_spipe_destroy(yaz_spipe_t p)
257 {
258 yaz_spipe_close(&p->m_fd[0]);
259 yaz_spipe_close(&p->m_fd[1]);
260 yaz_spipe_close(&p->m_socket);
261 xfree(p);
262 #ifdef WIN32
263 WSACleanup();
264 #endif
265 }
266
yaz_spipe_get_read_fd(yaz_spipe_t p)267 int yaz_spipe_get_read_fd(yaz_spipe_t p)
268 {
269 return p->m_fd[0];
270 }
271
yaz_spipe_get_write_fd(yaz_spipe_t p)272 int yaz_spipe_get_write_fd(yaz_spipe_t p)
273 {
274 return p->m_fd[1];
275 }
276
277
278 /*
279 * Local variables:
280 * c-basic-offset: 4
281 * c-file-style: "Stroustrup"
282 * indent-tabs-mode: nil
283 * End:
284 * vim: shiftwidth=4 tabstop=8 expandtab
285 */
286
287