00001 /* 00002 * Copyright (C) 2003-2009 Olivier Boudeville 00003 * 00004 * This file is part of the Ceylan library. 00005 * 00006 * The Ceylan library is free software: you can redistribute it and/or modify 00007 * it under the terms of either the GNU Lesser General Public License or 00008 * the GNU General Public License, as they are published by the Free Software 00009 * Foundation, either version 3 of these Licenses, or (at your option) 00010 * any later version. 00011 * 00012 * The Ceylan library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License and the GNU General Public License 00016 * for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License and the GNU General Public License along with the Ceylan library. 00020 * If not, see <http://www.gnu.org/licenses/>. 00021 * 00022 * Author: Olivier Boudeville (olivier.boudeville@esperide.com) 00023 * 00024 */ 00025 00026 00027 #include "CeylanPipe.h" 00028 00029 #include "CeylanStandardFileSystemManager.h" // for Duplicate 00030 #include "CeylanLogPlug.h" // for Log primitives 00031 00032 00033 #ifdef CEYLAN_USES_CONFIG_H 00034 #include "CeylanConfig.h" // for configure-time feature settings 00035 #endif // CEYLAN_USES_CONFIG_H 00036 00037 00038 00039 extern "C" 00040 { 00041 00042 #ifdef CEYLAN_USES_SYS_TIME_H 00043 #include <sys/time.h> // for ::select 00044 #endif // CEYLAN_USES_SYS_TIME_H 00045 00046 #ifdef CEYLAN_USES_UNISTD_H 00047 #include <unistd.h> // for ::pipe,::select 00048 #endif // CEYLAN_USES_UNISTD_H 00049 00050 00051 #ifdef CEYLAN_USES_SYS_TYPES_H 00052 #include <sys/types.h> // for ::select 00053 #endif // CEYLAN_USES_SYS_TYPES_H 00054 00055 00056 #ifdef CEYLAN_USES_STRING_H 00057 #include <string.h> // for ::select 00058 #endif // CEYLAN_USES_STRING_H 00059 00060 00061 #ifdef CEYLAN_USES_STRINGS_H 00062 #include <strings.h> // for ::select 00063 #endif // CEYLAN_USES_STRINGS_H 00064 00065 00066 #ifdef CEYLAN_USES_SYS_SELECT_H 00067 #include <sys/select.h> // for ::select 00068 #endif // CEYLAN_USES_SYS_SELECT_H 00069 00070 } 00071 00072 00073 using std::string ; 00074 00075 using namespace Ceylan::System ; 00076 using namespace Ceylan::Log ; 00077 using namespace Ceylan ; 00078 00079 00080 00081 Pipe::PipeException::PipeException( const string & reason ) : 00082 SystemException( reason ) 00083 { 00084 00085 } 00086 00087 00088 Pipe::PipeException::~PipeException() throw() 00089 { 00090 00091 } 00092 00093 00094 00095 // Numerous child classes: 00096 00097 00098 Pipe::CouldNotCreate::CouldNotCreate( const string & reason ) : 00099 Pipe::PipeException( reason ) 00100 { 00101 00102 } 00103 00104 00105 00106 Pipe::ReadFailed::ReadFailed( const string & reason ) : 00107 InputStream::ReadFailedException( reason ) 00108 { 00109 00110 } 00111 00112 00113 00114 Pipe::WriteFailed::WriteFailed( const string & reason ) : 00115 OutputStream::WriteFailedException( reason ) 00116 { 00117 00118 } 00119 00120 00121 00122 00123 Pipe::Pipe() : 00124 InputOutputStream() 00125 { 00126 00127 #if CEYLAN_ARCH_NINTENDO_DS 00128 00129 throw Pipe::CouldNotCreate( "Pipe constructor failed: " 00130 "not available on the Nintendo DS." ) ; 00131 00132 #else // CEYLAN_ARCH_NINTENDO_DS 00133 00134 #if CEYLAN_USES_FILE_DESCRIPTORS 00135 00136 if ( ::pipe( _fd ) ) 00137 { 00138 _fd[ 0 ] = _fd[ 1 ] = -1 ; 00139 throw CouldNotCreate( "Pipe constructor: " + System::explainError() ) ; 00140 } 00141 00142 #else // CEYLAN_USES_FILE_DESCRIPTORS 00143 00144 throw CouldNotCreate( 00145 "Pipe constructor called whereas the file desciptor feature " 00146 "is not available." ) ; 00147 00148 #endif // CEYLAN_USES_FILE_DESCRIPTORS 00149 00150 #endif // CEYLAN_ARCH_NINTENDO_DS 00151 00152 } 00153 00154 00155 00156 Pipe::Pipe( const Pipe & other ) : 00157 Stream(), 00158 InputOutputStream() 00159 { 00160 00161 #if CEYLAN_ARCH_NINTENDO_DS 00162 00163 throw Pipe::CouldNotCreate( "Pipe constructor failed: " 00164 "not available on the Nintendo DS." ) ; 00165 00166 #else // CEYLAN_ARCH_NINTENDO_DS 00167 00168 _fd[ 1 ] = -1 ; 00169 00170 try 00171 { 00172 00173 _fd[ 0 ] = StandardFileSystemManager::Duplicate( other._fd[ 0 ] ) ; 00174 _fd[ 1 ] = StandardFileSystemManager::Duplicate( other._fd[ 1 ] ) ; 00175 00176 } 00177 catch( const System::DuplicateFailed & e ) 00178 { 00179 throw PipeException( "Pipe copy constructor failed: " 00180 + e.toString() ) ; 00181 } 00182 00183 #endif // CEYLAN_ARCH_NINTENDO_DS 00184 00185 } 00186 00187 00188 00189 Pipe::~Pipe() throw() 00190 { 00191 00192 try 00193 { 00194 00195 close() ; 00196 00197 } 00198 catch( const Stream::CloseException & e ) 00199 { 00200 LogPlug::error( "Pipe destructor failed: " + e.toString() ) ; 00201 } 00202 00203 00204 } 00205 00206 00207 00208 Size Pipe::read( char * buffer, Size maxLength ) 00209 { 00210 00211 setSelected( false ) ; 00212 00213 SignedSize n = static_cast<SignedSize>( 00214 System::FDRead( _fd[ 0 ], buffer, maxLength ) ) ; 00215 00216 // Actually, n should never be negative: 00217 if ( n < 0 ) 00218 throw ReadFailedException( "Pipe::read failed: " 00219 + System::explainError() ) ; 00220 00221 return static_cast<Size>( n ) ; 00222 00223 } 00224 00225 00226 00227 Size Pipe::write( const string & message ) 00228 { 00229 00230 return write( message.c_str(), message.size() ) ; 00231 00232 } 00233 00234 00235 00236 Size Pipe::write( const char * buffer, Size maxLength ) 00237 { 00238 00239 #if CEYLAN_USES_FILE_DESCRIPTORS 00240 00241 SignedSize n = System::FDWrite( _fd[ 1 ], buffer, maxLength ) ; 00242 00243 if ( n < static_cast<SignedSize>( maxLength ) ) 00244 throw WriteFailedException( "Pipe::write failed: " 00245 + System::explainError() ) ; 00246 00247 return static_cast<Size>( n ) ; 00248 00249 #else // CEYLAN_USES_FILE_DESCRIPTORS 00250 00251 throw OutputStream::WriteFailedException( 00252 "Pipe::write called whereas the file desciptor feature " 00253 "is not available." ) ; 00254 00255 #endif // CEYLAN_USES_FILE_DESCRIPTORS 00256 00257 } 00258 00259 00260 00261 bool Pipe::hasAvailableData() const 00262 { 00263 00264 return System::HasAvailableData( _fd[ 0 ] ) ; 00265 00266 } 00267 00268 00269 00270 void Pipe::clearInput() 00271 { 00272 00273 char c ; 00274 00275 while( hasAvailableData() ) 00276 read( &c, 1 ) ; 00277 00278 } 00279 00280 00281 00282 bool Pipe::close() 00283 { 00284 00285 #if CEYLAN_USES_FILE_DESCRIPTORS 00286 00287 bool res = Stream::Close( _fd[ 0 ] ) ; 00288 00289 if ( Stream::Close( _fd[ 1 ] ) ) 00290 return true ; 00291 else 00292 return res ; 00293 00294 #else 00295 00296 throw Stream::CloseException( "Pipe::close failed: " 00297 "pipe support not available." ) ; 00298 00299 #endif // CEYLAN_USES_FILE_DESCRIPTORS 00300 00301 } 00302 00303 00304 00305 StreamID Pipe::getInputStreamID() const 00306 { 00307 00308 return getReadFileDescriptor() ; 00309 00310 } 00311 00312 00313 00314 StreamID Pipe::getOutputStreamID() const 00315 { 00316 00317 return getOutputStreamID() ; 00318 00319 } 00320 00321 00322 00323 00324 // Protected section. 00325 00326 00327 FileDescriptor Pipe::getReadFileDescriptor() const 00328 { 00329 00330 return _fd[ 0 ] ; 00331 00332 } 00333 00334 00335 00336 FileDescriptor Pipe::getWriteFileDescriptor() const 00337 { 00338 00339 return _fd[ 1 ] ; 00340 00341 } 00342