00001
00002
00003
00004
00005
00006
00007 #include "wvistreamlist.h"
00008 #include "wvunixlistener.h"
00009 #include "wvunixsocket.h"
00010 #include "wvstringmask.h"
00011 #include "wvmoniker.h"
00012 #include "wvlinkerhack.h"
00013
00014 #if HAVE_ERRNO_H
00015 # include <errno.h>
00016 #endif
00017 #include <stdio.h>
00018 #if HAVE_SYS_TYPES_H
00019 # include <sys/types.h>
00020 #endif
00021 #if STDC_HEADERS
00022 # include <stdlib.h>
00023 # include <stddef.h>
00024 #else
00025 # if HAVE_STDLIB_H
00026 # include <stdlib.h>
00027 # endif
00028 #endif
00029 #if HAVE_SYS_STAT_H
00030 # include <sys/stat.h>
00031 #endif
00032 #if HAVE_SYS_SOCKET_H
00033 # include <sys/socket.h>
00034 #endif
00035 #if HAVE_NETDB_H
00036 # include <netdb.h>
00037 #endif
00038 #if HAVE_NETINET_IN_H
00039 # include <netinet/in.h>
00040 #endif
00041 #if HAVE_NETINET_IP_H
00042 # if HAVE_NETINET_IN_SYSTM_H
00043 # include <netinet/in_systm.h>
00044 # endif
00045 # include <netinet/ip.h>
00046 #endif
00047 #if HAVE_NETINET_TCP_H
00048 # include <netinet/tcp.h>
00049 #endif
00050
00051 #include <fcntl.h>
00052 #include <sys/un.h>
00053
00054 WV_LINK(WvUnixConn);
00055 WV_LINK(WvUnixListener);
00056
00057 static IWvStream *creator(WvStringParm s, IObject*)
00058 {
00059 return new WvUnixConn(s);
00060 }
00061
00062 static WvMoniker<IWvStream> reg("unix", creator);
00063
00064
00065 static IWvListener *listener(WvStringParm s, IObject *)
00066 {
00067 WvConstStringBuffer b(s);
00068 WvString path = wvtcl_getword(b);
00069 WvString wrapper = b.getstr();
00070 IWvListener *l = new WvUnixListener(path, 0777);
00071 if (l && !!wrapper)
00072 l->addwrap(wv::bind(&IWvStream::create, wrapper, _1));
00073 return l;
00074 }
00075
00076 static IWvListener *modelistener(WvStringParm s, IObject *)
00077 {
00078 WvConstStringBuffer b(s);
00079
00080
00081 int mode = strtoul(wvtcl_getword(b, WvStringMask(":")), NULL, 0);
00082 if (b.peekch() == ':')
00083 b.get(1);
00084 WvString path = wvtcl_getword(b);
00085 WvString wrapper = b.getstr();
00086 IWvListener *l = new WvUnixListener(path, mode);
00087 if (l && !!wrapper)
00088 l->addwrap(wv::bind(&IWvStream::create, wrapper, _1));
00089 return l;
00090 }
00091
00092 static WvMoniker<IWvListener> lreg("unix", listener);
00093 static WvMoniker<IWvListener> lmodereg("unixmode", modelistener);
00094
00095
00096 WvUnixConn::WvUnixConn(int _fd, const WvUnixAddr &_addr)
00097 : WvFDStream(_fd), addr(_addr)
00098 {
00099
00100 set_nonblock(true);
00101 set_close_on_exec(true);
00102 }
00103
00104
00105 WvUnixConn::WvUnixConn(const WvUnixAddr &_addr)
00106 : addr(_addr)
00107 {
00108 setfd(socket(PF_UNIX, SOCK_STREAM, 0));
00109 if (getfd() < 0)
00110 {
00111 seterr(errno);
00112 return;
00113 }
00114
00115
00116 fcntl(getfd(), F_SETFD, FD_CLOEXEC);
00117 fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
00118
00119 sockaddr *sa = addr.sockaddr();
00120 if (connect(getfd(), sa, addr.sockaddr_len()) < 0)
00121 seterr(errno);
00122 delete sa;
00123
00124
00125 set_nonblock(true);
00126 set_close_on_exec(true);
00127 }
00128
00129
00130 WvUnixConn::~WvUnixConn()
00131 {
00132
00133
00134
00135
00136 close();
00137 }
00138
00139
00140 const WvUnixAddr *WvUnixConn::src() const
00141 {
00142 return &addr;
00143 }
00144
00145
00146 WvUnixListener::WvUnixListener(const WvUnixAddr &_addr, int create_mode)
00147 : WvListener(new WvFdStream(socket(PF_UNIX, SOCK_STREAM, 0))),
00148 addr(_addr)
00149 {
00150 WvFdStream *fds = (WvFdStream *)cloned;
00151
00152 mode_t oldmask;
00153 bound_okay = false;
00154
00155 if (getfd() < 0)
00156 {
00157
00158 return;
00159 }
00160
00161 fds->set_close_on_exec(true);
00162 fds->set_nonblock(true);
00163
00164 sockaddr *sa = addr.sockaddr();
00165 size_t salen = addr.sockaddr_len();
00166
00167 if (connect(getfd(), sa, salen) == 0)
00168 seterr(EADDRINUSE);
00169 else
00170 {
00171
00172
00173
00174
00175
00176 oldmask = umask(0777);
00177 umask(oldmask | ((~create_mode) & 0777));
00178
00179 ::unlink(WvString(addr));
00180
00181 if (bind(getfd(), sa, salen) || listen(getfd(), 50))
00182 seterr(errno);
00183 else
00184 bound_okay = true;
00185
00186 umask(oldmask);
00187 }
00188
00189 delete sa;
00190 }
00191
00192
00193 WvUnixListener::~WvUnixListener()
00194 {
00195 close();
00196 }
00197
00198
00199 void WvUnixListener::close()
00200 {
00201
00202
00203
00204 if (bound_okay)
00205 {
00206 WvString filename(addr);
00207 ::unlink(filename);
00208 }
00209
00210 WvListener::close();
00211 }
00212
00213
00214 IWvStream *WvUnixListener::accept()
00215 {
00216 struct sockaddr_un saun;
00217 socklen_t len = sizeof(saun);
00218
00219 if (!isok()) return NULL;
00220
00221 int newfd = ::accept(getfd(), (struct sockaddr *)&saun, &len);
00222 if (newfd >= 0)
00223 return wrap(new WvUnixConn(newfd, addr));
00224 else if (errno == EAGAIN || errno == EINTR)
00225 return NULL;
00226 else
00227 {
00228 seterr(errno);
00229 return NULL;
00230 }
00231 }
00232
00233
00234 void WvUnixListener::accept_callback(WvIStreamList *list,
00235 wv::function<void(IWvStream*)> cb,
00236 IWvStream *_conn)
00237 {
00238 WvStreamClone *conn = new WvStreamClone(_conn);
00239 conn->setcallback(wv::bind(cb, conn));
00240 list->append(conn, true, "WvUnixConn");
00241 }
00242
00243
00244 const WvUnixAddr *WvUnixListener::src() const
00245 {
00246 return &addr;
00247 }
00248