home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3251 < prev    next >
Encoding:
Internet Message Format  |  1991-04-29  |  50.0 KB

  1. From: mat@zeus.opt-sci.arizona.edu (Mat Watson)
  2. Newsgroups: alt.sources
  3. Subject: Simple Socket Library
  4. Message-ID: <MAT.91Apr29003829@zeus.math.arizona.edu>
  5. Date: 29 Apr 91 07:38:30 GMT
  6.  
  7. ***** Simple Socket Library *******
  8. by Mat Watson and Hubert Bartels
  9.  
  10. The Simple Socket library is intended to simplify programming with BSD
  11. sockets, by providing a set of functions which mimic the stdio library.
  12. The basic data type used by the library is the SOCKET,
  13. which is analogous to the stdio FILE data type.  Here's a comparison
  14. of some code fragments to illustrate the similarities:
  15.  
  16. --Normal file IO--        --Using Simple Sockets--
  17. #include <stdio.h>        #include <ss.h>
  18. ...                ...
  19. FILE *fp;            SOCKET *sp;
  20. ...                ...
  21. fp = fopen("foobar.dat","r");    sp = ConnectSock("whereami.edu",4010)
  22. ...                ...
  23. fgets( buffer, 99, fp);        SockGets( buffer, 99, sp);
  24.  
  25. The calls which open and close the sockets themselves hide many of the
  26. gory details associated with using sockets, and provide a more natural
  27. interface.  The call to ConnectSock() above takes two arguments: a
  28. host name, and a port number.  Which is a good deal simpler than the
  29. series of steps one normally takes to establish a connection using
  30. standard system calls.  As is the case with most other routines that
  31. simplify a complicated process, the Simple Socket Library makes
  32. certain assumptions about how one wishes to use sockets to
  33. communicate.
  34.  
  35. This library assumes communications using 'streams' as opposed to
  36. datagrams, as they are quite similar to the stdio 'streams'.  In
  37. addition, the library does not use ioctl() to modify socket
  38. characteristics.  So if you want to make the sockets non blocking (for
  39. example), you'll have to modify the library code ( or this
  40. functionality could probably be added later ).  Instead, sockets
  41. should be checked to see if they are ready to be accessed before
  42. trying to read from one.
  43.  
  44. Since I don't have the time to write a bonafide manual, I put together
  45. some test/example programs that should be looked over.  The file named
  46. Testing explains how to use the test programs.  I also wrote the file
  47. named Notes, which gives a man page like synopsis and a short
  48. description for the library routines.  The file named Install has
  49. instructions for building the library.
  50.  
  51. Much of the code is based on a version of the stdio library written by
  52. Hubert Bartels.  Without that code as a basis, this library probably
  53. wouldn't be here now.  Thanks Hubert.
  54.  
  55. If you find the code useful, have any constructive criticism, bug
  56. fixes, or suggestions for improvement, send them to me (Mat).  I'm
  57. finishing up my dissertation, so don't be surprised if I'm a bit slow
  58. in replying :-).
  59.  
  60. This code is know to run on a: Sun3/160, Sparc 2, Data General Aviion,
  61. and IBM risc workstation.  It compiled on an ATT 3b2, but didn't
  62. run too well at all.
  63.  
  64. --Mat      4/29/91
  65.  
  66. Authors:
  67. Mat Watson   mat@zeus.opt-sci.arizona.edu
  68. and
  69. Hubert Bartels hgb@catalina.opt-sci.arizona.edu
  70.  
  71. ------------------------------- Cut Here -------------------------
  72. #!/bin/sh
  73. # shar:    Shell Archiver  (v1.22)
  74. #
  75. #    Run the following text with /bin/sh to create:
  76. #      README
  77. #      Makefile
  78. #      Notes
  79. #      Testing
  80. #      Install
  81. #      ss.c
  82. #      ss.base.h
  83. #      ss.sun.h
  84. #      ss.ibm.h
  85. #      ss.3b2.h
  86. #      test.h
  87. #      stdlib.h
  88. #      server1.c
  89. #      client1.c
  90. #      server2.c
  91. #      client2.c
  92. #      server3.c
  93. #      client3.c
  94. #
  95. sed 's/^X//' << 'SHAR_EOF' > README &&
  96. X***** Simple Socket Library *******
  97. Xby Mat Watson and Hubert Bartels
  98. X
  99. XThe Simple Socket library is intended to simplify programming with BSD
  100. Xsockets, by providing a set of functions which mimic the stdio library.
  101. XThe basic data type used by the library is the SOCKET,
  102. Xwhich is analogous to the stdio FILE data type.  Here's a comparison
  103. Xof some code fragments to illustrate the similarities:
  104. X
  105. X--Normal file IO--        --Using Simple Sockets--
  106. X#include <stdio.h>        #include <ss.h>
  107. X...                ...
  108. XFILE *fp;            SOCKET *sp;
  109. X...                ...
  110. Xfp = fopen("foobar.dat","r");    sp = ConnectSock("whereami.edu",4010)
  111. X...                ...
  112. Xfgets( buffer, 99, fp);        SockGets( buffer, 99, sp);
  113. X
  114. XThe calls which open and close the sockets themselves hide many of the
  115. Xgory details associated with using sockets, and provide a more natural
  116. Xinterface.  The call to ConnectSock() above takes two arguments: a
  117. Xhost name, and a port number.  Which is a good deal simpler than the
  118. Xseries of steps one normally takes to establish a connection using
  119. Xstandard system calls.  As is the case with most other routines that
  120. Xsimplify a complicated process, the Simple Socket Library makes
  121. Xcertain assumptions about how one wishes to use sockets to
  122. Xcommunicate.
  123. X
  124. XThis library assumes communications using 'streams' as opposed to
  125. Xdatagrams, as they are quite similar to the stdio 'streams'.  In
  126. Xaddition, the library does not use ioctl() to modify socket
  127. Xcharacteristics.  So if you want to make the sockets non blocking (for
  128. Xexample), you'll have to modify the library code ( or this
  129. Xfunctionality could probably be added later ).  Instead, sockets
  130. Xshould be checked to see if they are ready to be accessed before
  131. Xtrying to read from one.
  132. X
  133. XSince I don't have the time to write a bonafide manual, I put together
  134. Xsome test/example programs that should be looked over.  The file named
  135. XTesting explains how to use the test programs.  I also wrote the file
  136. Xnamed Notes, which gives a man page like synopsis and a short
  137. Xdescription for the library routines.  The file named Install has
  138. Xinstructions for building the library.
  139. X
  140. XMuch of the code is based on a version of the stdio library written by
  141. XHubert Bartels.  Without that code as a basis, this library probably
  142. Xwouldn't be here now.  Thanks Hubert.
  143. X
  144. XIf you find the code useful, have any constructive criticism, bug
  145. Xfixes, or suggestions for improvement, send them to me (Mat).  I'm
  146. Xfinishing up my dissertation, so don't be surprised if I'm a bit slow
  147. Xin replying :-).
  148. X
  149. XThis code is know to run on a: Sun3/160, Sparc 2, Data General Aviion,
  150. Xand IBM risc workstation.  It compiled on an ATT 3b2, but didn't
  151. Xrun too well at all.
  152. X
  153. X--Mat      4/29/90
  154. X
  155. XAuthors:
  156. XMat Watson   mat@zeus.opt-sci.arizona.edu
  157. Xand
  158. XHubert Bartels hgb@catalina.opt-sci.arizona.edu
  159. X
  160. X
  161. SHAR_EOF
  162. chmod 0775 README || echo "restore of README fails"
  163. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  164. X# Makefile
  165. XVERSION = 1.0
  166. XPATCHLEVEL = 0
  167. X
  168. X# Make sure you create the directories that libss.a and ss.h
  169. X# will get copied to.
  170. X# The directory where the file libss.a will get copied to on installation.
  171. XINSTALL_LIB_DIR = /usr/local/lib/here
  172. X# The directory where the file ss.h will get copied to on installation.
  173. XINSTALL_INC_DIR = /usr/local/include
  174. X
  175. X# Uncomment these lines to compile on a 3B2
  176. X#DEFINES = 
  177. X#LIBS = -lss -lnet -lnsl_s
  178. X#INCLUDEDIRS = -I/usr/netinclude
  179. X#HEADERFILE = ss.3b2.h
  180. X
  181. X# Uncomment the following lines for a Sun3 or Sparc.
  182. XDEFINES = -DVerbose_Errors
  183. XLIBS = -lss
  184. XINCLUDEDIRS =
  185. XHEADERFILE = ss.sun.h
  186. X
  187. X# Uncomment the following lines for an Aviion.
  188. X#DEFINES = -DVerbose_Errors -D_BSD_SOURCE # -D__STDC__
  189. X#LIBS = -lss
  190. X#INCLUDEDIRS =
  191. X#HEADERFILE = ss.sun.h
  192. X
  193. X# Uncomment the following lines for an IBM risc workstation.
  194. X#DEFINES = -DVerbose_Errors
  195. X#LIBS = -lss
  196. X#INCLUDEDIRS =
  197. X#HEADERFILE = ss.ibm.h
  198. X
  199. X# gcc compiler options
  200. X#CC = gcc
  201. X#CFLAGS = -g $(DEFINES) $(INCLUDEDIRS) #-traditional
  202. X
  203. X#CC = cc
  204. X#CFLAGS = -g $(DEFINES) $(INCLUDEDIRS)
  205. X
  206. XOBJS = ss.o
  207. X
  208. XCFILES = ss.c
  209. X
  210. XMISCFILES = README Makefile Notes Testing Install
  211. X
  212. XHFILES = ss.base.h ss.sun.h ss.ibm.h ss.3b2.h test.h stdlib.h
  213. X
  214. XDEMOFILES = server1.c client1.c server2.c client2.c server3.c client3.c
  215. X
  216. XARCHIVEFILES = $(MISCFILES) $(CFILES) $(HFILES) $(DEMOFILES) 
  217. X
  218. X.c.o:
  219. X    $(CC) -c $(CFLAGS) $<
  220. X
  221. Xall: libss.a client1 server1 client2 server2 client3 server3
  222. X
  223. Xlibss.a: ss.h $(OBJS) 
  224. X    ar rcv libss.a $(OBJS)
  225. X    ranlib libss.a
  226. X
  227. Xss.h: ss.base.h $(HEADERFILE)
  228. X    cat $(HEADERFILE) ss.base.h > ss.h
  229. X
  230. X$(OBJS): ss.h
  231. X
  232. Xinstall:
  233. X    cp libss.a $(INSTALL_LIB_DIR)
  234. X    cp ss.h    $(INSTALL_INC_DIR)
  235. X
  236. Xtar:
  237. X    tar cf - $(ARCHIVEFILES) | compress > ss-$(VERSION).tar.Z
  238. Xshar:
  239. X    xshar $(ARCHIVEFILES) > ss-$(VERSION).shar
  240. X
  241. Xclean:
  242. X    rm *.o core
  243. X
  244. Xrealclean: clean
  245. X    rm  server1 server2 server3 client1 client2 client3 libss.a
  246. Xlint:
  247. X    lint $(CFILES) $(DEFINES)
  248. X
  249. Xserver1: server1.o libss.a
  250. X    $(CC) server1.o -L. $(LIBS) -o server1
  251. X
  252. Xclient1: client1.o libss.a
  253. X    $(CC) client1.o -L. $(LIBS) -o client1
  254. X
  255. Xserver2: server2.o libss.a
  256. X    $(CC) server2.o -lss -L. -o server2
  257. X
  258. Xclient2: client1.o libss.a
  259. X    $(CC) client1.o -lss -L. -o client2
  260. X
  261. Xserver3: server3.o libss.a
  262. X    $(CC) server3.o -lss -L. -o server3
  263. X
  264. Xclient3: client3.o libss.a
  265. X    $(CC) client3.o -lss -L. -o client3
  266. X
  267. SHAR_EOF
  268. chmod 0775 Makefile || echo "restore of Makefile fails"
  269. sed 's/^X//' << 'SHAR_EOF' > Notes &&
  270. X######## Commands for opening and closing sockets ###########
  271. X
  272. XSocket * ServerSock( int port_number )
  273. X
  274. XOpens a socket on port number 'port_number' on the machine that the
  275. Xserver program is running on.  Returns a pointer to an open socket
  276. Xthat clients may use to connect to. If an error occurs, SeverSock
  277. Xreturns SS_NULL.
  278. X
  279. XSOCKET * ConnectSock( char * hostname, int port_number )
  280. X
  281. XAllows a client program to connect to a socket on port 'port_number'
  282. Xon system 'hostname'.  Returns a pointer to an open socket which the
  283. Xclient program can use to communicate with the server program.  If the
  284. Xcommand fails for any reason, it returns SS_NULL.
  285. X
  286. XSOCKET * AcceptSock( SOCKET * server_socket )
  287. X
  288. XUses the accept() system call to accept a connect request from a
  289. Xclient.  The variable 'server_socket' must point to the socket opened
  290. Xby the server program using the ServerSock() command.  Returns a
  291. Xpointer to an open socket that the server program may use to
  292. Xcommunicate with the client program.  AcceptSock() blocks if there are
  293. Xno connection requests pending on the server socket. If this command
  294. Xfails for any reason, it returns SS_NULL.
  295. X
  296. Xint SockClose( SOCKET * sp)
  297. X
  298. XCloses the socket pointed to by 'sp', and performs some internal
  299. Xhousecleaning.  Returns 0 if successful, otherwise returns SS_EOF.
  300. X
  301. X######## Commands for reading from and writing to sockets ########
  302. XMost of these commands are intended to behave similarly to their stdio
  303. Xnamesakes; replace FILE in your man pages with SOCKET and you'll
  304. Xhave a pretty good description of what these routines do.  For example:
  305. XSockPuts() behaves similarly to the stdio function fputs().
  306. X
  307. Xint SockGetc( SOCKET * sp )
  308. X
  309. XReturns the next character (byte) to be input from the socket 'sp'.
  310. X
  311. Xint SockPutc( char c, SOCKET * sp )
  312. X
  313. XWrites the character 'c' to the socket 'sp'.  Returns the character
  314. Xwritten.
  315. X
  316. Xint SockWrites( char * string, SOCKET * sp )
  317. Xint SockPuts( char * string, SOCKET * sp )
  318. X
  319. XThese functions write the string 'string' to the socket 'sp'.
  320. XSockPuts returns the value of the last character written to the buffer
  321. Xif successful, otherwise it returns SS_EOF. SockWrites returns 0 if
  322. Xsuccessful, otherwise returns SS_EOF.  SockPuts buffers it's output,
  323. Xwhile SockWrites issues the SockFlush() command on 'sp' to force
  324. Xcharacters in 'string' to be sent.
  325. X
  326. Xchar * SockGets( char * buffer, int nbytes, SOCKET * sp )
  327. X
  328. XReads characters from the socket 'sp' into 'buffer' until nbytes have
  329. Xbeen read, a newline character is read, or an end of file is reached.
  330. XIf the end of file is reached SockGets returns SS_EOF, otherwise it
  331. Xreturns 'buffer'.
  332. X
  333. Xint SockFlush( SOCKET * sp)
  334. X
  335. XForces any buffered data in 'sp' to be sent.  Returns 0 on success,
  336. Xand SS_EOF on failure.
  337. X
  338. X################ Checking sockets ###############
  339. XThese routines are built around the select() system call, and are
  340. Xused to check for sockets being ready for reading and writing,
  341. Xor to wait for an event to occur ( like the arival of data from
  342. Xanother machine ).
  343. X
  344. Xint SockSelect( double timeval, char * flag )
  345. X
  346. XThis function performs a select() system call on all open sockets.
  347. XSockSelect() returns the number of sockets which select() found to be
  348. Xready.  To examine the state of a particular socket after calling
  349. XSockSelect() you must use one of: IsReadSet(), IsWriteSet(), or
  350. XIsExceptSet().  The select call will block for 'timeval' seconds if
  351. Xtimeval is positive.  If 'timeval' is negative, then the select call
  352. Xwill block indefinitely until at least one of the open sockets is
  353. Xready.  The variable 'flag' is used to determine what the select()
  354. Xwill check for:
  355. X
  356. X     'flag'        select() checks for
  357. X        -----           ------------------
  358. X    "r"        socket ready to be read from.
  359. X    "w"        socket ready to be written to.
  360. X    "e"        socket has exceptional condition pending.
  361. X
  362. XAny combination of the set {r,w,e} may be used in any order.  For
  363. Xexample: flag = "er", will cause select() to check for sockets ready
  364. Xto be read from or having exceptional conditions pending.
  365. X
  366. Xint IsWriteSet( SOCKET * sp )
  367. Xint IsReadSet( SOCKET * sp )
  368. Xint IsExceptSet( SOCKET * sp )
  369. X
  370. XThese functions check a particular socket to see it is ready for
  371. Xreading, writing, or has an exceptional condition pending.  If the
  372. Xsocket is ready, the functions return 1, otherwise they return 0.
  373. XThese functions use information obtained during the last SockSelect()
  374. Xcall.
  375. X
  376. Xint SockIsRead( SOCKET * sp )
  377. Xint SockIsWrite( SOCKET * sp )
  378. X
  379. XThese functions combine the select() system call and FD_ISSET() macro,
  380. Xand are used to check whether a socket is ready for reading or
  381. Xwriting.  If the socket is ready the functions return 1, otherwise
  382. Xthey return 0.  These functions have no timeval parameter (see
  383. XSockSelect()), and return immediately.
  384. X
  385. SHAR_EOF
  386. chmod 0644 Notes || echo "restore of Notes fails"
  387. sed 's/^X//' << 'SHAR_EOF' > Testing &&
  388. XSeveral test programs have been provided which, in addition to making
  389. Xsure the code works, serve as examples of how to use the library
  390. Xroutines.
  391. X
  392. XThe test programs are set up to work in pairs; client1 works with
  393. Xserver1, client2 works with server2 and so on.
  394. X
  395. XTesting is most easily done on a windowing system.  Open a window,
  396. Xand start up a server program:
  397. X% server1
  398. XThen open another window, and start up a client program:
  399. X% client1
  400. X
  401. XTest program descriptions:
  402. X
  403. Xclient1/server1 - server1 waits for a client1 to connect and prints
  404. X    out any and all input it recieve from the client.  Once the
  405. X    client disconnects the server waits for another connection.
  406. X    Client1 connects to the server, and accepts input from the
  407. X    standard input which it sends to the server. Upon receipt
  408. X    of an EOF (^D) client1 stops and says goodbye.
  409. X
  410. Xclient2/server2 - server2 waits a short while for a client to connect.
  411. X    If no client attempts a connection, the server goes off and
  412. X    does something else, and then waits again.  If a client connects,
  413. X    then server2 behaves the same as server1.  Client2 is identical
  414. X    to client1.
  415. X
  416. Xclient3/server3 - Server3 is able to multiplex clients.  Whenever one
  417. X    of the clients is ready for reading, the server reads a single
  418. X    line, and then waits again.  Client3 requires no user input;
  419. X    it carries on a trivial conversation with the server. I found
  420. X    this command to be usefull for starting several client3 programs:
  421. X    % sleep 6 ; ( client3 & client3 & client3 & )
  422. X    The command waits six seconds ( giving me time to bring up the
  423. X    window I was running the server in ), and then starts three client3
  424. X    programs in parallel.
  425. SHAR_EOF
  426. chmod 0644 Testing || echo "restore of Testing fails"
  427. sed 's/^X//' << 'SHAR_EOF' > Install &&
  428. XTo build the Simple Socket Library:
  429. X
  430. X1. Edit the Makefile.
  431. X
  432. XYou will need to set the install directories, and uncomment the
  433. Xdefines that go along with your machine.
  434. X
  435. X2. Edit test.h
  436. X
  437. XYou will need to set the machine name and port number that you
  438. Xwant the test programs to use.
  439. X
  440. X3. type  % make
  441. X
  442. XTakes about 3 minutes on my sun3 to build the library and test
  443. Xprograms.
  444. X
  445. X4. Run the test programs.  See the file named Testing for instructions
  446. Xon how to do this.
  447. X
  448. X5. If your happy with what you see, then go ahead and install
  449. Xthe library and header file.  Make sure that you create the directories
  450. Xyou named at the top of the Makefile.
  451. X
  452. Xmake install
  453. X
  454. X6. Send problems, fixes, and comments to:  mat@zues.opt-sci.arizona.edu
  455. X
  456. XI can't promise to fix problems associated with porting to new machines,
  457. Xas I've already ported the code to all the machines that I know anything
  458. Xat all about.
  459. X
  460. X--Mat
  461. SHAR_EOF
  462. chmod 0644 Install || echo "restore of Install fails"
  463. sed 's/^X//' << 'SHAR_EOF' > ss.c &&
  464. X/* Simple Socket Libary
  465. X   Written by Mat Watson and Hubert Bartels.  12/01/90
  466. X*/
  467. X/*
  468. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  469. X
  470. XPermission to use, copy, and/or distribute for any purpose and 
  471. Xwithout fee is hereby granted, provided that both the above copyright 
  472. Xnotice and this permission notice appear in all copies and derived works. 
  473. XFees for distribution of this software or for derived sources may only 
  474. Xbe charged with the express written permission of the copyright holders. 
  475. XThis software is provided ``as is'' without express or implied warranty.
  476. X*/
  477. X
  478. X#include "ss.h"
  479. X
  480. X/* #include "private_globals.h" */
  481. X/* #include <signal.h> */
  482. X
  483. Xint ss_server_flag;
  484. Xint ss_client_flag;
  485. Xint ss_init_flag=0;
  486. XSOCKARRAY ss_sockbuff;
  487. Xint max_sd;  /* this variable is a private global */
  488. X
  489. Xchar *malloc();
  490. X
  491. XSOCKET *AcceptSock( ssp )
  492. XSOCKET *ssp;               /* Server Socket Pointer */
  493. X{
  494. X  SOCKET *csp;             /* Client Socket Pointer */
  495. X  struct sockaddr *adrp;   /* Address Poiner        */
  496. X  int *adrlen;             /* Address Length        */
  497. X  int csd;                 /* Client Socket Descriptor */
  498. X
  499. X  if( !(ss_sockbuff.n_sockets < MaxSockets) )
  500. X    return (SOCKET *) SS_NULL;
  501. X
  502. X  /* Allocate space for the client's socket structure */
  503. X  csp = (SOCKET *)malloc( sizeof( SOCKET ));
  504. X
  505. X  if( !csp )
  506. X    sserror("AcceptSock: malloc()",EXIT);
  507. X
  508. X  csp->_rcnt = 0;
  509. X  csp->_rptr = SS_NULL;
  510. X  csp->_rbase = SS_NULL;
  511. X  csp->_wcnt = 0;
  512. X  csp->_wptr = SS_NULL;
  513. X  csp->_wbase = SS_NULL;
  514. X  csp->_flag = 0;
  515. X
  516. X  adrp = (struct sockaddr *)0;
  517. X  adrlen = (int *)0;
  518. X
  519. X  csd = accept( ssp->sd, adrp, adrlen );
  520. X  if( csd < 0 ) {
  521. X#ifdef Verbose_Errors
  522. X    sserror("AcceptSock: accept()",CONT);
  523. X#endif
  524. X    return SS_NULL;
  525. X  }
  526. X
  527. X  /* Set the value of the maximum socket descriptor used so far */
  528. X  max_sd = csd >= max_sd ? csd : max_sd;
  529. X  
  530. X  csp->sd = csd;
  531. X
  532. X  AddSock( csp, &ss_sockbuff );
  533. X
  534. X  /* Return a pointer to the client socket */
  535. X  return csp;
  536. X}
  537. X
  538. Xvoid AddSock( sp, sap )
  539. XSOCKET *sp;
  540. XSOCKARRAY *sap;
  541. X{
  542. X  int n;
  543. X  n = sap->n_sockets;
  544. X  sap->n_sockets++;
  545. X  sap->spa[n] = sp;
  546. X  return;
  547. X}
  548. X
  549. XSOCKET *ConnectSock( hostname, port_number )
  550. Xchar *hostname;
  551. Xunsigned port_number;
  552. X{
  553. X  SOCKET *sp;
  554. X  struct hostent *hep;
  555. X  struct sockaddr *adrp;
  556. X  int adrlen;
  557. X  int result;
  558. X
  559. X  SockInit( 'c' );
  560. X
  561. X  sp = (SOCKET *) malloc( sizeof( SOCKET ) );
  562. X
  563. X  if( !sp ) {
  564. X#ifdef Verbose_Errors
  565. X    sserror("ConnectSock: malloc()",CONT);
  566. X#endif
  567. X    return (SOCKET *) SS_NULL;
  568. X  }
  569. X
  570. X  sp->_rcnt = 0;
  571. X  sp->_rptr = SS_NULL;
  572. X  sp->_rbase = SS_NULL;
  573. X  sp->_wcnt = 0;
  574. X  sp->_wptr = SS_NULL;
  575. X  sp->_wbase = SS_NULL;
  576. X  sp->_flag = 0;
  577. X
  578. X  AddSock( sp, &ss_sockbuff );
  579. X
  580. X  hep = gethostbyname( hostname );
  581. X  if( hep == (struct hostent *)0 ) {
  582. X#ifdef Verbose_Errors
  583. X    perror("ConnectSock: gethostbyname()");
  584. X#endif
  585. X    return (SOCKET *) SS_NULL;
  586. X  }
  587. X
  588. X  bcopy( (char *)(hep->h_addr), (char *)&(sp->addr.sin_addr), hep->h_length );
  589. X
  590. X  sp->addr.sin_family = AF_INET;
  591. X  sp->addr.sin_port = htons( (u_short)port_number );
  592. X  sp->sd = socket( AF_INET, SOCK_STREAM, 0 );
  593. X  if( sp->sd < 0 ) {
  594. X#ifdef Verbos_Errors
  595. X    sserror("ConnectSock: socket()",CONT);
  596. X#endif
  597. X    return (SOCKET *) SS_NULL;
  598. X  }
  599. X
  600. X  adrp = (struct sockaddr *) &(sp->addr);
  601. X  adrlen = sizeof( sp->addr );
  602. X
  603. X  result = connect( sp->sd, adrp, adrlen );
  604. X  if( result < 0 ) {
  605. X#ifdef Verbos_Errors
  606. X    sserror("ConnectSock: connect()",CONT);
  607. X#endif
  608. X    close(sp->sd);
  609. X    free((char *) sp );
  610. X    return (SOCKET *) SS_NULL;
  611. X  }
  612. X  max_sd = sp->sd >= max_sd ? sp->sd : max_sd ;
  613. X  return sp;
  614. X}
  615. X
  616. Xint IsExceptSet( sp )
  617. XSOCKET *sp;
  618. X{
  619. X  int result, i;
  620. X  SOCKARRAY * sap;
  621. X  sap = &ss_sockbuff;
  622. X  i = SockIndex( sp, sap );
  623. X  if( i == -1 )
  624. X    return -1;           /* Socket is not in ss_sockbuff */
  625. X  result = FD_ISSET( sap->spa[i]->sd, &(sap->exceptfds) );
  626. X  return result;
  627. X}
  628. X
  629. Xint IsReadSet( sp )
  630. XSOCKET *sp;
  631. X{
  632. X  int result, i;
  633. X  SOCKARRAY * sap;
  634. X  sap = &ss_sockbuff;
  635. X  i = SockIndex( sp, sap );
  636. X  if( i == -1 )
  637. X    return i;               /* Socket is not in the ss_sockbuff */
  638. X  result = FD_ISSET( sap->spa[i]->sd, &(sap->readfds) );
  639. X  return result;
  640. X}
  641. X
  642. Xint IsWriteSet( sp )
  643. XSOCKET *sp;
  644. X{
  645. X  int result, i;
  646. X  SOCKARRAY * sap;
  647. X  sap = &ss_sockbuff;
  648. X  i = SockIndex( sp, sap );
  649. X  if( i == -1 )
  650. X    return -1;    /* Socket is not in ss_sockbuff */
  651. X  result = FD_ISSET( sap->spa[i]->sd, &(sap->writefds) );
  652. X  return result;
  653. X}
  654. X
  655. Xvoid RemoveSock( sp )
  656. XSOCKET *sp;
  657. X{
  658. X  int i, n;
  659. X  SOCKARRAY *sap;
  660. X  sap = &ss_sockbuff;
  661. X
  662. X  for( i = 0; i < sap->n_sockets; i++ ) 
  663. X    if( sp == sap->spa[i] ) break;
  664. X
  665. X  n = i;
  666. X
  667. X  for( i = n + 1; i < sap->n_sockets; i++ )
  668. X    sap->spa[i-1] = sap->spa[i];
  669. X
  670. X  sap->spa[sap->n_sockets - 1] = SS_NULL;
  671. X  sap->n_sockets--;
  672. X  return;
  673. X}
  674. X
  675. X
  676. XSOCKET *ServerSock( port_number )
  677. Xunsigned port_number;
  678. X{
  679. X  int sd;
  680. X  int optval;
  681. X  unsigned optlen;
  682. X  SOCKET *sp;
  683. X  int result;
  684. X
  685. X  SockInit( 's' );
  686. X
  687. X  sd = socket( AF_INET, SOCK_STREAM, 0 );
  688. X  if( sd < 0 ) {
  689. X    sserror("ServerSock: socket()",EXIT);
  690. X    /* return (SOCKET *) SS_NULL; */
  691. X  }
  692. X  
  693. X  optval = 1;  /* any nonzero value will cause the flag to be set */
  694. X  optlen = sizeof( int );
  695. X  result = setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, optlen );
  696. X  if( result != 0 ) {
  697. X#ifdef Verbose_Errors
  698. X    sserror("ServerSock: setsockopt()",CONT);
  699. X#endif
  700. X    return (SOCKET *) SS_NULL;
  701. X  }
  702. X
  703. X  sp = (SOCKET *)malloc( sizeof(SOCKET));
  704. X  if( !sp ) {
  705. X#ifdef Verbose_Errors
  706. X    sserror("ServerSock: mallock()",CONT);
  707. X#endif
  708. X    return (SOCKET *) SS_NULL;
  709. X  }
  710. X  
  711. X  sp->addr.sin_family = AF_INET;
  712. X  sp->addr.sin_addr.s_addr = INADDR_ANY;
  713. X  sp->addr.sin_port = htons( (u_short)port_number );
  714. X
  715. X  result = bind( sd, (struct sockaddr *)&(sp->addr), sizeof(struct sockaddr));
  716. X  if( result !=0 ) {
  717. X#ifdef Verbose_Errors
  718. X    sserror("ServerSock: bind()",CONT);
  719. X#endif
  720. X    return (SOCKET *) SS_NULL;
  721. X  }
  722. X
  723. X  max_sd = sd >= max_sd ? sd : max_sd;
  724. X  sp->sd = sd;
  725. X  sp->_rcnt = 0;
  726. X  sp->_rptr = SS_NULL;
  727. X  sp->_rbase = SS_NULL;
  728. X  sp->_wcnt = 0;
  729. X  sp->_wptr = SS_NULL;
  730. X  sp->_wbase = SS_NULL;
  731. X  sp->_flag = 0;
  732. X  
  733. X  result = listen( sd, 5 );
  734. X  if( result != 0 ) {
  735. X#ifdef Verbose_Errors
  736. X    sserror("ServerSock: listen()",CONT);
  737. X#endif
  738. X    return (SOCKET *) SS_NULL;
  739. X  }
  740. X
  741. X  AddSock( sp, &ss_sockbuff );
  742. X  
  743. X  return sp;
  744. X}
  745. X
  746. Xvoid SockArrayInit( sap )
  747. XSOCKARRAY *sap;
  748. X{
  749. X  int i;
  750. X  sap->n_sockets = 0;
  751. X  for( i = 0; i < MaxSockets; i++ )
  752. X    sap->spa[i] = SS_NULL;
  753. X  return;
  754. X}
  755. X
  756. X/*    fclose.c
  757. X    
  758. X    Hubert Bartels
  759. X    
  760. X    August 8, 1985
  761. X    
  762. X    fclose closes the file and frees the entry in the _iob block.
  763. X
  764. X        Modified for sockets by Mat Watson 12/1/90
  765. X
  766. X*/
  767. Xint SockClose(sp)
  768. XSOCKET *sp;
  769. X{
  770. X    int result;
  771. X
  772. X  RemoveSock( sp );
  773. X
  774. X  result = SockFlush(sp);      /* Flush the buffer if needed */
  775. X  if( result < 0 ) {
  776. X#ifdef Verbose_Errors
  777. X    sserror("SockClose(): SockFlush failed",CONT);
  778. X#endif
  779. X    return SS_EOF;
  780. X  }
  781. X  result = close((int)sp->sd);        /* Close the file */
  782. X  if( result < 0 )
  783. X    sserror("SockClose: close() failed",EXIT);
  784. X  sp->sd = '\0';
  785. X  sp->_rcnt = 0;
  786. X  sp->_rptr = SS_NULL;
  787. X  if( (sp->_flag & SS_IONBF) == 0 ) 
  788. X    free( (char *) sp->_rbase );
  789. X  sp->_rbase = SS_NULL;
  790. X
  791. X  sp->_wcnt = 0;
  792. X  sp->_wptr = SS_NULL;
  793. X  if( (sp->_flag & SS_IONBF) == 0 ) 
  794. X    free( (char *) sp->_wbase );
  795. X  sp->_wbase = SS_NULL;
  796. X  sp->_flag = 0;
  797. X  return 0; /* Success */
  798. X}
  799. X
  800. X/* SockFilbuf.c
  801. X   Modified for sockets by Mat Watson 12/01/90
  802. X*/
  803. X/*    filbuf.c
  804. X    
  805. X    Hubert Bartels
  806. X    
  807. X    July 8, 1985
  808. X    
  809. X    filbuf is used to fill the buffer of files being read by the
  810. X    polyp. As such, it is part of the file system of the polyp.
  811. X*/
  812. Xint _SockFilbuf(sp)
  813. XSOCKET *sp;
  814. X{
  815. X  static char smallbuf[NOFILE];  /* for unbuffered i/o */
  816. X  char *calloc();
  817. X
  818. X  if( (sp->_flag & (SS_IOEOF | SS_IOERR)) != 0 )
  819. X    return(SS_EOF);
  820. X
  821. X  while (sp->_rbase == SS_NULL) /* find buffer space */
  822. X    if(sp->_flag & SS_IONBF) /* unbuffered */
  823. X      sp->_rbase = &smallbuf[sp->sd];
  824. X    else if ((sp->_rbase = calloc(SS_BUFSIZ, 1)) == SS_NULL)
  825. X      sp->_flag |= SS_IONBF;    /* Cannot get unbuffered */
  826. X    else
  827. X      sp->_flag |= SS_IOMYBUF;    /* Got a big buffer */
  828. X
  829. X  sp->_rptr = sp->_rbase;
  830. X  sp->_rcnt = read(sp->sd, sp->_rptr,
  831. X          sp->_flag & SS_IONBF ? 1 : SS_BUFSIZ);
  832. X  if(--sp->_rcnt < 0) {
  833. X    if(sp->_rcnt == -1 || errno == ECONNRESET ) /* ECONNRESET if socket */
  834. X      sp->_flag |= SS_IOEOF;                    /* was closed.          */
  835. X    else {
  836. X      sp->_flag |= SS_IOERR;
  837. X#ifdef Verbose_Errors
  838. X      sserror("SockFilbuf(): read()",CONT);
  839. X#endif
  840. X    }
  841. X    sp->_rcnt = 0;
  842. X    return(SS_EOF);
  843. X  }
  844. X  return(*sp->_rptr++ & 0377);    /* make character positive */
  845. X}
  846. X/* SockFlsbuf.c
  847. X   Modified for sockets by Mat Watson 12/01/90
  848. X*/
  849. X/*    flsbuf.c
  850. X    
  851. X    Hubert Bartels
  852. X    
  853. X    July 29, 1985
  854. X    
  855. X    Version 2.0
  856. X            Correct the bug, initialization of buffer
  857. X    flsbuf is used to flush the buffer of files being written by
  858. X    the polyp. As such, it is part of the file system of the polyp.
  859. X    _flsbuf may be called with unbuffered or buffered data. There
  860. X    may be data still in the buffers when the program completes. 
  861. X    either fflush or fclose should be called when closing the program
  862. X    or file, to enure that all the data has been read out.
  863. X*/
  864. X
  865. Xint _SockFlsbuf(x,sp)
  866. Xchar x;
  867. XSOCKET *sp;
  868. X{
  869. X    static char smallbuf[NOFILE];        /* for unbuffered i/o */
  870. X    char *malloc();
  871. X
  872. X    if( (sp->_flag & SS_IOERR) != 0)
  873. X        return SS_EOF;
  874. X    if (sp->_wbase == SS_NULL) { /* find buffer space */
  875. X        if(sp->_flag & SS_IONBF) { /* unbuffered */
  876. X            sp->_wbase = &smallbuf[sp->sd];
  877. X        }
  878. X        else if ((sp->_wbase = malloc(SS_BUFSIZ)) == SS_NULL) {
  879. X            sp->_wbase = &smallbuf[sp->sd];
  880. X            sp->_flag |= SS_IONBF;    /* Cannot get unbuffered */
  881. X        }
  882. X        else
  883. X            sp->_flag |= SS_IOMYBUF;    /* Got a big buffer */
  884. X        sp->_wptr = sp->_wbase;        /* Initialize pointer */
  885. X        sp->_wcnt = (sp->_flag & SS_IONBF)?0:SS_BUFSIZ; /* Buffer size */
  886. X        if(sp->_flag & SS_IONBF) {        /* If unbuffered */
  887. X            write(sp->sd,&x, 1);
  888. X            sp->_wcnt = 0;
  889. X            }
  890. X        else {
  891. X                *(sp)->_wptr++ = x;        /* Store char */
  892. X                sp->_wcnt--;
  893. X                }
  894. X        return 0;
  895. X    } /* End of sp->_base buffer allocation */
  896. X    if(sp->_flag & SS_IONBF) {        /* If unbuffered */
  897. X        write(sp->sd,&x, 1);
  898. X        sp->_wcnt = 0;
  899. X    } else {
  900. X        if(write(sp->sd,sp->_wbase,(SS_BUFSIZ-sp->_wcnt)) == -1)
  901. X            sp->_flag |= SS_IOERR;
  902. X        sp->_wcnt = SS_BUFSIZ;
  903. X        sp->_wptr = sp->_wbase;
  904. X        *(sp)->_wptr++ = x;
  905. X        sp->_wcnt--;
  906. X    }
  907. X    return 0;
  908. X}
  909. X
  910. X/*  SockFlush.c
  911. X   Modified for sockets by Mat Watson 12/01/90
  912. X*/
  913. X/*    fflush.c
  914. X    
  915. X    Hubert Bartels
  916. X    
  917. X    July 29, 1985
  918. X    
  919. X    fflush is called to clear out the buffers to ensure that everything
  920. X    has been written. Called in the middle of the programs, it ensures
  921. X    that the information will be complete before finishing some long
  922. X    calculation. Called at the end, it performs the sync function for
  923. X    the program.
  924. X*/
  925. X
  926. Xint SockFlush(sp)
  927. XSOCKET *sp;
  928. X{
  929. X  int n_writen;
  930. X  char *my_base;
  931. X
  932. X  if(
  933. X     /* (sp->_flag &SS_IOWRT) == 0  || */ /* Not Appropriate for Sock */
  934. X     (sp->_flag & SS_IOERR) != 0
  935. X     ) {
  936. X#ifdef Verbose_Errors
  937. X    sserror("SockFlush: SS_IOERR is set",CONT);
  938. X#endif
  939. X    return SS_EOF;                /* If errors in file */
  940. X  }
  941. X  if( sp->_wbase == SS_NULL )
  942. X    return 0;                                /* No buffer to flush */
  943. X  if((sp->_flag & SS_IONBF) == 0) {        /* If buffered */
  944. X    my_base = sp->_wbase;
  945. X    while( sp->_wcnt != SS_BUFSIZ ) {
  946. X      n_writen = write( sp->sd, my_base, (SS_BUFSIZ - sp->_wcnt) );
  947. X      if( n_writen < 0 ) {
  948. X        extern int errno;
  949. X        if( errno == EPIPE )
  950. X          return 0;
  951. X#ifdef Verbose_Errors
  952. X    sserror("SockFlush: write error",CONT);
  953. X    /* When the socket has been set non blocking and the socket
  954. X       would otherwise block, write will return a -1 and errno
  955. X       will be set to EWOULDBLOCK. */
  956. X    /* When write tries to send characters to a client or server
  957. X       that has dissconnected errno is set to EPIPE */
  958. X#endif
  959. X        return SS_EOF;
  960. X      }
  961. X      sp->_wcnt += n_writen;
  962. X      my_base += n_writen;
  963. X    }
  964. X    sp->_wcnt = SS_BUFSIZ;
  965. X    sp->_wptr = sp->_wbase;
  966. X  }
  967. X  return 0;
  968. X}
  969. X
  970. X/* SockGets.c
  971. X   Modified for sockets by Mat Watson 12/01/90
  972. X*/
  973. X/*    fgets.c
  974. X
  975. X    read a newline-terminated string from device (file) dev
  976. X
  977. X    Hubert Bartels
  978. X    August 12, 1985
  979. X*/
  980. X
  981. Xchar *SockGets(s, n, sp)
  982. Xchar *s;
  983. Xint n;
  984. XSOCKET *sp;
  985. X{
  986. X    int c;
  987. X    char *cs;
  988. X
  989. X    cs = s;
  990. X        while ( --n > 0 && ( c = SockGetc( sp )) >= 0 ) {
  991. X        *cs++ = (char)c;
  992. X        if ( (char)c =='\n' )
  993. X            break;
  994. X    }
  995. X    if ( c < 0 && cs == s )
  996. X        return SS_NULL;
  997. X    *cs++ = '\0';
  998. X    return s;
  999. X}
  1000. X
  1001. X/* SockIndex.c
  1002. X   Writen by Mat Watson 12/01/90
  1003. X*/
  1004. X
  1005. Xint SockIndex( sp, sap )
  1006. XSOCKET *sp;
  1007. XSOCKARRAY *sap;
  1008. X{
  1009. X  int i;
  1010. X
  1011. X  for( i = 0; i < sap->n_sockets; i++ ) 
  1012. X    if( sp == sap->spa[i] ) break;
  1013. X
  1014. X  if( i == sap->n_sockets )
  1015. X    i = -1;
  1016. X
  1017. X  return i;
  1018. X}
  1019. X
  1020. X/* SockInit.c
  1021. X   Writen by Mat Watson 12/01/90
  1022. X*/
  1023. Xvoid SockInit( c )
  1024. Xchar c;
  1025. X{
  1026. X  if( ss_server_flag == 0 && c == 's' )
  1027. X      ss_server_flag = 1;
  1028. X
  1029. X  if( ss_client_flag == 0 && c == 'c' )
  1030. X      ss_client_flag = 1;
  1031. X
  1032. X  if( ss_init_flag == 0 ) {
  1033. X    ss_sockbuff.n_sockets = 0;
  1034. X    ss_init_flag = 1;
  1035. X    max_sd = 0;
  1036. X    signal(SIGPIPE,SockSignal);
  1037. X  }
  1038. X
  1039. X  return;
  1040. X}
  1041. X
  1042. X/* SockIsRead.c
  1043. X   Writen by Mat Watson 12/01/90
  1044. X*/
  1045. X
  1046. Xint SockIsRead( sp )
  1047. XSOCKET *sp;
  1048. X{
  1049. X  int result;
  1050. X  struct timeval to;
  1051. X  fd_set readfds;
  1052. X
  1053. X  to.tv_sec = 0;
  1054. X  to.tv_usec = 0;
  1055. X  
  1056. X
  1057. X  FD_ZERO( &readfds );
  1058. X  FD_SET( sp->sd, &readfds );
  1059. X  result = select( max_sd+1, &readfds, (fd_set *)0, (fd_set *)0, &to );
  1060. X  if( result == -1 )
  1061. X    sserror("SockSelect1(): select() returned -1",CONT);
  1062. X
  1063. X  return FD_ISSET( sp->sd, &readfds ) ? 1 : 0;
  1064. X}
  1065. X
  1066. Xint SockIsWrite( sp )
  1067. XSOCKET *sp;
  1068. X{
  1069. X  int result;
  1070. X  struct timeval to;
  1071. X  fd_set writefds;
  1072. X
  1073. X  to.tv_sec = 0;
  1074. X  to.tv_usec = 0;
  1075. X  
  1076. X
  1077. X  FD_ZERO( &writefds );
  1078. X  FD_SET( sp->sd, &writefds );
  1079. X  result = select( max_sd+1, (fd_set *)0, &writefds, (fd_set *)0, &to );
  1080. X  if( result == -1 )
  1081. X    sserror("SockSelect1(): select() returned -1",CONT);
  1082. X
  1083. X  return FD_ISSET( sp->sd, &writefds ) ? 1 : 0;
  1084. X}
  1085. X
  1086. X/*    SockPuts.c
  1087. X    Modified for sockets by Mat Watson 12/01/90
  1088. X*/
  1089. X/*    fputs.c
  1090. X
  1091. X    places a string on the output file pointed to by fp.
  1092. X
  1093. X    Hubert Bartels
  1094. X    August 12, 1985
  1095. X*/
  1096. Xint SockPuts(s, sp)
  1097. XSOCKET *sp;
  1098. Xchar *s;
  1099. X{
  1100. X    int r;
  1101. X    char c;
  1102. X
  1103. X    while (c = *s++)
  1104. X                r = SockPutc(c, sp);
  1105. X    return(r);
  1106. X}
  1107. X
  1108. Xint SockSelect( timeout, flag )
  1109. Xdouble timeout;
  1110. Xchar *flag;
  1111. X{
  1112. X  int i;
  1113. X  int result;
  1114. X  long seconds;
  1115. X  long microseconds;
  1116. X  SOCKARRAY * sap;
  1117. X  struct timeval to, *tvp;
  1118. X  fd_set *rfdsp, *wfdsp, *efdsp;
  1119. X  char *cp;
  1120. X
  1121. X  sap = &ss_sockbuff;
  1122. X
  1123. X  if( timeout < 0.0 ) {
  1124. X    tvp = SS_NULL;
  1125. X  }
  1126. X  else {
  1127. X    seconds = timeout / 1.0;
  1128. X    microseconds = (timeout - (double)seconds) / 1e-6;
  1129. X    to.tv_sec = seconds;
  1130. X    to.tv_usec = microseconds;
  1131. X    tvp = &to;
  1132. X  }
  1133. X
  1134. X  rfdsp = (fd_set *)0;
  1135. X  wfdsp = (fd_set *)0;
  1136. X  efdsp = (fd_set *)0;
  1137. X
  1138. X  for( cp = flag; *cp != '\0'; cp++ ) {
  1139. X    if( *cp == 'r' ) {
  1140. X      rfdsp = &(sap->readfds);
  1141. X      FD_ZERO( rfdsp );
  1142. X      for( i = 0; i < sap->n_sockets; i ++ )
  1143. X    FD_SET( sap->spa[i]->sd, rfdsp );
  1144. X    } 
  1145. X    else if( *cp == 'w' ) {
  1146. X      wfdsp = &(sap->writefds);
  1147. X      FD_ZERO( wfdsp );
  1148. X      for( i = 0; i < sap->n_sockets; i ++ )
  1149. X    FD_SET( sap->spa[i]->sd, wfdsp );
  1150. X    }
  1151. X    else if( *cp == 'e' ) {
  1152. X      efdsp = &(sap->exceptfds);
  1153. X      FD_ZERO( efdsp );
  1154. X      for( i = 0; i < sap->n_sockets; i ++ )
  1155. X    FD_SET( sap->spa[i]->sd, efdsp );
  1156. X    }
  1157. X    else {
  1158. X      sserror("SockSelect(): Unknown flag",CONT);
  1159. X    }
  1160. X  }
  1161. X
  1162. X  result = select( max_sd+1, rfdsp, wfdsp, efdsp, tvp );
  1163. X  if( result == -1 )
  1164. X    perror("SockSelect(): select() returned -1");
  1165. X
  1166. X  return result;
  1167. X}
  1168. X
  1169. Xvoid SockSignal( sig )
  1170. Xint sig;
  1171. X{
  1172. X  switch ( sig )
  1173. X    {
  1174. X    case SIGPIPE :
  1175. X#ifdef Verbose_Signals
  1176. X      sserror(
  1177. X        "Caught a SIGPIPE signal, Server/Client probably disconnected",
  1178. X     CONT );
  1179. X#endif
  1180. X      break;
  1181. X    }
  1182. X  return;
  1183. X}
  1184. X
  1185. X/* SockWrites
  1186. X   Writen by Mat Watson 12/01/90
  1187. X   Based on fputs.c by Hubert Bartels.
  1188. X*/
  1189. Xint SockWrites(s, sp)
  1190. XSOCKET *sp;
  1191. Xchar *s;
  1192. X{
  1193. X    int r;
  1194. X    char c;
  1195. X
  1196. X    while (c = *s++)
  1197. X                r = SockPutc(c, sp);
  1198. X    r = SockFlush( sp );
  1199. X    return(r);
  1200. X}
  1201. X
  1202. Xvoid sserror( mesg, code )
  1203. Xchar * mesg;
  1204. Xint code;
  1205. X{
  1206. X  fprintf(stderr,"%s",mesg);
  1207. X  fputc(' ',stderr);
  1208. X  fflush(stderr);
  1209. X  perror(NULL);
  1210. X  if ( code == EXIT ) exit( 1 );
  1211. X  return;
  1212. X}
  1213. SHAR_EOF
  1214. chmod 0644 ss.c || echo "restore of ss.c fails"
  1215. sed 's/^X//' << 'SHAR_EOF' > ss.base.h &&
  1216. X/* ss.h */
  1217. X/* writen by Mat Watson 12/01/90 */
  1218. X/*
  1219. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1220. X
  1221. XPermission to use, copy, and/or distribute for any purpose and 
  1222. Xwithout fee is hereby granted, provided that both the above copyright 
  1223. Xnotice and this permission notice appear in all copies and derived works. 
  1224. XFees for distribution of this software or for derived sources may only 
  1225. Xbe charged with the express written permission of the copyright holders. 
  1226. XThis software is provided ``as is'' without express or implied warranty.
  1227. X*/
  1228. X
  1229. X#define MaxSockets 30
  1230. X#define EXIT 0
  1231. X#define CONT 1
  1232. X
  1233. Xtypedef struct m_in_socket SOCKET;
  1234. Xtypedef struct m_in_socket_array SOCKARRAY;
  1235. X
  1236. Xstruct m_in_socket {
  1237. X  int sd;
  1238. X  struct sockaddr_in addr;
  1239. X  int _rcnt;
  1240. X  char *_rptr;
  1241. X  char *_rbase;
  1242. X  int _rbufsiz;
  1243. X  int _wcnt;
  1244. X  char *_wptr;
  1245. X  char *_wbase;
  1246. X  int _wbufsiz;
  1247. X  short _flag;
  1248. X};
  1249. X
  1250. Xstruct m_in_socket_array {
  1251. X  int n_sockets;
  1252. X  SOCKET *spa[MaxSockets];
  1253. X  fd_set readfds;
  1254. X  fd_set writefds;
  1255. X  fd_set exceptfds;
  1256. X};
  1257. X
  1258. X/* define flags */
  1259. X/**/
  1260. X#define SS_IOFBF  0
  1261. X#define SS_IOREAD 01
  1262. X#define SS_IOWRT  02
  1263. X#define SS_IONBF  04
  1264. X#define SS_IOMYBUF        010
  1265. X#define SS_IOEOF  020
  1266. X#define SS_IOERR  040
  1267. X#define SS_IOSTRG 0100
  1268. X#define SS_IOLBF  0200
  1269. X#define SS_IORW   0400
  1270. X#define SS_NULL    0
  1271. X#define SS_EOF     (-1)
  1272. X#define SS_BUFSIZ  1024
  1273. X
  1274. X#define SockGetc(p)  (--(p)->_rcnt>=0? ((int)*(p)->_rptr++):_SockFilbuf(p))
  1275. X
  1276. X#define SockPutc(x, p)  (--(p)->_wcnt >= 0 ?\
  1277. X        (int)(*(p)->_wptr++ = (char)(x)) :\
  1278. X           (((p)->_flag & SS_IOLBF) && -(p)->_wcnt < (p)->_wbufsiz ?\
  1279. X                ((*(p)->_wptr = (char)(x)) != '\n' ?\
  1280. X                        (int)(*(p)->_wptr++) :\
  1281. X                        _SockFlsbuf(*(char *)(p)->_wptr, p)) :\
  1282. X                _SockFlsbuf((char)(x), p)))
  1283. X
  1284. X#define SockEof(p)         (((p)->_flag&SS_IOEOF)!=0)
  1285. X#define SockError(p)       (((p)->_flag&SS_IOERR)!=0)
  1286. X#define SockFileno(p)       ((p)->sd)
  1287. X#define SockClearerr(p)     (void) ((p)->_flag &= ~(SS_IOERR|SS_IOEOF))
  1288. X
  1289. X#ifdef __STDC__
  1290. X# define    P_(s) s
  1291. X#else
  1292. X# define P_(s) ()
  1293. X#endif
  1294. X
  1295. X
  1296. X/* ss.c */
  1297. XSOCKET *AcceptSock P_((SOCKET *ssp ));
  1298. Xvoid AddSock P_((SOCKET *sp , SOCKARRAY *sap ));
  1299. XSOCKET *ConnectSock P_((char *hostname , unsigned port_number ));
  1300. Xint IsExceptSet P_((SOCKET *sp ));
  1301. Xint IsReadSet P_((SOCKET *sp ));
  1302. Xint IsWriteSet P_((SOCKET *sp ));
  1303. Xvoid RemoveSock P_((SOCKET *sp ));
  1304. XSOCKET *ServerSock P_((unsigned port_number ));
  1305. Xvoid SockArrayInit P_((SOCKARRAY *sap ));
  1306. Xint SockClose P_((SOCKET *sp ));
  1307. Xint _SockFilbuf P_((SOCKET *sp ));
  1308. Xint _SockFlsbuf P_((int x , SOCKET *sp ));
  1309. Xint SockFlush P_((SOCKET *sp ));
  1310. Xchar *SockGets P_((char *s , int n , SOCKET *sp ));
  1311. Xint SockIndex P_((SOCKET *sp , SOCKARRAY *sap ));
  1312. Xvoid SockInit P_((int c ));
  1313. Xint SockIsRead P_((SOCKET *sp ));
  1314. Xint SockIsWrite P_((SOCKET *sp ));
  1315. Xint SockPuts P_((char *s , SOCKET *sp ));
  1316. Xint SockSelect P_((double timeout , char *flag ));
  1317. Xvoid SockSignal P_((int sig ));
  1318. Xint SockWrites P_((char *s , SOCKET *sp ));
  1319. Xvoid sserror P_((char *mesg , int code ));
  1320. X
  1321. X#undef P_
  1322. SHAR_EOF
  1323. chmod 0644 ss.base.h || echo "restore of ss.base.h fails"
  1324. sed 's/^X//' << 'SHAR_EOF' > ss.sun.h &&
  1325. X/* ss.h */
  1326. X/* writen by Mat Watson 12/01/90 */
  1327. X/*
  1328. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1329. X
  1330. XPermission to use, copy, and/or distribute for any purpose and 
  1331. Xwithout fee is hereby granted, provided that both the above copyright 
  1332. Xnotice and this permission notice appear in all copies and derived works. 
  1333. XFees for distribution of this software or for derived sources may only 
  1334. Xbe charged with the express written permission of the copyright holders. 
  1335. XThis software is provided ``as is'' without express or implied warranty.
  1336. X*/
  1337. X#include <stdio.h>
  1338. X#include <signal.h>
  1339. X#include <errno.h>
  1340. X#include "stdlib.h"
  1341. X#include <sys/types.h>
  1342. X#include <sys/param.h>
  1343. X#include <sys/socket.h>
  1344. X#include <netinet/in.h>
  1345. X#include <netdb.h>
  1346. X#include <sys/time.h>
  1347. SHAR_EOF
  1348. chmod 0644 ss.sun.h || echo "restore of ss.sun.h fails"
  1349. sed 's/^X//' << 'SHAR_EOF' > ss.ibm.h &&
  1350. X/* ss.h */
  1351. X/* writen by Mat Watson 12/01/90 */
  1352. X/*
  1353. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1354. X
  1355. XPermission to use, copy, and/or distribute for any purpose and 
  1356. Xwithout fee is hereby granted, provided that both the above copyright 
  1357. Xnotice and this permission notice appear in all copies and derived works. 
  1358. XFees for distribution of this software or for derived sources may only 
  1359. Xbe charged with the express written permission of the copyright holders. 
  1360. XThis software is provided ``as is'' without express or implied warranty.
  1361. X*/
  1362. X#include <stdio.h>
  1363. X#include <signal.h>
  1364. X#include <errno.h>
  1365. X#include "stdlib.h"
  1366. X#include <sys/types.h>
  1367. X#include <sys/param.h>
  1368. X#include <sys/socket.h>
  1369. X#include <sys/select.h>
  1370. X#include <netinet/in.h>
  1371. X#include <netdb.h>
  1372. X#include <sys/time.h>
  1373. SHAR_EOF
  1374. chmod 0644 ss.ibm.h || echo "restore of ss.ibm.h fails"
  1375. sed 's/^X//' << 'SHAR_EOF' > ss.3b2.h &&
  1376. X/* ss.h */
  1377. X/* writen by Mat Watson 12/01/90 */
  1378. X/*
  1379. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1380. X
  1381. XPermission to use, copy, and/or distribute for any purpose and 
  1382. Xwithout fee is hereby granted, provided that both the above copyright 
  1383. Xnotice and this permission notice appear in all copies and derived works. 
  1384. XFees for distribution of this software or for derived sources may only 
  1385. Xbe charged with the express written permission of the copyright holders. 
  1386. XThis software is provided ``as is'' without express or implied warranty.
  1387. X*/
  1388. X#include <errno.h>
  1389. X#include <sys/types.h>
  1390. X#include <sys/param.h>
  1391. X#include <sys/socket.h>
  1392. X#include <sys/in.h>
  1393. X#include <netdb.h>
  1394. X#include <sys/time.h>
  1395. Xtypedef int fd_set;
  1396. Xtypedef unsigned short u_short;
  1397. SHAR_EOF
  1398. chmod 0644 ss.3b2.h || echo "restore of ss.3b2.h fails"
  1399. sed 's/^X//' << 'SHAR_EOF' > test.h &&
  1400. X#define SERVER_HOSTNAME "zeus.opt-sci.arizona.edu" /* your machine name. */
  1401. X#define PORT_NUMBER 4020
  1402. SHAR_EOF
  1403. chmod 0644 test.h || echo "restore of test.h fails"
  1404. sed 's/^X//' << 'SHAR_EOF' > stdlib.h &&
  1405. X/* stdlib.h */
  1406. Xchar *malloc();
  1407. Xchar *calloc();
  1408. SHAR_EOF
  1409. chmod 0644 stdlib.h || echo "restore of stdlib.h fails"
  1410. sed 's/^X//' << 'SHAR_EOF' > server1.c &&
  1411. X/* server1.c */
  1412. X/*
  1413. X  Writen by Mat Watson 12/01/90
  1414. X*/
  1415. X/*
  1416. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1417. X
  1418. XPermission to use, copy, and/or distribute for any purpose and 
  1419. Xwithout fee is hereby granted, provided that both the above copyright 
  1420. Xnotice and this permission notice appear in all copies and derived works. 
  1421. XFees for distribution of this software or for derived sources may only 
  1422. Xbe charged with the express written permission of the copyright holders. 
  1423. XThis software is provided ``as is'' without express or implied warranty.
  1424. X*/
  1425. X#include <stdio.h>
  1426. X#include "ss.h"
  1427. X#include "test.h"
  1428. X
  1429. Xmain()
  1430. X{
  1431. X  SOCKET *ssp, *csp;
  1432. X  char buffer[100], *result;
  1433. X  int n_read;
  1434. X
  1435. X  /* open a socket that clients can connect to. */
  1436. X  ssp = ServerSock( PORT_NUMBER );
  1437. X
  1438. X  /* Wait for a client to connect.  Accept input from the client.
  1439. X     Close the client socket pointer when the connection is broken
  1440. X     by the client.  Then wait again for another connection.  */
  1441. X
  1442. X  (void)printf("Use ^C to stop this program\n");
  1443. X
  1444. X  while(1) {
  1445. X    /* Wait for a client to connect. */
  1446. X    csp = AcceptSock( ssp );
  1447. X
  1448. X    (void)printf("Accepted a client.\n");
  1449. X
  1450. X    /* Read whatever the client sends, and print that out to the
  1451. X     * standard output.
  1452. X     */
  1453. X    while((result=SockGets(buffer,sizeof(buffer)-1,csp)) != SS_NULL) {
  1454. X      (void)printf("%s", buffer);
  1455. X    }
  1456. X
  1457. X    /* Close the socket. */
  1458. X    SockClose( csp );
  1459. X    (void)printf("Client disconnected.\n");
  1460. X  }
  1461. X}
  1462. SHAR_EOF
  1463. chmod 0644 server1.c || echo "restore of server1.c fails"
  1464. sed 's/^X//' << 'SHAR_EOF' > client1.c &&
  1465. X/* client1.c */
  1466. X/*
  1467. X  Writen by Mat Watson 12/01/90
  1468. X*/
  1469. X/*
  1470. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1471. X
  1472. XPermission to use, copy, and/or distribute for any purpose and 
  1473. Xwithout fee is hereby granted, provided that both the above copyright 
  1474. Xnotice and this permission notice appear in all copies and derived works. 
  1475. XFees for distribution of this software or for derived sources may only 
  1476. Xbe charged with the express written permission of the copyright holders. 
  1477. XThis software is provided ``as is'' without express or implied warranty.
  1478. X*/
  1479. X#include <stdio.h>
  1480. X#include "ss.h"
  1481. X#include "test.h"
  1482. X
  1483. Xmain()
  1484. X{
  1485. X  char *line, buffer[200];
  1486. X  SOCKET *ssp;
  1487. X
  1488. X
  1489. X  /* Establish a connection with the server. */
  1490. X  ssp = ConnectSock( SERVER_HOSTNAME, PORT_NUMBER );
  1491. X  if( ssp == SS_NULL )
  1492. X    sserror("server1: ConnectSock()", EXIT);
  1493. X
  1494. X  /* Get text from the standard input, and send it to the server program */
  1495. X  (void)printf("enter text (^d to quit)\n");
  1496. X  while( ( line = gets(buffer) ) != NULL ) {
  1497. X    sprintf(buffer, "%s\n", line);
  1498. X    SockWrites(buffer, ssp);
  1499. X  }
  1500. X  (void)printf("Saioonara\n");
  1501. X  SockClose(ssp);
  1502. X  exit(0);
  1503. X}
  1504. SHAR_EOF
  1505. chmod 0644 client1.c || echo "restore of client1.c fails"
  1506. sed 's/^X//' << 'SHAR_EOF' > server2.c &&
  1507. X/* server2.c */
  1508. X/*
  1509. X  Writen by Mat Watson 12/01/90
  1510. X*/
  1511. X/*
  1512. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1513. X
  1514. XPermission to use, copy, and/or distribute for any purpose and 
  1515. Xwithout fee is hereby granted, provided that both the above copyright 
  1516. Xnotice and this permission notice appear in all copies and derived works. 
  1517. XFees for distribution of this software or for derived sources may only 
  1518. Xbe charged with the express written permission of the copyright holders. 
  1519. XThis software is provided ``as is'' without express or implied warranty.
  1520. X*/
  1521. X#include <stdio.h>
  1522. X#include "ss.h"
  1523. X
  1524. X#define PORT_NUMBER 4020
  1525. X
  1526. Xmain()
  1527. X{
  1528. X  SOCKET *ssp, *csp;
  1529. X  char buffer[100], *result;
  1530. X
  1531. X  /* Open a socket for clients to connect to. */
  1532. X  ssp = ServerSock( PORT_NUMBER );
  1533. X
  1534. X  /* Look to see if a client wants to connect to the server socket.
  1535. X     If there's a client take input from it until the client breaks
  1536. X     the connection.  If there's no client trying to connect then
  1537. X     just do something else.                                        */
  1538. X
  1539. X  (void)printf("Use ^C to stop this program\n");
  1540. X
  1541. X  while(1) {
  1542. X    SockSelect( 5.0, "r" );       /* Wait 5 seconds for a client to
  1543. X                     request a connection. */
  1544. X    if( IsReadSet( ssp ) ) {      /* Is a client is trying to connect? */
  1545. X      csp = AcceptSock( ssp );    /* Accept the connection. */
  1546. X      (void)printf("Accepted a client\n");
  1547. X      /* Accept input until client disconnects. Print that output to the
  1548. X     standard ouput. */
  1549. X      while( (result=SockGets(buffer,sizeof(buffer)-1,csp)) != SS_NULL ) {
  1550. X    (void)printf("%s", buffer);
  1551. X      }
  1552. X      if( SockClose(csp) == SS_EOF )
  1553. X    sserror("server2 - SockClose()",CONT);
  1554. X      (void)printf("Client disconnected.\n");
  1555. X    }
  1556. X    else {
  1557. X      (void)printf("doing something else\n");
  1558. X    }
  1559. X  }
  1560. X}
  1561. SHAR_EOF
  1562. chmod 0644 server2.c || echo "restore of server2.c fails"
  1563. sed 's/^X//' << 'SHAR_EOF' > client2.c &&
  1564. X/* client2.c */
  1565. X/*
  1566. X  Writen by Mat Watson 12/01/90
  1567. X*/
  1568. X/*
  1569. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1570. X
  1571. XPermission to use, copy, and/or distribute for any purpose and 
  1572. Xwithout fee is hereby granted, provided that both the above copyright 
  1573. Xnotice and this permission notice appear in all copies and derived works. 
  1574. XFees for distribution of this software or for derived sources may only 
  1575. Xbe charged with the express written permission of the copyright holders. 
  1576. XThis software is provided ``as is'' without express or implied warranty.
  1577. X*/
  1578. X/* Exercise the SockPuts() or the SockWrites() command */
  1579. X#include <stdio.h>
  1580. X#include "ss.h"
  1581. X#include "test.h"
  1582. X
  1583. Xmain()
  1584. X{
  1585. X  char *line, buffer[200], message[200];
  1586. X  SOCKET *ssp;
  1587. X  ssp = ConnectSock( "zeus.opt-sci.arizona.edu", 4020 );
  1588. X  if( ssp == SS_NULL ) {
  1589. X    printf("ConnectSock returned SS_NULL.  Exiting ..... \n\n");
  1590. X    exit(1);
  1591. X  }
  1592. X
  1593. X#ifdef PUTC
  1594. X  SockPutc('a',ssp);
  1595. X  SockPutc('\n',ssp);
  1596. X  SockFlush(ssp);
  1597. X#endif /* PUTC */
  1598. X  SockWrites("I'm the client\n",ssp);
  1599. X  printf("enter text (^d to end)\n");
  1600. X  while( ( line = gets(buffer) ) != NULL ) {
  1601. X    sprintf(message,"%s\n",line);
  1602. X    /*
  1603. X    SockPuts(message,ssp);
  1604. X    */
  1605. X    SockWrites(message,ssp);
  1606. X  }
  1607. X  
  1608. X  SockFlush(ssp);
  1609. X  SockClose(ssp);
  1610. X  exit(0);
  1611. X}
  1612. SHAR_EOF
  1613. chmod 0644 client2.c || echo "restore of client2.c fails"
  1614. sed 's/^X//' << 'SHAR_EOF' > server3.c &&
  1615. X/* server.c */
  1616. X/* Writen by Mat Watson 12/01/90
  1617. X*/
  1618. X/*
  1619. XCopyright (c) 1990 Mat Watson and Hubert Bartels. All rights reserved. 
  1620. X
  1621. XPermission to use, copy, and/or distribute for any purpose and 
  1622. Xwithout fee is hereby granted, provided that both the above copyright 
  1623. Xnotice and this permission notice appear in all copies and derived works. 
  1624. XFees for distribution of this software or for derived sources may only 
  1625. Xbe charged with the express written permission of the copyright holders. 
  1626. XThis software is provided ``as is'' without express or implied warranty.
  1627. X*/
  1628. X#include <stdio.h>
  1629. X#include "ss.h"
  1630. X#include "test.h"
  1631. X
  1632. Xtypedef struct client_list CLIST;
  1633. Xchar *malloc();
  1634. Xstruct client_list {
  1635. X  CLIST *prev;
  1636. X  CLIST *next;
  1637. X  SOCKET *sp;
  1638. X};
  1639. X
  1640. XCLIST * AddClient( sp, clp )
  1641. XSOCKET *sp;
  1642. XCLIST *clp;
  1643. X{
  1644. X  CLIST *newclp;
  1645. X
  1646. X  newclp = (CLIST *)malloc( sizeof( struct client_list ) );
  1647. X  newclp->prev = SS_NULL;
  1648. X  newclp->sp = sp;
  1649. X  newclp->next = clp;
  1650. X  if( clp != SS_NULL )
  1651. X    clp->prev = newclp;
  1652. X  return newclp;
  1653. X}
  1654. X
  1655. XCLIST * RemoveClient( p_remove, clp )
  1656. XCLIST *p_remove;
  1657. XCLIST *clp;
  1658. X{
  1659. X  CLIST *p, *pnext;
  1660. X
  1661. X  for( p = clp; p; p = p->next )
  1662. X    if( p == p_remove )
  1663. X      break;
  1664. X  if( !p )
  1665. X    perror("RemoveClient(): sp not in client list");
  1666. X  if( p->prev )
  1667. X    (p->prev)->next = p->next;
  1668. X  if( p->next )
  1669. X    (p->next)->prev = p->prev;
  1670. X
  1671. X  pnext = p->next; /* we may want to return this value
  1672. X              after deallocating p              */
  1673. X
  1674. X  free( (char *)p );
  1675. X  return p == clp ? pnext : clp;
  1676. X}
  1677. X
  1678. Xmain()
  1679. X{
  1680. X  SOCKET *ssp, *csp;
  1681. X  char buffer[100], *result, cmesg[100];
  1682. X  int n_read;
  1683. X  CLIST *clp, *p;
  1684. X  int test;
  1685. X
  1686. X  clp = SS_NULL;
  1687. X
  1688. X  (void)printf("Use ^C to stop this program.\n");
  1689. X
  1690. X  ssp = ServerSock( PORT_NUMBER );
  1691. X  printf("Server socket opened on descriptor %d\n",ssp->sd);
  1692. X
  1693. X  while(1) {
  1694. X    (void)printf("Waiting for input or a connection.\n");
  1695. X    SockSelect( -5.0, "r" );  /* Block until something is ready to be
  1696. X                 read from. */
  1697. X    if( IsReadSet( ssp ) > 0 ) { /* Connect new clients first. */
  1698. X      csp = AcceptSock( ssp );
  1699. X      clp = AddClient( csp, clp );
  1700. X      (void)printf("Adding client on descriptor %d.\n",csp->sd);
  1701. X      /* Ask a silly question.*/
  1702. X      SockWrites("Client, what is your pid number?\n",csp); 
  1703. X    }
  1704. X    else /* no new clients to connect. */ {
  1705. X      if( clp != SS_NULL ) {
  1706. X    (void)printf("Looping over clients.\n");
  1707. X    p = clp;
  1708. X    while( p ) {
  1709. X          (void)printf("  ");  /* Not necessary. Makes output look nice. */
  1710. X      if( /* Either of the following two statements will work. */ 
  1711. X         IsReadSet(p->sp) > 0 /* This function relies on the last call to
  1712. X                     SockSelect(). */
  1713. X         /* SockIsRead(p->sp) /* This function calls select() again; however,
  1714. X        it only affects IsXxxSet() for this socket.
  1715. X        */ 
  1716. X         ) {
  1717. X        result = SockGets(buffer, 99 , p->sp );
  1718. X        if( result == SS_NULL ) {
  1719. X          goto remove;
  1720. X        }
  1721. X        printf("%s",buffer); /* Get a silly answer. */
  1722. X        /* Repeat the silly question. */
  1723. X        test = SockWrites("Client, what is your pid number?\n",p->sp);
  1724. X        if( test == SS_EOF ) {
  1725. X          goto remove;
  1726. X        }
  1727. X      } /* end if socket ready to read from */
  1728. X      else {
  1729. X        (void)printf("Descriptor %d was not ready for reading.\n",p->sp->sd);
  1730. X      }
  1731. X      p = p->next;
  1732. X      continue;
  1733. X    remove:  {
  1734. X      CLIST *tmp;
  1735. X      (void)printf("Removing client with descriptor = %d.\n",p->sp->sd);
  1736. X      tmp = p->next;
  1737. X      SockClose( p->sp );
  1738. X      /* RemoveClient frees the space pointed to by p, so we need to
  1739. X         store its 'next' pointer in the variable tmp. */
  1740. X      clp = RemoveClient( p, clp );
  1741. X      p = tmp;
  1742. X    } /* end ther remove clause. */
  1743. X    } /* end the while clients. */
  1744. X    (void)printf("Done looping over clients.\n");
  1745. X      } /* end if client list is non null. */
  1746. X    } /* end of else.  No new clients to connect. */
  1747. X  } /* end of infinite while loop. */
  1748. X}  /* end the program */
  1749. SHAR_EOF
  1750. chmod 0644 server3.c || echo "restore of server3.c fails"
  1751. sed 's/^X//' << 'SHAR_EOF' > client3.c &&
  1752. X/* client3.c */
  1753. X/*
  1754. X  Writen by Mat Watson 12/01/90
  1755. X*/
  1756. X#include <stdio.h>
  1757. X#include <errno.h>
  1758. X#include "ss.h"
  1759. X#include "test.h"
  1760. Xmain()
  1761. X{
  1762. X  char *line, buffer[200], message[200],message1[100];
  1763. X  int pid;
  1764. X  int result;
  1765. X  SOCKET *ssp;
  1766. X  int n;
  1767. X  int i;
  1768. X
  1769. X  /* Attempt to connect to the server program. */
  1770. X  ssp = ConnectSock( SERVER_HOSTNAME, PORT_NUMBER );
  1771. X  if( ssp == SS_NULL ) {
  1772. X    printf("ConnectSock returned SS_NULL.  Exiting ..... \n\n");
  1773. X    return;
  1774. X  }
  1775. X  pid = getpid();
  1776. X  (void)printf("This clients pid is %d.\n",pid);
  1777. X  /* Create a message to send to the server program. */
  1778. X  sprintf(message,"Client pid = %d.\n",pid);
  1779. X
  1780. X  i = 3;
  1781. X  while( i ) {
  1782. X    i--;
  1783. X    sleep(2);
  1784. X    n = SockSelect( -5.0, "r" );  /* Block, Check for any open socket
  1785. X                      being read ready. */
  1786. X    if( IsReadSet( ssp ) ) {   /* Do we have anything to be read from the
  1787. X                  server? */
  1788. X      SockGets(message1,99,ssp);  /* Read it. */
  1789. X      printf("%s",message1);      /* Print it out. */
  1790. X      fflush(stdout);             /* Now! :-) */
  1791. X      result = SockWrites(message,ssp);
  1792. X      if( result == SS_EOF ) break; /* Probably connection broken. */
  1793. X    }
  1794. X  }
  1795. X  if( errno == EPIPE )
  1796. X    (void)printf("Server disconnected\n");
  1797. X  (void)printf("bye\n"); fflush(stdout);
  1798. X  exit(0);
  1799. X}
  1800. SHAR_EOF
  1801. chmod 0644 client3.c || echo "restore of client3.c fails"
  1802. exit 0
  1803.