/* * Copyright (c) 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ // FIXME! This currently works as MLLP #pragma implementation #include "HLLPSocket.h" #ifdef PROTOGEN # include "exception.h" # include "logfile.h" #else # include # define ERROR(fmt, args...) { fprintf(stderr, fmt "\n" , ## args); exit(1); } # define FATAL(fmt, args...) { fprintf(stderr, fmt "\n" , ## args); abort(); } # define WARNING(fmt, args...) { fprintf(stderr, fmt "\n" , ## args); } #endif static char CtrlChars[17] = { 0x0B, // start of block 'D', 'N', // block type 'C', 'X', 'B', 'G', // NAK block code (or data) '0', '0', '0', '0', '0', // block length '9', '9', '9', // block checksum 0x1C, 0x0D, // end of block }; const int Cstart = 0; const int Tdata = 1; const int Tnak = 2; const int Nlen = 3; const int Nchk = 4; const int Nbuf = 5; const int Nerr = 6; const int Len = 7; const int Lenlen = 5; const int Chk = 12; const int Chklen = 3; const int Cend = 15; const int Ccret = 16; /********************************************************************** * ctor, dtor, and copy **********************************************************************/ HLLPSocket::HLLPSocket(const char *address, const char *, size_t) : Socket(address) { if(! (_lower_level->capabilities() & any_duplex)) ERROR("cannot work with simplex socket"); _chksum = 0; _blen = 0; } HLLPSocket::HLLPSocket() : Socket() { _chksum = 0; _blen = 0; } HLLPSocket::~HLLPSocket() { if(state() & connected) close(); } Socket *HLLPSocket::ctor(const char *address, const char *param, size_t parlen) { return new HLLPSocket(address, param, parlen); } Socket *HLLPSocket::ctor() { return new HLLPSocket(); } /********************************************************************** * socket methods **********************************************************************/ size_t HLLPSocket::send(const char *buf, size_t len, int msgf) { if(_state_plus & receiving) // leave receiving state { char ch; do { if(_lower_level->recv(&ch, 1) == 0) { WARNING("unexpected end of input 1"); break; } } while(ch != CtrlChars[Cend]); do { if(_lower_level->recv(&ch, 1) == 0) { WARNING("unexpected end of input 2"); break; } } while(ch != CtrlChars[Ccret]); _state_plus &= ~receiving; } if( len > 0 || !(msgf & (msg_eom | msg_eot)) ) { if(!(_state_plus & sending)) // enter sending state { _lower_level->send(&CtrlChars[Cstart], 1); _state_plus = _state_plus | sending & ~eox_any; } len = _lower_level->send(buf, len, msgf & ~(msg_eom | msg_eot)); } if(msgf & (msg_eom | msg_eot) && (_state_plus & sending)) { _lower_level->send(&CtrlChars[Cend], 2); _state_plus = _state_plus & ~sending | eom_placed | eot_placed; } return len; } size_t HLLPSocket::recv(char *buf, size_t max, int msgf) { if(_state_plus & sending) { _lower_level->send(&CtrlChars[Cend], 2); _state_plus = _state_plus & ~sending; } if(_state_plus & (eom_seen | eot_seen)) { _state_plus &= ~receiving; return 0; } if(! (_state_plus & receiving)) { char ch; do { if(_lower_level->recv(&ch, 1) == 0) return 0; } while(ch != CtrlChars[Cstart]); _state_plus = _state_plus | receiving & ~eox_any; } size_t i; for(i = 0; i < max; i++, buf++) { if(_lower_level->recv(buf, 1, msgf) == 0) { WARNING("unexpected end of input 4"); _state_plus |= eom_seen; return i; } else { if(*buf == CtrlChars[Cend]) { char ch; do { if(_lower_level->recv(&ch, 1, msgf) == 0) { WARNING("unexpected end of input 5"); break; } } while(ch != CtrlChars[Ccret]); _state_plus |= eom_seen | eot_seen; return i; } } } return i; } void HLLPSocket::shutdown(flags_t mode) { if(_state_plus & sending) { _lower_level->send(&CtrlChars[Cend], 2); _state_plus = _state_plus & ~sending | eot_placed | eom_placed; } if(_state_plus & receiving) { _state_plus &= ~receiving; } _lower_level->shutdown(mode); } void HLLPSocket::close(flags_t mode) { if(_state_plus & sending) { if(! (mode & silently)) { _lower_level->send(&CtrlChars[Cend], 2); _state_plus |= eot_placed | eom_placed; } _state_plus &= ~sending; } if(_state_plus & receiving) { _state_plus &= ~receiving; } _lower_level->close(mode); }