home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1649 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  16.7 KB

  1. From: yukngo@obelix.gaul.csd.uwo.ca (Cheung Yukngo)
  2. Newsgroups: alt.sources
  3. Subject: A domain name library in perl
  4. Message-ID: <YUKNGO.90Aug6204914@obelix.gaul.csd.uwo.ca>
  5. Date: 6 Aug 90 19:49:14 GMT
  6.  
  7. A few months ago I wrote a program called pns and posted it in
  8. comp.lang.perl. I then realised that the program could be a lot more
  9. useful as a library. So, this is the library version of pns. The
  10. documentation is very bad (as usual) but you probably need to read
  11. RFC1035 which contains all the information about domain name service
  12. if you ask more than just IP addresses from hostnames.
  13.  
  14. Please let me know if you find a bug.
  15.  
  16. clipper@csd.uwo.ca
  17.  
  18. #! /bin/sh
  19. # This is a shell archive, meaning:
  20. # 1. Remove everything above the #! /bin/sh line.
  21. # 2. Save the resulting text in a file.
  22. # 3. Execute the file with /bin/sh (not csh) to create the files:
  23. #    nslib.doc
  24. #    nslib.perl
  25. #
  26. if test -f 'nslib.doc'
  27. then
  28.     echo shar: will not over-write existing file "'nslib.doc'"
  29. else
  30.     echo x - 'nslib.doc'
  31.     sed 's/^X//' >'nslib.doc' << 'SHAR_EOF'
  32. X# Copyright 1990 Khun Yee Fung <clipper@csd.uwo.ca>
  33. X#
  34. X# Permission to use, copy, modify, and distribute, this software and its
  35. X# documentation for any purpose is hereby granted without fee, provided that
  36. X# the above copyright notice appear in all copies and that both that
  37. X# copyright notice and this permission notice appear in supporting
  38. X# documentation, and that the name of the copyright holders be used in
  39. X# advertising or publicity pertaining to distribution of the software with
  40. X# specific, written prior permission, and that no fee is charged for further
  41. X# distribution of this software, or any modifications thereof.  The copyright
  42. X# holder make no representations about the suitability of this software for
  43. X# any purpose.  It is provided "as is" without express or implied warranty.
  44. X#
  45. X# THE COPYRIGHT HOLDER DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  46. X# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  47. X# EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  48. X# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  49. X# DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
  50. X# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  51. X# PERFORMANCE OF THIS SOFTWARE.
  52. X
  53. Xnslib is a library for Perl providing domain name client services. If
  54. Xyou find any errors, please let me know.
  55. X
  56. XPlease give the name server you use in the line marked by # *** in the
  57. Xpackage.
  58. X
  59. XThe library consists of three subroutines callable from the main
  60. Xprogram. The first one is called nsinit(). This subroutine initialises
  61. Xthe server connection. The second one is called nsend(). This should
  62. Xbe used to shut down the server connection. The third one is called
  63. Xnsquery().
  64. X
  65. Xnsinit() 
  66. X
  67. X  Parameter - optional one parameter to give the server address. The
  68. X  IP address of the server should be known by the machine you are
  69. X  using (either its IP address is in /etc/hosts or it is given by its
  70. X  IP address).
  71. X
  72. X  Error codes:
  73. X    255 - More than one paramter
  74. X    254 - nsinit can't find the IP address of the server
  75. X    253 - can't use socket
  76. X    252 - can't use connect
  77. X
  78. Xnsend()
  79. X
  80. X    shut down the server. No error code.
  81. X
  82. Xnsquery()
  83. X
  84. X  Parameters: exactly two parameters
  85. X    option - the type of query required. These include
  86. X      Address - returns the IP address
  87. X      Name server - the name server for the host given
  88. X      Mail destination - no idea what this is used for
  89. X      Mail forwarder - ditto
  90. X      Canonical name - returns the canonical name for the host name given
  91. X      Zone of authority - no idea
  92. X      Mailbox - dunno
  93. X      Mail group - dunno
  94. X      Mail rename - dunno
  95. X      Null - apparently nothing
  96. X      Services - well known services provided by the host given
  97. X      Domain name - return the host name given an IP address
  98. X      Host info - CPU and OS of the host
  99. X      Mailbox info - beats me
  100. X      Mail exchange - for the mail wizard
  101. X      Text - dunno
  102. X      Transfer of zone - no idea
  103. X      Mail record - dunno
  104. X      Mail agent - no idea
  105. X      Everything - returns everything the name server knows about the host
  106. X
  107. X    If you are more curious than me, read RFC1035 for the full
  108. X    information. I actually implemented this program using the
  109. X    information there but just too lazy to fill in the infotmation I
  110. X    never care to know. If you are interested, feel free to fill in
  111. X    the information and send me a copy too.
  112. X  
  113. X    Hostname: The second parameter. This should either be a hostname
  114. X    or a IP address, depending whether the name server is expecting a
  115. X    hostname or a IP address. If you want to know the IP address of
  116. X    tut.cis.ohio-state.edu, for example, you should give
  117. X    "tut.cis.ohio-state.edu" as the hostname. But if you want to know
  118. X    the hostname of 128.64.18.60, you should give "128.64.18.60". Yes,
  119. X    the program will reverse the IP address and add "in-addr.arpa" for
  120. X    you.
  121. X
  122. X  Output: nsquery returns an ASSOCIATE ARRAY. So be prepared to catch
  123. X  an associative array. The possible keys for the array are the same
  124. X  as the options for nsquery with the following additional keys:
  125. X    Error - 0 if nothing is wrong. Else, error.
  126. X      251 - parameter number is not 2
  127. X      250 - no such option
  128. X      1   - format error
  129. X      2   - server failure
  130. X      3   - name error
  131. X      4   - not implemented
  132. X      5   - refused
  133. X    Message - the string version of Error.
  134. X    AA - whether the answer is authoritative
  135. X    QR - what kind of query it was
  136. X    Truncation - whether the answer has been truncated or not
  137. X    Recursion desired - yes for this program
  138. X    Recursion available - whether the name server has recursion
  139. X    Address - the value of this key contains all the hosts with IP
  140. X      addresses found in the query. The hostnames will be used as keys
  141. X      to store the IP addresses.
  142. X
  143. X  Examples:
  144. X    &nsquery('Host info', 'tut.cis.ohio-state.edu');
  145. X    &nsquery('Domain name', '129.100.11.2');
  146. X
  147. X
  148. XWarning: I assume $[ to be 0. It is also the first time I used
  149. Xpackage, I have no idea whether I used it right or wrong. You must
  150. Xalso initialise the $server variable in nslib.perl. I don't want to
  151. Xinclude the domain name server we use.
  152. X
  153. XWish list:
  154. X  1. Some sort of documentation for the library (want to take a shot
  155. X     at this?)
  156. X  2. Multiple queries at the same time.
  157. X
  158. XExample program:
  159. X#!/u3/thesis/clipper/pl/perl
  160. X
  161. Xdo 'nslib.perl || die "Can't do nslib.perl";
  162. X
  163. Xif(&nsinit() != 0) {
  164. X    print "Can't open server\n";
  165. X    exit(1);
  166. X}
  167. X%reply1 = &nsquery('Host info', 'tut.cis.ohio-state.edu');
  168. X%reply2 = &nsquery('Domain name', '129.100.11.2');
  169. X&nsend();
  170. Xprint "reply 1\n";
  171. X@keys = keys(%reply1);
  172. Xforeach $key (@keys) {
  173. X    print $key, '    :', $reply1{$key}, "\n";
  174. X}
  175. Xprint "reply 2\n";
  176. X@keys = keys(%reply2);
  177. Xforeach $key (@keys) {
  178. X    print $key, ' ', $reply2{$key}, "\n";
  179. X}
  180. SHAR_EOF
  181. if test 5791 -ne "`wc -c < 'nslib.doc'`"
  182. then
  183.     echo shar: error transmitting "'nslib.doc'" '(should have been 5791 characters)'
  184. fi
  185. fi
  186. if test -f 'nslib.perl'
  187. then
  188.     echo shar: will not over-write existing file "'nslib.perl'"
  189. else
  190.     echo x - 'nslib.perl'
  191.     sed 's/^X//' >'nslib.perl' << 'SHAR_EOF'
  192. X#!/u3/thesis/clipper/pl/perl
  193. X# Copyright 1990 by Khun Yee Fung <clipper@csd.uwo.ca>
  194. X# See nslib.doc for warranty information
  195. X# $Source: /u3/thesis/clipper/pl/RCS/pns,v $
  196. X# $Id: pns,v 1.3 90/05/12 16:29:58 clipper Exp $
  197. X
  198. Xpackage domainname;
  199. X
  200. X$sockaddr = 'S n a4 x8';
  201. X$port = 53;
  202. X%question = ('Address', 1, 'Name server', 2, 'Mail destination', 3,
  203. X         'Mail forwarder', 4, 'Canonical name', 5, 'Zone of authority',
  204. X         6, 'Mailbox', 7, 'Mail group', 8, 'Mail rename', 9, 'Null', 10,
  205. X         'Services', 11, 'Domain name', 12, 'Host info', 13,
  206. X         'Mailbox info', 14, 'Mail exchange', 15, 'Text', 16,
  207. X         'Transfer of zone', 252, 'Mail record', 253, 'Mail agent', 254,
  208. X         'Everything', 255);
  209. X@question = ('', 'Address', 'Name server', 'Mail destination',
  210. X         'Mail forwarder', 'Canonical name', 'Zone of authority',
  211. X         'Mailbox', 'Mail group', 'Mail rename', 'Null', 'Services',
  212. X         'Domain name', 'Host info', 'Mailbox info', 'Mail exchange',
  213. X         'Text');
  214. X
  215. X@bits = (0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
  216. X  0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001);
  217. X$PORTS[5] = "RJE"; $PORTS[7] = "ECHO"; $PORTS[9] = "DISCARD";
  218. X$PORTS[11] = "USERS"; $PORTS[13] = "DAYTIME"; $PORTS[17] = "QUOTE";
  219. X$PORTS[19] = "CHARGEN"; $PORTS[20] = "FTP-DATA"; $PORTS[21] = "FTP";
  220. X$PORTS[23] = "TELNET"; $PORTS[25] = "SMTP"; $PORTS[27] = "NSW-FE";
  221. X$PORTS[29] = "MSG-ICP"; $PORTS[31] = "MSG-AUTH"; $PORTS[33] = "DSP";
  222. X$PORTS[37] = "TIME"; $PORTS[39] = "RLP"; $PORTS[41] = "GRAPHICS";
  223. X$PORTS[42] = "NAMESERVER"; $PORTS[43] = "NICNAME"; $PORTS[44] = "MPM-FLAGS";
  224. X$PORTS[45] = "MPM"; $PORTS[46] = "MPM-SND"; $PORTS[47] = "NI-FTP";
  225. X$PORTS[49] = "LOGIN"; $PORTS[51] = "LA-MAINT"; $PORTS[53] = "DOMAIN";
  226. X$PORTS[55] = "ISI-GL"; $PORTS[61] = "NI-MAIL"; $PORTS[63] = "VIA-FTP";
  227. X$PORTS[65] = "TACACS-DS"; $PORTS[67] = "BOOTPS"; $PORTS[68] = "BOOTPC";
  228. X$PORTS[69] = "TFTP"; $PORTS[71] = "NETRJS-1"; $PORTS[72] = "NETRJS-2";
  229. X$PORTS[73] = "NETRJS-3"; $PORTS[64] = "NETRJS-4"; $PORTS[79] = "FINGER";
  230. X$PORTS[81] = "HOSTS-NS"; $PORTS[83] = "MIT-ML-DEV"; $PORTS[85] = "MIT-ML-DEV";
  231. X$PORTS[89] = "SU-MIT-TG"; $PORTS[91] = "MIT-DOV"; $PORTS[93] = "DCP";
  232. X$PORTS[95] = "SUPDUP"; $PORTS[97] = "SWIFT-RVF"; $PORTS[98] = "TACNEWS";
  233. X$PORTS[99] = "METAGRAM"; $PORTS[101] = "HOSTNAME"; $PORTS[102] = "ISO-TSAP";
  234. X$PORTS[103] = "X400"; $PORTS[104] = "X400-SND"; $PORTS[105] = "CSNET-NS";
  235. X$PORTS[107] = "RTELNET"; $PORTS[109] = "POP2"; $PORTS[111] = "SUNRPC";
  236. X$PORTS[113] = "AUTH"; $PORTS[115] = "SFTP"; $PORTS[117] = "UUCP-PATH";
  237. X$PORTS[119] = "NNTP"; $PORTS[121] = "ERPC"; $PORTS[123] = "NTP";
  238. X$PORTS[125] = "LOCUS-MAP"; $PORTS[127] = "LOCUS-CON"; $PORTS[129] = "PWDGEN";
  239. X$PORTS[130] = "CISCO-FNA"; $PORTS[131] = "CISCO-TNA"; 
  240. X$PORTS[132] = "CISCO-SYS"; $PORTS[133] = "STATSRV"; $PORTS[134] = "INGRES-NET";
  241. X$PORTS[135] = "LOC-SRV"; $PORTS[136] = "PROFILE"; $PORTS[137] = "NETBIOS-NS";
  242. X$PORTS[138] = "NETBIOS-DGM"; $PORTS[139] = "NETBIOS-SSN"; 
  243. X$PORTS[140] = "EMFIS-DATA"; $PORTS[141] = "EMFIS-CNTL"; $PORTS[142] = "BL-IDM";
  244. X
  245. X@QR = ("query", "response");
  246. X@OPCODE = ("QUERY", "IQUERY", "STATUS");
  247. X@AA = ("Non-Authoritive", "Authoritive");
  248. X@TC = ("Not Truncated", "Truncated");
  249. X@RD = ("Don't recurse", "Do Recurse");
  250. X@RA = ("No recursion", "Has recursion");
  251. X@RCODE = ("No error", "Format error", "Server Failure", "Name error",
  252. X      "Not implemented", "Refused");
  253. X@PROTOCOL = ("", "ICMP", "IGMP", "GGP", "", "ST", "TCP", "UCL", "EGP",
  254. X  "IGP", "BBN-RCC-MON", "NVP-II", "PUP", "ARGUS", "EMCON", "XNET", "CHAOS",
  255. X  "UDP", "MUX", "DCN-MEAS", "HMP", "PRM", "XNS-IDP", "TRUNK1", "TRUNK2",
  256. X  "LEAF1", "LEAF2", "RDP", "IRTP", "ISO-TP4", "NETBLT", "MFE-NSP", "MERIT-INP",
  257. X  "SEP");
  258. X$PROTOCOL[62] = "CFTP"; $PROTOCOL[64] = "SAT-EXPAK";
  259. X$PROTOCOL[65] = "MIT-SUBNET"; $PROTOCOL[66] = "RVD"; $PROTOCOL[67] = "IPPC";
  260. X$PROTOCOL[69] = "SAT-MON"; $PROTOCOL[71] = "IPCV"; 
  261. X$PROTOCOL[76] = "BR-SAT-MON"; $PROTOCOL[78] = "WB-MON";
  262. X$PROTOCOL[79] = "WB-EXPAK";
  263. X
  264. Xsub main'nsinit {
  265. X    if ($#_ == $[) {
  266. X    $server = $_[0];
  267. X    }
  268. X    elsif ($#_ > $[) {
  269. X    return 255;
  270. X    }
  271. X    else {
  272. X    # *** Give the name server you use
  273. X    $server = 'ria';
  274. X    }
  275. X    if ($server =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
  276. X    $saddr = pack("CCCC", $1, $2, $3, $4);
  277. X    }
  278. X    elsif (!(($name, $dummy, $type, $len, $saddr) = gethostbyname($server))) {
  279. X    return 254;
  280. X    }
  281. X
  282. X    $sin = pack($sockaddr, 2, $port, $saddr);
  283. X
  284. X    socket(SERVER, 2, 1, 0) || return 253;
  285. X    connect(SERVER, $sin) || return 252;
  286. X
  287. X    select(SERVER); $| = 1; select(STDOUT);
  288. X    0;
  289. X}
  290. X
  291. Xsub main'nsquery {
  292. X    undef(%reply);
  293. X    if ($#_ != 1) {
  294. X    return (("Error", 251, "Message", "parameter size should be 2"));
  295. X    }
  296. X    local($hostname) = $_[1];
  297. X    if(($question = $question{$_[0]}) eq '') {
  298. X    return (("Error", 250, "Message", "No such option"));
  299. X    }
  300. X    $len = 17;
  301. X    @names = split('\.', $hostname);
  302. X    if ($question == 12) {
  303. X    @names = reverse(@names);
  304. X    push(@names, ("in-addr", "arpa"));
  305. X    }
  306. X    foreach $arg (@names) {
  307. X    $len += 1 + length($arg);
  308. X    }
  309. X    print SERVER pack('S', $len);
  310. X    print SERVER pack('S6', 319, 256, 1, 0, 0, 0);
  311. X    foreach $arg (@names) {
  312. X    print SERVER pack('C', length($arg));
  313. X    print SERVER $arg;
  314. X    }
  315. X    print SERVER pack('C', 0);
  316. X    print SERVER pack('S2', $question, 1);
  317. X
  318. X    read(SERVER, $len, 2);
  319. X    read(SERVER, $response, unpack('S', $len));
  320. X    @shead = unpack('S6', $response);
  321. X    $reply{'Error'} = $shead[1] & 0x000F;
  322. X    $reply{'Message'} = $RCODE[$shead[1] & 0x000F];
  323. X    $reply{'AA'} = $AA[($shead[1] & 0x0400) >> 10];
  324. X    $reply{'QR'} = $QR[($shead[1] & 0x8000) >> 15];
  325. X    $reply{'Truncation'} = $TC[($shead[1] & 0x0200) >> 9];
  326. X    $reply{'Recursion desired'} = $RD[($shead[1] & 0x0100) >> 8];
  327. X    $reply{'Recursion available'} = $RA[($shead[1] & 0x0080) >> 7];
  328. X
  329. X    $in = 12;
  330. X    $ans = $shead[2];
  331. X    while ($ans > 0) {
  332. X    &label();
  333. X    $in += 4;
  334. X    $ans--;
  335. X    }
  336. X
  337. X    foreach $index ((3, 4, 5)) {
  338. X    $ans = $shead[$index];
  339. X    while ($ans > 0) {
  340. X        $label = &label();
  341. X        $type = substr($response, $in, 2); $in += 8;
  342. X        $rdlength = substr($response, $in, 2); $in += 2;
  343. X        $rdata = substr($response, $in, unpack('n', $rdlength));
  344. X        &process($label);
  345. X    }
  346. X    continue {
  347. X        $ans--;
  348. X    }
  349. X    }
  350. X    %reply;
  351. X}
  352. X
  353. X
  354. Xsub label {
  355. X    $qname = "";
  356. X    $c = substr($response, $in, 1); $in++;
  357. X    $offset = $in;
  358. X    $forward = 1;
  359. X  loop: while ($c ne "\000") {
  360. X      $cc = ord($c);
  361. X      if (($cc & 0xc0) == 0xc0) {
  362. X      if ($forward) {
  363. X          $forward = 0;
  364. X          $in = $offset + 1;
  365. X      }
  366. X      $offset = ($cc - 192) * 256 + ord(substr($response, $offset, 1));
  367. X      }
  368. X      else {
  369. X      $qname = $qname . substr($response, $offset, $cc) . "."; 
  370. X      $offset += $cc;
  371. X      }
  372. X      $c = substr($response, $offset, 1); $offset++;
  373. X    }
  374. X    if ($forward) {
  375. X    $in = $offset;
  376. X    }
  377. X    chop($qname);
  378. X    $qname =~ y/A-Z/a-z/;
  379. X    $qname;
  380. X}
  381. X
  382. Xsub process {
  383. X    local($label) = $_[0];
  384. X    local($RR);
  385. X    $RR = unpack('S', $type);
  386. X    if ($RR == 1) {
  387. X    @host = unpack('C4', $rdata);
  388. X    if($reply{'Address'} eq '') {
  389. X        $reply{'Address'} = $label;
  390. X    }
  391. X    else {
  392. X        $reply{'Address'} = $reply{'Address'} . ' ' . $label;
  393. X    }
  394. X    $reply{$label} = "$host[0].$host[1].$host[2].$host[3]";
  395. X    $in += 4;
  396. X    }
  397. X    elsif ($RR == 6) {
  398. X    $serial = substr($response, $in, 4); $in += 4;
  399. X    $refresh = substr($response, $in, 4); $in += 4;
  400. X    $retry = substr($response, $in, 4); $in += 4;
  401. X    $expire = substr($response, $in, 4); $in += 4;
  402. X    $minimum = substr($response, $in, 4); $in += 4;
  403. X    $reply{'Zone of authority'} = &label() . " " . &label() . 
  404. X         " " . unpack('N', $serial) . " " .  unpack('N', $refresh) . 
  405. X         " " . unpack('N', $retry) . " " . unpack('N', $expire) . 
  406. X         " " . unpack('N', $minimum);
  407. X    }
  408. X    elsif ($RR == 10) {
  409. X    $in += unpack('n', $rdlength);
  410. X    $reply{'Null'} = 'Nothing';
  411. X    }
  412. X    elsif ($RR == 11) {
  413. X    $limit = $in + unpack('n', $rdlength);
  414. X    $ip = substr($response, $in, 4); $in += 4;
  415. X    $protocol = substr($response, $in, 1); $in++;
  416. X    $bitmap = substr($response, $in, $limit - $in);
  417. X    $in = $limit;
  418. X    $result = "$PROTOCOL[ord($protocol)] ";
  419. X    $result .= &ipaddr($ip) . " ";
  420. X    $result .= &protocols();
  421. X    $reply{'Services'} = $result;
  422. X    }
  423. X    elsif ($RR ==13) {
  424. X    $len = substr($response, $in, 1); $in++;
  425. X    $CPU = substr($response, $in, ord($len)); $in += ord($len);
  426. X    $len = substr($response, $in, 1); $in++;
  427. X    $OS = substr($response, $in, ord($len)); $in += ord($len);
  428. X    $reply{'Host info'} = "$CPU $OS";
  429. X    }
  430. X    elsif ($RR == 15) {
  431. X    $prefer = unpack("n", substr($response, $in, 2)); $in += 2;
  432. X    $reply{'Mail exchange'} = "$prefer" . &label();
  433. X    }
  434. X    elsif ($RR == 16) {
  435. X    $limit = $in + unpack('n', $rdlength);
  436. X    $string = '';
  437. X    while ($in < $limit) {
  438. X        $len = substr($response, $in, 1); $in++;
  439. X        $string .= substr($response, $in, ord($len)); $in += ord($len);
  440. X    }
  441. X    $reply{'Text'} = $string;
  442. X    }
  443. X    else {
  444. X    $lab = &label();
  445. X    if ($reply{$question[$RR]} eq '') {
  446. X        $reply{$question[$RR]} = $lab;
  447. X    }
  448. X    else {
  449. X        $reply{$question[$RR]} .= ' ' . $lab;
  450. X    }
  451. X    }
  452. X}
  453. X
  454. Xsub ipaddr {
  455. X    local(@host) = unpack('C4', $_[0]);
  456. X    "$host[0].$host[1].$host[2].$host[3]";
  457. X}
  458. X
  459. Xsub protocols {
  460. X    local($i, $j, $k, $result);
  461. X    $k = length($bitmap);
  462. X    @portsnum = unpack('n10', $bitmap);
  463. X    for ($i = 0; $i <= $k; $i++) {
  464. X    for ($j = 0; $j < 16; $j++) {
  465. X        if (($portsnum[$i] & $bits[$j]) != 0) {
  466. X        $result .= "$PORTS[$i * 16 + $j] ";
  467. X        }
  468. X    }
  469. X    }
  470. X    $result;
  471. X}
  472. X
  473. Xsub main'nsend {
  474. X    close SERVER;
  475. X}
  476. SHAR_EOF
  477. if test 9328 -ne "`wc -c < 'nslib.perl'`"
  478. then
  479.     echo shar: error transmitting "'nslib.perl'" '(should have been 9328 characters)'
  480. fi
  481. fi
  482. echo Done
  483. exit 0
  484.