forked from unpbook/unpv13e
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcliopen.c
132 lines (110 loc) · 3.9 KB
/
cliopen.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
* Copyright (c) 1993 W. Richard Stevens. All rights reserved.
* Permission to use or modify this software and its documentation only for
* educational purposes and without fee is hereby granted, provided that
* the above copyright notice appear in all copies. The author makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
*/
#include "sock.h"
int
cliopen(char *host, char *port)
{
int fd, i, on;
const char *protocol;
struct in_addr inaddr;
struct servent *sp;
struct hostent *hp;
protocol = udp ? "udp" : "tcp";
/* initialize socket address structure */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
/* see if "port" is a service name or number */
if ( (i = atoi(port)) == 0) {
if ( (sp = getservbyname(port, protocol)) == NULL)
err_quit("getservbyname() error for: %s/%s", port, protocol);
servaddr.sin_port = sp->s_port;
} else
servaddr.sin_port = htons(i);
/*
* First try to convert the host name as a dotted-decimal number.
* Only if that fails do we call gethostbyname().
*/
if (inet_aton(host, &inaddr) == 1)
servaddr.sin_addr = inaddr; /* it's dotted-decimal */
else if ( (hp = gethostbyname(host)) != NULL)
memcpy(&servaddr.sin_addr, hp->h_addr, hp->h_length);
else
err_quit("invalid hostname: %s", host);
if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0)
err_sys("socket() error");
if (reuseaddr) {
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
err_sys("setsockopt of SO_REUSEADDR error");
}
#ifdef SO_REUSEPORT
if (reuseport) {
on = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof (on)) < 0)
err_sys("setsockopt of SO_REUSEPORT error");
}
#endif
/*
* User can specify port number for client to bind. Only real use
* is to see a TCP connection initiated by both ends at the same time.
* Also, if UDP is being used, we specifically call bind() to assign
* an ephemeral port to the socket.
* Also, for experimentation, client can also set local IP address
* (and port) using -l option. Allow localip[] to be set but bindport
* to be 0.
*/
if (bindport != 0 || localip[0] != 0 || udp) {
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(bindport); /* can be 0 */
if (localip[0] != 0) {
if (inet_aton(localip, &cliaddr.sin_addr) == 0)
err_quit("invalid IP address: %s", localip);
} else
cliaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */
if (bind(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0)
err_sys("bind() error");
}
/* Need to allocate buffers before connect(), since they can affect
* TCP options (window scale, etc.).
*/
buffers(fd);
sockopts(fd, 0); /* may also want to set SO_DEBUG */
/*
* Connect to the server. Required for TCP, optional for UDP.
*/
if (udp == 0 || connectudp) {
for ( ; ; ) {
if (connect(fd, (struct sockaddr *) &servaddr, sizeof(servaddr))
== 0)
break; /* all OK */
if (errno == EINTR) /* can happen with SIGIO */
continue;
if (errno == EISCONN) /* can happen with SIGIO */
break;
err_sys("connect() error");
}
}
if (verbose) {
/* Call getsockname() to find local address bound to socket:
TCP ephemeral port was assigned by connect() or bind();
UDP ephemeral port was assigned by bind(). */
i = sizeof(cliaddr);
if (getsockname(fd, (struct sockaddr *) &cliaddr, &i) < 0)
err_sys("getsockname() error");
/* Can't do one fprintf() since inet_ntoa() stores
the result in a static location. */
fprintf(stderr, "connected on %s.%d ",
INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
fprintf(stderr, "to %s.%d\n",
INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port));
}
sockopts(fd, 1); /* some options get set after connect() */
return(fd);
}