Вести с полей
Привет всем.
Медленно и печально продираюсь сквозь терни подключения к FB3 минуя fbclient.dll. Добрался до настройки шифрования подключения (op_crypt). Разобравшись что к чему, я даже немного оживился — если делать по уму, то конструкция получается достаточно красивой.
Изначально объект порта отправлял и получал пакеты напрямую через объект сокета. С внедрением шифрования пришлось спрятать сокет за интерфейсом RemoteFB__PortStream:
class RemoteFB__PortStream:public RemoteFB__SmartInterface
{
public:
virtual void Write(size_t cb,
const void* pv)=0;
virtual void FlushWriteBuf()=0;
virtual void Read(size_t cb,
void* pv)=0;
};//class RemoteFB__PortStream
Для этого интерфейса соорудил класс, который реализует алгоритм шифрования «Arc4» и читает/пишет данные через нижележащий объект с интерфейсом RemoteFB__PortStream:
void RemoteFB__PortStream__Crypt_Arc4::Write(size_t const cb,
const void* const pv)
{
CHECK_READ_PTR(pv,cb);
assert(m_spBaseStream);
const byte_type* p=reinterpret_cast<const byte_type*>(pv);
const byte_type* const e=(p+cb);
for(;;)
{
assert(m_write_buf_beg<=m_write_buf_cur);
assert(m_write_buf_cur<=m_write_buf_end);
for(;;++p,++m_write_buf_cur)
{
if(p==e)
return;
if(m_write_buf_cur==m_write_buf_end)
break;
(*m_write_buf_cur)=m_Encoder.transform(*p);
}//for[ever]
assert(m_write_buf_cur==m_write_buf_end);
m_spBaseStream->Write(m_write_buf_end-m_write_buf_beg,
m_write_buf_beg); //throw
m_write_buf_cur=m_write_buf_beg;
}//for[ever]
}//Write
//------------------------------------------------------------------------
void RemoteFB__PortStream__Crypt_Arc4::FlushWriteBuf()
{
assert(m_write_buf_beg<=m_write_buf_cur);
assert(m_write_buf_cur<=m_write_buf_end);
assert(m_spBaseStream);
//1. сброс буферизированных данных
if(m_write_buf_cur!=m_write_buf_beg)
{
m_spBaseStream->Write(m_write_buf_cur-m_write_buf_beg,
m_write_buf_beg);
m_write_buf_cur=m_write_buf_beg;
}//if
assert(m_write_buf_cur==m_write_buf_beg);
//2. сброс буфера на нижнем уровне
m_spBaseStream->FlushWriteBuf(); //throw
}//FlushWriteBuf
//------------------------------------------------------------------------
void RemoteFB__PortStream__Crypt_Arc4::Read(size_t const cb,
void* const pv)
{
CHECK_READ_WRITE_PTR(pv,cb);
assert(m_spBaseStream);
m_spBaseStream->Read(cb,pv); //throw
byte_type* p=reinterpret_cast<byte_type*>(pv);
const byte_type* const e=(p+cb);
for(;p!=e;++p)
{
(*p)=m_Decoder.transform(*p);
}//for p
}//Read
Сам процесс «инициализации» шифрования выглядит просто:
1. Отправляем серверу пакет op_crypt с именем типа ключа шифрования (Symmetric) и названием алгоритма (плагина) шифрования (Arc4).
2. Замещаем объект сокета на объект зашифрованного потока:
m_spSocket.swap(spCryptStream);
3. Читаем (зашифрованный!) ответ сервера. Прочитали — все ок (хотя статус вектор, все таки, стоит проверить).
Не смогли прочитать (сервер оборвал подключение) — можно залезть в лог сервера и посмотреть, что он там написал:
HOME3 Wed Aug 17 12:20:11 2016 start_crypt: Client attempted to start wire encryption using unsupported plugin QUQU HOME3 Wed Aug 17 12:34:53 2016 start_crypt: Client attempted to start wire encryption using unsupported plugin QUQU+++
Нормальную нотификацию клиента (вместо обрыва) о проблеме разработчики сервера неасилили. Главное ошибку о некорректном логине/пароле — сервер присылает, а тут тупо закрывает подключение. Жаль.
В тройке еще компрессор к потоку данных прикрутили. По сути, думаю, это то же шифрование. Посмотрим. Потом.