/Awk.Net/ext/SocketExtension.cs
C# | 1672 lines | 905 code | 136 blank | 631 comment | 93 complexity | eb0f462f92afb24acfa99575d15e07d4 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1using System; 2using System.Collections.Generic; 3using System.IO; 4using System.Net.Sockets; 5using java.util; 6using System.Threading; 7 8namespace org.jawk.ext 9{ 10 /// <summary>Enable Socket processing in Jawk.</summary> 11 /// <remarks> 12 /// Enable Socket processing in Jawk. 13 /// <p> 14 /// To use: 15 /// <blockquote><pre> 16 /// ## example echo server using CServerSocket (character-based) 17 /// BEGIN { 18 /// css = CServerSocket(7777); 19 /// } 20 /// $0 = SocketAcceptBlock(css, 21 /// SocketInputBlock(handles, 22 /// SocketCloseBlock(css, handles \ 23 /// ))); 24 /// $1 == "SocketAccept" { 25 /// handles[SocketAccept($2)] = 1 26 /// } 27 /// $1 == "SocketClose" { 28 /// SocketClose($2) 29 /// delete handles[$2] 30 /// } 31 /// $1 == "SocketInput" { 32 /// input = SocketRead($2) 33 /// SocketWrite($2, input); ## do the echo 34 /// } 35 /// </pre></blockquote> 36 /// <p> 37 /// The extension functions are as follows: 38 /// <ul> 39 /// <hr> 40 /// <li><strong><em><font size=+1>ServerSocket</font></em></strong> -<br /> 41 /// Sets up a server socket to listen for incomming 42 /// connections. SocketRead on sockets accepted 43 /// by ServerSocket return arbitrary-length Strings 44 /// (bytes buffered by the input stream, converted 45 /// to a string).<br /> 46 /// <strong>Parameters:</strong> 47 /// <ul> 48 /// <li>port number - required 49 /// </ul> 50 /// <strong>Returns:</strong> 51 /// <ul> 52 /// <li>A string handle to a serversocket. 53 /// </ul><p> 54 /// <li><strong><em><font size=+1>CServerSocket</font></em></strong> -<br /> 55 /// Sets up a server socket to listen for incomming 56 /// connections. SocketRead on sockets accepted 57 /// by CServerSocket return strings which terminate 58 /// by a newline, or text in the input buffer just 59 /// prior to the closing of the socket.<br /> 60 /// <strong>Parameters:</strong> 61 /// <ul> 62 /// <li>port number - required 63 /// </ul> 64 /// <strong>Returns:</strong> 65 /// <ul> 66 /// <li>A string handle to a cserversocket. 67 /// </ul><p> 68 /// <hr> 69 /// <li><strong><em><font size=+1>Socket</font></em></strong> -<br /> 70 /// Create a Socket and connect it to a TCP socket 71 /// endpoint. SocketRead on sockets returned 72 /// by Socket return arbitrary-length Strings 73 /// (bytes buffered by the input stream, converted 74 /// to a string).<br /> 75 /// <strong>Parameters:</strong> 76 /// <ul> 77 /// <li>hostname/ip/"localhost" - required 78 /// <li>port number - required 79 /// </ul> 80 /// <strong>Returns:</strong> 81 /// <ul> 82 /// <li>A string handle to a socket. 83 /// </ul><p> 84 /// <li><strong><em><font size=+1>CSocket</font></em></strong> -<br /> 85 /// Create a Socket and connect it to a TCP socket 86 /// endpoint. SocketRead on sockets returned 87 /// by Socket return strings which terminate 88 /// by a newline, or text in the input buffer just 89 /// prior to the closing of the socket.<br /> 90 /// <strong>Parameters:</strong> 91 /// <ul> 92 /// <li>hostname/ip/"localhost" - required 93 /// <li>port number - required 94 /// </ul> 95 /// <strong>Returns:</strong> 96 /// <ul> 97 /// <li>A string handle to a csocket. 98 /// </ul><p> 99 /// <hr> 100 /// <li><strong><em><font size=+1>SocketAcceptBlock</font></em></strong> -<br /> 101 /// Blocks until a serversocket or cserversocket 102 /// is ready to accept a connecting socket.<br /> 103 /// <strong>Parameters:</strong> 104 /// <ul> 105 /// <li>Any mix of 106 /// serversocket or cserversocket handles 107 /// and/or associative arrays whose keys 108 /// are serversocket or cserversocket handles. 109 /// The last argument can optionally be 110 /// another block call for block chaining. 111 /// </ul> 112 /// <strong>Returns:</strong> 113 /// <ul> 114 /// <li>A string of the form: 115 /// <code><font size=+1>SocketAccept<em>OFS</em>handle</font></code> 116 /// where handle is a serversocket or cserversocket 117 /// handle. 118 /// </ul><p> 119 /// <li><strong><em><font size=+1>SocketInputBlock</font></em></strong> -<br /> 120 /// Blocks until a socket or csocket is ready 121 /// to accept input (via SocketRead).<br /> 122 /// <strong>Parameters:</strong> 123 /// <ul> 124 /// <li>Any mix of 125 /// socket or csocket handles and/or associative 126 /// arrays whose keys are socket or csocket handles. 127 /// The last argument can optionally be 128 /// another block call for block chaining. 129 /// </ul> 130 /// <strong>Returns:</strong> 131 /// <ul> 132 /// <li>A string of the form: <code><font size=+1>SocketInput<em>OFS</em>handle</font></code> 133 /// where handle is a socket or csocket 134 /// handle. 135 /// </ul><p> 136 /// <li><strong><em><font size=+1>SocketCloseBlock</font></em></strong> -<br /> 137 /// Blocks until a serversocket, cserversocket, 138 /// socket, or csocket has been closed on the 139 /// remote end.<br /> 140 /// <strong>Parameters:</strong> 141 /// <ul> 142 /// <li>Any mix of 143 /// serversocket, cserversocket, socket, or csocket 144 /// handles and/or associative 145 /// arrays whose keys are serversocket, cserversocket, 146 /// socket, or csocket handles. 147 /// The last argument can optionally be 148 /// another block call for block chaining. 149 /// </ul> 150 /// <strong>Returns:</strong> 151 /// <ul> 152 /// <li>A string of the form: <code><font size=+1>SocketClose<em>OFS</em>handle</font></code> 153 /// where handle is a serversocket, cserversocket, socket, 154 /// or csocket handle. 155 /// </ul><p> 156 /// <hr> 157 /// <li><strong><em><font size=+1>SocketAccept</font></em></strong> -<br /> 158 /// Accepts a socket from a serversocket or 159 /// a cserversocket. The operation will 160 /// block if there is no socket to accept.<br /> 161 /// <strong>Parameters:</strong> 162 /// <ul> 163 /// <li>serversocket-or-cserversocket handle - required 164 /// </ul> 165 /// <strong>Returns:</strong> 166 /// <ul> 167 /// <li>A string handle to a socket or csocket. 168 /// </ul><p> 169 /// <hr> 170 /// <li><strong><em><font size=+1>SocketRead</font></em></strong> -<br /> 171 /// Reads input from the input stream of a socket 172 /// or a csocket. For a socket, the input length 173 /// is arbitrary. For a csocket, the input 174 /// length is bounded by a newline or upon 175 /// termination of the socket. 176 /// The operation will block if there is no input 177 /// on the socket.<br /> 178 /// <strong>Parameters:</strong> 179 /// <ul> 180 /// <li>socket-or-csocket handle - required 181 /// </ul> 182 /// <strong>Returns:</strong> 183 /// <ul> 184 /// <li>A string containing the input on the socket. 185 /// </ul><p> 186 /// <li><strong><em><font size=+1>SocketWrite</font></em></strong> -<br /> 187 /// Writes data to the socket or csocket. 188 /// For a socket, the string is converted 189 /// to bytes (via java.lang.String.getBytes()), 190 /// and the bytes are sent to the socket's 191 /// output stream. 192 /// For a csocket, println() is called on the 193 /// underlying socket's PrintStream.<br /> 194 /// <strong>Parameters:</strong> 195 /// <ul> 196 /// <li>socket-or-csocket handle - required 197 /// <li>msg - required - The string to write to 198 /// the socket. For a csocket, a newline 199 /// is added to it (via the 200 /// java.io.PrintStream.println() method). 201 /// </ul> 202 /// <strong>Returns:</strong> 203 /// <ul> 204 /// <li>1 upon a successful write, 0 otherwise 205 /// </ul><p> 206 /// <li><strong><em><font size=+1>SocketFlush</font></em></strong> -<br /> 207 /// Flushes the output stream of a socket or csocket.<br /> 208 /// <strong>Parameters:</strong> 209 /// <ul> 210 /// <li>socket-or-csocket handle - required 211 /// </ul> 212 /// <strong>Returns:</strong> 213 /// <ul> 214 /// <li>1 upon a successful flush, 0 otherwise 215 /// </ul><p> 216 /// <hr> 217 /// <li><strong><em><font size=+1>SocketClose</font></em></strong> -<br /> 218 /// Closes the socket/csocket on the local end, 219 /// or a serversocket/cserversocket. 220 /// Can be called in response to a SocketCloseBlock 221 /// event, or to force a socket/csocket connection to 222 /// terminate.<br /> 223 /// <strong>Parameters:</strong> 224 /// <ul> 225 /// <li>socket/csocket/serversocket/cserversocket handle - required 226 /// </ul> 227 /// <strong>Returns:</strong> 228 /// <ul> 229 /// <li>1 upon successful close, 0 otherwise 230 /// </ul><p> 231 /// <hr> 232 /// </ul> 233 /// </remarks> 234 public class SocketExtension : org.jawk.ext.AbstractExtension 235 { 236 /// <summary> 237 /// Either threaded or non-threaded (nio-style) socket 238 /// handling. 239 /// </summary> 240 /// <remarks> 241 /// Either threaded or non-threaded (nio-style) socket 242 /// handling. The threaded implementation is provided 243 /// upon initial release. Non-threaded 244 /// functionality will be available in a subsequent 245 /// release. 246 /// </remarks> 247 private org.jawk.ext.IIO_Style impl_delegate; 248 249 public sealed override void Init(org.jawk.jrt.IVariableManager vm, org.jawk.jrt.JRT 250 jrt) 251 { 252 base.Init(vm, jrt); 253 impl_delegate = new org.jawk.ext.Threaded_IO_Style(vm); 254 } 255 256 public sealed override string GetExtensionName() 257 { 258 return "Socket Support"; 259 } 260 261 public sealed override string[] ExtensionKeywords() 262 { 263 return new string[] { "ServerSocket", "CServerSocket", "Socket", "CSocket", "SocketAcceptBlock" 264 , "SocketInputBlock", "SocketCloseBlock", "SocketAccept", "SocketRead", "SocketWrite" 265 , "SocketFlush", "SocketClose" }; 266 } 267 268 // i.e., ss = ServerSocket(8080) or ss = ServerSocket("ip", 8080) 269 // i.e., css = CServerSocket(8080) or css = CServerSocket("ip", 8080) 270 // i.e., s = Socket("localhost", 8080) 271 // i.e., cs = CSocket("localhost", 8080) 272 // i.e., $0 = SocketAcceptBlock(ss, css, 273 // i.e., SocketInputBlock(s, cs, 274 // i.e., SocketCloseBlock(ss,css, s,cs))); 275 // i.e., cs = SocketAccept(css) 276 // i.e., buf = SocketRead(s) or line = SocketRead(cs) 277 // i.e., SocketWrite(s, "hi there\n") or SocketWrite(cs, "hi there") 278 // i.e., SocketFlush(s) or SocketFlush(cs) 279 // i.e., SocketClose(ss) or SocketClose(cs) 280 public sealed override object Invoke(string method_name, object[] args) 281 { 282 // large if-then-else block to decide which extension to invoke 283 if (false) 284 { 285 throw new System.Exception("Should never reach."); 286 } 287 else 288 { 289 if (method_name.Equals("ServerSocket")) 290 { 291 if (args.Length == 1) 292 { 293 return impl_delegate.Serversocket(null, (int)org.jawk.jrt.JRT.ToDouble(args[0])); 294 } 295 else 296 { 297 if (args.Length == 2) 298 { 299 return impl_delegate.Serversocket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble 300 (args[1])); 301 } 302 else 303 { 304 throw new org.jawk.jrt.IllegalAwkArgumentException("Expecting 1 or 2 arguments, not " 305 + args.Length); 306 } 307 } 308 } 309 else 310 { 311 if (method_name.Equals("CServerSocket")) 312 { 313 if (args.Length == 1) 314 { 315 return impl_delegate.Cserversocket(null, (int)org.jawk.jrt.JRT.ToDouble(args[0])); 316 } 317 else 318 { 319 if (args.Length == 2) 320 { 321 return impl_delegate.Cserversocket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble 322 (args[1])); 323 } 324 else 325 { 326 throw new org.jawk.jrt.IllegalAwkArgumentException("Expecting 1 or 2 arguments, not " 327 + args.Length); 328 } 329 } 330 } 331 else 332 { 333 if (method_name.Equals("Socket")) 334 { 335 CheckNumArgs(args, 2); 336 return impl_delegate.Socket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble( 337 args[1])); 338 } 339 else 340 { 341 if (method_name.Equals("CSocket")) 342 { 343 CheckNumArgs(args, 2); 344 return impl_delegate.Csocket(ToAwkString(args[0]), (int)org.jawk.jrt.JRT.ToDouble 345 (args[1])); 346 } 347 else 348 { 349 if (method_name.Equals("SocketAcceptBlock")) 350 { 351 return impl_delegate.Socketacceptblock(args); 352 } 353 else 354 { 355 if (method_name.Equals("SocketInputBlock")) 356 { 357 return impl_delegate.Socketinputblock(args); 358 } 359 else 360 { 361 if (method_name.Equals("SocketCloseBlock")) 362 { 363 return impl_delegate.Socketcloseblock(args); 364 } 365 else 366 { 367 if (method_name.Equals("SocketAccept")) 368 { 369 CheckNumArgs(args, 1); 370 return impl_delegate.Socketaccept(ToAwkString(args[0])); 371 } 372 else 373 { 374 if (method_name.Equals("SocketRead")) 375 { 376 CheckNumArgs(args, 1); 377 return impl_delegate.Socketread(ToAwkString(args[0])); 378 } 379 else 380 { 381 if (method_name.Equals("SocketWrite")) 382 { 383 CheckNumArgs(args, 2); 384 return impl_delegate.Socketwrite(ToAwkString(args[0]), ToAwkString(args[1])); 385 } 386 else 387 { 388 if (method_name.Equals("SocketFlush")) 389 { 390 CheckNumArgs(args, 1); 391 return impl_delegate.Socketflush(ToAwkString(args[0])); 392 } 393 else 394 { 395 if (method_name.Equals("SocketClose")) 396 { 397 CheckNumArgs(args, 1); 398 return impl_delegate.Socketclose(ToAwkString(args[0])); 399 } 400 else 401 { 402 throw new org.jawk.NotImplementedError(method_name); 403 } 404 } 405 } 406 } 407 } 408 } 409 } 410 } 411 } 412 } 413 } 414 } 415 } 416 } 417 } 418 419 /// <summary> 420 /// Interface to the socket handling delegate which 421 /// does all the work. 422 /// </summary> 423 /// <remarks> 424 /// Interface to the socket handling delegate which 425 /// does all the work. The SocketExtension manager 426 /// class delegates all concrete socket IO 427 /// processing to an instance of this interface. 428 /// </remarks> 429 internal interface IIO_Style 430 { 431 // public class SocketExtension {AbstractExtension} 432 // 433 // INTERFACE TO DELEGATE 434 // 435 /// <summary> 436 /// Sets up a server socket to listen for incomming 437 /// connections. 438 /// </summary> 439 /// <remarks> 440 /// Sets up a server socket to listen for incomming 441 /// connections. SocketRead on sockets accepted 442 /// by ServerSocket return arbitrary-length Strings 443 /// (bytes buffered by the input stream, converted 444 /// to a string). 445 /// </remarks> 446 /// <param name="hostname"> 447 /// The hostname or IP address as a string. 448 /// hostname can be null. 449 /// </param> 450 /// <param name="port">The port number.</param> 451 /// <returns>A handle to a newly created serversocket.</returns> 452 string Serversocket(string hostname, int port); 453 454 /// <summary> 455 /// Sets up a server socket to listen for incomming 456 /// connections. 457 /// </summary> 458 /// <remarks> 459 /// Sets up a server socket to listen for incomming 460 /// connections. SocketRead on sockets accepted 461 /// by CServerSocket return strings which terminate 462 /// by a newline, or text in the input buffer just 463 /// prior to the closing of the socket. 464 /// </remarks> 465 /// <param name="hostname"> 466 /// The hostname or IP address as a string. 467 /// hostname can be null. 468 /// </param> 469 /// <param name="port">The port number.</param> 470 /// <returns>A handle to a newly created cserversocket.</returns> 471 string Cserversocket(string hostname, int port); 472 473 /// <summary> 474 /// Create a Socket and connect it to a TCP socket 475 /// endpoint. 476 /// </summary> 477 /// <remarks> 478 /// Create a Socket and connect it to a TCP socket 479 /// endpoint. SocketRead on sockets returned 480 /// by Socket return arbitrary-length Strings 481 /// (bytes buffered by the input stream, converted 482 /// to a string). 483 /// </remarks> 484 /// <param name="hostname"> 485 /// The hostname or IP address as a string. 486 /// hostname can be null. 487 /// </param> 488 /// <param name="port">The port number.</param> 489 /// <returns>A handle to a newly created socket.</returns> 490 string Socket(string hostname, int port); 491 492 /// <summary> 493 /// Create a Socket and connect it to a TCP socket 494 /// endpoint. 495 /// </summary> 496 /// <remarks> 497 /// Create a Socket and connect it to a TCP socket 498 /// endpoint. SocketRead on sockets returned 499 /// by Socket return strings which terminate 500 /// by a newline, or text in the input buffer just 501 /// prior to the closing of the socket. 502 /// </remarks> 503 /// <param name="hostname"> 504 /// The hostname or IP address as a string. 505 /// hostname can be null. 506 /// </param> 507 /// <param name="port">The port number.</param> 508 /// <returns>A handle to a newly created csocket.</returns> 509 string Csocket(string hostname, int port); 510 511 /// <summary> 512 /// Blocks until a serversocket or cserversocket 513 /// is ready to accept a connecting socket. 514 /// </summary> 515 /// <remarks> 516 /// Blocks until a serversocket or cserversocket 517 /// is ready to accept a connecting socket. 518 /// </remarks> 519 /// <param name="args"> 520 /// An array of 521 /// serversocket or cserversocket handles 522 /// and/or associative arrays whose keys 523 /// are serversocket or cserversocket handles. 524 /// The last argument can optionally be 525 /// another block call for block chaining. 526 /// </param> 527 /// <returns> 528 /// A block object conditioned 529 /// to block on the acceptance of 530 /// socket connections from any of 531 /// the serversockets / cserversockets 532 /// referred to by the handles passed 533 /// in to the object array. 534 /// </returns> 535 org.jawk.jrt.BlockObject Socketacceptblock(object[] args); 536 537 /// <summary> 538 /// Blocks until a socket or csocket is ready 539 /// to accept input (via SocketRead). 540 /// </summary> 541 /// <remarks> 542 /// Blocks until a socket or csocket is ready 543 /// to accept input (via SocketRead). 544 /// </remarks> 545 /// <param name="args"> 546 /// An array of 547 /// socket or csocket handles and/or associative 548 /// arrays whose keys are socket or csocket handles. 549 /// The last argument can optionally be 550 /// another block call for block chaining. 551 /// </param> 552 /// <returns> 553 /// A block object conditioned 554 /// to block on the availability of 555 /// input from any of the sockets / csockets 556 /// referred to by the handles passed 557 /// in to the object array. 558 /// </returns> 559 org.jawk.jrt.BlockObject Socketinputblock(object[] args); 560 561 /// <summary> 562 /// Blocks until a serversocket, cserversocket, 563 /// socket, or csocket has been closed on the 564 /// remote end. 565 /// </summary> 566 /// <remarks> 567 /// Blocks until a serversocket, cserversocket, 568 /// socket, or csocket has been closed on the 569 /// remote end. 570 /// </remarks> 571 /// <param name="args"> 572 /// An array of 573 /// serversocket, cserversocket, socket, or csocket 574 /// handles and/or associative 575 /// arrays whose keys are serversocket, cserversocket, 576 /// socket, or csocket handles. 577 /// The last argument can optionally be 578 /// another block call for block chaining. 579 /// </param> 580 /// <returns> 581 /// A block object conditioned 582 /// to block until any of the sockets / 583 /// csockets / serversockets / cserversockets 584 /// in to the object array have closed. 585 /// </returns> 586 org.jawk.jrt.BlockObject Socketcloseblock(object[] args); 587 588 /// <summary> 589 /// Accepts a socket from a serversocket or 590 /// a cserversocket. 591 /// </summary> 592 /// <remarks> 593 /// Accepts a socket from a serversocket or 594 /// a cserversocket. The operation will 595 /// block if there is no socket to accept. 596 /// </remarks> 597 /// <param name="handle"> 598 /// A string handle to a serversocket 599 /// or cserversocket. 600 /// </param> 601 /// <returns> 602 /// A handle to a socket or csocket that 603 /// has connected to the serversocket / cserversocket 604 /// referred to by the handle argument. 605 /// </returns> 606 string Socketaccept(string handle); 607 608 /// <summary> 609 /// Reads input from the input stream of a socket 610 /// or a csocket. 611 /// </summary> 612 /// <remarks> 613 /// Reads input from the input stream of a socket 614 /// or a csocket. For a socket, the input length 615 /// is arbitrary. For a csocket, the input 616 /// length is bounded by a newline or upon 617 /// termination of the socket. 618 /// The operation will block if there is no input 619 /// on the socket. 620 /// </remarks> 621 /// <param name="handle"> 622 /// A string handle to a socket 623 /// or csocket. 624 /// </param> 625 /// <returns> 626 /// A block of byte input from a socket 627 /// (converted to a string), or a line of 628 /// string input from a csocket bounded by 629 /// a newline in the stream or upon the closing 630 /// of the csocket. 631 /// </returns> 632 string Socketread(string handle); 633 634 /// <summary>Writes data to the socket or csocket.</summary> 635 /// <remarks> 636 /// Writes data to the socket or csocket. 637 /// For a socket, the string is converted 638 /// to bytes (via java.lang.String.getBytes()), 639 /// and the bytes are sent to the underlying 640 /// socket's output stream. 641 /// For a csocket, println() is called on the 642 /// underlying socket's PrintStream. 643 /// </remarks> 644 /// <param name="handle"> 645 /// A string handle to a socket 646 /// or csocket. 647 /// </param> 648 /// <param name="buf"> 649 /// The string containing the 650 /// bytes to write. SocketWrite writes 651 /// the contents of the resulting buf.getBytes() 652 /// call to the socket. 653 /// </param> 654 /// <param name="handle"> 655 /// A String handle to a socket 656 /// or csocket. 657 /// </param> 658 /// <param name="buf"> 659 /// A string containing a block of 660 /// bytes to write to a socket (via 661 /// java.lang.String.getBytes()) if handle 662 /// refers to a socket. If handle refers 663 /// to a csocket, the line of text to write 664 /// via PrintStream.println(String). 665 /// </param> 666 /// <returns> 667 /// 1 upon a successful write, 668 /// 0 upon an IO exception/error. 669 /// </returns> 670 int Socketwrite(string handle, string buf); 671 672 /// <summary>Flushes the output stream of a socket or csocket.</summary> 673 /// <remarks>Flushes the output stream of a socket or csocket.</remarks> 674 /// <param name="handle"> 675 /// A string handle to a socket 676 /// or csocket. 677 /// </param> 678 /// <returns> 679 /// 1 upon a successful flush operation, 680 /// 0 upon an IO exception/error. 681 /// </returns> 682 int Socketflush(string handle); 683 684 /// <summary> 685 /// Closes the socket/csocket on the local end, 686 /// or a serversocket/cserversocket. 687 /// </summary> 688 /// <remarks> 689 /// Closes the socket/csocket on the local end, 690 /// or a serversocket/cserversocket. 691 /// Can be called in response to a SocketCloseBlock 692 /// event, or to force a socket/csocket connection to 693 /// terminate. 694 /// </remarks> 695 /// <param name="handle"> 696 /// A string handle to a socket, 697 /// csocket, serversocket, or cserversocket. 698 /// </param> 699 /// <returns> 700 /// 1 upon a successful close operation, 701 /// 0 upon an IO exception/error. 702 /// </returns> 703 int Socketclose(string handle); 704 } 705 706 /// <summary>A view of two maps as one map.</summary> 707 /// <remarks>A view of two maps as one map.</remarks> 708 internal class MapUnion<K, V> : Dictionary<K, V> 709 { 710 private System.Collections.Generic.IDictionary<K, V> m1; 711 712 private System.Collections.Generic.IDictionary<K, V> m2; 713 714 internal MapUnion(System.Collections.Generic.IDictionary<K, V> m1, System.Collections.Generic.IDictionary 715 <K, V> m2) 716 { 717 this.m1 = m1; 718 this.m2 = m2; 719 } 720 721 public System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair <K, V>> EntrySet() 722 { 723 // build the entry set 724 System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>> entry_set = new List<KeyValuePair<K, V>>(); 725 System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>> s1 = m1; 726 System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<K, V>> s2 = m2; 727 foreach (System.Collections.Generic.KeyValuePair<K, V> me in s1) 728 { 729 entry_set.Add(me); 730 } 731 foreach (System.Collections.Generic.KeyValuePair<K, V> me in s2) 732 { 733 entry_set.Add(me); 734 } 735 return entry_set; 736 } 737 } 738 739 internal class Threaded_IO_Style : org.jawk.ext.IIO_Style 740 { 741 private string last_err = null; 742 743 /// <summary> 744 /// Map of "Socket"/"CSocket" handles to 745 /// the objects which perform the actual 746 /// read and block operations. 747 /// </summary> 748 /// <remarks> 749 /// Map of "Socket"/"CSocket" handles to 750 /// the objects which perform the actual 751 /// read and block operations. 752 /// <p> 753 /// <strong>Note:</strong> 754 /// "consumers" originally was of type 755 /// Map<String,Consumer>, but changed to ...,Closeable. 756 /// (Likewise, "accepters" was originally ...,Accepter, 757 /// but then changed to ...,Closeable.) 758 /// Why? Because MapUnion could not infer that "Consumer" 759 /// nor "Accepter" were extensions of "Blockable". 760 /// MapUnion originally accepted 3 generic parameters: 761 /// K, V1 extends Blockable, and V2 extends Blockable. 762 /// And, close_blocker's BulkBlockObject Map parameter was: 763 /// new MapUnion<String,Accepter,Consumer>(accepters,consumers). 764 /// But, it wouldn't compile. 765 /// The resulting warning/error messages stated that 766 /// "capture #XXX of ? extends Blockable" does not 767 /// match "? extends Blockable". I believe the error 768 /// results from Blockable being compiled against 769 /// Java 1.5.x and extensions being developed against 770 /// Java 1.6.x, and that they don't grok one another 771 /// in this scenario. 772 /// We, then, decided to assign its lowest common 773 /// subclass, "Closeable", and typecast when we need 774 /// specific "Accepter" and "Consumer" functionality. 775 /// This resolved the issue while losing some 776 /// compile-time type safety. 777 /// </remarks> 778 private readonly System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable> consumers = new System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable>(); 779 780 /// <summary> 781 /// Map of "ServerSocket"/"CServerSocket" handles 782 /// to the objects which perform the actual 783 /// socket accept operation. 784 /// </summary> 785 /// <remarks> 786 /// Map of "ServerSocket"/"CServerSocket" handles 787 /// to the objects which perform the actual 788 /// socket accept operation. 789 /// <p> 790 /// <strong>Note:</strong> 791 /// See lengthy diatribe above for "consumers". 792 /// The same applies for "accepters"'s generic 793 /// type choice for values of the Map. 794 /// </remarks> 795 private readonly System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable> accepters = new System.Collections.Generic.Dictionary<string, org.jawk.jrt.ICloseable>(); 796 797 private readonly org.jawk.jrt.IVariableManager vm; 798 799 private readonly org.jawk.jrt.BulkBlockObject accept_blocker; 800 801 private readonly org.jawk.jrt.BulkBlockObject input_blocker; 802 803 private readonly org.jawk.jrt.BulkBlockObject close_blocker; 804 805 internal Threaded_IO_Style(org.jawk.jrt.IVariableManager vm) 806 { 807 accept_handle_validator = new _IBlockHandleValidator_759(this); 808 input_handle_validator = new _IBlockHandleValidator_772(this); 809 close_handle_validator = new _IBlockHandleValidator_785(this); 810 //assert vm != null; 811 this.vm = vm; 812 accept_blocker = new org.jawk.jrt.BulkBlockObject("SocketAccept", accepters, vm); 813 input_blocker = new org.jawk.jrt.BulkBlockObject("SocketInput", consumers, vm); 814 close_blocker = new org.jawk.jrt.BulkBlockObject("SocketClose", new org.jawk.ext.MapUnion<string, org.jawk.jrt.ICloseable>(accepters, consumers), vm); 815 } 816 817 public string Serversocket(string hostname, int port) 818 { 819 try 820 { 821 822 TcpListener ss = null; 823 824 if (hostname == null) 825 { 826 ss = new TcpListener(System.Net.IPAddress.Any, port); 827 } 828 else 829 { 830 // 0 = default backlog 831 System.Net.IPAddress[] tab = System.Net.Dns.GetHostAddresses(hostname); 832 833 System.Net.IPAddress address = System.Net.IPAddress.Any; 834 if(tab!=null && tab.Length>0) 835 { 836 address = tab[0]; 837 } 838 ss = new TcpListener(address, port); 839 } 840 string handle = CreateHandle(ss); 841 //ssockets.put(handle, ss); 842 org.jawk.ext.Threaded_IO_Style.Accepter accepter_thread = new org.jawk.ext.Threaded_IO_Style.Accepter 843 (this, handle, ss); 844 accepters[handle] = accepter_thread; 845 accepter_thread.Start(); 846 return handle; 847 } 848 catch (System.IO.IOException ioe) 849 { 850 Console.Error.WriteLine(ioe.ToString()); 851 last_err = ioe.ToString(); 852 return string.Empty; 853 } 854 } 855 856 public string Cserversocket(string hostname, int port) 857 { 858 try 859 { 860 TcpListener ss; 861 if (hostname == null) 862 { 863 ss = new TcpListener(System.Net.IPAddress.Any,port); 864 } 865 else 866 { 867 // 0 = default backlog 868 System.Net.IPAddress[] tab = System.Net.Dns.GetHostAddresses(hostname); 869 870 System.Net.IPAddress address = System.Net.IPAddress.Any; 871 if (tab != null && tab.Length > 0) 872 { 873 address = tab[0]; 874 } 875 ss = new TcpListener(address, port); 876 } 877 string handle = CreateHandle(ss); 878 //ssockets.put(handle, ss); 879 org.jawk.ext.Threaded_IO_Style.Accepter accepter_thread = new org.jawk.ext.Threaded_IO_Style.CAccepter 880 (this, handle, ss); 881 accepters[handle] = accepter_thread; 882 accepter_thread.Start(); 883 return handle; 884 } 885 catch (System.IO.IOException ioe) 886 { 887 Console.Error.WriteLine(ioe.ToString()); 888 last_err = ioe.ToString(); 889 return string.Empty; 890 } 891 } 892 893 public string Socket(string hostname, int port) 894 { 895 // create the socket 896 try 897 { 898 TcpClient socket = new TcpClient(hostname, port); 899 string handle = CreateHandle(socket); 900 //sockets.put(handle, socket); 901 // start the reader 902 org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.ByteConsumer 903 (this, handle, socket); 904 consumers[handle] = reader_thread; 905 reader_thread.Start(); 906 return handle; 907 } 908 catch (System.IO.IOException ioe) 909 { 910 Console.Error.WriteLine(ioe.ToString()); 911 last_err = ioe.ToString(); 912 return string.Empty; 913 } 914 } 915 916 public string Csocket(string hostname, int port) 917 { 918 try 919 { 920 // create the socket 921 TcpClient socket = new TcpClient(hostname, port); 922 string handle = CreateHandle(socket); 923 //sockets.put(handle, socket); 924 // start the reader 925 org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.CharacterConsumer 926 (this, handle, socket); 927 consumers[handle] = reader_thread; 928 reader_thread.Start(); 929 return handle; 930 } 931 catch (System.IO.IOException ioe) 932 { 933 Console.Error.WriteLine(ioe.ToString()); 934 last_err = ioe.ToString(); 935 return string.Empty; 936 } 937 } 938 939 private int socket_idx = 0; 940 941 private int ssocket_idx = 0; 942 943 private string CreateHandle(TcpListener socket) 944 { 945 System.Net.IPEndPoint endPoint = socket.LocalEndpoint as System.Net.IPEndPoint; 946 947 if (endPoint != null) 948 { 949 return "Socket:" + endPoint.Address.ToString() + ":" + endPoint.Port + "/" + (++ssocket_idx); 950 } 951 else 952 { 953 return "Socket:" + socket.LocalEndpoint.Serialize().ToString() + "/" + (++ssocket_idx); 954 } 955 } 956 957 private string CreateHandle(TcpClient socket) 958 { 959 System.Net.IPEndPoint endPoint = socket.Client.LocalEndPoint as System.Net.IPEndPoint; 960 961 if (endPoint != null) 962 { 963 return "Socket:" + endPoint.Address.ToString() + ":" + endPoint.Port + "/" + (++socket_idx); 964 } 965 else 966 { 967 return "Socket:" + socket.Client.LocalEndPoint.Serialize().ToString() + "/" + (++socket_idx); 968 } 969 } 970 971 private sealed class _IBlockHandleValidator_759 : org.jawk.jrt.IBlockHandleValidator 972 { 973 public _IBlockHandleValidator_759(Threaded_IO_Style _enclosing) 974 { 975 this._enclosing = _enclosing; 976 } 977 978 ////////////////////////////////////////////////////////////////// 979 ////////////////////////////////////////////////////////////////// 980 ////////////////////////////////////////////////////////////////// 981 // to satisfy the BlockHandleValidator interface 982 public string IsBlockHandleValid(string handle) 983 { 984 org.jawk.jrt.ICloseable closeable = null; 985 if(this._enclosing.accepters.ContainsKey(handle)) 986 { 987 closeable = this._enclosing.accepters[handle]; 988 } 989 if (closeable == null) 990 { 991 return "Invalid ServerSocket handle."; 992 } 993 if (closeable.IsClosed()) 994 { 995 return "ServerSocket is closed."; 996 } 997 else 998 { 999 return null; 1000 } 1001 } 1002 1003 private readonly Threaded_IO_Style _enclosing; 1004 } 1005 1006 private readonly org.jawk.jrt.IBlockHandleValidator accept_handle_validator; 1007 1008 private sealed class _IBlockHandleValidator_772 : org.jawk.jrt.IBlockHandleValidator 1009 { 1010 public _IBlockHandleValidator_772(Threaded_IO_Style _enclosing) 1011 { 1012 this._enclosing = _enclosing; 1013 } 1014 1015 // valid 1016 // to satisfy the BlockHandleValidator interface 1017 public string IsBlockHandleValid(string handle) 1018 { 1019 org.jawk.jrt.ICloseable closeable = null; 1020 if (this._enclosing.consumers.ContainsKey(handle)) 1021 { 1022 closeable = this._enclosing.consumers[handle]; 1023 } 1024 if (closeable == null) 1025 { 1026 return "Invalid socket handle. (Could have already been closed?)"; 1027 } 1028 if (closeable.IsClosed()) 1029 { 1030 return "Socket is closed."; 1031 } 1032 else 1033 { 1034 return null; 1035 } 1036 } 1037 1038 private readonly Threaded_IO_Style _enclosing; 1039 } 1040 1041 private readonly org.jawk.jrt.IBlockHandleValidator input_handle_validator; 1042 1043 private sealed class _IBlockHandleValidator_785 : org.jawk.jrt.IBlockHandleValidator 1044 { 1045 public _IBlockHandleValidator_785(Threaded_IO_Style _enclosing) 1046 { 1047 this._enclosing = _enclosing; 1048 } 1049 1050 // valid 1051 // to satisfy the BlockHandleValidator interface 1052 public string IsBlockHandleValid(string handle) 1053 { 1054 org.jawk.jrt.ICloseable closeable = null; 1055 if(this._enclosing.accepters.ContainsKey(handle)) 1056 { 1057 closeable = this._enclosing.accepters[handle]; 1058 } 1059 if (closeable == null && this._enclosing.consumers.ContainsKey(handle)) 1060 { 1061 closeable = this._enclosing.consumers[handle]; 1062 } 1063 if (closeable == null) 1064 { 1065 return "Invalid socket handle. (Could have already been closed?)"; 1066 } 1067 if (closeable.IsClosed()) 1068 { 1069 return "Socket is already closed."; 1070 } 1071 else 1072 { 1073 return null; 1074 } 1075 } 1076 1077 private readonly Threaded_IO_Style _enclosing; 1078 } 1079 1080 private readonly org.jawk.jrt.IBlockHandleValidator close_handle_validator; 1081 1082 // valid 1083 public org.jawk.jrt.BlockObject Socketacceptblock(object[] args) 1084 { 1085 return accept_blocker.PopulateHandleSet(args, vm, accept_handle_validator); 1086 } 1087 1088 public org.jawk.jrt.BlockObject Socketinputblock(object[] args) 1089 { 1090 return input_blocker.PopulateHandleSet(args, vm, input_handle_validator); 1091 } 1092 1093 public org.jawk.jrt.BlockObject Socketcloseblock(object[] args) 1094 { 1095 return close_blocker.PopulateHandleSet(args, vm, close_handle_validator); 1096 } 1097 1098 public string Socketaccept(string handle) 1099 { 1100 try 1101 { 1102 org.jawk.ext.Threaded_IO_Style.Accepter accepter = null; 1103 if(accepters.ContainsKey(handle)) 1104 { 1105 accepter = (org.jawk.ext.Threaded_IO_Style.Accepter)accepters[handle]; 1106 } 1107 if (accepter == null) 1108 { 1109 throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid server socket handle : " 1110 + handle); 1111 } 1112 // it's "as if" accept_blocker is querying whether to block or not 1113 if (accepter.WillBlock(accept_blocker) && accepter.IsClosed()) 1114 { 1115 last_err = "Server closed."; 1116 return string.Empty; 1117 } 1118 return accepter.GetSocket(); 1119 } 1120 catch (System.IO.IOException ioe) 1121 { 1122 Console.Error.WriteLine(ioe.ToString()); 1123 throw new System.Exception("Error occurred during creation of accepted socket."); 1124 } 1125 catch (System.Exception ie) 1126 { 1127 Console.Error.WriteLine(ie.ToString()); 1128 throw new System.Exception("A queue operation cannot be interrupted."); 1129 } 1130 } 1131 1132 public string Socketread(string handle) 1133 { 1134 try 1135 { 1136 org.jawk.jrt.IConsumer consumer = null; 1137 if(consumers.ContainsKey(handle)) 1138 { 1139 consumer = (org.jawk.jrt.IConsumer)consumers[handle]; 1140 } 1141 if (consumer == null) 1142 { 1143 throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid socket handle : " + handle 1144 ); 1145 } 1146 // it's "as if" input_blocker is querying whether to block or not 1147 if (consumer.WillBlock(input_blocker) && consumer.IsClosed()) 1148 { 1149 last_err = "No more input."; 1150 return string.Empty; 1151 } 1152 return consumer.GetInput(); 1153 } 1154 catch (System.Exception ie) 1155 { 1156 Console.Error.WriteLine(ie); 1157 throw new System.Exception("A queue operation cannot be interrupted."); 1158 } 1159 } 1160 1161 public int Socketwrite(string handle, string buf) 1162 { 1163 org.jawk.jrt.IConsumer consumer = null; 1164 if(consumers.ContainsKey(handle)) 1165 { 1166 consumer = (org.jawk.jrt.IConsumer)consumers[handle]; 1167 } 1168 if (consumer == null) 1169 { 1170 throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid socket handle : " + handle 1171 ); 1172 } 1173 return consumer.Write(buf); 1174 } 1175 1176 public int Socketflush(string handle) 1177 { 1178 org.jawk.jrt.IConsumer consumer = null; 1179 if(consumers.ContainsKey(handle)) 1180 { 1181 consumer = (org.jawk.jrt.IConsumer)consumers[handle]; 1182 } 1183 if (consumer == null) 1184 { 1185 throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid socket handle : " + handle 1186 ); 1187 } 1188 return consumer.Flush(); 1189 } 1190 1191 public int Socketclose(string handle) 1192 { 1193 1194 org.jawk.jrt.ICloseable t = null; 1195 1196 if (consumers.ContainsKey(handle)) 1197 { 1198 t = consumers[handle]; 1199 consumers.Remove(handle); 1200 } 1201 1202 if (t == null && accepters.ContainsKey(handle)) 1203 { 1204 t = accepters[handle]; 1205 accepters.Remove(handle); 1206 } 1207 1208 if (t == null) 1209 { 1210 throw new org.jawk.jrt.IllegalAwkArgumentException("Invalid [server]socket handle : " + handle); 1211 } 1212 int retval; 1213 try 1214 { 1215 t.Close(); 1216 retval = 1; 1217 } 1218 catch (System.IO.IOException ioe) 1219 { 1220 Console.Error.WriteLine(ioe); 1221 retval = 0; 1222 } 1223 // interrupt the thread 1224 t.Interrupt(); 1225 // join on the thread 1226 try 1227 { 1228 t.Join(); 1229 } 1230 catch (System.Exception) 1231 { 1232 throw new System.Exception("A socket close() cannot be interrupted."); 1233 } 1234 return retval; 1235 } 1236 1237 private class Accepter : IThread, org.jawk.jrt.ICloseable 1238 { 1239 private string handle; 1240 1241 private TcpListener ssocket; 1242 1243 protected java.util.BlockingQueue<TcpClient> queue = new java.util.BlockingQueue 1244 <TcpClient>(1); 1245 1246 ////////////////////////////////////////////////////////////////// 1247 ////////////////////////////////////////////////////////////////// 1248 ////////////////////////////////////////////////////////////////// 1249 // only 1 slot 1250 //private BlockingQueue<String> queue = new LinkedBlockingQueue<String>(); 1251 public virtual bool WillBlock(org.jawk.jrt.BlockObject bo) 1252 { 1253 return this.queue.Count == 0; 1254 } 1255 1256 /// <exception cref="System.IO.IOException"></exception> 1257 public Accepter(Threaded_IO_Style _enclosing, string handle, TcpListener ssocket) 1258 { 1259 this._enclosing = _enclosing; 1260 this.handle = handle; 1261 //ssocket = ssockets.get(handle); 1262 this.ssocket = ssocket; 1263 1264 mThread = new Thread(Run); 1265 } 1266 1267 //assert ssocket != null; 1268 public void Run() 1269 { 1270 if (Thread.CurrentThread != mThread) 1271 { 1272 throw new System.Exception("Invalid thread access : " + Thread.CurrentThread); 1273 } 1274 try 1275 { 1276 TcpClient socket; 1277 while (true) 1278 { 1279 socket = this.ssocket.AcceptTcpClient(); 1280 this.queue.Put(socket); 1281 lock (this._enclosing.accept_blocker) 1282 { 1283 Monitor.Pulse(this._enclosing.accept_blocker); 1284 } 1285 } 1286 } 1287 catch (System.Net.Sockets.SocketException se) 1288 { 1289 Console.Error.WriteLine(se); 1290 } 1291 catch (System.IO.IOException ioe) 1292 { 1293 // no big deal 1294 // assume we should just shutdown now 1295 Console.Error.WriteLine(ioe); 1296 } 1297 catch (System.Exception ie) 1298 { 1299 Console.Error.WriteLine(ie); 1300 throw new System.Exception("A queue operation cannot be interrupted."); 1301 } 1302 // no big deal 1303 lock (this._enclosing.close_blocker) 1304 { 1305 Monitor.Pulse(this._enclosing.close_blocker); 1306 } 1307 } 1308 1309 // can be overridden 1310 /// <exception cref="System.IO.IOException"></exception> 1311 /// <exception cref="System.Exception"></exception> 1312 public virtual string GetSocket() 1313 { 1314 TcpClient socket = this.queue.Take(); 1315 // ... same as socket() method ... 1316 string handle = this._enclosing.CreateHandle(socket); 1317 // start the reader 1318 org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.ByteConsumer 1319 (this._enclosing, handle, socket); 1320 reader_thread.Start(); 1321 this._enclosing.consumers[handle] = reader_thread; 1322 return handle; 1323 } 1324 1325 public virtual bool IsClosed() 1326 { 1327 return !mThread.IsAlive; 1328 } 1329 1330 /// <exception cref="System.IO.IOException"></exception> 1331 public void Close() 1332 { 1333 this.ssocket.Stop(); 1334 } 1335 1336 private readonly Threaded_IO_Style _enclosing; 1337 1338 #region IThread Members 1339 1340 private Thread mThread; 1341 public void Start() 1342 { 1343 mThread.Start(); 1344 } 1345 1346 public void SetDaemon(bool b) 1347 { 1348 mThread.IsBackground = b; 1349 } 1350 1351 #endregion 1352 1353 #region IJoinable Members 1354 1355 public void Join() 1356 { 1357 mThread.Join(); 1358 } 1359 1360 public void Interrupt() 1361 { 1362 mThread.Interrupt(); 1363 } 1364 1365 #endregion 1366 } 1367 1368 private sealed class CAccepter : org.jawk.ext.Threaded_IO_Style.Accepter 1369 { 1370 /// <exception cref="System.IO.IOException"></exception> 1371 public CAccepter(Threaded_IO_Style _enclosing, string handle, TcpListener 1372 ssocket) : base(_enclosing, handle, ssocket) 1373 { 1374 this._enclosing = _enclosing; 1375 } 1376 1377 /// <exception cref="System.IO.IOException"></exception> 1378 /// <exception cref="System.Exception"></exception> 1379 public sealed override string GetSocket() 1380 { 1381 TcpClient socket = this.queue.Take(); 1382 // ... same as socket() method ... 1383 string handle = this._enclosing.CreateHandle(socket); 1384 // start the reader 1385 org.jawk.jrt.IConsumer reader_thread = new org.jawk.ext.Threaded_IO_Style.CharacterConsumer 1386 (this._enclosing, handle, socket); 1387 reader_thread.Start(); 1388 this._enclosing.consumers[handle] = reader_thread; 1389 return handle; 1390 } 1391 1392 private readonly Threaded_IO_Style _enclosing; 1393 } 1394 1395 1396 1397 1398 1399 private abstract class AbstractConsumer<T> : IThread, org.jawk.jrt.IConsumer 1400 { 1401 private readonly string handle; 1402 1403 protected readonly TcpClient socket; 1404 1405 protected readonly System.IO.TextWriter ps; 1406 1407 private int state = org.jawk.ext.Threaded_IO_Style.ACTIVE_STATE; 1408 1409 protected java.util.BlockingQueue<T> queue = new java.util.BlockingQueue 1410 <T>(1); 1411 1412 // only 1 slot 1413 public bool WillBlock(org.jawk.jrt.BlockObject bo) 1414 { 1415 if (bo == this._enclosing.input_blocker) 1416 { 1417 return this.queue.Count == 0; 1418 } 1419 else 1420 { 1421 if (bo == this._enclosing.close_blocker) 1422 { 1423 return this.state == org.jawk.ext.Threaded_IO_Style.ACTIVE_STATE; 1424 } 1425 else 1426 { 1427 throw new System.Exception("Unknown block object : " + bo.GetNotifierTag()); 1428 } 1429 } 1430 } 1431 1432 /// <exception cref="System.IO.IOException"></exception> 1433 protected AbstractConsumer(Threaded_IO_Style _enclosing, string handle, TcpClient 1434 socket) 1435 { 1436 this._enclosing = _enclosing; 1437 this.handle = handle; 1438 //socket = sockets.get(handle); 1439 this.socket = socket; 1440 //assert socket != null; 1441 this.ps = new System.IO.StreamWriter(socket.GetStream()); 1442 1443 1444 mThread = new Thread(new ThreadStart(Run)); 1445 } 1446 1447 /// <exception cref="System.IO.IOException"></exception> 1448 protected abstract T ReadFromSocket(); 1449 1450 public void Run() 1451 { 1452 if (Thread.CurrentThread != this.mThread) 1453 { 1454 throw new System.Exception("Invalid thread access : " + Thread.CurrentThread); 1455 } 1456 try 1457 { 1458 T input; 1459 while ((input = this.ReadFromSocket()) != null) 1460 { 1461 this.queue.Put(input); 1462 lock (this._enclosing.input_blocker) 1463 { 1464 Monitor.Pulse(this._enclosing.input_blocker); 1465 } 1466 } 1467 } 1468 catch (System.Net.Sockets.SocketException se) 1469 { 1470 Console.Error.WriteLine(se); 1471 } 1472 catch (System.IO.IOException ioe) 1473 { 1474 // no big deal 1475 // assume we should just shutdown now 1476 Console.Error.WriteLine(ioe); 1477 } 1478 catch (System.Exception ie) 1479 { 1480 Console.Error.WriteLine(ie); 1481 throw new System.Exception("A queue operation cannot be interrupted."); 1482 } 1483 // no big deal 1484 lock (this._enclosing.close_blocker) 1485 { 1486 if (this.state == org.jawk.ext.Threaded_IO_Style.ACTIVE_STATE) 1487 { 1488 this.state = org.jawk.ext.Threaded_IO_Style.CLOSE_PENDING_STATE; 1489 Monitor.Pulse(this._enclosing.close_blocker); 1490 } 1491 } 1492 } 1493 1494 /// <exception cref="System.Exception"></exception> 1495 protected abstract string ReadFromQueue(); 1496 1497 /// <exception cref="System.Exception"></exception> 1498 public string GetInput() 1499 { 1500 //assert state != CLOSED_STATE; // active or close_pending 1501 string str = this.ReadFromQueue(); 1502 if (this.queue.Count == 0 && this.state 1503 == org.jawk.ext.Threaded_IO_Style.CLOSE_PENDING_STATE) 1504 { 1505 lock (this._enclosing.close_blocker) 1506 { 1507 // could be either ACTIVE or CLOSE_PENDING states 1508 //assert state != CLOSED_STATE; 1509 Monitor.Pulse(this._enclosing.close_blocker); 1510 } 1511 } 1512 return str; 1513 } 1514 1515 // write is defined in subclasses 1516 public int Flush() 1517 { 1518 this.ps.Flush(); 1519 return 1; 1520 } 1521 1522 public bool IsClosed() 1523 { 1524 return this.state == org.jawk.ext.Threaded_IO_Style.CLOSED_STATE; 1525 } 1526 1527 /// <exception cref="System.IO.IOException"></exception> 1528 public void Close() 1529 { 1530 this.socket.Close(); 1531 } 1532 1533 public abstract int Write(string arg1); 1534 1535 private readonly Threaded_IO_Style _enclosing; 1536 1537 #region IThread Members 1538 1539 private Thread mThread = null; 1540 public void Start() 1541 { 1542 mThread.Start(); 1543 } 1544 1545 public void SetDaemon(bool b) 1546 { 1547 mThread.IsBackground = b; 1548 } 1549 #endregion 1550 1551 #region IJoinable Members 1552 1553 public void Join() 1554 { 1555 mThread.Join(); 1556 } 1557 1558 public void Interrupt() 1559 { 1560 mThread.Interrupt(); 1561 } 1562 1563 #endregion 1564 } 1565 1566 private const int ACTIVE_STATE = 1; 1567 1568 private const int CLOSE_PENDING_STATE = 2; 1569 1570 private const int CLOSED_STATE = 3; 1571 1572 private sealed class CharacterConsumer : org.jawk.ext.Threaded_IO_Style.AbstractConsumer 1573 <string> 1574 { 1575 private readonly System.IO.StreamReader br; 1576 1577 /// <exception cref="System.IO.IOException"></exception> 1578 public CharacterConsumer(Threaded_IO_Style _enclosing, string handle, TcpClient 1579 socket) : base(_enclosing, handle, socket) 1580 { 1581 this._enclosing = _enclosing; 1582 // private abstract class AbstractConsumer<T> {Thread} [Consumer] 1583 // constructs socket (protected field in AbstractConsumer) 1584 this.br = new StreamReader(socket.GetStream()); 1585 } 1586 1587 ~CharacterConsumer() 1588 { 1589 this.br.Dispose(); 1590 } 1591 1592 /// <exception cref="System.IO.IOException"></exception> 1593 protected sealed override string ReadFromSocket() 1594 { 1595 return this.br.ReadLine(); 1596 } 1597 1598 /// <exception cref="System.Exception"></exception> 1599 protected sealed override string ReadFromQueue() 1600 { 1601 return this.queue.Take(); 1602 } 1603 1604 public sealed override int Write(string buf) 1605 { 1606 this.ps.WriteLine(buf); 1607 return 1; 1608 } 1609 1610 private readonly Threaded_IO_Style _enclosing; 1611 } 1612 1613 private sealed class ByteConsumer : org.jawk.ext.Threaded_IO_Style.AbstractConsumer 1614 <int?>…
Large files files are truncated, but you can click here to view the full file