1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * vs_eng.c manages the vs_engines array of scan engine. 30 * Access to the array and other private data is protected by vs_eng_mutex. 31 * A caller can wait for an available engine connection on vs_eng_cv 32 * 33 */ 34 35 #include <sys/types.h> 36 #include <sys/synch.h> 37 #include <sys/socket.h> 38 #include <sys/filio.h> 39 #include <sys/ioctl.h> 40 #include <sys/debug.h> 41 #include <sys/time.h> 42 #include <netinet/in.h> 43 #include <netinet/tcp.h> 44 #include <arpa/inet.h> 45 #include <unistd.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <syslog.h> 49 #include <errno.h> 50 #include <poll.h> 51 #include <pthread.h> 52 #include <time.h> 53 54 #include <signal.h> 55 #include <thread.h> 56 57 #include "vs_incl.h" 58 59 /* max connections per scan engine */ 60 #define VS_CXN_MAX VS_VAL_SE_MAXCONN_MAX 61 62 /* 63 * vs_eng_state_t - connection state 64 * 65 * Each configured scan engine supports up to vse_cfg.vep_maxconn 66 * connections. These connections are represented by a vs_connection_t 67 * which defines the connection state, associated socket descriptor 68 * and how long the connection has been available. A connection 69 * that has been available but unused for vs_inactivity_timeout 70 * seconds will be closed by the housekeeper thread. 71 * 72 * When a scan engine is reconfigured to have less connections 73 * (or is disabled) any of he superflous connections which are in 74 * AVAILABLE state are closed (DISCONNECTED). Others are set to 75 * CLOSE_PENDING to be closed (DISCONNECTED) when the engine is 76 * released (when the current request completes). 77 * 78 * +---------------------+ 79 * |---------->| VS_ENG_DISCONNECTED |<-----------------| 80 * | +---------------------+ | 81 * | | | 82 * | | eng_get | 83 * | v | release/ 84 * | shutdown +---------------------+ reconfig | shutdown 85 * |<----------| VS_ENG_RESERVED | -----------| | 86 * | +---------------------+ | | 87 * | | v | 88 * | | +----------------------+ 89 * | | connect | VS_ENG_CLOSE_PENDING | 90 * | | +----------------------+ 91 * | v ^ 92 * | shutdown +---------------------+ | 93 * |<----------| VS_ENG_INUSE |------------| 94 * | +---------------------+ reconfig/error 95 * | | ^ 96 * | | release | eng_get 97 * | reconfig/ | | 98 * | timeout/ v | 99 * | shutdown +---------------------+ 100 * |<----------| VS_ENG_AVAILABLE | 101 * +---------------------+ 102 * 103 */ 104 105 typedef enum { 106 VS_ENG_DISCONNECTED = 0, 107 VS_ENG_RESERVED, 108 VS_ENG_INUSE, 109 VS_ENG_AVAILABLE, 110 VS_ENG_CLOSE_PENDING 111 } vs_eng_state_t; 112 113 typedef struct vs_connection { 114 vs_eng_state_t vsc_state; 115 int vsc_sockfd; 116 struct timeval vsc_avail_time; 117 } vs_connection_t; 118 119 typedef struct vs_engine { 120 vs_props_se_t vse_cfg; /* host, port, maxconn */ 121 int vse_inuse; /* # connections in use */ 122 boolean_t vse_error; 123 vs_connection_t vse_cxns[VS_CXN_MAX]; 124 } vs_engine_t; 125 126 static vs_engine_t vs_engines[VS_SE_MAX]; 127 128 static int vs_eng_next; /* round-robin "finger" */ 129 static int vs_eng_count; /* how many configured engines */ 130 static int vs_eng_total_maxcon; /* total configured connections */ 131 static int vs_eng_total_inuse; /* total connections in use */ 132 static int vs_eng_wait_count; /* # threads waiting for connection */ 133 134 static pthread_mutex_t vs_eng_mutex = PTHREAD_MUTEX_INITIALIZER; 135 static pthread_cond_t vs_eng_cv; 136 int vs_inactivity_timeout = 60; /* seconds */ 137 int vs_reuse_connection = 1; 138 139 time_t vs_eng_wait = VS_ENG_WAIT_DFLT; 140 141 /* local functions */ 142 static int vs_eng_connect(char *, int); 143 static boolean_t vs_eng_check_errors(void); 144 static int vs_eng_find_connection(int *, int *, boolean_t); 145 static int vs_eng_find_next(boolean_t); 146 static int vs_eng_compare(int, char *, int); 147 static void vs_eng_config_close(vs_engine_t *, int); 148 static void *vs_eng_housekeeper(void *); 149 150 151 #ifdef FIONBIO 152 /* non-blocking connect */ 153 static int nbio_connect(int, const struct sockaddr *, int); 154 int vs_connect_timeout = 5000; /* milliseconds */ 155 #endif /* FIONBIO */ 156 157 158 /* 159 * vs_eng_init 160 */ 161 void 162 vs_eng_init() 163 { 164 pthread_t tid; 165 166 (void) pthread_cond_init(&vs_eng_cv, NULL); 167 (void) pthread_mutex_lock(&vs_eng_mutex); 168 169 (void) memset(vs_engines, 0, sizeof (vs_engine_t) * VS_SE_MAX); 170 171 vs_eng_total_maxcon = 0; 172 vs_eng_total_inuse = 0; 173 vs_eng_count = 0; 174 vs_eng_next = 0; 175 176 (void) pthread_mutex_unlock(&vs_eng_mutex); 177 178 (void) pthread_create(&tid, NULL, vs_eng_housekeeper, NULL); 179 } 180 181 182 /* 183 * vs_eng_config 184 * 185 * Configure scan engine connections. 186 * 187 * If a scan engine has been reconfigured (different host or port) 188 * the scan engine's error count is reset. 189 * 190 * If the host/port has changed, the engine has been disabled 191 * or less connections are configured now, connections need 192 * to be closed or placed in CLOSE_PENDING state (vs_eng_config_close) 193 * 194 * vs_icap_config is invoked to reset engine-specific data stored 195 * in vs_icap. 196 * 197 */ 198 void 199 vs_eng_config(vs_props_all_t *config) 200 { 201 int i; 202 vs_props_se_t *cfg; 203 vs_engine_t *eng; 204 205 (void) pthread_mutex_lock(&vs_eng_mutex); 206 207 vs_eng_count = 0; 208 vs_eng_total_maxcon = 0; 209 210 for (i = 0; i < VS_SE_MAX; i++) { 211 cfg = &config->va_se[i]; 212 eng = &vs_engines[i]; 213 214 if (vs_eng_compare(i, cfg->vep_host, cfg->vep_port) != 0) { 215 vs_eng_config_close(eng, 0); 216 eng->vse_error = B_FALSE; 217 } 218 219 if (cfg->vep_enable) { 220 if (cfg->vep_maxconn < eng->vse_cfg.vep_maxconn) 221 vs_eng_config_close(eng, cfg->vep_maxconn); 222 223 eng->vse_cfg = *cfg; 224 vs_eng_total_maxcon += cfg->vep_maxconn; 225 vs_eng_count++; 226 } else { 227 vs_eng_config_close(eng, 0); 228 (void) memset(&eng->vse_cfg, 0, sizeof (vs_props_se_t)); 229 } 230 231 vs_icap_config(i, eng->vse_cfg.vep_host, eng->vse_cfg.vep_port); 232 } 233 234 if ((vs_eng_total_maxcon <= 0) || (vs_eng_count == 0)) 235 syslog(LOG_NOTICE, "Scan Engine - no engines configured"); 236 237 (void) pthread_mutex_unlock(&vs_eng_mutex); 238 } 239 240 241 /* 242 * vs_eng_config_close 243 * 244 * If the host/port has changed, the engine has been disabled 245 * or less connections are configured now, connections need 246 * to be closed or placed in CLOSE_PENDING state 247 */ 248 static void 249 vs_eng_config_close(vs_engine_t *eng, int start_idx) 250 { 251 int i; 252 vs_connection_t *cxn; 253 254 for (i = start_idx; i < eng->vse_cfg.vep_maxconn; i++) { 255 cxn = &(eng->vse_cxns[i]); 256 257 switch (cxn->vsc_state) { 258 case VS_ENG_RESERVED: 259 case VS_ENG_INUSE: 260 cxn->vsc_state = VS_ENG_CLOSE_PENDING; 261 break; 262 case VS_ENG_AVAILABLE: 263 (void) close(cxn->vsc_sockfd); 264 cxn->vsc_sockfd = -1; 265 cxn->vsc_state = VS_ENG_DISCONNECTED; 266 break; 267 case VS_ENG_CLOSE_PENDING: 268 case VS_ENG_DISCONNECTED: 269 break; 270 } 271 } 272 } 273 274 275 /* 276 * vs_eng_fini 277 */ 278 void 279 vs_eng_fini() 280 { 281 (void) pthread_cond_destroy(&vs_eng_cv); 282 } 283 284 285 /* 286 * vs_eng_housekeeper 287 * 288 * Wakeup every (vs_inactivity_timeout / 2) seconds and close 289 * any connections that are in AVAILABLE state but have not 290 * been used for vs_inactivity_timeout seconds. 291 */ 292 /* ARGSUSED */ 293 static void * 294 vs_eng_housekeeper(void *arg) 295 { 296 struct timeval now; 297 long expire; 298 int i, j; 299 vs_engine_t *eng; 300 vs_connection_t *cxn; 301 302 for (;;) { 303 (void) sleep(vs_inactivity_timeout / 2); 304 305 if (vscand_get_state() == VS_STATE_SHUTDOWN) 306 break; 307 308 (void) gettimeofday(&now, NULL); 309 expire = now.tv_sec - vs_inactivity_timeout; 310 311 (void) pthread_mutex_lock(&vs_eng_mutex); 312 for (i = 0; i < VS_SE_MAX; i++) { 313 eng = &(vs_engines[i]); 314 for (j = 0; j < eng->vse_cfg.vep_maxconn; j++) { 315 cxn = &(eng->vse_cxns[j]); 316 317 if ((cxn->vsc_state == VS_ENG_AVAILABLE) && 318 (cxn->vsc_avail_time.tv_sec < expire)) { 319 (void) close(cxn->vsc_sockfd); 320 cxn->vsc_sockfd = -1; 321 cxn->vsc_state = VS_ENG_DISCONNECTED; 322 } 323 } 324 } 325 (void) pthread_mutex_unlock(&vs_eng_mutex); 326 } 327 328 return (NULL); 329 } 330 331 332 /* 333 * vs_eng_set_error 334 * 335 * If the engine identified in conn (host, port) matches the 336 * engine in vs_engines set or clear the error state of the 337 * engine and update the error statistics. 338 * 339 * If error == 0, clear the error state(B_FALSE), else set 340 * the error state (B_TRUE) and increment engine error stats 341 */ 342 void 343 vs_eng_set_error(vs_eng_ctx_t *eng_ctx, int error) 344 { 345 int eidx = eng_ctx->vse_eidx; 346 int cidx = eng_ctx->vse_cidx; 347 vs_engine_t *eng; 348 349 (void) pthread_mutex_lock(&vs_eng_mutex); 350 351 eng = &(vs_engines[eidx]); 352 353 if (vs_eng_compare(eidx, eng_ctx->vse_host, eng_ctx->vse_port) == 0) 354 eng->vse_error = (error == 0) ? B_FALSE : B_TRUE; 355 356 if (error != 0) { 357 eng->vse_cxns[cidx].vsc_state = VS_ENG_CLOSE_PENDING; 358 vs_stats_eng_err(eng_ctx->vse_engid); 359 } 360 361 (void) pthread_mutex_unlock(&vs_eng_mutex); 362 } 363 364 365 /* 366 * vs_eng_get 367 * Get next available scan engine connection. 368 * If retry == B_TRUE look for a scan engine with no errors. 369 * 370 * Returns: 0 - success 371 * -1 - error 372 */ 373 int 374 vs_eng_get(vs_eng_ctx_t *eng_ctx, boolean_t retry) 375 { 376 struct timespec tswait; 377 int eidx, cidx, sockfd; 378 vs_engine_t *eng; 379 vs_connection_t *cxn; 380 381 (void) pthread_mutex_lock(&vs_eng_mutex); 382 383 /* 384 * If no engines connections configured OR 385 * retry and only one engine configured, give up 386 */ 387 if ((vs_eng_total_maxcon <= 0) || 388 ((retry == B_TRUE) && (vs_eng_count <= 1))) { 389 (void) pthread_mutex_unlock(&vs_eng_mutex); 390 return (-1); 391 } 392 393 tswait.tv_sec = vs_eng_wait; 394 tswait.tv_nsec = 0; 395 396 while ((vscand_get_state() != VS_STATE_SHUTDOWN) && 397 (vs_eng_find_connection(&eidx, &cidx, retry) == -1)) { 398 /* If retry and all configured engines have errors, give up */ 399 if (retry && vs_eng_check_errors() == B_TRUE) { 400 (void) pthread_mutex_unlock(&vs_eng_mutex); 401 return (-1); 402 } 403 404 /* wait for a connection to become available */ 405 vs_eng_wait_count++; 406 if (pthread_cond_reltimedwait_np(&vs_eng_cv, &vs_eng_mutex, 407 &tswait) < 0) { 408 syslog(LOG_NOTICE, "Scan Engine " 409 "- timeout waiting for available engine"); 410 vs_eng_wait_count--; 411 (void) pthread_mutex_unlock(&vs_eng_mutex); 412 return (-1); 413 } 414 vs_eng_wait_count--; 415 } 416 417 if (vscand_get_state() == VS_STATE_SHUTDOWN) { 418 (void) pthread_mutex_unlock(&vs_eng_mutex); 419 return (-1); 420 } 421 422 eng = &(vs_engines[eidx]); 423 cxn = &(eng->vse_cxns[cidx]); 424 425 /* update in use counts */ 426 eng->vse_inuse++; 427 vs_eng_total_inuse++; 428 429 /* update round-robin index */ 430 if (!retry) 431 vs_eng_next = (eidx == VS_SE_MAX) ? 0 : eidx + 1; 432 433 /* populate vs_eng_ctx_t */ 434 eng_ctx->vse_eidx = eidx; 435 eng_ctx->vse_cidx = cidx; 436 (void) strlcpy(eng_ctx->vse_engid, eng->vse_cfg.vep_engid, 437 sizeof (eng_ctx->vse_engid)); 438 (void) strlcpy(eng_ctx->vse_host, eng->vse_cfg.vep_host, 439 sizeof (eng_ctx->vse_host)); 440 eng_ctx->vse_port = eng->vse_cfg.vep_port; 441 eng_ctx->vse_sockfd = cxn->vsc_sockfd; 442 443 if (cxn->vsc_state == VS_ENG_INUSE) { 444 (void) pthread_mutex_unlock(&vs_eng_mutex); 445 return (0); 446 } 447 448 /* state == VS_ENG_RESERVED, need to connect */ 449 450 (void) pthread_mutex_unlock(&vs_eng_mutex); 451 452 sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port); 453 454 /* retry a failed connection once */ 455 if (sockfd == -1) { 456 (void) sleep(1); 457 sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port); 458 } 459 460 if (sockfd == -1) { 461 syslog(LOG_NOTICE, "Scan Engine - connection error (%s:%d) %s", 462 eng_ctx->vse_host, eng_ctx->vse_port, 463 errno ? strerror(errno) : ""); 464 vs_eng_set_error(eng_ctx, 1); 465 vs_eng_release(eng_ctx); 466 return (-1); 467 } 468 469 (void) pthread_mutex_lock(&vs_eng_mutex); 470 switch (cxn->vsc_state) { 471 case VS_ENG_DISCONNECTED: 472 /* SHUTDOWN occured */ 473 (void) pthread_mutex_unlock(&vs_eng_mutex); 474 vs_eng_release(eng_ctx); 475 return (-1); 476 case VS_ENG_RESERVED: 477 cxn->vsc_state = VS_ENG_INUSE; 478 break; 479 case VS_ENG_CLOSE_PENDING: 480 /* reconfigure occured. Connection will be closed after use */ 481 break; 482 case VS_ENG_INUSE: 483 case VS_ENG_AVAILABLE: 484 default: 485 ASSERT(0); 486 break; 487 } 488 489 cxn->vsc_sockfd = sockfd; 490 eng_ctx->vse_sockfd = sockfd; 491 492 (void) pthread_mutex_unlock(&vs_eng_mutex); 493 return (0); 494 } 495 496 497 /* 498 * vs_eng_check_errors 499 * 500 * Check if all engines with maxconn > 0 are in error state 501 * 502 * Returns: B_TRUE - all (valid) engines are in error state 503 * B_FALSE - otherwise 504 */ 505 static boolean_t 506 vs_eng_check_errors() 507 { 508 int i; 509 510 for (i = 0; i < VS_SE_MAX; i++) { 511 if (vs_engines[i].vse_cfg.vep_maxconn > 0 && 512 (vs_engines[i].vse_error == B_FALSE)) 513 return (B_FALSE); 514 } 515 516 return (B_TRUE); 517 } 518 519 520 /* 521 * vs_eng_find_connection 522 * 523 * Identify the next engine to be used (vs_eng_find_next()). 524 * Select the engine's first connection in AVAILABLE state. 525 * If no connection is in AVAILABLE state, select the first 526 * that is in DISCONNECTED state. 527 * 528 * Returns: 0 success 529 * -1 no engine connections available (eng_idx & cxn_idx undefined) 530 */ 531 static int 532 vs_eng_find_connection(int *eng_idx, int *cxn_idx, boolean_t retry) 533 { 534 int i, idx; 535 vs_engine_t *eng; 536 vs_connection_t *cxn; 537 538 /* identify engine */ 539 if ((idx = vs_eng_find_next(retry)) == -1) 540 return (-1); 541 542 eng = &(vs_engines[idx]); 543 *eng_idx = idx; 544 545 /* identify connection */ 546 idx = -1; 547 for (i = 0; i < eng->vse_cfg.vep_maxconn; i++) { 548 cxn = &(eng->vse_cxns[i]); 549 if (cxn->vsc_state == VS_ENG_AVAILABLE) { 550 *cxn_idx = i; 551 cxn->vsc_state = VS_ENG_INUSE; 552 return (0); 553 } 554 555 if ((idx == -1) && 556 (cxn->vsc_state == VS_ENG_DISCONNECTED)) { 557 idx = i; 558 } 559 } 560 561 if (idx == -1) 562 return (-1); 563 564 eng->vse_cxns[idx].vsc_state = VS_ENG_RESERVED; 565 *cxn_idx = idx; 566 return (0); 567 } 568 569 570 /* 571 * vs_eng_find_next 572 * 573 * Returns: -1 no engine connections available 574 * idx of engine to use 575 */ 576 static int 577 vs_eng_find_next(boolean_t retry) 578 { 579 int i; 580 581 for (i = vs_eng_next; i < VS_SE_MAX; i++) { 582 if (vs_engines[i].vse_inuse < 583 vs_engines[i].vse_cfg.vep_maxconn) { 584 if (!retry || (vs_engines[i].vse_error == B_FALSE)) 585 return (i); 586 } 587 } 588 589 for (i = 0; i < vs_eng_next; i++) { 590 if (vs_engines[i].vse_inuse < 591 vs_engines[i].vse_cfg.vep_maxconn) { 592 if (!retry || (vs_engines[i].vse_error == B_FALSE)) 593 return (i); 594 } 595 } 596 597 return (-1); 598 } 599 600 601 /* 602 * vs_eng_release 603 */ 604 void 605 vs_eng_release(const vs_eng_ctx_t *eng_ctx) 606 { 607 int eidx = eng_ctx->vse_eidx; 608 int cidx = eng_ctx->vse_cidx; 609 vs_connection_t *cxn; 610 611 (void) pthread_mutex_lock(&vs_eng_mutex); 612 cxn = &(vs_engines[eidx].vse_cxns[cidx]); 613 614 switch (cxn->vsc_state) { 615 case VS_ENG_DISCONNECTED: 616 break; 617 case VS_ENG_RESERVED: 618 cxn->vsc_state = VS_ENG_DISCONNECTED; 619 break; 620 case VS_ENG_INUSE: 621 if (vs_reuse_connection) { 622 cxn->vsc_state = VS_ENG_AVAILABLE; 623 (void) gettimeofday(&cxn->vsc_avail_time, NULL); 624 break; 625 } 626 /* LINTED E_CASE_FALL_THROUGH - close connection */ 627 case VS_ENG_CLOSE_PENDING: 628 (void) close(cxn->vsc_sockfd); 629 cxn->vsc_sockfd = -1; 630 cxn->vsc_state = VS_ENG_DISCONNECTED; 631 break; 632 case VS_ENG_AVAILABLE: 633 default: 634 ASSERT(0); 635 break; 636 } 637 638 /* decrement in use counts */ 639 vs_engines[eidx].vse_inuse--; 640 vs_eng_total_inuse--; 641 642 /* wake up next thread waiting for a connection */ 643 (void) pthread_cond_signal(&vs_eng_cv); 644 645 (void) pthread_mutex_unlock(&vs_eng_mutex); 646 } 647 648 649 /* 650 * vs_eng_close_connections 651 * 652 * Set vs_eng_total_maxcon to 0 to ensure no new engine sessions 653 * can be initiated. 654 * Close all open connections to abort in-progress scans. 655 * Set connection state to DISCONNECTED. 656 */ 657 void 658 vs_eng_close_connections(void) 659 { 660 int i, j; 661 vs_connection_t *cxn; 662 663 (void) pthread_mutex_lock(&vs_eng_mutex); 664 vs_eng_total_maxcon = 0; 665 666 for (i = 0; i < VS_SE_MAX; i++) { 667 for (j = 0; j < VS_CXN_MAX; j++) { 668 cxn = &(vs_engines[i].vse_cxns[j]); 669 670 switch (cxn->vsc_state) { 671 case VS_ENG_INUSE: 672 case VS_ENG_AVAILABLE: 673 case VS_ENG_CLOSE_PENDING: 674 (void) close(cxn->vsc_sockfd); 675 cxn->vsc_sockfd = -1; 676 break; 677 case VS_ENG_DISCONNECTED: 678 case VS_ENG_RESERVED: 679 default: 680 break; 681 682 } 683 684 cxn->vsc_state = VS_ENG_DISCONNECTED; 685 } 686 } 687 (void) pthread_mutex_unlock(&vs_eng_mutex); 688 } 689 690 691 /* 692 * vs_eng_connect 693 * open socket connection to remote scan engine 694 * 695 * Returns: sockfd or -1 (error) 696 */ 697 static int 698 vs_eng_connect(char *host, int port) 699 { 700 int rc, sockfd, opt_nodelay, opt_keepalive, opt_reuseaddr, err_num; 701 struct sockaddr_in addr; 702 struct hostent *hp; 703 704 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 705 return (-1); 706 707 hp = getipnodebyname(host, AF_INET, 0, &err_num); 708 if (hp == NULL) { 709 (void) close(sockfd); 710 return (-1); 711 } 712 713 (void) memset(&addr, 0, sizeof (addr)); 714 (void) memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); 715 addr.sin_port = htons(port); 716 addr.sin_family = hp->h_addrtype; 717 freehostent(hp); 718 719 #ifdef FIONBIO /* Use non-blocking mode for connect. */ 720 rc = nbio_connect(sockfd, (struct sockaddr *)&addr, 721 sizeof (struct sockaddr)); 722 #else 723 rc = connect(sockfd, (struct sockaddr *)&addr, 724 sizeof (struct sockaddr)); 725 #endif 726 727 opt_nodelay = 1; 728 opt_keepalive = 1; 729 opt_reuseaddr = 1; 730 731 if ((rc < 0) || 732 (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, 733 &opt_nodelay, sizeof (opt_nodelay)) < 0) || 734 (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, 735 &opt_keepalive, sizeof (opt_keepalive)) < 0) || 736 (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 737 &opt_reuseaddr, sizeof (opt_reuseaddr)) < 0)) { 738 (void) close(sockfd); 739 return (-1); 740 } 741 742 return (sockfd); 743 } 744 745 746 /* 747 * nbio_connect 748 * 749 * Attempt to do a non-blocking connect call. 750 * Wait for a maximum of "vs_connect_timeout" millisec, then check for 751 * socket error to determine if connect successful or not. 752 */ 753 #ifdef FIONBIO 754 static int 755 nbio_connect(int sockfd, const struct sockaddr *sa, int sa_len) 756 { 757 struct pollfd pfd; 758 int nbio, rc; 759 int error, len = sizeof (error); 760 761 nbio = 1; 762 if ((ioctl(sockfd, FIONBIO, &nbio)) < 0) 763 return (connect(sockfd, sa, sa_len)); 764 765 if ((rc = connect(sockfd, sa, sa_len)) != 0) { 766 if (errno == EINPROGRESS || errno == EINTR) { 767 errno = 0; 768 pfd.fd = sockfd; 769 pfd.events = POLLOUT; 770 pfd.revents = 0; 771 772 if ((rc = poll(&pfd, 1, vs_connect_timeout)) <= 0) { 773 if (rc == 0) 774 errno = ETIMEDOUT; 775 rc = -1; 776 } else { 777 if ((pfd.revents & 778 (POLLHUP | POLLERR | POLLNVAL)) || 779 (!(pfd.revents & POLLOUT))) { 780 rc = -1; 781 } else { 782 rc = getsockopt(sockfd, SOL_SOCKET, 783 SO_ERROR, &error, &len); 784 if (rc != 0 || error != 0) 785 rc = -1; 786 if (error != 0) 787 errno = error; 788 } 789 } 790 } 791 } 792 793 nbio = 0; 794 (void) ioctl(sockfd, FIONBIO, &nbio); 795 796 return (rc); 797 } 798 #endif 799 800 801 /* 802 * vs_eng_scanstamp_current 803 * 804 * Check if scanstamp matches that of ANY engine with no errors. 805 * We cannot include engines with errors as they may have been 806 * inaccessible for a long time and thus we may have an old 807 * scanstamp value for them. 808 * If a match is found the scanstamp is considered to be current 809 * 810 * returns: 1 if current, 0 otherwise 811 */ 812 int 813 vs_eng_scanstamp_current(vs_scanstamp_t scanstamp) 814 { 815 int i; 816 817 /* if scan stamp is null, not current */ 818 if (scanstamp[0] == '\0') 819 return (0); 820 821 /* if scanstamp matches that of any enabled engine with no errors */ 822 (void) pthread_mutex_lock(&vs_eng_mutex); 823 for (i = 0; i < VS_SE_MAX; i++) { 824 if ((vs_engines[i].vse_cfg.vep_enable) && 825 (vs_engines[i].vse_error == B_FALSE) && 826 (vs_icap_compare_scanstamp(i, scanstamp) == 0)) 827 break; 828 } 829 (void) pthread_mutex_unlock(&vs_eng_mutex); 830 831 return ((i < VS_SE_MAX) ? 1 : 0); 832 } 833 834 835 /* 836 * vs_eng_compare 837 * compare host and port with that stored for engine idx 838 * 839 * Returns: 0 - if equal 840 */ 841 static int 842 vs_eng_compare(int idx, char *host, int port) 843 { 844 if (vs_engines[idx].vse_cfg.vep_port != port) 845 return (-1); 846 847 if (strcmp(vs_engines[idx].vse_cfg.vep_host, host) != 0) 848 return (-1); 849 850 return (0); 851 } 852