|
13 | 13 | *
|
14 | 14 | *Copyright (c) 2001-2003, PostgreSQL Global Development Group
|
15 | 15 | *
|
16 |
| - *$Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.46 2003/11/07 21:55:50 tgl Exp $ |
| 16 | + *$Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.47 2003/11/15 17:24:07 tgl Exp $ |
17 | 17 | * ----------
|
18 | 18 | */
|
19 | 19 | #include"postgres.h"
|
@@ -203,60 +203,83 @@ pgstat_init(void)
|
203 | 203 | gotostartup_failed;
|
204 | 204 | }
|
205 | 205 |
|
| 206 | +/* |
| 207 | + * On some platforms, getaddrinfo_all() may return multiple addresses |
| 208 | + * only one of which will actually work (eg, both IPv6 and IPv4 addresses |
| 209 | + * when kernel will reject IPv6). Worse, the failure may occur at the |
| 210 | + * bind() or perhaps even connect() stage. So we must loop through the |
| 211 | + * results till we find a working combination. We will generate LOG |
| 212 | + * messages, but no error, for bogus combinations. |
| 213 | + */ |
206 | 214 | for (addr=addrs;addr;addr=addr->ai_next)
|
207 | 215 | {
|
208 | 216 | #ifdefHAVE_UNIX_SOCKETS
|
209 | 217 | /* Ignore AF_UNIX sockets, if any are returned. */
|
210 | 218 | if (addr->ai_family==AF_UNIX)
|
211 | 219 | continue;
|
212 | 220 | #endif
|
213 |
| -if ((pgStatSock=socket(addr->ai_family,SOCK_DGRAM,0)) >=0) |
214 |
| -break; |
215 |
| -} |
| 221 | +/* |
| 222 | + * Create the socket. |
| 223 | + */ |
| 224 | +if ((pgStatSock=socket(addr->ai_family,SOCK_DGRAM,0))<0) |
| 225 | +{ |
| 226 | +ereport(LOG, |
| 227 | +(errcode_for_socket_access(), |
| 228 | +errmsg("could not create socket for statistics collector: %m"))); |
| 229 | +continue; |
| 230 | +} |
216 | 231 |
|
217 |
| -if (!addr||pgStatSock<0) |
218 |
| -{ |
219 |
| -ereport(LOG, |
220 |
| -(errcode_for_socket_access(), |
221 |
| -errmsg("could not create socket for statistics collector: %m"))); |
222 |
| -gotostartup_failed; |
223 |
| -} |
| 232 | +/* |
| 233 | + * Bind it to a kernel assigned port on localhost and get the assigned |
| 234 | + * port via getsockname(). |
| 235 | + */ |
| 236 | +if (bind(pgStatSock,addr->ai_addr,addr->ai_addrlen)<0) |
| 237 | +{ |
| 238 | +ereport(LOG, |
| 239 | +(errcode_for_socket_access(), |
| 240 | +errmsg("could not bind socket for statistics collector: %m"))); |
| 241 | +closesocket(pgStatSock); |
| 242 | +pgStatSock=-1; |
| 243 | +continue; |
| 244 | +} |
224 | 245 |
|
225 |
| -/* |
226 |
| - * Bind it to a kernel assigned port on localhost and get the assigned |
227 |
| - * port via getsockname(). |
228 |
| - */ |
229 |
| -if (bind(pgStatSock,addr->ai_addr,addr->ai_addrlen)<0) |
230 |
| -{ |
231 |
| -ereport(LOG, |
232 |
| -(errcode_for_socket_access(), |
233 |
| -errmsg("could not bind socket for statistics collector: %m"))); |
234 |
| -gotostartup_failed; |
235 |
| -} |
| 246 | +alen=sizeof(pgStatAddr); |
| 247 | +if (getsockname(pgStatSock, (structsockaddr*)&pgStatAddr,&alen)<0) |
| 248 | +{ |
| 249 | +ereport(LOG, |
| 250 | +(errcode_for_socket_access(), |
| 251 | +errmsg("could not get address of socket for statistics collector: %m"))); |
| 252 | +closesocket(pgStatSock); |
| 253 | +pgStatSock=-1; |
| 254 | +continue; |
| 255 | +} |
236 | 256 |
|
237 |
| -freeaddrinfo_all(hints.ai_family,addrs); |
238 |
| -addrs=NULL; |
| 257 | +/* |
| 258 | + * Connect the socket to its own address. This saves a few cycles by |
| 259 | + * not having to respecify the target address on every send. This also |
| 260 | + * provides a kernel-level check that only packets from this same |
| 261 | + * address will be received. |
| 262 | + */ |
| 263 | +if (connect(pgStatSock, (structsockaddr*)&pgStatAddr,alen)<0) |
| 264 | +{ |
| 265 | +ereport(LOG, |
| 266 | +(errcode_for_socket_access(), |
| 267 | +errmsg("could not connect socket for statistics collector: %m"))); |
| 268 | +closesocket(pgStatSock); |
| 269 | +pgStatSock=-1; |
| 270 | +continue; |
| 271 | +} |
239 | 272 |
|
240 |
| -alen=sizeof(pgStatAddr); |
241 |
| -if (getsockname(pgStatSock, (structsockaddr*)&pgStatAddr,&alen)<0) |
242 |
| -{ |
243 |
| -ereport(LOG, |
244 |
| -(errcode_for_socket_access(), |
245 |
| -errmsg("could not get address of socket for statistics collector: %m"))); |
246 |
| -gotostartup_failed; |
| 273 | +/* If we get here, we have a working socket */ |
| 274 | +break; |
247 | 275 | }
|
248 | 276 |
|
249 |
| -/* |
250 |
| - * Connect the socket to its own address. This saves a few cycles by |
251 |
| - * not having to respecify the target address on every send. This also |
252 |
| - * provides a kernel-level check that only packets from this same |
253 |
| - * address will be received. |
254 |
| - */ |
255 |
| -if (connect(pgStatSock, (structsockaddr*)&pgStatAddr,alen)<0) |
| 277 | +/* Did we find a working address? */ |
| 278 | +if (!addr||pgStatSock<0) |
256 | 279 | {
|
257 | 280 | ereport(LOG,
|
258 | 281 | (errcode_for_socket_access(),
|
259 |
| -errmsg("could not connect socketforstatistics collector: %m"))); |
| 282 | +errmsg("disabling statistics collectorforlack of working socket"))); |
260 | 283 | gotostartup_failed;
|
261 | 284 | }
|
262 | 285 |
|
@@ -285,6 +308,8 @@ pgstat_init(void)
|
285 | 308 | gotostartup_failed;
|
286 | 309 | }
|
287 | 310 |
|
| 311 | +freeaddrinfo_all(hints.ai_family,addrs); |
| 312 | + |
288 | 313 | return;
|
289 | 314 |
|
290 | 315 | startup_failed:
|
|