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