Port Pipe class to windows.
[metaproxy-moved-to-github.git] / src / pipe.cpp
1
2 /* $Id: pipe.cpp,v 1.3 2005-11-07 22:43:17 adam Exp $
3    Copyright (c) 2005, Index Data.
4
5 %LICENSE%
6  */
7 #include "config.hpp"
8
9 #if HAVE_UNISTD_H
10 #include <unistd.h>
11 #endif
12
13 #include <errno.h>
14 #ifdef WIN32
15 #include <winsock.h>
16 #else
17 #include <netinet/in.h>
18 #include <netdb.h>
19 #include <arpa/inet.h>
20 #include <netinet/tcp.h>
21
22 #include <fcntl.h>
23 #endif
24
25 #if HAVE_SYS_SOCKET_H
26 #include <sys/socket.h>
27 #endif
28 #if HAVE_SYS_SELECT_H
29 #include <sys/select.h>
30 #endif
31
32 #include <boost/thread/thread.hpp>
33 #include <boost/thread/mutex.hpp>
34 #include <boost/thread/condition.hpp>
35
36 #include <stdio.h>
37
38 #include <deque>
39
40 #include <yaz++/socket-observer.h>
41 #include <yaz/log.h>
42
43 #include "pipe.hpp"
44
45 namespace yp2 {
46     class Pipe::Rep : public boost::noncopyable {
47         friend class Pipe;
48         Rep();
49         int m_fd[2];
50         int m_socket;
51         bool nonblock(int s);
52         void close(int &fd);
53     };
54 }
55
56 using namespace yp2;
57
58 void Pipe::Rep::close(int &fd)
59 {
60 #ifdef WIN32
61     if (fd != -1)
62         ::closesocket(fd);
63 #else
64     if (fd != -1)
65         ::close(fd);
66 #endif
67     fd = -1;
68 }
69
70 Pipe::Rep::Rep()
71 {
72     m_fd[0] = m_fd[1] = -1;
73     m_socket = -1;
74 }
75
76 bool Pipe::Rep::nonblock(int s)
77 {
78 #ifdef WIN32
79     unsigned long tru = 1;
80     if (ioctlsocket(s, FIONBIO, &tru) < 0)
81         return false;
82 #else
83     if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
84         return false;
85 #ifndef MSG_NOSIGNAL
86     signal (SIGPIPE, SIG_IGN);
87 #endif
88 #endif
89     return true;
90 }
91
92 Pipe::Pipe(int port_to_use) : m_p(new Rep)
93 {
94     if (port_to_use)
95     {
96         // create server socket
97         m_p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
98         if (m_p->m_socket < 0)
99             throw Pipe::Error("could not create socket");
100 #ifndef WIN32
101         unsigned long one = 1;
102         if (setsockopt(m_p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*) 
103                        &one, sizeof(one)) < 0)
104             throw Pipe::Error("setsockopt error");
105 #endif
106         // bind server socket
107         struct sockaddr_in add;
108         add.sin_family = AF_INET;
109         add.sin_port = htons(port_to_use);
110         add.sin_addr.s_addr = INADDR_ANY;
111         struct sockaddr *addr = ( struct sockaddr *) &add;
112       
113         if (bind(m_p->m_socket, addr, sizeof(struct sockaddr_in)))
114             throw Pipe::Error("could not bind on socket");
115         
116         if (listen(m_p->m_socket, 3) < 0)
117             throw Pipe::Error("could not listen on socket");
118
119         // client socket
120         unsigned int tmpadd;
121         tmpadd = (unsigned) inet_addr("127.0.0.1");
122         if (tmpadd)
123             memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
124         else
125             throw Pipe::Error("inet_addr failed");
126             
127         m_p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
128         if (m_p->m_fd[1] < 0)
129             throw Pipe::Error("could not create socket");
130         
131         m_p->nonblock(m_p->m_fd[1]);
132
133         if (connect(m_p->m_fd[1], addr, sizeof(*addr)) < 0)
134         {
135 #ifdef WIN32
136             if (WSAGetLastError() != WSAEWOULDBLOCK)
137                 throw Pipe::Error("could not connect to socket");
138 #else
139             if (errno != EINPROGRESS)
140                 throw Pipe::Error("could not connect to socket");
141 #endif
142         }
143
144         // server accept
145         struct sockaddr caddr;
146 #ifdef WIN32
147         int caddr_len = sizeof(caddr);
148 #else
149         socklen_t caddr_len = sizeof(caddr);
150 #endif
151         m_p->m_fd[0] = accept(m_p->m_socket, &caddr, &caddr_len);
152         if (m_p->m_fd[0] < 0)
153             throw Pipe::Error("could not accept on socket");
154
155         // complete connect
156         fd_set write_set;
157         FD_ZERO(&write_set);
158         FD_SET(m_p->m_fd[1], &write_set);
159         int r = select(m_p->m_fd[1]+1, 0, &write_set, 0, 0);
160         if (r != 1)
161             throw Pipe::Error("could not complete connect");
162
163         m_p->close(m_p->m_socket);
164     }
165     else
166     {
167 #ifndef WIN32
168         pipe(m_p->m_fd);
169 #endif
170     }
171 }
172
173 Pipe::~Pipe()
174 {
175     m_p->close(m_p->m_fd[0]);
176     m_p->close(m_p->m_fd[1]);
177     m_p->close(m_p->m_socket);
178 }
179
180 int &Pipe::read_fd() const
181 {
182     return m_p->m_fd[0];
183 }
184
185 int &Pipe::write_fd() const
186 {
187     return m_p->m_fd[1];
188 }
189
190 /*
191  * Local variables:
192  * c-basic-offset: 4
193  * indent-tabs-mode: nil
194  * c-file-style: "stroustrup"
195  * End:
196  * vim: shiftwidth=4 tabstop=8 expandtab
197  */
198