summaryrefslogtreecommitdiff
path: root/docs/tutorials/002/page03.html
blob: 7fe8c8ab6114f01c4278faff338c4c92a545f411 (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
<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 002</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

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

<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER>


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

<P>Now lets take a look at the new <A HREF="handler.h">Logging_Handler</A>:

<P>
<HR WIDTH="100%">
<BR> 
<PRE>#ifndef LOGGING_HANDLER_H
#define LOGGING_HANDLER_H

/*
  Since we used the template to create the acceptor, we don't know if there is a
  way to get to the reactor it uses.  We'll take the easy way out and grab the
  global pointer.  (There is a way to get back to the acceptor's reactor that
  we'll see later on.)
 */
extern ACE_Reactor * g_reactor;

/*
  This time we're deriving from ACE_Svc_Handler instead of ACE_Event_Handler.
  The big reason for this is because it already knows how to contain a SOCK_Stream
  and provides all of the method calls needed by the reactor.  The second template
  parameter is for some advanced stuff we'll do with later servers.  For now, just
  use it as is...
 */
class Logging_Handler : public ACE_Svc_Handler &lt; ACE_SOCK_STREAM, ACE_NULL_SYNCH >
{

public:

  /*
    The Acceptor&lt;> template will open() us when there is a new client connection.
   */
  int open (void *)
  {
    ACE_INET_Addr addr;

    /*
      Ask the peer() (held in our baseclass) to tell us the address of the cient
      which has connected.  There may be valid reasons for this to fail where we
      wouldn't want to drop the connection but I can't think of one.
     */
    if (this->peer ().get_remote_addr (addr) == -1)
      return -1;

    /*
      The Acceptor&lt;> won't register us with it's reactor, so we have to do so
      ourselves.  This is where we have to grab that global pointer.  Notice
      that we again use the READ_MASK so that handle_input() will be called
      when the client does something.
     */
    if (g_reactor->register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
      ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);

    /*
      Here's another new treat.  We schedule a timer event.  This particular one
      will fire in two seconds and then every three seconds after that.  It doesn't
      serve any useful purpose in our application other than to show you how it
      is done.
     */
    else if (g_reactor->schedule_timer (this, 0, ACE_Time_Value (2), ACE_Time_Value (3)) == -1)
      ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);

    ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() ));

    return 0;
  }

  /*
    This is a matter of style &amp; maybe taste.  Instead of putting all of this stuff
    into a destructor, we put it here and request that everyone call destroy()
    instead of 'delete'.
   */
  void destroy (void)
  {
    /*
      Remove ourselves from the reactor
     */
    g_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL);

    /*
      Cancel that timer we scheduled in open()
     */
    g_reactor->cancel_timer (this);

    /*
      Shut down the connection to the client.
     */
    this->peer ().close ();

    /*
      Free our memory.
     */
    delete this;
  }

  /*
    If somebody doesn't like us, the will close() us.  Actually, if our open() method
    returns -1, the Acceptor&lt;> will invoke close() on us for cleanup.
   */
  int close (u_long)
  {
    /*
      Clean up and go away.
     */
    this->destroy ();
    return 0;
  }

protected:

  /*
    Respond to input just like Tutorial 1.
   */
  int handle_input (ACE_HANDLE)
  {
    char buf[128];
    memset (buf, 0, sizeof (buf));

    switch (this->peer ().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 the timer expires, handle_timeout() will be called.  The 'arg' is the value passed
    after 'this' in the schedule_timer() call.  You can pass in anything there that you can
    cast to a void*.
   */
  int handle_timeout (const ACE_Time_Value &amp; tv, const void *arg)
  {
    ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
    return 0;
  }

  /*
    Clean ourselves up when handle_input() (or handle_timer()) returns -1
   */
  int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask)
  {
    this->destroy();
    return 0;
  }
};

#endif // LOGGING_HANDLER_H</PRE>


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

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

</BODY>
</HTML>