2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * WvStream-based Unix domain socket connection class. See wvunixsocket.h.
7 #include "wvistreamlist.h"
8 #include "wvunixlistener.h"
9 #include "wvunixsocket.h"
10 #include "wvstringmask.h"
11 #include "wvmoniker.h"
12 #include "wvlinkerhack.h"
19 # include <sys/types.h>
30 # include <sys/stat.h>
33 # include <sys/socket.h>
39 # include <netinet/in.h>
42 # if HAVE_NETINET_IN_SYSTM_H
43 # include <netinet/in_systm.h>
45 # include <netinet/ip.h>
47 #if HAVE_NETINET_TCP_H
48 # include <netinet/tcp.h>
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);
72 l
->addwrap(wv::bind(&IWvStream::create
, wrapper
, _1
));
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() == ':')
84 WvString path
= wvtcl_getword(b
);
85 WvString wrapper
= b
.getstr();
86 IWvListener
*l
= new WvUnixListener(path
, mode
);
88 l
->addwrap(wv::bind(&IWvStream::create
, wrapper
, _1
));
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.
101 set_close_on_exec(true);
105 WvUnixConn::WvUnixConn(const WvUnixAddr
&_addr
)
108 setfd(socket(PF_UNIX
, SOCK_STREAM
, 0));
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)
124 // all is well and we're connected.
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
140 const WvUnixAddr
*WvUnixConn::src() const
146 WvUnixListener::WvUnixListener(const WvUnixAddr
&_addr
, int create_mode
)
147 : WvListener(new WvFdStream(socket(PF_UNIX
, SOCK_STREAM
, 0))),
150 WvFdStream
*fds
= (WvFdStream
*)cloned
;
157 // error inherited from substream
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!
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))
193 WvUnixListener::~WvUnixListener()
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.
206 WvString
filename(addr
);
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
);
223 return wrap(new WvUnixConn(newfd
, addr
));
224 else if (errno
== EAGAIN
|| errno
== EINTR
)
225 return NULL
; // this listener is doing weird stuff
234 void WvUnixListener::auto_accept(WvIStreamList
*list
,
235 wv::function
<void(IWvStream
*)> cb
)
237 onaccept(wv::bind(&WvUnixListener::accept_callback
, this, list
,
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
,
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