All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.org.jafer.transport.PDUDriver Maven / Gradle / Ivy

/**
 * JAFER Toolkit Poject.
 * Copyright (C) 2002, JAFER Toolkit Project, Oxford University.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package org.jafer.transport;



import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;

import asn1.ASN1Exception;
import asn1.ASN1Integer;
import asn1.BEREncoding;
import z3950.v3.PDU;
import z3950.v3.CloseReason;

import z3950.v3.*;
import asn1.*;
import java.util.TimerTask;
import java.util.Timer;
import org.jafer.util.*;


class KillSocketTask extends TimerTask {
  private static Logger logger;
  private Socket sock;

  public KillSocketTask(Socket asock) {
    logger = Logger.getLogger("org.jafer.util");
    this.sock = asock;
  }

  public void run() {
    try {
      logger.fine("Attempting to force close timed out socket");
      this.sock.close();
    }
    catch (Exception ex) {
      logger.fine("Force closed timed out socket failed: " + ex.getMessage());
    }
  }
}

/**
 * 

Used by ZClient and ZServer Session for Z39.50 input/output - each session has it's own PDUDriver. * Includes methods for get/send PDU and close. I/O errors throw org.jafer.util.ConnectionException - * caught and handled by the session object.

* @author Antony Corfield; Matthew Dovey; Colin Tatham * @version 1.0 */ public class PDUDriver { private static long DATA_TIMEOUT = 60000; // Allow 60 seconds for typical data transfer private static Logger logger; private Hashtable closeReason; private Socket socket; private BufferedInputStream src; private BufferedOutputStream dest; private String sessionName; /** * @todo: how do we handle preferredMessageSize and exceptionalRecordSize? */ /** * @todo: read closeReason from config */ public PDUDriver(String sessionName, Socket socket, int timeout) throws IOException { logger = Logger.getLogger("org.jafer.util"); this.sessionName = sessionName; this.socket = socket; closeReason = loadCloseReason(new Hashtable()); String message; try { this.socket.setSoTimeout(timeout); src = new BufferedInputStream(socket.getInputStream()); dest = new BufferedOutputStream(socket.getOutputStream()); } catch(java.net.SocketException e) { message = sessionName + " could not reset timeout on socket (" + e.toString() + ")"; logger.log(Level.SEVERE, message, e); throw e; } catch (IOException e) { try { socket.close(); } catch (IOException ex) {} socket = null; throw e; } } public BEREncoding getBEREncoding() throws ConnectionException { Timer timer = null; try { long timeout = this.socket.getSoTimeout(); if (timeout > 0) { timer = new Timer(); timer.schedule(new KillSocketTask(this.socket), (long) (timeout + DATA_TIMEOUT)); } BEREncoding berEncoding = BEREncoding.input(src); if (timer != null) { timer.cancel(); } return berEncoding; } catch (java.net.SocketException ex) { if (timer != null) { timer.cancel(); } throw new ConnectionException("socket closed", ex); } catch (java.net.SocketTimeoutException ex) { if (timer != null) { timer.cancel(); } initClose(7); throw new ConnectionException("association timed out", ex); } catch (java.io.InterruptedIOException ex) { if (timer != null) { timer.cancel(); } initClose(7); throw new ConnectionException("association interrupted", ex); } catch (java.io.IOException ex) { if (timer != null) { timer.cancel(); } initClose(6); throw new ConnectionException(ex.toString(), ex); } catch (ASN1Exception ex) { if (timer != null) { timer.cancel(); } initClose(2); throw new ConnectionException(ex.toString(), ex); } } private String dumpPDU(PDU pdu) { return pdu.toString(); } public PDU getPDU() throws ConnectionException { try { BEREncoding ber = getBEREncoding(); PDU pduRequest = new PDU(ber, true); logger.log(Level.FINEST, sessionName + " incoming PDU: " + dumpPDU(pduRequest)); return pduRequest; } catch (asn1.ASN1Exception ex) { throw new ConnectionException("ASN1 data error", ex); } catch (NullPointerException ex) { throw new ConnectionException("connection dropped by client", ex); } } public synchronized void sendPDU(PDU pduResponse) throws ConnectionException { Timer timer = null; try { logger.log(Level.FINEST, sessionName + " outgoing PDU: " + dumpPDU(pduResponse)); long timeout = this.socket.getSoTimeout(); if (timeout > 0) { timer = new Timer(); timer.schedule(new KillSocketTask(this.socket), (long)(timeout + DATA_TIMEOUT)); } pduResponse.ber_encode().output(dest); dest.flush(); if (timer != null) { timer.cancel(); } } catch (java.net.SocketException ex) { if (timer != null) { timer.cancel(); } throw new ConnectionException("socket closed", ex); } catch (java.net.SocketTimeoutException ex) { if (timer != null) { timer.cancel(); } throw new ConnectionException("association timed out", ex); } catch (java.io.InterruptedIOException ex) { if (timer != null) { timer.cancel(); } throw new ConnectionException("association interrupted", ex); } catch (java.io.IOException ex) { if (timer != null) { timer.cancel(); } throw new ConnectionException(ex.toString(), ex); } catch (asn1.ASN1Exception ex) { if (timer != null) { timer.cancel(); } throw new ConnectionException(ex.toString(), ex); } } boolean reentrant = false; public void initClose(int reason) throws ConnectionException { if (reentrant) { return; } reentrant = true; String closeReason = getCloseReason(reason); logger.log(Level.FINE, sessionName + " requesting close due to " + closeReason); PDU pduResponse = new PDU(); pduResponse.c_close = new z3950.v3.Close(); pduResponse.c_close.s_closeReason = new CloseReason(); pduResponse.c_close.s_closeReason.value = new ASN1Integer(reason); pduResponse.c_close.s_referenceId = null; sendPDU(pduResponse); waitClosePDU(); reentrant = false; } public void respClose(PDU pduRequest) throws ConnectionException { int k = 9; if (pduRequest.c_close.s_closeReason.value != null) k = pduRequest.c_close.s_closeReason.value.get(); logger.log(Level.FINE, sessionName + " close requested due to " + getCloseReason(k)); PDU pduResponse = new PDU(); pduResponse.c_close = new z3950.v3.Close(); pduResponse.c_close.s_closeReason = new CloseReason(); pduResponse.c_close.s_closeReason.value = new ASN1Integer(pduResponse.c_close.s_closeReason.E_peerAbort); pduResponse.c_close.s_referenceId = pduRequest.c_close.s_referenceId; sendPDU(pduResponse); } private void waitClosePDU() { BEREncoding ber; PDU pdu = null; logger.log(Level.FINE, sessionName + " waiting for close response"); try { for (int n = 0; n < 10; n++) { pdu = waitForPDU(); if (pdu.c_close != null) { logger.log(Level.FINE, sessionName + " got close response"); return; } } logger.log(Level.FINE, sessionName + " close PDU not received"); } catch (Exception ex) { logger.log(Level.WARNING, sessionName + " communications error waiting for Close response (" + ex.toString() + ")"); } } private PDU waitForPDU() throws ConnectionException { BEREncoding ber = getBEREncoding(); if (ber == null) return null; PDU pdu = null; try { pdu = new PDU(ber, true); } catch (ASN1Exception ex) { return null; } return pdu; } private String getCloseReason(int k) { Integer key = new Integer(k); if (closeReason.containsKey(key)) return (String)closeReason.get(key); return (String)closeReason.get(new Integer(9)); } private Hashtable loadCloseReason(Hashtable closeReason) { /** @todo Read from config */ closeReason.put(new Integer(0), "Finished"); closeReason.put(new Integer(1), "Shutdown"); closeReason.put(new Integer(2), "System Problem"); closeReason.put(new Integer(3), "Cost Limit"); closeReason.put(new Integer(4), "Resources"); closeReason.put(new Integer(5), "Security violation"); closeReason.put(new Integer(6), "Protocol error"); closeReason.put(new Integer(7), "Lack of activity"); closeReason.put(new Integer(8), "Peer abort"); closeReason.put(new Integer(9), "unknown reason"); return closeReason; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy