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