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
vs_eng_init()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
vs_eng_config(vs_props_all_t * config)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
vs_eng_config_close(vs_engine_t * eng,int start_idx)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
vs_eng_fini()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 *
vs_eng_housekeeper(void * arg)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
vs_eng_set_error(vs_eng_ctx_t * eng_ctx,int error)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
vs_eng_get(vs_eng_ctx_t * eng_ctx,boolean_t retry)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
vs_eng_check_errors()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
vs_eng_find_connection(int * eng_idx,int * cxn_idx,boolean_t retry)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
vs_eng_find_next(boolean_t retry)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
vs_eng_release(const vs_eng_ctx_t * eng_ctx)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
vs_eng_close_connections(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
vs_eng_connect(char * host,int port)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
nbio_connect(int sockfd,const struct sockaddr * sa,int sa_len)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
vs_eng_scanstamp_current(vs_scanstamp_t scanstamp)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
vs_eng_compare(int idx,char * host,int port)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