libassa 3.5.1
Loading...
Searching...
No Matches
Connector.h
Go to the documentation of this file.
1// -*- c++ -*-
2//------------------------------------------------------------------------------
3// Connector.h
4//------------------------------------------------------------------------------
5// Copyright (C) 1999 Vladislav Grinchenko
6//
7// This library is free software; you can redistribute it and/or
8// modify it under the terms of the GNU Library General Public
9// License as published by the Free Software Foundation; either
10// version 2 of the License, or (at your option) any later version.
11//------------------------------------------------------------------------------
12#ifndef CONNECTOR_H
13#define CONNECTOR_H
14
15#include <unistd.h> // fcntl(2)
16#include <fcntl.h> // fcntl(2)
17
18#if defined(WIN32)
19typedef unsigned int socklen_t;
20#else
21# include <sys/socket.h>
22#endif
23
24#include <string.h> // strerror(3)
25#include <errno.h> // errno(3)
26
27#include "assa/Logger.h"
28#include "assa/EventHandler.h"
29#include "assa/Reactor.h"
30#include "assa/TimeVal.h"
31#include "assa/Address.h"
32#include "assa/Socket.h"
33
34namespace ASSA {
35
47
62template<class SERVICE_HANDLER, class PEER_CONNECTOR>
63class Connector : public virtual EventHandler
64{
65public:
67 Connector ();
68
70 virtual ~Connector ();
71
83 virtual int open (const TimeVal& tv_ = TimeVal (5.0),
85 Reactor* r_ = (Reactor*)NULL);
86
91 virtual int close (void);
92
117 virtual int connect (SERVICE_HANDLER* sh_,
118 Address& addr_,
119 int protocol_ = AF_INET);
120
122 virtual int handle_write (int fd);
123
125 virtual int handle_timeout (TimerId tid);
126
127protected:
137
146
152 virtual int connectServiceHandler (Address& addr, int protocol);
153
157 virtual int activateServiceHandler ();
158
159protected:
162
165
168
171
174
177
179 int m_fd;
180
183
184private:
186 void doAsync (void);
187
191 int doSync (void);
192};
193
194// Convenience definitions
195
196#define SH SERVICE_HANDLER
197#define PC PEER_CONNECTOR
198
199//------------------------------------------------------------------------------
200// Template member functions definitions
201//------------------------------------------------------------------------------
202
203template<class SH, class PC>
205Connector ()
206 : m_tid (0), m_reactor (0), m_state (idle),
207 m_flags (0), m_sh ((SERVICE_HANDLER*)NULL), m_fd (-1), m_mode (sync)
208{
209 trace_with_mask("Connector::Connector",SOCKTRACE);
210 set_id ("Connector");
211}
212
213template<class SH, class PC>
215~Connector ()
216{
217 trace_with_mask("Connector::~Connector",SOCKTRACE);
218 // If I created SERVICE_HANDLER, should I delete it too?
219}
220
221template<class SH, class PC> int
224{
225 trace_with_mask("Connector::open", SOCKTRACE);
226
227 m_timeout = tv_;
228 if (async == mode_ && (Reactor*) NULL == r_)
229 return -1;
230 m_mode = mode_;
231 m_reactor = r_;
232 return 0;
233}
234
235template<class SH, class PC> int
237close ()
238{
239 trace_with_mask("Connector::close",SOCKTRACE);
240 return 0;
241}
242
243template<class SH, class PC> int
246{
247 /*
248 * We restore socket to its original mode only on
249 * successful connection. If error occured, client would have
250 * to close socket anyway.
251 *
252 * NOTE: If sh_==0, then result is dangling pointer
253 * new_sh produced ! Destructor should determine whether
254 * SERVICE_HANDLER has been created dynamically and if so, delete
255 * it.
256 */
257 trace_with_mask("Connector::connect",SOCKTRACE);
258 errno = 0;
259
260 m_sh = makeServiceHandler (sh_);
261 PEER_CONNECTOR& s = *m_sh;
262
263 if (addr_.bad ()) {
264 set_errno (EFAULT); // Bad address
265 EL((ASSA::ASSAERR,"Bad address (errno %d)\n", errno));
266 return -1;
267 }
268
269 if (connectServiceHandler (addr_, protocol_family_) == -1)
270 {
271 int e = get_errno ();
272 if (e == EINPROGRESS || e == EWOULDBLOCK)
273 {
274 if (async == m_mode) {
275 doAsync ();
276 return 0;
277 }
278
279 return doSync ();
280 }
281 return -1;
282 }
283
284 return activateServiceHandler ();
285}
286
287template<class SH, class PC> SERVICE_HANDLER*
290{
291 trace_with_mask("Connector::makeServiceHandler",SOCKTRACE);
292
294
295 if (sh_ == 0) {
297 }
298 return new_sh;
299}
300
301template<class SH, class PC> int
304{
305 trace_with_mask("Connector::connectServiceHandler",SOCKTRACE);
306
307 PEER_CONNECTOR& s = *m_sh;
308
309 if ( !s.open (protocol_family_) ) {
310 EL((ASSA::ASSAERR,"Socket::open (protocol=%d) failed\n",
312 return -1;
313 }
314
315 m_fd = s.getHandler ();
316 s.setOption (ASSA::Socket::nonblocking, 1);
317
318 return (s.connect (addr_) ? 0 : -1);
319}
320
321template<class SH, class PC> int
324{
325 trace_with_mask("Connector::activateServiceHandler",SOCKTRACE);
326
327 return m_sh->open ();
328}
329
330template<class SH, class PC> void
332doAsync (void)
333{
334 trace_with_mask("Connector::doAsync",SOCKTRACE);
335
336 /* We are doing async and 3-way handshake is in
337 * progress - hook up with Reactor and wait on timer.
338 * Write event will be our indicator whether connection
339 * was completed or not.
340 */
341 m_reactor->registerIOHandler (this, m_fd, WRITE_EVENT);
342
343 m_tid = m_reactor->registerTimerHandler (this, m_timeout, "ASYNC Connect");
344 m_state = waiting;
345}
346
347template<class SH, class PC> int
349doSync (void)
350{
351 trace_with_mask("Connector::doSync",SOCKTRACE);
352
353 m_reactor = new Reactor;
354
355 m_reactor->registerIOHandler (this, m_fd, WRITE_EVENT);
356 m_reactor->registerTimerHandler (this, m_timeout, "SYNC Connect");
357 m_state = waiting;
358 m_reactor->waitForEvents (&m_timeout); // Let the ball rolling ...
359 m_reactor->removeHandler (this); // Remove all handlers.
360
361 delete m_reactor;
362 m_reactor = 0;
363
364 if (conned == m_state)
365 {
366 DL((SOCKTRACE,"Synchronous connect() succeeded.\n"));
367 return 0;
368 }
369
370 EL((ASSA::ASSAERR,"Synchronous connect() timed out.\n"));
372
373 return -1;
374}
375
376template<class SH, class PC> int
378handle_write (int fd_)
379{
380 trace_with_mask("Connector::handle_write",SOCKTRACE);
381
382 /* Precondition
383 */
384 if (fd_ != m_fd) {
385 return -1;
386 }
387
388 /* This method serves both sync and async modes - thus the
389 * differences. For async we remove Timer here. sync runs
390 * its own private Reactor and handler termination is
391 * handled in doSync().
392 */
393
394 if (async == m_mode) { // Complete SH activation
395 m_reactor->removeTimerHandler (m_tid);
396 m_tid = 0;
397 }
398
399 /*
400 * Although SUN and Linux man pages on connect(3) claims that
401 * "upon asynchronous establishement of connection, select(3)
402 * will indicate that the file descriptor for the socket is ready
403 * for writing", as discussed in W.S.Stevens "UNIX network
404 * programming", Vol I, 2nd edition, BSD-derived systems also
405 * mark file descriptor both readable and writable when the
406 * connection establishment encouters an error.
407 *
408 * Therefore we need an extra step to find out what really happened.
409 * One way to do so is to look at socket pending errors...
410 */
411
412 int error;
413 int ret;
414 error = ret = errno = 0;
415 socklen_t n = sizeof (error);
416
419 m_reactor->removeHandler (this, WRITE_EVENT);
420
421#if defined(__CYGWIN32__)
422 ret = getsockopt (m_fd, SOL_SOCKET, SO_ERROR, (void*)&error, (int*)&n);
423#elif defined (WIN32)
424 ret = getsockopt (m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, (int*)&n);
425#else
426 ret = getsockopt (m_fd, SOL_SOCKET, SO_ERROR, (void*)&error, &n);
427#endif
428
429 if (ret == 0) {
430 if (error == 0)
431 {
432 if (activateServiceHandler () == 0) {
433 DL((SOCKTRACE,"Nonblocking connect() completed\n"));
434 m_state = conned;
435 }
436 else {
437 DL((SOCKTRACE,"Nonblocking connect() failed\n"));
438 m_state = failed;
439 }
440 return (0); // return value doesn't really matter
441 }
442 /* Socket pending error - propagate it via errno. */
443
444 EL((ASSA::ASSAERR,"Socket pending error: %d\n",error));
445 set_errno (error);
446 }
447 else { /* Solaris pending error. */
448 EL((ASSA::ASSAERR,"getsockopt(3) = %d\n", ret));
449 EL((ASSA::ASSAERR,"Solaris pending error!\n"));
450 }
451 m_state = failed;
452
453 EL((ASSA::ASSAERR,"Nonblocking connect (2) failed\n"));
454
455 if (get_errno () == ECONNREFUSED)
456 {
457 EL((ASSA::ASSAERR,"Try to compare port "
458 "numbers on client and service hosts.\n"));
459 }
460 /* This is the only way to tell SH that we failed to connect.
461 */
462 if (async == m_mode) {
463 m_sh->close ();
464 }
465
466 /* Don't alter fd mask - SERVICE_HANDLER::open() could have changed
467 * it already for application processing needs.
468 */
469 return 0;
470}
471
472template<class SH, class PC> int
475{
476 trace_with_mask("Connector::handle_timeout",SOCKTRACE);
477
478 m_state = failed;
479 set_errno (ETIMEDOUT); // Connection timed out
480
481 if (async == m_mode) {
482 m_reactor->removeHandler (this, WRITE_EVENT);
483 }
484 return -1; // Remove Timer Handler
485}
486
487} // end namespace ASSA
488
489#endif /* CONNECTOR_H */
#define SH
Definition Acceptor.h:134
Address is an abstraction for INET or UNIX-domain address data type.
An abstract interface for handling I/O events, timers, and such.
An abstraction to message logging facility.
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
An implementation of Reactor pattern.
Abstraction of socket data type.
Class TimeVal is a wrapper around UNIX timeval structure.
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
Connector is a template class for initialization of communication services.
Definition Connector.h:64
void doAsync(void)
Setup for asynchronous mode completion.
Definition Connector.h:332
virtual int close(void)
Do-nothing close.
Definition Connector.h:237
virtual int connectServiceHandler(Address &addr, int protocol)
Default strategy is to make synchronous connection with no timeouts.
Definition Connector.h:303
int m_flags
Socket flags (obsolete)
Definition Connector.h:173
ProgressState
state.
Definition Connector.h:131
@ idle
Initialized.
Definition Connector.h:132
@ failed
Failed to connect.
Definition Connector.h:135
@ conned
Connected.
Definition Connector.h:134
@ waiting
Asynchronously waiting on connection completion.
Definition Connector.h:133
TimeVal m_timeout
Timeout.
Definition Connector.h:161
virtual int activateServiceHandler()
Activate handler by calling its open() method.
Definition Connector.h:323
virtual int open(const TimeVal &tv_=TimeVal(5.0), ConnectMode mode_=sync, Reactor *r_=(Reactor *) NULL)
Configure Connector.
Definition Connector.h:223
virtual int connect(SERVICE_HANDLER *sh_, Address &addr_, int protocol_=AF_INET)
Define strategy for establishing connection.
Definition Connector.h:245
virtual int handle_write(int fd)
Handle connection completion.
Definition Connector.h:378
virtual ~Connector()
Destructor. Do-nothing.
Definition Connector.h:215
virtual SERVICE_HANDLER * makeServiceHandler(SERVICE_HANDLER *sh_)
Defines creation strategy for ServiceHandler.
Definition Connector.h:289
Connector()
Constructor. Do-nothing.
Definition Connector.h:205
ConnectMode m_mode
Mode (sync/async)
Definition Connector.h:182
ProgressState m_state
Connection progress state.
Definition Connector.h:170
SERVICE_HANDLER * m_sh
Reference to ServiceHandler.
Definition Connector.h:176
virtual int handle_timeout(TimerId tid)
Handler connection timeout.
Definition Connector.h:474
TimerId m_tid
Timer id.
Definition Connector.h:164
int doSync(void)
Synchronous mode completion.
Definition Connector.h:349
int m_fd
Socket file descriptor.
Definition Connector.h:179
Reactor * m_reactor
Reference to Reactor (for async)
Definition Connector.h:167
EventHandler class.
void set_id(const std::string &id_)
Set EventHandler ID.
bool registerIOHandler(EventHandler *eh_, handler_t fd_, EventType et_=RWE_EVENTS)
Register I/O Event handler with Reactor.
Definition Reactor.cpp:93
@ nonblocking
Set Socket to a non-blocking mode (O_RDWR|O_NONBLOCK).
Definition Socket.h:115
@ WRITE_EVENT
Notify when there will be room for at least 1 byte to be written to IO channel without blocking.
void set_errno(int new_errno_)
Set error number in a portable way.
unsigned long TimerId
Timer Id is used in handle_timeout() calls.
@ SOCKTRACE
Extended Socket & friends messages
Definition LogMask.h:42
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34
int get_errno()
Fetch error number in a portable way.
ConnectMode
Definition Connector.h:43
@ sync
Synchronous connection mode.
Definition Connector.h:44
@ async
Asynchronous connection mode.
Definition Connector.h:45