summaryrefslogtreecommitdiff
path: root/docs/tutorials/001/page04.html
blob: 5223bb342822afbc4d64ee706ec329bcc50fed46 (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
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
   <META NAME="Author" CONTENT="James CE Johnson">
   <META NAME="Description" CONTENT="A first step towards using ACE productively">
   <TITLE>ACE Tutorial 001</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER>

<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER>


<P>
<HR WIDTH="100%">

<P>Now we begin to look at the <A HREF="logger.h">logger</A>
object.

<P>
<HR WIDTH="100%">
<PRE>
#if !defined (_CLIENT_HANDLER_H)
#define _CLIENT_HANDLER_H

/*
  A connection handler will also be derived from ACE_Event_Handler so that we
  can register with a reactor.
 */
#include "ace/Event_Handler.h"

#include "ace/INET_Addr.h"

/*
  Since we're doing TCP/IP, we'll need a SOCK_Stream for the connection.
 */
#include "ace/SOCK_Stream.h"

class Logging_Handler : public ACE_Event_Handler
{
public:

  /*
    Like the acceptor, we're simple enough to avoid constructor and destructor.
   */

  /*
    To open the client handler, we have to register ourselves with the reactor.
    Notice that we don't have to "open" our ACE_SOCK_Stream member variable.
    Why?  Because the call to the acceptor's accept() method took care of those
    details for us.
   */
  int open ( ACE_Reactor * _reactor )
  {
    /*
      Remember our reactor...
     */
    reactor_ = _reactor;

    /*
      In this case we're using the READ_MASK.  Like the acceptor, handle_input()
      will be called due to this mask but it's a nice piece of bookkeeping to
      have separate masks for the separate types of activity.
     */
    if (_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
      ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);

    return 0;
  }

  /*
    If we're explicitly closed we'll close our "file handle".  The net result
    is to close the connection to the client and remove ourselves from the
    reactor if we're registered
   */
  int close (void)
  {
    return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK);
  }

  /*
    This is a bit of magic...  When we call the accept() method of the acceptor
    object, it wants to do work on an ACE_SOCK_Stream.  We have one of those as
    our connection to the client but it would be gross to provide a method to
    access that object.  It's much cooler if the acceptor can just treat the
    Logging_Handler as an ACE_SOCK_Stream.  Providing this cast operator lets
    that happen cleanly.
   */
  operator ACE_SOCK_Stream &amp;()
  {
    return this->cli_stream_;
  }

protected:

  /*
    Again, like the acceptor, we need to provide the connection handle to the reactor.
   */
  ACE_HANDLE get_handle (void) const
  {
    return this->cli_stream_.get_handle ();
  }

  /*
    And here's the handle_input().  This is really the workhorse of the application.
   */
  int handle_input (ACE_HANDLE)
  {
    /*
      Create and initialize a small receive buffer.
     */
    char buf[128];
    memset(buf,0,sizeof(buf));
                
    /*
      Invoke the recv() method of the ACE_SOCK_Stream to get some data.  It will
      return -1 if there is an error.  Otherwise, it will return the number of bytes
      read.  Of course, if it read zero bytes then the connection must be gone.
      How do I know that?  Because handle_input() would not be called by the reactor
      if there wasn't *some* kind of activity and a closed connection looks like a
      read request to the reactor.  But when you read from a closed connection you'll
      read zero bytes.
      Notice that in the error case or closed case we return -1.  That tells the reactor
      to call our handle_close() where we'll take care of shutting down cleanly.
     */
    switch( this->cli_stream_.recv(buf,sizeof buf) )
    {
    case -1:
      ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
    case 0:
      ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n",
        this->get_handle ()), -1);
    default:
      ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
    }
        
    return 0;
  }

  /*
    When handle_input() returns -1, we'll end up here.  There are a few housekeeping
    chores to handle.
   */
  int handle_close (ACE_HANDLE, ACE_Reactor_Mask _mask)
  {
    /*
      Remove ourselves from the reactor.  We have to include the DONT_CALL in the
      mask so that it won't call handle_close() on us again!
     */
    reactor_->remove_handler(this,_mask|ACE_Event_Handler::DONT_CALL);

    /*
      Close the socket that we're connected to the client with.
     */
    cli_stream_.close();

    /*
      Since we know we were dynamically allocated by the acceptor, now is a good
      time to get rid of ourselves.
     */
    delete this;          

    return 0;
  }

protected:

  /*
    Our peer connection.
   */
  ACE_SOCK_Stream cli_stream_; 

  /*
    Our reactor (and our acceptor's reactor).
   */
  ACE_Reactor * reactor_;
};

#endif /* _CLIENT_HANDLER_H */</PRE>


<P>
<HR WIDTH="100%">

<P>Now that we know how to accept a connection request, let's move on to
the next page where we learn how to handle the actual connection. Even
though we just learned about this cool template thing, we will continue
to use the "hand-written" acceptor developed above. As I mentioned, the
only difference will be in the <I>open</I> function of the connection handler
anyway.

<P>
<HR WIDTH="100%">
<CENTER></CENTER>

<CENTER>[<A HREF="..">Tutorial
Index</A>] [<A HREF="page03.html">Previous
Page</A>] [<A HREF="page05.html">Continue
This Tutorial</A>]</CENTER>

</BODY>
</HTML>