WvStreams
wvunixdgsocket.cc
1 #include "wvunixdgsocket.h"
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 
5 WvUnixDGSocket::WvUnixDGSocket(WvStringParm filename, bool _server, int perms)
6  : socketfile(filename)
7 {
8 // log(WvLog::Debug2, "Starting up %s!\n", filename);
9  server = _server;
10  backoff = 10;
11 
12  bufsize = 0;
13 
14  // open a datagram unix domain socket
15  setfd(socket(PF_UNIX, SOCK_DGRAM, 0));
16 
17  // if we don't have a file desciptor, something is wrong.
18  if (getfd() < 0)
19  {
20  seterr("No Socket available.");
21  return;
22  }
23 
24  // set non-blocking mode
25  fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
26 
27  WvUnixAddr uaddr(socketfile);
28 
29  // Let this file be reusable, since we're going to own this anyway
30  // The business with the int x is just Unix stupidities.. *sigh*
31  int x = 1;
32  setsockopt(getfd(), SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
33 
34  if (server)
35  {
36  // Fix it so that there can't be another process on this file
37  unlink(socketfile);
38 
39  // Actually bind to the address we set up above.
40  sockaddr *addr = uaddr.sockaddr();
41  if (bind(getfd(), (sockaddr *)addr, uaddr.sockaddr_len()))
42  {
43  seterr("Bind to %s failed: %s", socketfile, strerror(errno));
44  close();
45  }
46  delete addr;
47 
48  chmod(socketfile, perms);
49  }
50  else
51  {
52  // we're the client, so we connect to someone else's socket
53  sockaddr *addr = uaddr.sockaddr();
54  if (connect(getfd(), (sockaddr *)addr, uaddr.sockaddr_len()))
55  {
56  seterr("Connect to %s failed: %s",
57  socketfile, strerror(errno));
58  close();
59  }
60  delete addr;
61  }
62 
63  drain();
64 }
65 
66 WvUnixDGSocket::~WvUnixDGSocket()
67 {
68 // log(WvLog::Debug2, "Destroying: %s\n", socketfile);
69  close();
70  if (server)
71  unlink(socketfile);
72 }
73 
74 size_t WvUnixDGSocket::uwrite(const void *buf, size_t count)
75 {
76  size_t ret = bufs.isempty() ? WvFDStream::uwrite(buf, count) : 0;
77 
78  if (ret < count)
79  {
80  WvDynBuf *b = new WvDynBuf;
81  b->put(buf, count);
82  bufs.append(b, true);
83  bufsize += count;
84  }
85 
86  return count;
87 }
88 
90 {
91  SelectRequest oldwant = si.wants;
92  if (!bufs.isempty())
93  {
94  // stupid unix domain sockets seem to return true when selecting
95  // for write EVEN IF write() RETURNS -EAGAIN! Just shoot me.
96  //
97  // To deal with this, we set an alarm() in post_select() if we
98  // couldn't write everything we wanted. While the alarm is set,
99  // we don't try to flush our output buffer.
100  if (alarm_remaining() <= 0)
101  si.wants.writable = true;
102  else if (si.msec_timeout < 0
103  || si.msec_timeout > alarm_remaining())
104  si.msec_timeout = alarm_remaining();
105  }
106 
108 
109  si.wants = oldwant;
110 }
111 
113 {
114  SelectRequest oldwant = si.wants;
115  if (!bufs.isempty())
116  si.wants.writable = true;
117 
118  bool sure = WvFDStream::post_select(si);
119 
120  si.wants = oldwant;
121 
122  if (sure)
123  {
124  // try flushing previous bufs
125  WvBufList::Iter i(bufs);
126  for (i.rewind(); i.next(); )
127  {
128  int used = i->used();
129  int retval = WvFDStream::uwrite(i->get(used), used);
130  if (retval < used)
131  {
132  i->unget(used);
133  alarm(backoff *= 2);
134  if (backoff > 1000)
135  backoff = 1000;
136  break; // can't continue
137  }
138  else
139  {
140  bufsize -= used;
141  i.xunlink(); // done with that one
142  backoff = 10;
143  }
144  }
145  }
146 
147  return sure;
148 }
149 
150