00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifndef MUMULIB_H
00014 #define MUMULIB_H
00015
00016 #include <stdio.h>
00017 #include <errno.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 #include <string.h>
00022 #include <unistd.h>
00023 #include <sys/select.h>
00024 #include <sys/time.h>
00025
00026 #include <string>
00027 #include <stdexcept>
00028
00029
00030
00031
00032
00033 namespace mumu
00034 {
00035
00036
00037
00038 enum RWMode
00039 {
00040 ReadOnly = O_RDONLY,
00041 WriteOnly = O_WRONLY,
00042 ReadWrite = O_RDWR
00043 };
00044
00045
00046
00047
00048 template <typename Type>
00049 class Entry
00050 {
00051 private:
00052 int fd;
00053 RWMode mode;
00054
00055 public:
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 explicit Entry( const std::string & path,
00067 RWMode openMode = ReadWrite,
00068 bool isBlocking = true ) : fd( -1 ), mode( openMode )
00069 {
00070 int flags( openMode | O_CREAT );
00071 if ( !isBlocking ) flags |= O_NONBLOCK;
00072
00073 fd = open( path.c_str(), flags, S_IRUSR | S_IWUSR |
00074 S_IRGRP | S_IWGRP |
00075 S_IROTH | S_IWOTH );
00076 if ( fd < 0 ) throw std::runtime_error( "Cannot open the given entry." );
00077 }
00078
00079
00080
00081
00082 ~Entry()
00083 {
00084 close( fd );
00085 }
00086
00087
00088
00089
00090
00091
00092 Entry( const Entry & rhs ) : fd( dup( rhs.fd ) )
00093 {
00094 if ( fd < 0 ) throw std::runtime_error( "Cannot duplicate file descriptor." );
00095 }
00096
00097 private:
00098
00099 Entry & operator= ( const Entry & rhs );
00100
00101 protected:
00102
00103
00104
00105
00106
00107
00108
00109 struct timeval AddTimeval( const struct timeval & Left,
00110 const struct timeval & Right ) const
00111 {
00112 struct timeval Result;
00113
00114 Result.tv_sec = Left.tv_sec + Right.tv_sec;
00115 Result.tv_usec = Left.tv_usec + Right.tv_usec;
00116 while ( Result.tv_usec >= 1000000 )
00117 {
00118 ++Result.tv_sec;
00119 Result.tv_usec -= 1000000;
00120 }
00121 return Result;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130 struct timeval SubTimeval( const struct timeval & Left,
00131 const struct timeval & Right ) const
00132 {
00133 struct timeval Result;
00134
00135 Result.tv_sec = Left.tv_sec - Right.tv_sec;
00136 Result.tv_usec = Left.tv_usec - Right.tv_usec;
00137 while ( Result.tv_usec < 0 )
00138 {
00139 --Result.tv_sec;
00140 Result.tv_usec += 1000000;
00141 }
00142 return Result;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 bool LessTimeval( const struct timeval & Left,
00152 const struct timeval & Right ) const
00153 {
00154 if ( Left.tv_sec < Right.tv_sec ) return true;
00155 if ( Left.tv_sec > Right.tv_sec ) return false;
00156 return Left.tv_usec < Right.tv_usec;
00157 }
00158
00159
00160
00161
00162
00163
00164
00165 off_t GetFileSize( void ) const
00166 {
00167 struct stat fileInfo;
00168
00169 if ( fstat( fd, &fileInfo ) != 0 )
00170 {
00171 throw std::runtime_error( "Cannot get fstat" );
00172 }
00173 return fileInfo.st_size;
00174 }
00175
00176 public:
00177
00178
00179
00180
00181
00182
00183
00184 bool Select( struct timeval * inTimeout )
00185 {
00186 if ( mode == WriteOnly ) throw std::runtime_error( "Select for WriteOnly mode is not supported" );
00187
00188 fd_set Set;
00189 struct timeval AbsoluteEnd;
00190 struct timeval Timeout;
00191 struct timeval * Argument( NULL );
00192
00193 if ( inTimeout != NULL )
00194 {
00195 Timeout = *inTimeout;
00196 Argument = &Timeout;
00197 gettimeofday( &AbsoluteEnd, NULL );
00198 AbsoluteEnd = AddTimeval( AbsoluteEnd, Timeout );
00199 }
00200
00201
00202 FD_ZERO( &Set );
00203 FD_SET( fd, &Set );
00204
00205 int RetVal;
00206
00207 for ( ; ; )
00208 {
00209 RetVal = select( fd + 1, &Set, NULL, NULL, Argument );
00210
00211
00212 if ( RetVal >= 1 ) return true;
00213 if ( RetVal == 0 ) return false;
00214
00215
00216 if ( errno == EINTR )
00217 {
00218
00219
00220 FD_ZERO( &Set );
00221 FD_SET( fd, &Set );
00222
00223 struct timeval Current;
00224 gettimeofday( &Current, NULL );
00225
00226 if ( LessTimeval( AbsoluteEnd, Current ) ) return false;
00227
00228 Timeout = SubTimeval( AbsoluteEnd, Current );
00229 continue;
00230 }
00231
00232 throw std::runtime_error( "Select call error." );
00233 }
00234 }
00235
00236
00237
00238
00239
00240
00241
00242 void Write( const unsigned char * Buffer, size_t BufferSize )
00243 {
00244 if ( mode == ReadOnly ) throw std::runtime_error( "Cannot write into ReadOnly entry" );
00245
00246 for ( ; ; )
00247 {
00248 int Bytes( write( fd, Buffer, BufferSize ) );
00249 if ( Bytes == static_cast<int>(BufferSize) ) return;
00250
00251 if ( Bytes == -1 && errno == EINTR ) continue;
00252
00253 throw std::runtime_error( "Error writing to file descriptor." );
00254 }
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 void Write( const Type & T )
00266 {
00267 this->Write( reinterpret_cast<const unsigned char *>(&T), sizeof( T ) );
00268 }
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 int Read( unsigned char * Buffer, size_t BufferSize )
00281 {
00282 if ( mode == WriteOnly ) throw std::runtime_error( "Cannot read from WriteOnly entry" );
00283
00284 for ( ; ; )
00285 {
00286 int Bytes( read( fd, Buffer, BufferSize ) );
00287 if ( Bytes > 0 ) return Bytes;
00288 if ( Bytes == -1 && errno == EINTR ) continue;
00289 if ( Bytes == -1 && errno == EAGAIN ) return 0;
00290 if ( Bytes == -1 && errno == EINVAL ) return -1;
00291
00292 throw std::runtime_error( "Error reading from file descriptor." );
00293 }
00294 }
00295
00296
00297
00298
00299
00300 Type Read( void )
00301 {
00302 Type T;
00303 Read( T );
00304 return T;
00305 }
00306
00307
00308
00309
00310
00311
00312
00313 int Read( Type & T )
00314 {
00315 if ( mode == WriteOnly ) throw std::runtime_error( "Cannot read from WriteOnly entry" );
00316 for ( ; ; )
00317 {
00318 int Bytes( read( fd, &T, sizeof( T ) ) );
00319 if ( Bytes == sizeof( T ) ) return Bytes;
00320
00321 if ( Bytes == -1 && errno == EINTR ) continue;
00322 if ( Bytes == -1 && errno == EAGAIN ) return 0;
00323
00324 throw std::runtime_error( "Error reading from file descriptor" );
00325 }
00326 }
00327 };
00328
00329
00330
00331
00332
00333
00334
00335 template <>
00336 void Entry< std::string >::Write( const std::string & T )
00337 {
00338 if ( mode == ReadOnly ) throw std::runtime_error( "Cannot write into ReadOnly entry" );
00339
00340 size_t size( T.size() + 1 );
00341 for ( ; ; )
00342 {
00343 int Bytes( write( fd, T.c_str(), size ) );
00344 if ( Bytes == static_cast< int >( size ) ) return;
00345
00346 if ( Bytes == -1 && errno == EINTR ) continue;
00347
00348 throw std::runtime_error( "Error writing to file descriptor" );
00349 }
00350 }
00351
00352
00353
00354
00355
00356
00357
00358 template <>
00359 int Entry< std::string >::Read( std::string & S )
00360 {
00361 if ( mode == WriteOnly ) throw std::runtime_error( "Cannot read from WriteOnly entry" );
00362
00363 off_t BufferSize( GetFileSize() + 1 );
00364 char * Buffer( new char[ BufferSize ] );
00365
00366 for ( ; ; )
00367 {
00368 int Bytes( read( fd, Buffer, BufferSize ) );
00369
00370 if ( Bytes > 0 && Bytes < static_cast<int>( BufferSize ) )
00371 {
00372 if ( Buffer[ Bytes - 1 ] == '\0' ) S = std::string( Buffer, Bytes - 1 );
00373 else S = std::string( Buffer, Bytes );
00374 delete [] Buffer;
00375 return Bytes;
00376 }
00377
00378 if ( Bytes == -1 && errno == EAGAIN ) { delete [] Buffer; return 0; }
00379 if ( Bytes == -1 && errno == EINTR ) continue;
00380 if ( Bytes == -1 && errno == EINVAL )
00381 {
00382 delete [] Buffer;
00383 BufferSize = GetFileSize() + 1;
00384 Buffer = new char[ BufferSize ];
00385 continue;
00386 }
00387
00388 delete [] Buffer;
00389 throw std::runtime_error( "Error reading from file descriptor" );
00390 }
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 template <>
00400 std::string Entry< std::string >::Read( void )
00401 {
00402 std::string S;
00403 Read( S );
00404 return S;
00405 }
00406
00407 }
00408
00409
00410 #endif
00411