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