summaryrefslogtreecommitdiff
path: root/ace/Asynch_Acceptor.cpp
blob: 9f0756d2be2e8c7dc680109a28b3cb0d37b2bc3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#if !defined (ACE_ASYNCH_ACCEPTOR_C)
#define ACE_ASYNCH_ACCEPTOR_C

#define ACE_BUILD_DLL
#include "ace/Asynch_Acceptor.h"

#if defined (ACE_WIN32) 
// This only works on Win32 platforms 

#include "ace/Message_Block.h"
#include "ace/INET_Addr.h"

#if !defined (__ACE_INLINE__)
#include "ace/Asynch_Acceptor.i"
#endif /* __ACE_INLINE__ */

template <class HANDLER>
ACE_Asynch_Acceptor<HANDLER>::ACE_Asynch_Acceptor (void)
  : listen_handle_ (ACE_INVALID_HANDLE),
    pass_addresses_ (0),
    bytes_to_read_ (0)
{
}
 
template <class HANDLER>
ACE_Asynch_Acceptor<HANDLER>::~ACE_Asynch_Acceptor (void)
{
  // Close down the listen socket
  if (this->listen_handle_ != ACE_INVALID_HANDLE)
    ACE_OS::closesocket (this->listen_handle_);
}
 
template <class HANDLER> int 
ACE_Asynch_Acceptor<HANDLER>::open (const ACE_INET_Addr &address,
				    size_t bytes_to_read,
				    int pass_addresses,
				    int backlog,
				    int reuse_addr,
				    ACE_Proactor *proactor)
{
  this->proactor (proactor);
  this->pass_addresses_ = pass_addresses;
  this->bytes_to_read_ = bytes_to_read;

  // Create the listener socket
  this->listen_handle_ = ACE_OS::socket (PF_INET, SOCK_STREAM, 0);
  if (this->listen_handle_ == ACE_INVALID_HANDLE)
    ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::socket"), -1);
  
  // Initialize the ACE_Asynch_Accept
  if (this->asynch_accept_.open (*this,
				 this->listen_handle_,
				 0,
				 this->proactor ()) == -1)
    ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Accept::open"), -1);

  if (reuse_addr)
    {
      // Reuse the address
      int one = 1;
      if (ACE_OS::setsockopt (this->listen_handle_, 
			      SOL_SOCKET, 
			      SO_REUSEADDR, 
			      (const char*) &one, 
			      sizeof one) == -1)
	ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_OS::setsockopt"), -1);
    }

  // If port is not specified, bind to any port.
  static ACE_INET_Addr sa ((const ACE_INET_Addr &) ACE_Addr::sap_any);

  if (address == sa && ACE::bind_port (this->listen_handle_) == -1)
    ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE::bind_port"), -1);

  // Bind to the specified port.
  if (ACE_OS::bind (this->listen_handle_, 
		    (sockaddr *) address.get_addr (), 
		    address.get_size ()) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "%p\n",
                       "ACE_OS::bind"),
                      -1);
  
  // Start listening
  if (ACE_OS::listen (this->listen_handle_, backlog) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "%p\n",
                       "ACE_OS::listen"), -1);

  // For the number of <backlog>.

  for (int i = 0; i < backlog; i++)
    // Initiate accepts.
    if (this->accept (bytes_to_read) == -1)
      ACE_ERROR_RETURN ((LM_ERROR,
                         "%p\n",
                         "ACE_Asynch_Acceptor::accept"), -1);	
  return 0;
}
 
template <class HANDLER> int
ACE_Asynch_Acceptor<HANDLER>::accept (size_t bytes_to_read)
{
  ACE_Message_Block *message_block = 0;
  size_t space_needed = bytes_to_read + 2 * this->address_size ();

  // Create a new message block big enough for the addresses and data
  ACE_NEW_RETURN (message_block, ACE_Message_Block (space_needed), -1);

  // Initiate asynchronous accepts
  if (this->asynch_accept_.accept (*message_block,
				   bytes_to_read) == -1)
    {
      // Cleanup on error
      message_block->release ();
      ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Asynch_Accept::accept"), -1);
    }
  return 0;
}

template <class HANDLER> void 
ACE_Asynch_Acceptor<HANDLER>::handle_accept (const ACE_Asynch_Accept::Result &result)
{  
#if (defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)) || (_WIN32_WINNT >= 0x0400)
  // If the asynchronous accept succeeds
  if (result.success ())
    {
      // In order to use accept handle with other Window Sockets 1.1
      // functions, we call the setsockopt function with the
      // SO_UPDATE_ACCEPT_CONTEXT option. This option initializes the
      // socket so that other Windows Sockets routines to access the
      // socket correctly.

      if (ACE_OS::setsockopt (result.accept_handle (),  
			      SOL_SOCKET, 
			      SO_UPDATE_ACCEPT_CONTEXT, 
			      (char *) &this->listen_handle_, 
			      sizeof (this->listen_handle_)) == -1)
	ACE_ERROR ((LM_ERROR, "%p", "ACE_OS::setsockopt"));
      
      // The Template method
      HANDLER *new_handler = this->make_handler ();
      
      if (this->pass_addresses_)
	{
	  ACE_INET_Addr local_address, remote_address;
	  // Parse the addresses
	  this->parse_address (result.message_block (),
			       remote_address, 
			       local_address);
	  // Pass the addresses
	  new_handler->addresses (remote_address, local_address);
	}
      // Initiate the handler
      new_handler->open (result.accept_handle (),
			 result.message_block ());
    }
  else
    // The asynchronous accept fails
    {
      // Close the accept handle
      ACE_OS::closesocket (result.accept_handle ());
      ACE_ERROR ((LM_ERROR, "%p\n", "Asynchronous Accept"));
    }
  
  // Delete the dynamically allocated message_block
  result.message_block ().release ();

  // Start off another asynchronous accept to keep the backlog going
  this->accept (this->bytes_to_read_);
#endif // defined (ACE_HAS_WINSOCK2) || (_WIN32_WINNT >= 0x0400)
}

template <class HANDLER> int
ACE_Asynch_Acceptor<HANDLER>::cancel (void)
{
  // All I/O operations that are canceled will complete with the error
  // ERROR_OPERATION_ABORTED. All completion notifications for the I/O
  // operations will occur normally.
  return -1; // ::CancelIO (this->listen_handle_);
}

template <class HANDLER> void
ACE_Asynch_Acceptor<HANDLER>::parse_address (ACE_Message_Block &message_block,
					     ACE_INET_Addr &remote_address,
					     ACE_INET_Addr &local_address)
{
#if (defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)) || (_WIN32_WINNT >= 0x0400)
  sockaddr *local_addr = 0;
  sockaddr *remote_addr = 0;
  int local_size = 0;
  int remote_size = 0;
  
  ::GetAcceptExSockaddrs (message_block.rd_ptr (),
			  message_block.size () - 2 * this->address_size (),
			  this->address_size (),
			  this->address_size (),
			  &local_addr,
			  &local_size,
			  &remote_addr,
			  &remote_size);

  local_address.set_addr  ((sockaddr_in *)  local_addr,  local_size);
  remote_address.set_addr ((sockaddr_in *) remote_addr, remote_size);
#else
  // just in case
  errno = ENOTSUP;
#endif // defined (ACE_HAS_WINSOCK2) || (_WIN32_WINNT >= 0x0400)
}

template <class HANDLER> ACE_HANDLE 
ACE_Asynch_Acceptor<HANDLER>::handle (void) const
{
  return this->listen_handle_;
}

template <class HANDLER> HANDLER *
ACE_Asynch_Acceptor<HANDLER>::make_handler (void) 
{
  // Default behavior
  HANDLER *handler = 0;
  ACE_NEW_RETURN (handler, HANDLER, 0);
  return handler;
}

/* static */
template <class HANDLER> size_t
ACE_Asynch_Acceptor<HANDLER>::address_size (void)
{
  return sizeof (sockaddr) + sizeof (sockaddr_in);
}

#endif /* ACE_WIN32 */
#endif /* ACE_ASYNCH_ACCEPTOR_C */