1 // -*- Mode: C++; -*-
2 //                            Package   : omniORB2
3 // giopStrand.h               Created on: 05/01/2001
4 //                            Author    : Sai Lai Lo (sll)
5 //
6 //    Copyright (C) 2002-2012 Apasphere Ltd
7 //    Copyright (C) 2001      AT&T Laboratories Cambridge
8 //
9 //    This file is part of the omniORB library
10 //
11 //    The omniORB library is free software; you can redistribute it and/or
12 //    modify it under the terms of the GNU Lesser General Public
13 //    License as published by the Free Software Foundation; either
14 //    version 2.1 of the License, or (at your option) any later version.
15 //
16 //    This library is distributed in the hope that it will be useful,
17 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 //    Lesser General Public License for more details.
20 //
21 //    You should have received a copy of the GNU Lesser General Public
22 //    License along with this library. If not, see http://www.gnu.org/licenses/
23 //
24 //
25 // Description:
26 //	*** PROPRIETARY INTERFACE ***
27 //
28 
29 #ifndef __GIOPSTRAND_H__
30 #define __GIOPSTRAND_H__
31 
32 #include <omniORB4/omniTransport.h>
33 #include "giopStrandFlags.h"
34 
35 #ifdef _core_attr
36 # error "A local CPP macro _core_attr has already been defined."
37 #endif
38 
39 #if defined(_OMNIORB_LIBRARY)
40 #     define _core_attr
41 #else
42 #     define _core_attr _OMNIORB_NTDLL_IMPORT
43 #endif
44 
45 
46 OMNI_NAMESPACE_BEGIN(omni)
47 
48 class giopStream;
49 class giopStreamImpl;
50 class giopWorker;
51 class giopServer;
52 class giopCompressor;
53 class GIOP_S;
54 struct giopStream_Buffer;
55 
56 
57 ////////////////////////////////////////////////////////////////////////
58 ////////////////////////////////////////////////////////////////////////
59 class giopStreamList {
60 public:
61   giopStreamList* next;
62   giopStreamList* prev;
63 
giopStreamList()64   inline giopStreamList() {
65     next = this;
66     prev = this;
67   }
68 
insert(giopStreamList & head)69   inline void insert(giopStreamList& head) {
70     next = head.prev->next;
71     head.prev->next = this;
72     prev = head.prev;
73     head.prev = this;
74   }
75 
remove()76   inline void remove() {
77     prev->next = next;
78     next->prev = prev;
79     next = prev = this;
80   }
81 
is_empty(giopStreamList & head)82   static inline CORBA::Boolean is_empty(giopStreamList& head) {
83     return (head.next == &head);
84   }
85 
86 private:
87   giopStreamList(const giopStreamList&);
88   giopStreamList& operator=(const giopStreamList&);
89 };
90 
91 ////////////////////////////////////////////////////////////////////////
92 ////////////////////////////////////////////////////////////////////////
93 class giopStrand : public Strand {
94 public:
95 
96   giopStrand(const giopAddress*);
97   // Ctor for an active strand. I.e. those that are used to connect to
98   // a remote address space.
99   // When a connection is establshed, the reference count goes to 1.
100   //
101   // No thread safety precondition
102 
103 
104   giopStrand(giopConnection*,giopServer*);
105   // Ctor for a passive strand. I.e. those that are created because a
106   // client has connected to this address space.
107   // Increment the reference count on the connection.
108   //
109   // No thread safety precondition
110 
111 
112   CORBA::Boolean safeDelete(CORBA::Boolean forced = 0);
113   // This should be the *ONLY* method to call to delete a strand.
114   // Return TRUE if the strand can be considered deleted.
115   //
116   // The function checks if this connection is satisfied before it returns
117   // true:
118   //
119   //    giopStreamList::is_empty(clients) &&
120   //    giopStreamList::is_empty(servers) &&
121   //    giopStream::noLockWaiting(this)
122   //
123   // If the function returns true, the above condition becomes an invariant
124   // and should not be violated until the dtor of the strand is called.
125   //
126   // The <forced> flag, if set explicitly to 1, causes the function to
127   // skip checking for the above condition. Instead it just go ahead as if
128   // the condition is met. This flag is used for internal implementation
129   // and should not be used by any client of this class.
130   //
131   // Internally, the strand may stays on a bit longer until the connection's
132   // reference count goes to 0 as well.
133   //
134   // Thread Safety preconditions:
135   //    Caller must hold omniTransportLock unless forced == 1.
136 
137 private:
138   CORBA::Boolean pd_safelyDeleted;
139 
140 public:
141 
142   CORBA::Boolean deletePending();
143   // Return true, if safeDelete() has been called and it returns true.
144   //
145   // If this method returns true, the following invariant is always true
146   // until the strand is deleted:
147   //
148   //    giopStreamList::is_empty(clients) &&
149   //    giopStreamList::is_empty(servers) &&
150   //    giopStream::noLockWaiting(this)
151   //
152   // The caller must not do anything that would cause the strand to violate
153   // this invariant. For example, attempt or wait to acquire a lock on the
154   // strand, or to queue any GIOP_S or GIOP_C object to the strand.
155   //
156   //
157   // Thread Safety preconditions:
158   //    Caller must hold omniTransportLock.
159 
160 
161   GIOP_S* acquireServer(giopWorker*);
162   // Acquire a GIOP_S from the strand. Normally this is only  done on
163   // passive strands. However, it can also be used for active strands when
164   // they become birectional, i.e. BiDir == 1.
165   //
166   // Return 0 if a GIOP_S cannot be acquired.
167   //
168   // Thread Safety preconditions:
169   //    Caller must not hold omniTransportLock, it is used internally for
170   //    synchronisation.
171 
172   void   releaseServer(IOP_S*);
173   // Release the GIOP_S to the strand. The GIOP_S must have been acquired
174   // previously through acquireServer from this strand. Passing in a GIOP_S
175   // from a different strand would result in undefined behaviour.
176   //
177   // Thread Safety preconditions:
178   //    Caller must not hold omniTransportLock, it is used internally for
179   //    synchronisation.
180 
181 
182   enum State { ACTIVE,  // The strand is in active use
183 
184 	       DYING,   // Something terminally wrong has happened to the
185 	                // strand, it should be removed at the earliest
186 	                // convenient time.
187 
188 	       TIMEDOUT // This strand can still be used when required but
189        	                // it can also be removed if resources are scarce.
190   };
191 
state()192   State state() const { return pd_state; }
193   // No thread safety precondition, use with extreme care
194 
state(State s)195   void state(State s) { pd_state = s; }
196   // No thread safety precondition, use with extreme care
197 
198 
199   /////////////////////////////////////////////////////////////////////////
200   CORBA::Boolean startIdleCounter();
201   // returns 1 if the idle counter has been successfully started.
202   // returns 0 if the idle counter is already active or has already expired.
203   //
204   // Thread Safety preconditions:
205   //    Caller must hold omniTransportLock.
206 
207   CORBA::Boolean stopIdleCounter();
208   // returns 1 if the idle counter has been successfully stopped.
209   // returns 0 if the idle counter has already expired and cannot be reset.
210   // In the latter case, the caller should assume that the strand is about
211   // to be shutdown and hence should cleanup its usage accordingly.
212   //
213   // Thread Safety preconditions:
214   //    Caller must hold omniTransportLock.
215 
216 
217   ////////////////////////////////////////////////////////////////////////
218   // When idlebeats go to 0, the strand has been idle for a sufficently
219   // long time and should be deleted.
220   // This variable SHOULD NOT be manipulated outside the implementation of
221   // giopStrand.
222   CORBA::Long         idlebeats;
223 
224 
225   giopStreamList      servers;
226   giopStreamList      clients;
227   // a strand may have more than one giopStream instance associated with
228   // it. Mostly this is because from GIOP 1.2 onwards, requests can be
229   // interleaved on associated connection. Each of these request is
230   // represented by a giopStream instance. They are linked together by
231   // servers and clients.
232   //   servers - all the GIOP_S that is serving calls for this strand
233   //   clients - all the GIOP_C that is doing invocation using this strand
234   //
235   // Except when a strand is used to support bidirectional GIOP, only one of
236   // the list will be populated (because plain GIOP is asymetric and one
237   // end is either a client or a server but not both). With bidirectional GIOP,
238   // both lists may be populated.
239 
isClient()240   inline CORBA::Boolean isClient() { return (address != 0); }
241   // Return TRUE if this is an active strand on the client side. Unless
242   // biDir is TRUE, only those messages expected by a GIOP client can be
243   // received from this connection.
244 
isBiDir()245   inline CORBA::Boolean isBiDir() { return (flags & GIOPSTRAND_BIDIR) ? 1 : 0; }
246   // Return TRUE if this is a bidirectional strand.
247 
248   const giopAddress*  address;
249   // address is provided as ctor arg if this is a active strand, otherwise
250   // it is 0.
251 
252   giopConnection*     connection;
253   // connection is provided as ctor arg if this is a passive strand
254   // otherwise it is obtained by address->connect().
255 
256   giopServer*         server;
257   // server is provided as ctor arg if this is a passive strand
258   // otherwise it is 0.
259 
260   CORBA::ULong        flags;
261   // Flags for use by interceptors. See giopStrandFlags.h for
262   // allocated flags values.
263   // Initialised to 0 in the constructor.
264 
265   CORBA::Boolean      gatekeeper_checked;
266   // only applies to passive strand. TRUE(1) means that the serverTransportRule
267   // has been checked. This flag is set by giopWorker and is
268   // not manipulated by the strand class.
269 
270   CORBA::Boolean      first_use;
271   // only applies to active strand. TRUE(1) means this connection has
272   // not been used for any purpose before.
273   // This flag is set to 1 by ctor and reset to 0 by GIOP_C.
274 
275   CORBA::Boolean      first_call;
276   // only applies to active strand. TRUE(1) means this connection has
277   // not yet been used to start a normal invocation. It may have been
278   // used for other purposes, e.g. a locate request.
279   // This flag is set to 1 by ctor and reset to 0 by GIOP_C.
280 
281   CORBA::Boolean      orderly_closed;
282   // only applies to active strand. TRUE(1) means a GIOP CloseConnection
283   // was received and cause the strand state to change to DYING.
284   // This flag is set to 0 by ctor and set to 1 by the giopImpl?? classes.
285 
286 
287   CORBA::Boolean      biDir_initiated;
288   // only applies to active strand. TRUE(1) means biDir service context
289   // has been sent for this connection.
290   // This flag is initialised to 0 by ctor and set to 1 by
291   // setBiDirServiceContext.
292 
293   CORBA::Boolean      biDir_has_callbacks;
294   // only applies to active bidirectional strand. TRUE(1) means call back
295   // objects have been sent through this connection. In other words, the
296   // connection may receive invocations on these objects from the other
297   // end.
298   // This flag is initialised to 0 by ctor and set to 1 by
299   // omniObjRef::_marshal.
300 
301 
302   ////////////////////////////////////////////////////////////////////////
303   ////////////////////////////////////////////////////////////////////////
304   // The following are data structures used by the giopStream instances
305   // associated with this strand AND SHOULD NOT BE manipulated by the Strand
306   // class!!!
307 
308   CORBA::Boolean      tcs_selected;
309   omniCodeSet::TCS_C* tcs_c;
310   omniCodeSet::TCS_W* tcs_w;
311   GIOP::Version       version;
312   giopStreamImpl*     giopImpl;
313   // The transmission codesets for char, wchar, string and wstring are
314   // selected by the client based on the codeset info in the IOR. The
315   // client informs the server of its selection using a codeset service
316   // context. This is done only once per lifetime of a connection (strand).
317   // If <tcs_selected> == 1,
318   //   <tcs_c>, <tcs_w> and <version> records the chosen code set convertors
319   //   and the GIOP version for which the convertors apply.
320 
321   giopCompressor*     compressor;
322   // Compressor used for ZIOP.
323 
324   // Condition variables and counters to implement giopStream locking
325   // functions.
326   omni_tracedcondition rdcond;
327   int                  rd_nwaiting;
328   int                  rd_n_justwaiting;
329   omni_tracedcondition wrcond;
330   int                  wr_nwaiting;
331 
332 
333   CORBA::ULong newSeqNumber();
334   // Return a number suitable for use as the GIOP request id.
335   //
336   // Thread Safety preconditions:
337   //    Caller must hold omniTransportLock.
338 
339 private:
340   CORBA::ULong         seqNumber;
341   // monotonically increasing number to be used as the GIOP request id.
342 
343 
344 public:
345   giopStream_Buffer*   head;
346   giopStream_Buffer*   spare;
347 
348 public:
349   static _core_attr StrandList  active;
350   static _core_attr StrandList  active_timedout;
351   static _core_attr StrandList  passive;
352   // Throughout the lifetime of a strand, it is a member of one and only one
353   // of the lists:
354   //   active           - the ORB uses this connection in the role of a client
355   //                      it is 'active' in the sense that the connection was
356   //                      initiated by this ORB
357   //   active_timedout  - the connection was previously active and has been
358   //                      idled for some time. It will be deleted soon.
359   //   passive          - the ORB uses this connection in the role of a server
360   //                      it is 'passive' because the connection was initiated
361   //                      by the remote party.
362   //
363 
364 
365   static _core_attr CORBA::ULong idleOutgoingBeats;
366   // Number to instantiate idlebeats when the active strand becomes idle.
367 
368   static _core_attr CORBA::ULong idleIncomingBeats;
369   // idleIncomingBeats * scanPeriod == no. of sec. a passive strand should
370   // be allowed to stay idle.
371 
372 public:
373   void deleteStrandAndConnection(CORBA::Boolean forced=0);
374   // Decrement connection's reference count. If it goes to 0, delete
375   // this strand as well. This call ensures that both the strand and
376   // connection die at the same time.
377   //
378   // Thread Safety preconditions:
379   //    Caller must hold omniTransportLock unless forced == 1.
380 
381 #ifdef __GNUG__
382   friend class keep_gcc_happy;
383 #endif
384 
385 private:
386   virtual ~giopStrand();
387 
388   State pd_state;
389 
390   giopStrand(const giopStrand&);
391   giopStrand& operator=(const giopStrand&);
392 
393 };
394 
395 OMNI_NAMESPACE_END(omni)
396 
397 #undef _core_attr
398 
399 #endif // __GIOPSTRAND_H__
400