/* * 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. */ #include "pg_config.h" IDENT("@(#) ansi2i.c (Gunther Schadow) 12/19/96"); #include "llpdrv.h" #include "ansi.h" #include "trap.h" #include "socket.h" #include "intern.h" #include "ansi.h" #include #include #include #include #include result ansi2i(ASTRM *asp, FILE *ifp) { result res; /* * We are going to modify the signal HUP, TERM and INT */ struct sigsave svTERM, svHUP, svINT; svsignal(SIGHUP, &svHUP); svsignal(SIGTERM, &svTERM); svsignal(SIGINT, &svINT); /* * Set signal handling for proper cancellation of interaction. */ atsignal(SIGHUP, 0) goto interrupt_signal; atsignal(SIGTERM, 0) goto interrupt_signal; atsignal(SIGINT, 0) goto interrupt_signal; DBG(syslog(LOG_DEBUG, "forwarding ANSI X3.28 to internal")); if(asmode(asp, AS_IN | AS_TEXT, AS_DIR_MASK | AS_RESET_MASK) < 0) switch(AS_ERRNO(asp)) { case AS_EIO: errno = asp->_errno; syslog(LOG_ERR, "ansi2i:asmode: system error: %m"); goto fail_extern; case AS_ECONNRESET: syslog(LOG_WARNING, "ansi2i:asmode: %s", ansi_errlist[AS_ERRNO(asp)]); goto fail_extern; case AS_ENOTEXT: syslog(LOG_WARNING, "ansi2i:asmode: %s", ansi_errlist[AS_ERRNO(asp)]); goto end_message; case AS_EABORT: syslog(LOG_WARNING, "ansi2i:asmode: %s", ansi_errlist[AS_ERRNO(asp)]); goto sending_abort; case AS_ETIMERA: case AS_ETIMERD: case AS_ETIMERE: syslog(LOG_WARNING, "ansi2i:asmode: %s", ansi_errlist[AS_ERRNO(asp)]); goto timeout; default: syslog(LOG_WARNING, "ansi2i:asmode: %s", ansi_errlist[AS_ERRNO(asp)]); goto interrupt; } while(!aseof(asp)) { int c; if((c = asgetc(asp)) == FAIL) { switch(AS_ERRNO(asp)) { case AS_EIO: errno = asp->_errno; syslog(LOG_ERR, "ansi2i:asgetc: system error: %m"); goto fail_extern; case AS_ECONNRESET: syslog(LOG_WARNING, "ansi2i:asgetc: %s", ansi_errlist[AS_ERRNO(asp)]); goto fail_extern; case AS_EABORT: syslog(LOG_WARNING, "ansi2i:getc: %s", ansi_errlist[AS_ERRNO(asp)]); goto sending_abort; case AS_ETIMERA: case AS_ETIMERD: case AS_ETIMERE: syslog(LOG_WARNING, "ansi2i:asgetc: %s", ansi_errlist[AS_ERRNO(asp)]); goto timeout; default: syslog(LOG_WARNING, "ansi2i:asgetc: %s", ansi_errlist[AS_ERRNO(asp)]); goto interrupt; } } if(putc(c, ifp) == FAIL) { syslog(LOG_ERR,"ansi2i: putc: %m"); goto fail_intern; } DBG(syslog(LOG_DEBUG, "ansi2i: wrote 0x%02x `%c'", c, c)); } end_message: /* * Flush internal stream and shutdown the write end. */ DBG(syslog(LOG_DEBUG, "message successful")); fflush(ifp); shutdown(fileno(ifp), 1); res = SUCCESS; goto end; fail_intern: /* * Abort and detach ANSI X3.28 stream. Close (detach) internal stream. */ llp_errno = RF_INTERN; res = FAIL; asdetach(asp, 0); fclose(ifp); goto end; sending_abort: /* * Detach ANSI X3.28 stream, doing no further handshake. Cancel * internal transaction. */ llp_errno = RF_ABORT; res = FAIL; asdetach(asp, -1); goto cancel_intern; fail_extern: /* * Detach ANSI X3.28 stream, doing no further handshake. Cancel * internal transaction. */ llp_errno = RF_EXTERN; res = FAIL; if(AS_ERRNO(asp) != AS_EIO) /* yes try to abort gracefully if possible */ asdetach(asp, 0); /* FIXME: graceful exit is not an option here, but */ else /* this is used for AS_ESYNTAX as well! */ asdetach(asp, -1); goto cancel_intern; timeout: interrupt: /* * Detach ANSI X3.28 stream, with termination interrupt. Cancel * internal transaction. */ llp_errno = RF_ABORT; res = FAIL; asdetach(asp, 0); goto cancel_intern; interrupt_signal: /* * Interrupt and detach ANSI X3.28 stream. Cancel internal transaction. */ res = -2; asdetach(asp, 0); goto cancel_intern; cancel_intern: /* * Cancel internal transaction: Send CAN as oob-data and close * internal stream. */ DBG(syslog(LOG_DEBUG, "cancel server interaction")); fpurge(ifp); send_oob(ifp, A_CAN); fclose(ifp); goto end; end: rssignal(SIGHUP, &svHUP); rssignal(SIGTERM, &svTERM); rssignal(SIGINT, &svINT); if(res == -2) raise(SIGTERM); return res; } result i2ansi(FILE *ifp, ASTRM *asp) { result res; #ifdef hpux int minuspid = -getpid(); #endif /* * We are going to modify the signal HUP, TERM and INT */ struct sigsave svTERM, svHUP, svINT; svsignal(SIGHUP, &svHUP); svsignal(SIGTERM, &svTERM); svsignal(SIGINT, &svINT); /* * Set signal handling for proper cancellation of interaction. */ atsignal(SIGHUP, 0) goto interrupt_signal; atsignal(SIGTERM, 0) goto interrupt_signal; atsignal(SIGINT, 0) goto interrupt_signal; DBG(syslog(LOG_DEBUG, "forwarding internal to ANSI X3.28")); #ifdef hpux if(ioctl(fileno(ifp), SIOCSPGRP, &minuspid) == FAIL) #else if(fcntl(fileno(ifp), F_SETOWN, getpid()) == FAIL) #endif { syslog(LOG_ERR, "F_SETOWN: %m"); goto fail_intern; } if(asmode(asp, AS_OUT | AS_TEXT, AS_DIR_MASK | AS_RESET_MASK) == FAIL) { syslog(LOG_ERR, __FUNCTION__ ":asmode: %s", ansi_errlist[AS_ERRNO(asp)]); switch(AS_ERRNO(asp)) { case AS_EIO: errno = asp->_errno; syslog(LOG_ERR, __FUNCTION__ ":asmode: %m"); case AS_ECONNRESET: goto fail_extern; default: goto sending_abort; } } atsignal(SIGURG, 0) { char c = recv_oob(ifp); switch(c) { case A_STX: syslog(LOG_NOTICE, "message restarted"); asmode(asp, 0, AS_DIR_MASK); asmode(asp, AS_OUT | AS_TEXT, AS_RESET_MASK); break; case A_CAN: syslog(LOG_WARNING, "transaction cancelled by server"); goto sending_abort; case FAIL: goto fail_intern; default: syslog(LOG_ERR, "undefined out of band signal %d", c); goto fail_intern; } } do { char c = getc(ifp); if(c == EOF) if(ferror(ifp)) /* read error */ { syslog(LOG_ERR, "getc: %m"); goto fail_intern; } else /* connection closed: end of message */ { DBG(syslog(LOG_DEBUG, "end of message")); goto end_message; } /* data */ if(asputc(c, asp) == FAIL) { syslog(LOG_ERR, __FUNCTION__ ":asputc: %s", ansi_errlist[AS_ERRNO(asp)]); switch(AS_ERRNO(asp)) { case AS_EIO: errno = asp->_errno; syslog(LOG_ERR, "asputc: %m"); case AS_ECONNRESET: goto fail_extern; default: /* i.e. ERETRY, ETIMER., ESYNTAX */ goto sending_abort; } } } while(TRUE); end_message: /* * Flush ANSI X3.28 stream and finish the message. */ DBG(syslog(LOG_DEBUG, "message successful")); res = SUCCESS; if(asflush(asp, AS_LAST) == FAIL) { syslog(LOG_ERR, __FUNCTION__ ":asflush: %s", ansi_errlist[AS_ERRNO(asp)]); switch(AS_ERRNO(asp)) { case AS_EIO: errno = asp->_errno; syslog(LOG_ERR, "asflush: %m"); llp_errno = RF_EXTERN; res = FAIL; break; default: goto sending_abort; } } goto end; fail_intern: /* * Abort and detach ANSI X3.28 stream. Close (detach) internal stream. */ llp_errno = RF_INTERN; res = FAIL; asdetach(asp, 0); fclose(ifp); goto end; fail_extern: /* * Detach ANSI X3.28 stream doing no further handshake. Cancel * internal transaction. */ llp_errno = RF_EXTERN; res = FAIL; if(AS_ERRNO(asp) == AS_EIO) asdetach(asp, -1); else asdetach(asp, 0); /* FIXME! (see fail_extern in ansi2i()) */ goto cancel_intern; sending_abort: /* * Abort and detach ANSI X3.28 stream. Close (detach) internal * stream. */ llp_errno = RF_ABORT; res = FAIL; asdetach(asp, 0); fclose(ifp); goto end; interrupt_signal: /* * Abort and detach ANSI X3.28 stream. Cancel internal transaction. */ res = -2; asdetach(asp, 0); goto cancel_intern; cancel_intern: /* * Cancel internal transaction: Just close it, the server gets a * EPIPE error when trying to write any more data. */ syslog(LOG_WARNING, "cancel server transaction"); fclose(ifp); res = FAIL; llp_errno = RF_ABORT; end: rssignal(SIGHUP, &svHUP); rssignal(SIGTERM, &svTERM); rssignal(SIGINT, &svINT); if(res == -2) raise(SIGTERM); return res; }