home *** CD-ROM | disk | FTP | other *** search
/ Programmer's ROM - The Computer Language Library / programmersrom.iso / ada / misc / netio.src < prev    next >
Encoding:
Text File  |  1988-05-03  |  17.9 KB  |  554 lines

  1. --::::::::::
  2. --NETIO.DIS
  3. --::::::::::
  4. -- NETWORK_IO Prologue and Distribution Files
  5. NETIO.DIS
  6. NETIO.PRO
  7. -- NETWORK_IO Package Documentation
  8. NETIO.DOC
  9. -- NETWORK_IO in Compilation Order
  10. NETIO.SPC
  11. NETIO.BOD
  12. --::::::::::
  13. --NETIO.PRO
  14. --::::::::::
  15. -------- SIMTEL20 Ada Software Repository Prologue ------------
  16. --                                                           -*
  17. -- Unit name    : generic package NETWORK_IO
  18. -- Version      : 2.0
  19. -- Author       : Stanley R. Allen
  20. --              : Lockheed Engineering Management Services Company
  21. --              : Computer Systems Engineering Department  MS B08
  22. --              : Houston, TX  77258
  23. --              : (713) 333-6120
  24. -- DDN Address  : SALLEN%LOCK.SPAN@Jpl-VLSI.ARPA
  25. -- Copyright    : none
  26. -- Date created : Fri 31 Jul 87
  27. -- Release date : Mon 31 Aug 87
  28. -- Last update  : Mon 31 Aug 87
  29. -- Machine/System Compiled/Run on : VAX 11/785, VAX 8650
  30. --                                                           -*
  31. ---------------------------------------------------------------
  32. --                                                           -*
  33. -- Keywords     :  NETWORK, COMMUNICATION
  34. ----------------:
  35. --
  36. -- Abstract     :  This package provides an Ada interface to a
  37. ----------------:  communication network.  The model of the network
  38. ----------------:  is one that allows tasks on separate nodes to
  39. ----------------:  pass messages (message-passing).  The package
  40. ----------------:  is designed to be similar to the standard
  41. ----------------:  package SEQUENTIAL_IO, with the same basic
  42. ----------------:  operations, applicable to networks.  The
  43. ----------------:  idea of SEQUENTIAL_IO (just as for the other
  44. ----------------:  predefined I/O packages) is machine independent
  45. ----------------:  logical operations defined in the spec, and
  46. ----------------:  machine dependencies hidden in the private
  47. ----------------:  parts and the bodies.  Currently NETWORK_IO
  48. ----------------:  allows any typed link to be created between
  49. ----------------:  two VAX DECnet nodes.
  50. -- Dependent Units : package SYSTEM, STARLET, CONDITION_HANDLING,
  51. --                   IO_EXCEPTIONS, TASKING_SERVICES.
  52. --                                                           -*
  53. ------------------ Revision history ---------------------------
  54. --                                                           -*
  55. -- DATE         VERSION              AUTHOR     HISTORY
  56. -- 08/31/87     2.0               Allen      Updates
  57. --
  58. --    A number of changes have been made to version 1.0:
  59. --
  60. --    1)  The name of the abstraction is no longer FILE_TYPE,
  61. --        but is LINK_TYPE instead.  This just seemed to make
  62. --        more logical sense.  The only change made to the
  63. --        source to reflect this was the text substitution
  64. --        LINK for FILE throughout.  This includes the change
  65. --        from IN_FILE and OUT_FILE to IN_LINK and OUT_LINK
  66. --        for MODE_TYPE.  In old programs where you used
  67. --        version 1.0, just make the same global text
  68. --        substitution to upgrade, and recompile.
  69. --
  70. --    2)  The body has been changed to use the VAX's TASK_QIOW
  71. --        instead of STARLET.QIOW.  This means that now the
  72. --        network i/o READ and WRITE operation will not suspend
  73. --        the entire VMS process while waiting for completion,
  74. --        only the individual Ada task.
  75. --
  76. --    3)  The package no longer uses the VAX-specific 'MACHINE_SIZE
  77. --        attribute to determine the size of the message to be sent.
  78. --        Now 'SIZE is used on the object (as opposed to the type)
  79. --        to be sent.
  80. --
  81. --
  82. --                                                           -*
  83. ------------------ Distribution and Copyright -----------------
  84. --                                                           -*
  85. -- This prologue must be included in all copies of this software.
  86. --
  87. -- This software is released to the Ada community.
  88. -- This software is released to the Public Domain (note:
  89. --   software released to the Public Domain is not subject
  90. --   to copyright protection).
  91. -- Restrictions on use or distribution:  NONE
  92. --                                                           -*
  93. ------------------ Disclaimer ---------------------------------
  94. --                                                           -*
  95. -- This software and its documentation are provided "AS IS" and
  96. -- without any expressed or implied warranties whatsoever.
  97. -- No warranties as to performance, merchantability, or fitness
  98. -- for a particular purpose exist.
  99. --
  100. -- Because of the diversity of conditions and hardware under
  101. -- which this software may be used, no warranty of fitness for
  102. -- a particular purpose is offered.  The user is advised to
  103. -- test the software thoroughly before relying on it.  The user
  104. -- must assume the entire risk and liability of using this
  105. -- software.
  106. --
  107. -- In no event shall any person or organization of people be
  108. -- held responsible for any direct, indirect, consequential
  109. -- or inconsequential damages or lost profits.
  110. --                                                           -*
  111. -------------------END-PROLOGUE--------------------------------
  112. -------
  113. --::::::::::
  114. --NETIO.DOC
  115. --::::::::::
  116.  
  117.  
  118.     How to use the NETWORK_IO and NETWORK_MIXED_IO packages.
  119.  
  120.     These packages provide an interface to DECnet task-to-task
  121. communication.  In each of the packages, in the CREATE procedure,
  122. a full task-specification string is to be used for the NAME parameter.
  123. The network link is abstracted as the limited private data type LINK_TYPE.
  124.  
  125.     Here are two programs showing the use of the NETWORK_IO
  126. package.  The first program is run on the node called SOURCE, and the
  127. second is placed on a node called TARGET.  At the node TARGET there is
  128. a command procedure called GENERATE.COM which contains the single line
  129. $ run GENERATE.exe .  To get the whole thing going, the PROCESS program
  130. is run on the SOURCE node:  $ RUN PROCESS.  
  131.  
  132.     --| On the node SOURCE.
  133.     with NETWORK_IO, TEXT_IO;
  134.     procedure PROCESS is
  135.  
  136.       TARGET : constant STRING
  137.         := "TARGET""username password""::""0=GENERATE""";
  138.  
  139.       type A_RECORD is  -- something to read from the TARGET node
  140.         record
  141.           INT : INTEGER;
  142.           FLT : FLOAT;
  143.         end record;
  144.  
  145.         --| Instantiate the NETWORK_IO package for the above type.
  146.       package NET_IO is new NETWORK_IO (A_RECORD);
  147.       use NET_IO;
  148.  
  149.       AREC  : A_RECORD;
  150.       ILINK : NET_IO.LINK_TYPE;   --| Or communication link
  151.  
  152.       procedure DO_SOMETHING_WITH_THE_DATA (A : in A_RECORD) is
  153.         --| Just print the data out.
  154.         package FLOAT_IO is new TEXT_IO.FLOAT_IO(FLOAT);
  155.         package INT_IO is new TEXT_IO.INTEGER_IO(INTEGER);
  156.       begin
  157.         INT_IO.PUT(A.INT); TEXT_IO.NEW_LINE;
  158.         FLOAT_IO.PUT(A.FLT, FORE => 5, AFT => 5, EXP => 0);
  159.         TEXT_IO.NEW_LINE;
  160.       end;
  161.  
  162.     begin
  163.       NET_IO.CREATE(ILINK, IN_LINK, NAME => TARGET);
  164.         --| CREATE, not OPEN, the link.
  165.       for I in 1..100 loop
  166.         NET_IO.READ (ILINK, AREC);
  167.         DO_SOMETHING_WITH_THE_DATA (AREC);
  168.       end loop;
  169.  
  170.       NET_IO.CLOSE(ILINK);
  171.     end PROCESS;
  172.  
  173.  
  174.  
  175.     with NETWORK_IO;
  176.     procedure GENERATE is  -- on node TARGET.
  177.  
  178.       type A_RECORD is  -- something to read from the TARGET node
  179.         record
  180.           INT : INTEGER;
  181.           FLT : FLOAT;
  182.         end record;
  183.  
  184.         --| Instantiate the NETWORK_IO package for the above type.
  185.       package NET_IO is new NETWORK_IO (A_RECORD);
  186.       use NET_IO;
  187.  
  188.       AREC  : A_RECORD;
  189.       ILINK : NET_IO.LINK_TYPE;    --| Our communication link
  190.       I     : INTEGER  := 1;
  191.       F     : FLOAT    := 0.0;
  192.  
  193.       procedure GENERATE_DATA (A : out A_RECORD) is
  194.       begin
  195.         A.INT := I;
  196.         A.FLT := F;
  197.         I := I + 1;
  198.         F := F + 10.0;
  199.       end;
  200.  
  201.     begin
  202.       NET_IO.OPEN (ILINK, OUT_LINK);
  203.         --| OPEN, not CREATE the link.
  204.       for I in 1..100 loop
  205.         GENERATE_DATA (AREC);
  206.         NET_IO.WRITE (ILINK, AREC);
  207.       end loop;
  208.       NET_IO.CLOSE(ILINK);
  209.     end GENERATE;
  210.  
  211.  
  212.     The package NETWORK_MIXED_IO is very similar, except that it
  213. allows multiple types to be passed along a link.  NETWORK_MIXED_IO is
  214. not generic, but contains two generic procedures, READ and WRITE, which
  215. are instantiated for each type that is to be passed.  NETWORK_MIXED_IO
  216. is probably the more useful of the two packages.
  217.     Here is a program which uses NETWORK_MIXED_IO for network
  218. communication.  Of course, another program, not shown, is to be placed
  219. on the TARGET node. The package NET_TYPES is used by both programs. The
  220. procedure REQUEST is run on the node SOURCE and SUPPLY is on the
  221. node TARGET.  The command procedure SUPPLY.COM is also to be placed on
  222. TARGET and contains the single line "$ run SUPPLY.exe".  The program
  223. SUPPLY should be written corresponding to the protocol defined by
  224. this program.
  225.     (By the way, this brings up the important point: you have to
  226. define your own application protocol for the use of this network stuff.
  227. Rather than re-create a new protocol for each application, it should be
  228. fairly easy to create generic packages and procedures based on NETWORK_IO
  229. and NETWORK_MIXED_IO which implement (re-useably) such common protocols
  230. as the one used here REQUEST/SUPPLY....).
  231.  
  232.  
  233.     package NET_TYPES is
  234.  
  235.         type REQUEST_TYPE is (RTYPE_1, RTYPE_2, RTYPE_3, STOP);
  236.  
  237.         type TYPE_1 is array (1..40) of INTEGER;
  238.  
  239.         type TYPE_2 is
  240.           record
  241.         C : CHARACTER;
  242.             Q : BOOLEAN;
  243.             I : INTEGER range 0..127;
  244.           end record;
  245.         for TYPE_2 use
  246.           record
  247.         C at 0 range 0..7;
  248.         Q at 1 range 0..0;
  249.         I at 1 range 1..7;
  250.           end record;
  251.         for TYPE_2'SIZE use 16;
  252.  
  253.         type TYPE_3 is range 0..31;
  254.         for TYPE_3'SIZE use 5;
  255.  
  256.     end NET_TYPES;
  257.  
  258.  
  259.     --| On node SOURCE
  260.     with NET_TYPES, NETWORK_MIXED_IO, TEXT_IO;
  261.     use NET_TYPES, TEXT_IO;
  262.     procedure REQUEST is
  263.  
  264.         TARGET : constant STRING :=
  265.         "TARGET""user passwd""::""0=SUPPLY""";
  266.  
  267.         package NMIO renames NETWORK_MIXED_IO;
  268.  
  269.         A : NET_TYPES.TYPE_1;
  270.         B : NET_TYPES.TYPE_2;
  271.         C : NET_TYPES.TYPE_3;
  272.         R : NET_TYPES.REQUEST_TYPE;
  273.         L : NMIO.LINK_TYPE;
  274.  
  275.         procedure REQ_WRITE is
  276.         new NMIO.WRITE (NET_TYPES.REQUEST_TYPE);
  277.         procedure T1_READ is
  278.         new NMIO.READ (NET_TYPES.TYPE_1);
  279.         procedure T2_READ is
  280.         new NMIO.READ (NET_TYPES.TYPE_2);
  281.         procedure T3_READ is
  282.         new NMIO.READ (NET_TYPES.TYPE_3);
  283.         use NMIO;
  284.  
  285.         function MENU return NET_TYPES.REQUEST_TYPE is
  286.         CH      : CHARACTER;
  287.         begin
  288.         loop
  289.             PUT_LINE("Which type to receive?: "); 
  290.             PUT_LINE("A  --  type 1");
  291.             PUT_LINE("B  --  type 2");
  292.             PUT_LINE("C  --  type 3");
  293.             PUT_LINE("Q  --  exit program, close link");
  294.             NEW_LINE; PUT("Which one? : "); GET(CH);
  295.             if CH = 'A' or CH = 'a' then
  296.             return RTYPE_1;
  297.             elsif CH = 'B' or CH = 'b' then
  298.             return RTYPE_2;
  299.             elsif CH = 'C' or CH = 'c' then
  300.             return RTYPE_3;
  301.             elsif CH = 'Q' or CH = 'q' then
  302.             return STOP;
  303.             else
  304.             PUT_LINE ("Bad Choice, reenter"); 
  305.             end if;
  306.         end loop;
  307.         end MENU;
  308.  
  309.     begin
  310.         NMIO.CREATE(L, INOUT_LINK, NAME => TARGET);
  311.         --| remember: OPEN will complete the VC link on the other side.
  312.         loop
  313.           R := MENU;
  314.           exit when R = STOP;
  315.           REQ_WRITE (LINK => L, ITEM => R);
  316.           case R is
  317.         when RTYPE_1 => T1_READ(L, A); --| Ideally, a procedure for
  318.         when RTYPE_2 => T2_READ(L, B); --| each type which processes
  319.         when RTYPE_3 => T3_READ(L, C); --| the incoming data would
  320.         when others => null;           --| go after each READ here.
  321.           end case;
  322.         end loop;
  323.         REQ_WRITE(L, STOP);
  324.         NMIO.CLOSE(L);
  325.     end REQUEST;
  326.  
  327. -----
  328. This pseudocode describes just one possible protocol.  Basically
  329. any protocol is possible.
  330.  
  331. Source Loop Pseudocode            Target Loop Pseudocode
  332. ----------------------            ----------------------
  333.  
  334. Determine request  (MENU)
  335. Netio.Write (request)            Netio.Read (request)
  336. case (request) is            case (request) is
  337.   when type1 => Netio.Read(type1)      when type1 => Netio.Write(type1)
  338.   when type2 => Netio.Read(type2)      when type2 => Netio.Write(type2)
  339.   ...                      ...
  340. end case                end case
  341. --------------------------------------------------------------------------
  342. --::::::::::
  343. --NETIO.SPC
  344. --::::::::::
  345. with STARLET;
  346. with IO_EXCEPTIONS;
  347. generic
  348.     type MESSAGE_TYPE is private;
  349. package NETWORK_IO is
  350.  
  351.     type LINK_TYPE is limited private;
  352.     type LINK_MODE is (IN_LINK, OUT_LINK);
  353.  
  354.     procedure CREATE(               --| Create a VC link to remote PE.
  355.         LINK : in out LINK_TYPE;    --| LINK: logical name.
  356.         MODE : in LINK_MODE;        --| MODE: IN_LINK, OUT_LINK.
  357.         NAME : in STRING := "";     --| NAME: Physical name of remote PE.
  358.         FORM : in STRING := "");    --| FORM: Special local parameters.
  359.  
  360.     procedure OPEN (                --| Complete a VC link to remote PE.
  361.         LINK : in out LINK_TYPE;    --| LINK: logical name.
  362.         MODE : in LINK_MODE;        --| MODE: IN_LINK, OUT_LINK.
  363.         NAME : in STRING := "";     --| NAME: Physical name of remote PE.
  364.         FORM : in STRING := "");    --| FORM: Special local parameters.
  365.  
  366.     procedure CLOSE (LINK : in out LINK_TYPE);  --| Disconnect VC.
  367.  
  368.     procedure READ (LINK : in LINK_TYPE;
  369.             ITEM : out MESSAGE_TYPE);
  370.  
  371.     procedure WRITE (LINK : in LINK_TYPE;
  372.              ITEM : in MESSAGE_TYPE);
  373.  
  374.     STATUS_ERROR : exception renames IO_EXCEPTIONS.STATUS_ERROR;
  375.     MODE_ERROR   : exception renames IO_EXCEPTIONS.MODE_ERROR;
  376.     NAME_ERROR   : exception renames IO_EXCEPTIONS.NAME_ERROR;
  377.     USE_ERROR    : exception renames IO_EXCEPTIONS.USE_ERROR;
  378.     DEVICE_ERROR : exception renames IO_EXCEPTIONS.DEVICE_ERROR;
  379.  
  380. private
  381.  
  382.     type LINK_STATUS is (OPEN, CLOSED);
  383.     type LINK_TYPE is
  384.       record
  385.         CHAN : STARLET.CHANNEL_TYPE;
  386.         MODE : LINK_MODE;
  387.         STAT : LINK_STATUS := CLOSED;
  388.       end record;
  389.  
  390. end NETWORK_IO;
  391. --::::::::::
  392. --NETIO.BOD
  393. --::::::::::
  394. with    SYSTEM,
  395.     STARLET,
  396.     TASKING_SERVICES,
  397.     CONDITION_HANDLING;
  398. use    SYSTEM,
  399.     STARLET;
  400. package body NETWORK_IO is
  401.  
  402.  
  403.     --|
  404.     --| CREATE creates a link to the remote task specified
  405.     --| in the string NAME.  The system service $ASSIGN is
  406.     --| used to do this.
  407.     --|
  408.  
  409.     procedure CREATE (
  410.         LINK : in out LINK_TYPE;
  411.         MODE : in LINK_MODE;
  412.         NAME : in STRING := "";
  413.         FORM : in STRING := "")
  414.     is
  415.         STAT : CONDITION_HANDLING.COND_VALUE_TYPE;
  416.     begin
  417.       if LINK.STAT = OPEN then
  418.         raise STATUS_ERROR;
  419.       end if;
  420.  
  421.       STARLET.ASSIGN (STAT, NAME, LINK.CHAN);
  422.  
  423.       if not CONDITION_HANDLING.SUCCESS(STAT) then 
  424.         case STAT is
  425.         when SS_CONNECFAIL | SS_DEVOFFLINE | SS_INSFMEM | SS_SHUT |
  426.                SS_NOLINKS | SS_PROTOCOL | SS_UNREACHABLE | SS_REJECT |
  427.                SS_REMRSRC | SS_THIRDPARTY | SS_LINKEXIT =>
  428.                 raise DEVICE_ERROR;
  429.         when SS_INVLOGIN | SS_IVDEVNAM | SS_NOSUCHNODE |
  430.                SS_NOSUCHUSER | SS_NOSUCHOBJ  =>
  431.                 raise NAME_ERROR;
  432.         when SS_NOPRIV |  SS_TOOMUCHDATA =>
  433.                 raise USE_ERROR;
  434.         when others => null;
  435.         end case;
  436.       end if;
  437.       LINK.STAT := OPEN;
  438.       LINK.MODE := MODE;
  439.     end CREATE;
  440.  
  441.     procedure OPEN (
  442.         LINK : in out LINK_TYPE;
  443.         MODE : in LINK_MODE;
  444.         NAME : in STRING := "";
  445.         FORM : in STRING := "")
  446.     is
  447.         STAT : CONDITION_HANDLING.COND_VALUE_TYPE;
  448.     begin
  449.       if LINK.STAT = OPEN then
  450.         raise STATUS_ERROR;
  451.       end if;
  452.  
  453.       STARLET.ASSIGN (STAT, "SYS$NET", LINK.CHAN);
  454.  
  455.       if not CONDITION_HANDLING.SUCCESS(STAT) then 
  456.         case STAT is
  457.         when SS_CONNECFAIL | SS_DEVOFFLINE | SS_INSFMEM | SS_SHUT |
  458.                SS_NOLINKS | SS_PROTOCOL | SS_UNREACHABLE | SS_REJECT |
  459.                SS_REMRSRC | SS_THIRDPARTY | SS_LINKEXIT =>
  460.                 raise DEVICE_ERROR;
  461.         when SS_INVLOGIN | SS_IVDEVNAM | SS_NOSUCHNODE |
  462.                SS_NOSUCHUSER | SS_NOSUCHOBJ  =>
  463.                 raise NAME_ERROR;
  464.         when SS_NOPRIV |  SS_TOOMUCHDATA =>
  465.                 raise USE_ERROR;
  466.         when others => null;
  467.         end case;
  468.       end if;
  469.       LINK.STAT := OPEN;
  470.       LINK.MODE := MODE;
  471.     end OPEN;
  472.  
  473.  
  474.     --|
  475.     --| Terminate the logical link, using STARLET.DASSGN.
  476.     --|
  477.  
  478.     procedure CLOSE (LINK : in out LINK_TYPE) is
  479.         STAT : CONDITION_HANDLING.COND_VALUE_TYPE;
  480.     begin
  481.       if LINK.STAT = CLOSED then raise STATUS_ERROR; end if;
  482.       STARLET.DASSGN(STAT, LINK.CHAN);
  483.       if not CONDITION_HANDLING.SUCCESS(STAT) then
  484.         raise USE_ERROR; --| USE_ERROR for SS$_NOPRIV and SS$_IVCHAN
  485.       end if;
  486.       LINK.STAT := CLOSED;
  487.     end CLOSE;
  488.  
  489.  
  490.     procedure READ (LINK : in LINK_TYPE;
  491.             ITEM : out MESSAGE_TYPE)
  492.     is
  493.         STAT : CONDITION_HANDLING.COND_VALUE_TYPE;
  494.         IOSB : STARLET.IOSB_TYPE;
  495.         MSIZE : SYSTEM.UNSIGNED_LONGWORD       --| Size of ITEM in bytes
  496.         := ITEM'SIZE/SYSTEM.STORAGE_UNIT;
  497.     begin
  498.         if LINK.STAT = CLOSED then raise STATUS_ERROR; end if;
  499.         if LINK.MODE = OUT_LINK then raise MODE_ERROR; end if;
  500.         TASKING_SERVICES.TASK_QIOW (
  501.         STATUS => STAT,
  502.         CHAN   => LINK.CHAN,
  503.         FUNC   => IO_READVBLK,
  504.         IOSB   => IOSB,
  505.         P1     => SYSTEM.TO_UNSIGNED_LONGWORD (ITEM'ADDRESS),
  506.         P2     => MSIZE);
  507.         if not CONDITION_HANDLING.SUCCESS(STAT) then
  508.           case STAT is
  509.         when SS_DATAOVERUN | SS_INSFMEM | SS_PATHLOST |
  510.              SS_LINKEXIT | SS_PROTOCOL | SS_LINKABORT |
  511.              SS_LINKDISCON | SS_THIRDPARTY =>
  512.             raise DEVICE_ERROR;
  513.         when SS_FILNOTACC =>
  514.             raise USE_ERROR;
  515.         when others => null;
  516.           end case;
  517.         end if;
  518.         if IOSB.STATUS /= SS_NORMAL then raise DEVICE_ERROR; end if;
  519.     end READ;
  520.  
  521.  
  522.     procedure WRITE (LINK : in LINK_TYPE;
  523.              ITEM : in MESSAGE_TYPE)
  524.     is
  525.         STAT : CONDITION_HANDLING.COND_VALUE_TYPE;
  526.         IOSB : STARLET.IOSB_TYPE;
  527.         MSIZE : SYSTEM.UNSIGNED_LONGWORD       --| Size of ITEM in bytes
  528.         := ITEM'SIZE/SYSTEM.STORAGE_UNIT;
  529.     begin
  530.         if LINK.STAT = CLOSED then raise STATUS_ERROR; end if;
  531.         if LINK.MODE = IN_LINK then raise MODE_ERROR; end if;
  532.         TASKING_SERVICES.TASK_QIOW (
  533.         STATUS => STAT,
  534.         CHAN   => LINK.CHAN,
  535.         FUNC   => IO_WRITEVBLK,
  536.         IOSB   => IOSB,
  537.         P1     => SYSTEM.TO_UNSIGNED_LONGWORD (ITEM'ADDRESS),
  538.         P2     => MSIZE);
  539.         if not CONDITION_HANDLING.SUCCESS(STAT) then
  540.           case STAT is
  541.         when SS_DATAOVERUN | SS_INSFMEM | SS_PATHLOST |
  542.              SS_LINKEXIT | SS_PROTOCOL | SS_LINKABORT |
  543.              SS_LINKDISCON | SS_THIRDPARTY =>
  544.             raise DEVICE_ERROR;
  545.         when SS_FILNOTACC =>
  546.             raise USE_ERROR;
  547.         when others => null;
  548.           end case;
  549.         end if;
  550.         if IOSB.STATUS /= SS_NORMAL then raise DEVICE_ERROR; end if;
  551.     end WRITE;
  552.  
  553. end NETWORK_IO;
  554.