[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 * tcpcheck.c - checks to see if a TCP connection can be established 3 * to the specified host/port. Prints a success message 4 * or a failure message for each host. 5 * 6 * Think of it as 'fping' for TCP connections. Maximum 7 * parallelism. 8 * 9 * Designed to be as non-blocking as possible, but DNS FAILURES WILL 10 * CAUSE IT TO PAUSE. You have been warned. 11 * 12 * Timeout handling: 13 * 14 * Uses the depricated alarm() syntax for simple compatability between 15 * BSD systems. 16 * 17 * Copyright (C) 1998 David G. Andersen <angio@aros.net> 18 * 19 * This information is subject to change without notice and does not 20 * represent a commitment on the part of David G. Andersen 21 * This software is furnished under a license and a nondisclosure agreement. 22 * This software may be used or copied only in accordance with the terms of 23 * this agreement. It is against Federal Law to copy this software on magnetic 24 * tape, disk, or any other medium for any purpose other than the purchaser's 25 * use. David G. Andersen makes no warranty of any kind, expressed 26 * or implied, with regard to these programs or documentation. David G. 27 * Andersen shall not be liable in any event for incidental or consequential 28 * damages in connection with, or arising out of, the furnishing, performance, 29 * or use of these programs. 30 */ 31 32 33 #include <unistd.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/types.h> 38 #include <sys/time.h> 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 #include <netdb.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <signal.h> 45 #include <time.h> 46 47 #define ERR_SUCCESS 0 48 #define ERR_REFUSED 1 49 #define ERR_TIMEOUT 2 50 #define ERR_OTHER 3 51 52 #define MAXTRIES 220; /* Max number of connection attempts we can 53 try at once. Must be lower than the 54 max number of sockets we can have open... */ 55 56 int numcons; 57 int consused; /* Number actually used */ 58 int timeout = 20; /* 20 second default timeout */ 59 struct connectinfo **cons; 60 61 struct connectinfo { 62 char *hostname; 63 char *portname; 64 short port; 65 int status; 66 int socket; 67 struct sockaddr_in *sockaddr; 68 int socklen; 69 }; 70 71 /* 72 * setupsocket: Configures a socket to make it go away quickly: 73 * 74 * SO_REUSEADDR - allow immediate reuse of the address 75 * not SO_LINGER - Don't wait for data to be delivered. 76 */ 77 78 int setupsocket(int sock) { 79 int flags; 80 struct linger nolinger; 81 82 nolinger.l_onoff = 0; 83 if (setsockopt(sock, SOL_SOCKET, 84 SO_LINGER, (char *) &nolinger, sizeof(nolinger)) == -1) 85 return -1; 86 87 flags = 1; 88 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flags, 89 sizeof(flags)) == -1) 90 return -1; 91 92 /* Last thing we do: Set it nonblocking */ 93 94 flags = O_NONBLOCK | fcntl(sock, F_GETFL); 95 fcntl(sock, F_SETFL, flags); 96 97 return 0; 98 } 99 100 /* 101 * setuphost: Configures a struct connectinfo for 102 * connecting to a host. Opens a socket for it. 103 * 104 * returns 0 on success, -1 on failure 105 */ 106 107 int setuphost(struct connectinfo *cinfo, char *hostport) 108 { 109 struct hostent *tmp; 110 char *port; 111 struct servent *serv; 112 113 if (!hostport) { 114 fprintf(stderr, "null hostname passed to setuphost. bailing\n"); 115 exit(-1); 116 } 117 118 port = strchr(hostport, ':'); 119 if (!port || *(++port) == 0) { 120 return -1; 121 } 122 123 if (port[0] < '0' || port[0] > '9') { 124 serv = getservbyname(port, "tcp"); 125 if (!serv) { 126 return -1; 127 } 128 cinfo->port = ntohs(serv->s_port); 129 } else { 130 cinfo->port = atoi(port); 131 } 132 cinfo->portname = strdup(port); 133 134 cinfo->hostname = strdup(hostport); 135 port = strchr(cinfo->hostname, ':'); 136 *port = 0; 137 138 tmp = gethostbyname(cinfo->hostname); 139 140 /* If DNS fails, skip this puppy */ 141 if (tmp == NULL) { 142 cinfo->status = -1; 143 return -1; 144 } 145 146 cinfo->status = 0; 147 148 /* Groovy. DNS stuff worked, now open a socket for it */ 149 cinfo->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 150 if (cinfo->socket == -1) { 151 return -1; 152 } 153 154 /* Set the socket stuff */ 155 setupsocket(cinfo->socket); 156 157 cinfo->socklen = sizeof(struct sockaddr_in); 158 cinfo->sockaddr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in)); 159 bzero(cinfo->sockaddr, cinfo->socklen); 160 161 bcopy(tmp->h_addr_list[0], 162 &(cinfo->sockaddr->sin_addr), 163 sizeof(cinfo->sockaddr->sin_addr)); 164 #ifdef DA_HAS_STRUCT_SINLEN 165 cinfo->sockaddr->sin_len = cinfo->socklen; 166 #endif 167 cinfo->sockaddr->sin_family = AF_INET; 168 cinfo->sockaddr->sin_port = htons(cinfo->port); 169 170 return 0; 171 } 172 173 void usage() 174 { 175 fprintf(stderr, "usage: tcpcheck <timeout> <host:port> [host:port]\n"); 176 exit(1); 177 } 178 179 void wakeme(int sig) 180 { 181 printf("Got a timeout. Will fail all outstanding connections.\n"); 182 exit(ERR_TIMEOUT); 183 } 184 185 void goodconnect(int i) { 186 printf("%s:%s is alive\n", cons[i]->hostname, cons[i]->portname); 187 cons[i]->status = 1; 188 close(cons[i]->socket); 189 } 190 191 void failedconnect(int i) { 192 printf("%s:%s failed\n", cons[i]->hostname, cons[i]->portname); 193 cons[i]->status = -1; 194 } 195 196 197 /* 198 * utility function to set res = a - b 199 * for timeval structs 200 * Assumes that a > b 201 */ 202 203 void subtime(struct timeval *a, struct timeval *b, struct timeval *res) 204 { 205 206 res->tv_sec = a->tv_sec - b->tv_sec; 207 if (b->tv_usec > a->tv_usec) { 208 a->tv_usec += 1000000; 209 res->tv_sec -= 1; 210 } 211 res->tv_usec = a->tv_usec - b->tv_usec; 212 } 213 214 /* 215 * set up our fd sets 216 */ 217 218 void setupset(fd_set *theset, int *numfds) 219 { 220 int i; 221 int fds_used = 0; 222 223 *numfds = 0; 224 for (i = 0; i < numcons; i++) { 225 if (cons[i] == NULL) continue; 226 if (cons[i]->status == 0 && cons[i]->socket != -1) { 227 FD_SET(cons[i]->socket, theset); 228 fds_used++; 229 if (cons[i]->socket > *numfds) 230 *numfds = cons[i]->socket; 231 } 232 } 233 if (!fds_used) { 234 exit(0); /* Success! */ 235 } 236 } 237 238 /* 239 * We've initiated all connection attempts. 240 * Here we sit and wait for them to complete. 241 */ 242 243 244 void waitforconnects() 245 { 246 fd_set writefds, exceptfds; 247 struct timeval timeleft; 248 struct timeval starttime; 249 struct timeval curtime; 250 struct timeval timeoutval; 251 struct timeval timeused; 252 struct sockaddr_in dummysock; 253 int dummyint = sizeof(dummysock); 254 int numfds; 255 int res; 256 int i; 257 258 gettimeofday(&starttime, NULL); 259 260 261 timeoutval.tv_sec = timeout; 262 timeoutval.tv_usec = 0; 263 264 timeleft = timeoutval; 265 266 while (1) 267 { 268 FD_ZERO(&writefds); 269 FD_ZERO(&exceptfds); 270 setupset(&writefds, &numfds); 271 setupset(&exceptfds, &numfds); 272 res = select(numfds+1, NULL, &writefds, &exceptfds, &timeleft); 273 274 if (res == -1) { 275 perror("select barfed, bailing"); 276 exit(-1); 277 } 278 279 if (res == 0) /* We timed out */ 280 break; 281 282 /* Oooh. We have some successes */ 283 /* First test the exceptions */ 284 285 for (i = 0; i < numcons; i++) 286 { 287 if (cons[i] == NULL) continue; 288 if (FD_ISSET(cons[i]->socket, &exceptfds)) { 289 failedconnect(i); 290 } else if (FD_ISSET(cons[i]->socket, &writefds)) { 291 /* Boggle. It's not always good. select() is weird. */ 292 if (getpeername(cons[i]->socket, (struct sockaddr *)&dummysock, 293 &dummyint)) 294 failedconnect(i); 295 else 296 goodconnect(i); 297 } 298 } 299 300 /* now, timeleft = timeoutval - timeused */ 301 302 gettimeofday(&curtime, NULL); 303 subtime(&curtime, &starttime, &timeused); 304 subtime(&timeoutval, &timeused, &timeleft); 305 } 306 307 /* Now clean up the remainder... they timed out. */ 308 for (i = 0; i < numcons; i++) { 309 if (cons[i]->status == 0) { 310 printf("%s:%d failed: timed out\n", 311 cons[i]->hostname, cons[i]->port); 312 } 313 } 314 } 315 316 317 int main(int argc, char **argv) 318 { 319 struct connectinfo *pending; 320 int i; 321 int res; 322 323 signal(SIGALRM, wakeme); 324 325 if (argc <= 2) usage(); 326 if (argv == NULL || argv[1] == NULL || argv[2] == NULL) usage(); 327 328 timeout = atoi(argv[1]); 329 330 numcons = argc-2; 331 cons = malloc(sizeof(struct connectinfo *) * (numcons+1)); 332 bzero((char *)cons, sizeof(struct connectinfo *) * (numcons+1)); 333 334 pending = NULL; 335 consused = 0; 336 337 /* Create a bunch of connection management structs */ 338 for (i = 2; i < argc; i++) { 339 if (pending == NULL) 340 pending = malloc(sizeof(struct connectinfo)); 341 if (setuphost(pending, argv[i])) { 342 printf("%s failed. could not resolve address\n", pending->hostname); 343 } else { 344 cons[consused++] = pending; 345 pending = NULL; 346 } 347 } 348 349 for (i = 0; i < consused; i++) { 350 if (cons[i] == NULL) continue; 351 res = connect(cons[i]->socket, (struct sockaddr *)(cons[i]->sockaddr), 352 cons[i]->socklen); 353 354 if (res && errno != EINPROGRESS) { 355 failedconnect(i); 356 } 357 } 358 359 /* Okay, we've initiated all of our connection attempts. 360 * Now we just have to wait for them to timeout or complete 361 */ 362 363 waitforconnects(); 364 365 exit(0); 366 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |