ncftp for win32 3.0.3
[reactos.git] / reactos / apps / utils / net / ncftp / sio / sio.html
1 <HTML>
2 <HEAD>
3 <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
4 <META NAME="Author" CONTENT="Mike Gleason">
5 <META NAME="GENERATOR" CONTENT="Mozilla/4.03 [en] (WinNT; I) [Netscape]">
6 <TITLE>sio: SocketIO Library</TITLE>
7 </HEAD>
8 <BODY BGCOLOR="#FFFFFF">
9
10 <H1>
11 SocketIO Library Documentation</H1>
12
13 <UL>
14 <LI>
15 <A HREF="#Introduction">Introduction</A></LI>
16
17 <LI>
18 <A HREF="#Installation">Installation</A></LI>
19
20 <LI>
21 <A HREF="#Functions">Function Reference</A></LI>
22
23 <LI>
24 <A HREF="#Sample">Sample Code</A></LI>
25 </UL>
26 The purpose of the <I>SocketIO Library</I> (<I>sio</I> for short) is to
27 provide a safe and consistent wrapper interface to a BSD Sockets implementation.&nbsp;
28 The library also takes steps to protect against a few common pitfalls that
29 plague poorly written BSD Sockets programs.&nbsp; Specifically, it was
30 designed to do the following:
31
32
33 <UL>
34 <LI>
35 Take care of reading and writing the full operation.
36
37 <P><FONT SIZE=-1>For example, a network <TT>write()</TT> for 50 bytes may
38 only write 30 bytes; <I>Sio</I> would continue writing until all 50 bytes
39 have been sent.</FONT>
40 <P></LI>
41
42 <LI>
43 <P>
44 Allow operations that would normally block can be set to timeout after
45 a customizable period of time.<P></LI>
46
47 <LI>
48 <P>
49 Catch the SIGPIPE signal which would cause an unexpecting process to exit.<P>
50
51 <P><FONT SIZE=-1>A frequent source of problems for beginning programmers
52 is the situation where their process is suddenly no longer running because
53 a write to a socket caused a broken pipe. This problem can be difficult
54 to diagnose if the process is running as a daemon process in the background.</FONT>
55 <P>
56 </LI>
57
58 <LI>
59 <P>
60 Resume operation when system calls are interrupted (operations errout
61 with <TT>EINTR</TT>).<P></LI>
62
63 <LI>
64 <P>
65 Cater to the internet socket interface (i.e. <TT>struct sockaddr_in</TT>).<P></LI>
66
67 <LI>
68 <P>
69 Simplified interface to name service.
70
71
72 <P><FONT SIZE=-1>Library routines can take a textual address specification
73 instead of you having to prepare a <TT>struct sockaddr_in</TT>.</FONT>
74 <P>
75 </LI>
76
77 </UL>
78 The library was written by Mike Gleason. The first incarnation dates
79 back to some time in 1992. The library may be used and distributed
80 freely, as long as you give due credit.
81 <P>
82 <H3>
83 <A NAME="Introduction"></A>Introduction</H3>
84 The reader is assumed to be familiar with BSD Sockets.&nbsp; An excellent
85 source of information is W. Richard Stevens' <U>UNIX Network Programming,
86 Volume 1, Second Edition: Networking APIs: Sockets and XTI</U>, Prentice
87 Hall, 1998, ISBN 0-13-490012-X.
88 <BR>&nbsp;
89 <H4>
90 <A NAME="Connection_modes"></A>Connection modes</H4>
91 A communications exchange between two end-points can be connection-oriented
92 or connectionless.&nbsp; An connection-oriented exchange is characterized
93 by a connection establishment, a series of messages, and a disconnection.&nbsp;
94 A connectionless exchange is characterized by one or more independent messages.&nbsp;
95 An analogy to a connection-oriented exchange would be a telephone call
96 where one party establishes a connection to another, and a conversation
97 ensues.&nbsp; A connectionless exchange analogy would be a letter sent
98 via the postal service -- even if a writer sends two letters to the same
99 recipient, each letter is transported independently.
100 <BR>&nbsp;
101 <H4>
102 <A NAME="Message_modes"></A>Message modes</H4>
103 For the <I>sio</I> library, all connection-oriented exchanges are data
104 streams using the <I>TCP/IP</I> protocol.&nbsp; After connection establishment,
105 the conversation consists of one long sequence of data bytes, which is
106 known as a <I>stream</I>.&nbsp; Therefore there is no concept of a record
107 boundary associated with a stream connection at the transport level, although
108 often there is a record associated over the stream at the application level.&nbsp;
109 The important thing here is to realize that there is no flow control associated
110 with the stream, so although the data bytes are guaranteed to arrive in
111 order, there is no guarantee that messages will be read in the same size
112 blocks as they were originally written.
113
114 <P>For connectionless exchanges, <I>sio</I> uses the <I>UDP/IP</I> protocol's
115 datagram messages.&nbsp; There is an implicit definition of a record boundary,
116 because each message is treated as a record. So, three writes results in
117 three separate messages.
118
119 <P>For example, let's say a sender writes three 50-byte messages.&nbsp;
120 If a receiver does a 20-byte read followed by 100-byte read followed by
121 a 50-byte read, the receiver would get the first 20 bytes of the first
122 message, 50 of 50 bytes of the second message, and 50 of 50 bytes of the
123 third message.&nbsp; It's important to understand that in the first read
124 that since UDP datagrams are message oriented that the remaining 30 bytes
125 of the first message are lost, and that although the second read is for
126 100 bytes, the read immediately returns as finished even though only 50
127 bytes were actually read.
128
129 <P>With UDP datagrams, there are also other important implications that
130 affect message ordering, duplication, and overall reliability.
131 <BR>&nbsp;
132 <H4>
133 <A NAME="Creating_and_disposing"></A>Creating and disposing sockets</H4>
134 A socket is an I/O descriptor that is associated with one side of a communications
135 exchange.&nbsp; A socket must be either a client or a server, although
136 after communications is established the difference is arbitrary.&nbsp;
137 A server socket is one that waits for contact to be initiated by a client
138 on a mutually agreed upon address and port number.&nbsp; A client socket
139 initiates the first communication by sending to an existing server socket.&nbsp;
140 Client and server sockets may of course be on different machines, and different
141 networks altogether.
142
143 <P>A stream server socket is created using <TT><A HREF="#SNewStreamServer">SNewStreamServer()</A></TT>,
144 which returns a socket file descriptor ready to accept new client connections.&nbsp;
145 After a socket descriptor is obtained, your server program can then use
146 <TT><A HREF="#SAccept">SAccept()</A></TT> to establish a connection with
147 a client.
148
149 <P>A stream client socket is created using <TT><A HREF="#SNewStreamClient">SNewStreamClient()</A></TT>.&nbsp;
150 After a socket descriptor is obtained, your client program can use <TT><A HREF="#SConnectByName">SConnectByName()</A></TT>
151 or <TT><A HREF="#SConnect">SConnect()</A></TT> to initiate a connection
152 to a server.
153
154 <P>A datagram server socket is created using <TT><A HREF="#SNewDatagramServer">SNewDatagramServer()</A></TT>.&nbsp;
155 After a socket descriptor is obtained, it is ready to receive messages
156 from clients using <TT><A HREF="#SRecvfrom">SRecvfrom()</A></TT> and reply
157 back with <TT><A HREF="#SSendto">SSendto()</A></TT>.
158
159 <P>A datagram client socket is created using <TT><A HREF="#SNewDatagramClient">SNewDatagramClient()</A></TT>.&nbsp;
160 After a socket descriptor is obtained, it is ready to communicate with
161 servers using <TT><A HREF="#SSendto">SSendto()</A></TT> and <TT><A HREF="#SRecvfrom">SRecvfrom()</A></TT>.
162
163 <P>All socket descriptors are disposed of with <TT><A HREF="#SClose">SClose()</A></TT>
164 when communication is finished.
165 <BR>&nbsp;
166 <H4>
167 <A NAME="SocketIO"></A>Socket I/O</H4>
168 A stream connection uses <TT><A HREF="#SRead">SRead()</A></TT> to receive
169 data from the stream and <TT><A HREF="#SWrite">SWrite()</A></TT> to send
170 data.&nbsp; A datagram socket should use <TT><A HREF="#SRecvfrom">SRecvfrom()</A></TT>
171 to read a message and <TT><A HREF="#SSendtoByName">SSendtoByName()</A></TT>
172 or <TT><A HREF="#SSendto">SSendto()</A></TT> to send a message.&nbsp; Since
173 each datagram communication is independent, these routines use an address
174 specifier along with each call.
175 <BR>&nbsp;
176 <H3>
177 <A NAME="Installation"></A>Installation</H3>
178 First, unpack the archive. If the package arrived as a '.tar.gz' or '.tgz'
179 file, you need to run gunzip, and then tar to extract the source files.
180 You can do that in one shot by doing "<TT>gunzip -c sio.tgz | tar xvf -</TT>".
181 If the package you have is a '.tar' file you can use "<TT>tar xvf sio.tar</TT>".
182 If the package you have is a '.zip' file you can use "<TT>unzip sio.zip</TT>"
183 or "<TT>pkunzip sio.zip</TT>".
184
185 <P>Now go to the "<TT>sio</TT>" directory you just made. There is a script
186 you must run which will checks your system for certain features, so that
187 the library can be compiled on a variety of U<FONT SIZE=-1>NIX</FONT> systems.
188 Run this script by typing "<TT>sh ./configure</TT>" in that directory.
189 After that, you can look at the <TT>Makefile</TT> it made if you like,
190 and then you run "<TT>make</TT>" to create the "<TT>libsio.a</TT>" library
191 file.
192
193 <P>Finally, install the library and headers. You can manually copy the
194 files, or you can run "<TT>make install</TT>" to copy the files for you.
195 If you choose to "<TT>make install</TT>" you may want to edit the <TT>Makefile</TT>
196 if you do not want to install to the <TT>/usr/local</TT> tree.
197 <BR>&nbsp;
198 <H3>
199 <A NAME="Functions"></A>Function Reference</H3>
200
201 <UL>
202 <table width="100%">
203 <tr>
204 <td><A HREF="#AddrStrToAddr">AddrStrToAddr</A></td>
205 <td><A HREF="#SConnectByName">SConnectByName</A></td>
206 <td><A HREF="#SSendtoByName">SSendtoByName</A></td>
207 </tr>
208 <tr>
209 <td><A HREF="#AddrToAddrStr">AddrToAddrStr</A></td>
210 <td><A HREF="#SListen">SListen</A></td>
211 <td><A HREF="#SWrite">SWrite</A></td>
212 </tr>
213 <tr>
214 <td><A HREF="#DisposeSReadlineInfo">DisposeSReadlineInfo</A></td>
215 <td><A HREF="#SNewDatagramClient">SNewDatagramClient</A></td>
216 <td><A HREF="#SelectR">SelectR</A></td>
217 </tr>
218 <tr>
219 <td><A HREF="#FlushSReadlineInfo">FlushSReadlineInfo</A></td>
220 <td><A HREF="#SNewDatagramServer">SNewDatagramServer</A></td>
221 <td><A HREF="#SelectSetAdd">SelectSetAdd</A></td>
222 </tr>
223 <tr>
224 <td><A HREF="#GetSocketBufSize">GetSocketBufSize</A></td>
225 <td><A HREF="#SNewStreamClient">SNewStreamClient</A></td>
226 <td><A HREF="#SelectSetInit">SelectSetInit</A></td>
227 </tr>
228 <tr>
229 <td><A HREF="#GetSocketLinger">GetSocketLinger</A></td>
230 <td><A HREF="#SNewStreamServer">SNewStreamServer</A></td>
231 <td><A HREF="#SelectSetRemove">SelectSetRemove</A></td>
232 </tr>
233 <tr>
234 <td><A HREF="#GetSocketNagleAlgorithm">GetSocketNagleAlgorithm</A></td>
235 <td><A HREF="#SRead">SRead</A></td>
236 <td><A HREF="#SelectW">SelectW</A></td>
237 </tr>
238 <tr>
239 <td><A HREF="#InitSReadlineInfo">InitSReadlineInfo</A></td>
240 <td><A HREF="#SReadline">SReadline</A></td>
241 <td><A HREF="#Sendto">Sendto</A></td>
242 </tr>
243 <tr>
244 <td><A HREF="#SAcceptA">SAcceptA</A></td>
245 <td><A HREF="#SRecv">SRecv</A></td>
246 <td><A HREF="#SendtoByName">SendtoByName</A></td>
247 </tr>
248 <tr>
249 <td><A HREF="#SAcceptS">SAcceptS</A></td>
250 <td><A HREF="#SRecvfrom">SRecvfrom</A></td>
251 <td><A HREF="#SetSocketBufSize">SetSocketBufSize</A></td>
252 </tr>
253 <tr>
254 <td><A HREF="#SBind">SBind</A></td>
255 <td><A HREF="#SRecvmsg">SRecvmsg</A></td>
256 <td><A HREF="#SetSocketLinger">SetSocketLinger</A></td>
257 </tr>
258 <tr>
259 <td><A HREF="#SClose">SClose</A></td>
260 <td><A HREF="#SSend">SSend</A></td>
261 <td><A HREF="#SetSocketNagleAlgorithm">SetSocketNagleAlgorithm</A></td>
262 </tr>
263 <tr>
264 <td><A HREF="#SConnect">SConnect</A></td>
265 <td><A HREF="#SSendto">SSendto</A></td>
266 </tr>
267 </table>
268 </UL>
269
270 <H5>
271 <A NAME="AddrStrToAddr"></A>AddrStrToAddr</H5>
272 <TT>int</TT> <TT>AddrStrToAddr(const char * const s, struct sockaddr_in
273 * const sa, const int defaultPort);</TT>
274
275 <P>This takes a textual internet address specification and converts it
276 to a <TT>struct sockaddr_in</TT>.&nbsp; An address string may be any of
277 the following forms:
278 <UL>
279 <LI>
280 <TT>hostname:port</TT></LI>
281
282 <LI>
283 <TT>service://hostname</TT></LI>
284
285 <LI>
286 <TT>service://hostname:port</TT></LI>
287
288 <LI>
289 <TT>service://hostname[/more/junk/which/is/ignored/]</TT></LI>
290
291 <LI>
292 <TT>port@hostname</TT></LI>
293 </UL>
294 Additionally, the <I>hostname</I> may be a name or an IP address string
295 (i.e. <TT>192.168.1.13</TT>).
296
297 <P>If the string contains a hostname but a port number does not appear
298 to be present and the <I>defaultPort</I> parameter is greater than zero,
299 then the address structure will use <I>defaultPort</I> as the port number.
300
301 <P>The function returns a negative number if the string could not be converted,
302 such as the case where the hostname was not found in the name service.
303 Name service is not used unless there is a name instead of an IP address,
304 so if you don't want to use name service, only use IP addresses.
305
306 <P><I>Example</I>:
307 <UL>
308 <PRE>struct sockaddr_in addr;
309 int result;
310
311 result = AddrStrToAddr("ftp.probe.net", &amp;addr, 21);
312 result = AddrStrToAddr("ftp.probe.net:21", &amp;addr, 21);
313 result = AddrStrToAddr("206.28.166.234:21", &amp;addr, 21);
314 result = AddrStrToAddr("ftp://ftp.probe.net", &amp;addr, 0);
315 result = AddrStrToAddr("21@ftp.probe.net", &amp;addr, 0);</PRE>
316 </UL>
317
318 <UL>
319 <PRE></PRE>
320 </UL>
321
322 <H5>
323 <A NAME="#AddrToAddrStr"></A>AddrToAddrStr</H5>
324 <TT>char *AddrToAddrStr(char *const dst, size_t dsize, struct sockaddr_in
325 * const saddrp, int dns, const char *fmt);</TT>
326
327 <P>This function takes a <TT>struct sockaddr_in</TT> and converts into
328 a readable internet textual address.
329
330 <P>The <I>dns</I> parameter specifies if name service should be used to
331 lookup the symbolic hostname from the raw address.&nbsp; If zero, it expresses
332 the raw IP address in the standard dotted-decimal format, like 192.168.1.13.
333
334 <P>The <I>fmt</I> parameter is a magic cookie string, with the following
335 cookies:
336 <UL>
337 <LI>
338 <TT>%h</TT> = hostname</LI>
339
340 <LI>
341 <TT>%p</TT> = port number</LI>
342
343 <LI>
344 <TT>%s</TT> = service name (based off of the port number)</LI>
345 </UL>
346 This lets you print the address in just about any way you like.&nbsp; The
347 <I>dst</I> parameter is the string to write the results to, and is always
348 null-terminated.&nbsp; The <I>dst</I> parameter is also returned as the
349 result of the function.
350
351 <P><I>Example</I>:
352 <UL>
353 <PRE>char str[128];
354
355 fputs(AddrToAddrStr(str, sizeof(str), &amp;sin, 1, "%h"), stdout);
356 fputs(AddrToAddrStr(str, sizeof(str), &amp;sin, 1, "%h:%p"), stdout);
357 fputs(AddrToAddrStr(str, sizeof(str), &amp;sin, 1, "%s://%h"), stdout);</PRE>
358 </UL>
359
360 <H5>
361 <A NAME="#DisposeSReadlineInfo"></A>DisposeSReadlineInfo</H5>
362 <TT>void DisposeSReadlineInfo(SReadlineInfo *srl);</TT>
363
364 <P>This function is used to dispose of a <TT>SReadlineInfo</TT> structure
365 that was created using <TT><A HREF="#InitSReadlineInfo">InitSReadlineInfo()</A></TT>.&nbsp;
366 You're required to use this to free dynamically allocated buffers it creates
367 unless you specified that you wanted to use your own buffer, in which case
368 it's optional (but recommended for clarity).
369 <H5>
370 <A NAME="#FlushSReadlineInfo"></A>FlushSReadlineInfo</H5>
371 <TT>void FlushSReadlineInfo(SReadlineInfo *srl);</TT>
372
373 <P>This rarely used function is used to reset and clear the buffer used
374 by <TT><A HREF="#SReadline">SReadline()</A></TT>.&nbsp; It acts similarly
375 to a <TT>fflush(stdin)</TT>.
376 <H5>
377 <A NAME="#GetSocketBufSize"></A>GetSocketBufSize</H5>
378 <TT>int GetSocketBufSize(int sockfd, size_t *const rsize, size_t *const
379 ssize);</TT>
380
381 <P>This utility routine returns the size of the socket's internal buffers,
382 as maintained by the kernel (or socket library).&nbsp; It does this by
383 calling <TT>getsockopt()</TT> with the <TT>SO_RCVBUF</TT> and <TT>SO_SNDBUF</TT>
384 options, if they are defined.&nbsp; In the event they aren't defined, it
385 returns a negative result code.
386
387 <P><I>Example</I>:
388 <UL>
389 <PRE>size_t rsize, ssize;
390
391 if (GetSocketBufSize(sockfd, &amp;rsize, &amp;ssize) == 0) ...</PRE>
392 </UL>
393
394 <H5>
395 <A NAME="#GetSocketLinger"></A>GetSocketLinger</H5>
396 <TT>int GetSocketLinger(const int fd, int *const lingertime);</TT>
397
398 <P>This utility routine returns whether linger mode has been turned on,
399 and also sets the amount of time in the <I>lingertime</I> parameter.
400
401 <P><I>Example</I>:
402 <UL>
403 <PRE>int lingertime;
404
405 if (GetSocketLinger(sockfd, &amp;lingtime) > 0)
406 &nbsp;&nbsp;&nbsp; /* linger is on... */ ...;</PRE>
407 </UL>
408
409 <H5>
410 <A NAME="#GetSocketNagleAlgorithm"></A>GetSocketNagleAlgorithm</H5>
411 <TT>int GetSocketNagleAlgorithm(const int fd);</TT>
412
413 <P>This utility routine returns whether the <I>Nagle Algorithm</I> is in
414 effect (<TT>TCP_NODELAY</TT> mode not on).
415 <H5>
416 <A NAME="#InitSReadlineInfo"></A>InitSReadlineInfo</H5>
417 <TT>int InitSReadlineInfo(SReadlineInfo *srl, int sockfd, char *buf, size_t
418 bsize, int tlen);</TT>
419
420 <P>This function is used to prepare a <TT>SReadlineInfo</TT> structure
421 for use with the <TT><A HREF="#SReadline">SReadline()</A></TT> function.&nbsp;
422 The <I>sockfd</I> parameter specifies the socket that will be used for
423 line buffering.&nbsp; The <I>sio</I> library does not open or close this
424 socket.
425
426 <P>The buf parameter is the area of memory to use for buffering; it should
427 be large enough to hold several lines of data.&nbsp; If <I>buf</I> is NULL,
428 the function will <TT>malloc()</TT> one of <I>bsize</I> bytes, otherwise
429 it is assumed that buf is maintained by you and is of size <I>bsize</I>
430 bytes.&nbsp; If you let <I>sio</I> <TT>malloc()</TT> this buffer, you must
431 also use <TT><A HREF="#DisposeSReadlineInfo">DisposeSReadlineInfo()</A></TT>
432 to free it when you're finished with it.
433
434 <P>The <I>tlen</I> parameter is the timeout value (in seconds) to use for
435 each call of <TT><A HREF="#SReadline">SReadline()</A></TT>.
436
437 <P><I>Example</I>:
438 <UL>
439 <PRE>SReadlineInfo sri;
440 char localbuf[2048];
441
442 if (InitSReadlineInfo(&amp;sri, sockfd, NULL, 512, 10) &lt; 0)
443 &nbsp;&nbsp;&nbsp; perror("malloc 512 bytes failed");
444 ...or...
445 (void) InitSReadlineInfo(&amp;sri, sockfd, localbuf, sizeof(localbuf), 10);</PRE>
446 </UL>
447
448 <H5>
449 <A NAME="SAccept"></A>SAccept</H5>
450 <TT>int SAccept(int sfd, struct sockaddr_in *const addr, int tlen);</TT>
451
452 <P>This is does an <TT>accept()</TT>, with a timeout of <I>tlen</I> seconds
453 (<I>tlen</I> may be zero to mean block indefinitely).&nbsp; If no new connection
454 is accepted, <TT>kTimeoutErr</TT> is returned, otherwise a new socket or
455 (-1) is returned.&nbsp; The socket is still usable if a timeout occurred,
456 so you can call <TT>SAccept()</TT> again.
457 <H5>
458 <A NAME="#SBind"></A>SBind</H5>
459 <TT>int SBind(int sockfd, const int port, const int nTries, const int reuseFlag);</TT>
460
461 <P>This calls <TT>bind()</TT>, to the wildcard address with the specified
462 <I>port </I>(not in network byte order).&nbsp; The <I>nTries</I> parameter
463 tells how many attempts it tries before giving up (which is useful if other
464 processes are grabbing the same port number).&nbsp; If the <I>reuseFlag</I>
465 parameter is non-zero, <TT>SBind()</TT> tries to turn on the <TT>SO_REUSEADDR</TT>
466 (and <TT>SO_REUSEPORT</TT>, if available) socket options before binding.
467
468 <P>Normally you will not call this function directly, since <TT><A HREF="#SNewStreamServer">SNewStreamServer()</A></TT>
469 and <TT><A HREF="#SNewDatagramServer">SNewDatagramServer()</A></TT> do
470 this for you.
471 <H5>
472 <A NAME="#SClose"></A>SClose</H5>
473 <TT>int SClose(int sfd, int tlen);</TT>
474
475 <P>This is <TT>close()</TT> with a timeout of <I>tlen</I> seconds.&nbsp;
476 Normally you don't need to worry about <TT>close()</TT> blocking, but if
477 you have turned on linger mode, <TT>close()</TT> could block.&nbsp; <TT>SClose()</TT>
478 calls <TT>close()</TT> for up to <I>tlen</I> seconds, and if the timeout
479 expires, it calls <TT>shutdown()</TT> on the socket.
480 <H5>
481 <A NAME="#SConnect"></A>SConnect</H5>
482 <TT>int SConnect(int sfd, const struct sockaddr_in *const addr, int tlen);</TT>
483
484 <P>This is <TT>connect()</TT> with a timeout of <I>tlen</I> seconds (<I>tlen</I>
485 may be zero to mean block indefinitely).&nbsp; If it returns (-1) or <TT>kTimeoutErr</TT>,
486 the socket is no longer usable and must be closed.
487 <H5>
488 <A NAME="#SConnectByName"></A>SConnectByName</H5>
489 <TT>int SConnectByName(int sfd, const char * const addrStr, const int tlen);</TT>
490
491 <P>This is <TT>connect()</TT> with a timeout of <I>tlen</I> seconds (<I>tlen</I>
492 may be zero to mean block indefinitely).&nbsp; If it returns (-1) or <TT>kTimeoutErr</TT>,
493 the socket is no longer usable and must be closed. The difference between
494 <TT><A HREF="#SConnect">SConnect()</A></TT> is that this function takes
495 a textual address string instead of a <TT>struct sockaddr_in</TT>.
496
497 <P><I>Example</I>:
498 <UL>
499 <PRE>if (SConnectByName(sockfd, "http://www.probe.net", 15) == 0) ...</PRE>
500 </UL>
501
502 <H5>
503 <A NAME="#SListen"></A>SListen</H5>
504 <TT>int SListen(int sfd, int backlog);</TT>
505
506 <P>This isn't too useful at present, since it just does <TT>listen(sfd,
507 backlog)</TT>.&nbsp; And, you will not call this function directly, since
508 <TT><A HREF="#SNewStreamServer">SNewStreamServer()</A></TT> and <TT><A HREF="#SNewDatagramServer">SNewDatagramServer()</A></TT>
509 do this for you.
510 <H5>
511 <A NAME="#SNewDatagramClient"></A>SNewDatagramClient</H5>
512 <TT>int SNewDatagramClient(void);</TT>
513
514 <P>This returns a new datagram socket, which is ready to send (and then
515 receive) datagrams.&nbsp; This function is just <TT>socket(AF_INET, SOCK_DGRAM,
516 0)</TT>. If successful, it returns a non-negative socket descriptor.
517
518 <P><I>Example</I>:
519 <UL>
520 <PRE>int sockfd;
521
522 sockfd = SNewDatagramClient();</PRE>
523 </UL>
524
525 <H5>
526 <A NAME="#SNewDatagramServer"></A>SNewDatagramServer</H5>
527 <TT>int SNewDatagramServer(const int port, const int nTries, const int
528 reuseFlag);</TT>
529
530 <P>This function creates a new socket and binds it to the specified <I>port</I>
531 (not in network byte order) on the wildcard address.&nbsp; The <I>nTries</I>
532 and <I>reuseFlag</I> are used when it calls <TT><A HREF="#SBind">SBind()</A></TT>.
533 If successful, it returns a non-negative socket descriptor.
534
535 <P><I>Example</I>:
536 <UL>
537 <PRE>int sockfd;
538
539 sockfd = SNewDatagramServer(13, 3, 0);
540 if (sockfd >= 0)
541 &nbsp;&nbsp;&nbsp; /* ready to receive requests on the daytime port (13) */</PRE>
542 </UL>
543
544 <H5>
545 <A NAME="#SNewStreamClient"></A>SNewStreamClient</H5>
546 <TT>int SNewStreamClient(void);</TT>
547 <P>
548 This returns a new stream socket, which is ready to <TT><A HREF="#SConnect">SConnect()</A></TT>
549 to a server.&nbsp; This function is just <TT>socket(AF_INET, SOCK_STREAM,
550 0)</TT>.&nbsp; If successful, it returns a non-negative socket descriptor.
551
552 <P><I>Example</I>:
553 <UL>
554 <PRE>int sockfd;
555
556 sockfd = SNewStreamClient();</PRE>
557 </UL>
558
559 <H5>
560 <A NAME="#SNewStreamServer"></A>SNewStreamServer</H5>
561 <TT>int SNewStreamServer(const int port, const int nTries, const int reuseFlag,
562 int listenQueueSize);</TT>
563
564 <P>This function creates a new socket, binds it to the specified <I>port</I>
565 (not in network byte order) on the wildcard address, and turns it on for
566 listening.&nbsp; The <I>nTries</I> and <I>reuseFlag</I> are used when it
567 calls <TT><A HREF="#SBind">SBind()</A></TT>. The <I>listenQueueSize</I>
568 is for the <TT>listen()</TT> call.&nbsp; If successful, it returns a non-negative
569 socket descriptor.
570
571 <P><I>Example</I>:
572 <UL>
573 <PRE>int sockfd;
574
575 sockfd = SNewStreamServer(80, 3, 0);
576 if (sockfd >= 0)
577 &nbsp;&nbsp;&nbsp; /* ready to accept HTTP connections */</PRE>
578 </UL>
579
580 <H5>
581 <A NAME="#SRead"></A>SRead</H5>
582 <TT>int SRead(int sfd, char *const buf0, size_t size, int tlen, int retry);</TT>
583
584 <P>This is <TT>read()</TT> on a socket descriptor, with a timeout of <I>tlen</I>
585 seconds (<I>tlen</I> must be greater than zero).&nbsp; Like <TT>read()</TT>,
586 it can return 0, (-1), or the number of bytes read, but in addition, it
587 can also return <TT>kTimeoutErr</TT>.
588
589 <P>If <I>retry</I> is set to <TT>kFullBufferRequired</TT>, <TT>SRead()</TT>
590 does not return until <I>size</I> bytes has been read or EOF is encountered.&nbsp;
591 This is useful if you expect fixed-length records, and it doesn't do much
592 good until a complete record has been read. However, it is still possible
593 that an EOF is encountered after some bytes have been read, and with <I>retry</I>
594 set to <TT>kFullBufferRequired</TT>, you get EOF instead of that partial
595 record.&nbsp; If you set retry to <TT>kFullBufferRequiredExceptLast</TT>,
596 you get the partial record (and EOF on the next <TT>SRead()</TT>).&nbsp;
597 Otherwise, if you should set retry to kFullBufferNotRequired and SRead()
598 will return when there is some data read.
599
600 <P><I>Example</I>:
601 <UL>
602 <PRE>int nread;
603 char buf[256];
604
605 while (1) {
606 &nbsp;&nbsp;&nbsp; nread = SRead(sockfd, buf, sizeof(buf), 15, kFullBufferNotRequired);
607 &nbsp;&nbsp;&nbsp; if (nread &lt;= 0) {
608 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nread == 0)
609 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;&nbsp;&nbsp;&nbsp; /* okay, EOF */
610 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (nread == kTimeoutErr) {
611 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "timed-out\n");
612 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;
613 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {
614 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; perror("read");
615 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
616 &nbsp;&nbsp;&nbsp; }
617 &nbsp;&nbsp;&nbsp; (void) write(1, buf, nread);
618 }</PRE>
619 </UL>
620
621 <H5>
622 <A NAME="#SReadline"></A>SReadline</H5>
623 <TT>int SReadline(SReadlineInfo *srl, char *const linebuf, size_t linebufsize);</TT>
624
625 <P>It is often desirable to process data from sockets line by line, however
626 this is cumbersome to do on a socket descriptor.&nbsp; The <TT>SReadline()</TT>
627 function allows you to do this, so you can do one call of the function
628 and get back a line of input.&nbsp; It accomplishes this much the same
629 way the standard library's I/O routines do this, using a buffer.&nbsp;
630 However, it is usually not possible to determine if the standard library
631 takes the same special I/O measures on socket descriptors that sio does,
632 so using the standard library function <TT>fdopen()</TT> with a socket
633 descriptor may or may not work the way you want.
634
635 <P><TT>SReadline()</TT> needs to maintain state information for each call,
636 so a data structure is required.&nbsp; You must first call <TT><A HREF="#InitSReadlineInfo">InitSReadlineInfo()</A></TT>
637 to initialize a <TT>SReadlineInfo</TT> structure.&nbsp; After that, you
638 may call <TT>SReadline()</TT> repeatedly until it returns 0 to indicate
639 EOF. The function returns the number of characters in the input line, including
640 a newline (however, carriage return characters are omitted).&nbsp; You
641 must call <TT><A HREF="#DisposeSReadlineInfo">DisposeSReadlineInfo()</A></TT>
642 if you chose to let <TT><A HREF="#InitSReadlineInfo">InitSReadlineInfo()</A></TT>
643 use <TT>malloc()</TT> to allocate your buffer.
644
645 <P><I>Example</I>:
646 <UL>
647 <PRE>SReadlineInfo sri;
648 char line[80];
649 int nread;
650
651 if (InitSReadlineInfo(&amp;sri, sockfd, NULL, 512, 10) &lt; 0) {
652 &nbsp;&nbsp;&nbsp; perror("malloc");
653 &nbsp;&nbsp;&nbsp; exit(1);
654 }
655 while (1) {
656 &nbsp;&nbsp;&nbsp; nread = SReadline(&amp;sri, line, sizeof(line));
657 &nbsp;&nbsp;&nbsp; if (nread &lt;= 0) {
658 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (nread == kTimeoutErr)
659 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "readline timed-out.\n");
660 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (nread &lt; 0)
661 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; perror("readline");
662 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;
663 &nbsp;&nbsp;&nbsp; }
664 &nbsp;&nbsp;&nbsp; line[nread] = '\0';&nbsp;&nbsp;&nbsp; /* omit newline */
665 &nbsp;&nbsp;&nbsp; fprintf(stdout, "read [%s]\n", line);
666 }
667 DisposeSReadlineInfo(&amp;sri);
668 (void) SClose(sockfd, 3);</PRE>
669 </UL>
670
671 <H5>
672 <A NAME="#SRecv"></A>SRecv</H5>
673 <TT>int SRecv(int sfd, char *const buf0, size_t size, int fl, int tlen,
674 int retry);</TT>
675
676 <P>This is the corresponding wrapper for <TT>recv()</TT>, as <TT><A HREF="#SRead">SRead()</A></TT>
677 is for <TT>read()</TT>.&nbsp; You will never need this function, unless
678 you need the special receiving flags that <TT>recv()</TT> gives you.
679 <H5>
680 <A NAME="#SRecvfrom"></A>SRecvfrom</H5>
681 <TT>int SRecvfrom(int sfd, char *const buf, size_t size, int fl, struct
682 sockaddr_in *const fromAddr, int tlen);</TT>
683
684 <P>This is <TT>recvfrom()</TT> with a timeout of <I>tlen</I> seconds (<I>tlen</I>
685 must be greater than zero).&nbsp; Like <TT>recvfrom()</TT>, it can return
686 0, (-1), or the number of bytes read, but in addition, it can also return
687 <TT>kTimeoutErr</TT>. Upon a timeout, the socket is still valid for additional
688 I/O.
689
690 <P><I>Example</I>:
691 <UL>
692 <PRE>int nread;
693 char buf[80];
694 struct sockaddr_in remoteClientAddr;
695
696 nread = SRecvfrom(sockfd, buf, sizeof(buf), 0, &amp;remoteClientAddr, 15);
697 if (nread &lt;= 0) {
698 &nbsp;&nbsp;&nbsp; if (nread == kTimeoutErr)
699 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "recvfrom timed-out.\n");
700 &nbsp;&nbsp;&nbsp; else if (nread &lt; 0)
701 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; perror("recvfrom");
702 }</PRE>
703 </UL>
704
705 <H5>
706 <A NAME="#SRecvmsg"></A>SRecvmsg</H5>
707 <TT>int SRecvmsg(int sfd, void *const msg, int fl, int tlen);</TT>
708
709 <P>This is the corresponding wrapper for <TT>recvmsg()</TT>, as <TT><A HREF="#SRead">SRead()</A></TT>
710 is for <TT>read()</TT>.
711 <H5>
712 <A NAME="#SSend"></A>SSend</H5>
713 <TT>int SSend(int sfd, char *buf0, size_t size, int fl, int tlen);</TT>
714
715 <P>This is the corresponding wrapper for <TT>send()</TT>, as <TT><A HREF="#SWrite">SWrite()</A></TT>
716 is for <TT>write()</TT>.&nbsp; You will never need this function, unless
717 you need the special receiving flags that <TT>send()</TT> gives you.
718 <H5>
719 <A NAME="#SSendto"></A>SSendto</H5>
720 <TT>int SSendto(int sfd, const char *const buf, size_t size, int fl, const
721 struct sockaddr_in *const toAddr, int tlen);</TT>
722
723 <P>This is <TT>sendto()</TT> with a timeout of <I>tlen</I> seconds (<I>tlen</I>
724 must be greater than zero).&nbsp; Like <TT>sendto()</TT>, it can return
725 0, (-1), or the number of bytes sent, but in addition, it can also return
726 <TT>kTimeoutErr</TT>. Upon a timeout, the socket is still valid for additional
727 I/O.
728
729 <P>Since <TT>sendto()</TT> rarely blocks (only if the outgoing queue is
730 full), you probably do not want to use a timeout or bother with its associated
731 overhead; therefore <TT><A HREF="#Sendto">Sendto()</A></TT> would be a
732 better choice.
733 <H5>
734 <A NAME="#SSendtoByName"></A>SSendtoByName</H5>
735 <TT>int SSendtoByName(int sfd, const char *const buf, size_t size, int
736 fl, const char *const toAddrStr, int tlen);</TT>
737
738 <P>This is <TT><A HREF="#SSendto">SSendto()</A></TT>, only you can use
739 a textual internet address string instead of a <TT>struct sockaddr_in</TT>.
740 <H5>
741 <A NAME="#SWrite"></A>SWrite</H5>
742 <TT>int SWrite(int sfd, const char *const buf0, size_t size, int tlen);</TT>
743
744 <P>This is <TT>write()</TT> on a network socket with a timeout of <I>tlen</I>
745 seconds (<I>tlen</I> must be greater than zero).&nbsp; Like <TT>write()</TT>,
746 it can return 0, (-1), or the number of bytes sent, but in addition, it
747 can also return <TT>kTimeoutErr</TT>.
748 <H5>
749 <A NAME="SelectR"></A>SelectR</H5>
750 <TT>int SelectR(SelectSetPtr ssp, SelectSetPtr resultssp);</TT>
751
752 <P>This does a <TT>select()</TT> for reading with the file descriptors
753 in the specified <TT>SelectSet</TT>.&nbsp; Using a <TT>SelectSet</TT> ensures
754 that the first argument to select is always correct (the smallest correct
755 value, for speed) and <TT>SelectR()</TT> does not destroy the original
756 <TT>fd_set</TT> and <TT>timeval</TT> (it copies it to <I>resultssp</I>
757 before using <TT>select()</TT>).
758
759 <P><I>Example</I>:
760 <UL>
761 <PRE>SelectSet ss, selected;
762
763 SelectSetInit(&amp;ss, 10.0);
764 SelectSetAdd(&amp;ss, sockfd1);
765 SelectSetAdd(&amp;ss, sockfd2);
766 rc = SelectR(&amp;ss, &amp;selected);
767 if ((rc > 0) &amp;&amp; (FD_ISSET(sockfd2, &amp;selected.fds))) ...</PRE>
768 </UL>
769
770 <H5>
771 <A NAME="SelectW"></A>SelectW</H5>
772 <TT>int SelectW(SelectSetPtr ssp, SelectSetPtr resultssp);</TT>
773
774 <P>This does a <TT>select()</TT> for writing with the file descriptors
775 in the specified <TT>SelectSet</TT>.&nbsp; Using a <TT>SelectSet</TT> ensures
776 that the first argument to select is always correct (the smallest correct
777 value, for speed) and <TT>SelectW()</TT> does not destroy the original
778 <TT>fd_set</TT> and <TT>timeval</TT> (it copies it to <I>resultssp</I>
779 before using <TT>select()</TT>).
780
781 <P><I>Example</I>:
782 <UL>
783 <PRE>SelectSet ss, selected;
784
785 SelectSetInit(&amp;ss, 10.0);
786 SelectSetAdd(&amp;ss, sockfd1);
787 SelectSetAdd(&amp;ss, sockfd2);
788 rc = SelectW(&amp;ss, &amp;selected);
789 if ((rc > 0) &amp;&amp; (FD_ISSET(sockfd2, &amp;selected.fds))) ...</PRE>
790 </UL>
791
792 <H5>
793 <A NAME="#SelectSetAdd"></A>SelectSetAdd</H5>
794 <TT>void SelectSetAdd(SelectSetPtr const ssp, const int fd);</TT>
795
796 <P>This adds a descriptor to the set to select on.
797
798 <P><I>Example</I>:
799 <UL>
800 <PRE>SelectSet ss;
801
802 SelectSetInit(&amp;ss, 10.0);
803 SelectSetAdd(&amp;ss, sockfd);</PRE>
804 </UL>
805
806 <H5>
807 <A NAME="#SelectSetInit"></A>SelectSetInit</H5>
808 <TT>void SelectSetInit(SelectSetPtr const ssp, const double timeout);</TT>
809
810 <P>Before adding members to the <TT>SelectSet</TT> structure, it must be
811 initialized with this function.&nbsp; The timeout parameter initializes
812 the timeout to use for future <TT>Selects</TT>.
813 <H5>
814 <A NAME="#SelectSetRemove"></A>SelectSetRemove</H5>
815 <TT>void SelectSetRemove(SelectSetPtr const ssp, const int fd);</TT>
816
817 <P>This removes a descriptor from the set to select on.&nbsp; You will
818 need to do this just before you close a descriptor that was in the set.
819 <H5>
820 <A NAME="#Sendto"></A>Sendto</H5>
821 <TT>int Sendto(int sfd, const char *const buf, size_t size, const struct
822 sockaddr_in *const toAddr);</TT>
823
824 <P>This is a simple wrapper for <TT>sendto()</TT>, which only handles <TT>EINTR</TT>
825 for you.&nbsp; It does not worry about <TT>SIGPIPEs</TT>.
826 <H5>
827 <A NAME="#SendtoByName"></A>SendtoByName</H5>
828 <TT>int SendtoByName(int sfd, const char *const buf, size_t size, const
829 char *const toAddrStr);</TT>
830
831 <P>This is a simple wrapper for <TT>sendto()</TT>, which only handles <TT>EINTR</TT>
832 for you.&nbsp; In addition, you can use a textual internet address string
833 instead of a <TT>struct sockaddr_in</TT>.
834
835 <P><I>Example</I>:
836 <UL>
837 <PRE>if (SendtoByName(sockfd, msg, sizeof(msg), "elwood.probe.net:13") > 0) ...</PRE>
838 </UL>
839
840 <H5>
841 <A NAME="#SetSocketBufSize"></A>SetSocketBufSize</H5>
842 <TT>int SetSocketBufSize(int sockfd, size_t rsize, size_t ssize);</TT>
843
844 <P>This utility routine changes the size of the socket's internal buffers,
845 as maintained by the kernel (or socket library).&nbsp; It does this by
846 calling <TT>setsockopt()</TT> with the <TT>SO_RCVBUF</TT> and <TT>SO_SNDBUF</TT>
847 options, if they are defined.&nbsp; In the event they aren't defined, it
848 returns a negative result code.&nbsp; The operation is only performed if
849 the size is greater than zero, so if you only wanted to change the receive
850 buffer you could set <I>rsize</I> to greater than zero and <I>ssize</I>
851 to 0.
852 <H5>
853 <A NAME="#SetSocketLinger"></A>SetSocketLinger</H5>
854 <TT>int SetSocketLinger(const int fd, const int l_onoff, const int l_linger);</TT>
855
856 <P>This is an interface to the <TT>SO_LINGER</TT> socket option.&nbsp;
857 The <I>l_onoff</I> parameter is a boolean specifying whether linger is
858 on, and the <I>l_linger</I> parameter specifies the length of the linger
859 time if enabled.
860
861 <P><I>Example</I>:
862 <UL>
863 <PRE>if (SetSocketLinger(sockfd, 1, 90) == 0) ...</PRE>
864 </UL>
865
866 <H5>
867 <A NAME="#SetSocketNagleAlgorithm"></A>SetSocketNagleAlgorithm</H5>
868 <TT>int SetSocketNagleAlgorithm(const int fd, const int onoff);</TT>
869
870 <P>This utility routine enables or disables the <I>Nagle Algorithm</I>
871 (<TT>TCP_NODELAY</TT> mode is off or on).&nbsp; Generally you won't care
872 about this, unless you're writing an interactive application like <I>telnet</I>,
873 <I>talk</I>, or <I>rlogin</I>, where response time is more important than
874 throughput.
875
876 <P><I>Example</I>:
877 <UL>
878 <PRE>if (SetSocketNagleAlgorithm(sockfd, 0) == 0) ...</PRE>
879 </UL>
880
881 <H3>
882 <A NAME="Sample"></A>Sample Code</H3>
883 Here is an example client and server that uses the <I>sio</I> library routines.&nbsp;
884 The server simply takes data and uppercases any lower case data, and returns
885 the result to the client.&nbsp; To try it on port number 5123, you could
886 run "<TT>ucase_s 5123</TT>" in one window, and "<TT>ucase_c localhost:5123</TT>"
887 in another.
888 <BR>&nbsp;
889 <H4>
890 Server:</H4>
891
892 <PRE>/* ucase_s.c */
893
894 #include &lt;unistd.h&gt;
895 #include &lt;sys/types.h&gt;
896 #include &lt;sys/socket.h&gt;
897 #include &lt;sys/wait.h&gt;
898 #include &lt;netinet/in.h&gt;
899 #include &lt;arpa/inet.h&gt;
900 #include &lt;errno.h&gt;
901 #include &lt;stdio.h&gt;
902 #include &lt;string.h&gt;
903 #include &lt;stdlib.h&gt;
904 #include &lt;time.h&gt;
905
906 #include &quot;sio.h&quot;
907
908 static void
909 ServeOneClient(int sockfd, struct sockaddr_in *cliAddr)
910 {
911 char buf[32], cliAddrStr[64];
912 int nread, nwrote, i;
913
914 printf(&quot;subserver[%d]: started, connected to %s.\n&quot;, (int) getpid(),
915 AddrToAddrStr(cliAddrStr, sizeof(cliAddrStr), cliAddr, 1, &quot;&lt;%h:%p&gt;&quot;)
916 );
917 for (;;) {
918 nread = SRead(sockfd, buf, sizeof(buf), 15, kFullBufferNotRequired);
919 if (nread == 0) {
920 break;
921 } else if (nread &lt; 0) {
922 fprintf(stderr, &quot;subserver[%d]: read error: %s\n&quot;,
923 (int) getpid(), strerror(errno));
924 break;
925 }
926 for (i=0; i&lt;nread; i++)
927 if (islower(buf[i]))
928 buf[i] = toupper(buf[i]);
929 nwrote = SWrite(sockfd, buf, nread, 15);
930 if (nwrote &lt; 0) {
931 fprintf(stderr, &quot;subserver[%d]: write error: %s\n&quot;,
932 (int) getpid(), strerror(errno));
933 break;
934 }
935 }
936 (void) SClose(sockfd, 10);
937 printf(&quot;subserver[%d]: done.\n&quot;, (int) getpid());
938 exit(0);
939 } /* ServeOneClient */
940
941
942 static void
943 Server(int port)
944 {
945 int sockfd, newsockfd;
946 struct sockaddr_in cliAddr;
947 int pid;
948
949 sockfd = SNewStreamServer(port, 3, kReUseAddrYes, 3);
950 if (sockfd &lt; 0) {
951 perror(&quot;Server setup failed&quot;);
952 exit(1);
953 }
954
955 printf(&quot;server[%d]: started.\n&quot;, (int) getpid());
956 for(;;) {
957 while (waitpid(-1, NULL, WNOHANG) &gt; 0) ;
958 newsockfd = SAccept(sockfd, &amp;cliAddr, 5);
959 if (newsockfd &lt; 0) {
960 if (newsockfd == kTimeoutErr)
961 printf(&quot;server[%d]: idle\n&quot;, (int) getpid());
962 else
963 fprintf(stderr, &quot;server[%d]: accept error: %s\n&quot;,
964 (int) getpid(), strerror(errno));
965 } else if ((pid = fork()) &lt; 0) {
966 fprintf(stderr, &quot;server[%d]: fork error: %s\n&quot;,
967 (int) getpid(), strerror(errno));
968 exit(1);
969 } else if (pid == 0) {
970 ServeOneClient(newsockfd, &amp;cliAddr);
971 exit(0);
972 } else {
973 /* Parent doesn't need it now. */
974 (void) close(newsockfd);
975 }
976 }
977 } /* Server */
978
979
980 void
981 main(int argc, char **argv)
982 {
983 int port;
984
985 if (argc &lt; 2) {
986 fprintf(stderr, &quot;Usage: %s &lt;port&gt;\n&quot;, argv[0]);
987 exit(2);
988 }
989 port = atoi(argv[1]);
990 Server(port);
991 exit(0);
992 } /* main */
993 </PRE>
994
995 <H4>
996 Client:</H4>
997
998 <PRE>/* ucase_c.c */
999
1000 #include &lt;unistd.h&gt;
1001 #include &lt;sys/types.h&gt;
1002 #include &lt;sys/socket.h&gt;
1003 #include &lt;sys/wait.h&gt;
1004 #include &lt;netinet/in.h&gt;
1005 #include &lt;arpa/inet.h&gt;
1006 #include &lt;errno.h&gt;
1007 #include &lt;stdio.h&gt;
1008 #include &lt;string.h&gt;
1009 #include &lt;stdlib.h&gt;
1010 #include &lt;time.h&gt;
1011
1012 #include &quot;sio.h&quot;
1013
1014 static void
1015 Client(char *serverAddrStr)
1016 {
1017 char buf[256];
1018 int nread, nwrote, sockfd;
1019
1020 sockfd = SNewStreamClient();
1021 if (sockfd &lt; 0) {
1022 fprintf(stderr, &quot;client[%d]: socket error: %s\n&quot;,
1023 (int) getpid(), strerror(errno));
1024 exit(1);
1025 }
1026
1027 if (SConnectByName(sockfd, serverAddrStr, 15) &lt; 0) {
1028 fprintf(stderr, &quot;client[%d]: could not connect to &lt;%s&gt;: %s\n&quot;,
1029 (int) getpid(), serverAddrStr, strerror(errno));
1030 exit(1);
1031 }
1032
1033 printf(&quot;client[%d]: connected to &lt;%s&gt;.\n&quot;, (int) getpid(), serverAddrStr);
1034 for (buf[sizeof(buf) - 1] = '\0';;) {
1035 printf(&quot;client[%d]: Enter message to send -&gt; &quot;, (int) getpid());
1036 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
1037 break;
1038 buf[strlen(buf) - 1] = '\0'; /* Delete newline. */
1039 if (buf[0] == '\0')
1040 continue; /* Blank line. */
1041
1042 /* Send the request line to the server. */
1043 nwrote = SWrite(sockfd, buf, strlen(buf), 15);
1044 if (nwrote &lt; 0) {
1045 fprintf(stderr, &quot;client[%d]: write error: %s\n&quot;,
1046 (int) getpid(), strerror(errno));
1047 break;
1048 }
1049
1050 /* Wait for complete reply line */
1051 nread = SRead(sockfd, buf, nwrote, 15, kFullBufferRequired);
1052 if (nread == 0) {
1053 fprintf(stderr, &quot;client[%d]: no reply received (EOF).\n&quot;,
1054 (int) getpid());
1055 break;
1056 } else if (nread &lt; 0) {
1057 fprintf(stderr, &quot;client[%d]: read error: %s\n&quot;,
1058 (int) getpid(), strerror(errno));
1059 break;
1060 }
1061 buf[nread] = '\0';
1062 fprintf(stdout, &quot;client[%d]: received: %s\n&quot;,
1063 (int) getpid(), buf);
1064 }
1065 (void) SClose(sockfd, 10);
1066 printf(&quot;\nclient[%d]: done.\n&quot;, (int) getpid());
1067 exit(0);
1068 } /* Client */
1069
1070
1071 void
1072 main(int argc, char **argv)
1073 {
1074 int port;
1075
1076 if (argc &lt; 2) {
1077 fprintf(stderr, &quot;Usage: %s &lt;host:port&gt;\n&quot;, argv[0]);
1078 exit(2);
1079 }
1080 Client(argv[1]);
1081 exit(0);
1082 } /* main */
1083 </PRE>
1084
1085 </BODY>
1086 </HTML>