wvunixsocket.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvStream-based Unix domain socket connection class.  See wvunixsocket.h.
00006  */
00007 #include "wvistreamlist.h"
00008 #include "wvunixsocket.h"
00009 #include "wvmoniker.h"
00010 
00011 #if HAVE_ERRNO_H
00012 # include <errno.h>
00013 #endif
00014 #include <stdio.h>
00015 #if HAVE_SYS_TYPES_H
00016 # include <sys/types.h>
00017 #endif
00018 #if STDC_HEADERS
00019 # include <stdlib.h>
00020 # include <stddef.h>
00021 #else
00022 # if HAVE_STDLIB_H
00023 #  include <stdlib.h>
00024 # endif
00025 #endif
00026 #if HAVE_SYS_STAT_H
00027 # include <sys/stat.h>
00028 #endif
00029 #if HAVE_SYS_SOCKET_H
00030 # include <sys/socket.h>
00031 #endif
00032 #if HAVE_NETDB_H
00033 # include <netdb.h>
00034 #endif
00035 #if HAVE_NETINET_IN_H
00036 # include <netinet/in.h>
00037 #endif
00038 #if HAVE_NETINET_IP_H
00039 # if HAVE_NETINET_IN_SYSTM_H
00040 #  include <netinet/in_systm.h>
00041 # endif
00042 # include <netinet/ip.h>
00043 #endif
00044 #if HAVE_NETINET_TCP_H
00045 # include <netinet/tcp.h>
00046 #endif
00047 
00048 #include <fcntl.h>
00049 #include <sys/un.h>
00050 
00051 static IWvStream *creator(WvStringParm s)
00052 {
00053     return new WvUnixConn(s);
00054 }
00055 
00056 static WvMoniker<IWvStream> reg("unix", creator);
00057 
00058 
00059 WvUnixConn::WvUnixConn(int _fd, const WvUnixAddr &_addr)
00060     : WvFDStream(_fd), addr(_addr)
00061 {
00062     // all is well and we're connected.
00063     set_nonblock(true);
00064     set_close_on_exec(true);
00065 }
00066 
00067 
00068 WvUnixConn::WvUnixConn(const WvUnixAddr &_addr)
00069     : addr(_addr)
00070 {
00071     setfd(socket(PF_UNIX, SOCK_STREAM, 0));
00072     if (getfd() < 0)
00073     {
00074         seterr(errno);
00075         return;
00076     }
00077     
00078     // Make the socket non-blocking and close-on-exec.
00079     fcntl(getfd(), F_SETFD, FD_CLOEXEC);
00080     fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
00081     
00082     sockaddr *sa = addr.sockaddr();
00083     if (connect(getfd(), sa, addr.sockaddr_len()) < 0)
00084         seterr(errno);
00085     delete sa;
00086     
00087     // all is well and we're connected.
00088     set_nonblock(true);
00089     set_close_on_exec(true);
00090 }
00091 
00092 
00093 WvUnixConn::~WvUnixConn()
00094 {
00095     // we don't want to delete the socket file here; that's a job for the
00096     // listener class.
00097     
00098     // close the socket
00099     close();
00100 }
00101 
00102 
00103 const WvUnixAddr *WvUnixConn::src() const
00104 {
00105     return &addr;
00106 }
00107 
00108 
00109 WvUnixListener::WvUnixListener(const WvUnixAddr &_addr, int create_mode)
00110         : addr(_addr)
00111 {
00112     mode_t oldmask;
00113     
00114     auto_list = NULL;
00115     auto_userdata = NULL;
00116     bound_okay = false;
00117     
00118     setfd(socket(PF_UNIX, SOCK_STREAM, 0));
00119     if (getfd() < 0 || fcntl(getfd(), F_SETFD, 1))
00120     {
00121         seterr(errno);
00122         return;
00123     }
00124     
00125     sockaddr *sa = addr.sockaddr();
00126     size_t salen = addr.sockaddr_len();
00127     
00128     if (connect(getfd(), sa, salen) == 0) // successful connect?!
00129         seterr(EADDRINUSE); // someone is using this already!
00130     else
00131     {
00132         // unfortunately we have to change the umask here to make the
00133         // create_mode work, because bind() doesn't take extra arguments
00134         // like open() does. However, we don't actually want to _cancel_
00135         // the effects of umask, only add to them; so the original umask is
00136         // or'ed into ~create_mode.
00137         oldmask = umask(0777); // really just reading the old umask here
00138         umask(oldmask | ((~create_mode) & 0777));
00139         
00140         ::unlink(WvString(addr));
00141         
00142         if (bind(getfd(), sa, salen) || listen(getfd(), 50))
00143             seterr(errno);
00144         else
00145             bound_okay = true;
00146 
00147         umask(oldmask);
00148     }
00149     
00150     delete sa;
00151 }
00152 
00153 
00154 WvUnixListener::~WvUnixListener()
00155 {
00156     close();
00157 }
00158 
00159 
00160 void WvUnixListener::close()
00161 {
00162     // delete the socket _before_ closing it.  Unix will keep
00163     // existing connections around anyway (if any), but if it's idle, then
00164     // we never have an existing not-in-use socket inode.
00165     if (bound_okay)
00166     {
00167         WvString filename(addr);
00168         ::unlink(filename);
00169     }
00170     
00171     WvFDStream::close();
00172 }
00173 
00174 
00175 WvUnixConn *WvUnixListener::accept()
00176 {
00177     struct sockaddr_un saun;
00178     socklen_t len = sizeof(saun);
00179     int newfd;
00180     WvUnixConn *ret;
00181 
00182     newfd = ::accept(getfd(), (struct sockaddr *)&saun, &len);
00183     ret = new WvUnixConn(newfd, addr);
00184     return ret;
00185 }
00186 
00187 
00188 void WvUnixListener::auto_accept(WvIStreamList *list,
00189                                  WvStreamCallback callfunc, void *userdata)
00190 {
00191     auto_list = list;
00192     auto_callback = callfunc;
00193     auto_userdata = userdata;
00194     setcallback(accept_callback, this);
00195 }
00196 
00197 
00198 void WvUnixListener::accept_callback(WvStream &, void *userdata)
00199 {
00200     WvUnixListener &l = *(WvUnixListener *)userdata;
00201 
00202     WvUnixConn *connection = l.accept();
00203     connection->setcallback(l.auto_callback, l.auto_userdata);
00204     l.auto_list->append(connection, true);
00205 }
00206 
00207 
00208 size_t WvUnixListener::uread(void *, size_t)
00209 {
00210     return 0;
00211 }
00212 
00213 
00214 size_t WvUnixListener::uwrite(const void *, size_t)
00215 {
00216     return 0;
00217 }
00218 
00219 
00220 const WvUnixAddr *WvUnixListener::src() const
00221 {
00222     return &addr;
00223 }
00224 

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