WvStreams
wvunixsocket.cc
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"
13 
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
50 
51 #include <fcntl.h>
52 #include <sys/un.h>
53 
54 WV_LINK(WvUnixConn);
55 WV_LINK(WvUnixListener);
56 
57 static IWvStream *creator(WvStringParm s, IObject*)
58 {
59  return new WvUnixConn(s);
60 }
61 
62 static WvMoniker<IWvStream> reg("unix", creator);
63 
64 
65 static IWvListener *listener(WvStringParm s, IObject *)
66 {
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;
74 }
75 
76 static IWvListener *modelistener(WvStringParm s, IObject *)
77 {
79 
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;
90 }
91 
92 static WvMoniker<IWvListener> lreg("unix", listener);
93 static WvMoniker<IWvListener> lmodereg("unixmode", modelistener);
94 
95 
96 WvUnixConn::WvUnixConn(int _fd, const WvUnixAddr &_addr)
97  : WvFDStream(_fd), addr(_addr)
98 {
99  // all is well and we're connected.
100  set_nonblock(true);
101  set_close_on_exec(true);
102 }
103 
104 
106  : addr(_addr)
107 {
108  setfd(socket(PF_UNIX, SOCK_STREAM, 0));
109  if (getfd() < 0)
110  {
111  seterr(errno);
112  return;
113  }
114 
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);
118 
119  sockaddr *sa = addr.sockaddr();
120  if (connect(getfd(), sa, addr.sockaddr_len()) < 0)
121  seterr(errno);
122  delete sa;
123 
124  // all is well and we're connected.
125  set_nonblock(true);
126  set_close_on_exec(true);
127 }
128 
129 
130 WvUnixConn::~WvUnixConn()
131 {
132  // we don't want to delete the socket file here; that's a job for the
133  // listener class.
134 
135  // close the socket
136  close();
137 }
138 
139 
141 {
142  return &addr;
143 }
144 
145 
146 WvUnixListener::WvUnixListener(const WvUnixAddr &_addr, int create_mode)
147  : WvListener(new WvFdStream(socket(PF_UNIX, SOCK_STREAM, 0))),
148  addr(_addr)
149 {
150  WvFdStream *fds = (WvFdStream *)cloned;
151 
152  mode_t oldmask;
153  bound_okay = false;
154 
155  if (getfd() < 0)
156  {
157  // error inherited from substream
158  return;
159  }
160 
161  fds->set_close_on_exec(true);
162  fds->set_nonblock(true);
163 
164  sockaddr *sa = addr.sockaddr();
165  size_t salen = addr.sockaddr_len();
166 
167  if (connect(getfd(), sa, salen) == 0) // successful connect?!
168  seterr(EADDRINUSE); // someone is using this already!
169  else
170  {
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));
178 
179  ::unlink(WvString(addr));
180 
181  if (bind(getfd(), sa, salen) || listen(getfd(), 50))
182  seterr(errno);
183  else
184  bound_okay = true;
185 
186  umask(oldmask);
187  }
188 
189  delete sa;
190 }
191 
192 
193 WvUnixListener::~WvUnixListener()
194 {
195  close();
196 }
197 
198 
199 void WvUnixListener::close()
200 {
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)
205  {
206  WvString filename(addr);
207  ::unlink(filename);
208  }
209 
210  WvListener::close();
211 }
212 
213 
215 {
216  struct sockaddr_un saun;
217  socklen_t len = sizeof(saun);
218 
219  if (!isok()) return NULL;
220 
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
227  {
228  seterr(errno);
229  return NULL;
230  }
231 }
232 
233 
234 void WvUnixListener::accept_callback(WvIStreamList *list,
235  wv::function<void(IWvStream*)> cb,
236  IWvStream *_conn)
237 {
238  WvStreamClone *conn = new WvStreamClone(_conn);
239  conn->setcallback(wv::bind(cb, conn));
240  list->append(conn, true, "WvUnixConn");
241 }
242 
243 
245 {
246  return &addr;
247 }
248 
WvStringMask
A class used to provide a masked lookup for characters in a string.
Definition: wvstringmask.h:18
wvtcl_getword
WvString wvtcl_getword(WvBuf &buf, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
Get a single tcl word from an input buffer, and return the rest of the buffer untouched.
Definition: wvtclstring.cc:359
IWvListener::addwrap
virtual void addwrap(IWvListenerWrapper _wrapper)=0
Add a wrapper function for this stream: something that accept() will call to possibly wrap the stream...
WvListener
Definition: wvlistener.h:15
IWvStream
Definition: iwvstream.h:24
WvErrorBase::seterr
virtual void seterr(int _errnum)
Set the errnum variable – we have an error.
Definition: wverror.cc:144
IWvListener
Definition: iwvlistener.h:16
WvConstStringBuffer
A raw memory read-only buffer backed by a constant WvString.
Definition: wvbuf.h:241
WvStream::seterr
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
Definition: wvstream.cc:451
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvFdStream::setfd
void setfd(int fd)
Sets the file descriptor for both reading and writing.
Definition: wvfdstream.h:36
WvMoniker
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:61
WvStreamClone
WvStreamClone simply forwards all requests to the "cloned" stream.
Definition: wvstreamclone.h:23
WvFdStream::getfd
int getfd() const
Returns the Unix file descriptor for reading and writing.
Definition: wvfdstream.h:81
WvFdStream::set_close_on_exec
void set_close_on_exec(bool close_on_exec)
Make the fds on this stream close-on-exec or not.
Definition: wvfdstream.cc:107
IObject
Definition: IObject.h:65
WvUnixConn::src
virtual const WvUnixAddr * src() const
return the remote address (source of all incoming packets), which is a constant for any given connect...
Definition: wvunixsocket.cc:140
WvFdStream::close
virtual void close()
Closes the file descriptors.
Definition: wvfdstream.cc:117
WvStream::setcallback
void setcallback(IWvStreamCallback _callfunc)
define the callback function for this stream, called whenever the callback() member is run,...
Definition: wvstream.cc:1130
WvUnixListener
Server end of a Unix Sockets stream.
Definition: wvunixlistener.h:15
WvFdStream
Base class for streams built on Unix file descriptors.
Definition: wvfdstream.h:20
WvUnixConn::WvUnixConn
WvUnixConn(int _fd, const WvUnixAddr &_addr)
connect an already-open socket (used by WvUnixListener)
Definition: wvunixsocket.cc:96
WvUnixListener::src
virtual const WvUnixAddr * src() const
src() is a bit of a misnomer, but it returns the socket address.
Definition: wvunixsocket.cc:244
WvIStreamList
WvStreamList holds a list of WvStream objects – and its select() and callback() functions know how to...
Definition: wvistreamlist.h:20
WvFdStream::set_nonblock
void set_nonblock(bool nonblock)
Make the fds on this stream blocking or non-blocking.
Definition: wvfdstream.cc:97
WvUnixConn
WvStream-based Unix domain socket connection class.
Definition: wvunixsocket.h:33
WvUnixAddr
A Unix domain socket address is really just a filename.
Definition: wvaddr.h:429
WvUnixListener::accept
IWvStream * accept()
return a new WvUnixConn socket corresponding to a newly-accepted connection.
Definition: wvunixsocket.cc:214
WvListener::isok
virtual bool isok() const
By default, returns true if geterr() == 0.
Definition: wvlistener.h:38