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