1/* *****************************************************************************
2
3libcsc: BSD Network Socket Subsystem
4
5	----------------------------------------------------------------
6
7Copyright (c) 1999, 2000, 2001, 2002 Douglas R. Jerome, Peoria, AZ USA
8
9	This program is free software; you can redistribute it and/or modify
10	it under the terms of the GNU Library General Public License as
11	published by the Free Software Foundation; either version 2 of the
12	License, or (at your option) any later version.
13
14	This program is distributed in the hope that it will be useful,
15	but WITHOUT ANY WARRANTY; without even the implied warranty of
16	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17	GNU General Public License for more details.
18
19	You should have received a copy of the GNU Library General Public
20	License along with this program; if not, write to the Free Software
21	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23	----------------------------------------------------------------
24
25FILE NAME
26
27	$RCSfile: csc_sock.c,v $
28	$Revision: 1.5 $
29	$Date: 2002/05/13 04:26:05 $
30
31PROGRAM INFORMATION
32
33	Developed by:	libcsc project
34	Developer:	Douglas R. Jerome, drj, <jerome@primenet.com>
35
36FILE DESCRIPTION
37
38<SUBSYSTEM NAME="csc_sock">
39
40NAME
41	csc_sock
42
43DESCRIPTION
44	BSD Network Socket Subsystem
45
46FUNCTIONS
47	CSCsockConnectTCP - initiate a socket connection
48	CSCsockConnectUDP - initiate a socket connection
49	CSCsockPassiveTCP - listen for connections on a socket
50	CSCsockPassiveUCP - listen for connections on a socket
51</SUBSYSTEM>
52
53CHANGE LOG
54
55	12may02	drj	Small changes to support Solaris.
56
57	02may02	drj	Small changes to support Solaris.
58
59	21apr02	drj	Small comment changes.
60			Readded support for VxWorks.
61
62	11apr02	drj	Changed `CSCgenfnType' to `CSCgenFnType'.
63			               --                --
64
65	25jun01	drj	Converted to libcsc: renamed everything from rt to csc,
66			removed some debug message printing code.
67
68	11may00	drj	Free()'d the piePtr calloc()'d in the local
69			getprotobyname().
70
71	29apr99	drj	Rebaselined from librt version 0.3.1.
72
73***************************************************************************** */
74
75
76/* ************************************************************************* */
77/*                                                                           */
78/*      F e a t u r e   S w i t c h e s                                      */
79/*                                                                           */
80/* ************************************************************************* */
81
82/*
83 * Select these feature by moving them from the `if UNDEF' into the `else'
84 * section.
85 */
86#ifdef	UNDEF
87#   define	_POSIX_SOURCE	1	/* posix.1                      */
88#   define	_POSIX_C_SOURCE	199309L	/* posix.1 and posix.4          */
89#   define	_POSIX_C_SOURCE	199506L	/* posix.1 and posix.4 and MORE */
90#else
91#   define	_BSD_SOURCE	1	/* 4.3+bsd socket subsystem     */
92#   ifndef	_REENTRANT
93#      define	_REENTRANT		/* thread-safe for glibc        */
94#   endif
95#endif
96
97
98/* ************************************************************************* */
99/*                                                                           */
100/*      I n c l u d e d   F i l e s                                          */
101/*                                                                           */
102/* ************************************************************************* */
103
104/*
105 * OS Specific Header Files
106 */
107#ifdef	__vxworks__
108#   include	<vxWorks.h>
109#endif
110#ifdef	SOLARIS
111#   include	<strings.h> /* for bzero, bcopy */
112#endif
113
114/*
115 * Standard C (ANSI) Header Files
116 */
117#include	<errno.h>
118#include	<stdio.h>
119#include	<stdlib.h>
120#include	<string.h>
121
122/*
123 * Posix Header Files
124 */
125#include	<unistd.h>
126
127/*
128 * 4.3+BSD Header Files
129 */
130#ifdef	__vxworks__
131#   include	<inetLib.h>
132#   include	<sockLib.h>
133#else
134#   include	<sys/socket.h>  /* for BSD socket functions */
135#   include	<netinet/in.h>  /* for struct sockaddr_in   */
136#   include	<netdb.h>
137#endif
138
139/*
140 * Project Specific Header Files
141 */
142#include	"libcsc_debug.h"
143#include	"libcsc.h"
144
145
146/* ************************************************************************* */
147/*                                                                           */
148/*      M a n i f e s t   C o n s t a n t s                                  */
149/*                                                                           */
150/* ************************************************************************* */
151
152/*  (None.)  */
153
154
155/* ************************************************************************* */
156/*                                                                           */
157/*      E x t e r n a l   R e f e r e n c e s                                */
158/*                                                                           */
159/* ************************************************************************* */
160
161#ifndef	INADDR_NONE
162#define	INADDR_NONE	(0xFFFFFFFF)
163#endif
164
165#ifndef	USHRT_MAX
166#define	USHRT_MAX	(65535)
167#endif
168
169/*
170 * This 4.3+bsd socket subsystem function is prototyped in arpa/in.h, but I
171 * don't want to include such an old header file. This sort of usage is also
172 * seen in Douglas E. Comer, David L. Stevens "Internetworking with TCP/IP
173 * Vol. III", bsd socket version, (Englewood Cliffs: Prentice Hall, 1993).
174 */
175extern unsigned long   inet_addr (const char*);
176
177
178/* ************************************************************************* */
179/*                                                                           */
180/*      S c a l a r   D a t a   T y p e s                                    */
181/*                                                                           */
182/* ************************************************************************* */
183
184/*  (None.)  */
185
186
187/* ************************************************************************* */
188/*                                                                           */
189/*      N o n - S c a l a r   D a t a   S t r u c t u r e s                  */
190/*                                                                           */
191/* ************************************************************************* */
192
193#ifdef	__vxworks__
194struct  protoent
195   {
196   char*    p_name;     /* official protocol name */
197   char**   p_aliases;  /* alias list             */
198   int      p_proto;    /* protocol number        */
199   };
200struct  servent
201   {
202   char*    s_name;     /* official service name */
203   char**   s_aliases;  /* alias list            */
204   int      s_port;     /* port number           */
205   char*    s_proto;    /* protocol to use       */
206   };
207#endif
208
209
210/* ************************************************************************* */
211/*                                                                           */
212/*      P u b l i c   G l o b a l   V a r i a b l e s                        */
213/*                                                                           */
214/* ************************************************************************* */
215
216/*  (None.)  */
217
218
219/* ************************************************************************* */
220/*                                                                           */
221/*      P r i v a t e   G l o b a l   V a r i a b l e s                      */
222/*                                                                           */
223/* ************************************************************************* */
224
225#ifdef	__vxworks__
226PRIVATE char*   tcpName = "tcp";
227PRIVATE char*   tcpAliases[] = { "TCP", "" };
228PRIVATE char*   udpName = "udp";
229PRIVATE char*   udpAliases[] = { "UDP", "" };
230#endif
231
232
233/* ************************************************************************* */
234/*                                                                           */
235/*      E x e c u t a b l e   C o d e   (Locally Used Functions)             */
236/*                                                                           */
237/* ************************************************************************* */
238
239
240/**************************************************************************
241 * Private Function Prototypes
242 **************************************************************************/
243
244#ifdef	__vxworks__
245PRIVATE struct protoent*   getprotobyname (char* name);
246PRIVATE struct servent*    getservbyname (char* name, char* proto);
247#endif
248
249PRIVATE int   connectSocket (
250                                  int*           const sPtr,
251                            const char*                host,
252                            const char*                service,
253                            const char*                protocol,
254                                  CSCgenFnType         callbackFn
255                            );
256
257PRIVATE int    passiveSocket (
258                                   int*           const sPtr,
259                             const char*                service,
260                             const char*                protocol,
261                                   int                  backlog,
262                                   CSCgenFnType         callbackFn
263                             );
264
265
266/* ---------------------------------------------------------------------- */
267
268
269#ifdef	__vxworks__
270
271/**************************************************************************
272 * Private Function getprotobyname
273 **************************************************************************/
274
275PRIVATE struct protoent*   getprotobyname (char* name)
276   {
277   struct protoent*   retPtr = NULL;
278
279   retPtr = calloc (1, sizeof(struct protoent));
280   if (strcmp(name,"tcp") == 0) /* transmission control protocol */
281      {
282      retPtr->p_name    = tcpName;
283      retPtr->p_aliases = tcpAliases;
284      retPtr->p_proto   = 6;
285      }
286   if (strcmp(name,"ucp") == 0) /* user datagram protocol */
287      {
288      retPtr->p_name    = udpName;
289      retPtr->p_aliases = udpAliases;
290      retPtr->p_proto   = 17;
291      }
292
293   return (retPtr);
294   }
295
296
297/**************************************************************************
298 * Private Function getservbyname
299 **************************************************************************/
300
301PRIVATE struct servent*   getservbyname (char* name, char* proto)
302   {
303   struct servent*   retPtr = NULL;
304
305/*
306 * These assignments avoid compiler warnings about unused things.
307 */
308   name  = name;
309   proto = proto;
310
311   return (retPtr);
312   }
313
314#endif
315
316
317/**************************************************************************
318 * Private Function connectSocket
319 **************************************************************************/
320
321PRIVATE int   connectSocket (
322                                  int*           const sPtr,
323                            const char*                host,
324                            const char*                service,
325                            const char*                protocol,
326                                  CSCgenFnType         callbackFn
327                            )
328   {
329   struct sockaddr_in   sin;      /* Internet Endpoint Address           */
330#ifndef	__vxworks__
331   struct hostent*      hiePtr;   /* Host Name Information Entry Pointer */
332#endif
333   struct servent*      siePtr;   /* Service Information Entry Pointer   */
334   struct protoent*     piePtr;   /* Protocol Information Entry Pointer  */
335          int           sFd;      /* Socket Descriptor                   */
336          int           sType;    /* Socket Descriptor Type              */
337          int           sSize;    /* Socket Descriptor Size              */
338          int           port;     /* Temporary Port Number               */
339          int           myErrNo;  /* Temporary errno                     */
340          char          errBuf[80];
341
342   ASSERT_RTN (sPtr != NULL,     "connectSocket: NULL sPtr",     CSC_BADARG);
343   ASSERT_RTN (host != NULL,     "connectSocket: NULL host",     CSC_BADARG);
344   ASSERT_RTN (service != NULL,  "connectSocket: NULL service",  CSC_BADARG);
345   ASSERT_RTN (protocol != NULL, "connectSocket: NULL protocol", CSC_BADARG);
346
347   /*
348    * Assume failure.
349    */
350   *sPtr = -1;
351
352   /*
353    * Clear the IP address endpoint structure then set it (correctly) with an
354    * Internet Address Family.
355    */
356   bzero ((char *)&sin, sizeof(struct sockaddr_in));
357   sin.sin_family = AF_INET;
358
359   /*
360    * Use the host as a name to get the host's IP address; if this fails, then
361    * assume the host is an ASCII-Z string of the host IP address itself.
362    */
363#ifndef	__vxworks__
364   if ((hiePtr=gethostbyname(host)) != NULL)
365      bcopy (hiePtr->h_addr, (char*)&sin.sin_addr, hiePtr->h_length);
366   else
367#endif
368      {
369      sin.sin_addr.s_addr = inet_addr (host);
370      if (sin.sin_addr.s_addr == INADDR_NONE)
371         {
372         myErrNo = errno;
373         sprintf (errBuf, "can't get %s host entry (errno %d)", host, myErrNo);
374         if (callbackFn != NULL) (*callbackFn) (CSC_NOSOCK, myErrNo, errBuf);
375         return (CSC_NOTFOUND);
376         }
377      }
378
379   /*
380    * Use the service as a name to get the port number; if this fails, then
381    * assume the service is an ASCII-Z string of the port number itself.
382    */
383   if ((siePtr=getservbyname((char*)service,(char*)protocol)) != NULL)
384      sin.sin_port = siePtr->s_port;  /* This already is in host format. */
385   else
386      {
387      port = atoi (service);
388      if (port > USHRT_MAX)
389         {
390         sprintf (
391                 errBuf,
392                 "using service entry %s as port number; it is too big",
393                 service
394                 );
395         if (callbackFn != NULL) (*callbackFn) (CSC_NOSVC, CSC_ERROR, errBuf);
396         return (CSC_NOSVC);
397         }
398      if (port != 0)
399         sin.sin_port = htons (port);
400      else
401         {
402         sprintf (errBuf, "can't make sense of service entry %s", service);
403         if (callbackFn != NULL)
404            (*callbackFn) (CSC_NOSVC, CSC_ERROR, errBuf);
405         return (CSC_NOSVC);
406         }
407      }
408
409   /*
410    * Map the protocol name to its protocol number.
411    */
412   if ((piePtr=getprotobyname((char*)protocol)) == 0)
413      {
414      sprintf (errBuf, "can't make sense of protocol entry %s", protocol);
415      if (callbackFn != NULL) (*callbackFn) (CSC_NOPROT, CSC_ERROR, errBuf);
416#ifdef	__vxworks__
417      (void)free (piePtr); /* it was calloc()'d in the local getprotobyname() */
418#endif
419      return (CSC_NOPROT);
420      }
421
422   /*
423    * Use protocol to choose a socket type. NOTE: if protocol is not correct,
424    * then the code above would have returned false from this function.
425    */
426   sType = SOCK_STREAM;
427   if (strcmp(protocol,"udp")==0) sType = SOCK_DGRAM;
428
429   /*
430    * Allocate a socket. Notice the correct use of PF_INET (Protocol Family:
431    * InterNET).
432    */
433   sFd = socket (PF_INET, sType, piePtr->p_proto);
434#ifdef	__vxworks__
435   (void)free (piePtr); /* it was calloc()'d in the local getprotobyname() */
436#endif
437   if (sFd < 0)
438      {
439      myErrNo = errno;
440      sprintf (errBuf, "can't create socket (errno %d)", myErrNo);
441      if (callbackFn != NULL) (*callbackFn) (CSC_NOSOCK, myErrNo, errBuf);
442      return (CSC_NOSOCK);
443      }
444
445   /*
446    * bind() is not required: the port number on this machine, through
447    * which the connection is made, is dynamically allocated by the
448    * operating system's BSD network socket subsystem.
449    */
450
451   /*
452    * Make the connection
453    */
454   sSize = sizeof (struct sockaddr_in);
455   if (connect(sFd,(struct sockaddr*)&sin,sSize) < 0)
456      {
457      myErrNo = errno;
458      sprintf (errBuf, "can't make connection (errno %d)", myErrNo);
459      if (callbackFn != NULL) (*callbackFn) (CSC_NOSOCK, myErrNo, errBuf);
460      return (CSC_NOSOCK);
461      }
462
463   /*
464    * Return OK
465    */
466   *sPtr = sFd;
467   return (CSC_OK);
468   }
469
470
471/**************************************************************************
472 * Private Function passiveSocket
473 **************************************************************************/
474
475PRIVATE int   passiveSocket (
476                                  int*           const sPtr,
477                            const char*                service,
478                            const char*                protocol,
479                                  int                  backlog,
480                                  CSCgenFnType         callbackFn
481                            )
482   {
483   struct sockaddr_in   sin;     /* Internet Endpoint Address          */
484   struct protoent*     piePtr;  /* Protocol Information Entry Pointer */
485   struct servent*      siePtr;  /* Service Information Entry Pointer  */
486          int           sFd;     /* Socket Descriptor                  */
487          int           sType;   /* Socket Descriptor Type             */
488          int           sSize;   /* Socket Descriptor Size             */
489          int           port;    /* Temporary Port Number              */
490          int           myErrNo;
491          char          errBuf[80];
492
493   ASSERT_RTN (sPtr != NULL,     "passiveSocket: NULL sPtr",     CSC_BADARG);
494   ASSERT_RTN (service != NULL,  "passiveSocket: NULL service",  CSC_BADARG);
495   ASSERT_RTN (protocol != NULL, "passiveSocket: NULL protocol", CSC_BADARG);
496   ASSERT_RTN (backlog != 0,     "passiveSocket: no backlog",    CSC_BADARG);
497
498   /*
499    * Assume failure.
500    */
501   *sPtr = -1;
502
503   /*
504    * Clear the IP address endpoint structure, then set it with an Internet
505    * Address Family and set it to accept a connection from any IP. Notice the
506    * correct use of AF_INET (Address Family: InterNET).
507    */
508   bzero ((char *)&sin, sizeof(struct sockaddr_in));
509   sin.sin_family      = AF_INET;
510   sin.sin_addr.s_addr = htonl (INADDR_ANY);
511
512   /*
513    * Use the service as a name to get the port number; if this fails, then
514    * assume the service is an ASCII-Z string of the port number itself.
515    */
516   if ((siePtr=getservbyname((char*)service,(char*)protocol)) != NULL)
517      sin.sin_port = siePtr->s_port; /* This already is in host format. */
518   else
519      {
520      port = atoi (service);
521      if (port > USHRT_MAX)
522         {
523         sprintf (
524                 errBuf,
525                 "using service entry %s as port number; it is too big",
526                 service
527                 );
528         if (callbackFn != NULL) (*callbackFn) (CSC_NOSVC, CSC_ERROR, errBuf);
529         return (CSC_NOSVC);
530         }
531      if ((sin.sin_port=htons(port)) == 0)
532         {
533         sprintf (errBuf, "can't make sense of service entry %s", service);
534         if (callbackFn != NULL) (*callbackFn) (CSC_NOSVC, CSC_ERROR, errBuf);
535         return (CSC_NOSVC);
536         }
537      }
538   port = sin.sin_port;
539
540   /*
541    * Map the protocol name to its protocol number.
542    */
543   if ((piePtr=getprotobyname((char*)protocol)) == 0)
544      {
545      sprintf (errBuf, "can't make sense of protocol entry %s", protocol);
546      if (callbackFn != NULL) (*callbackFn) (CSC_NOPROT, CSC_ERROR, errBuf);
547      return (CSC_NOPROT);
548      }
549
550   /*
551    * Use protocol to choose a socket type. NOTE: if protocol is not correct,
552    * then the code above would have returned false from this function.
553    */
554   sType = SOCK_STREAM;
555   if (strcmp(protocol,"udp")==0) sType = SOCK_DGRAM;
556
557   /*
558    * Allocate a socket. Notice the correct use of PF_INET (Protocol Family:
559    * InterNET).
560    */
561   sFd = socket (PF_INET, sType, piePtr->p_proto);
562   if (sFd < 0)
563      {
564      myErrNo = errno;
565      sprintf (errBuf, "can't create socket (errno %d)", myErrNo);
566      if (callbackFn != NULL) (*callbackFn) (CSC_NOSOCK, myErrNo, errBuf);
567      return (CSC_NOSOCK);
568      }
569
570   /*
571    * Allow this server to be quickly brought back up. The socket is set to be
572    * able to reuse the same port; otherwise, the TIME_WAIT phenomenon will
573    * prevent binding to the local address.
574    *
575    * This is particularly useful when the server has been shut down and then
576    * quickly restarted (while the sockets are still active on its port).
577    * Unexpected data may come in and it may confuse the server; but while this
578    * is possible, it is very not likely:
579    *
580    *      "A socket is a 5-tuple (protocol, local address, local port,
581    *      remote address, remote port). SO_REUSEADDR just says that
582    *      you can reuse local addresses. The 5-tuple still must be
583    *      unique!"  -- Michael Hunter (mphunter@qnx.com)
584    *
585    * This is why it is very unlikely that unexpected data will ever be seen by
586    * the server. The danger is that such a 5-tuple is still floating around on
587    * the network, and while it is bouncing around a new connection from the
588    * same client (on the same system) happens to get the same remote port.
589    *
590    * Thanks to Vic Metcalfe (vic@acm.org) et. al. Most of this data in this
591    * comment block came from his FAQ:
592    * ``Programming UNIX Sockets in C - Frequently Asked Questions''
593    * dated March 28, 1998. The FAQ was found at
594    * http://www.ibrado.com/sock-faq/
595    */
596   {
597   int   on = 1;
598   if (setsockopt(sFd,SOL_SOCKET,SO_REUSEADDR,(char*)&on,sizeof(on)) < 0)
599      {
600      myErrNo = errno;
601      sprintf (errBuf, "can't set SO_REUSEADDR on socket (errno %d)", myErrNo);
602      if (callbackFn != NULL) (*callbackFn) (CSC_NOSOCK, myErrNo, errBuf);
603      return (CSC_NOSOCK);
604      }
605   }
606
607   /*
608    * Bind the socket.
609    */
610   sSize = sizeof (struct sockaddr_in);
611   if (bind(sFd,(struct sockaddr*)&sin,sSize) < 0)
612      {
613      myErrNo = errno;
614      sprintf (
615              errBuf,
616              "can't bind service %s to port %d (errno %d)",
617              service, port, myErrNo
618              );
619      if (callbackFn != NULL) (*callbackFn) (CSC_NOBIND, myErrNo, errBuf);
620      return (CSC_NOBIND);
621      }
622
623   /*
624    * Listen for something on the port. I've found out that a client's
625    * connect() can succeed at this point (before the server's accept())!
626    */
627   if (sType == SOCK_STREAM)
628      if (listen(sFd,backlog) < 0)
629         {
630         myErrNo = errno;
631         sprintf (
632                 errBuf,
633                 "can't listen on service %s port %d (errno %d)",
634                 service, port, myErrNo
635                 );
636         if (callbackFn != NULL) (*callbackFn) (CSC_NOLISTEN, myErrNo, errBuf);
637         return (CSC_NOLISTEN);
638         }
639
640   /*
641    * Return OK
642    */
643   *sPtr = sFd;
644   return (CSC_OK);
645   }
646
647
648
649/* ************************************************************************* */
650/*                                                                           */
651/*      E x e c u t a b l e   C o d e   (External Interface Functions)       */
652/*                                                                           */
653/* ************************************************************************* */
654
655
656/***************************************************************************
657 * Public Function CSCsockConnectTCP
658 ***************************************************************************
659
660<SUBROUTINE NAME="CSCsockConnectUDP">
661
662NAME
663        CSCsockConnectTCP - initiate a socket connection
664
665SYNOPSYS
666        #include "libcsc.h"
667
668        int   CSCsockConnectTCP (
669                                      int*           const socketPtr,
670                                const char*                host,
671                                const char*                service,
672                                      CSCgenFnType         errorCallback
673                                );
674
675RETURN VALUE
676        CSC_OK .......... successful, and the integer pointed to by socketPtr
677                          will be updated with the new socket descriptor
678
679        CSC_NOTFOUND .... can't make sense of host
680
681        CSC_NOSVC ....... can't make sense of service
682
683        CSC_NOPROT ...... can't make any sense out of the UDP protocol
684
685        CSC_NOSOCK ...... can't allocate a new socket or can't set a socket
686                          option
687
688        CSC_BADARG ...... socketPtr or service is NULL or connectCount is zero
689
690DESCRIPTION
691        CSCsockConnectTCP() attempts to create a PF_INET (IPv4) protocol
692        socket and make a TCP (SOCK_STREAM) connection to another socket.
693
694        The other socket to which to connect is expected to be on `host' and
695        `service', where `host' is the hostname or IP address, and `service' is
696        the service or port number. If `service' specifies port number, then the
697        integer value must fit in an unsigned 16 bit variable
698        (0 <= sevice <= 65535). For example:
699
700                host            service
701                ----            -------
702                "batman"        "telnet"
703                "spidergirl"    "5200"
704                "198.168.0.2"   "finger"
705                "198.168.0.2"   "5200"
706
707        Error conditions are announced via `errorCallback', if it is not NULL.
708        The `errorCallback' function is called with the CSCsockConnectTCP()
709        return value, errno, and a string describing the error e.g.,
710
711                (*errorCallback) (CSC_NOSOCK, errno, "can't create socket");
712
713SEE ALSO
714        CSCsockConnectUDP(3)
715        CSCsockPassiveTCP(3)
716        CSCsockPassiveUDP(3)
717</SUBROUTINE>
718
719 ***************************************************************************/
720
721PUBLIC int   (CSCsockConnectTCP) (
722                                       int*           const socketPtr,
723                                 const char*                host,
724                                 const char*                service,
725                                       CSCgenFnType         errorCallback
726                                 )
727   {
728   ASSERT_RTN (						\
729              socketPtr != NULL,			\
730              "CSCsockPassiveTCP: NULL socketPtr",	\
731              CSC_BADARG				\
732              );
733   ASSERT_RTN (						\
734              host != NULL,				\
735              "CSCsockPassiveTCP: NULL host",		\
736              CSC_BADARG				\
737              );
738   ASSERT_RTN (						\
739              service != NULL,			\
740              "CSCsockPassiveTCP: NULL service",	\
741              CSC_BADARG				\
742              );
743   return (connectSocket(socketPtr,host,service,"tcp",errorCallback));
744   }
745
746/***************************************************************************
747 * Public Function CSCsockConnectUDP
748 ***************************************************************************
749
750<SUBROUTINE NAME="CSCsockConnectUDP">
751
752NAME
753        CSCsockConnectUDP - initiate a socket connection
754
755SYNOPSYS
756        #include "libcsc.h"
757
758        int   CSCsockConnectUDP (
759                                      int*           const socketPtr,
760                                const char*                host,
761                                const char*                service,
762                                      CSCgenFnType         errorCallback
763                                );
764
765RETURN VALUE
766        CSC_OK .......... successful, and the integer pointed to by socketPtr
767                          will be updated with the new socket descriptor
768
769        CSC_NOTFOUND .... can't make sense of host
770
771        CSC_NOSVC ....... can't make sense of service
772
773        CSC_NOPROT ...... can't make any sense out of the UDP protocol
774
775        CSC_NOSOCK ...... can't allocate a new socket or can't set a socket
776                          option
777
778        CSC_BADARG ...... socketPtr or service is NULL or connectCount is zero
779
780DESCRIPTION
781        CSCsockConnectUDP() attempts to create a PF_INET (IPv4) protocol
782        socket and make a UDP (SOCK_DGRAM) connection to another socket.
783
784        The other socket to which to connect is expected to be on `host' and
785        `service', where `host' is the hostname or IP address, and `service' is
786        the service or port number. If `service' specifies port number, then the
787        integer value must fit in an unsigned 16 bit variable
788        (0 <= sevice <= 65535). For example:
789
790                host            service
791                ----            -------
792                "batman"        "telnet"
793                "spidergirl"    "5200"
794                "198.168.0.2"   "finger"
795                "198.168.0.2"   "5200"
796
797        Error conditions are announced via `errorCallback', if it is not NULL.
798        The `errorCallback' function is called with the CSCsockConnectUDP()
799        return value, errno, and a string describing the error e.g.,
800
801                (*errorCallback) (CSC_NOSOCK, errno, "can't create socket");
802
803BUGS
804        There's no "connection" in UDP! CSCsockConnectUDP() probably shouldn't
805        call connect() to make a connection.
806
807SEE ALSO
808        CSCsockConnectTCP(3)
809        CSCsockPassiveTCP(3)
810        CSCsockPassiveUDP(3)
811</SUBROUTINE>
812
813 ***************************************************************************/
814
815PUBLIC int   (CSCsockConnectUDP) (
816                                       int*           const socketPtr,
817                                 const char*                host,
818                                 const char*                service,
819                                       CSCgenFnType         errorCallback
820                                 )
821   {
822   ASSERT_RTN (						\
823              socketPtr != NULL,			\
824              "CSCsockPassiveUDP: NULL socketPtr",	\
825              CSC_BADARG				\
826              );
827   ASSERT_RTN (						\
828              host != NULL,				\
829              "CSCsockPassiveUDP: NULL host",		\
830              CSC_BADARG				\
831              );
832   ASSERT_RTN (						\
833              service != NULL,				\
834              "CSCsockPassiveUDP: NULL service",	\
835              CSC_BADARG				\
836              );
837   return (connectSocket(socketPtr,host,service,"udp",errorCallback));
838   }
839
840
841/***************************************************************************
842 * Public Function CSCsockPassiveTCP
843 ***************************************************************************
844
845<SUBROUTINE NAME="CSCsockPassiveTCP">
846
847NAME
848        CSCsockPassiveTCP - listen for connections on a socket
849
850SYNOPSYS
851        #include "libcsc.h"
852
853        int   CSCsockPassiveTCP (
854                                      int*           const socketPtr,
855                                const char*                service,
856                                      int                  connectCount,
857                                      CSCgenFnType         errorCallback
858                                );
859
860RETURN VALUE
861        CSC_OK .......... successful, and the integer pointed to by socketPtr
862                          will be updated with the new socket descriptor
863
864        CSC_NOSVC ....... can't make sense of service
865
866        CSC_NOPROT ...... can't make any sense out of the UDP protocol
867
868        CSC_NOSOCK ...... can't allocate a new socket or can't set a socket
869                          option
870
871        CSC_NOBIND ...... can't bind socket to service
872
873        CSC_NOLISTEN .... can't listen to socket
874
875        CSC_BADARG ...... socketPtr or service is NULL or connectCount is zero
876
877DESCRIPTION
878        CSCsockPassiveTCP() attempts to create a PF_INET (IPv4) protocol socket
879        and prepares it to accept TCP (SOCK_STREAM) connections. No accept() is
880        actually tried, this must be done after calling CSCsockPassiveTCP().
881
882        If successful, CSCsockPassiveTCP() creates a socket that is prepared
883        to accept a connection from any IP.
884
885        The `service' argument is a string that represents the the service (see
886        /etc/services) or port number. If `service' specifies port number, then
887        the integer value must fit in an unsigned 16 bit variable
888        (0 <= sevice <= 65535). For example:
889
890                service
891                -------
892                "echo"
893                "5200"
894                "fsp"
895                "7200"
896
897        The socket is set with the SO_REUSEADDR option to enable quick reuse of
898        the same port.
899
900        `connectCount' is the connection backlog (the number of allowed
901        concurrent connections).
902
903        Error conditions are announced via `errorCallback', if it is not NULL.
904        The `errorCallback' function is called with the CSCsockPassiveUDP()
905        return value, errno, and a string describing the error e.g.,
906
907                (*errorCallback) (CSC_NOSOCK, errno, "can't create socket");
908
909BUGS
910        Cannot select a desired host from which to accept a connection.
911
912SEE ALSO
913        CSCsockConnectTCP(3)
914        CSCsockConnectUDP(3)
915        CSCsockPassiveUDP(3)
916</SUBROUTINE>
917
918 ***************************************************************************/
919
920PUBLIC int   (CSCsockPassiveTCP) (
921                                       int*           const socketPtr,
922                                 const char*                service,
923                                       int                  connectCount,
924                                       CSCgenFnType         errorCallback
925                                 )
926   {
927   ASSERT_RTN (						\
928              socketPtr != NULL,			\
929              "CSCsockPassiveTCP: NULL socketPtr",	\
930              CSC_BADARG				\
931              );
932   ASSERT_RTN (						\
933              service != NULL,				\
934              "CSCsockPassiveTCP: NULL service",	\
935              CSC_BADARG				\
936              );
937   ASSERT_RTN (						\
938              connectCount != 0,			\
939              "CSCsockPassiveTCP: no connectCount",	\
940              CSC_BADARG				\
941              );
942   return (passiveSocket(socketPtr,service,"tcp",connectCount,errorCallback));
943   }
944
945
946/***************************************************************************
947 * Public Function CSCsockPassiveUDP
948 ***************************************************************************
949
950<SUBROUTINE NAME="CSCsockPassiveUDP">
951
952NAME
953        CSCsockPassiveUDP - listen for connections on a socket
954
955SYNOPSYS
956        #include "libcsc.h"
957
958        int   CSCsockPassiveUDP (
959                                      int*           const socketPtr,
960                                const char*                service,
961                                      int                  connectCount,
962                                      CSCgenFnType         errorCallback
963                                );
964
965RETURN VALUE
966        CSC_OK .......... successful, and the integer pointed to by socketPtr
967                          will be updated with the new socket descriptor
968
969        CSC_NOSVC ....... can't make sense of service
970
971        CSC_NOPROT ...... can't make any sense out of the UDP protocol
972
973        CSC_NOSOCK ...... can't allocate a new socket or can't set a socket
974                          option
975
976        CSC_NOBIND ...... can't bind socket to service
977
978        CSC_NOLISTEN .... can't listen to socket
979
980        CSC_BADARG ...... socketPtr or service is NULL or connectCount is zero
981
982DESCRIPTION
983        CSCsockPassiveUDP() attempts to create a PF_INET (IPv4) protocol socket
984        and prepares it to accept UDP (SOCK_DGRAM) connections.
985
986        If successful, CSCsockPassiveUDP() creates a socket that is prepared
987        to accept a datagrams from any IP.
988
989        The `service' argument is a string that represents the the service (see
990        /etc/services) or port number. If `service' specifies port number, then
991        the integer value must fit in an unsigned 16 bit variable
992        (0 <= sevice <= 65535). For example:
993
994                service
995                -------
996                "echo"
997                "5200"
998                "fsp"
999                "7200"
1000
1001        The socket is set with the SO_REUSEADDR option to enable quick reuse of
1002        the same port.
1003
1004        `connectCount' is the connection backlog (the number of allowed
1005        concurrent connections).
1006
1007        Error conditions are announced via `errorCallback', if it is not NULL.
1008        The `errorCallback' function is called with the CSCsockPassiveUDP()
1009        return value, errno, and a string describing the error e.g.,
1010
1011                (*errorCallback) (CSC_NOSOCK, errno, "can't create socket");
1012
1013BUGS
1014        There's no "connection" in UDP!  This function should be re-coded to
1015        remove the TCPisms. I think this function has never been used.
1016
1017SEE ALSO
1018        CSCsockConnectTCP(3)
1019        CSCsockConnectUDP(3)
1020        CSCsockPassiveTCP(3)
1021</SUBROUTINE>
1022
1023 ***************************************************************************/
1024
1025PUBLIC int   (CSCsockPassiveUDP) (
1026                                       int*           const socketPtr,
1027                                 const char*                service,
1028                                       int                  connectCount,
1029                                       CSCgenFnType         errorCallback
1030                                 )
1031   {
1032   ASSERT_RTN (						\
1033              socketPtr != NULL,			\
1034              "CSCsockPassiveUDP: NULL socketPtr",	\
1035              CSC_BADARG				\
1036              );
1037   ASSERT_RTN (						\
1038              service != NULL,				\
1039              "CSCsockPassiveUDP: NULL service",	\
1040              CSC_BADARG				\
1041              );
1042   ASSERT_RTN (						\
1043              connectCount != 0,			\
1044              "CSCsockPassiveUDP: no connectCount",	\
1045              CSC_BADARG				\
1046              );
1047   return (passiveSocket(socketPtr,service,"udp",connectCount,errorCallback));
1048   }
1049
1050
1051/* End of file. */
1052