wvunixdgsocket.cc

00001 #include "wvunixdgsocket.h"
00002 
00003 WvUnixDGSocket::WvUnixDGSocket(WvStringParm filename, bool _server, int perms)
00004     : socketfile(filename)
00005 {
00006 //    log(WvLog::Debug2, "Starting up %s!\n", filename);
00007     server = _server;
00008     backoff = 10;
00009 
00010     bufsize = 0;
00011 
00012     // open a datagram unix domain socket
00013     setfd(socket(PF_UNIX, SOCK_DGRAM, 0));
00014 
00015     // if we don't have a file desciptor, something is wrong.
00016     if (getfd() < 0)
00017     {
00018         seterr("No Socket available.");
00019         return;
00020     }
00021 
00022     // set non-blocking mode
00023     fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
00024 
00025     WvUnixAddr uaddr(socketfile);
00026 
00027     // Let this file be reusable, since we're going to own this anyway
00028     // The business with the int x is just Unix stupidities.. *sigh*
00029     int x = 1;
00030     setsockopt(getfd(), SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00031 
00032     if (server)
00033     {
00034         // Fix it so that there can't be another process on this file
00035         unlink(socketfile);
00036 
00037         // Actually bind to the address we set up above.
00038         sockaddr *addr = uaddr.sockaddr();
00039         if (bind(getfd(), (sockaddr *)addr, uaddr.sockaddr_len()))
00040         {
00041             seterr("Bind to %s failed: %s", socketfile, strerror(errno));
00042             close();
00043         }
00044         delete addr;
00045 
00046         chmod(socketfile, perms);
00047     }
00048     else
00049     {
00050         // we're the client, so we connect to someone else's socket
00051         sockaddr *addr = uaddr.sockaddr();
00052         if (connect(getfd(), (sockaddr *)addr, uaddr.sockaddr_len()))
00053         {
00054             seterr("Connect to %s failed: %s",
00055                    socketfile, strerror(errno));
00056             close();
00057         }
00058         delete addr;
00059     }
00060 
00061     drain();
00062 }
00063 
00064 WvUnixDGSocket::~WvUnixDGSocket()
00065 {
00066 //    log(WvLog::Debug2, "Destroying: %s\n", socketfile);
00067     close();
00068     if (server)
00069         unlink(socketfile);
00070 }
00071 
00072 size_t WvUnixDGSocket::uwrite(const void *buf, size_t count)
00073 {
00074     size_t ret = bufs.isempty() ? WvFDStream::uwrite(buf, count) : 0;
00075 
00076     if (ret < count)
00077     {
00078         WvDynBuf *b = new WvDynBuf;
00079         b->put(buf, count);
00080         bufs.append(b, true);
00081         bufsize += count;
00082     }
00083 
00084     return count;
00085 }
00086 
00087 bool WvUnixDGSocket::pre_select(SelectInfo &si)
00088 {
00089     SelectRequest oldwant = si.wants;
00090     if (!bufs.isempty())
00091     {
00092         // stupid unix domain sockets seem to return true when selecting
00093         // for write EVEN IF write() RETURNS -EAGAIN!  Just shoot me.
00094         // 
00095         // To deal with this, we set an alarm() in post_select() if we
00096         // couldn't write everything we wanted.  While the alarm is set,
00097         // we don't try to flush our output buffer.
00098         if (alarm_remaining() <= 0)
00099             si.wants.writable = true;
00100         else if (si.msec_timeout < 0
00101                  || si.msec_timeout > alarm_remaining())
00102             si.msec_timeout = alarm_remaining();
00103     }
00104 
00105     bool sure = WvFDStream::pre_select(si);
00106 
00107     si.wants = oldwant;
00108     return sure;
00109 }
00110 
00111 bool WvUnixDGSocket::post_select(SelectInfo &si)
00112 {
00113     SelectRequest oldwant = si.wants;
00114     if (!bufs.isempty())
00115         si.wants.writable = true;
00116 
00117     bool sure = WvFDStream::post_select(si);
00118 
00119     si.wants = oldwant;
00120 
00121     if (sure)
00122     {
00123         // try flushing previous bufs
00124         WvBufList::Iter i(bufs);
00125         for (i.rewind(); i.next(); )
00126         {
00127             int used = i->used();
00128             int retval = WvFDStream::uwrite(i->get(used), used);
00129             if (retval < used)
00130             {
00131                 i->unget(used);
00132                 alarm(backoff *= 2);
00133                 if (backoff > 1000)
00134                     backoff = 1000;
00135                 break; // can't continue
00136             }
00137             else
00138             {
00139                 bufsize -= used;
00140                 i.xunlink(); // done with that one
00141                 backoff = 10;
00142             }
00143         }
00144     }
00145 
00146     return sure;
00147 }
00148 
00149 

Generated on Fri Oct 5 18:20:29 2007 for WvStreams by  doxygen 1.5.3