001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.iso.channel;
020
021import org.jpos.iso.*;
022
023import java.io.BufferedReader;
024import java.io.EOFException;
025import java.io.IOException;
026import java.io.InputStreamReader;
027import java.net.ServerSocket;
028import java.net.Socket;
029import java.util.Vector;
030
031/**
032 * Implements an ISOChannel suitable to be used to connect to an X.25 PAD. 
033 * It waits a limited amount of time to decide when a packet is ready
034 * to be unpacked.
035 *
036 * This channel is based on PADChannel version 1.4. The new version
037 * seems to have some problems dealing with ETXs (we're working on it).
038 * Use this version _only_ if you have problems with current PADChannel
039 * as it will be deprecated some time in the future.
040 *
041 * @author  <a href="mailto:apr@cs.com.uy">Alejandro P. Revilla</a>
042 * @version $Id$
043 *
044 * @see ISOMsg
045 * @see ISOException
046 * @see ISOChannel
047 */
048@SuppressWarnings("unchecked")
049public class X25Channel extends BaseChannel {
050    /** Buffered reader used to consume the channel's input stream. */
051    BufferedReader reader = null;
052    /** Optional header bytes prepended to outgoing messages. */
053    protected byte[] header;
054    /**
055     * No-args constructor
056     */
057    public X25Channel () {
058        super();
059    }
060    /**
061     * Constructs client ISOChannel
062     * @param host  server TCP Address
063     * @param port  server port number
064     * @param p     an ISOPackager
065     * @see ISOPackager
066     */
067    public X25Channel (String host, int port, ISOPackager p) {
068        super(host, port, p);
069    }
070    /**
071     * Construct server ISOChannel
072     * @param p     an ISOPackager
073     * @see ISOPackager
074     * @exception IOException on I/O error
075     */
076    public X25Channel (ISOPackager p) throws IOException {
077        super(p);
078    }
079    /**
080     * constructs a server ISOChannel associated with a Server Socket
081     * @param p     an ISOPackager
082     * @param serverSocket where to accept a connection
083     * @exception IOException on I/O error
084     * @see ISOPackager
085     */
086    public X25Channel (ISOPackager p, ServerSocket serverSocket) 
087        throws IOException
088    {
089        super(p, serverSocket);
090    }
091    /**
092     * @return a byte array with the received message
093     * @exception IOException on I/O error
094     */
095    protected byte[] streamReceive() throws IOException {
096        int c, k=0, len = 1;
097        Vector v = new Vector();
098
099        c = serverIn.read();
100        if (c == -1)
101            throw new EOFException ("connection closed");
102        byte[] b = new byte[1];
103        b[0] = (byte) c;
104        v.addElement (b);
105
106        // Wait for packets until timeout
107        while ((c = serverIn.available()) > 0) {
108            b = new byte[c];
109            if (serverIn.read (b) != c)
110                throw new EOFException ("connection closed");
111            v.addElement (b);
112            len += c;
113            try {
114                Thread.sleep (50);
115            } catch (InterruptedException e) { }
116        }
117
118        byte[] d = new byte[len];
119        for (int i=0; i<v.size(); i++) {
120            b = (byte[]) v.elementAt(i);
121            System.arraycopy (b, 0, d, k, b.length);
122            k += b.length;
123        }
124        return d;
125    }
126    protected void connect (Socket socket) throws IOException {
127        super.connect (socket);
128        reader = new BufferedReader (new InputStreamReader (serverIn));
129    }
130    public void disconnect () throws IOException {
131        super.disconnect ();
132        reader = null;
133    }
134    protected int getHeaderLength() { 
135        return header != null ? header.length : 0;
136    }
137    public void setHeader (byte[] header) {
138        this.header = header;
139    }
140    /**
141     * @param header Hex representation of header
142     */
143    public void setHeader (String header) {
144        setHeader (
145            ISOUtil.hex2byte (header.getBytes(), 0, header.getBytes().length / 2)
146        );
147    }
148    public byte[] getHeader () {
149        return header;
150    }
151    protected void sendMessageHeader(ISOMsg m, int len) throws IOException { 
152        if (m.getHeader() != null)
153            serverOut.write(m.getHeader());
154        else if (header != null) 
155            serverOut.write(header);
156    }
157}