IBR-DTNSuite
0.8
|
00001 /* 00002 * iostreamBIO.cpp 00003 * 00004 * Created on: Mar 25, 2011 00005 * Author: roettger 00006 */ 00007 00008 #include "iostreamBIO.h" 00009 00010 #include "ibrcommon/Logger.h" 00011 00012 #include <openssl/err.h> 00013 00014 namespace ibrcommon 00015 { 00016 00017 static const int ERR_BUF_SIZE = 256; 00018 00019 const char * const iostreamBIO::name = "iostreamBIO"; 00020 00021 /* callback functions for openssl */ 00022 static int bwrite(BIO *bio, const char *buf, int len); 00023 static int bread(BIO *bio, char *buf, int len); 00024 //static int bputs(BIO *bio, const char *); 00025 //static int bgets(BIO *bio, char *, int); 00026 static long ctrl(BIO *bio, int cmd, long num, void *ptr); 00027 static int create(BIO *bio); 00028 //static int destroy(BIO *bio); 00029 //static long (*callback_ctrl)(BIO *, int, bio_info_cb *); 00030 00031 00032 static BIO_METHOD iostream_method = 00033 { 00034 iostreamBIO::type, 00035 iostreamBIO::name, 00036 bwrite, 00037 bread, 00038 NULL,//bputs 00039 NULL,//bgets 00040 ctrl, 00041 create, 00042 NULL,//destroy, 00043 NULL//callback_ctrl 00044 }; 00045 00046 iostreamBIO::iostreamBIO(iostream *stream) 00047 : _stream(stream) 00048 { 00049 /* create BIO */ 00050 _bio = BIO_new(&iostream_method); 00051 if(!_bio){ 00052 /* creation failed, throw exception */ 00053 char err_buf[ERR_BUF_SIZE]; 00054 ERR_error_string_n(ERR_get_error(), err_buf, ERR_BUF_SIZE); 00055 err_buf[ERR_BUF_SIZE - 1] = '\0'; 00056 IBRCOMMON_LOGGER(critical) << "iostreamBIO: BIO creation failed: " << err_buf << IBRCOMMON_LOGGER_ENDL; 00057 throw BIOException(err_buf); 00058 } 00059 00060 /* save the iostream in the bio object */ 00061 _bio->ptr = stream; 00062 } 00063 00064 BIO * 00065 iostreamBIO::getBIO(){ 00066 return _bio; 00067 } 00068 00069 static int create(BIO *bio) 00070 { 00071 bio->ptr = NULL; 00072 /* (from openssl memory bio) */ 00073 bio->shutdown=1; 00074 bio->init=1; 00075 /* from bss_mem.c (openssl): 00076 * bio->num is used to hold the value to return on 'empty', if it is 00077 * 0, should_retry is not set 00078 * 00079 * => -1 means the caller can retry, 0: retry is useless 00080 * it is set to 0 since the underlying stream is blocking 00081 */ 00082 bio->num= 0; 00083 00084 return 1; 00085 } 00086 00087 00088 00089 static long ctrl(BIO *bio, int cmd, long num, void *ptr) 00090 { 00091 long ret; 00092 iostream *stream = reinterpret_cast<iostream*>(bio->ptr); 00093 00094 IBRCOMMON_LOGGER_DEBUG(90) << "iostreamBIO: ctrl called, cmd: " << cmd << ", num: " << num << "." << IBRCOMMON_LOGGER_ENDL; 00095 00096 switch(cmd){ 00097 case BIO_CTRL_PUSH: 00098 case BIO_CTRL_POP: 00099 ret = 0; 00100 break; 00101 // case BIO_CTRL_GET_CLOSE: 00102 // ret = bio->shutdown; 00103 // break; 00104 // case BIO_CTRL_SET_CLOSE: 00105 // bio->shutdown = (int)num; 00106 // ret = 1; 00107 // break; 00108 case BIO_CTRL_FLUSH: 00109 /* try to flush the underlying stream */ 00110 ret = 1; 00111 try{ 00112 stream->flush(); 00113 } catch(ios_base::failure &ex){ 00114 /* ignore, the badbit is checked instead */ 00115 } 00116 // catch(ConnectionClosedException &ex){ 00117 // throw; 00118 // } 00119 if(stream->bad()){ 00120 IBRCOMMON_LOGGER_DEBUG(20) << "iostreamBIO: underlying Stream went bad while flushing." << IBRCOMMON_LOGGER_ENDL; 00121 ret = 0; 00122 } 00123 break; 00124 default: 00125 IBRCOMMON_LOGGER(warning) << "iostreamBIO: ctrl called with unhandled cmd: " << cmd << "." << IBRCOMMON_LOGGER_ENDL; 00126 ret = 0; 00127 break; 00128 } 00129 00130 return ret; 00131 } 00132 00133 00134 00135 static int bread(BIO *bio, char *buf, int len) 00136 { 00137 iostream *stream = reinterpret_cast<iostream*>(bio->ptr); 00138 streamsize num_bytes = bio->num; 00139 00140 try{ 00141 /* make sure to read at least 1 byte and then read as much as we can */ 00142 num_bytes = stream->read(buf, 1).readsome(buf+1, len-1) + 1; 00143 } catch(ios_base::failure &ex){ 00144 /* ignore, bio->num will be returned and indicate the error */ 00145 } 00146 // catch(ConnectionClosedException &ex){ 00147 // throw; //this exception will be catched at higher layers 00148 // } 00149 00150 return num_bytes; 00151 } 00152 00153 00154 00155 static int bwrite(BIO *bio, const char *buf, int len) 00156 { 00157 if(len == 0){ 00158 return 0; 00159 } 00160 iostream *stream = reinterpret_cast<iostream*>(bio->ptr); 00161 00162 /* write the data */ 00163 try{ 00164 stream->write(buf, len); 00165 } catch(ios_base::failure &ex){ 00166 /* ignore, the badbit is checked instead */ 00167 } 00168 // catch(ConnectionClosedException &ex){ 00169 // throw; 00170 // } 00171 if(stream->bad()){ 00172 IBRCOMMON_LOGGER_DEBUG(20) << "iostreamBIO: underlying Stream went bad while writing." << IBRCOMMON_LOGGER_ENDL; 00173 return 0; 00174 } 00175 00176 /* flush the underlying stream */ 00177 try{ 00178 stream->flush(); 00179 } catch(ios_base::failure &ex){ 00180 /* ignore, the badbit is checked instead */ 00181 } 00182 // catch(ConnectionClosedException &ex){ 00183 // throw; 00184 // } 00185 if(stream->bad()){ 00186 IBRCOMMON_LOGGER_DEBUG(20) << "iostreamBIO: underlying Stream went bad while flushing (bwrite)." << IBRCOMMON_LOGGER_ENDL; 00187 return 0; 00188 } 00189 00190 return len; 00191 } 00192 00193 }