xref: /titanic_52/usr/src/cmd/vscan/vscand/vs_eng.c (revision c8dbf746aa55f3a63c8095f8dbae339574156bb8)
1911106dfSjm199354 /*
2911106dfSjm199354  * CDDL HEADER START
3911106dfSjm199354  *
4911106dfSjm199354  * The contents of this file are subject to the terms of the
5911106dfSjm199354  * Common Development and Distribution License (the "License").
6911106dfSjm199354  * You may not use this file except in compliance with the License.
7911106dfSjm199354  *
8911106dfSjm199354  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9911106dfSjm199354  * or http://www.opensolaris.org/os/licensing.
10911106dfSjm199354  * See the License for the specific language governing permissions
11911106dfSjm199354  * and limitations under the License.
12911106dfSjm199354  *
13911106dfSjm199354  * When distributing Covered Code, include this CDDL HEADER in each
14911106dfSjm199354  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15911106dfSjm199354  * If applicable, add the following below this CDDL HEADER, with the
16911106dfSjm199354  * fields enclosed by brackets "[]" replaced with your own identifying
17911106dfSjm199354  * information: Portions Copyright [yyyy] [name of copyright owner]
18911106dfSjm199354  *
19911106dfSjm199354  * CDDL HEADER END
20911106dfSjm199354  */
21911106dfSjm199354 /*
2253c11029Sjm199354  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23911106dfSjm199354  * Use is subject to license terms.
24911106dfSjm199354  */
25911106dfSjm199354 
26911106dfSjm199354 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27911106dfSjm199354 
28911106dfSjm199354 /*
29911106dfSjm199354  * vs_eng.c manages the vs_engines array of scan engine.
30911106dfSjm199354  * Access to the array and other private data is protected by vs_eng_mutex.
31911106dfSjm199354  * A caller can wait for an available engine connection on vs_eng_cv
32911106dfSjm199354  *
33911106dfSjm199354  */
34911106dfSjm199354 
35911106dfSjm199354 #include <sys/types.h>
36911106dfSjm199354 #include <sys/synch.h>
37911106dfSjm199354 #include <sys/socket.h>
38911106dfSjm199354 #include <sys/filio.h>
39911106dfSjm199354 #include <sys/ioctl.h>
40911106dfSjm199354 #include <sys/debug.h>
41bfc848c6Sjm199354 #include <sys/time.h>
42911106dfSjm199354 #include <netinet/in.h>
43911106dfSjm199354 #include <netinet/tcp.h>
44911106dfSjm199354 #include <arpa/inet.h>
45911106dfSjm199354 #include <unistd.h>
46911106dfSjm199354 #include <stdlib.h>
47911106dfSjm199354 #include <string.h>
48911106dfSjm199354 #include <syslog.h>
49911106dfSjm199354 #include <errno.h>
50911106dfSjm199354 #include <poll.h>
51911106dfSjm199354 #include <pthread.h>
52911106dfSjm199354 #include <time.h>
53911106dfSjm199354 
54bfc848c6Sjm199354 #include <signal.h>
55bfc848c6Sjm199354 #include <thread.h>
56bfc848c6Sjm199354 
57911106dfSjm199354 #include "vs_incl.h"
58911106dfSjm199354 
59bfc848c6Sjm199354 /* max connections per scan engine */
60bfc848c6Sjm199354 #define	VS_CXN_MAX	VS_VAL_SE_MAXCONN_MAX
61bfc848c6Sjm199354 
62bfc848c6Sjm199354 /*
63bfc848c6Sjm199354  * vs_eng_state_t - connection state
64bfc848c6Sjm199354  *
65bfc848c6Sjm199354  * Each configured scan engine supports up to vse_cfg.vep_maxconn
66bfc848c6Sjm199354  * connections. These connections are represented by a vs_connection_t
67bfc848c6Sjm199354  * which defines the connection state, associated socket descriptor
68bfc848c6Sjm199354  * and how long the connection has been available. A connection
69bfc848c6Sjm199354  * that has been available but unused for vs_inactivity_timeout
70bfc848c6Sjm199354  * seconds will be closed by the housekeeper thread.
71bfc848c6Sjm199354  *
72bfc848c6Sjm199354  * When a scan engine is reconfigured to have less connections
73bfc848c6Sjm199354  * (or is disabled) any of he superflous connections which are in
74bfc848c6Sjm199354  * AVAILABLE state are closed (DISCONNECTED). Others are set to
75bfc848c6Sjm199354  * CLOSE_PENDING to be closed (DISCONNECTED) when the engine is
76bfc848c6Sjm199354  * released (when the current request completes).
77bfc848c6Sjm199354  *
78bfc848c6Sjm199354  *              +---------------------+
79bfc848c6Sjm199354  *  |---------->| VS_ENG_DISCONNECTED |<-----------------|
80bfc848c6Sjm199354  *  |           +---------------------+                  |
81bfc848c6Sjm199354  *  |              |                                     |
82bfc848c6Sjm199354  *  |              | eng_get                             |
83bfc848c6Sjm199354  *  |              v                                     | release/
84bfc848c6Sjm199354  *  | shutdown  +---------------------+   reconfig       | shutdown
85bfc848c6Sjm199354  *  |<----------| VS_ENG_RESERVED     | -----------|     |
86bfc848c6Sjm199354  *  |           +---------------------+            |     |
87bfc848c6Sjm199354  *  |              |                               v     |
88bfc848c6Sjm199354  *  |              |                       +----------------------+
89bfc848c6Sjm199354  *  |              | connect               | VS_ENG_CLOSE_PENDING |
90bfc848c6Sjm199354  *  |              |                       +----------------------+
91bfc848c6Sjm199354  *  |              v                               ^
92bfc848c6Sjm199354  *  | shutdown  +---------------------+            |
93bfc848c6Sjm199354  *  |<----------| VS_ENG_INUSE        |------------|
94bfc848c6Sjm199354  *  |           +---------------------+  reconfig/error
95bfc848c6Sjm199354  *  |              |           ^
96bfc848c6Sjm199354  *  |              | release   | eng_get
97bfc848c6Sjm199354  *  | reconfig/    |           |
98bfc848c6Sjm199354  *  | timeout/     v           |
99bfc848c6Sjm199354  *  | shutdown  +---------------------+
100bfc848c6Sjm199354  *  |<----------| VS_ENG_AVAILABLE    |
101bfc848c6Sjm199354  *              +---------------------+
102bfc848c6Sjm199354  *
103bfc848c6Sjm199354  */
104bfc848c6Sjm199354 
105bfc848c6Sjm199354 typedef enum {
106bfc848c6Sjm199354 	VS_ENG_DISCONNECTED = 0,
107bfc848c6Sjm199354 	VS_ENG_RESERVED,
108bfc848c6Sjm199354 	VS_ENG_INUSE,
109bfc848c6Sjm199354 	VS_ENG_AVAILABLE,
110bfc848c6Sjm199354 	VS_ENG_CLOSE_PENDING
111bfc848c6Sjm199354 } vs_eng_state_t;
112bfc848c6Sjm199354 
113bfc848c6Sjm199354 typedef struct vs_connection {
114bfc848c6Sjm199354 	vs_eng_state_t vsc_state;
115bfc848c6Sjm199354 	int vsc_sockfd;
116bfc848c6Sjm199354 	struct timeval vsc_avail_time;
117bfc848c6Sjm199354 } vs_connection_t;
118911106dfSjm199354 
119911106dfSjm199354 typedef struct vs_engine {
120bfc848c6Sjm199354 	vs_props_se_t vse_cfg;	/* host, port, maxconn */
121bfc848c6Sjm199354 	int vse_inuse;		/* # connections in use */
122bfc848c6Sjm199354 	boolean_t vse_error;
123bfc848c6Sjm199354 	vs_connection_t vse_cxns[VS_CXN_MAX];
124911106dfSjm199354 } vs_engine_t;
125911106dfSjm199354 
126911106dfSjm199354 static vs_engine_t vs_engines[VS_SE_MAX];
127911106dfSjm199354 
128911106dfSjm199354 static int vs_eng_next;		/* round-robin "finger" */
129911106dfSjm199354 static int vs_eng_count;	/* how many configured engines */
130911106dfSjm199354 static int vs_eng_total_maxcon;	/* total configured connections */
131911106dfSjm199354 static int vs_eng_total_inuse;	/* total connections in use */
132911106dfSjm199354 static int vs_eng_wait_count;	/* # threads waiting for connection */
133911106dfSjm199354 
134911106dfSjm199354 static pthread_mutex_t vs_eng_mutex = PTHREAD_MUTEX_INITIALIZER;
135911106dfSjm199354 static pthread_cond_t vs_eng_cv;
136bfc848c6Sjm199354 int vs_inactivity_timeout = 60; /* seconds */
137bfc848c6Sjm199354 int vs_reuse_connection = 1;
138911106dfSjm199354 
139bfc848c6Sjm199354 time_t vs_eng_wait = VS_ENG_WAIT_DFLT;
140911106dfSjm199354 
141911106dfSjm199354 /* local functions */
142bfc848c6Sjm199354 static int vs_eng_connect(char *, int);
143bfc848c6Sjm199354 static boolean_t vs_eng_check_errors(void);
144bfc848c6Sjm199354 static int vs_eng_find_connection(int *, int *, boolean_t);
145bfc848c6Sjm199354 static int vs_eng_find_next(boolean_t);
146911106dfSjm199354 static int vs_eng_compare(int, char *, int);
147bfc848c6Sjm199354 static void vs_eng_config_close(vs_engine_t *, int);
148bfc848c6Sjm199354 static void *vs_eng_housekeeper(void *);
149911106dfSjm199354 
150911106dfSjm199354 
151911106dfSjm199354 #ifdef FIONBIO
152911106dfSjm199354 /* non-blocking connect */
153bfc848c6Sjm199354 static int nbio_connect(int, const struct sockaddr *, int);
154911106dfSjm199354 int vs_connect_timeout = 5000; /* milliseconds */
155911106dfSjm199354 #endif /* FIONBIO */
156911106dfSjm199354 
157911106dfSjm199354 
158911106dfSjm199354 /*
159911106dfSjm199354  * vs_eng_init
160911106dfSjm199354  */
161911106dfSjm199354 void
162911106dfSjm199354 vs_eng_init()
163911106dfSjm199354 {
164bfc848c6Sjm199354 	pthread_t tid;
165bfc848c6Sjm199354 
166911106dfSjm199354 	(void) pthread_cond_init(&vs_eng_cv, NULL);
167911106dfSjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
168911106dfSjm199354 
169bfc848c6Sjm199354 	(void) memset(vs_engines, 0, sizeof (vs_engine_t) * VS_SE_MAX);
170bfc848c6Sjm199354 
171911106dfSjm199354 	vs_eng_total_maxcon = 0;
172911106dfSjm199354 	vs_eng_total_inuse = 0;
173911106dfSjm199354 	vs_eng_count = 0;
174911106dfSjm199354 	vs_eng_next = 0;
175911106dfSjm199354 
176911106dfSjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
177bfc848c6Sjm199354 
178bfc848c6Sjm199354 	(void) pthread_create(&tid, NULL, vs_eng_housekeeper, NULL);
179911106dfSjm199354 }
180911106dfSjm199354 
181911106dfSjm199354 
182911106dfSjm199354 /*
183911106dfSjm199354  * vs_eng_config
184911106dfSjm199354  *
185911106dfSjm199354  * Configure scan engine connections.
186911106dfSjm199354  *
187911106dfSjm199354  * If a scan engine has been reconfigured (different host or port)
18853c11029Sjm199354  * the scan engine's error count is reset.
18953c11029Sjm199354  *
190bfc848c6Sjm199354  * If the host/port has changed, the engine has been disabled
191bfc848c6Sjm199354  * or less connections are configured now, connections need
192bfc848c6Sjm199354  * to be closed or placed in CLOSE_PENDING state (vs_eng_config_close)
193bfc848c6Sjm199354  *
194911106dfSjm199354  * vs_icap_config is invoked to reset engine-specific data stored
19553c11029Sjm199354  * in vs_icap.
196911106dfSjm199354  *
197911106dfSjm199354  */
198911106dfSjm199354 void
199911106dfSjm199354 vs_eng_config(vs_props_all_t *config)
200911106dfSjm199354 {
201911106dfSjm199354 	int i;
202911106dfSjm199354 	vs_props_se_t *cfg;
20353c11029Sjm199354 	vs_engine_t *eng;
204911106dfSjm199354 
205911106dfSjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
206911106dfSjm199354 
207911106dfSjm199354 	vs_eng_count = 0;
208911106dfSjm199354 	vs_eng_total_maxcon = 0;
209911106dfSjm199354 
210911106dfSjm199354 	for (i = 0; i < VS_SE_MAX; i++) {
211911106dfSjm199354 		cfg = &config->va_se[i];
21253c11029Sjm199354 		eng = &vs_engines[i];
213911106dfSjm199354 
214bfc848c6Sjm199354 		if (vs_eng_compare(i, cfg->vep_host, cfg->vep_port) != 0) {
215bfc848c6Sjm199354 			vs_eng_config_close(eng, 0);
216bfc848c6Sjm199354 			eng->vse_error = B_FALSE;
217bfc848c6Sjm199354 		}
218911106dfSjm199354 
219911106dfSjm199354 		if (cfg->vep_enable) {
220bfc848c6Sjm199354 			if (cfg->vep_maxconn < eng->vse_cfg.vep_maxconn)
221bfc848c6Sjm199354 				vs_eng_config_close(eng, cfg->vep_maxconn);
222bfc848c6Sjm199354 
22353c11029Sjm199354 			eng->vse_cfg = *cfg;
224911106dfSjm199354 			vs_eng_total_maxcon += cfg->vep_maxconn;
225911106dfSjm199354 			vs_eng_count++;
226911106dfSjm199354 		} else {
227bfc848c6Sjm199354 			vs_eng_config_close(eng, 0);
22853c11029Sjm199354 			(void) memset(&eng->vse_cfg, 0, sizeof (vs_props_se_t));
229911106dfSjm199354 		}
230911106dfSjm199354 
23153c11029Sjm199354 		vs_icap_config(i, eng->vse_cfg.vep_host, eng->vse_cfg.vep_port);
232911106dfSjm199354 	}
233911106dfSjm199354 
234911106dfSjm199354 	if ((vs_eng_total_maxcon <= 0) || (vs_eng_count == 0))
235*c8dbf746Sjm199354 		syslog(LOG_NOTICE, "Scan Engine - no engines configured");
236911106dfSjm199354 
237911106dfSjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
238911106dfSjm199354 }
239911106dfSjm199354 
240911106dfSjm199354 
241911106dfSjm199354 /*
242bfc848c6Sjm199354  * vs_eng_config_close
243911106dfSjm199354  *
244bfc848c6Sjm199354  *	If the host/port has changed, the engine has been disabled
245bfc848c6Sjm199354  *	or less connections are configured now, connections need
246bfc848c6Sjm199354  *	to be closed or placed in CLOSE_PENDING state
247bfc848c6Sjm199354  */
248bfc848c6Sjm199354 static void
249bfc848c6Sjm199354 vs_eng_config_close(vs_engine_t *eng, int start_idx)
250bfc848c6Sjm199354 {
251bfc848c6Sjm199354 	int i;
252bfc848c6Sjm199354 	vs_connection_t *cxn;
253bfc848c6Sjm199354 
254bfc848c6Sjm199354 	for (i = start_idx; i < eng->vse_cfg.vep_maxconn; i++) {
255bfc848c6Sjm199354 		cxn = &(eng->vse_cxns[i]);
256bfc848c6Sjm199354 
257bfc848c6Sjm199354 		switch (cxn->vsc_state) {
258bfc848c6Sjm199354 		case VS_ENG_RESERVED:
259bfc848c6Sjm199354 		case VS_ENG_INUSE:
260bfc848c6Sjm199354 			cxn->vsc_state = VS_ENG_CLOSE_PENDING;
261bfc848c6Sjm199354 			break;
262bfc848c6Sjm199354 		case VS_ENG_AVAILABLE:
263bfc848c6Sjm199354 			(void) close(cxn->vsc_sockfd);
264bfc848c6Sjm199354 			cxn->vsc_sockfd = -1;
265bfc848c6Sjm199354 			cxn->vsc_state = VS_ENG_DISCONNECTED;
266bfc848c6Sjm199354 			break;
267bfc848c6Sjm199354 		case VS_ENG_CLOSE_PENDING:
268bfc848c6Sjm199354 		case VS_ENG_DISCONNECTED:
269bfc848c6Sjm199354 			break;
270bfc848c6Sjm199354 		}
271bfc848c6Sjm199354 	}
272bfc848c6Sjm199354 }
273bfc848c6Sjm199354 
274bfc848c6Sjm199354 
275bfc848c6Sjm199354 /*
276bfc848c6Sjm199354  * vs_eng_fini
277911106dfSjm199354  */
278911106dfSjm199354 void
279911106dfSjm199354 vs_eng_fini()
280911106dfSjm199354 {
281911106dfSjm199354 	(void) pthread_cond_destroy(&vs_eng_cv);
282bfc848c6Sjm199354 }
283bfc848c6Sjm199354 
284bfc848c6Sjm199354 
285bfc848c6Sjm199354 /*
286bfc848c6Sjm199354  * vs_eng_housekeeper
287bfc848c6Sjm199354  *
288bfc848c6Sjm199354  * Wakeup every (vs_inactivity_timeout / 2) seconds and close
289bfc848c6Sjm199354  * any connections that are in AVAILABLE state but have not
290bfc848c6Sjm199354  * been used for vs_inactivity_timeout seconds.
291bfc848c6Sjm199354  */
292bfc848c6Sjm199354 /* ARGSUSED */
293bfc848c6Sjm199354 static void *
294bfc848c6Sjm199354 vs_eng_housekeeper(void *arg)
295bfc848c6Sjm199354 {
296bfc848c6Sjm199354 	struct timeval now;
297bfc848c6Sjm199354 	long expire;
298bfc848c6Sjm199354 	int i, j;
299bfc848c6Sjm199354 	vs_engine_t *eng;
300bfc848c6Sjm199354 	vs_connection_t *cxn;
301bfc848c6Sjm199354 
302bfc848c6Sjm199354 	for (;;) {
303bfc848c6Sjm199354 		(void) sleep(vs_inactivity_timeout / 2);
304bfc848c6Sjm199354 
305bfc848c6Sjm199354 		if (vscand_get_state() == VS_STATE_SHUTDOWN)
306bfc848c6Sjm199354 			break;
307bfc848c6Sjm199354 
308bfc848c6Sjm199354 		(void) gettimeofday(&now, NULL);
309bfc848c6Sjm199354 		expire = now.tv_sec - vs_inactivity_timeout;
310bfc848c6Sjm199354 
311bfc848c6Sjm199354 		(void) pthread_mutex_lock(&vs_eng_mutex);
312bfc848c6Sjm199354 		for (i = 0; i < VS_SE_MAX; i++) {
313bfc848c6Sjm199354 			eng = &(vs_engines[i]);
314bfc848c6Sjm199354 			for (j = 0; j < eng->vse_cfg.vep_maxconn; j++) {
315bfc848c6Sjm199354 				cxn = &(eng->vse_cxns[j]);
316bfc848c6Sjm199354 
317bfc848c6Sjm199354 				if ((cxn->vsc_state == VS_ENG_AVAILABLE) &&
318bfc848c6Sjm199354 				    (cxn->vsc_avail_time.tv_sec < expire)) {
319bfc848c6Sjm199354 					(void) close(cxn->vsc_sockfd);
320bfc848c6Sjm199354 					cxn->vsc_sockfd = -1;
321bfc848c6Sjm199354 					cxn->vsc_state = VS_ENG_DISCONNECTED;
322bfc848c6Sjm199354 				}
323bfc848c6Sjm199354 			}
324bfc848c6Sjm199354 		}
325bfc848c6Sjm199354 		(void) pthread_mutex_unlock(&vs_eng_mutex);
326bfc848c6Sjm199354 	}
327bfc848c6Sjm199354 
328bfc848c6Sjm199354 	return (NULL);
329911106dfSjm199354 }
330911106dfSjm199354 
331911106dfSjm199354 
332911106dfSjm199354 /*
333911106dfSjm199354  * vs_eng_set_error
334911106dfSjm199354  *
335911106dfSjm199354  * If the engine identified in conn (host, port) matches the
336911106dfSjm199354  * engine in vs_engines set or clear the error state of the
337911106dfSjm199354  * engine and update the error statistics.
338911106dfSjm199354  *
339bfc848c6Sjm199354  * If error == 0, clear the error state(B_FALSE), else set
340bfc848c6Sjm199354  * the error state (B_TRUE) and increment engine error stats
341911106dfSjm199354  */
342911106dfSjm199354 void
343bfc848c6Sjm199354 vs_eng_set_error(vs_eng_ctx_t *eng_ctx, int error)
344911106dfSjm199354 {
345bfc848c6Sjm199354 	int eidx = eng_ctx->vse_eidx;
346bfc848c6Sjm199354 	int cidx =  eng_ctx->vse_cidx;
347bfc848c6Sjm199354 	vs_engine_t *eng;
348911106dfSjm199354 
349911106dfSjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
350911106dfSjm199354 
351bfc848c6Sjm199354 	eng = &(vs_engines[eidx]);
352bfc848c6Sjm199354 
353bfc848c6Sjm199354 	if (vs_eng_compare(eidx, eng_ctx->vse_host, eng_ctx->vse_port) == 0)
354bfc848c6Sjm199354 		eng->vse_error = (error == 0) ? B_FALSE : B_TRUE;
355bfc848c6Sjm199354 
356bfc848c6Sjm199354 	if (error != 0) {
357bfc848c6Sjm199354 		eng->vse_cxns[cidx].vsc_state = VS_ENG_CLOSE_PENDING;
358bfc848c6Sjm199354 		vs_stats_eng_err(eng_ctx->vse_engid);
359bfc848c6Sjm199354 	}
360911106dfSjm199354 
361911106dfSjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
362911106dfSjm199354 }
363911106dfSjm199354 
364911106dfSjm199354 
365911106dfSjm199354 /*
366911106dfSjm199354  * vs_eng_get
367911106dfSjm199354  * Get next available scan engine connection.
368bfc848c6Sjm199354  * If retry == B_TRUE look for a scan engine with no errors.
369911106dfSjm199354  *
370911106dfSjm199354  * Returns: 0 - success
371911106dfSjm199354  *         -1 - error
372911106dfSjm199354  */
373911106dfSjm199354 int
374bfc848c6Sjm199354 vs_eng_get(vs_eng_ctx_t *eng_ctx, boolean_t retry)
375911106dfSjm199354 {
376911106dfSjm199354 	struct timespec tswait;
377bfc848c6Sjm199354 	int eidx, cidx, sockfd;
378bfc848c6Sjm199354 	vs_engine_t *eng;
379bfc848c6Sjm199354 	vs_connection_t *cxn;
380911106dfSjm199354 
381911106dfSjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
382911106dfSjm199354 
383911106dfSjm199354 	/*
384bfc848c6Sjm199354 	 * If no engines connections configured OR
385911106dfSjm199354 	 * retry and only one engine configured, give up
386911106dfSjm199354 	 */
387bfc848c6Sjm199354 	if ((vs_eng_total_maxcon <= 0) ||
388bfc848c6Sjm199354 	    ((retry == B_TRUE) && (vs_eng_count <= 1))) {
389911106dfSjm199354 		(void) pthread_mutex_unlock(&vs_eng_mutex);
390911106dfSjm199354 		return (-1);
391911106dfSjm199354 	}
392911106dfSjm199354 
393911106dfSjm199354 	tswait.tv_sec = vs_eng_wait;
394911106dfSjm199354 	tswait.tv_nsec = 0;
395911106dfSjm199354 
396911106dfSjm199354 	while ((vscand_get_state() != VS_STATE_SHUTDOWN) &&
397bfc848c6Sjm199354 	    (vs_eng_find_connection(&eidx, &cidx, retry) == -1)) {
398911106dfSjm199354 		/* If retry and all configured engines have errors, give up */
399bfc848c6Sjm199354 		if (retry && vs_eng_check_errors() == B_TRUE) {
400911106dfSjm199354 			(void) pthread_mutex_unlock(&vs_eng_mutex);
401911106dfSjm199354 			return (-1);
402911106dfSjm199354 		}
403911106dfSjm199354 
404911106dfSjm199354 		/* wait for a connection to become available */
405911106dfSjm199354 		vs_eng_wait_count++;
406911106dfSjm199354 		if (pthread_cond_reltimedwait_np(&vs_eng_cv, &vs_eng_mutex,
407911106dfSjm199354 		    &tswait) < 0) {
408*c8dbf746Sjm199354 			syslog(LOG_NOTICE, "Scan Engine "
409911106dfSjm199354 			    "- timeout waiting for available engine");
410911106dfSjm199354 			vs_eng_wait_count--;
411911106dfSjm199354 			(void) pthread_mutex_unlock(&vs_eng_mutex);
412911106dfSjm199354 			return (-1);
413911106dfSjm199354 		}
414911106dfSjm199354 		vs_eng_wait_count--;
415911106dfSjm199354 	}
416911106dfSjm199354 
417911106dfSjm199354 	if (vscand_get_state() == VS_STATE_SHUTDOWN) {
418911106dfSjm199354 		(void) pthread_mutex_unlock(&vs_eng_mutex);
419911106dfSjm199354 		return (-1);
420911106dfSjm199354 	}
421911106dfSjm199354 
422bfc848c6Sjm199354 	eng = &(vs_engines[eidx]);
423bfc848c6Sjm199354 	cxn = &(eng->vse_cxns[cidx]);
424911106dfSjm199354 
425911106dfSjm199354 	/* update in use counts */
426bfc848c6Sjm199354 	eng->vse_inuse++;
427911106dfSjm199354 	vs_eng_total_inuse++;
428911106dfSjm199354 
429911106dfSjm199354 	/* update round-robin index */
430911106dfSjm199354 	if (!retry)
431bfc848c6Sjm199354 		vs_eng_next = (eidx == VS_SE_MAX) ? 0 : eidx + 1;
432bfc848c6Sjm199354 
433bfc848c6Sjm199354 	/* populate vs_eng_ctx_t */
434bfc848c6Sjm199354 	eng_ctx->vse_eidx = eidx;
435bfc848c6Sjm199354 	eng_ctx->vse_cidx = cidx;
436bfc848c6Sjm199354 	(void) strlcpy(eng_ctx->vse_engid, eng->vse_cfg.vep_engid,
437bfc848c6Sjm199354 	    sizeof (eng_ctx->vse_engid));
438bfc848c6Sjm199354 	(void) strlcpy(eng_ctx->vse_host, eng->vse_cfg.vep_host,
439bfc848c6Sjm199354 	    sizeof (eng_ctx->vse_host));
440bfc848c6Sjm199354 	eng_ctx->vse_port = eng->vse_cfg.vep_port;
441bfc848c6Sjm199354 	eng_ctx->vse_sockfd = cxn->vsc_sockfd;
442bfc848c6Sjm199354 
443bfc848c6Sjm199354 	if (cxn->vsc_state == VS_ENG_INUSE) {
444bfc848c6Sjm199354 		(void) pthread_mutex_unlock(&vs_eng_mutex);
445bfc848c6Sjm199354 		return (0);
446bfc848c6Sjm199354 	}
447bfc848c6Sjm199354 
448bfc848c6Sjm199354 	/* state == VS_ENG_RESERVED, need to connect */
449911106dfSjm199354 
450911106dfSjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
451911106dfSjm199354 
452bfc848c6Sjm199354 	sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port);
453bfc848c6Sjm199354 
454bfc848c6Sjm199354 	/* retry a failed connection once */
455bfc848c6Sjm199354 	if (sockfd == -1) {
456bfc848c6Sjm199354 		(void) sleep(1);
457bfc848c6Sjm199354 		sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port);
458bfc848c6Sjm199354 	}
459bfc848c6Sjm199354 
460bfc848c6Sjm199354 	if (sockfd == -1) {
461*c8dbf746Sjm199354 		syslog(LOG_NOTICE, "Scan Engine - connection error (%s:%d) %s",
462bfc848c6Sjm199354 		    eng_ctx->vse_host, eng_ctx->vse_port,
463bfc848c6Sjm199354 		    errno ? strerror(errno) : "");
464bfc848c6Sjm199354 		vs_eng_set_error(eng_ctx, 1);
465bfc848c6Sjm199354 		vs_eng_release(eng_ctx);
466bfc848c6Sjm199354 		return (-1);
467bfc848c6Sjm199354 	}
468bfc848c6Sjm199354 
469bfc848c6Sjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
470bfc848c6Sjm199354 	switch (cxn->vsc_state) {
471bfc848c6Sjm199354 	case VS_ENG_DISCONNECTED:
472bfc848c6Sjm199354 		/* SHUTDOWN occured */
473bfc848c6Sjm199354 		(void) pthread_mutex_unlock(&vs_eng_mutex);
474bfc848c6Sjm199354 		vs_eng_release(eng_ctx);
475bfc848c6Sjm199354 		return (-1);
476bfc848c6Sjm199354 	case VS_ENG_RESERVED:
477bfc848c6Sjm199354 		cxn->vsc_state = VS_ENG_INUSE;
478bfc848c6Sjm199354 		break;
479bfc848c6Sjm199354 	case VS_ENG_CLOSE_PENDING:
480bfc848c6Sjm199354 		/* reconfigure occured. Connection will be closed after use */
481bfc848c6Sjm199354 		break;
482bfc848c6Sjm199354 	case VS_ENG_INUSE:
483bfc848c6Sjm199354 	case VS_ENG_AVAILABLE:
484bfc848c6Sjm199354 	default:
485bfc848c6Sjm199354 		ASSERT(0);
486bfc848c6Sjm199354 		break;
487bfc848c6Sjm199354 	}
488bfc848c6Sjm199354 
489bfc848c6Sjm199354 	cxn->vsc_sockfd = sockfd;
490bfc848c6Sjm199354 	eng_ctx->vse_sockfd = sockfd;
491bfc848c6Sjm199354 
492bfc848c6Sjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
493911106dfSjm199354 	return (0);
494911106dfSjm199354 }
495911106dfSjm199354 
496911106dfSjm199354 
497911106dfSjm199354 /*
498911106dfSjm199354  * vs_eng_check_errors
499911106dfSjm199354  *
500bfc848c6Sjm199354  * Check if all engines with maxconn > 0 are in error state
501911106dfSjm199354  *
502bfc848c6Sjm199354  * Returns: B_TRUE  - all (valid) engines are in error state
503bfc848c6Sjm199354  *          B_FALSE - otherwise
504911106dfSjm199354  */
505bfc848c6Sjm199354 static boolean_t
506911106dfSjm199354 vs_eng_check_errors()
507911106dfSjm199354 {
508911106dfSjm199354 	int i;
509911106dfSjm199354 
510911106dfSjm199354 	for (i = 0; i < VS_SE_MAX; i++) {
511911106dfSjm199354 		if (vs_engines[i].vse_cfg.vep_maxconn > 0 &&
512bfc848c6Sjm199354 		    (vs_engines[i].vse_error == B_FALSE))
513bfc848c6Sjm199354 			return (B_FALSE);
514bfc848c6Sjm199354 	}
515bfc848c6Sjm199354 
516bfc848c6Sjm199354 	return (B_TRUE);
517bfc848c6Sjm199354 }
518bfc848c6Sjm199354 
519bfc848c6Sjm199354 
520bfc848c6Sjm199354 /*
521bfc848c6Sjm199354  * vs_eng_find_connection
522bfc848c6Sjm199354  *
523bfc848c6Sjm199354  * Identify the next engine to be used (vs_eng_find_next()).
524bfc848c6Sjm199354  * Select the engine's first connection in AVAILABLE state.
525bfc848c6Sjm199354  * If no connection is in AVAILABLE state, select the first
526bfc848c6Sjm199354  * that is in DISCONNECTED state.
527bfc848c6Sjm199354  *
528bfc848c6Sjm199354  * Returns: 0 success
529bfc848c6Sjm199354  *         -1 no engine connections available (eng_idx & cxn_idx undefined)
530bfc848c6Sjm199354  */
531bfc848c6Sjm199354 static int
532bfc848c6Sjm199354 vs_eng_find_connection(int *eng_idx, int *cxn_idx, boolean_t retry)
533bfc848c6Sjm199354 {
534bfc848c6Sjm199354 	int i, idx;
535bfc848c6Sjm199354 	vs_engine_t *eng;
536bfc848c6Sjm199354 	vs_connection_t *cxn;
537bfc848c6Sjm199354 
538bfc848c6Sjm199354 	/* identify engine */
539bfc848c6Sjm199354 	if ((idx = vs_eng_find_next(retry)) == -1)
540bfc848c6Sjm199354 		return (-1);
541bfc848c6Sjm199354 
542bfc848c6Sjm199354 	eng = &(vs_engines[idx]);
543bfc848c6Sjm199354 	*eng_idx = idx;
544bfc848c6Sjm199354 
545bfc848c6Sjm199354 	/* identify connection */
546bfc848c6Sjm199354 	idx = -1;
547bfc848c6Sjm199354 	for (i = 0; i < eng->vse_cfg.vep_maxconn; i++) {
548bfc848c6Sjm199354 		cxn = &(eng->vse_cxns[i]);
549bfc848c6Sjm199354 		if (cxn->vsc_state == VS_ENG_AVAILABLE) {
550bfc848c6Sjm199354 			*cxn_idx = i;
551bfc848c6Sjm199354 			cxn->vsc_state = VS_ENG_INUSE;
552911106dfSjm199354 			return (0);
553911106dfSjm199354 		}
554911106dfSjm199354 
555bfc848c6Sjm199354 		if ((idx == -1) &&
556bfc848c6Sjm199354 		    (cxn->vsc_state == VS_ENG_DISCONNECTED)) {
557bfc848c6Sjm199354 			idx = i;
558bfc848c6Sjm199354 		}
559bfc848c6Sjm199354 	}
560bfc848c6Sjm199354 
561bfc848c6Sjm199354 	if (idx == -1)
562bfc848c6Sjm199354 		return (-1);
563bfc848c6Sjm199354 
564bfc848c6Sjm199354 	eng->vse_cxns[idx].vsc_state = VS_ENG_RESERVED;
565bfc848c6Sjm199354 	*cxn_idx = idx;
566bfc848c6Sjm199354 	return (0);
567911106dfSjm199354 }
568911106dfSjm199354 
569911106dfSjm199354 
570911106dfSjm199354 /*
571911106dfSjm199354  * vs_eng_find_next
572911106dfSjm199354  *
573911106dfSjm199354  * Returns: -1 no engine connections available
574911106dfSjm199354  *          idx of engine to use
575911106dfSjm199354  */
576911106dfSjm199354 static int
577bfc848c6Sjm199354 vs_eng_find_next(boolean_t retry)
578911106dfSjm199354 {
579911106dfSjm199354 	int i;
580911106dfSjm199354 
581911106dfSjm199354 	for (i = vs_eng_next; i < VS_SE_MAX; i++) {
582bfc848c6Sjm199354 		if (vs_engines[i].vse_inuse <
583911106dfSjm199354 		    vs_engines[i].vse_cfg.vep_maxconn) {
584bfc848c6Sjm199354 			if (!retry || (vs_engines[i].vse_error == B_FALSE))
585911106dfSjm199354 				return (i);
586911106dfSjm199354 		}
587911106dfSjm199354 	}
588911106dfSjm199354 
589911106dfSjm199354 	for (i = 0; i < vs_eng_next; i++) {
590bfc848c6Sjm199354 		if (vs_engines[i].vse_inuse <
591911106dfSjm199354 		    vs_engines[i].vse_cfg.vep_maxconn) {
592bfc848c6Sjm199354 			if (!retry || (vs_engines[i].vse_error == B_FALSE))
593911106dfSjm199354 				return (i);
594911106dfSjm199354 		}
595911106dfSjm199354 	}
596911106dfSjm199354 
597911106dfSjm199354 	return (-1);
598911106dfSjm199354 }
599911106dfSjm199354 
600911106dfSjm199354 
601911106dfSjm199354 /*
602911106dfSjm199354  * vs_eng_release
603911106dfSjm199354  */
604911106dfSjm199354 void
605bfc848c6Sjm199354 vs_eng_release(const vs_eng_ctx_t *eng_ctx)
606911106dfSjm199354 {
607bfc848c6Sjm199354 	int eidx = eng_ctx->vse_eidx;
608bfc848c6Sjm199354 	int cidx = eng_ctx->vse_cidx;
609bfc848c6Sjm199354 	vs_connection_t *cxn;
610911106dfSjm199354 
611911106dfSjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
612bfc848c6Sjm199354 	cxn = &(vs_engines[eidx].vse_cxns[cidx]);
613bfc848c6Sjm199354 
614bfc848c6Sjm199354 	switch (cxn->vsc_state) {
615bfc848c6Sjm199354 	case VS_ENG_DISCONNECTED:
616bfc848c6Sjm199354 		break;
617bfc848c6Sjm199354 	case VS_ENG_RESERVED:
618bfc848c6Sjm199354 		cxn->vsc_state = VS_ENG_DISCONNECTED;
619bfc848c6Sjm199354 		break;
620bfc848c6Sjm199354 	case VS_ENG_INUSE:
621bfc848c6Sjm199354 		if (vs_reuse_connection) {
622bfc848c6Sjm199354 			cxn->vsc_state = VS_ENG_AVAILABLE;
623bfc848c6Sjm199354 			(void) gettimeofday(&cxn->vsc_avail_time, NULL);
624bfc848c6Sjm199354 			break;
625bfc848c6Sjm199354 		}
626bfc848c6Sjm199354 		/* LINTED E_CASE_FALL_THROUGH - close connection */
627bfc848c6Sjm199354 	case VS_ENG_CLOSE_PENDING:
628bfc848c6Sjm199354 		(void) close(cxn->vsc_sockfd);
629bfc848c6Sjm199354 		cxn->vsc_sockfd = -1;
630bfc848c6Sjm199354 		cxn->vsc_state = VS_ENG_DISCONNECTED;
631bfc848c6Sjm199354 		break;
632bfc848c6Sjm199354 	case VS_ENG_AVAILABLE:
633bfc848c6Sjm199354 	default:
634bfc848c6Sjm199354 		ASSERT(0);
635bfc848c6Sjm199354 		break;
636bfc848c6Sjm199354 	}
637911106dfSjm199354 
638911106dfSjm199354 	/* decrement in use counts */
639bfc848c6Sjm199354 	vs_engines[eidx].vse_inuse--;
640911106dfSjm199354 	vs_eng_total_inuse--;
641911106dfSjm199354 
642911106dfSjm199354 	/* wake up next thread waiting for a connection */
643911106dfSjm199354 	(void) pthread_cond_signal(&vs_eng_cv);
644911106dfSjm199354 
645911106dfSjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
646911106dfSjm199354 }
647911106dfSjm199354 
648911106dfSjm199354 
649911106dfSjm199354 /*
650911106dfSjm199354  * vs_eng_close_connections
651bfc848c6Sjm199354  *
652bfc848c6Sjm199354  * Set vs_eng_total_maxcon to 0 to ensure no new engine sessions
653bfc848c6Sjm199354  * can be initiated.
654911106dfSjm199354  * Close all open connections to abort in-progress scans.
655bfc848c6Sjm199354  * Set connection state to DISCONNECTED.
656911106dfSjm199354  */
657bfc848c6Sjm199354 void
658911106dfSjm199354 vs_eng_close_connections(void)
659911106dfSjm199354 {
660bfc848c6Sjm199354 	int i, j;
661bfc848c6Sjm199354 	vs_connection_t *cxn;
662bfc848c6Sjm199354 
663bfc848c6Sjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
664bfc848c6Sjm199354 	vs_eng_total_maxcon = 0;
665911106dfSjm199354 
666911106dfSjm199354 	for (i = 0; i < VS_SE_MAX; i++) {
667bfc848c6Sjm199354 		for (j = 0; j < VS_CXN_MAX; j++) {
668bfc848c6Sjm199354 			cxn = &(vs_engines[i].vse_cxns[j]);
669bfc848c6Sjm199354 
670bfc848c6Sjm199354 			switch (cxn->vsc_state) {
671bfc848c6Sjm199354 			case VS_ENG_INUSE:
672bfc848c6Sjm199354 			case VS_ENG_AVAILABLE:
673bfc848c6Sjm199354 			case VS_ENG_CLOSE_PENDING:
674bfc848c6Sjm199354 				(void) close(cxn->vsc_sockfd);
675bfc848c6Sjm199354 				cxn->vsc_sockfd = -1;
676bfc848c6Sjm199354 				break;
677bfc848c6Sjm199354 			case VS_ENG_DISCONNECTED:
678bfc848c6Sjm199354 			case VS_ENG_RESERVED:
679bfc848c6Sjm199354 			default:
680bfc848c6Sjm199354 				break;
681bfc848c6Sjm199354 
682bfc848c6Sjm199354 			}
683bfc848c6Sjm199354 
684bfc848c6Sjm199354 			cxn->vsc_state = VS_ENG_DISCONNECTED;
685911106dfSjm199354 		}
686911106dfSjm199354 	}
687bfc848c6Sjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
688911106dfSjm199354 }
689911106dfSjm199354 
690911106dfSjm199354 
691911106dfSjm199354 /*
692911106dfSjm199354  * vs_eng_connect
693911106dfSjm199354  * open socket connection to remote scan engine
694bfc848c6Sjm199354  *
695bfc848c6Sjm199354  * Returns: sockfd or -1 (error)
696911106dfSjm199354  */
697bfc848c6Sjm199354 static int
698bfc848c6Sjm199354 vs_eng_connect(char *host, int port)
699911106dfSjm199354 {
700bfc848c6Sjm199354 	int rc, sockfd, opt_nodelay, opt_keepalive, opt_reuseaddr, err_num;
701911106dfSjm199354 	struct sockaddr_in addr;
702911106dfSjm199354 	struct hostent *hp;
703911106dfSjm199354 
704bfc848c6Sjm199354 	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
705911106dfSjm199354 		return (-1);
706911106dfSjm199354 
707bfc848c6Sjm199354 	hp = getipnodebyname(host, AF_INET, 0, &err_num);
708bfc848c6Sjm199354 	if (hp == NULL) {
709bfc848c6Sjm199354 		(void) close(sockfd);
710911106dfSjm199354 		return (-1);
711bfc848c6Sjm199354 	}
712911106dfSjm199354 
713911106dfSjm199354 	(void) memset(&addr, 0, sizeof (addr));
714911106dfSjm199354 	(void) memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
715bfc848c6Sjm199354 	addr.sin_port = htons(port);
716911106dfSjm199354 	addr.sin_family = hp->h_addrtype;
717911106dfSjm199354 	freehostent(hp);
718911106dfSjm199354 
719911106dfSjm199354 #ifdef FIONBIO /* Use non-blocking mode for connect. */
720bfc848c6Sjm199354 	rc = nbio_connect(sockfd, (struct sockaddr *)&addr,
721911106dfSjm199354 	    sizeof (struct sockaddr));
722911106dfSjm199354 #else
723bfc848c6Sjm199354 	rc = connect(sockfd, (struct sockaddr *)&addr,
724911106dfSjm199354 	    sizeof (struct sockaddr));
725911106dfSjm199354 #endif
726911106dfSjm199354 
727bfc848c6Sjm199354 	opt_nodelay = 1;
728bfc848c6Sjm199354 	opt_keepalive = 1;
729bfc848c6Sjm199354 	opt_reuseaddr = 1;
730911106dfSjm199354 
731bfc848c6Sjm199354 	if ((rc < 0) ||
732bfc848c6Sjm199354 	    (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
733bfc848c6Sjm199354 	    &opt_nodelay, sizeof (opt_nodelay)) < 0) ||
734bfc848c6Sjm199354 	    (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
735bfc848c6Sjm199354 	    &opt_keepalive, sizeof (opt_keepalive)) < 0) ||
736bfc848c6Sjm199354 	    (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
737bfc848c6Sjm199354 	    &opt_reuseaddr, sizeof (opt_reuseaddr)) < 0)) {
738bfc848c6Sjm199354 		(void) close(sockfd);
739911106dfSjm199354 		return (-1);
740911106dfSjm199354 	}
741911106dfSjm199354 
742bfc848c6Sjm199354 	return (sockfd);
743911106dfSjm199354 }
744911106dfSjm199354 
745911106dfSjm199354 
746911106dfSjm199354 /*
747911106dfSjm199354  * nbio_connect
748911106dfSjm199354  *
749911106dfSjm199354  * Attempt to do a non-blocking connect call.
750911106dfSjm199354  * Wait for a maximum of "vs_connect_timeout" millisec, then check for
751911106dfSjm199354  * socket error to determine if connect successful or not.
752911106dfSjm199354  */
753911106dfSjm199354 #ifdef FIONBIO
754911106dfSjm199354 static int
755bfc848c6Sjm199354 nbio_connect(int sockfd, const struct sockaddr *sa, int sa_len)
756911106dfSjm199354 {
757911106dfSjm199354 	struct pollfd pfd;
758911106dfSjm199354 	int nbio, rc;
759911106dfSjm199354 	int error, len = sizeof (error);
760911106dfSjm199354 
761911106dfSjm199354 	nbio = 1;
762bfc848c6Sjm199354 	if ((ioctl(sockfd, FIONBIO, &nbio)) < 0)
763bfc848c6Sjm199354 		return (connect(sockfd, sa, sa_len));
764911106dfSjm199354 
765bfc848c6Sjm199354 	if ((rc = connect(sockfd, sa, sa_len)) != 0) {
766911106dfSjm199354 		if (errno == EINPROGRESS || errno == EINTR) {
767bfc848c6Sjm199354 			errno = 0;
768bfc848c6Sjm199354 			pfd.fd = sockfd;
769911106dfSjm199354 			pfd.events = POLLOUT;
770911106dfSjm199354 			pfd.revents = 0;
771911106dfSjm199354 
772911106dfSjm199354 			if ((rc = poll(&pfd, 1, vs_connect_timeout)) <= 0) {
773911106dfSjm199354 				if (rc == 0)
774911106dfSjm199354 					errno = ETIMEDOUT;
775911106dfSjm199354 				rc = -1;
776911106dfSjm199354 			} else {
777bfc848c6Sjm199354 				if ((pfd.revents &
778bfc848c6Sjm199354 				    (POLLHUP | POLLERR | POLLNVAL)) ||
779bfc848c6Sjm199354 				    (!(pfd.revents & POLLOUT))) {
780bfc848c6Sjm199354 					rc = -1;
781bfc848c6Sjm199354 				} else {
782bfc848c6Sjm199354 					rc = getsockopt(sockfd, SOL_SOCKET,
783bfc848c6Sjm199354 					    SO_ERROR, &error, &len);
784911106dfSjm199354 					if (rc != 0 || error != 0)
785911106dfSjm199354 						rc = -1;
786bfc848c6Sjm199354 					if (error != 0)
787bfc848c6Sjm199354 						errno = error;
788bfc848c6Sjm199354 				}
789911106dfSjm199354 			}
790911106dfSjm199354 		}
791911106dfSjm199354 	}
792911106dfSjm199354 
793911106dfSjm199354 	nbio = 0;
794bfc848c6Sjm199354 	(void) ioctl(sockfd, FIONBIO, &nbio);
795911106dfSjm199354 
796911106dfSjm199354 	return (rc);
797911106dfSjm199354 }
798911106dfSjm199354 #endif
799911106dfSjm199354 
800911106dfSjm199354 
801911106dfSjm199354 /*
802911106dfSjm199354  * vs_eng_scanstamp_current
803911106dfSjm199354  *
804911106dfSjm199354  * Check if scanstamp matches that of ANY engine with no errors.
805911106dfSjm199354  * We cannot include engines with errors as they may have been
806911106dfSjm199354  * inaccessible for a long time and thus we may have an old
807911106dfSjm199354  * scanstamp value for them.
808911106dfSjm199354  * If a match is found the scanstamp is considered to be current
809911106dfSjm199354  *
810911106dfSjm199354  * returns: 1 if current, 0 otherwise
811911106dfSjm199354  */
812911106dfSjm199354 int
813911106dfSjm199354 vs_eng_scanstamp_current(vs_scanstamp_t scanstamp)
814911106dfSjm199354 {
815911106dfSjm199354 	int i;
816911106dfSjm199354 
817911106dfSjm199354 	/* if scan stamp is null, not current */
818911106dfSjm199354 	if (scanstamp[0] == '\0')
819911106dfSjm199354 		return (0);
820911106dfSjm199354 
82153c11029Sjm199354 	/* if scanstamp matches that of any enabled engine with no errors */
822911106dfSjm199354 	(void) pthread_mutex_lock(&vs_eng_mutex);
823911106dfSjm199354 	for (i = 0; i < VS_SE_MAX; i++) {
82453c11029Sjm199354 		if ((vs_engines[i].vse_cfg.vep_enable) &&
825bfc848c6Sjm199354 		    (vs_engines[i].vse_error == B_FALSE) &&
826911106dfSjm199354 		    (vs_icap_compare_scanstamp(i, scanstamp) == 0))
827911106dfSjm199354 			break;
828911106dfSjm199354 	}
829911106dfSjm199354 	(void) pthread_mutex_unlock(&vs_eng_mutex);
830911106dfSjm199354 
831911106dfSjm199354 	return ((i < VS_SE_MAX) ? 1 : 0);
832911106dfSjm199354 }
833911106dfSjm199354 
834911106dfSjm199354 
835911106dfSjm199354 /*
836911106dfSjm199354  * vs_eng_compare
837911106dfSjm199354  * compare host and port with that stored for engine idx
838911106dfSjm199354  *
839911106dfSjm199354  * Returns: 0 - if equal
840911106dfSjm199354  */
841911106dfSjm199354 static int
842911106dfSjm199354 vs_eng_compare(int idx, char *host, int port)
843911106dfSjm199354 {
844911106dfSjm199354 	if (vs_engines[idx].vse_cfg.vep_port != port)
845911106dfSjm199354 		return (-1);
846911106dfSjm199354 
847911106dfSjm199354 	if (strcmp(vs_engines[idx].vse_cfg.vep_host, host) != 0)
848911106dfSjm199354 		return (-1);
849911106dfSjm199354 
850911106dfSjm199354 	return (0);
851911106dfSjm199354 }
852