summaryrefslogtreecommitdiff
path: root/docs/tutorials/015/page13.html
blob: 967948e3d16b9f84ad5d6ccafea1db89084e8fcf (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
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="James CE Johnson">
   <TITLE>ACE Tutorial 015</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

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

<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER>

<P>
<HR WIDTH="100%">
The Protocol_Task implementation takes care of the open(), close(),
put() and svc() methods so that derivatives can concentrate on the
send() and recv() methods.  After a while you find that most
ACE_Task<> derivatives look very similar in the four basic methods and 
only need one or two additional to do any real work.
<HR>
<PRE>

<font color=red>// $Id$</font>

<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>"

<font color=red>// Construct the object and remember the thread count.</font>
<font color=#008888>Protocol_Task::Protocol_Task</font>( int _thr_count )
        : desired_thr_count_(_thr_count)
{
}

<font color=#008888>Protocol_Task::~Protocol_Task</font>(void)
{
}

<font color=red>// Activate the object if necessary.</font>
int <font color=#008888>Protocol_Task::open</font>(void *arg) 
{
  ACE_UNUSED_ARG(arg);

  if( desired_thr_count_ )
  {
      return this->activate(THR_NEW_LWP, desired_thr_count_);
  }

  return(0);
}

<font color=red>/* When we're being closed by the ACE_Stream and we've got threads to
   worry about then we drop a hangup message onto the message queue so 
   that svc() will go away.  Except for the call to is_active(), this
   is lifted directly from Tutorial 14.
*/</font>
int <font color=#008888>Protocol_Task::close</font>(u_long flags)
{
    if (flags == 1 && is_active() )
    {
        ACE_Message_Block *hangupBlock = new ACE_Message_Block();

        hangupBlock->msg_type(<font color=#008888>ACE_Message_Block::MB_HANGUP</font>);
    
        if (this->putq(hangupBlock->duplicate()) == -1) {
            ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::close</font>() putq</font>"), -1);
        }
    
        hangupBlock->release();

        return this->wait();
    }

    return 0;
}

<font color=red>/* The put() method has to make a decision.  If we've got threads then 
   put the unit of work onto the message queue for svc() to deal
   with.  If not then process() it directly.
*/</font>
int <font color=#008888>Protocol_Task::put</font>(ACE_Message_Block *message,ACE_Time_Value *timeout)
{
    if( is_active() )
    {
        return this->putq(message,timeout);
    }

    return this->process(message,timeout);
}

<font color=red>/* svc() is about what you would expect.  This is again lifted
   directly from Tutorial 14 but with a call to process() for handling 
   the logic instead of doing the work right here.
 */</font>
int <font color=#008888>Protocol_Task::svc</font>(void)
{
    ACE_Message_Block * message;
    
    while (1)
    {
            <font color=red>// Get a message</font>
        if ( this->getq(message, 0) == -1) {
            ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Protocol_Task::svc</font>() getq</font>"), -1);
        }

        ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) <font color=#008888>Protocol_Task::svc</font>() got message\n</font>"));

            <font color=red>// Check for hangup</font>
        if (message->msg_type() == <font color=#008888>ACE_Message_Block::MB_HANGUP</font>) {
 
            ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) <font color=#008888>Protocol_Task::svc</font>() -- HANGUP block received\n</font>"));

                <font color=red>// Hangup our thread-pool peers (if any)</font>
            if (this->putq(message->duplicate()) == -1) {
                ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Protocol_Task::svc</font>() putq</font>"), -1);
            }

                <font color=red>// Leave svc()</font>
            break;
        }

            <font color=red>// Do some work on the data.</font>
        if( this->process(message->duplicate(),0) == -1 )
        {
            break;
        }

            <font color=red>// Give up the message block before we go get another.</font>
        message->release();
    }

        <font color=red>// Give up the message block that caused us to exit the</font>
        <font color=red>// while(1) loop.</font>
    message->release();
    
    return(0);
}

<font color=red>/* There's nothing really magic about process().  We just decide if
   we're moving data upstream or downstream and invoke the appropriate 
   virtual function to handle it.
*/</font>
int <font color=#008888>Protocol_Task::process</font>(ACE_Message_Block * message, ACE_Time_Value *timeout)
{
    if( this->is_writer() )
    {
        return this->send(message,timeout);
    }
    
    return this->recv(message,timeout);
}

<font color=red>/* We must insist that derivatives provide a meaningful overload for
   these methods.  It's fairly common for ACE object methods to return 
   an error when an overload is expected but the method cannot be
   safely made pure virtual.
 */</font>
 
int <font color=#008888>Protocol_Task::send</font>(ACE_Message_Block *message,
                        ACE_Time_Value *timeout)
{
    return -1;
}

int <font color=#008888>Protocol_Task::recv</font>(ACE_Message_Block * message,
                        ACE_Time_Value *timeout)
{
    return -1;
}
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page14.html">Continue This Tutorial</A>]</CENTER>