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