Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Implements: | |
12 | */ | |
13 | #include <afsconfig.h> | |
14 | #include "afs/param.h" | |
15 | ||
16 | ||
17 | #include "afs/stds.h" | |
18 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
19 | ||
20 | #if !defined(UKERNEL) | |
21 | #if !defined(AFS_LINUX20_ENV) | |
22 | #include <net/if.h> | |
23 | #endif | |
24 | #include <netinet/in.h> | |
25 | ||
26 | #ifdef AFS_SGI62_ENV | |
27 | #include "h/hashing.h" | |
28 | #endif | |
29 | #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) | |
30 | #include <netinet/in_var.h> | |
31 | #endif /* ! AFS_HPUX110_ENV */ | |
32 | #endif /* !defined(UKERNEL) */ | |
33 | ||
34 | #include "afsincludes.h" /* Afs-based standard headers */ | |
35 | #include "afs/afs_stats.h" /* afs statistics */ | |
36 | ||
37 | #if defined(AFS_SUN5_ENV) | |
38 | #include <inet/led.h> | |
39 | #include <inet/common.h> | |
40 | #include <netinet/ip6.h> | |
41 | #include <inet/ip.h> | |
42 | #endif | |
43 | ||
44 | /* Exported variables */ | |
45 | afs_rwlock_t afs_xconn; /* allocation lock for new things */ | |
46 | afs_rwlock_t afs_xinterface; /* for multiple client address */ | |
47 | afs_int32 cryptall = 1; /* encrypt all communications */ | |
48 | ||
49 | /* some connection macros */ | |
50 | ||
51 | /* a constructor */ | |
52 | #define new_conn_vector(xcv) \ | |
53 | do { \ | |
54 | xcv = (struct sa_conn_vector *) \ | |
55 | afs_osi_Alloc(sizeof(struct sa_conn_vector)); \ | |
56 | if (xcv) { \ | |
57 | memset((char *)xcv, 0, sizeof(struct sa_conn_vector)); \ | |
58 | } \ | |
59 | } while (0); | |
60 | ||
61 | /* select a connection to return (if no connection has lower utilization | |
62 | * than any other) */ | |
63 | #define conn_vec_select_conn(xcv, bix, conn) \ | |
64 | do { \ | |
65 | (bix) = ((xcv)->select_index)++ % CVEC_LEN; \ | |
66 | (conn) = &((xcv)->cvec[bix]); \ | |
67 | } while (0); | |
68 | ||
69 | #define struct_conn(s) ((struct afs_conn *)(s)) | |
70 | ||
71 | #define REPORT_CONNECTIONS_ISSUED 0 /* enable to see utilization */ | |
72 | ||
73 | /** | |
74 | * Find a connection with call slots available, allocating one | |
75 | * if nothing is available and we find an allocated slot | |
76 | * @param xcv A connection vector | |
77 | * @param create If set, a new connection may be created | |
78 | */ | |
79 | static struct afs_conn * | |
80 | find_preferred_connection(struct sa_conn_vector *xcv, int create) | |
81 | { | |
82 | afs_int32 cix, bix; | |
83 | struct afs_conn *tc = NULL; | |
84 | ||
85 | bix = -1; | |
86 | for(cix = 0; cix < CVEC_LEN; ++cix) { | |
87 | tc = &(xcv->cvec[cix]); | |
88 | if (!tc->id) { | |
89 | if (create) { | |
90 | tc->parent = xcv; | |
91 | tc->forceConnectFS = 1; | |
92 | tc->activated = 1; | |
93 | bix = cix; | |
94 | break; | |
95 | } /* create */ | |
96 | } else { | |
97 | if (tc->refCount < (RX_MAXCALLS-1)) { | |
98 | bix = cix; | |
99 | goto f_conn; | |
100 | } else if (cix == (CVEC_LEN-1)) | |
101 | conn_vec_select_conn(xcv, bix, tc); | |
102 | } /* tc->id */ | |
103 | } /* for cix < CVEC_LEN */ | |
104 | ||
105 | if (bix < 0) { | |
106 | tc = NULL; | |
107 | goto out; | |
108 | } | |
109 | ||
110 | f_conn: | |
111 | tc->refCount++; | |
112 | xcv->refCount++; | |
113 | ||
114 | #if REPORT_CONNECTIONS_ISSUED | |
115 | afs_warn("Issuing conn %d refCount=%d parent refCount=%d\n", bix, | |
116 | tc->refCount, xcv->refCount); | |
117 | #endif | |
118 | ||
119 | out: | |
120 | return (tc); | |
121 | ||
122 | } /* find_preferred_connection */ | |
123 | ||
124 | ||
125 | /** | |
126 | * Release all connections for unix user xu at server xs | |
127 | * @param xu | |
128 | * @param xs | |
129 | */ | |
130 | static void | |
131 | release_conns_user_server(struct unixuser *xu, struct server *xs) | |
132 | { | |
133 | int cix, glocked; | |
134 | struct srvAddr *sa; | |
135 | struct afs_conn *tc; | |
136 | struct sa_conn_vector *tcv, **lcv, *tcvn; | |
137 | for (sa = (xs)->addr; sa; sa = sa->next_sa) { | |
138 | lcv = &sa->conns; | |
139 | for (tcv = *lcv; tcv; lcv = &tcv->next, tcv = *lcv) { | |
140 | if (tcv->user == (xu) && tcv->refCount == 0) { | |
141 | *lcv = tcv->next; | |
142 | /* our old friend, the GLOCK */ | |
143 | glocked = ISAFS_GLOCK(); | |
144 | if (glocked) | |
145 | AFS_GUNLOCK(); | |
146 | for(cix = 0; cix < CVEC_LEN; ++cix) { | |
147 | tc = &(tcv->cvec[cix]); | |
148 | if (tc->activated) { | |
149 | rx_SetConnSecondsUntilNatPing(tc->id, 0); | |
150 | rx_DestroyConnection(tc->id); | |
151 | /* find another eligible connection */ | |
152 | if (sa->natping == tc) { | |
153 | int cin; | |
154 | struct afs_conn *tcn; | |
155 | for (tcvn = sa->conns; tcvn; tcvn = tcvn->next) { | |
156 | if (tcvn == tcv) | |
157 | continue; | |
158 | for(cin = 0; cin < CVEC_LEN; ++cin) { | |
159 | tcn = &(tcvn->cvec[cin]); | |
160 | if (tcn->activated) { | |
161 | rx_SetConnSecondsUntilNatPing(tcn->id, 20); | |
162 | sa->natping = tcn; | |
163 | break; | |
164 | } | |
165 | } | |
166 | } | |
167 | } | |
168 | } | |
169 | } | |
170 | if (glocked) | |
171 | AFS_GLOCK(); | |
172 | afs_osi_Free(tcv, sizeof(struct sa_conn_vector)); | |
173 | break; /* at most one instance per server */ | |
174 | } /*Found unreferenced connection for user */ | |
175 | } | |
176 | } /*For each connection on the server */ | |
177 | ||
178 | } /* release_conns_user_server */ | |
179 | ||
180 | ||
181 | static void | |
182 | release_conns_vector(struct sa_conn_vector *tcv) | |
183 | { | |
184 | int cix, glocked; | |
185 | struct afs_conn *tc; | |
186 | struct sa_conn_vector *next; | |
187 | ||
188 | while (tcv != NULL) { | |
189 | next = tcv->next; | |
190 | ||
191 | /* you know it, you love it, the GLOCK */ | |
192 | glocked = ISAFS_GLOCK(); | |
193 | if (glocked) | |
194 | AFS_GUNLOCK(); \ | |
195 | for(cix = 0; cix < CVEC_LEN; ++cix) { | |
196 | tc = &(tcv->cvec[cix]); | |
197 | if (tc->activated) { | |
198 | rx_SetConnSecondsUntilNatPing(tc->id, 0); | |
199 | rx_DestroyConnection(tc->id); | |
200 | if (tcv->srvr->natping == tc) | |
201 | tcv->srvr->natping = NULL; | |
202 | } | |
203 | } | |
204 | if (glocked) | |
205 | AFS_GLOCK(); | |
206 | afs_osi_Free(tcv, sizeof(struct sa_conn_vector)); | |
207 | tcv = next; | |
208 | } | |
209 | ||
210 | } /* release_conns_vector */ | |
211 | ||
212 | ||
213 | unsigned int VNOSERVERS = 0; | |
214 | ||
215 | /** | |
216 | * Pick a security object to use for a connection to a given server, | |
217 | * by a given user | |
218 | * | |
219 | * @param[in] conn | |
220 | * The AFS connection for which the security object is required | |
221 | * @param[out] secLevel | |
222 | * The security level of the returned object | |
223 | * | |
224 | * @return | |
225 | * An rx security object. This function is guaranteed to return | |
226 | * an object, although that object may be rxnull (with a secLevel | |
227 | * of 0) | |
228 | */ | |
229 | static struct rx_securityClass * | |
230 | afs_pickSecurityObject(struct afs_conn *conn, int *secLevel) | |
231 | { | |
232 | struct rx_securityClass *secObj = NULL; | |
233 | union tokenUnion *token; | |
234 | ||
235 | /* Do we have tokens ? */ | |
236 | if (conn->parent->user->states & UHasTokens) { | |
237 | token = afs_FindToken(conn->parent->user->tokens, RX_SECIDX_KAD); | |
238 | if (token) { | |
239 | *secLevel = RX_SECIDX_KAD; | |
240 | /* kerberos tickets on channel 2 */ | |
241 | secObj = rxkad_NewClientSecurityObject( | |
242 | cryptall ? rxkad_crypt : rxkad_clear, | |
243 | (struct ktc_encryptionKey *) | |
244 | token->rxkad.clearToken.HandShakeKey, | |
245 | token->rxkad.clearToken.AuthHandle, | |
246 | token->rxkad.ticketLen, token->rxkad.ticket); | |
247 | /* We're going to use this token, so populate the viced */ | |
248 | conn->parent->user->viceId = token->rxkad.clearToken.ViceId; | |
249 | } | |
250 | } | |
251 | if (secObj == NULL) { | |
252 | *secLevel = 0; | |
253 | secObj = rxnull_NewClientSecurityObject(); | |
254 | } | |
255 | ||
256 | return secObj; | |
257 | } | |
258 | ||
259 | ||
260 | /** | |
261 | * Try setting up a connection to the server containing the specified fid. | |
262 | * Gets the volume, checks if it's up and does the connection by server address. | |
263 | * | |
264 | * @param afid | |
265 | * @param areq Request filled in by the caller. | |
266 | * @param locktype Type of lock that will be used. | |
267 | * | |
268 | * @return The conn struct, or NULL. | |
269 | */ | |
270 | struct afs_conn * | |
271 | afs_Conn(struct VenusFid *afid, struct vrequest *areq, | |
272 | afs_int32 locktype, struct rx_connection **rxconn) | |
273 | { | |
274 | u_short fsport = AFS_FSPORT; | |
275 | struct volume *tv; | |
276 | struct afs_conn *tconn = NULL; | |
277 | struct srvAddr *lowp = NULL; | |
278 | struct unixuser *tu; | |
279 | int notbusy; | |
280 | int i; | |
281 | struct srvAddr *sa1p; | |
282 | afs_int32 replicated = -1; /* a single RO will increment to 0 */ | |
283 | ||
284 | *rxconn = NULL; | |
285 | ||
286 | AFS_STATCNT(afs_Conn); | |
287 | /* Get fid's volume. */ | |
288 | tv = afs_GetVolume(afid, areq, READ_LOCK); | |
289 | if (!tv) { | |
290 | if (areq) { | |
291 | afs_FinalizeReq(areq); | |
292 | areq->volumeError = 1; | |
293 | } | |
294 | return NULL; | |
295 | } | |
296 | ||
297 | if (tv->serverHost[0] && tv->serverHost[0]->cell) { | |
298 | fsport = tv->serverHost[0]->cell->fsport; | |
299 | } else { | |
300 | VNOSERVERS++; | |
301 | } | |
302 | ||
303 | /* First is always lowest rank, if it's up */ | |
304 | if ((tv->status[0] == not_busy) && tv->serverHost[0] | |
305 | && tv->serverHost[0]->addr | |
306 | && !(tv->serverHost[0]->addr->sa_flags & SRVR_ISDOWN) && | |
307 | !(((areq->idleError > 0) || (areq->tokenError > 0)) | |
308 | && (areq->skipserver[0] == 1))) | |
309 | lowp = tv->serverHost[0]->addr; | |
310 | ||
311 | /* Otherwise we look at all of them. There are seven levels of | |
312 | * not_busy. This means we will check a volume seven times before it | |
313 | * is marked offline. Ideally, we only need two levels, but this | |
314 | * serves a second purpose of waiting some number of seconds before | |
315 | * the client decides the volume is offline (ie: a clone could finish | |
316 | * in this time). | |
317 | */ | |
318 | for (notbusy = not_busy; (!lowp && (notbusy <= end_not_busy)); notbusy++) { | |
319 | for (i = 0; i < AFS_MAXHOSTS && tv->serverHost[i]; i++) { | |
320 | if (tv->states & VRO) | |
321 | replicated++; | |
322 | if (((areq->tokenError > 0)||(areq->idleError > 0)) | |
323 | && (areq->skipserver[i] == 1)) | |
324 | continue; | |
325 | if (tv->status[i] != notbusy) { | |
326 | if (tv->status[i] == rd_busy || tv->status[i] == rdwr_busy) { | |
327 | if (!areq->busyCount) | |
328 | areq->busyCount++; | |
329 | } else if (tv->status[i] == offline) { | |
330 | if (!areq->volumeError) | |
331 | areq->volumeError = VOLMISSING; | |
332 | } | |
333 | continue; | |
334 | } | |
335 | for (sa1p = tv->serverHost[i]->addr; sa1p; sa1p = sa1p->next_sa) { | |
336 | if (sa1p->sa_flags & SRVR_ISDOWN) | |
337 | continue; | |
338 | if (!lowp || (lowp->sa_iprank > sa1p->sa_iprank)) | |
339 | lowp = sa1p; | |
340 | } | |
341 | } | |
342 | } | |
343 | if ((replicated == -1) && (tv->states & VRO)) { | |
344 | for (i = 0; i < AFS_MAXHOSTS && tv->serverHost[i]; i++) { | |
345 | if (tv->states & VRO) | |
346 | replicated++; | |
347 | } | |
348 | } else | |
349 | replicated = 0; | |
350 | ||
351 | afs_PutVolume(tv, READ_LOCK); | |
352 | ||
353 | if (lowp) { | |
354 | tu = afs_GetUser(areq->uid, afid->Cell, SHARED_LOCK); | |
355 | tconn = afs_ConnBySA(lowp, fsport, afid->Cell, tu, 0 /*!force */ , | |
356 | 1 /*create */ , locktype, replicated, rxconn); | |
357 | ||
358 | afs_PutUser(tu, SHARED_LOCK); | |
359 | } | |
360 | ||
361 | return tconn; | |
362 | } /*afs_Conn */ | |
363 | ||
364 | ||
365 | /** | |
366 | * Connects to a server by it's server address. | |
367 | * | |
368 | * @param sap Server address. | |
369 | * @param aport Server port. | |
370 | * @param acell | |
371 | * @param tu Connect as this user. | |
372 | * @param force_if_down | |
373 | * @param create | |
374 | * @param replicated | |
375 | * @param locktype Specifies type of lock to be used for this function. | |
376 | * | |
377 | * @return The new connection. | |
378 | */ | |
379 | struct afs_conn * | |
380 | afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell, | |
381 | struct unixuser *tu, int force_if_down, afs_int32 create, | |
382 | afs_int32 locktype, afs_int32 replicated, | |
383 | struct rx_connection **rxconn) | |
384 | { | |
385 | int glocked, foundvec; | |
386 | struct afs_conn *tc = NULL; | |
387 | struct sa_conn_vector *tcv = NULL; | |
388 | struct rx_securityClass *csec; /*Security class object */ | |
389 | int isec; /*Security index */ | |
390 | int service; | |
391 | int isrep = (replicated > 0)?CONN_REPLICATED:0; | |
392 | ||
393 | *rxconn = NULL; | |
394 | ||
395 | if (!sap || ((sap->sa_flags & SRVR_ISDOWN) && !force_if_down)) { | |
396 | /* sa is known down, and we don't want to force it. */ | |
397 | return NULL; | |
398 | } | |
399 | ||
400 | /* find cached connection */ | |
401 | ObtainSharedLock(&afs_xconn, 15); | |
402 | foundvec = 0; | |
403 | for (tcv = sap->conns; tcv; tcv = tcv->next) { | |
404 | if (tcv->user == tu && tcv->port == aport && | |
405 | (isrep == (tcv->flags & CONN_REPLICATED))) { | |
406 | /* return most eligible conn */ | |
407 | if (!foundvec) | |
408 | foundvec = 1; | |
409 | UpgradeSToWLock(&afs_xconn, 37); | |
410 | tc = find_preferred_connection(tcv, create); | |
411 | ConvertWToSLock(&afs_xconn); | |
412 | break; | |
413 | } | |
414 | } | |
415 | ||
416 | if (!tc && !create) { | |
417 | /* Not found and can't create a new one. */ | |
418 | ReleaseSharedLock(&afs_xconn); | |
419 | return NULL; | |
420 | } | |
421 | ||
422 | if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) { | |
423 | afs_warnuser("afs_ConnBySA: disconnected\n"); | |
424 | ReleaseSharedLock(&afs_xconn); | |
425 | return NULL; | |
426 | } | |
427 | ||
428 | if (!foundvec && create) { | |
429 | /* No such connection vector exists. Create one and splice it in. | |
430 | * Make sure the server record has been marked as used (for the purposes | |
431 | * of calculating up & down times, it's now considered to be an | |
432 | * ``active'' server). Also make sure the server's lastUpdateEvalTime | |
433 | * gets set, marking the time of its ``birth''. | |
434 | */ | |
435 | UpgradeSToWLock(&afs_xconn, 37); | |
436 | new_conn_vector(tcv); | |
437 | ||
438 | tcv->user = tu; | |
439 | tcv->port = aport; | |
440 | tcv->srvr = sap; | |
441 | tcv->next = sap->conns; | |
442 | if (isrep) | |
443 | tcv->flags |= CONN_REPLICATED; | |
444 | sap->conns = tcv; | |
445 | ||
446 | /* all struct afs_conn ptrs come from here */ | |
447 | tc = find_preferred_connection(tcv, create); | |
448 | ||
449 | afs_ActivateServer(sap); | |
450 | ||
451 | ConvertWToSLock(&afs_xconn); | |
452 | } /* end of if (!tcv) */ | |
453 | ||
454 | if (!tc) { | |
455 | /* Not found and no alternatives. */ | |
456 | ReleaseSharedLock(&afs_xconn); | |
457 | return NULL; | |
458 | } | |
459 | ||
460 | if (tc->refCount > 10000) { | |
461 | static int warned; | |
462 | if (!warned) { | |
463 | warned = 1; | |
464 | afs_warn("afs: Very high afs_conn refCount detected (conn %p, count %d)\n", | |
465 | tc, (int)tc->refCount); | |
466 | afs_warn("afs: Trying to continue, but this may indicate an issue\n"); | |
467 | afs_warn("afs: that may eventually crash the machine. Please file\n"); | |
468 | afs_warn("afs: a bug report.\n"); | |
469 | } | |
470 | } | |
471 | ||
472 | if (tu->states & UTokensBad) { | |
473 | /* we may still have an authenticated RPC connection here, | |
474 | * we'll have to create a new, unauthenticated, connection. | |
475 | * Perhaps a better way to do this would be to set | |
476 | * conn->forceConnectFS on all conns when the token first goes | |
477 | * bad, but that's somewhat trickier, due to locking | |
478 | * constraints (though not impossible). | |
479 | */ | |
480 | if (tc->id && (rx_SecurityClassOf(tc->id) != RX_SECIDX_NULL)) { | |
481 | tc->forceConnectFS = 1; /* force recreation of connection */ | |
482 | } | |
483 | tu->states &= ~UHasTokens; /* remove the authentication info */ | |
484 | } | |
485 | ||
486 | glocked = ISAFS_GLOCK(); | |
487 | if (tc->forceConnectFS) { | |
488 | UpgradeSToWLock(&afs_xconn, 38); | |
489 | if (tc->id) { | |
490 | if (sap->natping == tc) | |
491 | sap->natping = NULL; | |
492 | if (glocked) | |
493 | AFS_GUNLOCK(); | |
494 | rx_SetConnSecondsUntilNatPing(tc->id, 0); | |
495 | rx_DestroyConnection(tc->id); | |
496 | if (glocked) | |
497 | AFS_GLOCK(); | |
498 | } | |
499 | /* | |
500 | * Stupid hack to determine if using vldb service or file system | |
501 | * service. | |
502 | */ | |
503 | if (aport == sap->server->cell->vlport) | |
504 | service = 52; | |
505 | else | |
506 | service = 1; | |
507 | isec = 0; | |
508 | ||
509 | csec = afs_pickSecurityObject(tc, &isec); | |
510 | ||
511 | if (glocked) | |
512 | AFS_GUNLOCK(); | |
513 | tc->id = rx_NewConnection(sap->sa_ip, aport, service, csec, isec); | |
514 | if (glocked) | |
515 | AFS_GLOCK(); | |
516 | if (service == 52) { | |
517 | rx_SetConnHardDeadTime(tc->id, afs_rx_harddead); | |
518 | } | |
519 | ||
520 | /* Setting idle dead time to non-zero activates idle-dead | |
521 | * RX_CALL_TIMEOUT errors. */ | |
522 | if (isrep) | |
523 | rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead_rep); | |
524 | else | |
525 | rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead); | |
526 | ||
527 | /* | |
528 | * Only do this for one connection | |
529 | */ | |
530 | if ((service != 52) && (sap->natping == NULL)) { | |
531 | sap->natping = tc; | |
532 | rx_SetConnSecondsUntilNatPing(tc->id, 20); | |
533 | } | |
534 | ||
535 | tc->forceConnectFS = 0; /* apparently we're appropriately connected now */ | |
536 | if (csec) | |
537 | rxs_Release(csec); | |
538 | ConvertWToSLock(&afs_xconn); | |
539 | } /* end of if (tc->forceConnectFS)*/ | |
540 | ||
541 | *rxconn = tc->id; | |
542 | rx_GetConnection(*rxconn); | |
543 | ||
544 | ReleaseSharedLock(&afs_xconn); | |
545 | return tc; | |
546 | } | |
547 | ||
548 | /** | |
549 | * forceConnectFS is set whenever we must recompute the connection. UTokensBad | |
550 | * is true only if we know that the tokens are bad. We thus clear this flag | |
551 | * when we get a new set of tokens.. | |
552 | * Having force... true and UTokensBad true simultaneously means that the tokens | |
553 | * went bad and we're supposed to create a new, unauthenticated, connection. | |
554 | * | |
555 | * @param aserver Server to connect to. | |
556 | * @param aport Connection port. | |
557 | * @param acell The cell where all of this happens. | |
558 | * @param areq The request. | |
559 | * @param aforce Force connection? | |
560 | * @param locktype Type of lock to be used. | |
561 | * @param replicated | |
562 | * | |
563 | * @return The established connection. | |
564 | */ | |
565 | struct afs_conn * | |
566 | afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell, | |
567 | struct vrequest *areq, int aforce, afs_int32 locktype, | |
568 | afs_int32 replicated, struct rx_connection **rxconn) | |
569 | { | |
570 | struct unixuser *tu; | |
571 | struct afs_conn *tc = NULL; | |
572 | struct srvAddr *sa = NULL; | |
573 | ||
574 | *rxconn = NULL; | |
575 | ||
576 | AFS_STATCNT(afs_ConnByHost); | |
577 | ||
578 | if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) { | |
579 | afs_warnuser("afs_ConnByHost: disconnected\n"); | |
580 | return NULL; | |
581 | } | |
582 | ||
583 | /* | |
584 | 1. look for an existing connection | |
585 | 2. create a connection at an address believed to be up | |
586 | (if aforce is true, create a connection at the first address) | |
587 | */ | |
588 | ||
589 | tu = afs_GetUser(areq->uid, acell, SHARED_LOCK); | |
590 | ||
591 | for (sa = aserver->addr; sa; sa = sa->next_sa) { | |
592 | tc = afs_ConnBySA(sa, aport, acell, tu, aforce, | |
593 | 0 /*don't create one */ , | |
594 | locktype, replicated, rxconn); | |
595 | if (tc) | |
596 | break; | |
597 | } | |
598 | ||
599 | if (!tc) { | |
600 | for (sa = aserver->addr; sa; sa = sa->next_sa) { | |
601 | tc = afs_ConnBySA(sa, aport, acell, tu, aforce, | |
602 | 1 /*create one */ , | |
603 | locktype, replicated, rxconn); | |
604 | if (tc) | |
605 | break; | |
606 | } | |
607 | } | |
608 | ||
609 | afs_PutUser(tu, SHARED_LOCK); | |
610 | return tc; | |
611 | ||
612 | } /*afs_ConnByHost */ | |
613 | ||
614 | ||
615 | /** | |
616 | * Connect by multiple hosts. | |
617 | * Try to connect to one of the hosts from the ahosts array. | |
618 | * | |
619 | * @param ahosts Multiple hosts to connect to. | |
620 | * @param aport Connection port. | |
621 | * @param acell The cell where all of this happens. | |
622 | * @param areq The request. | |
623 | * @param locktype Type of lock to be used. | |
624 | * @param replicated | |
625 | * | |
626 | * @return The established connection or NULL. | |
627 | */ | |
628 | struct afs_conn * | |
629 | afs_ConnByMHosts(struct server *ahosts[], unsigned short aport, | |
630 | afs_int32 acell, struct vrequest *areq, | |
631 | afs_int32 locktype, afs_int32 replicated, | |
632 | struct rx_connection **rxconn) | |
633 | { | |
634 | afs_int32 i; | |
635 | struct afs_conn *tconn; | |
636 | struct server *ts; | |
637 | ||
638 | *rxconn = NULL; | |
639 | ||
640 | /* try to find any connection from the set */ | |
641 | AFS_STATCNT(afs_ConnByMHosts); | |
642 | for (i = 0; i < AFS_MAXCELLHOSTS; i++) { | |
643 | if ((ts = ahosts[i]) == NULL) | |
644 | break; | |
645 | tconn = afs_ConnByHost(ts, aport, acell, areq, 0, locktype, | |
646 | replicated, rxconn); | |
647 | if (tconn) { | |
648 | return tconn; | |
649 | } | |
650 | } | |
651 | return NULL; | |
652 | ||
653 | } /*afs_ConnByMHosts */ | |
654 | ||
655 | ||
656 | /** | |
657 | * Decrement reference count to this connection. | |
658 | * @param ac | |
659 | * @param locktype | |
660 | */ | |
661 | void | |
662 | afs_PutConn(struct afs_conn *ac, struct rx_connection *rxconn, | |
663 | afs_int32 locktype) | |
664 | { | |
665 | AFS_STATCNT(afs_PutConn); | |
666 | ac->refCount--; | |
667 | if (ac->refCount < 0) { | |
668 | osi_Panic("afs_PutConn: refcount imbalance 0x%lx %d", | |
669 | (unsigned long)(uintptrsz)ac, (int)ac->refCount); | |
670 | } | |
671 | ac->parent->refCount--; | |
672 | rx_PutConnection(rxconn); | |
673 | } /*afs_PutConn */ | |
674 | ||
675 | ||
676 | /** | |
677 | * Free up a connection vector, allowing, eg, code in afs_user.c | |
678 | * to ignore how connections are stored/pooled | |
679 | * @param tcv | |
680 | */ | |
681 | void | |
682 | afs_ReleaseConns(struct sa_conn_vector *tcv) { | |
683 | release_conns_vector(tcv); | |
684 | } | |
685 | ||
686 | ||
687 | /** | |
688 | * Free connection vector(s) for a user | |
689 | * @param au | |
690 | */ | |
691 | void | |
692 | afs_ReleaseConnsUser(struct unixuser *au) { | |
693 | ||
694 | int i; | |
695 | struct server *ts; | |
696 | ||
697 | for (i = 0; i < NSERVERS; i++) { | |
698 | for (ts = afs_servers[i]; ts; ts = ts->next) { | |
699 | release_conns_user_server(au, ts); | |
700 | } /*For each server on chain */ | |
701 | } /*For each chain */ | |
702 | } | |
703 | ||
704 | ||
705 | /** | |
706 | * For multi homed clients, a RPC may timeout because of a | |
707 | * client network interface going down. We need to reopen new | |
708 | * connections in this case. | |
709 | * | |
710 | * @param sap Server address. | |
711 | */ | |
712 | void | |
713 | ForceNewConnections(struct srvAddr *sap) | |
714 | { | |
715 | int cix; | |
716 | struct afs_conn *tc = NULL; | |
717 | struct sa_conn_vector *tcv = NULL; | |
718 | ||
719 | if (!sap) | |
720 | return; /* defensive check */ | |
721 | ||
722 | ObtainWriteLock(&afs_xconn, 413); | |
723 | for (tcv = sap->conns; tcv; tcv = tcv->next) { | |
724 | for(cix = 0; cix < CVEC_LEN; ++cix) { | |
725 | tc = &(tcv->cvec[cix]); | |
726 | if (tc->activated) | |
727 | tc->forceConnectFS = 1; | |
728 | } | |
729 | } | |
730 | ReleaseWriteLock(&afs_xconn); | |
731 | } | |
732 | ||
733 |