/* * 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" #include "llpdrv.h" #include "minimal.h" #include "trap.h" #include "socket.h" #include "intern.h" #include #include #include #include static result find_char(FILE* fp, char stop) { char c; DBG(syslog(LOG_DEBUG, "looking for char %d '%c'", stop, stop)); while((c = getc(fp)) != stop) if(c == EOF) if(ferror(fp)) { syslog(LOG_ERR, "find_char: %m"); return FAIL; } else /* connection closed */ { syslog(LOG_ERR, "connection closed"); return FAIL; } else DBG(syslog(LOG_DEBUG, "got: 0x%02x `%c'", (int)c, c)); DBG(syslog(LOG_DEBUG, "found")); return SUCCESS; } int mini2i(FILE *mfp, FILE *ifp) { DBG(syslog(LOG_DEBUG, "forwarding minimal llp to internal llp")); if(find_char(mfp, BSTART) == FAIL) goto fail_extern; start: while(TRUE) { char c = getc(mfp); if(c == EOF) if(ferror(mfp)) { syslog(LOG_ERR, "find_char: %m"); return FAIL; } else /* connection closed */ { syslog(LOG_ERR, "connection closed"); return FAIL; } switch(c) { case BEND: DBG(syslog(LOG_DEBUG, "block ended")); goto end; case BSTART: syslog(LOG_NOTICE, "block restarted"); if(send_oob(ifp, A_STX) == FAIL) goto fail_intern; goto start; default: /* data */ if(putc(c, ifp) == EOF) { syslog(LOG_ERR, "putc: %m"); goto fail_intern; } } } end: if(find_char(mfp, BCRET) == FAIL) goto fail_extern; DBG(syslog(LOG_DEBUG, "message successful")); fflush(ifp); shutdown(fileno(ifp), 1); return SUCCESS; fail_extern: /* * Detach MINI stream, doing no further handshake. Cancel * internal transaction. */ fclose(mfp); DBG(syslog(LOG_DEBUG, "cancel transaction")); send_oob(ifp, A_CAN); fclose(ifp); llp_errno = RF_EXTERN; return FAIL; fail_intern: /* * Detach MINI stream. Close (detach) internal stream. */ fclose(mfp); fclose(ifp); llp_errno = RF_INTERN; return FAIL; } result i2mini(FILE *ifp, FILE *mfp) { #ifdef hpux int minuspid = -getpid(); #endif DBG(syslog(LOG_DEBUG, "forwarding internal llp to minimal llp")); #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; } atsignal(SIGURG, 0) { char c = recv_oob(ifp); switch(c) { case A_STX: syslog(LOG_NOTICE, "block restarted"); break; case A_CAN: syslog(LOG_WARNING, "transaction cancelled by server"); goto fail_intern; case FAIL: goto fail_intern; default: syslog(LOG_ERR, "undefined out of band signal %d", c); goto fail_intern; } } fputc(BSTART, mfp); 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 block */ { DBG(syslog(LOG_DEBUG, "end of block")); putc(BEND, mfp); putc(BCRET, mfp); goto success; } /* data */ if(putc(c, mfp) == EOF) if(ferror(mfp)) /* read error */ { syslog(LOG_ERR, "putc: %m"); goto fail_extern; } else /* connection closed by client */ { syslog(LOG_ERR, "connection closed by client"); goto fail_extern; } } while(TRUE); success: DBG(syslog(LOG_DEBUG, "message successful")); fflush(mfp); return SUCCESS; fail_extern: /* * Detach MINI stream doing no further handshake. Cancel * internal transaction. * Cancel internal transaction: Just close it, the server gets a * EPIPE error when trying to write any more data. */ fclose(mfp); syslog(LOG_WARNING, "cancel server transaction"); fclose(ifp); llp_errno = RF_EXTERN; return FAIL; fail_intern: /* * Abort and Detach MINI stream. Close (detach) internal stream. */ fclose(mfp); fclose(ifp); llp_errno = RF_INTERN; goto fail_commit; fail_commit: return FAIL; }