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