configure.ac: if neither boost nor tr1 is available, die right away.
[wvstreams.git] / ipstreams / wvunixsocket.cc
blob329eafcc25b96383da5c925bad70eb5ab54119e1
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * WvStream-based Unix domain socket connection class. See wvunixsocket.h.
6 */
7 #include "wvistreamlist.h"
8 #include "wvunixlistener.h"
9 #include "wvunixsocket.h"
10 #include "wvstringmask.h"
11 #include "wvmoniker.h"
12 #include "wvlinkerhack.h"
14 #if HAVE_ERRNO_H
15 # include <errno.h>
16 #endif
17 #include <stdio.h>
18 #if HAVE_SYS_TYPES_H
19 # include <sys/types.h>
20 #endif
21 #if STDC_HEADERS
22 # include <stdlib.h>
23 # include <stddef.h>
24 #else
25 # if HAVE_STDLIB_H
26 # include <stdlib.h>
27 # endif
28 #endif
29 #if HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
32 #if HAVE_SYS_SOCKET_H
33 # include <sys/socket.h>
34 #endif
35 #if HAVE_NETDB_H
36 # include <netdb.h>
37 #endif
38 #if HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41 #if HAVE_NETINET_IP_H
42 # if HAVE_NETINET_IN_SYSTM_H
43 # include <netinet/in_systm.h>
44 # endif
45 # include <netinet/ip.h>
46 #endif
47 #if HAVE_NETINET_TCP_H
48 # include <netinet/tcp.h>
49 #endif
51 #include <fcntl.h>
52 #include <sys/un.h>
54 WV_LINK(WvUnixConn);
55 WV_LINK(WvUnixListener);
57 static IWvStream *creator(WvStringParm s, IObject*)
59 return new WvUnixConn(s);
62 static WvMoniker<IWvStream> reg("unix", creator);
65 static IWvListener *listener(WvStringParm s, IObject *)
67 WvConstStringBuffer b(s);
68 WvString path = wvtcl_getword(b);
69 WvString wrapper = b.getstr();
70 IWvListener *l = new WvUnixListener(path, 0777);
71 if (l && !!wrapper)
72 l->addwrap(wv::bind(&IWvStream::create, wrapper, _1));
73 return l;
76 static IWvListener *modelistener(WvStringParm s, IObject *)
78 WvConstStringBuffer b(s);
80 // strtoul knows how to interpret octal if it starts with '0'
81 int mode = strtoul(wvtcl_getword(b, WvStringMask(":")), NULL, 0);
82 if (b.peekch() == ':')
83 b.get(1);
84 WvString path = wvtcl_getword(b);
85 WvString wrapper = b.getstr();
86 IWvListener *l = new WvUnixListener(path, mode);
87 if (l && !!wrapper)
88 l->addwrap(wv::bind(&IWvStream::create, wrapper, _1));
89 return l;
92 static WvMoniker<IWvListener> lreg("unix", listener);
93 static WvMoniker<IWvListener> lmodereg("unixmode", modelistener);
96 WvUnixConn::WvUnixConn(int _fd, const WvUnixAddr &_addr)
97 : WvFDStream(_fd), addr(_addr)
99 // all is well and we're connected.
100 set_nonblock(true);
101 set_close_on_exec(true);
105 WvUnixConn::WvUnixConn(const WvUnixAddr &_addr)
106 : addr(_addr)
108 setfd(socket(PF_UNIX, SOCK_STREAM, 0));
109 if (getfd() < 0)
111 seterr(errno);
112 return;
115 // Make the socket non-blocking and close-on-exec.
116 fcntl(getfd(), F_SETFD, FD_CLOEXEC);
117 fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
119 sockaddr *sa = addr.sockaddr();
120 if (connect(getfd(), sa, addr.sockaddr_len()) < 0)
121 seterr(errno);
122 delete sa;
124 // all is well and we're connected.
125 set_nonblock(true);
126 set_close_on_exec(true);
130 WvUnixConn::~WvUnixConn()
132 // we don't want to delete the socket file here; that's a job for the
133 // listener class.
135 // close the socket
136 close();
140 const WvUnixAddr *WvUnixConn::src() const
142 return &addr;
146 WvUnixListener::WvUnixListener(const WvUnixAddr &_addr, int create_mode)
147 : WvListener(new WvFdStream(socket(PF_UNIX, SOCK_STREAM, 0))),
148 addr(_addr)
150 WvFdStream *fds = (WvFdStream *)cloned;
152 mode_t oldmask;
153 bound_okay = false;
155 if (getfd() < 0)
157 // error inherited from substream
158 return;
161 fds->set_close_on_exec(true);
162 fds->set_nonblock(true);
164 sockaddr *sa = addr.sockaddr();
165 size_t salen = addr.sockaddr_len();
167 if (connect(getfd(), sa, salen) == 0) // successful connect?!
168 seterr(EADDRINUSE); // someone is using this already!
169 else
171 // unfortunately we have to change the umask here to make the
172 // create_mode work, because bind() doesn't take extra arguments
173 // like open() does. However, we don't actually want to _cancel_
174 // the effects of umask, only add to them; so the original umask is
175 // or'ed into ~create_mode. This way it acts like open().
176 oldmask = umask(0777); // really just reading the old umask here
177 umask(oldmask | ((~create_mode) & 0777));
179 ::unlink(WvString(addr));
181 if (bind(getfd(), sa, salen) || listen(getfd(), 50))
182 seterr(errno);
183 else
184 bound_okay = true;
186 umask(oldmask);
189 delete sa;
193 WvUnixListener::~WvUnixListener()
195 close();
199 void WvUnixListener::close()
201 // delete the socket _before_ closing it. Unix will keep
202 // existing connections around anyway (if any), but if it's idle, then
203 // we never have an existing not-in-use socket inode.
204 if (bound_okay)
206 WvString filename(addr);
207 ::unlink(filename);
210 WvListener::close();
214 IWvStream *WvUnixListener::accept()
216 struct sockaddr_un saun;
217 socklen_t len = sizeof(saun);
219 if (!isok()) return NULL;
221 int newfd = ::accept(getfd(), (struct sockaddr *)&saun, &len);
222 if (newfd >= 0)
223 return wrap(new WvUnixConn(newfd, addr));
224 else if (errno == EAGAIN || errno == EINTR)
225 return NULL; // this listener is doing weird stuff
226 else
228 seterr(errno);
229 return NULL;
234 void WvUnixListener::auto_accept(WvIStreamList *list,
235 wv::function<void(IWvStream*)> cb)
237 onaccept(wv::bind(&WvUnixListener::accept_callback, this, list,
238 cb, _1));
241 void WvUnixListener::auto_accept(wv::function<void(IWvStream*)> cb)
243 auto_accept(&WvIStreamList::globallist, cb);
247 void WvUnixListener::accept_callback(WvIStreamList *list,
248 wv::function<void(IWvStream*)> cb,
249 IWvStream *_conn)
251 WvStreamClone *conn = new WvStreamClone(_conn);
252 conn->setcallback(wv::bind(cb, conn));
253 list->append(conn, true, "WvUnixConn");
257 const WvUnixAddr *WvUnixListener::src() const
259 return &addr;