]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/BASE/HOMER/AliHLTHOMERReader.cxx
enhanced HOMER reader to work on normal buffer
[u/mrichter/AliRoot.git] / HLT / BASE / HOMER / AliHLTHOMERReader.cxx
1 /************************************************************************
2 **
3 **
4 ** This file is property of and copyright by the Technical Computer
5 ** Science Group, Kirchhoff Institute for Physics, Ruprecht-Karls-
6 ** University, Heidelberg, Germany, 2001
7 ** This file has been written by Timm Morten Steinbeck, 
8 ** timm@kip.uni-heidelberg.de
9 **
10 **
11 ** See the file license.txt for details regarding usage, modification,
12 ** distribution and warranty.
13 ** Important: This file is provided without any warranty, including
14 ** fitness for any particular purpose.
15 **
16 **
17 ** Newer versions of this file's package will be made available from 
18 ** http://web.kip.uni-heidelberg.de/Hardwinf/L3/ 
19 ** or the corresponding page of the Heidelberg Alice Level 3 group.
20 **
21 *************************************************************************/
22
23 /*
24 ***************************************************************************
25 **
26 ** $Author$ - Initial Version by Timm Morten Steinbeck
27 **
28 ** $Id$ 
29 **
30 ***************************************************************************
31 */
32
33 /** @file   AliHLTHOMERReader.cxx
34     @author Timm Steinbeck
35     @date   Sep 14 2007
36     @brief  HLT Online Monitoring Environment including ROOT - Reader
37     @note   migrated from PubSub HLT-stable-20070905.141318 (rev 2375)    */
38
39 // see header file for class documentation
40 // or
41 // refer to README to build package
42 // or
43 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
44
45 #include "AliHLTHOMERReader.h"
46 #include <stdio.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <netdb.h>
50 extern int h_errno;
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <netinet/in.h>
54 #include <netinet/tcp.h>
55 #include <unistd.h>
56 #include <rpc/types.h>
57 #include <fcntl.h>
58 #include <sys/stat.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #ifdef USE_ROOT
62 #include <Rtypes.h>
63 #endif
64
65
66 #define MOD_BIN "MOD BIN\n"
67 #define MOD_ASC "MOD ASC\n"
68 #define GET_ONE "GET ONE\n"
69 #define GET_ALL "GET ALL\n"
70
71 #ifdef USE_ROOT
72 ClassImp(AliHLTMonitoringReader);
73 ClassImp(AliHLTHOMERReader);
74 #endif
75
76
77
78
79
80 #ifdef USE_ROOT
81 AliHLTHOMERReader::AliHLTHOMERReader()
82   :
83   fCurrentEventType(~(homer_uint64)0),
84   fCurrentEventID(~(homer_uint64)0),
85   fBlockCnt(0),
86   fMaxBlockCnt(0),
87   fBlocks(NULL),
88   fDataSourceCnt(0),
89   fTCPDataSourceCnt(0),
90   fShmDataSourceCnt(0),
91   fDataSourceMaxCnt(0),
92   fDataSources(NULL),
93   fConnectionStatus(0),
94   fErrorConnection(~(unsigned int)0),
95   fEventRequestAdvanceTime(0)
96     {
97 // Reader implementation of the HOMER interface.
98 // The HLT Monitoring Environment including ROOT is
99 // a native interface to ship out data from the HLT chain.
100 // See pdf document shiped with the package
101 // for class documentation and tutorial.
102     Init();
103     }
104 #endif
105
106
107 AliHLTHOMERReader::AliHLTHOMERReader( const char* hostname, unsigned short port )
108   :
109   AliHLTMonitoringReader(),
110   fCurrentEventType(~(homer_uint64)0),
111   fCurrentEventID(~(homer_uint64)0),
112   fBlockCnt(0),
113   fMaxBlockCnt(0),
114   fBlocks(NULL),
115   fDataSourceCnt(0),
116   fTCPDataSourceCnt(0),
117   fShmDataSourceCnt(0),
118   fDataSourceMaxCnt(0),
119   fDataSources(NULL),
120   fConnectionStatus(0),
121   fErrorConnection(~(unsigned int)0),
122   fEventRequestAdvanceTime(0)
123     {
124 // see header file for class documentation
125 // For reading from a TCP port
126     Init();
127     if ( !AllocDataSources(1) )
128         {
129         fErrorConnection = 0;
130         fConnectionStatus = ENOMEM;
131         return;
132         }
133     fConnectionStatus = AddDataSource( hostname, port, fDataSources[0] );
134     if ( fConnectionStatus )
135         fErrorConnection = 0;
136     else
137         {
138         fDataSourceCnt++;
139         fTCPDataSourceCnt++;
140         fDataSources[0].fNdx = 0;
141         }
142     }
143
144 AliHLTHOMERReader::AliHLTHOMERReader( unsigned int tcpCnt, const char** hostnames, unsigned short* ports )
145   :
146   AliHLTMonitoringReader(),
147   fCurrentEventType(~(homer_uint64)0),
148   fCurrentEventID(~(homer_uint64)0),
149   fBlockCnt(0),
150   fMaxBlockCnt(0),
151   fBlocks(NULL),
152   fDataSourceCnt(0),
153   fTCPDataSourceCnt(0),
154   fShmDataSourceCnt(0),
155   fDataSourceMaxCnt(0),
156   fDataSources(NULL),
157   fConnectionStatus(0),
158   fErrorConnection(~(unsigned int)0),
159   fEventRequestAdvanceTime(0)
160     {
161 // see header file for class documentation
162 // For reading from multiple TCP ports
163     Init();
164     if ( !AllocDataSources(tcpCnt) )
165         {
166         fErrorConnection = 0;
167         fConnectionStatus = ENOMEM;
168         return;
169         }
170     for ( unsigned int n = 0; n < tcpCnt; n++, fDataSourceCnt++, fTCPDataSourceCnt++ )
171         {
172         fConnectionStatus = AddDataSource( hostnames[n], ports[n], fDataSources[n] );
173         if ( fConnectionStatus )
174             {
175             fErrorConnection = n;
176             return;
177             }
178         fDataSources[n].fNdx = n;
179         }
180     }
181
182 AliHLTHOMERReader::AliHLTHOMERReader( key_t shmKey, int shmSize )
183   :
184   AliHLTMonitoringReader(),
185   fCurrentEventType(~(homer_uint64)0),
186   fCurrentEventID(~(homer_uint64)0),
187   fBlockCnt(0),
188   fMaxBlockCnt(0),
189   fBlocks(NULL),
190   fDataSourceCnt(0),
191   fTCPDataSourceCnt(0),
192   fShmDataSourceCnt(0),
193   fDataSourceMaxCnt(0),
194   fDataSources(NULL),
195   fConnectionStatus(0),
196   fErrorConnection(~(unsigned int)0),
197   fEventRequestAdvanceTime(0)
198     {
199 // see header file for class documentation
200 // For reading from a System V shared memory segment
201     Init();
202     if ( !AllocDataSources(1) )
203         {
204         fErrorConnection = 0;
205         fConnectionStatus = ENOMEM;
206         return;
207         }
208     fConnectionStatus = AddDataSource( shmKey, shmSize, fDataSources[0] );
209     if ( fConnectionStatus )
210         fErrorConnection = 0;
211     else
212         {
213         fDataSourceCnt++;
214         fShmDataSourceCnt++;
215         fDataSources[0].fNdx = 0;
216         }
217     }
218
219 AliHLTHOMERReader::AliHLTHOMERReader( unsigned int shmCnt, key_t* shmKeys, int* shmSizes )
220   :
221   AliHLTMonitoringReader(),
222   fCurrentEventType(~(homer_uint64)0),
223   fCurrentEventID(~(homer_uint64)0),
224   fBlockCnt(0),
225   fMaxBlockCnt(0),
226   fBlocks(NULL),
227   fDataSourceCnt(0),
228   fTCPDataSourceCnt(0),
229   fShmDataSourceCnt(0),
230   fDataSourceMaxCnt(0),
231   fDataSources(NULL),
232   fConnectionStatus(0),
233   fErrorConnection(~(unsigned int)0),
234   fEventRequestAdvanceTime(0)
235     {
236 // see header file for class documentation
237 // For reading from multiple System V shared memory segments
238     Init();
239     if ( !AllocDataSources(shmCnt) )
240         {
241         fErrorConnection = 0;
242         fConnectionStatus = ENOMEM;
243         return;
244         }
245     for ( unsigned int n = 0; n < shmCnt; n++, fDataSourceCnt++, fShmDataSourceCnt++ )
246         {
247         fConnectionStatus = AddDataSource( shmKeys[n], shmSizes[n], fDataSources[n] );
248         if ( fConnectionStatus )
249             {
250             fErrorConnection = n;
251             return;
252             }
253         fDataSources[n].fNdx = n;
254         }
255     }
256
257 AliHLTHOMERReader::AliHLTHOMERReader( unsigned int tcpCnt, const char** hostnames, unsigned short* ports, 
258                           unsigned int shmCnt, key_t* shmKeys, int* shmSizes )
259   :
260   AliHLTMonitoringReader(),
261   fCurrentEventType(~(homer_uint64)0),
262   fCurrentEventID(~(homer_uint64)0),
263   fBlockCnt(0),
264   fMaxBlockCnt(0),
265   fBlocks(NULL),
266   fDataSourceCnt(0),
267   fTCPDataSourceCnt(0),
268   fShmDataSourceCnt(0),
269   fDataSourceMaxCnt(0),
270   fDataSources(NULL),
271   fConnectionStatus(0),
272   fErrorConnection(~(unsigned int)0),
273   fEventRequestAdvanceTime(0)
274     {
275 // see header file for class documentation
276 // For reading from multiple TCP ports and multiple System V shared memory segments
277     Init();
278     if ( !AllocDataSources(tcpCnt+shmCnt) )
279         {
280         fErrorConnection = 0;
281         fConnectionStatus = ENOMEM;
282         return;
283         }
284     for ( unsigned int n = 0; n < tcpCnt; n++, fDataSourceCnt++, fTCPDataSourceCnt++ )
285         {
286         fConnectionStatus = AddDataSource( hostnames[n], ports[n], fDataSources[n] );
287         if ( fConnectionStatus )
288             {
289             fErrorConnection = n;
290             return;
291             }
292         fDataSources[n].fNdx = n;
293         }
294     for ( unsigned int n = 0; n < shmCnt; n++, fDataSourceCnt++, fShmDataSourceCnt++ )
295         {
296         fConnectionStatus = AddDataSource( shmKeys[n], shmSizes[n], fDataSources[tcpCnt+n] );
297         if ( fConnectionStatus )
298             {
299             fErrorConnection = tcpCnt+n;
300             return;
301             }
302         fDataSources[n].fNdx = n;
303         }
304     }
305
306 AliHLTHOMERReader::AliHLTHOMERReader( const void* pBuffer, int size )
307   :
308   AliHLTMonitoringReader(),
309   fCurrentEventType(~(homer_uint64)0),
310   fCurrentEventID(~(homer_uint64)0),
311   fBlockCnt(0),
312   fMaxBlockCnt(0),
313   fBlocks(NULL),
314   fDataSourceCnt(0),
315   fTCPDataSourceCnt(0),
316   fShmDataSourceCnt(0),
317   fDataSourceMaxCnt(0),
318   fDataSources(NULL),
319   fConnectionStatus(0),
320   fErrorConnection(~(unsigned int)0),
321   fEventRequestAdvanceTime(0)
322     {
323 // see header file for class documentation
324 // For reading from a System V shared memory segment
325     Init();
326     if ( !AllocDataSources(1) )
327         {
328         fErrorConnection = 0;
329         fConnectionStatus = ENOMEM;
330         return;
331         }
332     //fConnectionStatus = AddDataSource( shmKey, shmSize, fDataSources[0] );
333     if ( fConnectionStatus )
334         fErrorConnection = 0;
335     else
336         {
337         fDataSourceCnt++;
338         fShmDataSourceCnt++;
339         fDataSources[0].fNdx = 0;
340         }
341     }
342
343 AliHLTHOMERReader::~AliHLTHOMERReader()
344     {
345 // see header file for class documentation
346     ReleaseCurrentEvent();
347     FreeDataSources();
348     }
349
350 int  AliHLTHOMERReader::ReadNextEvent()
351     {
352 // see header file for class documentation
353 // Read in the next available event
354     return ReadNextEvent( false, 0 );
355     }
356
357 int AliHLTHOMERReader::ReadNextEvent( unsigned long timeout )
358     {
359 // see header file for class documentation
360 // Read in the next available event
361     return ReadNextEvent( true, timeout );
362     }
363
364 unsigned long AliHLTHOMERReader::GetBlockDataLength( unsigned long ndx ) const
365     {
366 // see header file for class documentation
367 // Return the size (in bytes) of the current event's data
368 // block with the given block index (starting at 0).
369     if ( ndx >= fBlockCnt )
370         return 0;
371     return fBlocks[ndx].fLength;
372     }
373
374 const void* AliHLTHOMERReader::GetBlockData( unsigned long ndx ) const
375     {
376 // see header file for class documentation
377 // Return a pointer to the start of the current event's data
378 // block with the given block index (starting at 0).
379     if ( ndx >= fBlockCnt )
380         return NULL;
381     return fBlocks[ndx].fData;
382     }
383
384 const char* AliHLTHOMERReader::GetBlockSendNodeID( unsigned long ndx ) const
385     {
386 // see header file for class documentation
387 // Return IP address or hostname of node which sent the 
388 // current event's data block with the given block index 
389 // (starting at 0).
390 // For HOMER this is the ID of the node on which the subscriber 
391 // that provided this data runs/ran.
392     if ( ndx >= fBlockCnt )
393         return NULL;
394 #ifdef DEBUG
395     if ( fBlocks[ndx].fSource >= fDataSourceCnt )
396         {
397         fprintf( stderr, "%s:%d: Internal Error: fBlocks[ndx].fSource (%lu) >= fDataSourceCnt (%lu)\n",
398                  __FILE__, __LINE__, fBlocks[ndx].fSource, fDataSourceCnt );
399         return NULL;
400         }
401 #endif
402     return fDataSources[ fBlocks[ndx].fSource ].fHostname;
403     //return fBlocks[ndx].fOriginatingNodeID;
404     }
405
406 homer_uint8 AliHLTHOMERReader::GetBlockByteOrder( unsigned long ndx ) const
407     {
408 // see header file for class documentation
409 // Return byte order of the data stored in the 
410 // current event's data block with the given block index (starting at 0). 
411 //         0 is unknown alignment, 
412 //         1 ist little endian, 
413 //         2 is big endian. */
414     if ( ndx >= fBlockCnt )
415         return 0;
416     //return ((AliHLTRIBlockDescriptorV1*)fBlocks[ndx].fMetaData)->fType.fID;
417     return *(((homer_uint8*)fBlocks[ndx].fMetaData)+kByteOrderAttribute_8b_Offset);
418     }
419
420 homer_uint8 AliHLTHOMERReader::GetBlockTypeAlignment( unsigned long ndx, homer_uint8 dataType ) const
421     {
422 // see header file for class documentation
423 // Return the alignment (in bytes) of the given datatype 
424 // in the data stored in the current event's data block
425 // with the given block index (starting at 0). 
426 // Possible values for the data type are
427 //         0: homer_uint64
428 //         1: homer_uint32
429 //         2: uin16
430 //         3: homer_uint8
431 //         4: double
432 //         5: float
433     if ( ndx >= fBlockCnt )
434         return 0;
435     if ( dataType > (kFloatAlignment_8b_Offset-kAlignment_8b_StartOffset) )
436         return 0;
437     //return ((AliHLTRIBlockDescriptorV1*)fBlocks[ndx].fMetaData)->fType.fID;
438     return *(((homer_uint8*)fBlocks[ndx].fMetaData)+kAlignment_8b_StartOffset+dataType);
439     }
440
441 homer_uint64 AliHLTHOMERReader::GetBlockStatusFlags( unsigned long ndx ) const
442     {
443 // see header file for class documentation
444     if ( ndx >= fBlockCnt )
445         return 0;
446     return *(((homer_uint64*)fBlocks[ndx].fMetaData)+kStatusFlags_64b_Offset);
447     }
448
449 /* HOMER specific */
450 /* Return the type of the data in the current event's data
451    block with the given block index (starting at 0). */
452 homer_uint64 AliHLTHOMERReader::GetBlockDataType( unsigned long ndx ) const
453     {
454 // see header file for class documentation
455     if ( ndx >= fBlockCnt )
456         return ~(homer_uint64)0;
457     //return ((AliHLTRIBlockDescriptorV1*)fBlocks[ndx].fMetaData)->fType.fID;
458     return *(((homer_uint64*)fBlocks[ndx].fMetaData)+kType_64b_Offset);
459     }
460
461 /* Return the origin of the data in the current event's data
462    block with the given block index (starting at 0). */
463 homer_uint32 AliHLTHOMERReader::GetBlockDataOrigin( unsigned long ndx ) const
464     {
465 // see header file for class documentation
466     if ( ndx >= fBlockCnt )
467         return ~(homer_uint32)0;
468     //return (homer_uint32)( ((AliHLTRIBlockDescriptorV1*)fBlocks[ndx].fMetaData)->fSubType1.fID );
469     return (homer_uint32)*(((homer_uint64*)fBlocks[ndx].fMetaData)+kSubType1_64b_Offset);
470     }
471
472 /* Return a specification of the data in the current event's data
473    block with the given block index (starting at 0). */
474 homer_uint32 AliHLTHOMERReader::GetBlockDataSpec( unsigned long ndx ) const
475     {
476 // see header file for class documentation
477     if ( ndx >= fBlockCnt )
478         return ~(homer_uint32)0;
479     //return (homer_uint32)( ((AliHLTRIBlockDescriptorV1*)fBlocks[ndx].fMetaData)->fSubType2.fID );
480     return (homer_uint32)*(((homer_uint64*)fBlocks[ndx].fMetaData)+kSubType2_64b_Offset);
481     }
482
483 /* Find the next data block in the current event with the given
484    data type, origin, and specification. Returns the block's 
485    index. */
486 unsigned long AliHLTHOMERReader::FindBlockNdx( homer_uint64 type, homer_uint32 origin, 
487                                          homer_uint32 spec, unsigned long startNdx ) const
488     {
489 // see header file for class documentation
490     for ( unsigned long n=startNdx; n < fBlockCnt; n++ )
491         {
492         if ( ( type == 0xFFFFFFFFFFFFFFFFULL || *(((homer_uint64*)fBlocks[n].fMetaData)+kType_64b_Offset)==type ) &&
493              ( origin == 0xFFFFFFFF || (homer_uint32)( *(((homer_uint64*)fBlocks[n].fMetaData)+kSubType1_64b_Offset) )==origin ) &&
494              ( spec == 0xFFFFFFFF || (homer_uint32)( *(((homer_uint64*)fBlocks[n].fMetaData)+kSubType2_64b_Offset) )==spec ) )
495             return n;
496         }
497     return ~(unsigned long)0;
498     }
499
500 /* Find the next data block in the current event with the given
501    data type, origin, and specification. Returns the block's 
502    index. */
503 unsigned long AliHLTHOMERReader::FindBlockNdx( char type[8], char origin[4], 
504                                          homer_uint32 spec, unsigned long startNdx ) const
505     {
506 // see header file for class documentation
507     for ( unsigned long n=startNdx; n < fBlockCnt; n++ )
508         {
509         bool found1=true, found2=true;
510         for ( unsigned i = 0; i < 8; i++ )
511             {
512             if ( type[i] != (char)0xFF )
513                 {
514                 found1=false;
515                 break;
516                 }
517             }
518         if ( !found1 )
519             {
520             found1 = true;
521             for ( unsigned i = 0; i < 8; i++ )
522                 {
523                 //printf( "%u: Comparing type '%c' and '%c'\n", i, ((char*)(((homer_uint64*)fBlocks[n].fMetaData)+kType_64b_Offset))[i], type[i] );
524                 if ( ((char*)(((homer_uint64*)fBlocks[n].fMetaData)+kType_64b_Offset))[i] != type[i] )
525                     {
526                     found1=false;
527                     break;
528                     }
529                 }
530             }
531         for ( unsigned i = 0; i < 4; i++ )
532             {
533             if ( origin[i] != (char)0xFF )
534                 {
535                 found2 = false;
536                 break;
537                 }
538             }
539         if ( !found2 )
540             {
541             found2 = true;
542             for ( unsigned i = 0; i < 4; i++ )
543                 {
544                 //printf( "Comparing origin '%c' and '%c'\n", ((char*)(((homer_uint64*)fBlocks[n].fMetaData)+kSubType1_64b_Offset))[i], origin[i] );
545                 if ( ((char*)(((homer_uint64*)fBlocks[n].fMetaData)+kSubType1_64b_Offset))[i] != origin[i] )
546                     {
547                     found2=false;
548                     break;
549                     }
550                 }
551             }
552         //printf( "Comparing spec '0x%08lX' and '0x%08lX'\n", (homer_uint32)( *(((homer_uint64*)fBlocks[n].fMetaData)+kSubType2_64b_Offset) ), spec );
553         if ( found1 && found2 &&
554              ( spec == 0xFFFFFFFF || ((homer_uint32)( *(((homer_uint64*)fBlocks[n].fMetaData)+kSubType2_64b_Offset)) )==spec ) )
555             return n;
556         }
557     return ~(unsigned long)0;
558     }
559
560 /* Return the ID of the node that actually produced this data block.
561    This may be different from the node which sent the data to this
562    monitoring object as returned by GetBlockSendNodeID. */
563 const char* AliHLTHOMERReader::GetBlockCreateNodeID( unsigned long ndx ) const
564     {
565 // see header file for class documentation
566     if ( ndx >= fBlockCnt )
567         return NULL;
568     return fBlocks[ndx].fOriginatingNodeID;
569     }
570
571
572 void AliHLTHOMERReader::Init()
573     {
574 // see header file for class documentation
575     fCurrentEventType = ~(homer_uint64)0;
576     fCurrentEventID = ~(homer_uint64)0;
577     fMaxBlockCnt = fBlockCnt = 0;
578     fBlocks = NULL;
579         
580     fDataSourceMaxCnt = fDataSourceCnt = fTCPDataSourceCnt = fShmDataSourceCnt = 0;
581     fDataSources = NULL;
582
583         
584     fConnectionStatus = 0;
585     fErrorConnection = ~(unsigned int)0;
586
587     fEventRequestAdvanceTime = 0;
588     }
589         
590 bool AliHLTHOMERReader::AllocDataSources( unsigned int sourceCnt )
591     {
592 // see header file for class documentation
593     fDataSources = new DataSource[ sourceCnt ];
594     if ( !fDataSources )
595         return false;
596     fDataSourceCnt = 0;
597     fDataSourceMaxCnt = sourceCnt;
598     return true;
599     }
600
601 int AliHLTHOMERReader::AddDataSource( const char* hostname, unsigned short port, DataSource& source )
602     {
603 // see header file for class documentation
604     struct hostent* he;
605     he = gethostbyname( hostname );
606     if ( he == NULL )
607         {
608         //fprintf( stderr, "Unable to determine remote host address from '%s'.\n", hostname );
609         return EADDRNOTAVAIL;
610         }
611
612     struct sockaddr_in remoteAddr;
613     remoteAddr.sin_family = AF_INET;    // host byte order 
614     remoteAddr.sin_port = htons(port);  // short, network byte order 
615     remoteAddr.sin_addr = *((struct in_addr *)he->h_addr);
616     memset(&(remoteAddr.sin_zero), '\0', 8);  // zero the rest of the struct
617
618     // Create socket and connect to target program on remote node
619     source.fTCPConnection = socket( AF_INET, SOCK_STREAM, 0 );
620     if ( source.fTCPConnection == -1 )
621         {
622         return errno;
623         }
624
625     int ret;
626
627     ret = connect( source.fTCPConnection, (struct sockaddr *)&remoteAddr, sizeof(struct sockaddr) );
628     if ( ret == -1 )
629         {
630         ret=errno;
631         close( source.fTCPConnection );
632         return ret;
633         } 
634
635     ret = write( source.fTCPConnection, MOD_BIN, strlen(MOD_BIN) );
636     if ( ret != (int)strlen(MOD_BIN) )
637         {
638         ret=errno;
639         close( source.fTCPConnection );
640         return ret;
641         }
642
643     char* tmpchar = new char[ strlen( hostname )+1 ];
644     if ( !tmpchar )
645         {
646         close( source.fTCPConnection );
647         return ENOMEM;
648         }
649     strcpy( tmpchar, hostname );
650     source.fHostname = tmpchar;
651
652     source.fType = kTCP;
653     source.fTCPPort = port;
654     source.fData = NULL;
655     source.fDataSize = 0;
656     source.fDataRead = 0;
657     return 0;
658     }
659
660 int AliHLTHOMERReader::AddDataSource( key_t shmKey, int shmSize, DataSource& source )
661     {
662 // see header file for class documentation
663     int ret;
664     char* tmpchar = new char[ MAXHOSTNAMELEN+1 ];
665     if ( !tmpchar )
666         {
667         return ENOMEM;
668         }
669     gethostname( tmpchar, MAXHOSTNAMELEN );
670     tmpchar[MAXHOSTNAMELEN]=(char)0;
671     source.fHostname = tmpchar;
672
673     source.fShmID = shmget( shmKey, shmSize, 0660 );
674     if ( source.fShmID == -1 )
675         {
676         ret = errno;
677         delete [] source.fHostname;
678         return ret;
679         }
680     
681     source.fShmPtr = (void*)shmat( source.fShmID, NULL, 0 );
682
683     if ( !source.fShmPtr )
684         {
685         ret = errno;
686         shmctl( source.fShmID, IPC_RMID, NULL );
687         delete [] source.fHostname;
688         return ret;
689         }
690
691     source.fType = kShm;
692     source.fShmKey = shmKey;
693     source.fShmSize = shmSize;
694     source.fDataSize = 0;
695     source.fDataRead = 0;
696     return 0;
697     }
698
699 int AliHLTHOMERReader::AddDataSource( void* pBuffer, int size, DataSource& source )
700     {
701 // see header file for class documentation
702 // a buffer data source is like a shm source apart from the shm attach and detach
703 // procedure. Furthermore, the size indicator at the beginning of the buffer is not
704 // cleared right before sources are read but after the reading.
705     int ret;
706     if ( !pBuffer || size<=0) return EINVAL;
707
708     char* tmpchar = new char[ MAXHOSTNAMELEN+1 ];
709     if ( !tmpchar )
710         {
711         return ENOMEM;
712         }
713     gethostname( tmpchar, MAXHOSTNAMELEN );
714     tmpchar[MAXHOSTNAMELEN]=(char)0;
715     source.fHostname = tmpchar;
716
717     source.fShmID = -1;
718     // the data buffer does not contain a size indicator in the first 4 bytes
719     // like the shm source buffer. Still we want to use the mechanism to invalidate/
720     // trigger by clearing the size indicator. Take the source.fShmSize variable.
721     source.fShmPtr = &source.fShmSize;
722     source.fType = kBuf;
723     source.fShmKey = 0;
724     source.fShmSize = size;
725     source.fData = pBuffer;
726     source.fDataSize = 0;
727     source.fDataRead = 0;
728     return 0;
729     }
730
731 void AliHLTHOMERReader::FreeDataSources()
732     {
733 // see header file for class documentation
734     for ( unsigned n=0; n < fDataSourceCnt; n++ )
735         {
736         if ( fDataSources[n].fType == kTCP )
737             FreeTCPDataSource( fDataSources[n] );
738         else if ( fDataSources[n].fType == kShm )
739             FreeShmDataSource( fDataSources[n] );
740         }
741     }
742
743 int AliHLTHOMERReader::FreeShmDataSource( DataSource& source )
744     {
745 // see header file for class documentation
746     if ( source.fShmPtr )
747         shmdt( source.fShmPtr );
748 //     if ( source.fShmID != -1 )
749 //      shmctl( source.fShmID, IPC_RMID, NULL );
750     if ( source.fHostname )
751         delete [] source.fHostname;
752     return 0;
753     }
754
755 int AliHLTHOMERReader::FreeTCPDataSource( DataSource& source )
756     {
757 // see header file for class documentation
758     if ( source.fTCPConnection )
759         close( source.fTCPConnection );
760     if ( source.fHostname )
761         delete [] source.fHostname;
762     return 0;
763     }
764
765 int AliHLTHOMERReader::ReadNextEvent( bool useTimeout, unsigned long timeout )
766     {
767 // see header file for class documentation
768     if ( fDataSourceCnt<=0 )
769         return ENXIO;
770     // Clean up currently active event.
771     ReleaseCurrentEvent();
772     int ret;
773     // Trigger all configured data sources
774     for ( unsigned n = 0; n<fDataSourceCnt; n++ )
775         {
776         if ( fDataSources[n].fType == kTCP )
777             ret = TriggerTCPSource( fDataSources[n], useTimeout, timeout );
778         else if ( fDataSources[n].fType == kShm )
779             ret = TriggerShmSource( fDataSources[n], useTimeout, timeout );
780         if ( ret )
781             {
782             fErrorConnection = n;
783             fConnectionStatus=ret;
784             return fConnectionStatus;
785             }
786         }
787     // Now read in data from the configured data source
788     ret = ReadDataFromTCPSources( fTCPDataSourceCnt, fDataSources, useTimeout, timeout );
789     if ( ret )
790         {
791         return ret;
792         }
793     ret = ReadDataFromShmSources( fShmDataSourceCnt, fDataSources+fTCPDataSourceCnt, useTimeout, timeout );
794     if ( ret )
795         {
796         return ret;
797         }
798 //     for ( unsigned n = 0; n<fDataSourceCnt; n++ )
799 //      {
800 //      if ( fDataSources[n].fType == kTCP )
801 //          ret = ReadDataFromTCPSource( fDataSources[n], useTimeout, timeout );
802 //      else
803 //          ret = ReadDataFromShmSource( fDataSources[n], useTimeout, timeout );
804 //      if ( ret )
805 //          {
806 //          fErrorConnection = n;
807 //          fConnectionStatus=ret;
808 //          return fConnectionStatus;
809 //          }
810 //      }
811     //Check to see that all sources contributed data for the same event
812     homer_uint64 eventID;
813     homer_uint64 eventType;
814     eventID = GetSourceEventID( fDataSources[0] );
815     eventType = GetSourceEventType( fDataSources[0] );
816     for ( unsigned n = 1; n < fDataSourceCnt; n++ )
817         {
818         if ( GetSourceEventID( fDataSources[n] ) != eventID || GetSourceEventType( fDataSources[n] ) != eventType )
819             {
820             fErrorConnection = n;
821             fConnectionStatus=56;//EBADRQC;
822             return fConnectionStatus;
823             }
824         }
825     // Find all the different data blocks contained in the data from all
826     // the sources.
827     for ( unsigned n = 0; n < fDataSourceCnt; n++ )
828         {
829         ret = ParseSourceData( fDataSources[n] );
830         if ( ret )
831             {
832             fErrorConnection = n;
833             fConnectionStatus=57;//EBADSLT;
834             return fConnectionStatus;
835             }
836         }
837     fCurrentEventID = eventID;
838     fCurrentEventType = eventType;
839     return 0;
840     }
841
842 void AliHLTHOMERReader::ReleaseCurrentEvent()
843     {
844 // see header file for class documentation
845     // sources.fDataRead = 0;
846     // fMaxBlockCnt
847     fCurrentEventID = ~(homer_uint64)0;
848     fCurrentEventType = ~(homer_uint64)0;
849     for ( unsigned n = 0; n < fDataSourceCnt; n++ )
850         {
851         if ( fDataSources[n].fData )
852             {
853             if ( fDataSources[n].fType == kTCP )
854                 delete [] (homer_uint8*)fDataSources[n].fData;
855             fDataSources[n].fData = NULL;
856             }
857         fDataSources[n].fDataSize = fDataSources[n].fDataRead = 0;
858         }
859     if ( fBlocks )
860         {
861         for ( unsigned n = 0; n < fMaxBlockCnt; n++ )
862             {
863             if ( fBlocks[n].fOriginatingNodeID )
864                 delete [] fBlocks[n].fOriginatingNodeID;
865             }
866         delete [] fBlocks;
867         fBlocks=0;
868         fMaxBlockCnt = 0;
869         fBlockCnt=0;
870         }
871     }
872
873 int AliHLTHOMERReader::TriggerTCPSource( DataSource& source, bool useTimeout, unsigned long timeoutUsec )
874     {
875 // see header file for class documentation
876     int ret;
877     struct timeval oldSndTO, newSndTO;
878     if ( useTimeout )
879         {
880         socklen_t optlen=sizeof(oldSndTO);
881         ret = getsockopt( source.fTCPConnection, SOL_SOCKET, SO_SNDTIMEO, &oldSndTO, &optlen );
882         if ( ret )
883             {
884             return errno;
885             }
886         if ( optlen!=sizeof(oldSndTO) )
887             {
888             return ENXIO;
889             }
890         newSndTO.tv_sec = timeoutUsec / 1000000;
891         newSndTO.tv_usec = timeoutUsec - (newSndTO.tv_sec*1000000);
892         ret = setsockopt( source.fTCPConnection, SOL_SOCKET, SO_SNDTIMEO, &newSndTO, sizeof(newSndTO) );
893         if ( ret )
894             {
895             return errno;
896             }
897         }
898     // Send one event request
899     if ( !fEventRequestAdvanceTime )
900         {
901         ret = write( source.fTCPConnection, GET_ONE, strlen(GET_ONE) );
902         
903         if ( ret != (int)strlen(GET_ONE) )
904             {
905             ret=errno;
906             setsockopt( source.fTCPConnection, SOL_SOCKET, SO_SNDTIMEO, &oldSndTO, sizeof(oldSndTO) );
907             return ret;
908             }
909         }
910     else
911         {
912         char tmpCmd[ 128 ];
913
914         int len = snprintf( tmpCmd, 128, "FIRST ORBIT EVENT 0x%Lu\n", (unsigned long long)fEventRequestAdvanceTime );
915         if ( len>128 || len<0 )
916             {
917             ret=EMSGSIZE;
918             setsockopt( source.fTCPConnection, SOL_SOCKET, SO_SNDTIMEO, &oldSndTO, sizeof(oldSndTO) );
919             return ret;
920             }
921         
922         ret = write( source.fTCPConnection, tmpCmd, strlen(tmpCmd) );
923         
924         if ( ret != (int)strlen(tmpCmd) )
925             {
926             ret=errno;
927             setsockopt( source.fTCPConnection, SOL_SOCKET, SO_SNDTIMEO, &oldSndTO, sizeof(oldSndTO) );
928             return ret;
929             }
930         
931         }
932     return 0;
933     }
934
935 int AliHLTHOMERReader::TriggerShmSource( DataSource& source, bool, unsigned long )
936     {
937 // see header file for class documentation
938 // clear the size indicator in the first 4 bytes of the buffer to request data
939 // from the HOMER writer.
940     if ( source.fShmPtr )
941         {
942         *(homer_uint32*)( source.fShmPtr ) = 0;
943         return 0;
944         }
945     else
946         return EFAULT;
947     }
948
949 int AliHLTHOMERReader::ReadDataFromTCPSources( unsigned sourceCnt, DataSource* sources, bool useTimeout, unsigned long timeout )
950     {
951 // see header file for class documentation
952     bool toRead = false;
953     do
954         {
955         fd_set conns;
956         FD_ZERO( &conns );
957         int highestConn=0;
958         toRead = false;
959         unsigned firstConnection=~(unsigned)0;
960         for ( unsigned long n = 0; n < sourceCnt; n++ )
961             {
962             if ( sources[n].fDataSize == 0 // size specifier not yet read
963                  || sources[n].fDataRead < sources[n].fDataSize ) // Data not yet read fully
964                 {
965                 toRead = true;
966                 FD_SET( sources[n].fTCPConnection, &conns );
967                 if ( sources[n].fTCPConnection > highestConn )
968                     highestConn = sources[n].fTCPConnection;
969                 fcntl( sources[n].fTCPConnection, F_SETFL, O_NONBLOCK );
970                 if ( firstConnection == ~(unsigned)0 )
971                     firstConnection = n;
972                 }
973             else
974                 {
975                 fcntl( sources[n].fTCPConnection, F_SETFL, 0 );
976                 }
977             }
978         if ( toRead )
979             {
980             struct timeval tv, *ptv;
981             if ( useTimeout )
982                 {
983                 tv.tv_sec = timeout / 1000000;
984                 tv.tv_usec = timeout - (tv.tv_sec*1000000);
985                 ptv = &tv;
986                 }
987             else
988                 ptv = NULL;
989             // wait until something is ready to be read
990             // either for timeout usecs or until eternity
991             int ret;
992             ret = select( highestConn+1, &conns, NULL, NULL, ptv ); 
993             if ( ret <=0 )
994                 {
995                 fErrorConnection = firstConnection;
996                 if ( errno )
997                     fConnectionStatus = errno;
998                 else
999                     fConnectionStatus = ETIMEDOUT;
1000                 return fConnectionStatus;
1001                 }
1002             for ( unsigned n = 0; n < sourceCnt; n++ )
1003                 {
1004                 if ( FD_ISSET( sources[n].fTCPConnection, &conns ) )
1005                     {
1006                     if ( sources[n].fDataSize == 0 )
1007                         {
1008                         ret=read( sources[n].fTCPConnection, &(sources[n].fDataSize), sizeof(homer_uint32) );
1009                         if ( ret != sizeof(homer_uint32) )
1010                             {
1011                             fErrorConnection = n;
1012                             if ( errno )
1013                                 fConnectionStatus = errno;
1014                             else
1015                                 fConnectionStatus = ENOMSG;
1016                             return fConnectionStatus;
1017                             }
1018                         sources[n].fDataSize = ntohl( sources[n].fDataSize );
1019                         sources[n].fDataRead = 0;
1020                         sources[n].fData = new homer_uint8[ sources[n].fDataSize ];
1021                         if ( !sources[n].fData )
1022                             {
1023                             fErrorConnection = n;
1024                             fConnectionStatus = ENOMEM;
1025                             return fConnectionStatus;
1026                             }
1027                         }
1028                     else if ( sources[n].fData && sources[n].fDataRead < sources[n].fDataSize)
1029                         {
1030                         ret=read( sources[n].fTCPConnection, ((homer_uint8*)sources[n].fData)+sources[n].fDataRead, sources[n].fDataSize-sources[n].fDataRead );
1031                         if ( ret>0 )
1032                             sources[n].fDataRead += ret;
1033                         else if ( ret == 0 )
1034                             {
1035                             fErrorConnection = n;
1036                             fConnectionStatus = ECONNRESET;
1037                             return fConnectionStatus;
1038                             }
1039                         else
1040                             {
1041                             fErrorConnection = n;
1042                             fConnectionStatus = errno;
1043                             return fConnectionStatus;
1044                             }
1045                         }
1046                     else
1047                         {
1048                         fErrorConnection = n;
1049                         fConnectionStatus = ENXIO;
1050                         return fConnectionStatus;
1051                         }
1052                     }
1053                 }
1054             }
1055         }
1056     while ( toRead );
1057     return 0;
1058     }
1059
1060 /*
1061 int AliHLTHOMERReader::ReadDataFromTCPSources( DataSource& source, bool useTimeout, unsigned long timeout )
1062     {
1063 #warning TODO If useTimeout: Set sockets to nonblocking, select + loop around GET_ONE write
1064     // Send one event request
1065     ret = write( source.fTCPConnection, GET_ONE, strlen(GET_ONE) );
1066     if ( ret != strlen(GET_ONE) )
1067         {
1068         return errno;
1069         }
1070     // wait for and read back size specifier
1071     unsigned sizeNBO;
1072     // The value transmitted is binary, in network byte order
1073     ret = read( source.fTCPConnection, &sizeNBO, sizeof(sizeNBO) );
1074     if ( ret != sizeof(sizeNBO) )
1075         {
1076         return errno;
1077         }
1078     // Convert back to host byte order
1079     source.fDataSize = ntohl( sizeNBO );
1080     source.fData = new homer_uint8[ source.fDataSize ];
1081     unsigned long dataRead=0, toRead;
1082     if ( !source.fData )
1083         {
1084         char buffer[1024];
1085         // Read in data into buffer in order not to block connection
1086         while ( dataRead < source.fDataSize )
1087             {
1088             if ( source.fDataSize-dataRead > 1024 )
1089                 toRead = 1024;
1090             else
1091                 toRead = source.fDataSize-dataRead;
1092             ret = read( source.fTCPConnection, buffer, toRead );
1093             if ( ret > 0 )
1094                 dataRead += ret;
1095             else
1096                 return errno;
1097             }
1098         return ENOMEM;
1099         }
1100     while ( dataRead < source.fDataSize )
1101         {
1102         toRead = source.fDataSize-dataRead;
1103         ret = read( source.fTCPConnection, source.fData+dataRead, toRead );
1104         if ( ret > 0 )
1105             dataRead += ret;
1106         else if ( ret == 0 && useTimeout )
1107             {
1108             struct timeval tv;
1109             tv.tv_sec = timeout / 1000000;
1110             tv.tv_usec = timeout - (tv.tv_sec*1000000);
1111             fd_set conns;
1112             FD_ZERO( &conns );
1113             FD_SET( source.fTCPConnection, &conns );
1114             ret = select( source.fTCPConnection+1, &conns, NULL, NULL );
1115             if ( ret <=0 )
1116                 return errno;
1117             }
1118         else if ( ret == 0 )
1119             {
1120             if ( errno == EOK )
1121                 return ECONNRESET;
1122             else
1123                 return errno;
1124             }
1125         else
1126             {
1127             return errno;
1128             }
1129         }
1130     return 0;
1131     }
1132 */
1133
1134 /*
1135 int AliHLTHOMERReader::ReadDataFromShmSource( DataSource& source, bool useTimeout, unsigned long timeout )
1136     {
1137     
1138     }
1139 */
1140
1141 int AliHLTHOMERReader::ReadDataFromShmSources( unsigned sourceCnt, DataSource* sources, bool useTimeout, unsigned long timeout )
1142     {
1143 // see header file for class documentation
1144     struct timeval tv1, tv2;
1145     bool found=false;
1146     bool all=true;
1147     if ( useTimeout )
1148         gettimeofday( &tv1, NULL );
1149     do
1150         {
1151         found = false;
1152         all = true;
1153         for ( unsigned n = 0; n < sourceCnt; n++ )
1154             {
1155             if ( !sources[n].fDataSize )
1156                 all = false;
1157             if ( sources[n].fShmPtr && *(homer_uint32*)sources[n].fShmPtr>0 && !sources[n].fDataSize )
1158                 {
1159                 found = true;
1160                 sources[n].fDataSize = *(homer_uint32*)sources[n].fShmPtr;
1161                 if (sources[n].fType==kBuf)
1162                   {
1163                     // the data buffer is already set to fData, just need to set fDataSize member
1164                     // to invalidate after the first reading. Subsequent calls to ReadNextEvent return 0
1165                     TriggerShmSource( sources[n], 0, 0 );
1166                   } else 
1167                   {
1168                     sources[n].fData = ((homer_uint8*)sources[n].fShmPtr)+sizeof(homer_uint32);
1169                   }
1170                 }
1171             }
1172         if ( found && useTimeout )
1173             gettimeofday( &tv1, NULL );
1174         if ( !all && useTimeout )
1175             {
1176             gettimeofday( &tv2, NULL );
1177             unsigned long long tdiff;
1178             tdiff = tv2.tv_sec-tv1.tv_sec;
1179             tdiff *= 1000000;
1180             tdiff += tv2.tv_usec-tv1.tv_usec;
1181             if ( tdiff > timeout )
1182                 return ETIMEDOUT;
1183             }
1184         if ( !all )
1185             usleep( 0 );
1186         }
1187     while ( !all );
1188     return 0;
1189     }
1190
1191 int AliHLTHOMERReader::ParseSourceData( DataSource& source )
1192     {
1193 // see header file for class documentation
1194     if ( source.fData )
1195         {
1196         homer_uint8 sourceByteOrder = ((homer_uint8*)source.fData)[ kByteOrderAttribute_8b_Offset ];
1197         homer_uint64 blockCnt = Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)source.fData)[ kSubType2_64b_Offset ] );
1198         int ret=ReAllocBlocks( fMaxBlockCnt+blockCnt );
1199         if ( ret )
1200             return ret;
1201         homer_uint64 descrOffset = Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)source.fData)[ kOffset_64b_Offset ] );
1202         for ( homer_uint64 n = 0; n < blockCnt && fBlockCnt < fMaxBlockCnt; n++, fBlockCnt++ )
1203             {
1204             homer_uint8* descr = ((homer_uint8*)source.fData)+descrOffset;
1205             unsigned descrLen = Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)descr)[ kLength_64b_Offset ] );
1206             fBlocks[fBlockCnt].fSource = source.fNdx;
1207             fBlocks[fBlockCnt].fData = ((homer_uint8*)source.fData) + Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)descr)[ kOffset_64b_Offset ] );
1208             fBlocks[fBlockCnt].fLength = Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)descr)[ kSize_64b_Offset ] );
1209             fBlocks[fBlockCnt].fMetaData = (homer_uint64*)descr;
1210             struct in_addr tmpA;
1211             tmpA.s_addr = (homer_uint32)( ((homer_uint64*)descr)[ kProducerNode_64b_Offset ] );
1212             char* addr = inet_ntoa( tmpA );
1213             char* tmpchar = new char[ strlen(addr)+1 ];
1214             if ( !tmpchar )
1215                 return ENOMEM;
1216             strcpy( tmpchar, addr );
1217             fBlocks[fBlockCnt].fOriginatingNodeID = tmpchar;
1218             descrOffset += descrLen;
1219             }
1220         return 0;
1221         }
1222     return EFAULT;
1223     }
1224         
1225 int AliHLTHOMERReader::ReAllocBlocks( unsigned long newCnt )
1226     {
1227 // see header file for class documentation
1228     DataBlock* newBlocks;
1229     newBlocks = new DataBlock[ newCnt ];
1230     if ( !newBlocks )
1231         return ENOMEM;
1232     unsigned long cpCnt = (newCnt > fMaxBlockCnt) ? fMaxBlockCnt : newCnt;
1233     memcpy( newBlocks, fBlocks, cpCnt*sizeof(DataBlock) );
1234     if ( newCnt > fMaxBlockCnt )
1235         memset( newBlocks+fMaxBlockCnt, 0, (newCnt-fMaxBlockCnt)*sizeof(DataBlock) );
1236     if ( fBlocks )
1237         delete [] fBlocks;
1238     fBlocks = newBlocks;
1239     fMaxBlockCnt = newCnt;
1240     return 0;
1241     }
1242
1243 homer_uint64 AliHLTHOMERReader::GetSourceEventID( DataSource& source )
1244     {
1245 // see header file for class documentation
1246     homer_uint8 sourceByteOrder = ((homer_uint8*)source.fData)[ kByteOrderAttribute_8b_Offset ];
1247     return Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)source.fData)[ kSubType1_64b_Offset ] );
1248     }
1249
1250 homer_uint64 AliHLTHOMERReader::GetSourceEventType( DataSource& source )
1251     {
1252 // see header file for class documentation
1253     homer_uint8 sourceByteOrder = ((homer_uint8*)source.fData)[ kByteOrderAttribute_8b_Offset ];
1254     return Swap( kHOMERNativeByteOrder, sourceByteOrder, ((homer_uint64*)source.fData)[ kType_64b_Offset ] );
1255     }
1256
1257 homer_uint64 AliHLTHOMERReader::Swap( homer_uint8 destFormat, homer_uint8 sourceFormat, homer_uint64 source ) const
1258     {
1259 // see header file for class documentation
1260     if ( destFormat == sourceFormat )
1261         return source;
1262     else
1263         return ((source & 0xFFULL) << 56) | 
1264         ((source & 0xFF00ULL) << 40) | 
1265         ((source & 0xFF0000ULL) << 24) | 
1266         ((source & 0xFF000000ULL) << 8) | 
1267         ((source & 0xFF00000000ULL) >> 8) | 
1268         ((source & 0xFF0000000000ULL) >> 24) | 
1269         ((source & 0xFF000000000000ULL) >>  40) | 
1270         ((source & 0xFF00000000000000ULL) >> 56);
1271     }
1272
1273 homer_uint32 AliHLTHOMERReader::Swap( homer_uint8 destFormat, homer_uint8 sourceFormat, homer_uint32 source ) const
1274     {
1275 // see header file for class documentation
1276     if ( destFormat == sourceFormat )
1277         return source;
1278     else
1279         return ((source & 0xFFUL) << 24) | 
1280         ((source & 0xFF00UL) << 8) | 
1281         ((source & 0xFF0000UL) >> 8) | 
1282         ((source & 0xFF000000UL) >> 24);
1283     }
1284
1285 AliHLTHOMERReader* AliHLTHOMERReaderCreate(const void* pBuffer, int size)
1286     {
1287 // see header file for function documentation
1288       return new AliHLTHOMERReader(pBuffer, size);
1289     }
1290
1291 void AliHLTHOMERReaderDelete(AliHLTHOMERReader* pInstance)
1292     {
1293 // see header file for function documentation
1294       if (pInstance) delete pInstance;
1295     }
1296
1297 /*
1298 ***************************************************************************
1299 **
1300 ** $Author$ - Initial Version by Timm Morten Steinbeck
1301 **
1302 ** $Id$ 
1303 **
1304 ***************************************************************************
1305 */