00001
00002
00003
00004
00005
00006
00007 #include "wvstreamlist.h"
00008 #include "wvtcp.h"
00009 #include <fcntl.h>
00010 #include <sys/socket.h>
00011 #include <netinet/in.h>
00012 #include <netinet/ip.h>
00013 #include <netinet/tcp.h>
00014 #include <errno.h>
00015
00016
00017 WvTCPConn::WvTCPConn(const WvIPPortAddr &_remaddr)
00018 {
00019 remaddr = _remaddr;
00020 resolved = true;
00021 connected = false;
00022
00023 do_connect();
00024 }
00025
00026
00027 WvTCPConn::WvTCPConn(int _fd, const WvIPPortAddr &_remaddr)
00028 : WvStream(_fd)
00029 {
00030 remaddr = _remaddr;
00031 resolved = true;
00032 connected = true;
00033
00034 nice_tcpopts();
00035
00036 if (getfd() < 0)
00037 seterr(errno);
00038 }
00039
00040
00041 WvTCPConn::WvTCPConn(const WvString &_hostname, __u16 _port)
00042 : hostname(_hostname)
00043 {
00044 char *hnstr = hostname.edit(), *cptr;
00045
00046 cptr = strchr(hnstr, ':');
00047 if (!cptr)
00048 cptr = strchr(hnstr, '\t');
00049 if (!cptr)
00050 cptr = strchr(hnstr, ' ');
00051 if (cptr)
00052 {
00053 *cptr++ = 0;
00054 remaddr.port = atoi(cptr);
00055 }
00056
00057 if (_port)
00058 remaddr.port = _port;
00059
00060 resolved = connected = false;
00061
00062 WvIPAddr x(hostname);
00063 if (x != WvIPAddr())
00064 {
00065 remaddr = WvIPPortAddr(x, remaddr.port);
00066 resolved = true;
00067 do_connect();
00068 }
00069 else
00070 dns.findaddr(0, hostname, NULL);
00071 }
00072
00073
00074 WvTCPConn::~WvTCPConn()
00075 {
00076
00077 }
00078
00079
00080
00081
00082 void WvTCPConn::nice_tcpopts()
00083 {
00084 fcntl(getfd(), F_SETFD, FD_CLOEXEC);
00085 fcntl(getfd(), F_SETFL, O_RDWR|O_NONBLOCK);
00086
00087 int value = 1;
00088 setsockopt(getfd(), SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value));
00089 }
00090
00091
00092 void WvTCPConn::low_delay()
00093 {
00094 int value;
00095
00096 value = 1;
00097 setsockopt(getfd(), SOL_TCP, TCP_NODELAY, &value, sizeof(value));
00098
00099 value = IPTOS_LOWDELAY;
00100 setsockopt(getfd(), SOL_IP, IP_TOS, &value, sizeof(value));
00101 }
00102
00103
00104 void WvTCPConn::do_connect()
00105 {
00106 sockaddr *sa;
00107
00108 rwfd = socket(PF_INET, SOCK_STREAM, 0);
00109 if (rwfd < 0)
00110 {
00111 seterr(errno);
00112 return;
00113 }
00114
00115 nice_tcpopts();
00116
00117 sa = remaddr.sockaddr();
00118 if (connect(getfd(), sa, remaddr.sockaddr_len()) < 0
00119 && errno != EINPROGRESS)
00120 {
00121 seterr(errno);
00122 delete sa;
00123 return;
00124 }
00125
00126 delete sa;
00127 }
00128
00129
00130 void WvTCPConn::check_resolver()
00131 {
00132 const WvIPAddr *ipr;
00133 int dnsres = dns.findaddr(0, hostname, &ipr);
00134
00135 if (dnsres == 0)
00136 {
00137
00138 resolved = true;
00139 seterr(WvString("Unknown host \"%s\"", hostname));
00140 }
00141 else if (dnsres > 0)
00142 {
00143 remaddr = WvIPPortAddr(*ipr, remaddr.port);
00144 resolved = true;
00145 do_connect();
00146 }
00147 }
00148
00149 #ifndef SO_ORIGINAL_DST
00150 # define SO_ORIGINAL_DST 80
00151 #endif
00152
00153 WvIPPortAddr WvTCPConn::localaddr()
00154 {
00155 sockaddr_in sin;
00156 socklen_t sl = sizeof(sin);
00157
00158 if (!isok())
00159 return WvIPPortAddr();
00160
00161 if (getsockopt(getfd(), SOL_IP, SO_ORIGINAL_DST, (char*)&sin, &sl) < 0
00162 && getsockname(getfd(), (sockaddr *)&sin, &sl))
00163 {
00164 return WvIPPortAddr();
00165 }
00166
00167 return WvIPPortAddr(&sin);
00168 }
00169
00170
00171 const WvIPPortAddr *WvTCPConn::src() const
00172 {
00173 return &remaddr;
00174 }
00175
00176
00177 bool WvTCPConn::pre_select(SelectInfo &si)
00178 {
00179 if (!resolved)
00180 {
00181 if (dns.pre_select(hostname, si))
00182 check_resolver();
00183 }
00184
00185 if (resolved && isok())
00186 {
00187 bool oldw = si.wants.writable, retval;
00188 if (!isconnected()) si.wants.writable = true;
00189 retval = WvStream::pre_select(si);
00190 si.wants.writable = oldw;
00191 return retval;
00192 }
00193 else
00194 return false;
00195 }
00196
00197 bool WvTCPConn::post_select(SelectInfo &si)
00198 {
00199 bool result = false;
00200
00201 if (!resolved)
00202 check_resolver();
00203 else
00204 {
00205 result = WvStream::post_select(si);
00206
00207 if (result && !connected)
00208 {
00209 sockaddr *sa = remaddr.sockaddr();
00210 int retval = connect(getfd(), sa, remaddr.sockaddr_len());
00211
00212 if (!retval || (retval < 0 && errno == EISCONN))
00213 connected = result = true;
00214 else if (retval < 0 && errno != EINPROGRESS)
00215 {
00216 seterr(errno);
00217 result = true;
00218 }
00219 else
00220 result = false;
00221
00222 delete sa;
00223 }
00224 }
00225
00226 return result;
00227 }
00228
00229
00230 bool WvTCPConn::isok() const
00231 {
00232 return !resolved || WvStream::isok();
00233 }
00234
00235
00236 WvTCPListener::WvTCPListener(const WvIPPortAddr &_listenport)
00237 : listenport(_listenport), auto_callback(NULL)
00238 {
00239 listenport = _listenport;
00240 auto_list = NULL;
00241 auto_userdata = NULL;
00242
00243 sockaddr *sa = listenport.sockaddr();
00244
00245 int x = 1;
00246
00247 rwfd = socket(PF_INET, SOCK_STREAM, 0);
00248 if (rwfd < 0
00249 || setsockopt(getfd(), SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x))
00250 || fcntl(getfd(), F_SETFD, 1)
00251 || bind(getfd(), sa, listenport.sockaddr_len())
00252 || listen(getfd(), 5))
00253 {
00254 seterr(errno);
00255 }
00256
00257 if (listenport.port == 0)
00258 {
00259 socklen_t namelen = listenport.sockaddr_len();
00260
00261 if (getsockname(getfd(), sa, &namelen) != 0)
00262 seterr(errno);
00263 else
00264 listenport = WvIPPortAddr((sockaddr_in *)sa);
00265 }
00266
00267 delete sa;
00268 }
00269
00270
00271 WvTCPListener::~WvTCPListener()
00272 {
00273 close();
00274 }
00275
00276
00277
00278 void WvTCPListener::close()
00279 {
00280 WvStream::close();
00281
00282
00283
00284
00285 }
00286
00287
00288 WvTCPConn *WvTCPListener::accept()
00289 {
00290 struct sockaddr_in sin;
00291 socklen_t len = sizeof(sin);
00292 int newfd;
00293 WvTCPConn *ret;
00294
00295 newfd = ::accept(getfd(), (struct sockaddr *)&sin, &len);
00296 ret = new WvTCPConn(newfd, WvIPPortAddr(&sin));
00297 return ret;
00298 }
00299
00300
00301 void WvTCPListener::auto_accept(WvStreamList *list,
00302 WvStreamCallback callfunc, void *userdata)
00303 {
00304 auto_list = list;
00305 auto_callback = callfunc;
00306 auto_userdata = userdata;
00307 setcallback(accept_callback, this);
00308 }
00309
00310
00311 void WvTCPListener::accept_callback(WvStream &, void *userdata)
00312 {
00313 WvTCPListener &l = *(WvTCPListener *)userdata;
00314
00315 WvTCPConn *connection = l.accept();
00316 connection->setcallback(l.auto_callback, l.auto_userdata);
00317 l.auto_list->append(connection, true);
00318 }
00319
00320
00321 size_t WvTCPListener::uread(void *, size_t)
00322 {
00323 return 0;
00324 }
00325
00326
00327 size_t WvTCPListener::uwrite(const void *, size_t)
00328 {
00329 return 0;
00330 }
00331
00332
00333 const WvIPPortAddr *WvTCPListener::src() const
00334 {
00335 return &listenport;
00336 }
00337