/* * Copyright (c) 1995, 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. */ /* ANSI X3.28 Protocol * * featuring: * * Establishment/Termination Subcategory 2.3 * Message Transfer Subcategory B2 * * Options: * * WITH_BLK Link Block Numbers [3.7] (implies MODULO_8) * MODULO_8 Modulo-8 numbered Acknowledgement (`a la C2) [4.2.2.4.3] * ALT_ACK Alternating Acknowledgement (`a la B2) [4.2.2.4.2] * TRANSPARENT Transparent Heading and Text (`a la D1) [6.10] */ #ifndef ANSI_X3_28_H #define ANSI_X3_28_H #ifdef WITH_BLK # ifdef ALT_ACK # undef ALT_ACK # endif # define MODULO_8 #endif #if defined(ALT_ACK) && defined(MODULO_8) # error ALT_ACK and MODULO_8 are mutually exclusive #endif #include #include #include #include #include /* ASCII Communication Control Characters [4.1] */ #define A_NUL 0 #define A_SOH 1 #define A_STX 2 #define A_ETX 3 #define A_EOT 4 #define A_ENQ 5 #define A_ACK 6 #define A_DLE 020 #define A_NAK 025 #define A_SYN 026 #define A_ETB 027 #define A_CAN 030 /* Control Sequences Represented by Code Extension [4.2] */ /* Control Sequences are carried from and to functions in the form * of `Control Compounds'. Control Compounds are integers (at least * 16 bit words) whose bytes in low to high order are the characters * of the control sequence. The int compounds are used here rather * than strings in order to faciliate testing in switch() statements. * * Use the folowing macros to work with Control Compounds: * * ASCC - ASsemble Control Compound (0 <= i < 4) * DICC - DIsassemble Control Compound (0 <= i < 4) * NCCC - Number of Characters in Control Compound * NCCS - Number of Characters in Control Sequence * BLKP - Link Block Number follows (Predicate) * BCCP - Block Check Character follows (Predicate) * T2C - Transparent to simple Control compound mapping * C2T - Simple Control compound to Transparent mapping */ #define _A_ASCC(s,i,c) ((((c)&0xff)<<(((i)&3)<<3))|(s)) /* DLE-x Control Compound */ #define _A_DLEC(x) _A_ASCC(A_DLE,1,x) #define _A_DICC(s,i) (((s)>>(((i)&3)<<3))&0xff) #define _A_NCCS(c) ((((c)&0xff)==A_DLE) ? 2 : 1) #define _A_NCCC(c) ((((c)&0xff)==A_DLE) ? 2 : 1) #ifdef WITH_BLK # define _A_BLKP(c) \ (((ctrl == _A_C2T(A_SOH)) || (ctrl == _A_C2T(A_STX))) ? TRUE : FALSE) # define A_BLK_INC(n) ((n)=((n)+1)&7) #else # define _A_BLKP(c) FALSE # define A_BLK_INC(n) #endif #ifdef TRANSPARENT # define _A_T2C(c) ((((c)&0xff)==A_DLE) ? ((c) >> 8) : (c)) # define _A_C2T(c) _A_DLEC(c) #else # define _A_T2C(c) (c) # define _A_C2T(c) (c) #endif #define _A_BCCP(c) \ (((ctrl == _A_C2T(A_ETB)) || (ctrl == _A_C2T(A_ETX))) ? TRUE : FALSE) /* DEOT (Mandatory Disconnect) [4.2.1] */ #define A_DEOT _A_DLEC(A_EOT) /* ACKN (Acknowledgement N) [4.2.2] */ #ifdef MODULO_8 # define A_ACKN(n) _A_DLEC(((n)&7)|0x30) #elif ALT_ACK # define A_ACKN(n) _A_DLEC(((n)&1)|0x30) #else # define A_ACKN(n) A_ACK #endif #define A_ACK0 A_ACKN(0) #define A_ACK1 A_ACKN(1) #define A_ACK2 A_ACKN(2) #define A_ACK3 A_ACKN(3) #define A_ACK4 A_ACKN(4) #define A_ACK5 A_ACKN(5) #define A_ACK6 A_ACKN(6) #define A_ACK7 A_ACKN(7) #ifdef MODULO_8 # define A_ACKN_INC(n) ((n)=((n)+1)&7) #elif defined(ALT_ACK) # define A_ACKN_INC(n) ((n)=((n)+1)&1) #else # define A_ACKN_INC(n) #endif /* SOTB (Start of Transmission Block) [4.2.3] */ #define A_SOTB _A_DLEC('=') /* Transparent Mode Control Sequences [4.2.4 -- 4.2.9, 4.2.12] */ #define A_TSOH _A_DLEC(A_SOH) /* [4.2.4] */ #define A_TSTX _A_DLEC(A_STX) /* [4.2.5] */ #define A_TETX _A_DLEC(A_ETX) /* [4.2.6] */ #define A_TETB _A_DLEC(A_ETB) /* [4.2.7] */ #define A_TSYN _A_DLEC(A_SYN) /* [4.2.8] */ #define A_TDLE _A_DLEC(A_DLE) /* [4.2.9] */ #define A_TENQ _A_DLEC(A_ENQ) /* [4.2.12] (Transparent Block Abort) */ /* Others */ #define A_WACK _A_DLEC(';') /* [4.2.10] */ #define A_SOSS _A_DLEC(':') /* [4.2.11] */ #define A_RINT _A_DLEC('<') /* [4.2.13] */ /* * Block Checking [4.3] */ /* BCC (Block Check Character) [4.3.1] */ #define A_BCC(bcc,c) { bcc^=c; } /* Prefixes [3.3] */ #define A_PREFIX_MAXLEN 15 /* Timers [3.5.2] * * Timer B is not implemented because it's functionality is taken * over by timer D plus the maximum block size. * Timer E is active when the direction is to be changed from master * to slave and ENQ is being awaited after having sent EOT. The * timeout time of timer E is typically longer than that of Timer A * or D since the remote application may need more time to generate * a response message. * Only one of the timers A, D and E is active at the same time. */ int astimer_A; /* A (Response Timer) [3.5.2.1] */ int astimer_D; /* D (No-Activity Timer) [3.5.2.4] */ int astimer_E; /* E (Application Response Timer) [non standard] */ /* * ANSI X3.28 Stream Data Structure (ASTRM) */ typedef struct _sASTRM { int _fd; /* file descriptor */ int _flags; /* flags register */ #define AS_IN 0x00000001 #define AS_OUT 0x00000002 #define AS_DIR_MASK (AS_IN|AS_OUT) /* flags & AS_DIR_MASK == 0 -> no xact */ #define AS_HEADING 0x00000004 #define AS_TEXT 0x00000008 #define AS_MIXED (AS_HEADING|AS_TEXT) #define AS_TYPE_MASK (AS_HEADING|AS_TEXT|AS_MIXED) #define AS_BLOCK 0x00000010 /* about to receive or send a block */ #define AS_LAST 0x00000040 /* last block in message */ #define AS_ACTION_MASK (AS_BLOCK | AS_LAST) #define AS_EXCEPTION 0x80000000 /* flags < 0 -> EXCEPTION */ #define AS_ERROR_MASK 0x7F000000 #define AS_ERROR_SHIFT 24 #define AS_ERROR(a, e) \ ((a)->_flags = ((a)->_flags & ~AS_ERROR_MASK) \ | AS_EXCEPTION | ((e) << AS_ERROR_SHIFT)) #define AS_ERRNO(a) \ (((a)->_flags & AS_ERROR_MASK) >> AS_ERROR_SHIFT) #define AS_EINTR 0x01 /* termination interrupt */ #define AS_EABORT 0x02 /* sending station abort */ #define AS_ERINT 0x03 /* reverse interrupt */ #define AS_EWACK 0x04 /* temporary interrupt */ #define AS_ERETRY 0x05 /* resend counter expired */ #define AS_ERANGE 0x06 /* reading beyond end of message */ #define AS_ESYNTAX 0x07 /* handshake syntax error */ #define AS_ETIMERA 0x08 /* timer a expired */ #define AS_ETIMERD 0x09 /* timer d expired */ #define AS_ETIMERE 0x0a /* timer e expired */ #define AS_ENOBUF 0x0b /* buffer memory exceeded */ #define AS_EILL 0x0c /* illegal operation */ #define AS_ENOTEXT 0x0d /* message has no text part */ #define AS_ETEXT 0x0e /* block has already some text */ #define AS_ECONNRESET 0x0f /* connection closed by peer */ #define AS_EIO 0x10 /* an error occured on OS level */ #define AS_MAX_ERRNO AS_EIO int _errno; /* the errno of an OS error (AS_EIO) */ #define AS_RESET_MASK (AS_TYPE_MASK|AS_ACTION_MASK|AS_EXCEPTION|AS_ERROR_MASK) size_t _size; /* buffer size */ char *_base; /* buffer memory */ char *_end; /* end of buffer = [last byte] + 1 */ char *_stx; /* start of text */ char *_poi; /* buffer pointer */ #define AS_PFX_SIZE (A_PREFIX_MAXLEN+1) char _pfx[AS_PFX_SIZE]; /* the prefix of advisory control sequence */ int _resp; /* last response for ENQ */ char _bcc; /* BCC */ int _ackn; /* ACKN number */ int _blk; /* BLK (Link Block Number) */ } ASTRM; #define AS_BUF_SIZE 1024 #define AS_MAX_RESEND 10 #define AS_MAX_RECTRL 10 char *ansi_errlist[AS_MAX_ERRNO + 1]; /* * Functions */ __BEGIN_DECLS ASTRM *asattach(int fd, size_t bs, int flags); result asdetach(ASTRM *asp, int how); result asbuf(ASTRM *asp, size_t buf_size); int asmode(ASTRM *asp, int flags, int mask); result asflush(ASTRM *asp, int flags); void aspurge(ASTRM *asp); void asreset(ASTRM *asp); char* asprefix(ASTRM *asp, const char*); result _as_send(ASTRM *asp); int _as_recv(ASTRM *asp); result _as_discard_block(ASTRM *asp, const char *prefix, int ctrl, bool care_bcc); result _as_send_ctrl(ASTRM *asp, const char *prefix, int ctrl, char BccBlk); int _as_recv_ctrl(ASTRM *asp, char *prefix, char *BccBlk, int timeout /* seconds */); result _as_send_ack(ASTRM *asp, const char *prefix, int ack); result _as_recv_ack(ASTRM *asp, char *prefix, int ack); result _as_recv_enq(ASTRM *asp); result _as_ipfx(ASTRM *fd, int timeout /* seconds */); result _as_opfx(ASTRM *fd, int timeout /* seconds */); result _as_select_except_handler(ASTRM *asp); __END_DECLS /* * Macros and Inline Functions */ #define aseof(s) (((s)->_flags & AS_LAST) && ((s)->_poi >= (s)->_end)) #if defined(__GNUC__) static __inline__ int asgetc(ASTRM *s) { if(s->_flags & AS_IN) { if(s->_poi >= s->_end) if(_as_recv(s) == FAIL) return FAIL; return *s->_poi++; } else { AS_ERROR(s, AS_EILL); return FAIL; } } static __inline__ int asputc(int c, ASTRM *s) { if(s->_flags & AS_OUT) { if(s->_poi < s->_end) goto putc; else if(_as_send(s) == FAIL) return FAIL; putc: if(c == A_DLE) { *s->_poi++ = A_DLE; A_BCC(s->_bcc, c); } *s->_poi++ = c; A_BCC(s->_bcc, c); return c; } else { AS_ERROR(s, AS_EILL); return FAIL; } } #else /* ! __GNUC__ */ int _as_getc(ASTRM *s); int _as_putc(int c, ASTRM *s); # define asgetc _as_getc # define asputc _as_putc #endif #endif