00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef CONNECTOR_H
00013 #define CONNECTOR_H
00014
00015 #include <unistd.h>
00016 #include <fcntl.h>
00017
00018 #if defined(WIN32)
00019 typedef unsigned int socklen_t;
00020 #else
00021 # include <sys/socket.h>
00022 #endif
00023
00024 #include <string.h>
00025 #include <errno.h>
00026
00027 #include "assa/Logger.h"
00028 #include "assa/EventHandler.h"
00029 #include "assa/Reactor.h"
00030 #include "assa/TimeVal.h"
00031 #include "assa/Address.h"
00032 #include "assa/Socket.h"
00033
00034 namespace ASSA {
00035
00043 enum ConnectMode {
00044 sync,
00045 async
00046 };
00047
00062 template<class SERVICE_HANDLER, class PEER_CONNECTOR>
00063 class Connector : public virtual EventHandler
00064 {
00065 public:
00067 Connector ();
00068
00070 virtual ~Connector ();
00071
00083 virtual int open (const TimeVal& tv_ = TimeVal (5.0),
00084 ConnectMode mode_ = sync,
00085 Reactor* r_ = (Reactor*)NULL);
00086
00091 virtual int close (void);
00092
00117 virtual int connect (SERVICE_HANDLER* sh_,
00118 Address& addr_,
00119 int protocol_ = AF_INET);
00120
00122 virtual int handle_write (int fd);
00123
00125 virtual int handle_timeout (TimerId tid);
00126
00127 protected:
00131 enum ProgressState {
00132 idle,
00133 waiting,
00134 conned,
00135 failed
00136 };
00137
00145 virtual SERVICE_HANDLER* makeServiceHandler (SERVICE_HANDLER* sh_);
00146
00152 virtual int connectServiceHandler (Address& addr, int protocol);
00153
00157 virtual int activateServiceHandler ();
00158
00159 protected:
00161 TimeVal m_timeout;
00162
00164 TimerId m_tid;
00165
00167 Reactor* m_reactor;
00168
00170 ProgressState m_state;
00171
00173 int m_flags;
00174
00176 SERVICE_HANDLER* m_sh;
00177
00179 int m_fd;
00180
00182 ConnectMode m_mode;
00183
00184 private:
00186 void doAsync (void);
00187
00191 int doSync (void);
00192 };
00193
00194
00195
00196 #define SH SERVICE_HANDLER
00197 #define PC PEER_CONNECTOR
00198
00199
00200
00201
00202
00203 template<class SH, class PC>
00204 Connector<SH, PC>::
00205 Connector ()
00206 : m_tid (0), m_reactor (0), m_state (idle),
00207 m_flags (0), m_sh ((SERVICE_HANDLER*)NULL), m_fd (-1), m_mode (sync)
00208 {
00209 trace_with_mask("Connector::Connector",SOCKTRACE);
00210 set_id ("Connector");
00211 }
00212
00213 template<class SH, class PC>
00214 Connector<SH, PC>::
00215 ~Connector ()
00216 {
00217 trace_with_mask("Connector::~Connector",SOCKTRACE);
00218
00219 }
00220
00221 template<class SH, class PC> int
00222 Connector<SH, PC>::
00223 open (const TimeVal& tv_, ConnectMode mode_, Reactor* r_)
00224 {
00225 trace_with_mask("Connector::open", SOCKTRACE);
00226
00227 m_timeout = tv_;
00228 if (async == mode_ && (Reactor*) NULL == r_)
00229 return -1;
00230 m_mode = mode_;
00231 m_reactor = r_;
00232 return 0;
00233 }
00234
00235 template<class SH, class PC> int
00236 Connector<SH, PC>::
00237 close ()
00238 {
00239 trace_with_mask("Connector::close",SOCKTRACE);
00240 return 0;
00241 }
00242
00243 template<class SH, class PC> int
00244 Connector<SH, PC>::
00245 connect (SH* sh_, Address& addr_, int protocol_family_)
00246 {
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 trace_with_mask("Connector::connect",SOCKTRACE);
00258 errno = 0;
00259
00260 m_sh = makeServiceHandler (sh_);
00261 PEER_CONNECTOR& s = *m_sh;
00262
00263 if (addr_.bad ()) {
00264 set_errno (EFAULT);
00265 EL((ASSA::ASSAERR,"Bad address (errno %d)\n", errno));
00266 return -1;
00267 }
00268
00269 if (connectServiceHandler (addr_, protocol_family_) == -1)
00270 {
00271 int e = get_errno ();
00272 if (e == EINPROGRESS || e == EWOULDBLOCK)
00273 {
00274 if (async == m_mode) {
00275 doAsync ();
00276 return 0;
00277 }
00278
00279 return doSync ();
00280 }
00281 return -1;
00282 }
00283
00284 return activateServiceHandler ();
00285 }
00286
00287 template<class SH, class PC> SERVICE_HANDLER*
00288 Connector<SH, PC>::
00289 makeServiceHandler (SERVICE_HANDLER* sh_)
00290 {
00291 trace_with_mask("Connector::makeServiceHandler",SOCKTRACE);
00292
00293 SERVICE_HANDLER* new_sh = sh_;
00294
00295 if (sh_ == 0) {
00296 new_sh = new SERVICE_HANDLER;
00297 }
00298 return new_sh;
00299 }
00300
00301 template<class SH, class PC> int
00302 Connector<SH, PC>::
00303 connectServiceHandler (Address& addr_, int protocol_family_)
00304 {
00305 trace_with_mask("Connector::connectServiceHandler",SOCKTRACE);
00306
00307 PEER_CONNECTOR& s = *m_sh;
00308
00309 if ( !s.open (protocol_family_) ) {
00310 EL((ASSA::ASSAERR,"Socket::open (protocol=%d) failed\n",
00311 protocol_family_));
00312 return -1;
00313 }
00314
00315 m_fd = s.getHandler ();
00316 s.setOption (ASSA::Socket::nonblocking, 1);
00317
00318 return (s.connect (addr_) ? 0 : -1);
00319 }
00320
00321 template<class SH, class PC> int
00322 Connector<SH, PC>::
00323 activateServiceHandler ()
00324 {
00325 trace_with_mask("Connector::activateServiceHandler",SOCKTRACE);
00326
00327 return m_sh->open ();
00328 }
00329
00330 template<class SH, class PC> void
00331 Connector<SH, PC>::
00332 doAsync (void)
00333 {
00334 trace_with_mask("Connector::doAsync",SOCKTRACE);
00335
00336
00337
00338
00339
00340
00341 m_reactor->registerIOHandler (this, m_fd, WRITE_EVENT);
00342
00343 m_tid = m_reactor->registerTimerHandler (this, m_timeout, "ASYNC Connect");
00344 m_state = waiting;
00345 }
00346
00347 template<class SH, class PC> int
00348 Connector<SH, PC>::
00349 doSync (void)
00350 {
00351 trace_with_mask("Connector::doSync",SOCKTRACE);
00352
00353 m_reactor = new Reactor;
00354
00355 m_reactor->registerIOHandler (this, m_fd, WRITE_EVENT);
00356 m_reactor->registerTimerHandler (this, m_timeout, "SYNC Connect");
00357 m_state = waiting;
00358 m_reactor->waitForEvents (&m_timeout);
00359 m_reactor->removeHandler (this);
00360
00361 delete m_reactor;
00362 m_reactor = 0;
00363
00364 if (conned == m_state)
00365 {
00366 DL((SOCKTRACE,"Synchronous connect() succeeded.\n"));
00367 return 0;
00368 }
00369
00370 EL((ASSA::ASSAERR,"Synchronous connect() timed out.\n"));
00371 set_errno (ETIMEDOUT);
00372
00373 return -1;
00374 }
00375
00376 template<class SH, class PC> int
00377 Connector<SH, PC>::
00378 handle_write (int fd_)
00379 {
00380 trace_with_mask("Connector::handle_write",SOCKTRACE);
00381
00382
00383
00384 if (fd_ != m_fd) {
00385 return -1;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394 if (async == m_mode) {
00395 m_reactor->removeTimerHandler (m_tid);
00396 m_tid = 0;
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 int error;
00413 int ret;
00414 error = ret = errno = 0;
00415 socklen_t n = sizeof (error);
00416
00419 m_reactor->removeHandler (this, WRITE_EVENT);
00420
00421 #if defined(__CYGWIN32__)
00422 ret = getsockopt (m_fd, SOL_SOCKET, SO_ERROR, (void*)&error, (int*)&n);
00423 #elif defined (WIN32)
00424 ret = getsockopt (m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, (int*)&n);
00425 #else
00426 ret = getsockopt (m_fd, SOL_SOCKET, SO_ERROR, (void*)&error, &n);
00427 #endif
00428
00429 if (ret == 0) {
00430 if (error == 0)
00431 {
00432 if (activateServiceHandler () == 0) {
00433 DL((SOCKTRACE,"Nonblocking connect() completed\n"));
00434 m_state = conned;
00435 }
00436 else {
00437 DL((SOCKTRACE,"Nonblocking connect() failed\n"));
00438 m_state = failed;
00439 }
00440 return (0);
00441 }
00442
00443
00444 EL((ASSA::ASSAERR,"Socket pending error: %d\n",error));
00445 set_errno (error);
00446 }
00447 else {
00448 EL((ASSA::ASSAERR,"getsockopt(3) = %d\n", ret));
00449 EL((ASSA::ASSAERR,"Solaris pending error!\n"));
00450 }
00451 m_state = failed;
00452
00453 EL((ASSA::ASSAERR,"Nonblocking connect (2) failed\n"));
00454
00455 if (get_errno () == ECONNREFUSED)
00456 {
00457 EL((ASSA::ASSAERR,"Try to compare port "
00458 "numbers on client and service hosts.\n"));
00459 }
00460
00461
00462 if (async == m_mode) {
00463 m_sh->close ();
00464 }
00465
00466
00467
00468
00469 return 0;
00470 }
00471
00472 template<class SH, class PC> int
00473 Connector<SH, PC>::
00474 handle_timeout (TimerId tid_)
00475 {
00476 trace_with_mask("Connector::handle_timeout",SOCKTRACE);
00477
00478 m_state = failed;
00479 set_errno (ETIMEDOUT);
00480
00481 if (async == m_mode) {
00482 m_reactor->removeHandler (this, WRITE_EVENT);
00483 }
00484 return -1;
00485 }
00486
00487 }
00488
00489 #endif