Source code: mas_gui/Connection.java
1 /* Copyright 1998 - 2003: Jim Cochrane - see file forum.txt */
2
3 package mas_gui;
4
5 import java.io.*;
6 import java.net.*;
7 import java.util.*;
8 import common.*;
9 import support.*;
10 import mas_gui.*;
11
12 /** Provides an interface for connecting and communicating with the server */
13 public class Connection implements NetworkProtocol
14 {
15 // args[0]: hostname, args[1]: port_number
16 public Connection(String hostname, Integer port_number) {
17 _hostname = hostname;
18 _port_number = port_number;
19 scanner = new DataInspector();
20 }
21
22 // The host name of the server
23 public String hostname() { return _hostname; }
24
25 // The port number for the server connection
26 public Integer port_number() { return _port_number; }
27
28 // Session state data received from the server when logging in.
29 public SessionState session_state() {
30 return _session_state;
31 }
32
33 // Is this connection currently logged in to the server?
34 public boolean logged_in() { return _logged_in; }
35
36 // Log in to the server with the specified login request code.
37 // Precondition: ! logged_in()
38 // Postcondition: logged_in() && session_state() != null
39 public void login() throws IOException {
40 String s = "";
41 Configuration conf = Configuration.instance();
42
43 connect();
44 send_msg(Login_request, conf.session_settings(), 0);
45 try {
46 s = receive_msg().toString();
47 if (error_occurred()) {
48 // Failure of login request is a fatal error.
49 throw new IOException (request_result.toString());
50 }
51 _session_state = new SessionState(s);
52 }
53 catch (Exception e) {
54 throw new IOException("Attempt to login to server " +
55 "failed: " + e);
56 }
57 try {
58 close_connection();
59 }
60 catch (Exception e) {
61 throw new IOException("Close connection failed");
62 }
63 _logged_in = true;
64 }
65
66 // Send a logout request to the server to end the current session.
67 // Precondition: logged_in()
68 public void logout() throws IOException {
69 connect();
70 send_msg(Logout_request, "", _session_state.session_key());
71 try {
72 close_connection();
73 }
74 catch (Exception e) {
75 throw new IOException("Error: close connection failed" + e);
76 }
77 }
78
79 // Send a request to the server.
80 // Precondition: logged_in()
81 // Postcondition: `result' gives the data resulting from this request.
82 public void send_request(int request_code, String request)
83 throws IOException {
84 connect();
85 send_msg(request_code, request, _session_state.session_key());
86 receive_msg();
87 close_connection();
88 }
89
90 // The data resulting from the last call to `send_request'
91 public StringBuffer result() {
92 return request_result;
93 }
94
95 // Last message ID received back from the server
96 public int last_received_message_ID() {
97 return last_rec_msgID;
98 }
99
100 // Implementation
101
102 // Receive the current pending message from the server.
103 protected StringBuffer receive_msg() throws IOException {
104 final int Max_input_count = 1000000;
105 char c;
106 int i;
107
108 in = new_reader_from_socket();
109 scanner.setReader(in);
110 scanner.getInt();
111 last_rec_msgID = scanner.lastInt();
112 if (! valid_server_response(last_rec_msgID)) {
113 System.err.println("Fatal error: received invalid " +
114 "message ID from server: " + last_rec_msgID);
115 System.exit(-1);
116 } else {
117 request_result = new StringBuffer();
118 }
119 i = 0;
120 do {
121 c = (char) in.read();
122 if (c == Eom_char) break;
123 request_result.append(c);
124 ++i;
125 if (i > Max_input_count) {
126 message_too_large(Max_input_count);
127 }
128 } while (true);
129
130 if (last_rec_msgID == Error) {
131 System.err.println(request_result);
132 // This error means there is a problem with the protocol of the
133 // last request passed to the server. Since this is a coding
134 // error (probably in the client), it is treated as fatal.
135 System.exit(-1);
136 }
137 //System.out.println("'" + request_result.toString() + "'");
138 return request_result;
139 }
140
141 // Send the `msgID', the session key, and `msg' - with field delimiters.
142 void send_msg(int msgID, String msg, int session_key) {
143 out.print(msgID);
144 out.print(Input_field_separator + session_key);
145 out.print(Input_field_separator + msg);
146 out.print(Eom);
147 out.flush();
148 }
149
150 // Precondition: out != null && socket != null
151 void close_connection() throws IOException {
152 out.close(); socket.close();
153 if (in != null) {
154 in.close();
155 }
156 }
157
158 private void connect() throws IOException {
159 try {
160 //It appears that the only way to connect a client socket is
161 //to create a new one!
162 socket = new Socket(_hostname, _port_number.intValue());
163 out = new PrintWriter(socket.getOutputStream(), true);
164 in = null;
165 }
166 catch (UnknownHostException e) {
167 throw new UnknownHostException("Don't know about host: " +
168 _hostname);
169 }
170 catch (IOException e) {
171 throw new IOException("Couldn't get I/O for the connection to: " +
172 _hostname);
173 }
174 }
175
176 boolean error_occurred() {
177 return last_rec_msgID != OK;
178 }
179
180 // A new Reader object created with socket's input stream
181 protected Reader new_reader_from_socket() {
182 //System.out.println("\nnot decompressing");
183 Reader result = null;
184 try {
185 result = new BufferedReader(new InputStreamReader(
186 new BufferedInputStream(socket.getInputStream())));
187 } catch (Exception e) {
188 System.err.println("Failed to read from server (" + e + ")");
189 System.exit(1);
190 }
191 return result;
192 }
193
194 // Handle message- (from server) too-large situation.
195 void message_too_large(int size) {
196 System.err.println("Message from server exceeded maximum " +
197 "buffer size of " + size + " - aborting");
198 System.exit(-1);
199 }
200
201 // Is `value' a valid server response?
202 boolean valid_server_response(int value) {
203 return value == OK || value == Error || value == Invalid_symbol ||
204 value == Warning;
205 }
206
207 protected SessionState _session_state;
208 protected boolean _logged_in = false;
209 protected String _hostname;
210 protected Integer _port_number;
211 protected Socket socket; // socket connection to server
212 protected PrintWriter out; // output to server via socket
213 protected Reader in; // input from server via socket
214 protected DataInspector scanner; // for scanning server messages
215 protected int last_rec_msgID; // last message ID received from server
216 protected StringBuffer request_result; // result of last data request
217 static int Eom_char = Eom.charAt(0);
218 }