|
- /**
- * @file Com.java
- *
- * @author Christos Choutouridis AEM:8997
- * @email cchoutou@ece.auth.gr
- */
- package net.hoo2.auth.vmodem;
-
- /** @name imports */
- /** @{ */
- import java.util.Arrays;
- import ithakimodem.*;
- /** @} */
-
- /**
- * @class Com
- *
- * Wrapper object of the provided Modem class to provide
- * a convenient and common API for all the session functionalities
- */
- class Com {
- static final int SPEED_DEFAULT = 48000; /**< default communication speed [bps] */
- static final int TIMEOUT_DEFAULT = 2000; /**< default timeout values [sec] */
- static final String URL_DEFAULT = "ithaki"; /**< Default destination. Ithaki of-course */
-
- private Modem modem_; /**< Ref to Modem */
- private int speed_; /**< Communication speed [bps] */
- private int timeout_; /**< communication timeout [sec] */
-
- /**
- * Basic constructor
- */
- Com () {
- modem_ = new Modem();
- speed_ = SPEED_DEFAULT;
- timeout_ = TIMEOUT_DEFAULT;
- modem_.setSpeed(speed_);
- modem_.setTimeout(timeout_);
- }
- /** A more fancy constructor
- *
- * @param log Reference to Log to use
- * @param speed The desired speed [bps]
- * @param timeout The desired timeout [sec]
- * @note
- * Currently not used
- */
- Com (Log log, int speed, int timeout) {
- modem_ = new Modem();
- speed_ = speed;
- timeout_ = timeout;
- modem_.setSpeed(speed_);
- modem_.setTimeout(timeout_);
- }
-
- /** @name Mutator interface */
- /**@{ */
- /** Get the current timeout value [sec] */
- int timeout () { return timeout_; }
- /** Set the timeout value [sec] */
- void timeout (int timeout) {
- if (timeout_ != timeout) {
- timeout_ = timeout;
- modem_.setTimeout(timeout_);
- }
- }
- /** Get the current speed [bps] */
- int speed () { return speed_; }
- /** Set the speed [bps] */
- void speed (int speed) {
- if (speed_ != speed) {
- speed_ = speed;
- modem_.setSpeed(speed_);
- }
- }
- /**@} */
-
- /** @name Public API of the class */
- /**@{ */
- /** Open a communication channel with a URL */
- boolean open (String url) { return modem_.open(url); }
- /** Open a communication channel with Ithaki */
- boolean open () { return modem_.open(URL_DEFAULT); }
- /** Close the connection */
- boolean close() { return modem_.close(); }
-
- /**
- * @grief The basic communication functionality
- *
- * This function sends a request to server and return the response. In order to
- * do that, the main reading loop seeks for the starting pattern and use the data
- * from that point up to the ending pattern. This is very helpful for binary incoming
- * data.
- * @note
- * Blocking mode
- * @param data Reference to Transaction data to use @see Transaction
- * @param code The request code to send
- * @param begin The starting pattern of the response data
- * @param end The ending pattern of the response data
- * @param bin A flag to indicate that the data are in binary form
- * @return Reference to Transaction object with the response data. @see Transaction
- */
- Transaction request (Transaction data, byte[] code, byte[] begin, byte[] end, boolean bin) {
- int ch =0;
- boolean have_begin = (begin != null) ? false : true;
- boolean incoming = false;
-
- // Clear the receive buffer first
- _clear (data.response, 0, data.response.length);
- if (code != null) {
- // if we have a request
- data.code = code; // store the request code for the transaction
- modem_.write(data.code); // send the code and mark the time
- modem_.write((int)'\r');
- data.departure = System.currentTimeMillis();// - (long)((8*(data.code.length+1))*(1000.0/speed_));
- }
-
- // main receive loop
- data.size =0;
- do {
- // escape guard for memory protection
- if (data.size >= data.response.length) {
- data.size =0;
- return data;
- }
- // read the data byte from server
- try {
- ch = modem_.read();
- }
- catch (Exception e) {
- // Oops!!!! something went wrong. Break and return :(
- System.err.println (e.getMessage());
- data.size =0;
- return data;
- }
- if (!incoming) {
- // first byte triggered. mark the time
- incoming = true;
- data.arrival = System.currentTimeMillis();// - (long)(8*(1000.0/speed_));
- }
- data.response [data.size++] = (byte)ch; // store the byte
-
- if (!have_begin && (detect(data.response, begin, data.size) != -1)) {
- // If begin pattern detected, start over.
- _clear(data.response, 0, data.size);
- data.size = _copy (data.response, begin);
- have_begin = true;
- }
- } while (ch != -1 &&
- (!have_begin ||
- ( (bin || (detect (data.response, "\r\n\n\n".getBytes(), data.size) == -1))
- && (bin || (detect (data.response, "NO CARRIER".getBytes(), data.size) == -1))
- && (detect (data.response, end, data.size) == -1)
- )
- )
- );
- /*^
- * We loop until:
- * 1) server returns -1
- * 2) A end pattern arrives
- * 3) A "\r\n\n\n" sequence arrives (in character mode, not for binary files)
- * 4) A "NO CARRIER" sequence arrives (in character mode, not for binary files)
- */
- return data;
- }
-
- /**
- * @brief
- * A pattern detect functionality.
- *
- * Search in data input for the pattern and return its position if found.
- * @note
- * O(n^2) in time.
- * @param data The data buffer to search into
- * @param pattern The pattern to search for
- * @param max The maximum length to search
- * @return The position of pattern in data, or -1 if not found
- */
- static int detect (byte[] data, byte[] pattern, int max) {
- if (pattern != null) {
- for (int i =0 ; i<max && i<data.length - pattern.length; ++i) {
- boolean detected = true;
- for (int j=0 ; j<pattern.length ; ++j) {
- if (data[i+j] != pattern[j]) {
- detected = false;
- break;
- }
- }
- if (detected)
- return i;
- }
- }
- return -1;
- }
- /**@} */
-
- /** @name Private helper api */
- /**@{*/
- /**
- * Clear a buffer segment
- * @param buffer Buffer to clear
- * @param begin The starting point
- * @param end The ending point
- */
- private void _clear (byte[] buffer, int begin, int end) {
- for (int i=begin ; i<end && i<buffer.length ; ++i)
- buffer[i] = 0;
- }
-
- /**
- * Copy a buffer to another
- * @param dest The destination buffer
- * @param src The source buffer
- * @return The number of bytes copied
- */
- private int _copy (byte[] dest, byte[] src) {
- if (dest.length >= src.length) {
- for (int i=0 ; i<src.length ; ++i)
- dest[i] = src[i];
- return src.length;
- }
- return 0;
- }
- /**@}*/
- }
-
- /**
- * @class
- * Class to represent client-server transaction data
- */
- class Transaction {
- byte[] code; /**< request code from client */
- byte[] response; /**< response data from server */
- long departure; /**< request time */
- long arrival; /**< response time */
- int size; /**< size of response data in bytes */
-
- /**
- * Basic constructor
- * @param code Code to use
- * @param response Response buffer to use
- */
- Transaction (byte[] code, byte[] response) {
- this.code = code;
- this.response = response;
- departure = arrival = 0;
- size = 0;
- }
-
- /**
- * Get a copy of the response
- */
- byte[] getResponse() {
- return Arrays.copyOf(response, size);
- }
- }
-
|