1 /* -*- c-basic-offset: 8; -*-
3 * Copyright (c) 1993 W. Richard Stevens. All rights reserved.
4 * Permission to use or modify this software and its documentation only for
5 * educational purposes and without fee is hereby granted, provided that
6 * the above copyright notice appear in all copies. The author makes no
7 * representations about the suitability of this software for any purpose.
8 * It is provided "as is" without express or implied warranty.
13 int cliopen(char *host
, char *port
)
17 struct in_addr inaddr
;
21 protocol
= udp
? "udp" : "tcp";
23 /* initialize socket address structure */
24 bzero(&servaddr
, sizeof(servaddr
));
25 servaddr
.sin_family
= AF_INET
;
27 /* see if "port" is a service name or number */
28 if ( (i
= atoi(port
)) == 0) {
29 if ( (sp
= getservbyname(port
, protocol
)) == NULL
)
30 err_quit("getservbyname() error for: %s/%s", port
, protocol
);
32 servaddr
.sin_port
= sp
->s_port
;
34 servaddr
.sin_port
= htons(i
);
37 * First try to convert the host name as a dotted-decimal number.
38 * Only if that fails do we call gethostbyname().
41 if (inet_aton(host
, &inaddr
) == 1)
42 servaddr
.sin_addr
= inaddr
; /* it's dotted-decimal */
43 else if ( (hp
= gethostbyname(host
)) != NULL
)
44 bcopy(hp
->h_addr
, &servaddr
.sin_addr
, hp
->h_length
);
46 err_quit("invalid hostname: %s", host
);
48 if ( (fd
= socket(AF_INET
, udp
? SOCK_DGRAM
: SOCK_STREAM
, 0)) < 0)
49 err_sys("socket() error");
53 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof (on
)) < 0)
54 err_sys("setsockopt of SO_REUSEADDR error");
60 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &on
, sizeof (on
)) < 0)
61 err_sys("setsockopt of SO_REUSEPORT error");
66 * User can specify port number for client to bind. Only real use
67 * is to see a TCP connection initiated by both ends at the same time.
68 * Also, if UDP is being used, we specifically call bind() to assign
69 * an ephemeral port to the socket.
70 * Also, for experimentation, client can also set local IP address
71 * (and port) using -l option. Allow localip[] to be set but bindport
75 if (bindport
!= 0 || localip
[0] != 0 || udp
) {
76 bzero(&cliaddr
, sizeof(cliaddr
));
77 cliaddr
.sin_family
= AF_INET
;
78 cliaddr
.sin_port
= htons(bindport
); /* can be 0 */
79 if (localip
[0] != 0) {
80 if (inet_aton(localip
, &cliaddr
.sin_addr
) == 0)
81 err_quit("invalid IP address: %s", localip
);
83 cliaddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
); /* wildcard */
85 if (bind(fd
, (struct sockaddr
*) &cliaddr
, sizeof(cliaddr
)) < 0)
86 err_sys("bind() error");
89 /* Need to allocate buffers before connect(), since they can affect
90 * TCP options (window scale, etc.).
94 sockopts(fd
, 0); /* may also want to set SO_DEBUG */
97 * Connect to the server. Required for TCP, optional for UDP.
100 if (udp
== 0 || connectudp
) {
102 if (connect(fd
, (struct sockaddr
*) &servaddr
, sizeof(servaddr
))
105 if (errno
== EINTR
) /* can happen with SIGIO */
107 if (errno
== EISCONN
) /* can happen with SIGIO */
109 err_sys("connect() error");
114 /* Call getsockname() to find local address bound to socket:
115 TCP ephemeral port was assigned by connect() or bind();
116 UDP ephemeral port was assigned by bind(). */
118 if (getsockname(fd
, (struct sockaddr
*) &cliaddr
, &i
) < 0)
119 err_sys("getsockname() error");
121 /* Can't do one fprintf() since inet_ntoa() stores
122 the result in a static location. */
123 fprintf(stderr
, "connected on %s.%d ",
124 INET_NTOA(cliaddr
.sin_addr
), ntohs(cliaddr
.sin_port
));
125 fprintf(stderr
, "to %s.%d\n",
126 INET_NTOA(servaddr
.sin_addr
), ntohs(servaddr
.sin_port
));
129 sockopts(fd
, 1); /* some options get set after connect() */