summaryrefslogtreecommitdiff
authormickeyl <mickeyl>2003-04-16 17:54:46 (UTC)
committer mickeyl <mickeyl>2003-04-16 17:54:46 (UTC)
commitfc4eab06caed9892ded036fc0dcacaf8074f00f9 (patch) (unidiff)
tree663a812e2e1af9c2bbc5a1c84fb89fcf72eb4376
parentbe5832dc22255be38884e352917f48d5b71ae657 (diff)
downloadopie-fc4eab06caed9892ded036fc0dcacaf8074f00f9.zip
opie-fc4eab06caed9892ded036fc0dcacaf8074f00f9.tar.gz
opie-fc4eab06caed9892ded036fc0dcacaf8074f00f9.tar.bz2
start documenting the packet class family - explain why deriving from QObject is clever
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opienet/opcap.h67
1 files changed, 50 insertions, 17 deletions
diff --git a/libopie2/opienet/opcap.h b/libopie2/opienet/opcap.h
index 6bf7416..fe88e68 100644
--- a/libopie2/opienet/opcap.h
+++ b/libopie2/opienet/opcap.h
@@ -39,407 +39,440 @@ extern "C" // work around a bpf/pcap conflict in recent headers
39{ 39{
40 #include <pcap.h> 40 #include <pcap.h>
41} 41}
42#include <netinet/ether.h> 42#include <netinet/ether.h>
43#include <netinet/ip.h> 43#include <netinet/ip.h>
44#include <netinet/udp.h> 44#include <netinet/udp.h>
45#include <netinet/tcp.h> 45#include <netinet/tcp.h>
46#include <time.h> 46#include <time.h>
47 47
48/* QT */ 48/* QT */
49#include <qevent.h> 49#include <qevent.h>
50#include <qfile.h> 50#include <qfile.h>
51#include <qhostaddress.h> 51#include <qhostaddress.h>
52#include <qobject.h> 52#include <qobject.h>
53#include <qstring.h> 53#include <qstring.h>
54#include <qmap.h> 54#include <qmap.h>
55 55
56/* OPIE */ 56/* OPIE */
57#include <opie2/onetutils.h> 57#include <opie2/onetutils.h>
58#include "802_11_user.h" 58#include "802_11_user.h"
59 59
60/* TYPEDEFS */ 60/* TYPEDEFS */
61typedef struct timeval timevalstruct; 61typedef struct timeval timevalstruct;
62typedef struct pcap_pkthdr packetheaderstruct; 62typedef struct pcap_pkthdr packetheaderstruct;
63 63
64/* FORWARDS */ 64/* FORWARDS */
65class OPacketCapturer; 65class OPacketCapturer;
66class QSocketNotifier; 66class QSocketNotifier;
67 67
68/*====================================================================================== 68/*======================================================================================
69 * OPacket - A frame on the wire 69 * OPacket - A frame on the wire
70 *======================================================================================*/ 70 *======================================================================================*/
71// FIXME how many OPackets do we've at a time? QObject seams to be a big for that usage 71
72/** @brief A class representing a data frame on the wire.
73 *
74 * The whole family of the packet classes are used when capturing frames from a network.
75 * Most standard network protocols in use share a common architecture, which mostly is
76 * a packet header and then the packet payload. In layered architectures, each lower layer
77 * encapsulates data from its upper layer - that is it
78 * treats the data from its upper layer as payload and prepends an own header to the packet,
79 * which - again - is treated as the payload for the layer below. The figure below is an
80 * example for how such a data frame is composed out of packets, e.g. when sending a mail.
81 *
82 * <pre>
83 * | User Data | == Mail Data
84 * | SMTP Header | User Data | == SMTP
85 * | TCP Header | SMTP Header | User Data | == TCP
86 * | IP Header | TCP Header | SMTP Header | User Data | == IP
87 * | MAC Header | IP Header | TCP Header | SMTP Header | User Data | == MAC
88 *
89 * </pre>
90 *
91 * The example is trimmed for simplicity, because the MAC (Medium Access Control) layer
92 * also contains a few more levels of encapsulation.
93 * Since the type of the payload is more or less independent from the encapsulating protocol,
94 * the header must be inspected before attempting to decode the payload. Hence, the
95 * encapsulation level varies and can't be deduced without actually looking into the packets.
96 *
97 * For actually working with captured frames, it's useful to identify the packets via names and
98 * insert them into a parent/child - relationship based on the encapsulation. This is why
99 * all packet classes derive from QObject. The amount of overhead caused by the QObject is
100 * not a problem in this case, because we're talking about a theoratical maximum of about
101 * 10 packets per captured frame. We need to stuff them into a searchable list anyway and the
102 * QObject also cares about destroying the sub-, (child-) packets.
103 *
104 * This enables us to perform a simple look for packets of a certain type:
105 * @code
106 * OPacketCapturer* pcap = new OPacketCapturer();
107 * pcap->open( "eth0" );
108 * OPacket* p = pcap->next();
109 * OIPPacket* ip = (OIPPacket*) p->child( "IP" ); // returns 0, if no such child exists
110 * odebug << "got ip packet from " << ip->fromIPAddress().toString() << " to " << ip->toIPAddress().toString() << oendl;
111 *
112 */
113
72class OPacket : public QObject 114class OPacket : public QObject
73{ 115{
74 Q_OBJECT 116 Q_OBJECT
75 117
76 public: 118 public:
77 OPacket( int datalink, packetheaderstruct, const unsigned char*, QObject* parent ); 119 OPacket( int datalink, packetheaderstruct, const unsigned char*, QObject* parent );
78 virtual ~OPacket(); 120 virtual ~OPacket();
79 121
80 timevalstruct timeval() const; 122 timevalstruct timeval() const;
81 123
82 int caplen() const; 124 int caplen() const;
83 int len() const; 125 int len() const;
84 QString dump( int = 32 ) const; 126 QString dump( int = 32 ) const;
85 127
86 void updateStats( QMap<QString,int>&, QObjectList* ); 128 void updateStats( QMap<QString,int>&, QObjectList* );
87 129
88 private: 130 private:
89 const packetheaderstruct _hdr; // pcap packet header 131 const packetheaderstruct _hdr; // pcap packet header
90 const unsigned char* _data; // pcap packet data 132 const unsigned char* _data; // pcap packet data
91 const unsigned char* _end; // end of pcap packet data 133 const unsigned char* _end; // end of pcap packet data
92}; 134};
93 135
94/*====================================================================================== 136/*======================================================================================
95 * OEthernetPacket - DLT_EN10MB frame 137 * OEthernetPacket - DLT_EN10MB frame
96 *======================================================================================*/ 138 *======================================================================================*/
97 139
98//FIXME same critic as above -zecke
99class OEthernetPacket : public QObject 140class OEthernetPacket : public QObject
100{ 141{
101 Q_OBJECT 142 Q_OBJECT
102 143
103 public: 144 public:
104 OEthernetPacket( const unsigned char*, const struct ether_header*, QObject* parent = 0 ); 145 OEthernetPacket( const unsigned char*, const struct ether_header*, QObject* parent = 0 );
105 virtual ~OEthernetPacket(); 146 virtual ~OEthernetPacket();
106 147
107 OMacAddress sourceAddress() const; 148 OMacAddress sourceAddress() const;
108 OMacAddress destinationAddress() const; 149 OMacAddress destinationAddress() const;
109 int type() const; 150 int type() const;
110 151
111 private: 152 private:
112 const struct ether_header* _ether; 153 const struct ether_header* _ether;
113}; 154};
114 155
115 156
116/*====================================================================================== 157/*======================================================================================
117 * OWaveLanPacket - DLT_IEEE802_11 frame 158 * OWaveLanPacket - DLT_IEEE802_11 frame
118 *======================================================================================*/ 159 *======================================================================================*/
119//FIXME same 160
120class OWaveLanPacket : public QObject 161class OWaveLanPacket : public QObject
121{ 162{
122 Q_OBJECT 163 Q_OBJECT
123 164
124 public: 165 public:
125 OWaveLanPacket( const unsigned char*, const struct ieee_802_11_header*, QObject* parent = 0 ); 166 OWaveLanPacket( const unsigned char*, const struct ieee_802_11_header*, QObject* parent = 0 );
126 virtual ~OWaveLanPacket(); 167 virtual ~OWaveLanPacket();
127 168
128 int duration() const; 169 int duration() const;
129 bool fromDS() const; 170 bool fromDS() const;
130 bool toDS() const; 171 bool toDS() const;
131 virtual OMacAddress macAddress1() const; 172 virtual OMacAddress macAddress1() const;
132 virtual OMacAddress macAddress2() const; 173 virtual OMacAddress macAddress2() const;
133 virtual OMacAddress macAddress3() const; 174 virtual OMacAddress macAddress3() const;
134 virtual OMacAddress macAddress4() const; 175 virtual OMacAddress macAddress4() const;
135 bool usesPowerManagement() const; 176 bool usesPowerManagement() const;
136 int type() const; 177 int type() const;
137 int subType() const; 178 int subType() const;
138 int version() const; 179 int version() const;
139 bool usesWep() const; 180 bool usesWep() const;
140 181
141 private: 182 private:
142 const struct ieee_802_11_header* _wlanhdr; 183 const struct ieee_802_11_header* _wlanhdr;
143}; 184};
144 185
145 186
146/*====================================================================================== 187/*======================================================================================
147 * OWaveLanManagementPacket - type: management (T_MGMT) 188 * OWaveLanManagementPacket - type: management (T_MGMT)
148 *======================================================================================*/ 189 *======================================================================================*/
149//FIXME same as above -zecke 190
150class OWaveLanManagementPacket : public QObject 191class OWaveLanManagementPacket : public QObject
151{ 192{
152 Q_OBJECT 193 Q_OBJECT
153 194
154 public: 195 public:
155 OWaveLanManagementPacket( const unsigned char*, const struct ieee_802_11_mgmt_header*, OWaveLanPacket* parent = 0 ); 196 OWaveLanManagementPacket( const unsigned char*, const struct ieee_802_11_mgmt_header*, OWaveLanPacket* parent = 0 );
156 virtual ~OWaveLanManagementPacket(); 197 virtual ~OWaveLanManagementPacket();
157 198
158 QString managementType() const; 199 QString managementType() const;
159 200
160 int beaconInterval() const; 201 int beaconInterval() const;
161 int capabilities() const; // generic 202 int capabilities() const; // generic
162 203
163 bool canESS() const; 204 bool canESS() const;
164 bool canIBSS() const; 205 bool canIBSS() const;
165 bool canCFP() const; 206 bool canCFP() const;
166 bool canCFP_REQ() const; 207 bool canCFP_REQ() const;
167 bool canPrivacy() const; 208 bool canPrivacy() const;
168 209
169 private: 210 private:
170 const struct ieee_802_11_mgmt_header* _header; 211 const struct ieee_802_11_mgmt_header* _header;
171 const struct ieee_802_11_mgmt_body* _body; 212 const struct ieee_802_11_mgmt_body* _body;
172}; 213};
173 214
174 215
175/*====================================================================================== 216/*======================================================================================
176 * OWaveLanManagementSSID 217 * OWaveLanManagementSSID
177 *======================================================================================*/ 218 *======================================================================================*/
178//FIXME is QObject necessary? -zecke 219
179class OWaveLanManagementSSID : public QObject 220class OWaveLanManagementSSID : public QObject
180{ 221{
181 Q_OBJECT 222 Q_OBJECT
182 223
183 public: 224 public:
184 OWaveLanManagementSSID( const unsigned char*, const struct ssid_t*, QObject* parent = 0 ); 225 OWaveLanManagementSSID( const unsigned char*, const struct ssid_t*, QObject* parent = 0 );
185 virtual ~OWaveLanManagementSSID(); 226 virtual ~OWaveLanManagementSSID();
186 227
187 QString ID() const; 228 QString ID() const;
188 229
189 private: 230 private:
190 const struct ssid_t* _data; 231 const struct ssid_t* _data;
191}; 232};
192 233
193/*====================================================================================== 234/*======================================================================================
194 * OWaveLanManagementRates 235 * OWaveLanManagementRates
195 *======================================================================================*/ 236 *======================================================================================*/
196// FIXME same as above -zecke 237
197class OWaveLanManagementRates : public QObject 238class OWaveLanManagementRates : public QObject
198{ 239{
199 Q_OBJECT 240 Q_OBJECT
200 241
201 public: 242 public:
202 OWaveLanManagementRates( const unsigned char*, const struct rates_t*, QObject* parent = 0 ); 243 OWaveLanManagementRates( const unsigned char*, const struct rates_t*, QObject* parent = 0 );
203 virtual ~OWaveLanManagementRates(); 244 virtual ~OWaveLanManagementRates();
204 245
205 private: 246 private:
206 const struct rates_t* _data; 247 const struct rates_t* _data;
207}; 248};
208 249
209/*====================================================================================== 250/*======================================================================================
210 * OWaveLanManagementCF 251 * OWaveLanManagementCF
211 *======================================================================================*/ 252 *======================================================================================*/
212 253
213//FIXME same....
214class OWaveLanManagementCF : public QObject 254class OWaveLanManagementCF : public QObject
215{ 255{
216 Q_OBJECT 256 Q_OBJECT
217 257
218 public: 258 public:
219 OWaveLanManagementCF( const unsigned char*, const struct cf_t*, QObject* parent = 0 ); 259 OWaveLanManagementCF( const unsigned char*, const struct cf_t*, QObject* parent = 0 );
220 virtual ~OWaveLanManagementCF(); 260 virtual ~OWaveLanManagementCF();
221 261
222 private: 262 private:
223 const struct cf_t* _data; 263 const struct cf_t* _data;
224}; 264};
225 265
226/*====================================================================================== 266/*======================================================================================
227 * OWaveLanManagementFH 267 * OWaveLanManagementFH
228 *======================================================================================*/ 268 *======================================================================================*/
229 269
230//FIXME same
231class OWaveLanManagementFH : public QObject 270class OWaveLanManagementFH : public QObject
232{ 271{
233 Q_OBJECT 272 Q_OBJECT
234 273
235 public: 274 public:
236 OWaveLanManagementFH( const unsigned char*, const struct fh_t*, QObject* parent = 0 ); 275 OWaveLanManagementFH( const unsigned char*, const struct fh_t*, QObject* parent = 0 );
237 virtual ~OWaveLanManagementFH(); 276 virtual ~OWaveLanManagementFH();
238 277
239 private: 278 private:
240 const struct fh_t* _data; 279 const struct fh_t* _data;
241}; 280};
242 281
243/*====================================================================================== 282/*======================================================================================
244 * OWaveLanManagementDS 283 * OWaveLanManagementDS
245 *======================================================================================*/ 284 *======================================================================================*/
246//FIXME same 285
247class OWaveLanManagementDS : public QObject 286class OWaveLanManagementDS : public QObject
248{ 287{
249 Q_OBJECT 288 Q_OBJECT
250 289
251 public: 290 public:
252 OWaveLanManagementDS( const unsigned char*, const struct ds_t*, QObject* parent = 0 ); 291 OWaveLanManagementDS( const unsigned char*, const struct ds_t*, QObject* parent = 0 );
253 virtual ~OWaveLanManagementDS(); 292 virtual ~OWaveLanManagementDS();
254 293
255 int channel() const; 294 int channel() const;
256 295
257 private: 296 private:
258 const struct ds_t* _data; 297 const struct ds_t* _data;
259}; 298};
260 299
261/*====================================================================================== 300/*======================================================================================
262 * OWaveLanManagementTim 301 * OWaveLanManagementTim
263 *======================================================================================*/ 302 *======================================================================================*/
264 303
265//FIXME guess what?
266class OWaveLanManagementTim : public QObject 304class OWaveLanManagementTim : public QObject
267{ 305{
268 Q_OBJECT 306 Q_OBJECT
269 307
270 public: 308 public:
271 OWaveLanManagementTim( const unsigned char*, const struct tim_t*, QObject* parent = 0 ); 309 OWaveLanManagementTim( const unsigned char*, const struct tim_t*, QObject* parent = 0 );
272 virtual ~OWaveLanManagementTim(); 310 virtual ~OWaveLanManagementTim();
273 311
274 private: 312 private:
275 const struct tim_t* _data; 313 const struct tim_t* _data;
276}; 314};
277 315
278/*====================================================================================== 316/*======================================================================================
279 * OWaveLanManagementIBSS 317 * OWaveLanManagementIBSS
280 *======================================================================================*/ 318 *======================================================================================*/
281 319
282//FIXME same as above ( Qobject )
283class OWaveLanManagementIBSS : public QObject 320class OWaveLanManagementIBSS : public QObject
284{ 321{
285 Q_OBJECT 322 Q_OBJECT
286 323
287 public: 324 public:
288 OWaveLanManagementIBSS( const unsigned char*, const struct ibss_t*, QObject* parent = 0 ); 325 OWaveLanManagementIBSS( const unsigned char*, const struct ibss_t*, QObject* parent = 0 );
289 virtual ~OWaveLanManagementIBSS(); 326 virtual ~OWaveLanManagementIBSS();
290 327
291 private: 328 private:
292 const struct ibss_t* _data; 329 const struct ibss_t* _data;
293}; 330};
294 331
295/*====================================================================================== 332/*======================================================================================
296 * OWaveLanManagementChallenge 333 * OWaveLanManagementChallenge
297 *======================================================================================*/ 334 *======================================================================================*/
298 335
299// Qobject do we need that?? 336// Qobject do we need that??
300class OWaveLanManagementChallenge : public QObject 337class OWaveLanManagementChallenge : public QObject
301{ 338{
302 Q_OBJECT 339 Q_OBJECT
303 340
304 public: 341 public:
305 OWaveLanManagementChallenge( const unsigned char*, const struct challenge_t*, QObject* parent = 0 ); 342 OWaveLanManagementChallenge( const unsigned char*, const struct challenge_t*, QObject* parent = 0 );
306 virtual ~OWaveLanManagementChallenge(); 343 virtual ~OWaveLanManagementChallenge();
307 344
308 private: 345 private:
309 const struct challenge_t* _data; 346 const struct challenge_t* _data;
310}; 347};
311 348
312/*====================================================================================== 349/*======================================================================================
313 * OWaveLanDataPacket - type: data (T_DATA) 350 * OWaveLanDataPacket - type: data (T_DATA)
314 *======================================================================================*/ 351 *======================================================================================*/
315// Qobject? 352// Qobject?
316class OWaveLanDataPacket : public QObject 353class OWaveLanDataPacket : public QObject
317{ 354{
318 Q_OBJECT 355 Q_OBJECT
319 356
320 public: 357 public:
321 OWaveLanDataPacket( const unsigned char*, const struct ieee_802_11_data_header*, OWaveLanPacket* parent = 0 ); 358 OWaveLanDataPacket( const unsigned char*, const struct ieee_802_11_data_header*, OWaveLanPacket* parent = 0 );
322 virtual ~OWaveLanDataPacket(); 359 virtual ~OWaveLanDataPacket();
323 360
324 private: 361 private:
325 const struct ieee_802_11_data_header* _header; 362 const struct ieee_802_11_data_header* _header;
326}; 363};
327 364
328/*====================================================================================== 365/*======================================================================================
329 * OWaveLanControlPacket - type: control (T_CTRL) 366 * OWaveLanControlPacket - type: control (T_CTRL)
330 *======================================================================================*/ 367 *======================================================================================*/
331// Qobject needed? 368
332class OWaveLanControlPacket : public QObject 369class OWaveLanControlPacket : public QObject
333{ 370{
334 Q_OBJECT 371 Q_OBJECT
335 372
336 public: 373 public:
337 OWaveLanControlPacket( const unsigned char*, const struct ieee_802_11_control_header*, OWaveLanPacket* parent = 0 ); 374 OWaveLanControlPacket( const unsigned char*, const struct ieee_802_11_control_header*, OWaveLanPacket* parent = 0 );
338 virtual ~OWaveLanControlPacket(); 375 virtual ~OWaveLanControlPacket();
339 376
340 private: 377 private:
341 const struct ieee_802_11_control_header* _header; 378 const struct ieee_802_11_control_header* _header;
342}; 379};
343 380
344/*====================================================================================== 381/*======================================================================================
345 * OLLCPacket - IEEE 802.2 Link Level Control 382 * OLLCPacket - IEEE 802.2 Link Level Control
346 *======================================================================================*/ 383 *======================================================================================*/
347 384
348// QObject needed?
349class OLLCPacket : public QObject 385class OLLCPacket : public QObject
350{ 386{
351 Q_OBJECT 387 Q_OBJECT
352 388
353 public: 389 public:
354 OLLCPacket( const unsigned char*, const struct ieee_802_11_802_2_header* data, QObject* parent = 0 ); 390 OLLCPacket( const unsigned char*, const struct ieee_802_11_802_2_header* data, QObject* parent = 0 );
355 virtual ~OLLCPacket(); 391 virtual ~OLLCPacket();
356 392
357 private: 393 private:
358 //FIXME how to get that header?
359 const struct ieee_802_11_802_2_header* _header; 394 const struct ieee_802_11_802_2_header* _header;
360}; 395};
361 396
362/*====================================================================================== 397/*======================================================================================
363 * OIPPacket 398 * OIPPacket
364 *======================================================================================*/ 399 *======================================================================================*/
365 400
366// Qobject as baseclass?
367class OIPPacket : public QObject 401class OIPPacket : public QObject
368{ 402{
369 Q_OBJECT 403 Q_OBJECT
370 404
371 public: 405 public:
372 OIPPacket( const unsigned char*, const struct iphdr*, QObject* parent = 0 ); 406 OIPPacket( const unsigned char*, const struct iphdr*, QObject* parent = 0 );
373 virtual ~OIPPacket(); 407 virtual ~OIPPacket();
374 408
375 QHostAddress fromIPAddress() const; 409 QHostAddress fromIPAddress() const;
376 QHostAddress toIPAddress() const; 410 QHostAddress toIPAddress() const;
377 411
378 int tos() const; 412 int tos() const;
379 int len() const; 413 int len() const;
380 int id() const; 414 int id() const;
381 int offset() const; 415 int offset() const;
382 int ttl() const; 416 int ttl() const;
383 int protocol() const; 417 int protocol() const;
384 int checksum() const; 418 int checksum() const;
385 419
386 private: 420 private:
387 const struct iphdr* _iphdr; 421 const struct iphdr* _iphdr;
388}; 422};
389 423
390/*====================================================================================== 424/*======================================================================================
391 * OUDPPacket 425 * OUDPPacket
392 *======================================================================================*/ 426 *======================================================================================*/
393// QObject? 427
394class OUDPPacket : public QObject 428class OUDPPacket : public QObject
395{ 429{
396 Q_OBJECT 430 Q_OBJECT
397 431
398 public: 432 public:
399 OUDPPacket( const unsigned char*, const struct udphdr*, QObject* parent = 0 ); 433 OUDPPacket( const unsigned char*, const struct udphdr*, QObject* parent = 0 );
400 virtual ~OUDPPacket(); 434 virtual ~OUDPPacket();
401 435
402 int fromPort() const; 436 int fromPort() const;
403 int toPort() const; 437 int toPort() const;
404 438
405 private: 439 private:
406 const struct udphdr* _udphdr; 440 const struct udphdr* _udphdr;
407}; 441};
408 442
409/*====================================================================================== 443/*======================================================================================
410 * OTCPPacket 444 * OTCPPacket
411 *======================================================================================*/ 445 *======================================================================================*/
412 446
413// Qobect needed?
414class OTCPPacket : public QObject 447class OTCPPacket : public QObject
415{ 448{
416 Q_OBJECT 449 Q_OBJECT
417 450
418 public: 451 public:
419 OTCPPacket( const unsigned char*, const struct tcphdr*, QObject* parent = 0 ); 452 OTCPPacket( const unsigned char*, const struct tcphdr*, QObject* parent = 0 );
420 virtual ~OTCPPacket(); 453 virtual ~OTCPPacket();
421 454
422 int fromPort() const; 455 int fromPort() const;
423 int toPort() const; 456 int toPort() const;
424 457
425 private: 458 private:
426 const struct tcphdr* _tcphdr; 459 const struct tcphdr* _tcphdr;
427}; 460};
428 461
429 462
430/*====================================================================================== 463/*======================================================================================
431 * OPacketCapturer 464 * OPacketCapturer
432 *======================================================================================*/ 465 *======================================================================================*/
433 466
434/** 467/**
435 * @brief A class based wrapper for network packet capturing. 468 * @brief A class based wrapper for network packet capturing.
436 * 469 *
437 * This class is the base of a high-level interface to the well known packet capturing 470 * This class is the base of a high-level interface to the well known packet capturing
438 * library libpcap. ... 471 * library libpcap. ...
439 */ 472 */
440class OPacketCapturer : public QObject 473class OPacketCapturer : public QObject
441{ 474{
442 Q_OBJECT 475 Q_OBJECT
443 476
444 public: 477 public:
445 /** 478 /**