WvStreams
wvunixdgsocket.cc
1#include "wvunixdgsocket.h"
2#include <sys/types.h>
3#include <sys/stat.h>
4
5WvUnixDGSocket::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
66WvUnixDGSocket::~WvUnixDGSocket()
67{
68// log(WvLog::Debug2, "Destroying: %s\n", socketfile);
69 close();
70 if (server)
71 unlink(socketfile);
72}
73
74size_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
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
virtual void close()
Closes the file descriptors.
Definition: wvfdstream.cc:117
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
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvfdstream.cc:214
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
void alarm(time_t msec_timeout)
set an alarm, ie.
Definition: wvstream.cc:1049
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:1058
A Unix domain socket address is really just a filename.
Definition: wvaddr.h:430
virtual size_t uwrite(const void *buf, size_t count)
unbuffered I/O functions; these ignore the buffer, which is handled by write().
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
the data structure used by pre_select()/post_select() and internally by select().
Definition: iwvstream.h:50
A SelectRequest is a convenient way to remember what we want to do to a particular stream: read from ...
Definition: iwvstream.h:34