Source code: rcs/nml/NMLConnection.java
1 package rcs.nml;
2
3
4 import java.net.*;
5 import java.io.*;
6 import java.util.*;
7 import rcs.utils.*;
8 import rcs.nml.NMLFormatConverter;
9 import rcs.nml.NMLFormatConverterBase;
10 import rcs.nml.XDRFormatConverter;
11 import rcs.nml.DISPFormatConverter;
12 import rcs.utils.jcrypt;
13 import rcs.utils.URL_and_FileLoader;
14 import rcs.nml.NMLException;
15
16 class NMLBufferConfigInfo
17 {
18 String buffer_name = null;
19 String buffer_line = null;
20 Hashtable process_lines = new Hashtable();
21 };
22
23 class NMLConfigInfo
24 {
25 String file_name = null;
26 Hashtable buffer_configurations = new Hashtable();
27 //Vector lines_vector;
28 URL_and_FileLoader loader = null;
29 // int lines_read = 0;
30 }
31
32 /**
33 * Class for connecting to NML buffers, ussually via network sockets.<br>
34 * <pre>
35 * Related Documentation:
36 * <A HREF="http://isd.cme.nist.gov/proj/rcs_lib">RCS Library</a>, <A HREF="http://isd.cme.nist.gov/proj/rcs_lib/NMLjava.html">NML Programmers Guide (Java Version)</a>
37 *
38 * Source Code:
39 * <A HREF="NMLConnection.java">NMLConnection.java</a>
40 *
41 * </pre>
42 *
43 * @author Will Shackleford -- <A HREF="mailto:shackle@cme.nist.gov">shackle@cme.nist.gov</a>
44 *
45 */
46 public class NMLConnection
47 {
48 static protected Hashtable previously_read_nml_configurations = null;
49
50 /**
51 * This variable can be set to true by some other thread to
52 * stop the login.
53 *
54 * @see rcs.nml.NMLConnection#login(java.lang.String,java.lang.String)
55 */
56 public static boolean interrupt_login = false;
57
58 protected NMLFormatConverterBase format_converter = null;
59 protected NMLMessageDictionary message_dictionary = null;
60 public String BufferLine = null;
61
62 // Protocol Options
63 protected static final int NML_STCP_PROTOCOL_TYPE = 1;
64 protected static final int NML_TCP_PROTOCOL_TYPE = 2;
65 protected static final int NML_UDP_PROTOCOL_TYPE = 3;
66 public int protocol_option = NML_STCP_PROTOCOL_TYPE;
67
68 // Data format Options
69 protected static final int NML_ASCII_ENCODING_TYPE = 4;
70 protected static final int NML_DISP_ENCODING_TYPE = 5;
71 protected static final int NML_XDR_ENCODING_TYPE = 6;
72 private int data_format_option =NML_DISP_ENCODING_TYPE;
73
74
75 private int serial_number = 0;
76 private int last_id_read = 0;
77 private int max_tries = 20;
78
79 // REMOTE_CMS_REQUEST_TYPE's
80 protected static final int REMOTE_CMS_READ_REQUEST_TYPE = 1;
81 protected static final int REMOTE_CMS_WRITE_REQUEST_TYPE = 2;
82 protected static final int REMOTE_CMS_GET_KEYS_REQUEST_TYPE = 7;
83 protected static final int REMOTE_CMS_LOGIN_REQUEST_TYPE = 8;
84 protected static final int REMOTE_CMS_SET_SUBSCRIPTION_REQUEST_TYPE = 9;
85 protected static final int REMOTE_CMS_READ_COMBINED_REQUEST_TYPE =10;
86 protected static final int REMOTE_CMS_BLOCKING_READ_REQUEST_TYPE =11;
87 protected static final int REMOTE_CMS_GET_BUF_NAME_REQUEST_TYPE=12;
88 protected static final int REMOTE_CMS_CANCEL_SUBSCRIPTION_REQUEST_TYPE=13;
89 protected static final int REMOTE_CMS_SET_DIAG_INFO_REQUEST_TYPE=14;
90 protected static final int REMOTE_CMS_GET_DIAG_INFO_REQUEST_TYPE=15;
91 protected static final int REMOTE_CMS_GET_MSG_COUNT_REQUEST_TYPE=16;
92
93 private int request_type = REMOTE_CMS_READ_REQUEST_TYPE;
94
95 // CMS_REMOTE_SUBSCRIPTION_REQUEST_TYPE's
96 public static final int CMS_POLLED_SUBSCRIPTION = 1;
97 public static final int CMS_NO_SUBSCRIPTION =2;
98 public static final int CMS_VARIABLE_SUBSCRIPTION =3;
99
100 // CMS_INTERNAL_ACCESS_TYPE's
101 protected static final int CMS_READ_ACCESS = 1;
102 protected static final int CMS_CHECK_IF_READ_ACCESS = 2;
103 protected static final int CMS_PEEK_ACCESS = 3;
104 protected static final int CMS_WRITE_ACCESS = 4;
105 protected static final int CMS_WRITE_IF_READ_ACCESS = 5;
106 private int access_type = CMS_READ_ACCESS;
107 private int remote_status = 0;
108 private int message_size = 0;
109 private int was_read = 0;
110 private int input_bytes_read = 0;
111 private boolean reply_header_received = false;
112 private boolean write_reply_received = true;
113 private boolean input_buffer_ready = false;
114 protected int output_data_size = 0;
115 public double min_compatible_version = 0.0;
116 public boolean confirm_write = false;
117 public boolean use_subscription=false;
118 public int subscription_id = 0;
119 public double subscription_period = 0.0;
120 public boolean poll = false;
121 public static boolean default_poll_state = false;
122 public boolean diag_enabled=false;
123 public int connection_number=0;
124
125 protected NMLmsg last_msg_read = null;
126 /**
127 * Set config_debug_on to true to print out additional information
128 * while reading the NML Congiguration file.
129 */
130 static public boolean config_debug_on = false;
131 /**
132 * Set read_debug_on to true to print out additional information
133 * while reading.
134 */
135 static public boolean read_debug_on = false;
136 /**
137 * Set write_debug_on to true to print out additional information
138 * while writing.
139 */
140 static public boolean write_debug_on = false;
141 private String input_string = "";
142
143 /**
144 * Name of buffer to connect to. (used in configuration file)
145 */
146 public String buffer_name = null;
147
148 /**
149 * Name of this process as used in configuration file.
150 */
151 public String process_name = null;
152
153
154 /**
155 * Name/URL the configuration file to read.
156 */
157 public String configuration_file = null;
158 private int input_buffer_offset = 0;
159 private int input_bytes_ready = 0;
160 private byte input_buffer[];
161 private byte output_buffer[];
162
163 private static final int NML_DEFAULT_BUFFER_SIZE=2048;
164 private int buffer_size;
165 /**
166 * TCP port of NML server.
167 */
168 public int port = 0;
169 /**
170 * buffer_number from NML configuration file.
171 */
172 public int buffer_number = 0;
173
174 /**
175 * name of the computer the NML server runs on.
176 */
177 public String host = "";
178 protected boolean read_request_sent = false;
179 private boolean null_error_reported = false;
180 private DataInputStream m_InputStream = null;
181 private DataOutputStream m_OutputStream = null;
182 private Socket m_Socket = null;
183 private NonBlockingDatagramSocket udpSocket = null;
184 private InetAddress udpServerAddress = null;
185 private ByteArrayOutputStream baOutputStream = null;
186 private ByteArrayInputStream baInputStream = null;
187 private DatagramPacket udpInputPacket = null;
188 private long udpRetryTimeoutMillis = 30;
189 private long lastUdpRequestTime = 0;
190 private int broadcast_port = 0;
191
192
193 /**
194 * True when this object is connected to the NML server.
195 * All reads and writes will fail when this is false.
196 */
197 public boolean connected = false;
198
199
200 /**
201 * This constructs an NMLConnection which will not work until
202 * the host and port are set manually or
203 * by reading the NML configuration file with ReadNMLConfigurationFile().
204 * Most users should use the other constructor with several parameters.
205 *
206 * @see rcs.nml.NMLConnection#NMLConnection(rcs.nml.NMLMessageDictionary, java.lang.String, java.lang.String, java.lang.String)
207 * @see rcs.nml.NMLConnection#ReadNMLConfigurationFile(java.lang.String, java.lang.String, java.lang.String)
208 *
209 */
210 public NMLConnection()
211 {
212 // System.out.print("\r\nconstructing NMLConnection\r\n");
213 try
214 {
215 input_buffer = new byte[NML_DEFAULT_BUFFER_SIZE];
216 output_buffer = new byte[NML_DEFAULT_BUFFER_SIZE];
217 buffer_size = NML_DEFAULT_BUFFER_SIZE;
218 interrupt_login = false;
219 poll = default_poll_state;
220 SetFormatConverter(new XDRFormatConverter());
221 }
222 catch(Exception e)
223 {
224 e.printStackTrace();
225 }
226 }
227
228 /**
229 * This functions sets the NMLMessageDictionary for this connection.
230 * The purpose of the NMLMessageDictionary is to provide a means
231 * for the NMLConnection to determine the structure of messages being
232 * sent or received using a message type. (An integer passed within
233 * all NML messages.)
234 *
235 * @param new_dict the NMLMessageDictionary for this NMLConnection to use.
236 * @see rcs.nml.NMLMessageDictionary
237 */
238 public void SetMessageDictionary(NMLMessageDictionary new_dict) throws NMLException
239 {
240 message_dictionary = new_dict;
241 if(null != format_converter)
242 {
243 format_converter.SetMessageDictionary(new_dict);
244 }
245 }
246
247 /**
248 * This functions gets the NMLMessageDictionary for this connection.
249 *
250 * @return the implementation of NMLMessageDictionary used by this
251 * NMLConnection
252 *
253 * @see rcs.nml.NMLConnection#SetMessageDictionary(rcs.nml.NMLMessageDictionary)
254 * @see rcs.nml.NMLMessageDictionary
255 */
256 public NMLMessageDictionary GetMessageDictionary() throws NMLException
257 {
258 if(null != format_converter)
259 {
260 message_dictionary = format_converter.GetMessageDictionary();
261 }
262 return message_dictionary;
263 }
264
265
266 /**
267 * This functions sets the NMLFormatConverter for this connection.
268 * The NMLFormatConverter is resposible for converting each of
269 * the basic data types to some neutral format that can be
270 * used on many different platforms. Most users should either accept
271 * the default (XDRFormatConverter) or allow the format to be specified
272 * in the NML configuration file rather than calling this function
273 * directly.
274 *
275 * @param new_fc the NMLFormatConverter for this Connection to use.
276 *
277 * @see rcs.nml.NMLFormatConverter
278 */
279 public void SetFormatConverter(NMLFormatConverter new_fc) throws NMLException
280 {
281 try
282 {
283 format_converter = (NMLFormatConverterBase) new_fc;
284 }
285 catch(ClassCastException e)
286 {
287 System.err.println("This NMLFormatConverter is not a subclass of NMLFormatConverterBase.");
288 e.printStackTrace();
289 throw new NMLException("This NMLFormatConverter is not a subclass of NMLFormatConverterBase.",buffer_name, configuration_file,e);
290 }
291 if(null != message_dictionary && null != format_converter)
292 {
293 format_converter.SetMessageDictionary(message_dictionary);
294 }
295 }
296
297 /**
298 * This functions gets the NMLFormatConverter for this connection.
299 *
300 * @return the NMLFormatConverter for this connection
301 *
302 * @see rcs.nml.NMLConnection#SetFormatConverter(rcs.nml.NMLFormatConverter)
303 */
304 public NMLFormatConverter GetFormatConverter() throws NMLException
305 {
306 return format_converter;
307 }
308
309
310 /**
311 * This constuctor creates a fully functional NML Connection
312 * using the application defined NMLMessageDictionary, read
313 * the NML configuration file, and connects immediately.
314 * This is the constructor most users should use.
315 *
316 * @param msg_dict the NMLMessageDictionary for this connection to use (the NMLMessageDictionary allows this Connection to determine the message structure from the message type)
317 * @param BufferName the name of the buffer to connect to, (must match one of the buffers in the configuration file.)
318 * @param ProcessName the name of the process that will use this connection (must match one of the process names in the configuration file)
319 * @param ConfigurationFile the file name or URL of an NML configuration file (URL's should either be complete, or they can be relative to
320 rcs.utils.URL_and_FileLoader.current_directory)
321 * @exception rcs.nml.NMLException
322 * If the configuration file can not be read, the file is improperly formatted or the buffer or process can
323 * can not be found in it.
324 *
325 */
326 public NMLConnection(NMLMessageDictionary msg_dict, String BufferName, String ProcessName, String ConfigurationFile) throws NMLException
327 {
328 this();
329 ReadNMLConfigurationFile(BufferName, ProcessName, ConfigurationFile);
330 SetMessageDictionary(msg_dict);
331 }
332
333
334 /**
335 * This function reads configuration information from the NML configuration file.
336 *
337 * @param BufferName the name of the buffer to connect to, (must match one of the buffers in the configuration file.)
338 * @param ProcessName the name of the process that will use this connection (must match one of the process names in the configuration file)
339 * @param ConfigurationFile the file name or URL of an NML configuration file (URL's should either be complete, or they can be relative to
340 rcs.utils.URL_and_FileLoader.current_directory)
341 * @exception rcs.nml.NMLException
342 * If the configuration file can not be read, the file is improperly formatted or the buffer or process can
343 * can not be found in it.
344 *
345 */
346 public void ReadNMLConfigurationFile(String BufferName, String ProcessName, String ConfigurationFile) throws NMLException
347 {
348 buffer_name = BufferName;
349 process_name = ProcessName;
350 configuration_file = ConfigurationFile;
351 ReadNMLConfigurationFile();
352 connect();
353 }
354
355 /**
356 * Clear any data saved from previously read configuration files.
357 */
358 public static void ClearStaticData()
359 {
360 previously_read_nml_configurations = null;
361 }
362
363 protected void LoadConfigurationFileData(String configuration_file) throws Exception
364 {
365 NMLConfigInfo config_info = new NMLConfigInfo();
366 NMLBufferConfigInfo bufferConfigInfo = null;
367 config_info.file_name= configuration_file;
368 URL_and_FileLoader loader = null;
369 String current_line = null;
370 String buffer_name = null;
371 String process_name = null;
372 loader = new URL_and_FileLoader(configuration_file);
373 while(true)
374 {
375 current_line = loader.readLine();
376 if(current_line == null)
377 {
378 break;
379 }
380 if(config_debug_on)
381 {
382 System.out.println(current_line);
383 }
384 if(current_line.length() < 3)
385 {
386 continue;
387 }
388 if(current_line.startsWith("#"))
389 {
390 continue;
391 }
392 if(current_line.startsWith("B"))
393 {
394 StringTokenizer tokenizer = new StringTokenizer(current_line," \t");
395 if(null == tokenizer)
396 {
397 continue;
398 }
399 int token_number = 0;
400 while(tokenizer.hasMoreTokens())
401 {
402 String token = tokenizer.nextToken();
403 if(null == token)
404 {
405 break;
406 }
407 if(config_debug_on)
408 {
409 System.out.println("token "+token_number+" = "+token);
410 }
411 if(token_number == 1)
412 {
413 buffer_name = token;
414 bufferConfigInfo = (NMLBufferConfigInfo) config_info.buffer_configurations.get(buffer_name);
415 if(bufferConfigInfo == null)
416 {
417 bufferConfigInfo = new NMLBufferConfigInfo();
418 bufferConfigInfo.buffer_name = buffer_name;
419 bufferConfigInfo.buffer_line = current_line;
420 config_info.buffer_configurations.put(buffer_name,bufferConfigInfo);
421 }
422 else
423 {
424 if(null == bufferConfigInfo.buffer_line)
425 {
426 bufferConfigInfo.buffer_line = current_line;
427 }
428 }
429 break;
430 }
431 token_number++;
432 }
433 }
434 if(current_line.startsWith("P"))
435 {
436 StringTokenizer tokenizer = new StringTokenizer(current_line," \t");
437 if(null == tokenizer)
438 {
439 continue;
440 }
441 int token_number = 0;
442 while(tokenizer.hasMoreTokens())
443 {
444 String token = tokenizer.nextToken();
445 if(null == token)
446 {
447 break;
448 }
449 if(config_debug_on)
450 {
451 System.out.println("token "+token_number+" = "+token);
452 }
453 if(token_number == 1)
454 {
455 process_name = token;
456 }
457 if(token_number == 2)
458 {
459 buffer_name = token;
460 bufferConfigInfo = (NMLBufferConfigInfo) config_info.buffer_configurations.get(buffer_name);
461 if(bufferConfigInfo == null)
462 {
463 bufferConfigInfo = new NMLBufferConfigInfo();
464 bufferConfigInfo.buffer_name = buffer_name;
465 config_info.buffer_configurations.put(buffer_name,bufferConfigInfo);
466 }
467 bufferConfigInfo.process_lines.put(process_name, current_line);
468 break;
469 }
470 token_number++;
471 }
472 }
473 }
474 previously_read_nml_configurations.put(configuration_file,config_info);
475 }
476
477 /**
478 * Read preset configuration file.
479 * @exception rcs.nml.NMLException
480 * If the configuration file can not be read, the file is improperly formatted or the buffer or process can
481 * can not be found in it.
482 */
483 public void ReadNMLConfigurationFile() throws NMLException
484 {
485 String current_line = null;
486 boolean BufferLineFound = false;
487 boolean ProcessLineFound = false;
488 boolean ConfigurationFileRead = false;
489 NMLConfigInfo config_info = null;
490 int lines_parsed = 0;
491 try
492 {
493 if(config_debug_on)
494 {
495 System.out.println("ReadNMLConfigurationFile(): buffer_name = "+buffer_name+", process_name = "+process_name+", configuration_file = "+configuration_file+",");
496 }
497
498
499 if(null == previously_read_nml_configurations)
500 {
501 previously_read_nml_configurations = new Hashtable();
502 }
503 else
504 {
505 config_info = (NMLConfigInfo) previously_read_nml_configurations.get(configuration_file);
506 }
507
508 boolean buffer_line_in_hashtable = false;
509 if(null == config_info)
510 {
511 LoadConfigurationFileData(configuration_file);
512 config_info = (NMLConfigInfo) previously_read_nml_configurations.get(configuration_file);
513 }
514
515 NMLBufferConfigInfo buf_info = (NMLBufferConfigInfo) config_info.buffer_configurations.get(buffer_name);
516 if(null == buf_info)
517 {
518 throw new NMLException("Can't find buffer line.", buffer_name, configuration_file);
519 }
520 String buffer_line = buf_info.buffer_line;
521 String process_line = (String) buf_info.process_lines.get(process_name);
522
523 data_format_option =NML_XDR_ENCODING_TYPE;
524 ConfigurationFileRead = true;
525 if(config_debug_on)
526 {
527 System.out.println("buffer_line="+buffer_line);
528 System.out.println("process_line="+process_line);
529 }
530 if(null != process_line)
531 {
532 current_line = process_line;
533 if(current_line.startsWith("P"))
534 {
535 StringTokenizer tokenizer = new StringTokenizer(current_line," \t");
536 int token_number = 0;
537 while(tokenizer.hasMoreTokens() && token_number < 10)
538 {
539 String token = tokenizer.nextToken();
540 if(config_debug_on)
541 {
542 System.out.println("token "+token_number+" = "+token);
543 }
544 if(token_number == 1 && !token.equals(process_name))
545 {
546 break;
547 }
548 if(token_number == 2 && token.equals(buffer_name))
549 {
550 ProcessLineFound = true;
551 }
552 if(token_number == 7 && ProcessLineFound)
553 {
554 try
555 {
556 double timeout_d = Double.valueOf(token).doubleValue();
557 if(timeout_d > 0.01)
558 {
559 max_tries = (int) (timeout_d * 100.0);
560 }
561 else
562 {
563 max_tries = 1;
564 poll = true;
565 }
566 }
567 catch(Exception e)
568 {
569 }
570 if(token.toUpperCase().startsWith("INF"))
571 {
572 max_tries = -1;
573 }
574 if(config_debug_on)
575 {
576 System.out.println("max_tries="+max_tries+", token = "+token);
577 }
578 }
579 if(token_number == 9 && ProcessLineFound)
580 {
581 connection_number = Integer.valueOf(token).intValue();
582 if(config_debug_on)
583 {
584 System.out.println("connection_number="+connection_number+", token = "+token);
585 }
586 }
587 token_number++;
588 }
589 int poll_index = current_line.toUpperCase().indexOf("POLL");
590 if(poll_index >= 0)
591 {
592 poll = true;
593 }
594 int sub_index = current_line.toUpperCase().indexOf("SUB=");
595 if(sub_index >= 0)
596 {
597 poll = true;
598 String sub_period_string = current_line.substring(sub_index+4);
599 if(config_debug_on)
600 {
601 System.out.println("sub_period_string ="+sub_period_string );
602 }
603 StringTokenizer t2 = new StringTokenizer(sub_period_string,"\r\n \t");
604 String token2 = t2.nextToken();
605 subscription_period = Double.valueOf(token2).doubleValue();
606 if(config_debug_on)
607 {
608 System.out.println("subscription_period ="+subscription_period );
609 }
610 }
611 } // current_line.startsWith("P")
612 } // process_line != null
613
614 current_line = buffer_line;
615 StringTokenizer tokenizer = new StringTokenizer(current_line," \t");
616 BufferLine = current_line;
617 int token_number = 0;
618 while(tokenizer.hasMoreTokens())
619 {
620 String token = tokenizer.nextToken();
621 if(null == token)
622 {
623 break;
624 }
625 if(config_debug_on)
626 {
627 System.out.println("token "+token_number+" = "+token);
628 }
629 if(token_number == 1)
630 {
631 if(token.equals(buffer_name))
632 {
633 BufferLineFound = true;
634 }
635 else
636 {
637 break;
638 }
639 }
640 if(token_number == 3)
641 {
642 host = token;
643 if(config_debug_on)
644 {
645 System.out.println("host = "+host);
646 }
647 }
648 if(token_number == 4)
649 {
650 try
651 {
652 buffer_size = (int) (StrToLong.convert(token))*4;
653 }
654 catch(Exception e)
655 {
656 System.err.println("Invalid buffer size token ("+token+") in "+configuration_file+" for "+buffer_name);
657 System.err.println("Using default buffer size.");
658 e.printStackTrace();
659 buffer_size = NML_DEFAULT_BUFFER_SIZE;
660 }
661 if(buffer_size <= 0)
662 {
663 buffer_size = NML_DEFAULT_BUFFER_SIZE;
664 }
665 if(config_debug_on)
666 {
667 System.out.println("buffer_size = "+buffer_size);
668 }
669 }
670 if(token_number == 7)
671 {
672 try
673 {
674 buffer_number = (((new Integer(0)).valueOf(token)).intValue());
675 }
676 catch(Exception e)
677 {
678 System.err.println("Invalid buffer number token ("+token+") in "+configuration_file+" for "+buffer_name);
679 e.printStackTrace();
680 }
681 if(config_debug_on)
682 {
683 System.out.println("buffer_number = "+buffer_number);
684 }
685 }
686 int port_index = -1;
687 if(-1 != (port_index = token.indexOf("TCP=")))
688 {
689 protocol_option = NML_TCP_PROTOCOL_TYPE;
690 String port_string = token.substring(port_index+4);
691 if(config_debug_on)
692 {
693 System.out.println("Setting port number: port_string = "+port_string);
694 }
695 try
696 {
697 port = (((new Integer(0)).valueOf(port_string)).intValue());
698 }
699 catch(Exception e)
700 {
701 System.err.println("Invalid port token ("+token+") in "+configuration_file+" for "+buffer_name);
702 e.printStackTrace();
703 }
704 if(config_debug_on)
705 {
706 System.out.println("port = "+port);
707 }
708 }
709 if(-1 != (port_index = token.indexOf("diag")))
710 {
711 diag_enabled = true;
712 }
713 if(-1 != (port_index = token.indexOf("DIAG")))
714 {
715 diag_enabled = true;
716 }
717 if(-1 != (port_index = token.indexOf("STCP=")))
718 {
719 protocol_option = NML_STCP_PROTOCOL_TYPE;
720 }
721 if(-1 != (port_index = token.indexOf("UDP=")))
722 {
723 protocol_option = NML_UDP_PROTOCOL_TYPE;
724 String port_string = token.substring(port_index+4);
725 if(config_debug_on)
726 {
727 System.out.println("Setting port number: port_string = "+port_string);
728 }
729 try
730 {
731 port = (((new Integer(0)).valueOf(port_string)).intValue());
732 }
733 catch(Exception e)
734 {
735 System.err.println("Invalid port token ("+token+") in "+configuration_file+" for "+buffer_name);
736 e.printStackTrace();
737 }
738 if(config_debug_on)
739 {
740 System.out.println("port = "+port);
741 }
742 }
743 if(-1 != (port_index = token.indexOf("ascii")))
744 {
745 data_format_option = NML_ASCII_ENCODING_TYPE;
746 }
747 if(-1 != (port_index = token.indexOf("disp")))
748 {
749 data_format_option = NML_DISP_ENCODING_TYPE;
750 }
751 int version_index = token.toUpperCase().indexOf("VERSION=");
752 if(version_index >= 0)
753 {
754 try
755 {
756 String version_string = token.substring(version_index+8);
757 min_compatible_version = Double.valueOf(version_string).doubleValue();
758 }
759 catch(Exception e)
760 {
761 e.printStackTrace();
762 }
763 }
764 int confirm_write_index = token.toUpperCase().indexOf("CONFIRM_WRITE");
765 if(confirm_write_index >= 0)
766 {
767 confirm_write = true;
768 }
769 token_number++;
770
771 }
772 int broadcast_port_index = current_line.toUpperCase().indexOf("BROADCAST_PORT=");
773 if(broadcast_port_index >= 0)
774 {
775 String broadcast_port_string = current_line.substring(broadcast_port_index+15);
776 if(config_debug_on)
777 {
778 System.out.println("broadcast_port_string ="+broadcast_port_string );
779 }
780 StringTokenizer t2 = new StringTokenizer(broadcast_port_string,"\r\n \t");
781 String token2 = t2.nextToken();
782 broadcast_port = Integer.valueOf(token2).intValue();
783 if(config_debug_on)
784 {
785 System.out.println(" ="+broadcast_port);
786 }
787 }// end while loop parsing tokens on on line
788 if(BufferLineFound)
789 {
790 if(buffer_size > 0)
791 {
792 input_buffer = new byte[buffer_size];
793 output_buffer = new byte[buffer_size];
794 }
795 switch(data_format_option)
796 {
797 case NML_XDR_ENCODING_TYPE:
798 SetFormatConverter(new XDRFormatConverter());
799 break;
800
801 case NML_DISP_ENCODING_TYPE:
802 SetFormatConverter(new DISPFormatConverter());
803 break;
804
805 default:
806 System.err.println("Invalid data_format_option.");
807 SetFormatConverter(new XDRFormatConverter());
808 break;
809 }
810 }
811 else
812 {
813 if(!ConfigurationFileRead)
814 {
815 System.err.println("Can not read configuration file "+configuration_file);
816 }
817 else
818 {
819 System.err.println("Can not find line for "+buffer_name+" in "+configuration_file);
820 }
821 }
822 }
823 catch(NMLException nml_e)
824 {
825 throw nml_e;
826 }
827 catch(Exception e)
828 {
829 System.err.println("Error reading NML configuration file "+configuration_file);
830 System.err.println("BufferName = "+buffer_name);
831 System.err.println("ProcessName = "+process_name);
832 if(null != current_line)
833 {
834 System.err.println("last line read = "+current_line);
835 }
836 e.printStackTrace();
837 throw new NMLException("Misc. Error",buffer_name,configuration_file,e);
838 }
839 if(!ConfigurationFileRead)
840 {
841 throw new NMLException("Can not open configuration file.", buffer_name,configuration_file);
842 }
843 if(!BufferLineFound)
844 {
845 throw new NMLException("Can not find buffer line.", buffer_name,configuration_file);
846 }
847 if(!ProcessLineFound)
848 {
849 System.err.println("NMLConnection : Can not find process line for "+process_name+" connecting to "+buffer_name+" in "+configuration_file);
850 }
851 }
852
853 protected void finalize()
854 {
855 disconnect();
856 }
857
858
859
860 /**
861 * This function connects this NMLConnection object to a server.
862 * All attempts to read or write will fail while the object is
863 * disconnected.
864 *
865 * Since the NMLConnection(NMLMessageDictionary, String, String,String)
866 *
867 */
868 public int connect() throws NMLException
869 {
870 try {
871
872 /*
873 FIXME: Netscape classes incompatible with newest JDK java.lang
874 try
875 {
876 if(rcs.utils.BrowserInfo.IsNetscapeFourOrLater())
877 {
878 try
879 {
880 netscape.security.PrivilegeManager.enablePrivilege("UniversalConnect");
881 }
882 catch(Exception e)
883 {
884 System.err.println("Netscape denied this applet permission for connecting to other computers. ("+e.getMessage()+")");
885 }
886 catch(LinkageError le)
887 {
888 le.printStackTrace();
889 }
890 }
891 } catch(Exception e)
892 {
893 }
894 */
895
896 read_request_sent = false;
897 if(port <= 0)
898 {
899 return -1;
900 }
901 if(connected)
902 {
903 disconnect();
904 }
905 if(config_debug_on)
906 {
907 System.out.println("");
908 System.out.println("Connecting (port="+port+", protocol_option="+protocol_option+", host = "+host+") . . .");
909 System.out.println("");
910 }
911
912 /* ****************************************************************** */
913 // javac now gives a warning if this Socket constructor is used,
914 // saying the method has been deprecated.
915 //m_Socket = new Socket(host,port,true);
916 /* ******************************************************************* */
917
918 switch(protocol_option)
919 {
920 case NML_TCP_PROTOCOL_TYPE:
921 case NML_STCP_PROTOCOL_TYPE:
922 m_Socket = new Socket(host,port);
923 m_OutputStream = new DataOutputStream(m_Socket.getOutputStream());
924 m_InputStream = new DataInputStream(m_Socket.getInputStream());
925 break;
926
927 case NML_UDP_PROTOCOL_TYPE:
928 if(broadcast_port > 0 && subscription_period > 1E-4 && subscription_period < 600.0)
929 {
930 udpSocket = new NonBlockingDatagramSocket(broadcast_port);
931 }
932 else
933 {
934 udpSocket = new NonBlockingDatagramSocket();
935 }
936 udpServerAddress = InetAddress.getByName(host);
937 baOutputStream = new ByteArrayOutputStream();
938 baInputStream = new ByteArrayInputStream(input_buffer);
939 m_OutputStream = new DataOutputStream(baOutputStream);
940 m_InputStream = new DataInputStream(baInputStream);
941 udpInputPacket = new DatagramPacket(input_buffer, buffer_size);
942 break;
943
944 default:
945 return -1;
946 }
947 write_reply_received = true;
948 read_request_sent = false;
949 input_buffer_ready = false;
950 input_bytes_read = 0;
951 last_msg_read = null;
952 interrupt_login = false;
953 message_size = 0;
954 serial_number = 0;
955
956 /*set = new SocketSet();
957 set.port = port;
958 set.m_Socket = m_Socket;
959 set.m_OutputStream = m_OutputStream;
960 set.m_InputStream = m_InputStream;
961 set.count = 1;
962 m_socketSetHashtable.put(portInteger, set); */
963 connected = true;
964 if(read_debug_on || write_debug_on || config_debug_on)
965 {
966 System.out.print("Socket openned to "+host+":"+port+".\r\n");
967 }
968 if(diag_enabled)
969 {
970 if(setDiagInfo() < 0)
971 {
972 throw new NMLException("Couldn't send diagnostics info",buffer_name, configuration_file);
973 }
974 }
975 if(subscription_period > 1E-4 && subscription_period < 600.0)
976 {
977 if(setSubscriptionPeriod(subscription_period) < 0)
978 {
979 throw new NMLException("Subscription error",buffer_name, configuration_file);
980 }
981 }
982
983 }
984 catch(NMLException nml_e)
985 {
986 throw nml_e;
987 }
988 catch(Exception e)
989 {
990 System.err.println("\r\nCan't connect to port "+port+" on host "+host+"\r\n");
991 throw new NMLException("Connect error",buffer_name, configuration_file, e);
992 }
993 return 0;
994 }
995
996 /**
997 * Disconnect this object from the NML server. This
998 * allows the NML server to shutdown and come back up
999 * while preserving the configuration information in this
1000 * object.
1001 *
1002 * All reads and writes will fail while the object is disconnected.
1003 */
1004 public void disconnect()
1005 {
1006 try{
1007 read_request_sent = false;
1008 /* SocketSet set;
1009 Integer portInteger = new Integer(port);
1010 set = (SocketSet) m_socketSetHashtable.get(portInteger);
1011 if(null != set)
1012 {
1013 set.count--;
1014 if(set.count <= 0)
1015 {
1016 if(set.m_OutputStream != null)
1017 {
1018 set.m_OutputStream.close();
1019 set.m_OutputStream = null;
1020 }
1021 if(set.m_InputStream != null);
1022 {
1023 set.m_InputStream.close();
1024 set.m_InputStream = null;
1025 }
1026 if(set.m_Socket != null)
1027 {
1028 set.m_Socket.close();
1029 set.m_Socket = null;
1030 }
1031 m_socketSetHashtable.remove(portInteger);
1032 m_OutputStream = null;
1033 m_InputStream = null;
1034 m_Socket = null;
1035 System.out.print("\r\n Socket "+set.port+" closed. \r\n");
1036 return;
1037 }
1038
1039 System.out.print("\r\n Socket "+port+" closed.\r\n");
1040 return;
1041 }
1042 */
1043
1044 if(protocol_option == NML_UDP_PROTOCOL_TYPE &&
1045 use_subscription && subscription_id > 0)
1046 {
1047 cancelUDPSubscription();
1048 }
1049
1050 if(connected)
1051 {
1052 if(m_OutputStream != null)
1053 {
1054 m_OutputStream.close();
1055 m_OutputStream = null;
1056 }
1057 if(m_InputStream != null);
1058 {
1059 m_InputStream.close();
1060 m_InputStream = null;
1061 }
1062 if(m_Socket != null)
1063 {
1064 m_Socket.close();
1065 m_Socket = null;
1066 }
1067 if(udpSocket != null)
1068 {
1069 udpSocket.close();
1070 udpSocket = null;
1071 }
1072 if(null != baOutputStream)
1073 {
1074 baOutputStream.reset();
1075 }
1076 baOutputStream = null;
1077 baInputStream = null;
1078 if(read_debug_on || write_debug_on || config_debug_on)
1079 {
1080 System.out.print("Socket "+port+" closed.\r\n");
1081 }
1082 }
1083 connected = false;
1084 }
1085 catch(Exception e)
1086 {
1087 if(null != e.getMessage())
1088 {
1089 System.err.print("\r\n"+e.getMessage()+"\r\n");
1090 }
1091 e.printStackTrace();
1092 }
1093 }
1094
1095 /**
1096 * This function allows the application to gain access to
1097 * NML servers with security enabled.
1098 *
1099 * @param name the login name of the user running the client program
1100 * @param passwd the passwd of the user to login as.
1101 * @exception rcs.nml.NMLException
1102 * If the login could not be attempted because the connection to the
1103 * NML server failed. (If the passwd is wrong it returns false.)
1104 *
1105 * @return true if login was successful
1106 */
1107 public boolean login(String name, String passwd) throws NMLException
1108 {
1109 switch(protocol_option)
1110 {
1111 case NML_TCP_PROTOCOL_TYPE:
1112 return loginTCP(name, passwd);
1113
1114 case NML_UDP_PROTOCOL_TYPE:
1115 return true;
1116
1117 case NML_STCP_PROTOCOL_TYPE:
1118 return true;
1119
1120 default:
1121 System.err.println("NMLConnection.read(): Invalid protocol_option = "+protocol_option+" -- buffer_name = "+buffer_name);
1122 return false;
1123 }
1124
1125 }
1126
1127 /**
1128 * Read a NMLmsg.
1129 *
1130 * @return null if the message in the
1131 * buffer has already been read by this NMLConnection, otherwise it
1132 * returns the NMLmsg read.
1133 *
1134 * @exception rcs.nml.NMLException
1135 * The read failed (ussually because of some network error).
1136 *
1137 */
1138 public NMLmsg read() throws NMLException
1139 {
1140 if(read_debug_on)
1141 {
1142 System.out.println("NMLConnection.peek() called for buffer ("+buffer_name+")");
1143 }
1144 switch(protocol_option)
1145 {
1146 case NML_TCP_PROTOCOL_TYPE:
1147 return readTCP();
1148
1149 case NML_UDP_PROTOCOL_TYPE:
1150 return readUDP();
1151
1152 case NML_STCP_PROTOCOL_TYPE:
1153 if(null == format_converter)
1154 {
1155 return null;
1156 }
1157 NMLmsg temp = format_converter.convertStringToMsg(readSTCPDataString());
1158 if(format_converter.error_in_update)
1159 {
1160 throw new NMLException("Format Error",buffer_name, configuration_file);
1161 }
1162 return temp;
1163
1164 default:
1165 System.err.println("NMLConnection.read(): Invalid protocol_option = "+protocol_option+" -- buffer_name = "+buffer_name);
1166 return null;
1167 }
1168 // return null;
1169 }
1170
1171 public int setDiagInfo()
1172 {
1173 switch(protocol_option)
1174 {
1175 case NML_TCP_PROTOCOL_TYPE:
1176 return setTCPDiagInfo();
1177
1178 default:
1179 break;
1180 }
1181 return -1;
1182 }
1183
1184 protected int setTCPDiagInfo()
1185 {
1186 try
1187 {
1188 if(null == m_OutputStream || null == m_InputStream)
1189 {
1190 return -1;
1191 }
1192 m_OutputStream.writeInt(serial_number);
1193 serial_number++;
1194 request_type = REMOTE_CMS_SET_DIAG_INFO_REQUEST_TYPE;
1195 m_OutputStream.writeInt(request_type);
1196 m_OutputStream.writeInt(buffer_number);
1197 int pad=0;
1198 m_OutputStream.writeInt(pad);
1199 m_OutputStream.writeInt(pad);
1200 byte bname[] = new byte[32];
1201 String temp_process_name = process_name;
1202 if(temp_process_name.length() > 15)
1203 {
1204 temp_process_name = temp_process_name.substring(0,15);
1205 }
1206 m_OutputStream.writeBytes(temp_process_name);
1207
1208 int extra_bytes = 16-temp_process_name.length();
1209 if(config_debug_on)
1210 {
1211 System.out.println("setTCPDiagInfo(): temp_process_name="+temp_process_name+", extra_bytes="+extra_bytes);
1212 }
1213 if(extra_bytes > 0)
1214 {
1215 m_OutputStream.write(bname,0,extra_bytes);
1216 }
1217 String host_sysinfo = "";
1218 try
1219 {
1220 InetAddress local_host = InetAddress.getLocalHost();
1221 if(null != local_host)
1222 {
1223 String host_name = local_host.getHostName();
1224 if(null != host_name)
1225 {
1226 host_sysinfo += host_name+", ";
1227 }
1228 }
1229 }
1230 catch(Exception e)
1231 {
1232 e.printStackTrace();
1233 }
1234 try
1235 {
1236 String java_version = System.getProperty("java.version");
1237 if(null != java_version)
1238 {
1239 if(Character.isDigit(java_version.charAt(0)))
1240 {
1241 java_version = "Java "+java_version;
1242 }
1243 host_sysinfo += java_version+", ";
1244 }
1245 String os_name = System.getProperty("os.name");
1246 if(null != os_name)
1247 {
1248 host_sysinfo += os_name+" ";
1249 }
1250 String os_version = System.getProperty("os.version");
1251 if(null != os_version)
1252 {
1253 host_sysinfo += os_version+", ";
1254 }
1255 String os_arch = System.getProperty("os.arch");
1256 if(null != os_arch)
1257 {
1258 host_sysinfo += os_arch;
1259 }
1260 }
1261 catch(Exception e)
1262 {
1263 e.printStackTrace();
1264 }
1265 if(host_sysinfo.length() > 31)
1266 {
1267 host_sysinfo = host_sysinfo.substring(0,31);
1268 }
1269 m_OutputStream.writeBytes(host_sysinfo);
1270 if(host_sysinfo.length() < 32)
1271 {
1272 m_OutputStream.write(bname,host_sysinfo.length(),32-host_sysinfo.length());
1273 }
1274
1275 int pid = 0;
1276 m_OutputStream.writeInt(pid);
1277 m_OutputStream.writeInt(connection_number);
1278 double rcslib_ver = 0.0;
1279 try
1280 {
1281 rcslib_ver = Double.valueOf(rcs.RCS_VERSION.version_string).doubleValue();
1282 }
1283 catch(Exception e)
1284 {
1285 e.printStackTrace();
1286 }
1287 m_OutputStream.writeDouble(rcslib_ver);
1288 int reverse_flag = 0x01020304;
1289 m_OutputStream.writeInt(reverse_flag);
1290 m_OutputStream.flush();
1291 return 0;
1292 }
1293 catch(Exception e)
1294 {
1295 e.printStackTrace();
1296 return -1;
1297 }
1298 }
1299
1300
1301 public int setSubscriptionPeriod( double period)
1302 {
1303
1304 switch(protocol_option)
1305 {
1306 case NML_TCP_PROTOCOL_TYPE:
1307 return setTCPSubscriptionPeriod(period);
1308
1309 case NML_UDP_PROTOCOL_TYPE:
1310 return setUDPSubscriptionPeriod(period);
1311
1312 default:
1313 System.err.println("No subscriptions allowed for protocol_option "+protocol_option);
1314 break;
1315 }
1316 return -1;
1317 }
1318
1319 protected int setUDPSubscriptionPeriod(double period)
1320 {
1321 if(min_compatible_version < 3.13 && min_compatible_version > 1e-6)
1322 {
1323 return 0;
1324 }
1325 boolean subscription_set = false;
1326 int subscription_interval_millis = (int) (period*1000);
1327 long start_set_subscription_interval = System.currentTimeMillis();
1328 reply_header_received = false;
1329 try
1330 {
1331 while(!subscription_set)
1332 {
1333 if(!udpSocket.ready((int) udpRetryTimeoutMillis))
1334 {
1335 input_buffer_ready = false;
1336 m_OutputStream.flush();
1337 baOutputStream.reset();
1338 request_type = REMOTE_CMS_SET_SUBSCRIPTION_REQUEST_TYPE;
1339 m_OutputStream.writeInt(request_type);
1340 m_OutputStream.writeInt(buffer_number);
1341 if(reply_header_received)
1342 {
1343 serial_number++;
1344 }
1345 m_OutputStream.writeInt(serial_number);
1346 m_OutputStream.writeInt(CMS_POLLED_SUBSCRIPTION);
1347 m_OutputStream.writeInt(subscription_interval_millis);
1348 m_OutputStream.writeInt(last_id_read);
1349 read_request_sent = true;
1350 reply_header_received = false;
1351 if(read_debug_on)
1352 {
1353 System.out.println("UDP setSubscription request sent.");
1354 System.out.println("serial_number = "+serial_number+", request_type = "+request_type+", buffer_number = "+buffer_number);
1355 System.out.println("access_type = "+access_type+", last_id_read = "+last_id_read+" -- buffer_name = "+buffer_name);
1356 System.out.println("lastUdpRequestTime = "+lastUdpRequestTime);
1357 }
1358 m_OutputStream.flush();
1359 byte ba[] = baOutputStream.toByteArray();
1360 int request_length = 24;
1361 if(ba.length < request_length)
1362 {
1363 throw new NMLException("Insufficient output byte array size.",buffer_name, configuration_file);
1364 }
1365 DatagramPacket dp = new DatagramPacket(ba,request_length,udpServerAddress, port);
1366 udpSocket.send(dp);
1367 if(null == udpSocket.currentPacket)
1368 {
1369 udpInputPacket = new DatagramPacket(input_buffer, buffer_size);
1370 udpSocket.receive(udpInputPacket);
1371 }
1372 lastUdpRequestTime = System.currentTimeMillis();
1373 }
1374 else
1375 {
1376 baInputStream.reset();
1377 int returned_serial_number = m_InputStream.readInt();
1378 if(read_debug_on)
1379 {
1380 System.out.println("UDP setSubscription reply received.");
1381 System.out.println("returned_serial_number = "+returned_serial_number);
1382 }
1383 if(returned_serial_number != serial_number)
1384 {
1385 serial_number_repeats++;
1386 if(read_debug_on)
1387 {
1388 System.out.println("serial_number="+serial_number+", returned_serial_number="+returned_serial_number+",serial_number_repeats ="+serial_number_repeats);
1389 }
1390 udpInputPacket = new DatagramPacket(input_buffer, buffer_size);
1391 udpSocket.receive(udpInputPacket);
1392 continue;
1393 }
1394 reply_header_received = true;
1395 remote_status = m_InputStream.readInt();
1396 subscription_id = m_InputStream.readInt();
1397 if(read_debug_on)
1398 {
1399 System.out.println("remote_status = "+remote_status+", buffer_number = "+buffer_number);
1400 System.out.println(" -- buffer_name = "+buffer_name);
1401 }
1402 udpSocket.lastPacket = null;
1403 subscription_set = true;
1404 use_subscription = true;
1405 continue;
1406 }
1407 }
1408 Thread.sleep(10);
1409 if(start_set_subscription_interval - System.currentTimeMillis() > 3000)
1410 {
1411 System.err.println("Timed out trying to setup the subscription.");
1412 return -1;
1413 }
1414 }
1415 catch(Exception e)
1416 {
1417 e.printStackTrace();
1418 return -1;
1419 }
1420 return 0;
1421 }
1422
1423 protected int cancelUDPSubscription()
1424 {
1425 if(min_compatible_version < 3.13 && min_compatible_version > 1e-6)
1426 {
1427 return 0;
1428 }
1429 boolean subscription_set = false;
1430 long start_set_subscription_interval = System.currentTimeMillis();
1431 reply_header_received = false;
1432 try
1433 {
1434 while(!subscription_set)
1435 {
1436 if(!udpSocket.ready((int) udpRetryTimeoutMillis))
1437 {
1438 input_buffer_ready = false;
1439 m_OutputStream.flush();
1440 baOutputStream.reset();
1441 request_type = REMOTE_CMS_CANCEL_SUBSCRIPTION_REQUEST_TYPE;
1442 m_OutputStream.writeInt(request_type);
1443 m_OutputStream.writeInt(buffer_number);
1444 if(reply_header_received)
1445 {
1446 serial_number++;
1447 }
1448 m_OutputStream.writeInt(serial_number);
1449 m_OutputStream.writeInt(subscription_id);
1450 m_OutputStream.writeInt(0);
1451 m_OutputStream.writeInt(0);
1452 read_request_sent = true;
1453 reply_header_received = <