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

Generated on Sun Sep 24 20:10:52 2006 for WvStreams by  doxygen 1.4.7