• Main Page
  • Modules
  • Classes
  • Files
  • File List
  • File Members

wvunixdgsocket.cc

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

Generated on Thu Aug 12 2010 11:33:11 for WvStreams by  doxygen 1.7.1