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