Call WSAStartup. Use port in test_pipe test
[metaproxy-moved-to-github.git] / src / pipe.cpp
1
2 /* $Id: pipe.cpp,v 1.4 2005-11-08 08:55:41 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 #ifdef WIN32
95     WSADATA wsaData;
96     WORD wVersionRequested = MAKEWORD(2, 0);
97     if (WSAStartup( wVersionRequested, &wsaData ))
98         throw Pipe::Error("WSAStartup failed");
99 #endif
100     if (port_to_use)
101     {
102         // create server socket
103         m_p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
104         if (m_p->m_socket < 0)
105             throw Pipe::Error("could not create socket");
106 #ifndef WIN32
107         unsigned long one = 1;
108         if (setsockopt(m_p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*) 
109                        &one, sizeof(one)) < 0)
110             throw Pipe::Error("setsockopt error");
111 #endif
112         // bind server socket
113         struct sockaddr_in add;
114         add.sin_family = AF_INET;
115         add.sin_port = htons(port_to_use);
116         add.sin_addr.s_addr = INADDR_ANY;
117         struct sockaddr *addr = ( struct sockaddr *) &add;
118       
119         if (bind(m_p->m_socket, addr, sizeof(struct sockaddr_in)))
120             throw Pipe::Error("could not bind on socket");
121         
122         if (listen(m_p->m_socket, 3) < 0)
123             throw Pipe::Error("could not listen on socket");
124
125         // client socket
126         unsigned int tmpadd;
127         tmpadd = (unsigned) inet_addr("127.0.0.1");
128         if (tmpadd)
129             memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
130         else
131             throw Pipe::Error("inet_addr failed");
132             
133         m_p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
134         if (m_p->m_fd[1] < 0)
135             throw Pipe::Error("could not create socket");
136         
137         m_p->nonblock(m_p->m_fd[1]);
138
139         if (connect(m_p->m_fd[1], addr, sizeof(*addr)) < 0)
140         {
141 #ifdef WIN32
142             if (WSAGetLastError() != WSAEWOULDBLOCK)
143                 throw Pipe::Error("could not connect to socket");
144 #else
145             if (errno != EINPROGRESS)
146                 throw Pipe::Error("could not connect to socket");
147 #endif
148         }
149
150         // server accept
151         struct sockaddr caddr;
152 #ifdef WIN32
153         int caddr_len = sizeof(caddr);
154 #else
155         socklen_t caddr_len = sizeof(caddr);
156 #endif
157         m_p->m_fd[0] = accept(m_p->m_socket, &caddr, &caddr_len);
158         if (m_p->m_fd[0] < 0)
159             throw Pipe::Error("could not accept on socket");
160
161         // complete connect
162         fd_set write_set;
163         FD_ZERO(&write_set);
164         FD_SET(m_p->m_fd[1], &write_set);
165         int r = select(m_p->m_fd[1]+1, 0, &write_set, 0, 0);
166         if (r != 1)
167             throw Pipe::Error("could not complete connect");
168
169         m_p->close(m_p->m_socket);
170     }
171     else
172     {
173 #ifndef WIN32
174         pipe(m_p->m_fd);
175 #endif
176     }
177 }
178
179 Pipe::~Pipe()
180 {
181     m_p->close(m_p->m_fd[0]);
182     m_p->close(m_p->m_fd[1]);
183     m_p->close(m_p->m_socket);
184 #ifdef WIN32
185     WSACleanup();
186 #endif
187 }
188
189 int &Pipe::read_fd() const
190 {
191     return m_p->m_fd[0];
192 }
193
194 int &Pipe::write_fd() const
195 {
196     return m_p->m_fd[1];
197 }
198
199 /*
200  * Local variables:
201  * c-basic-offset: 4
202  * indent-tabs-mode: nil
203  * c-file-style: "stroustrup"
204  * End:
205  * vim: shiftwidth=4 tabstop=8 expandtab
206  */
207