metaproxy 1.22.1
pipe.cpp
Go to the documentation of this file.
1/* This file is part of Metaproxy.
2 Copyright (C) Index Data
3
4Metaproxy is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "config.hpp"
20
21#if HAVE_UNISTD_H
22#include <unistd.h>
23#endif
24
25#include <signal.h>
26#include <errno.h>
27#ifdef WIN32
28#include <winsock.h>
29#else
30#include <netinet/in.h>
31#include <netdb.h>
32#include <arpa/inet.h>
33#include <netinet/tcp.h>
34
35#include <fcntl.h>
36#endif
37
38#if HAVE_SYS_SOCKET_H
39#include <sys/socket.h>
40#endif
41#if HAVE_SYS_SELECT_H
42#include <sys/select.h>
43#endif
44
45#include <boost/thread/thread.hpp>
46#include <boost/thread/mutex.hpp>
47#include <boost/thread/condition.hpp>
48#include <boost/noncopyable.hpp>
49
50#include <stdio.h>
51#include <string.h>
52
53#include <deque>
54
55#include <yazpp/socket-observer.h>
56#include <yaz/log.h>
57
58#include "pipe.hpp"
59
60namespace mp = metaproxy_1;
61
62namespace metaproxy_1 {
63 class Pipe::Rep : public boost::noncopyable {
64 friend class Pipe;
65 Rep();
66 int m_fd[2];
68 bool nonblock(int s);
69 void close(int &fd);
70 };
71}
72
73using namespace mp;
74
75void Pipe::Rep::close(int &fd)
76{
77#ifdef WIN32
78 if (fd != -1)
79 ::closesocket(fd);
80#else
81 if (fd != -1)
82 ::close(fd);
83#endif
84 fd = -1;
85}
86
88{
89 m_fd[0] = m_fd[1] = -1;
90 m_socket = -1;
91}
92
94{
95#ifdef WIN32
96 unsigned long tru = 1;
97 if (ioctlsocket(s, FIONBIO, &tru) < 0)
98 return false;
99#else
100 if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
101 return false;
102#ifndef MSG_NOSIGNAL
103 signal (SIGPIPE, SIG_IGN);
104#endif
105#endif
106 return true;
107}
108
109Pipe::Pipe(int port_to_use) : m_p(new Rep)
110{
111#ifdef WIN32
112 WSADATA wsaData;
113 WORD wVersionRequested = MAKEWORD(2, 0);
114 if (WSAStartup( wVersionRequested, &wsaData ))
115 throw Pipe::Error("WSAStartup failed");
116#else
117 port_to_use = 0; // we'll just use pipe on Unix
118#endif
119 if (port_to_use)
120 {
121 // create server socket
122 m_p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
123 if (m_p->m_socket < 0)
124 throw Pipe::Error("could not create socket");
125#ifndef WIN32
126 unsigned long one = 1;
127 if (setsockopt(m_p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)
128 &one, sizeof(one)) < 0)
129 throw Pipe::Error("setsockopt error");
130#endif
131 // bind server socket
132 struct sockaddr_in add;
133 add.sin_family = AF_INET;
134 add.sin_port = htons(port_to_use);
135 add.sin_addr.s_addr = INADDR_ANY;
136 struct sockaddr *addr = ( struct sockaddr *) &add;
137
138 if (bind(m_p->m_socket, addr, sizeof(struct sockaddr_in)))
139 throw Pipe::Error("could not bind on socket");
140
141 if (listen(m_p->m_socket, 3) < 0)
142 throw Pipe::Error("could not listen on socket");
143
144 // client socket
145 unsigned int tmpadd;
146 tmpadd = (unsigned) inet_addr("127.0.0.1");
147 if (tmpadd)
148 memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
149 else
150 throw Pipe::Error("inet_addr failed");
151
152 m_p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
153 if (m_p->m_fd[1] < 0)
154 throw Pipe::Error("could not create socket");
155
156 m_p->nonblock(m_p->m_fd[1]);
157
158 if (connect(m_p->m_fd[1], addr, sizeof(*addr)) < 0)
159 {
160#ifdef WIN32
161 if (WSAGetLastError() != WSAEWOULDBLOCK)
162 throw Pipe::Error("could not connect to socket");
163#else
164 if (errno != EINPROGRESS)
165 throw Pipe::Error("could not connect to socket");
166#endif
167 }
168
169 // server accept
170 struct sockaddr caddr;
171#ifdef WIN32
172 int caddr_len = sizeof(caddr);
173#else
174 socklen_t caddr_len = sizeof(caddr);
175#endif
176 m_p->m_fd[0] = accept(m_p->m_socket, &caddr, &caddr_len);
177 if (m_p->m_fd[0] < 0)
178 throw Pipe::Error("could not accept on socket");
179
180 // complete connect
181 fd_set write_set;
182 FD_ZERO(&write_set);
183 FD_SET(m_p->m_fd[1], &write_set);
184 int r = select(m_p->m_fd[1]+1, 0, &write_set, 0, 0);
185 if (r != 1)
186 throw Pipe::Error("could not complete connect");
187
188 m_p->close(m_p->m_socket);
189 }
190 else
191 {
192#ifndef WIN32
193 if (pipe(m_p->m_fd))
194 throw Pipe::Error("pipe failed");
195 else
196 {
197 assert(m_p->m_fd[0] >= 0);
198 assert(m_p->m_fd[1] >= 0);
199 }
200#endif
201 }
202}
203
205{
206 m_p->close(m_p->m_fd[0]);
207 m_p->close(m_p->m_fd[1]);
208 m_p->close(m_p->m_socket);
209#ifdef WIN32
210 WSACleanup();
211#endif
212}
213
214int &Pipe::read_fd() const
215{
216 return m_p->m_fd[0];
217}
218
219int &Pipe::write_fd() const
220{
221 return m_p->m_fd[1];
222}
223
224/*
225 * Local variables:
226 * c-basic-offset: 4
227 * c-file-style: "Stroustrup"
228 * indent-tabs-mode: nil
229 * End:
230 * vim: shiftwidth=4 tabstop=8 expandtab
231 */
232
bool nonblock(int s)
Definition pipe.cpp:93
void close(int &fd)
Definition pipe.cpp:75
boost::scoped_ptr< Rep > m_p
Definition pipe.hpp:42
int & read_fd() const
Definition pipe.cpp:214
Pipe(int port_to_use)
Definition pipe.cpp:109
int & write_fd() const
Definition pipe.cpp:219