]>
Commit | Line | Data |
---|---|---|
5f623035 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
5f623035 AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
0b96a9b3 | 9 | // Author: Jens-S. V?ckler <voeckler@rvs.uni-hannover.de> |
eb1f6bfa AJ |
10 | // |
11 | // File: socket.hh | |
12 | // Sun May 3 1998 | |
13 | // | |
14 | // (c) 1998 Lehrgebiet Rechnernetze und Verteilte Systeme | |
0b96a9b3 | 15 | // Universit?t Hannover, Germany |
eb1f6bfa AJ |
16 | // |
17 | // Books: W. Richard Steven, "Advanced Programming in the UNIX Environment", | |
18 | // Addison-Wesley, 1992. | |
19 | // | |
20 | // Permission to use, copy, modify, distribute, and sell this software | |
21 | // and its documentation for any purpose is hereby granted without fee, | |
22 | // provided that (i) the above copyright notices and this permission | |
23 | // notice appear in all copies of the software and related documentation, | |
24 | // and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte | |
25 | // Systeme and the University of Hannover may not be used in any | |
26 | // advertising or publicity relating to the software without the | |
27 | // specific, prior written permission of Lehrgebiet Rechnernetze und | |
28 | // Verteilte Systeme and the University of Hannover. | |
29 | // | |
30 | // THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, | |
31 | // EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY | |
32 | // WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | |
33 | // | |
34 | // IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR | |
35 | // THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL, | |
36 | // INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES | |
37 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT | |
38 | // ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, | |
39 | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
40 | // SOFTWARE. | |
41 | // | |
eb1f6bfa AJ |
42 | // Revision 1.3 1999/01/19 11:00:50 voeckler |
43 | // Linux glibc2 fixes for socket size parameters. | |
44 | // | |
45 | // Revision 1.2 1998/08/27 15:23:39 voeckler | |
46 | // added TCP_NODELAY options at several places. | |
47 | // | |
48 | // Revision 1.1 1998/08/13 21:52:55 voeckler | |
49 | // Initial revision | |
50 | // | |
5f623035 AJ |
51 | |
52 | #include "squid.h" | |
eb1f6bfa | 53 | #include "socket.hh" |
074d6a40 AJ |
54 | |
55 | #include <cerrno> | |
56 | #include <cstring> | |
eb1f6bfa AJ |
57 | #include <netinet/tcp.h> |
58 | #include <arpa/inet.h> | |
59 | #include <netdb.h> | |
60 | ||
eb1f6bfa AJ |
61 | #include <unistd.h> |
62 | ||
63 | #include "convert.hh" | |
64 | ||
eb1f6bfa AJ |
65 | int |
66 | setSocketBuffers( int sockfd, int size ) | |
feec68a0 A |
67 | // purpose: set socket buffers for both directions to the specified size |
68 | // paramtr: sockfd (IN): socket file descriptor | |
69 | // size (IN): new socket buffer size | |
70 | // returns: -1 on setsockopt() errors, 0 otherwise | |
71 | // warning: prints error message on stderr, errno will be changed | |
eb1f6bfa | 72 | { |
feec68a0 A |
73 | if ( setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, |
74 | (char*) &size, sizeof(size) ) == -1 ) { | |
75 | perror( "setsockopt( SO_RCVBUF )" ); | |
76 | return -1; | |
77 | } | |
eb1f6bfa | 78 | |
feec68a0 A |
79 | if ( setsockopt( sockfd, SOL_SOCKET, SO_SNDBUF, |
80 | (char*) &size, sizeof(size) ) == -1 ) { | |
81 | perror( "setsockopt( SO_SNDBUF )" ); | |
82 | return -1; | |
83 | } | |
eb1f6bfa | 84 | |
feec68a0 | 85 | return 0; |
eb1f6bfa AJ |
86 | } |
87 | ||
88 | int | |
89 | getSocketNoDelay( int sockfd ) | |
feec68a0 A |
90 | // purpose: get state of the TCP_NODELAY of the socket |
91 | // paramtr: sockfd (IN): socket descriptor | |
92 | // returns: 1, if TCP_NODELAY is set, | |
93 | // 0, if TCP_NODELAY is not set, | |
94 | // -1, if an error occurred (e.g. datagram socket) | |
eb1f6bfa | 95 | { |
feec68a0 | 96 | int delay = 0; |
2ccf2eb2 | 97 | socklen_t len = sizeof(delay); |
feec68a0 A |
98 | if ( getsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY, |
99 | (char*) &delay, &len ) == -1 ) { | |
100 | perror( "# getsockopt( TCP_NODELAY ) failed" ); | |
101 | return -1; | |
102 | } else | |
103 | return ( delay ? 1 : 0 ); | |
eb1f6bfa AJ |
104 | } |
105 | ||
106 | int | |
ced8def3 | 107 | setSocketNoDelay( int sockfd, bool) |
feec68a0 A |
108 | // purpose: get state of the TCP_NODELAY of the socket |
109 | // paramtr: sockfd (IN): socket descriptor | |
110 | // nodelay (IN): true, if TCP_NODELAY is to be set, false otherwise. | |
111 | // returns: 0, if everything worked out o.k. | |
112 | // -1, if an error occurred (e.g. datagram socket) | |
eb1f6bfa | 113 | { |
feec68a0 A |
114 | const int delay = 1; |
115 | if ( setsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY, | |
116 | (const char*) &delay, sizeof(delay) ) == -1 ) { | |
117 | perror( "setsockopt( TCP_NODELAY ) failed" ); | |
118 | return -1; | |
119 | } else | |
120 | return 0; | |
eb1f6bfa AJ |
121 | } |
122 | ||
eb1f6bfa AJ |
123 | int |
124 | commonCode( int& sockfd, bool nodelay, int sendBufferSize, int recvBufferSize ) | |
feec68a0 A |
125 | // purpose: common code in server sockets and client sockets |
126 | // paramtr: sockfd (IO): socket filedescriptor | |
127 | // nodelay (IN): true=set TCP_NODELAY option. | |
128 | // sendBufferSize (IN): don't set (use sys defaults) if < 0 | |
129 | // recvBufferSize (IN): don't set (use sys defaults) if < 0 | |
130 | // returns: 0 == if everthing went ok, -1 otherwise | |
131 | // warning: sockfd will be closed, if -1 is returned! | |
eb1f6bfa | 132 | { |
feec68a0 A |
133 | // set TCP_NODELAY option, if that is wanted. |
134 | // The socket API default is unset. | |
135 | if ( nodelay ) { | |
136 | const int delay = 1; | |
137 | if ( setsockopt( sockfd, IPPROTO_TCP, TCP_NODELAY, | |
138 | (const char*) &delay, sizeof(delay) ) == -1 ) { | |
139 | perror( "setsockopt( TCP_NODELAY ) failed" ); | |
140 | close(sockfd); | |
141 | return -1; | |
142 | } | |
eb1f6bfa | 143 | } |
eb1f6bfa | 144 | |
feec68a0 A |
145 | // set the socket send buffer size explicitly, or use the system default |
146 | if ( sendBufferSize >= 0 ) { | |
147 | if ( setsockopt( sockfd, SOL_SOCKET, SO_SNDBUF, (char*) &sendBufferSize, | |
148 | sizeof(sendBufferSize) ) == -1 ) { | |
149 | perror( "setsockopt( SO_SNDBUF )" ); | |
150 | close(sockfd); | |
151 | return -1; | |
152 | } | |
eb1f6bfa | 153 | } |
eb1f6bfa | 154 | |
feec68a0 A |
155 | // set the socket recv buffer size explicitly, or use the system default |
156 | if ( recvBufferSize >= 0 ) { | |
157 | if ( setsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, (char*) &recvBufferSize, | |
158 | sizeof(recvBufferSize) ) == -1 ) { | |
159 | perror( "setsockopt( SO_RCVBUF )" ); | |
160 | close(sockfd); | |
161 | return -1; | |
162 | } | |
eb1f6bfa | 163 | } |
feec68a0 | 164 | return 0; |
eb1f6bfa AJ |
165 | } |
166 | ||
167 | int | |
168 | connectTo( struct in_addr host, unsigned short port, bool nodelay, | |
feec68a0 A |
169 | int sendBufferSize, int recvBufferSize ) |
170 | // purpose: connect to a server as a client | |
171 | // paramtr: host (IN): address describing the server | |
172 | // port (IN): port to connect at the server | |
173 | // nodelay (IN): true=set TCP_NODELAY option. | |
174 | // sendBufferSize (IN): don't set (use sys defaults) if < 0 | |
175 | // recvBufferSize (IN): don't set (use sys defaults) if < 0 | |
176 | // returns: >=0 is the descriptor of the opened, connected socket, | |
177 | // -1 is an indication of an error (errno may have been reset). | |
eb1f6bfa | 178 | { |
feec68a0 A |
179 | int sockfd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); |
180 | if ( sockfd == -1 ) { | |
181 | perror( "socket() failed" ); | |
182 | return -1; | |
183 | } | |
184 | ||
185 | if ( commonCode( sockfd, nodelay, sendBufferSize, recvBufferSize ) == -1 ) | |
186 | return -1; | |
187 | ||
188 | struct sockaddr_in server; | |
189 | memset( &server, 0, sizeof(server) ); | |
190 | server.sin_family = AF_INET; | |
191 | server.sin_addr = host; | |
192 | server.sin_port = port; | |
193 | if ( connect( sockfd, (struct sockaddr*) &server, sizeof(server) ) == -1 ) { | |
194 | perror( "connect() failure" ); | |
195 | close(sockfd); | |
196 | return -1; | |
197 | } | |
eb1f6bfa | 198 | |
feec68a0 | 199 | return sockfd; |
eb1f6bfa AJ |
200 | } |
201 | ||
202 | int | |
203 | serverSocket( struct in_addr host, unsigned short port, | |
feec68a0 A |
204 | int backlog, bool reuse, bool nodelay, |
205 | int sendBufferSize, int recvBufferSize ) | |
206 | // purpose: open a server socket for listening | |
207 | // paramtr: host (IN): host to bind locally to, use INADDRY_ANY for * | |
208 | // port (IN): port to bind to, use 0 for system assigned | |
209 | // backlog (IN): listen backlog queue length | |
210 | // reuse (IN): set SO_REUSEADDR option - default usefully | |
211 | // nodelay (IN): true=set TCP_NODELAY option. | |
212 | // SETTING TCP_NODELAY ON A SERVER SOCKET DOES NOT MAKE SENSE! | |
213 | // sendBufferSize (IN): don't set (use sys defaults) if < 0 | |
214 | // recvBufferSize (IN): don't set (use sys defaults) if < 0 | |
215 | // returns: opened listening fd, or -1 on error. | |
216 | // warning: error message will be printed on stderr and errno reset. | |
eb1f6bfa | 217 | { |
feec68a0 A |
218 | int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); |
219 | if ( sockfd == -1 ) { | |
220 | perror( "socket" ); | |
221 | return -1; | |
222 | } | |
eb1f6bfa | 223 | |
feec68a0 | 224 | if ( reuse ) { |
9dca980d | 225 | int opt = 1; |
feec68a0 | 226 | if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, |
9dca980d | 227 | (char*) &opt, sizeof(int) ) == -1) { |
feec68a0 A |
228 | perror( "setsockopt( SO_REUSEADDR )" ); |
229 | close( sockfd ); | |
230 | return -1; | |
231 | } | |
eb1f6bfa | 232 | } |
eb1f6bfa | 233 | |
feec68a0 A |
234 | if ( commonCode( sockfd, nodelay, sendBufferSize, recvBufferSize ) == -1 ) |
235 | return -1; | |
eb1f6bfa | 236 | |
feec68a0 A |
237 | struct sockaddr_in server; |
238 | memset( &server, 0, sizeof(server) ); | |
239 | server.sin_family = AF_INET; | |
240 | server.sin_port = port; | |
241 | server.sin_addr = host; | |
242 | if ( bind( sockfd, (SA*) &server, sizeof(server) ) == -1 ) { | |
243 | SockAddress socket; | |
244 | fprintf( stderr, "bind(%s): %s\n", | |
245 | my_sock_ntoa(server,socket), strerror(errno) ); | |
246 | close(sockfd); | |
247 | return -1; | |
248 | } | |
eb1f6bfa | 249 | |
feec68a0 A |
250 | if ( listen( sockfd, backlog ) == -1 ) { |
251 | perror( "listen" ); | |
252 | close(sockfd); | |
253 | return -1; | |
254 | } | |
eb1f6bfa | 255 | |
feec68a0 | 256 | return sockfd; |
eb1f6bfa | 257 | } |
f53969cc | 258 |