SunSolve Internal

Infodoc ID   Synopsis   Date
12906   Sockets Programming PSD/FAQ   13 Oct 1999

Description Top

Product Support Document (PSD) for Sockets Programming

Including Sockets Programming

Revision 1.3
Date Top
April 9, 1996

1.0: About Sockets Programming
2.0: Debugging Sockets Programming
  2.1: Programming Hints
  2.2: netstat
  2.3: truss
  2.4: snoop
3.0: Common How Tos
  3.1: How to Write a Sockets Server
  3.2: How to Write a Sockets Client
4.0: Some Frequently Asked Questions
  4.1: General Questions
  4.2: Sockets Programming Problems
  4.3: Questions on Socket States
5.0: Patches
  5.1: SunOS Sockets Patches
  5.2: Solaris Sockets Patches
6.0: Known Bugs & RFEs
7.0: References
  7.1: Man Pages
  7.2: Sunsolve Documents
  7.3: Sun Educational Services
  7.4: Solaris Documentation
  7.5: Third Party Documentation
  7.6: RFCs
8.0: Supportability
9.0: Additional Support

 1.0: About Sockets Programming

==============================

This PSD documents a wide variety of information concerning Sockets
programming. It should be noted here that SunService is unable to
provide assistance with questions of how to program using sockets.
This document provides some information which can assist you in
figuring out Sockets programming on your own, but if it is
insufficient, you must utilize Sun's consulting services to get more
help. See Sections 8.0 and 9.0.

Sockets is a network programming API which is sometimes called "BSD
Sockets". Solaris also supports the newer TLI API, but Sockets will
continue to be supported. A separate PSD exists for the TLI API.

2.0 Debugging Sockets Programming

 2.1: Programming Hints

----------------------

If you are careful when are you writing your sockets programming, it
will make your debugging tasks easier.

First, you should always start with a very basic sockets frame work
client/server and make it work. Then, add more functionality
afterwards. This will allow you to detect where and when a problem
occurs.

If you are experiencing a problem, you might always want to check data
structure type casting before you move on to the more complex
debugging tools noted below.

 2.2: netstat

------------

The netstat program can help you to figure out what states Sockets
programs are in, possibly providing you with some clues about what
might be going wrong.

Run with no arguments, netstat will show you the states of active
connections:

%% netstat
TCP
   Local Address        Remote Address    Swind Send-Q Rwind Recv-Q  State
-------------------- -------------------- ----- ------ ----- ------ -------
mtvmail.32893        yeeha.48750           8760      0  8760      0 ESTABLISHED
mtvmail-111.32772    kuruma.34386          8760      0  8760      0 ESTABLISHED

This is particularly helpful if you want to make sure that your
program is actually running on the designated port and is also
connected to another machine on the correct port. The State column is
also notable, because it can help you figure out which signals have
already been exchanged. The netstat man page gives a good listing of
all of netstat's states.

If you run netstat -a, you will also see LISTENING programs:

rainbow%% netstat -a   more

UDP
   Local Address      State
-------------------- -------
      *.route         Idle
      *.*             Unbound
      *.*             Unbound
      *.sunrpc        Idle

This can be useful if you wish to insure that your Sockets program is
sitting on a port and listening, as it should be.

 2.3: truss

----------

Truss can be used to trace the output of a program as it runs. This
helps you to examine all the signals that a program receives and
also to examine system calls that are made and the values that are
returned.

If you've already started your Sockets process and want to run truss
on it, get the maximum amount of information, and follow all
forked processes, run truss as follows:

  # truss -v all -f -p pid-of-process

Truss is only available under Solaris 2.X. Trace offers somewhat
similar functionality for 1.X. See the trace man page for more
information.

 2.4: snoop

----------

The snoop command can allow you to examine all of the packets being
exchanged between two machines. If you are running a Sockets client on
one machine and a Sockets server on another, choose a third machine
on the same subnet as these two machines and run snoop:

  # snoop machine1 and machine2

This allows you to see all packets that are exchanged between
machine1 and machine2 and is especially helpful if you want to see
which signals have been exchanged.

snoop is only available under Solaris 2.X. etherfind offers somewhat
similar functionality for 1.X. See the etherfind man page for more
information.

3.0 Common How Tos

 3.1: How to Write a Sockets Server

----------------------------------

/*
 *  Program  :  TCP serv.c
 *  Function :  This server program demonstrates how to open the TCP
 *              socket, bind to a local transport address, listen on the,
 *              and ready to accept the connection from any TCP client.
 *              It sets up a loop w/ 10 iterations and reads the data
 *              sending from the client.  Then, go back to accept a new
 *              client connection.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/filio.h>
#include <sys/errno.h>
#include <signal.h>
#include <sys/resource.h> /* rlimit */

#define SERV_PORT   4999

extern int errno
fd_set read_fd

struct rlimit rl
 void
catcher(int a)
{
    printf("Server interrupt caught\n")
    exit(1)
}

void
catcher1(int a)
{
    printf("Server Broken Pipe caught\n")
    exit(1)
}

main()
{
    int                sock, n, sd, addrlen
    struct sockaddr_in server, peeraddr
    int                dtbsz

    int  on = 1

    rl.rlim_max = 0
    getrlimit(RLIMIT_NOFILE, &rl);
    if ((dtbsz = rl.rlim_max) == 0)
    {
        printf("Could not get the resource limits\n")
        exit(1)
    }

    printf("dtbsize = %%d\n", dtbsz)

    sigset(SIGINT, catcher)
    sigset(SIGPIPE, catcher1)

    /* Create socket */

    if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Open Stream Socket failed!")
        exit(1)
    }

    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) <
0)    {
        perror("Set SO_REUSEADDR failed!")
        exit(1)
    }

    memset ((char *) &server, 0, sizeof (server))

    server.sin_family = AF_INET
    server.sin_port = htons(SERV_PORT)
    server.sin_addr.s_addr = htonl(INADDR_ANY)

    addrlen = sizeof(peeraddr)

    if (bind (sock, (struct sockaddr *)&server, sizeof (server)) < 0)
    {
        perror("binding stream socket")
        exit(2)
    }

    /* listen on the socket */

    if (listen(sock, 5) < 0)
    {
          perror("Unable to listen on socket\n")
          exit(3)
    }

    for (  )
    {
       if ((sd = accept(sock, (struct sockaddr *)&peeraddr, &addrlen)) < 0)
       {
           perror("Accept failed")
           exit(4)
       }

       if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)) <
0)
       {
           perror("Set SO_KEEPALIVE failed")
           exit(1)
       }

       FD_ZERO(&read_fd)
       FD_SET(sd, &read_fd)

       printf("Begin to select\n")

       /* Wait until something on socket */

       if ((n = select (dtbsz, &read_fd, NULL, NULL, (struct timeval *)0)) < 0)
           perror("select")

       if (n >= 0)
           doit(sd)
    }
}

doit(sock)
    int sock
{
    int i, nbytes
    char buf[1024]

    printf("Start: fd number --> %%d\n", sock)
    memset ((char *)buf, 0, sizeof (buf))

    for (i = 0  i <= 10  i++)
    {
        if ((nbytes = read(sock, buf, 1024)) < 0 )
        {
           perror("Server Read failed")
           printf("Errno = %%d \n", errno)
           close(sock)
           exit(1)
        }

        if (nbytes == 0 )
        {
           perror("EOF Server Read")
           close(sock)
           exit(1)
        }
        printf("fd[%%d]-> %%s\n",sock, buf)
        memset ((char *)buf, 0, sizeof (buf))
    }
    printf("End loop, close fd[%%d]\n\n", sock)
    close(sock)
}

 3.2: How to Write a Sockets Client

----------------------------------

/*
 *  Program  :  TCP clnt.c
 *  Function :  This client program demonstrates how to open the TCP
 *              socket, connect to the TCP server via predetermined unique
 *              server port number.  Then, it sends data to the server via
 *              interactive user input from the keyboard.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>

#define SERV_TCP_PORT  4999
#define MSG_SIZE        256

extern int errno
struct hostent *gethostbyname()
struct hostent *hp
struct sockaddr_in peeraddr_in

void
catcher(int a)
{
    printf("Client interrupt caught\n")
    exit(1)
}

void
catcher1(int a)
{
    printf("Client Broken Pipe caught\n")
    exit(1)
}
 main (argc, argv) /* TCP client main */
    int  argc
    char *argv[]
{

    int  s                       /* socket file descriptor */
    char outbuf[MSG_SIZE]
    int  on = 1

    if (argc < 2)
    {
        printf("Usage: program <remote hostname>\n")
        exit(1)
    }

    /* Find information for the remote host */

    if ((hp = gethostbyname(argv[1])) == NULL)
    {
        printf("Host %%s not found\n", argv[1])
        exit(1)
    }

    sigset(SIGINT, catcher)
    sigset(SIGPIPE, catcher1)

    /* clear out the address structure */

    memset((char *)&peeraddr_in, 0, sizeof(peeraddr_in))

    /* Set up peer address for connect */

    peeraddr_in.sin_family = AF_INET

    memcpy((char *)&peeraddr_in.sin_addr, hp->h_addr, hp->h_length)

    peeraddr_in.sin_port = htons(SERV_TCP_PORT)

    /* Create the socket */

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Unable to create socket")
        exit(1)
    }

    while (connect(s, (struct sockaddr *)&peeraddr_in, sizeof(peeraddr_in)) <
0)    {
        if(errno != ECONNREFUSED)
        {
            perror("Connection attempt")
            printf("Connection attempt, errno = %%d\n", errno)
            exit(1)
       }
       sleep(5)   /* wait for the other side to become unbusy */
    }

    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
    {
        perror("Cannot set KEEPALIVE")
        exit(1)
    }

    for (  )
    {
        printf("Type in your message: ")
        gets(outbuf)
        write(s, outbuf, strlen(outbuf))
     }

} /* end TCP client main */

4.0 Some Frequently Asked Questions

 4.1: General Questions

----------------------

Q: Has the sockets implementation changed in Solaris?

A: Yes. Under Solaris, sockets are implemented as a user-level library
on top of a protocol stack containing Streams modules for TCP and IP.
Under SunOS, sockets were hard-wired into the kernel. In addition,
many libraries has changed under Solaris, due to the change from
SunOS' BSD to Solaris' SysV. This means that work will need to be done
to port sockets programs from SunOS to Solaris (see below).

Q: How do I port my SocketsRPC program from SunOS to Solaris?

A: Porting from SunOS to Solaris is not necessarily an easy task, as
you are converting from BSD to SysV libraries. You can definitely
expect there to be some problems in the process. However, because
porting is a Consulting issue, SunService is unable to help you with
it. Sun does have other groups which can work with you on porting
issues. Consult sections 8.0 & 9.0 for more information.

Q1: Why did my Sockets program break when I applied a patch to my
    Solaris system?
Q2: What should I do when I am sure that the Sockets functions are
    behaving incorrectly?

A: In cases where it appears that a bug has been introduced by a
patch or where it appears a Sockets function is behaving incorrectly,
SunService can look at your code, verify the bug and then pass it on
to Engineering. However, SunService must have a very small fragment of
code in order to do this. If you would like SunService to verify a
bug and pass it on to Engineering, you must cut your program down to
100 or so lines, containing only the relevant Sockets functions. Then,
contact SunService and arrange to send them your 100 line program,
along with complete instructions on how to compile it, an explanation
of what you expect to see when it runs and an explanation of what
actually happens. If this bug surfaced when you installed a new patch,
please include information on what patch your program originally
worked at and what new patch caused it to fail.

Please Note: SunService is only able to look at code fragments like
this when it genuinely appears that there is a bug. If you are having
problems porting from SunOS to Solaris or you are having problems
programming because you do not have a full understanding of all the
Sockets functions, you must instead contact Sun about Consulting
offerings. See Sections 8.0 and 9.0.

Q:  What libraries do I include when compiling/linking sockets program?

A:  Per the Solaris socket() man page:

    cc prog.c -lsocket -lnsl

Q:  How many sockets can I have open on Solaris 2.x?

A:  The max number of sockets an app can have open is the maximum number
of file descriptors it can have open.  This is controlled by the limit
command (do man limit).

The default for the number of descriptors and the max you can increase it to
are controlled (on 2.4) by /etc/system parameters.  For example, to
increase to 128:

set rlim_fd_cur=128
set rlim_fd_max=128

The "rlim_fd_cur" variable corresponds to the soft limit and the
"rlim_fd_max" is the hard limit.

These lines change the number of file descriptors
to 128 after a reboot.  By the way, boot -r is not needed.

However, before doing this, note the following:

1. Stdio routines are limited to using file descriptors 0 - 255.  Even
though you can set the limit higher than 256, if fopen() cannot get a
file descriptor lower than 256, the fopen() fails.  This can be a
problem if you have other routines using open() directly.  For example,
if you open 256 files with open() without closing any, you won't be able
to open any files at all with fopen(), because all the low-numbered file
descriptors have been used up.

2. It is somewhat dangerous to set the fd limits higher than 1024.
There are some structures defined in the system (like fd_set in
<sys/select.h>) that assume that the maximum fd is 1023.  If the
program uses an fd larger than this with the macros and routines that
access this structure (like FD_SET()), it will corrupt its memory
space because it will modify memory outside the bounds of the structure.
This structure is used specifically by the select() routine and
indirectly by many library calls that use select().

Q: What is the status of SO_DEBUG and trpt under Solaris 2.X?

A: Under Solaris 2.X, you can enable SO_DEBUG, but it just does a NOOP
operation. The "trpt" that prints out the SO_DEBUG trace is also gone.
Engineering has a different instrument to debug the protocol now and
it is not available to the public.

 4.2: Sockets Programming Problems

---------------------------------

Q: Older manuals say that I can select() as soon as connect() returns
EINPROGRESS, but that doesn't seem to work. Why not?

A: The older manuals were incorrect. Do not select() until connect()
is successful.

Q1: What does the "Protocol wrong type for socket" error mean?
Q2: What does "EPROTOTYPE, errno=98" mean?

A: This is an application programming error. You have specified a
protocol that does not support the semantics of the socket type
requested. Verify that any sockets requested are actually listed in
/usr/include/sys/socket.h.

 4.3: Questions on Socket States

-------------------------------

Q: Why do ports get stuck in the TIME_WAIT state?

A: This is due to the 2MSL timeout value, which is a part of the TCP
specification. After a connection has been closed by both the client
and the server, the port becomes unavailable for a certain amount of
time, so that a new program does not inadvertently get packets that
were intended for the old program. On Solaris machines, the 2MSL value
can be modified by adjust the /dev/tcp tcp_close_wait_interval ndd
variable.

Q: Why do I get "address already in use" when I try and reuse a port
which a previous program had used.

A1: It could be that the port is still in the TIME_WAIT state (see
above). You can confirm this by running netstat and examining the
port in question. If this is the case, you must simply wait the couple
of minutes it will take for the port to get out of the TIME_WAIT
state.

A2: It could be that the program you are using does not correctly list
the port as one that can be reused. You should verify that your
program is setting the SO_REUSEADDR socket option (Section 3.1 gives
an example of doing so).

5.0 Patches

 5.0: Patches

============

The following is the list of all of the Sockets related patches for
4.1.3, 4.1.3_u1, 4.1.4, 5.3 and 5.4. If you are having Sockets
problems, installing the patches is a good place to start, especially
if you recognize the general symptoms noted below.

For a machine to be stable, all of the recommended patches
should be installed as well. The list of recommended patches for your
operating system is available from sunsolve.sun.com.

 5.1: SunOS Sockets Patches

--------------------------

100584-08 SunOS 4.1.3: TCP Interface Jumbo Patch
100412-02 SunOS 4.1 4.1.1 4.1.2 4.1.3: applications bind to same port if IP
100896-01 SunOS 4.1.2 4.1.3: The system crashed in tcp_Ercvconnect() due to
101499-01 SunOS 4.1.3: SIGIO not generated properly for sockets.
102424-03 SunOS 4.1.3: uipc_socket fixes.

  A set of 413 options will all affect TCP/IP and Sockets.

101790-01 SunOS 4.1.3_U1: TCP socket and reset problems
101438-01 SunOS 4.1.3_U1: applications bind to same port if IP address supplied
101439-01 SunOS 4.1.3_U1: system crashed tcp_Ercvconnect() from a NULL socket
102010-02 SunOS 4.1.3_U1: TCP interface Jumbo Patch.
102425-03 SunOS 4.1.3_U1: uipc_socket fixes

  Similar patches for 413_u1.

102426-03 SunOS 4.1.4: uipc_socket fixes
102517-01 SunOS 4.1.4: TCP interface Jumbo Patch.

  Fixes getsockopt() and other socket functions, as well as a wide
  variety of bugs in TCP.

 5.2: Solaris Sockets Patches

----------------------------
101318-81 SunOS 5.3: Jumbo patch for kernel (includes libc, lockd)
101945-42 SunOS 5.4: jumbo patch for kernel
101946-35 SunOS 5.4_x86: jumbo patch for kernel

  Fix a large number of bugs in libsocket. Also fixes many other
  network problems and should be installed on all machines.

 6.0: Known Bugs & RFEs

======================

None.

7.0 References

 7.1: Man Pages

--------------

  accept (3N)
  bind (3N)
  connect (3N)
  getsockname (3N)
  getsockopt (3N)
  listen (3N)
  recv (3N)
  recvfrom (3N)
  setsockopt (3N)
  send (3N)
  shutdown (3N)
  socketpair (3N)

 7.2: Sunsolve Documents

-----------------------

FAQs
----
faqs    1625      Sockets remain in TIME_WAIT state for 4 minutes

Infodocs
--------
infodoc 2075      sharing socket descriptors between unrelated processes
infodoc 2243      First write on the client socket does not receive SIGPI

 7.3: Sun Educational Services

-----------------------------

SI-240 Network Programming

 7.4: Solaris Documentation

--------------------------

_Solaris Porting Guide, 2nd Ed_, published by SunSoft Press/Prentice
Hall, ISBN #0-13-443672-5

  Information on converting programs from SunOS to Solaris.

_2.5 Transport Interfaces Programming Guide_

_2.4 Network Interfaces Programming Guide_

 7.5: Third Party Documentation

------------------------------

UNIX System V Network Programming, Addison Wesley, ISBN# 0201563185

UNIX Network Programming, Prentice Hall, ISBN# 0139498761

 7.6: RFCs

---------

None.

 8.0: Supportability

===================

SunService is not responsible for providing help with either Sockets
programming or the porting of Sockets code. We can help resolve
problems where Sockets programming functions are not behaving
correctly, but in such cases, the contact must be a system
administrator or programmer with a firm understanding of how the
Sockets functions are supposed to work.

 9.0: Additional Support

=======================

For help with Sockets programming or the porting of Sockets code,
please contact your local SunService office for possible consulting
offerings. Sun's Customer Relations organization can put you in touch
with your local SunIntegration or Sales office. You can reach Customer
Relations at 800-821-4643.
Product Area Gen. Network
Product Sockets
OS any
Hardware any

Top

SunWeb Home SunWeb Search SunSolve Home Simple Search

Sun Proprietary/Confidential: Internal Use Only
Feedback to SunSolve Team