WvStreams
wvunixdgsocket.cc
1 #include "wvunixdgsocket.h"
2 #ifdef MACOS
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #endif
6 
7 WvUnixDGSocket::WvUnixDGSocket(WvStringParm filename, bool _server, int perms)
8  : socketfile(filename)
9 {
10 // log(WvLog::Debug2, "Starting up %s!\n", filename);
11  server = _server;
12  backoff = 10;
13 
14  bufsize = 0;
15 
16  // open a datagram unix domain socket
17  setfd(socket(PF_UNIX, SOCK_DGRAM, 0));
18 
19  // if we don't have a file desciptor, something is wrong.
20  if (getfd() < 0)
21  {
22  seterr("No Socket available.");
23  return;
24  }
25 
26  // set non-blocking mode
27  fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
28 
29  WvUnixAddr uaddr(socketfile);
30 
31  // Let this file be reusable, since we're going to own this anyway
32  // The business with the int x is just Unix stupidities.. *sigh*
33  int x = 1;
34  setsockopt(getfd(), SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
35 
36  if (server)
37  {
38  // Fix it so that there can't be another process on this file
39  unlink(socketfile);
40 
41  // Actually bind to the address we set up above.
42  sockaddr *addr = uaddr.sockaddr();
43  if (bind(getfd(), (sockaddr *)addr, uaddr.sockaddr_len()))
44  {
45  seterr("Bind to %s failed: %s", socketfile, strerror(errno));
46  close();
47  }
48  delete addr;
49 
50  chmod(socketfile, perms);
51  }
52  else
53  {
54  // we're the client, so we connect to someone else's socket
55  sockaddr *addr = uaddr.sockaddr();
56  if (connect(getfd(), (sockaddr *)addr, uaddr.sockaddr_len()))
57  {
58  seterr("Connect to %s failed: %s",
59  socketfile, strerror(errno));
60  close();
61  }
62  delete addr;
63  }
64 
65  drain();
66 }
67 
68 WvUnixDGSocket::~WvUnixDGSocket()
69 {
70 // log(WvLog::Debug2, "Destroying: %s\n", socketfile);
71  close();
72  if (server)
73  unlink(socketfile);
74 }
75 
76 size_t WvUnixDGSocket::uwrite(const void *buf, size_t count)
77 {
78  size_t ret = bufs.isempty() ? WvFDStream::uwrite(buf, count) : 0;
79 
80  if (ret < count)
81  {
82  WvDynBuf *b = new WvDynBuf;
83  b->put(buf, count);
84  bufs.append(b, true);
85  bufsize += count;
86  }
87 
88  return count;
89 }
90 
92 {
93  SelectRequest oldwant = si.wants;
94  if (!bufs.isempty())
95  {
96  // stupid unix domain sockets seem to return true when selecting
97  // for write EVEN IF write() RETURNS -EAGAIN! Just shoot me.
98  //
99  // To deal with this, we set an alarm() in post_select() if we
100  // couldn't write everything we wanted. While the alarm is set,
101  // we don't try to flush our output buffer.
102  if (alarm_remaining() <= 0)
103  si.wants.writable = true;
104  else if (si.msec_timeout < 0
105  || si.msec_timeout > alarm_remaining())
106  si.msec_timeout = alarm_remaining();
107  }
108 
110 
111  si.wants = oldwant;
112 }
113 
115 {
116  SelectRequest oldwant = si.wants;
117  if (!bufs.isempty())
118  si.wants.writable = true;
119 
120  bool sure = WvFDStream::post_select(si);
121 
122  si.wants = oldwant;
123 
124  if (sure)
125  {
126  // try flushing previous bufs
127  WvBufList::Iter i(bufs);
128  for (i.rewind(); i.next(); )
129  {
130  int used = i->used();
131  int retval = WvFDStream::uwrite(i->get(used), used);
132  if (retval < used)
133  {
134  i->unget(used);
135  alarm(backoff *= 2);
136  if (backoff > 1000)
137  backoff = 1000;
138  break; // can't continue
139  }
140  else
141  {
142  bufsize -= used;
143  i.xunlink(); // done with that one
144  backoff = 10;
145  }
146  }
147  }
148 
149  return sure;
150 }
151 
152 
WvStream::alarm_remaining
time_t alarm_remaining()
return the number of milliseconds remaining before the alarm will go off; -1 means no alarm is set (i...
Definition: wvstream.cc:1057
WvUnixDGSocket::uwrite
virtual size_t uwrite(const void *buf, size_t count)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
Definition: wvunixdgsocket.cc:76
WvErrorBase::strerror
static WvString strerror(int errnum)
A replacement for the operating system ::strerror() function that can map more kinds of error strings...
Definition: wverror.cc:91
WvFdStream::uwrite
virtual size_t uwrite(const void *buf, size_t count)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
Definition: wvfdstream.cc:162
WvStream::seterr
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
Definition: wvstream.cc:451
WvFdStream::post_select
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvfdstream.cc:254
WvFdStream::setfd
void setfd(int fd)
Sets the file descriptor for both reading and writing.
Definition: wvfdstream.h:36
IWvStream::SelectInfo
the data structure used by pre_select()/post_select() and internally by select().
Definition: iwvstream.h:50
WvFdStream::getfd
int getfd() const
Returns the Unix file descriptor for reading and writing.
Definition: wvfdstream.h:81
WvUnixDGSocket::post_select
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvunixdgsocket.cc:114
WvStream::alarm
void alarm(time_t msec_timeout)
set an alarm, ie.
Definition: wvstream.cc:1048
WvUnixDGSocket::pre_select
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvunixdgsocket.cc:91
IWvStream::SelectRequest
A SelectRequest is a convenient way to remember what we want to do to a particular stream: read from ...
Definition: iwvstream.h:34
WvFdStream::close
virtual void close()
Closes the file descriptors.
Definition: wvfdstream.cc:117
WvDynBufBase< unsigned char >
WvFdStream::pre_select
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvfdstream.cc:214
WvUnixAddr
A Unix domain socket address is really just a filename.
Definition: wvaddr.h:429
WvStream::drain
void drain()
drain the input buffer (read and discard data until select(0) returns false)
Definition: wvstream.cc:699