summaryrefslogtreecommitdiff
path: root/docs/tutorials/001/page04.html
blob: 0f8d7557c3913219de90a21fdf002307509d79ce (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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!-- $Id$ -->
<HTML>
<HEAD>
   <TITLE>ACE Tutorial 001</TITLE>
   <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
   <META NAME="Author" CONTENT="James CE Johnson">
   <META NAME="Description" CONTENT="A first step towards using ACE productively">
</HEAD>
<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">


<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>

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

<P>
<HR>
<PRE>
<font color=red>// $Id$</font>

<font color=blue>#ifndef</font> <font color=purple>_CLIENT_HANDLER_H</font>
<font color=blue>#define</font> <font color=purple>_CLIENT_HANDLER_H</font>

<font color=red>/* A connection handler will also be derived from ACE_Event_Handler so
  that we can register with a reactor.  */</font>

<font color=blue>#include</font> "<A HREF="../../../ace/Event_Handler.h">ace/Event_Handler.h</A>"

<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>)
<font color=blue># pragma</font> <font color=purple>once</font>
<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font>

<font color=blue>#include</font> "<A HREF="../../../ace/INET_Addr.h">ace/INET_Addr.h</A>"

<font color=red>/* Since we're doing TCP/IP, we'll need a SOCK_Stream for the
  connection.  */</font>
<font color=blue>#include</font> "<A HREF="../../../ace/SOCK_Stream.h">ace/SOCK_Stream.h</A>"

class Logging_Handler : public ACE_Event_Handler
{
public:
  <font color=red>/*
    Like the acceptor, we're simple enough to avoid constructor and destructor.
    */</font>

  <font color=red>/* To open the client handler, we have to register ourselves with
    the reactor.  Notice that we don't have to "<font color=green>open</font>" our
    ACE_SOCK_Stream member variable.  Why?  Because the call to the
    acceptor's accept() method took care of those details for us.  */</font>

  int open (ACE_Reactor *reactor)
  {
    <font color=red>/*
      Remember our reactor...
      */</font>
    reactor_ = reactor;

    <font color=red>/* 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.  */</font>

    if (reactor->register_handler (this,
                                   <font color=#008888>ACE_Event_Handler::READ_MASK</font>) == -1)
      ACE_ERROR_RETURN ((LM_ERROR,
                         "<font color=green>(%P|%t) can't register with reactor\n</font>"),
                        -1);
    return 0;
  }

  <font color=red>/* If we're explicitly closed we'll close our "<font color=green>file handle</font>".  The
    net result is to close the connection to the client and remove
    ourselves from the reactor if we're registered */</font>

  int close (void)
  {
    return this->handle_close (ACE_INVALID_HANDLE,
                               <font color=#008888>ACE_Event_Handler::RWE_MASK</font>);
  }

  <font color=red>/* 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.  */</font>

  operator ACE_SOCK_Stream &()
  {
    return this->cli_stream_;
  }

protected:

  <font color=red>/* Again, like the acceptor, we need to provide the connection
    handle to the reactor.  */</font>

  ACE_HANDLE get_handle (void) const
  {
    return this->cli_stream_.get_handle ();
  }

  <font color=red>/* And here's the handle_input().  This is really the workhorse of
    the application.  */</font>

  virtual int handle_input (ACE_HANDLE)
  {
    <font color=red>/*
      Create and initialize a small receive buffer.  The extra byte is
      there to allow us to have a null-terminated string when it's over.
     */</font>
    char buf[BUFSIZ + 1];

    <font color=red>/* 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.

      Although we don't make use of them, there are additional
      parameters you can use with the recv() call.  One of these is an
      ACE_Time_Value that allows you to limit the amount of time
      blocking on the recv().  You would use that if you weren't sure
      if data was available.  Since we only get to handle_input() when
      data is ready, that would be redundant.  On the other hand, if
      you use recv_n() to read *exactly* a number of bytes then
      limiting the time you wait for those bytes might be good.  The
      other paramter that may come in handy is an integer
      &lt;i>flags&lt;/i>.  This is passed directly to the underlying OS
      recv() call.  See the man page recv(2) and the header
      sys/socket.h for the gory details. */</font>

    ssize_t retval;
    switch (retval = this->cli_stream_.recv (buf, BUFSIZ))
    {
    case -1:
      ACE_ERROR_RETURN ((LM_ERROR,
                         "<font color=green>(%P|%t) %p bad read\n</font>",
                         "<font color=green>client logger</font>"),
                        -1);
    case 0:
      ACE_ERROR_RETURN ((LM_ERROR,
                         "<font color=green>(%P|%t) closing log daemon (fd = %d)\n</font>",
                         this->get_handle ()),
                        -1);
    default:
      buf[retval] = '\0';
      ACE_DEBUG ((LM_DEBUG,
                  "<font color=green>(%P|%t) from client: %s</font>",
                  buf));
    }

    return 0;
  }

  <font color=red>/* When handle_input() returns -1, we'll end up here.  There are a
    few housekeeping chores to handle.  */</font>

  int handle_close (ACE_HANDLE,
                    ACE_Reactor_Mask _mask)
  {
    <font color=red>/* 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!  */</font>
    reactor_->remove_handler (this,
                              _mask | <font color=#008888>ACE_Event_Handler::DONT_CALL</font>);

    <font color=red>/* Close the socket that we're connected to the client with.  */</font>
    cli_stream_.close ();

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

    return 0;
  }

protected:

  <font color=red>/* Our peer connection.  */</font>
  ACE_SOCK_Stream cli_stream_;

  <font color=red>/* Our reactor (and our acceptor's reactor).  */</font>
  ACE_Reactor *reactor_;
};

<font color=blue>#endif</font> <font color=red>/* _CLIENT_HANDLER_H */</font>

</PRE>
<HR WIDTH="100%">

<P>
The comments really should tell the story.  The really
interesting stuff is in <i>handle_input()</i>.  Everything
else is just housekeeping.
In the future, we'll learn about ACE_Svc_Handler&lt;>
which will take care of most of the housekeeping for us.
<P>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>