% % Network programming Lab report source code % % authors: % Χρήστος Χουτουρίδης ΑΕΜ 8997 % cchoutou@ece.auth.gr % Document configuration \newcommand{\ClassName}{Δίκτυα Υπολογιστών Ι} \newcommand{\DocTitle}{Κώδικας εφαρμογής} \newcommand{\InstructorName}{Δημήτριος Μητράκος} \newcommand{\InstructorMail}{mitrakos@eng.auth.gr} \newcommand{\CurrentDate}{\today} \input{AuthReport.tex} %\renewcommand{\AuthorName}{Χρήστος Χουτουρίδης} %\renewcommand{\AuthorMail}{cchoutou@ece.auth.gr} %\renewcommand{\AuthorAEM}{8997} \fancyhead[L]{\ClassName} \fancyhead[R]{Χρήστος Χουτουρίδης 8997} % Document % ================= \begin{document} \FirstPage \tableofcontents \section{Περιγραφή} Για την ανάπτυξη του κώδικα χρησιμοποιήσαμε το περιβάλλον \eng{eclipse} και το \eng{openjdk} στην έκδοση 11. Επειδή η εφαρμογή λειτουργεί ως \eng{command line tool,} χρησιμοποιήσαμε ακόμα το \eng{commons-cli} από \href{http://commons.apache.org/proper/commons-cli/}{\eng{apache commons}} ώς εργαλείο ανάγνωσης των ορισμάτων του χρήστη. Η υλοποίηση της εφαρμογής είναι πολύ απλή. Δεν χρησιμοποιούμε \eng{interfaces} ή κληρονομικότητα. Αντίθετα έχουμε χωρίσει την εφαρμογή σε αυτόνομα αντικείμενα. Τα αντικείμενα \eng{Com} και \eng{Log} παρέχουν τις βασικές λειτουργίες για την επικοινωνία με τον \eng{server} και την έξοδο του προγράμματος αντίστοιχα. Τα αντικείμενα αυτά χρησιμοποιούνται απλώς μέσα υπόλοιπα. Χρησιμοποιούμε δηλαδή την απλούστερη δυνατή τεχνική (\eng{build by composition}). \par Τον κώδικα καθώς και την παραγόμενη τεκμηρίωσή του μέσω \eng{JavaDoc} μπορείτε να την βρείτε στο παραδοτέο αρχείο στους καταλόγους \eng{src} και \eng{doc.} Τέλος στο \href{https://git.hoo2.net/hoo2/virtualModem}{προσωπικό αποθετήριο} του συντάκτη υπάρχει όλος ο κώδικας της εφαρμογής, της εργασίας και της επεξεργασίας των αποτελεσμάτων. Παραθέτουμε παρακάτω τον κώδικα της εφαρμογής σε μορφή !!κειμένου!!, όπως αυτό ζητήθηκε από την εκφώνηση της εργασίας. Το κάθε κεφάλαιο αντιστοιχεί σε ξεχωριστό αρχείο του κώδικα. \selectlanguage{english} \titleformat{\section}[block]{\large\textbf}{\thesection.}{1em}{} \small \section{virtualModem.java} \begin{verbatim} /** * @file VirtualModem.java * @brief * Contain the Main class for the project VirtualModem * * Usage examples: * ========================== * java -jar ./VirtualModem.jar -v -l Exxxx-$(date +%F-%T).log -e Exxxx 600 * java -jar ./VirtualModem.jar -v -l Qxxx-Rxxxx-$(date +%F-%T).log -a Qxxxx Rxxxx 600 * java -jar ./VirtualModem.jar -v -l Pxxxx_600_80_8p-$(date +%F-%T).log -p Pxxxx 600 80 8 P1124-$(date +%F-%T) * java -jar ./VirtualModem.jar -v -l Mxxxx-$(date +%F-%T).log -g Mxxxx Mxxxx-$(date +%F-%T) 2 * java -jar ./VirtualModem.jar -v -l Gxxxx-$(date +%F-%T).log -g Gxxxx Gxxxx-$(date +%F-%T) 2 * * @author Christos Choutouridis AEM:8997 * @email cchoutou@ece.auth.gr */ package net.hoo2.auth.vmodem; /** @name imports */ /** @{ */ import org.apache.commons.cli.*; /** command line utility */ /** @} */ /** * @class VirtualModem * * @brief This is the main control class of the program. * * This class includes the main function which read the user input * and create the appropriate object for the requested sequence to * retrieve data. */ public class VirtualModem { /** @name Data */ /** @{ */ CommandLine line; /** Command line for the argument list */ CommandLineParser parser; /** Parser for the argument list */ Options options; /** Option configuration container */ HelpFormatter formatter; /** An extra helper for -h */ Com com; /** Reference to basic configuration module */ Log log; /** Reference to basic logging module */ /** @} */ /** * @brief The main constructor of the class * We allocate memory for the data needed for the command line */ public VirtualModem () { parser = new DefaultParser(); options = new Options(); formatter = new HelpFormatter(); com = new Com(); // Create argument options and a basic help file // for future use. Option verb = new Option ("v", "verbose", false, "Be more verbose to the console"); Option help = new Option ("h", "help", false, "Print this message"); Option timeout = Option.builder("t") .longOpt("timeout") .hasArg() .valueSeparator('=') .desc("Select timeout in [sec]") .build(); Option speed = Option.builder("s") .longOpt("speed") .hasArg() .valueSeparator('=') .desc("Select speed in [bps]") .build(); Option log = Option.builder("l") .longOpt("log") .hasArg() .desc("Log file name to use") .build(); Option echo = Option.builder("e") .longOpt("echo") .numberOfArgs(2) .desc ("Request echo sequence where = <1> <2>\n" + " <1>: The echo requested code from virtual lab\n" + " <2>: The time duration of the session [sec]") .build(); Option arq = Option.builder("a") .longOpt("arq") .numberOfArgs(3) .desc ("Request arq sequence where = <1> <2> <3>\n" + " <1>: The ACK requested code for virtual lab\n" + " <2>: The NACK requested code from virtual lab\n" + " <2>: The time duration for the session [sec]") .build(); Option img = Option.builder("g") .longOpt("img") .numberOfArgs(3) .desc("Request an image sequence where = <1> <2> <3>\n" + " <1>: The image requested code from virtual lab\n" + " <2>: The filename to use for storing the image (without .jpg)\n" + " <3>: The requested images to fetch.") .build(); Option gps = Option.builder("p") .longOpt("gps") .numberOfArgs(5) // G8164 10 800 8 gps_10_800 .desc("Request a GPS sequence where = <1> <2> <3> <4>\n" + " <1>: The gps requested code from virtual lab\n" + " <2>: The time from trace to use as starting point [sec]\n" + " <3>: The time duration for the trace to fetch [sec]\n" + " <4>: The number of points to fetch from the above trace\n" + " <5>: The filename to use for storing the image (without .jpg)") .build(); options.addOption(verb); options.addOption(help); options.addOption(timeout); options.addOption(speed); options.addOption(log); options.addOption(echo); options.addOption(arq); options.addOption(img); options.addOption(gps); } /** @name private api */ /**@{*/ /** * parse the command line arguments * @param args the arguments to parse * @return the status of the operation */ private boolean getCmdOptions (String[] args) { try { // parse the command line arguments line = parser.parse (options, args); } catch( ParseException exp ) { // oops, something went wrong System.err.println( "Parsing command line failed: " + exp.getMessage() ); return false; } return true; } /** * Dispatch the correct functionality based on arguments * @return the status of the operation (currently true) */ private boolean commandDispatcher () { boolean verbose = false; if (line.hasOption("help")) { formatter.printHelp( "virtualModem", options ); return true; } // Get log and verbose options first if (line.hasOption("verbose")) verbose = true; if (line.hasOption("log")) log = new Log (line.getOptionValue("log"), verbose); else log = new Log (null, verbose); if (log.open() != true) return false; // get other options if (line.hasOption("timeout")) { com.timeout(Integer.parseInt(line.getOptionValue("timeout"))); } if (line.hasOption("speed")) { com.speed(Integer.parseInt(line.getOptionValue("speed"))); } // Execution dispatcher if (line.hasOption("echo")) { byte[] code = line.getOptionValues("echo")[0].getBytes(); Echo e = new Echo(com, log, code, Integer.valueOf(line.getOptionValues("echo")[1])); if (com.open()) { e.caption(code); e.run(); com.close(); } } else if (line.hasOption("arq")) { byte[] ack = line.getOptionValues("arq")[0].getBytes(); byte[] nack = line.getOptionValues("arq")[1].getBytes(); ARQ a = new ARQ(com, log, ack, nack, Integer.valueOf(line.getOptionValues("arq")[2])); if (com.open()) { a.caption(ack, nack); a.run(); com.close(); } } else if (line.hasOption("img")) { byte[] code = line.getOptionValues("img")[0].getBytes(); Image im = new Image (com, log, code, line.getOptionValues("img")[1], Integer.valueOf(line.getOptionValues("img")[2])); if (com.open()) { im.caption(code); im.run(); com.close(); } } else if (line.hasOption("gps")) { byte[] code = line.getOptionValues("gps")[0].getBytes(); GPS g = new GPS ( com, log, code, Integer.valueOf(line.getOptionValues("gps")[1]), Integer.valueOf(line.getOptionValues("gps")[2]), Integer.valueOf(line.getOptionValues("gps")[3]) ); Image im = new Image ( com, log, null, line.getOptionValues("gps")[4], 1 ); if (com.open()) { g.caption(); im.code(g.run().getBytes()); im.run(); com.close(); } } log.close(); return true; } /**@}*/ /** * @brief Main function */ public static void main(String[] args) { // allocate the main object VirtualModem vmodem = new VirtualModem(); // prepare command line input if (vmodem.getCmdOptions (args) != true) return; // Call the requested functionality if (vmodem.commandDispatcher() != true) return; } } \end{verbatim} \section{Com.java} \begin{verbatim} /** * @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= src.length) { for (int i=0 ; i1) file = filename_ + "_" + i + ".jpg"; else file = filename_ + ".jpg"; line = new String(code_) + ": "; log_.write(line); transaction_ = com_.request(transaction_, code_, IMAGE_BEGIN, IMAGE_END, true); line = "File= " + file + " Tr= " + (transaction_.arrival - transaction_.departure) + " [msec]" + " Tt= " + (System.currentTimeMillis() - transaction_.departure) + " [msec]"; log_.write(line); try { ostream = new BufferedOutputStream(new FileOutputStream(file)); ostream.write(transaction_.response); ostream.flush(); ostream.close(); } catch (Exception exp) { System.err.println ("Error creating " + file + exp.getMessage()); return; } } } } \end{verbatim} \end{document}