Calls to pipe(2) replaced with usage of Pipe class. Now passes
[metaproxy-moved-to-github.git] / src / pipe.cpp
1
2 /* $Id: pipe.cpp,v 1.2 2005-11-07 21:57:10 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     };
53 }
54
55 using namespace yp2;
56
57 Pipe::Rep::Rep()
58 {
59     m_fd[0] = m_fd[1] = -1;
60     m_socket = -1;
61 }
62
63 bool Pipe::Rep::nonblock(int s)
64 {
65 #ifdef WIN32
66     if (ioctlsocket(s, FIONBIO, &tru) < 0)
67         return false;
68 #else
69     if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
70         return false;
71 #ifndef MSG_NOSIGNAL
72     signal (SIGPIPE, SIG_IGN);
73 #endif
74 #endif
75     return true;
76 }
77
78 Pipe::Pipe(int port_to_use) : m_p(new Rep)
79 {
80     if (port_to_use)
81     {
82         // create server socket
83         m_p->m_socket = socket(AF_INET, SOCK_STREAM, 0);
84         if (m_p->m_socket < 0)
85             throw Pipe::Error("could not create socket");
86 #ifndef WIN32
87         unsigned long one = 1;
88         if (setsockopt(m_p->m_socket, SOL_SOCKET, SO_REUSEADDR, (char*) 
89                        &one, sizeof(one)) < 0)
90             throw Pipe::Error("setsockopt error");
91 #endif
92         // bind server socket
93         struct sockaddr_in add;
94         add.sin_family = AF_INET;
95         add.sin_port = htons(port_to_use);
96         add.sin_addr.s_addr = INADDR_ANY;
97         struct sockaddr *addr = ( struct sockaddr *) &add;
98       
99         if (bind(m_p->m_socket, addr, sizeof(struct sockaddr_in)))
100             throw Pipe::Error("could not bind on socket");
101         
102         if (listen(m_p->m_socket, 3) < 0)
103             throw Pipe::Error("could not listen on socket");
104
105         // client socket
106         in_addr_t tmpadd;
107         tmpadd = (unsigned) inet_addr("127.0.0.1");
108         if (tmpadd)
109             memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
110         else
111             throw Pipe::Error("inet_addr failed");
112             
113         m_p->m_fd[1] = socket(AF_INET, SOCK_STREAM, 0);
114         if (m_p->m_fd[1] < 0)
115             throw Pipe::Error("could not create socket");
116         
117         m_p->nonblock(m_p->m_fd[1]);
118
119         if (connect(m_p->m_fd[1], addr, sizeof(*addr)) < 0 &&
120             errno != EINPROGRESS)
121         {
122             fprintf(stderr, "errno=%d[%s] tmpadd=%x\n", 
123                     errno, strerror(errno), tmpadd);
124             throw Pipe::Error("could not connect to socket");
125         }
126
127         // server accept
128         struct sockaddr caddr;
129         socklen_t caddr_len = sizeof(caddr);
130         m_p->m_fd[0] = accept(m_p->m_socket, &caddr, &caddr_len);
131         if (m_p->m_fd[0] < 0)
132             throw Pipe::Error("could not accept on socket");
133
134         // complete connect
135         fd_set write_set;
136         FD_ZERO(&write_set);
137         FD_SET(m_p->m_fd[1], &write_set);
138         int r = select(m_p->m_fd[1]+1, 0, &write_set, 0, 0);
139         if (r != 1)
140             throw Pipe::Error("could not complete connect");
141
142         close(m_p->m_socket);
143         m_p->m_socket = -1;
144     }
145     else
146     {
147         pipe(m_p->m_fd);
148     }
149 }
150
151 Pipe::~Pipe()
152 {
153     if (m_p->m_fd[0] != -1)
154         close(m_p->m_fd[0]);
155     if (m_p->m_fd[1] != -1)
156         close(m_p->m_fd[1]);
157     if (m_p->m_socket != -1)
158         close(m_p->m_socket);
159 }
160
161 int &Pipe::read_fd() const
162 {
163     return m_p->m_fd[0];
164 }
165
166 int &Pipe::write_fd() const
167 {
168     return m_p->m_fd[1];
169 }
170
171 /*
172  * Local variables:
173  * c-basic-offset: 4
174  * indent-tabs-mode: nil
175  * c-file-style: "stroustrup"
176  * End:
177  * vim: shiftwidth=4 tabstop=8 expandtab
178  */
179