/* * 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. */ #pragma implementation #include "MLLPSocket.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 0x1C, 0x0D, // end of block }; const int Cstart = 0; const int Cend = 1; const int Ccret = 2; /********************************************************************** * ctor, dtor, and copy **********************************************************************/ MLLPSocket::MLLPSocket(const char *address, const char *, size_t) : Socket(address) {} MLLPSocket::MLLPSocket() : Socket() {} MLLPSocket::~MLLPSocket() { if(state() & connected) close(); } Socket *MLLPSocket::ctor(const char *address, const char *param, size_t parlen) { return new MLLPSocket(address, param, parlen); } Socket *MLLPSocket::ctor() { return new MLLPSocket(); } /********************************************************************** * socket methods **********************************************************************/ size_t MLLPSocket::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 MLLPSocket::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 MLLPSocket::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 MLLPSocket::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); }