6f0d9438e2352a927de221aafa587cb255f3d07d
[openafs.git] / src / ubik / remote.c
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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #else
19 #include <sys/file.h>
20 #include <netinet/in.h>
21 #endif
22 #include <lock.h>
23 #include <rx/xdr.h>
24 #include <rx/rx.h>
25
26 #define UBIK_INTERNALS
27 #include "ubik.h"
28 #include "ubik_int.h"
29 int (*ubik_CheckRXSecurityProc)();
30 char *ubik_CheckRXSecurityRock;
31 void printServerInfo();
32
33 /* routines for handling requests remotely-submitted by the sync site.  These are
34     only write transactions (we don't propagate read trans), and there is at most one
35     write transaction extant at any one time.
36 */
37
38 struct ubik_trans *ubik_currentTrans = 0;
39
40
41 ubik_CheckAuth(acall)
42 register struct rx_call *acall; {
43     register afs_int32 code;
44     if (ubik_CheckRXSecurityProc) {
45         code = (*ubik_CheckRXSecurityProc)(ubik_CheckRXSecurityRock, acall);
46         return code;
47     }
48     else return 0;
49 }
50
51 /* the rest of these guys handle remote execution of write
52  * transactions: this is the code executed on the other servers when a
53  * sync site is executing a write transaction.
54  */
55 SDISK_Begin(rxcall, atid)
56     register struct rx_call *rxcall;
57     struct ubik_tid *atid;
58 {
59     register afs_int32 code;
60
61     if (code = ubik_CheckAuth(rxcall)) {
62       return code;
63     }
64     DBHOLD(ubik_dbase);
65     urecovery_CheckTid(atid);
66     if (ubik_currentTrans) {
67         /* If the thread is not waiting for lock - ok to end it */
68         if (ubik_currentTrans->locktype != LOCKWAIT) {
69            udisk_end(ubik_currentTrans);
70         }
71         ubik_currentTrans = (struct ubik_trans *) 0;
72     }
73     code = udisk_begin(ubik_dbase, UBIK_WRITETRANS, &ubik_currentTrans);
74     if (!code && ubik_currentTrans) {
75         /* label this trans with the right trans id */
76         ubik_currentTrans->tid.epoch = atid->epoch;
77         ubik_currentTrans->tid.counter = atid->counter;
78     }
79     DBRELE(ubik_dbase);
80     return code;}
81
82
83 SDISK_Commit(rxcall, atid)
84     register struct rx_call *rxcall;
85     struct ubik_tid *atid;
86 {
87     register afs_int32 code;
88     register struct ubik_dbase *dbase;
89     
90     if (code = ubik_CheckAuth(rxcall)) {
91       return code;
92     }
93
94     if (!ubik_currentTrans) {
95       return USYNC;
96     }
97     /*
98      * sanity check to make sure only write trans appear here
99      */
100     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
101       return UBADTYPE;
102     }
103
104     dbase = ubik_currentTrans->dbase;
105     DBHOLD(dbase);
106     urecovery_CheckTid(atid);
107     if (!ubik_currentTrans) {
108         DBRELE(dbase);
109         return USYNC;
110     }
111
112     code = udisk_commit(ubik_currentTrans);
113     if (code == 0) {
114         /* sync site should now match */
115         ubik_dbVersion = ubik_dbase->version;
116     }
117     DBRELE(dbase);
118     return code;
119 }
120
121 SDISK_ReleaseLocks(rxcall, atid)
122     register struct rx_call *rxcall;
123     struct ubik_tid *atid;
124 {
125     register struct ubik_dbase *dbase;
126     register afs_int32 code;
127
128     if (code = ubik_CheckAuth(rxcall)) {
129       return code;
130     }
131
132     if (!ubik_currentTrans) {
133       return USYNC;
134     }
135     /* sanity check to make sure only write trans appear here */
136     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
137       return UBADTYPE;
138     }
139
140     dbase = ubik_currentTrans->dbase;
141     DBHOLD(dbase);
142     urecovery_CheckTid(atid);
143     if (!ubik_currentTrans) {
144         DBRELE(dbase);
145         return USYNC;
146     }
147
148     /* If the thread is not waiting for lock - ok to end it */
149     if (ubik_currentTrans->locktype != LOCKWAIT) {
150        udisk_end(ubik_currentTrans);
151     }
152     ubik_currentTrans = (struct ubik_trans *) 0;
153     DBRELE(dbase);
154     return 0;
155 }
156
157 SDISK_Abort(rxcall, atid)
158     register struct rx_call *rxcall;
159     struct ubik_tid *atid;
160 {
161     register afs_int32 code;
162     register struct ubik_dbase *dbase;
163     
164     if (code = ubik_CheckAuth(rxcall)) {
165       return code;
166     }
167
168     if (!ubik_currentTrans) {
169       return USYNC;
170     }
171     /* sanity check to make sure only write trans appear here  */
172     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
173       return UBADTYPE;
174     }
175
176     dbase = ubik_currentTrans->dbase;
177     DBHOLD(dbase);
178     urecovery_CheckTid(atid);
179     if (!ubik_currentTrans) {
180         DBRELE(dbase);
181         return USYNC;
182     }
183
184     code = udisk_abort(ubik_currentTrans);
185     /* If the thread is not waiting for lock - ok to end it */
186     if (ubik_currentTrans->locktype != LOCKWAIT) {
187        udisk_end(ubik_currentTrans);
188     }
189     ubik_currentTrans = (struct ubik_trans *) 0;
190     DBRELE(dbase);
191     return code;
192 }
193
194 SDISK_Lock(rxcall, atid, afile, apos, alen, atype)
195     register struct rx_call *rxcall;
196     struct ubik_tid *atid;
197     afs_int32 afile, apos, alen, atype;   /* apos and alen are not used */
198 {
199     register afs_int32 code;
200     register struct ubik_dbase *dbase;
201     struct ubik_trans *ubik_thisTrans;
202
203     if (code = ubik_CheckAuth(rxcall)) {
204       return code;
205     }
206     if (!ubik_currentTrans) {
207       return USYNC;
208     }
209     /* sanity check to make sure only write trans appear here */
210     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
211       return UBADTYPE;
212     }
213     if (alen != 1) {
214       return UBADLOCK;
215     }
216     dbase = ubik_currentTrans->dbase;
217     DBHOLD(dbase);
218     urecovery_CheckTid(atid);
219     if (!ubik_currentTrans) {
220         DBRELE(dbase);
221         return USYNC;
222     }
223
224     ubik_thisTrans = ubik_currentTrans;
225     code = ulock_getLock(ubik_currentTrans, atype, 1);
226
227     /* While waiting, the transaction may have been ended/
228      * aborted from under us (urecovery_CheckTid). In that
229      * case, end the transaction here.
230      */
231     if (!code && (ubik_currentTrans != ubik_thisTrans)) {
232        udisk_end(ubik_thisTrans);
233        code = USYNC;
234     }
235
236     DBRELE(dbase);
237     return code;
238 }
239
240 /* Write a vector of data */
241 SDISK_WriteV(rxcall, atid, io_vector, io_buffer)
242     register struct rx_call *rxcall;
243     struct ubik_tid *atid;
244     iovec_wrt *io_vector;
245     iovec_buf *io_buffer;
246 {
247     afs_int32 code, i, offset;
248     struct ubik_dbase *dbase;
249     struct ubik_iovec *iovec;
250     char              *iobuf;
251
252     if (code = ubik_CheckAuth(rxcall)) {
253       return code;
254     }
255     if (!ubik_currentTrans) {
256       return USYNC;
257     }
258     /* sanity check to make sure only write trans appear here */
259     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
260       return UBADTYPE;
261     }
262
263     dbase = ubik_currentTrans->dbase;
264     DBHOLD(dbase);
265     urecovery_CheckTid(atid);
266     if (!ubik_currentTrans) {
267         DBRELE(dbase);
268         return USYNC;
269     }
270
271     iovec = (struct ubik_iovec *)io_vector->iovec_wrt_val;
272     iobuf = (char *)io_buffer->iovec_buf_val;
273     for (i=0, offset=0; i<io_vector->iovec_wrt_len; i++) {
274        /* Sanity check for going off end of buffer */
275        if ((offset + iovec[i].length) > io_buffer->iovec_buf_len) {
276           code = UINTERNAL;
277        } else {
278           code = udisk_write(ubik_currentTrans, iovec[i].file,     &iobuf[offset],
279                                                 iovec[i].position, iovec[i].length);
280        }
281        if (code) break;
282
283        offset += iovec[i].length;
284     }
285
286     DBRELE(dbase);
287     return code;
288 }
289
290 SDISK_Write(rxcall, atid, afile, apos, adata)
291     register struct rx_call *rxcall;
292     struct ubik_tid *atid;
293     afs_int32 afile, apos;
294     register bulkdata *adata; 
295 {
296     register afs_int32 code;
297     register struct ubik_dbase *dbase;
298
299     if (code = ubik_CheckAuth(rxcall)) {
300       return code;
301     }
302     if (!ubik_currentTrans) {
303       return USYNC;
304     }
305     /* sanity check to make sure only write trans appear here */
306     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
307       return UBADTYPE;
308     }
309
310     dbase = ubik_currentTrans->dbase;
311     DBHOLD(dbase);
312     urecovery_CheckTid(atid);
313     if (!ubik_currentTrans) {
314         DBRELE(dbase);
315         return USYNC;
316     }
317     code = udisk_write(ubik_currentTrans, afile, adata->bulkdata_val, apos, adata->bulkdata_len);
318     DBRELE(dbase);
319     return code;
320 }
321
322 SDISK_Truncate(rxcall, atid, afile, alen)
323     register struct rx_call *rxcall;
324     struct ubik_tid *atid;
325     afs_int32 afile;
326     afs_int32 alen; 
327 {
328     register afs_int32 code;
329     register struct ubik_dbase *dbase;
330
331     if (code = ubik_CheckAuth(rxcall)) {
332       return code;
333     }
334     if (!ubik_currentTrans) { 
335       return USYNC;
336     }
337     /* sanity check to make sure only write trans appear here */
338     if (ubik_currentTrans->type != UBIK_WRITETRANS) {
339       return UBADTYPE;
340     }
341
342     dbase = ubik_currentTrans->dbase;
343     DBHOLD(dbase);
344     urecovery_CheckTid(atid);
345     if (!ubik_currentTrans) {
346         DBRELE(dbase);
347         return USYNC;
348     }
349     code = udisk_truncate(ubik_currentTrans, afile, alen);
350     DBRELE(dbase);
351     return code;
352 }
353
354 SDISK_GetVersion(rxcall, aversion)
355     register struct rx_call *rxcall;
356     register struct ubik_version *aversion; 
357 {
358     register afs_int32 code;
359
360     if (code = ubik_CheckAuth(rxcall)) {
361       return code;
362     }
363
364     /*
365      * If we are the sync site, recovery shouldn't be running on any
366      * other site. We shouldn't be getting this RPC as long as we are
367      * the sync site.  To prevent any unforseen activity, we should
368      * reject this RPC until we have recognized that we are not the
369      * sync site anymore, and/or if we have any pending WRITE
370      * transactions that have to complete. This way we can be assured
371      * that this RPC would not block any pending transactions that
372      * should either fail or pass. If we have recognized the fact that
373      * we are not the sync site any more, all write transactions would
374      * fail with UNOQUORUM anyway.
375      */
376     if (ubeacon_AmSyncSite()) {
377       return UDEADLOCK;
378     }
379
380     DBHOLD(ubik_dbase);
381     code = (*ubik_dbase->getlabel) (ubik_dbase, 0, aversion);
382     DBRELE(ubik_dbase);
383     if (code) {
384         /* tell other side there's no dbase */
385         aversion->epoch = 0;
386         aversion->counter = 0;
387     }
388     return 0;
389 }
390
391 SDISK_GetFile(rxcall, file, version)
392     register struct rx_call *rxcall;
393     register afs_int32 file;
394     struct ubik_version *version;
395 {
396     register afs_int32 code;
397     register struct ubik_dbase *dbase;
398     register afs_int32 offset;
399     struct ubik_stat ubikstat;
400     char tbuffer[256];
401     afs_int32 tlen;
402     afs_int32 length;
403     
404     if (code = ubik_CheckAuth(rxcall)) {
405       return code;
406     }
407 /* temporarily disabled because it causes problems for migration tool.  Hey, it's just
408  * a sanity check, anyway. 
409     if (ubeacon_AmSyncSite()) {
410       return UDEADLOCK;
411     }
412 */
413     dbase = ubik_dbase;
414     DBHOLD(dbase);
415     code = (*dbase->stat) (dbase, file, &ubikstat);
416     if (code < 0) {
417         DBRELE(dbase);
418         return code;
419     }
420     length = ubikstat.size;
421     tlen = htonl(length);
422     code = rx_Write(rxcall, &tlen, sizeof(afs_int32));
423     if (code != sizeof(afs_int32)) {
424         DBRELE(dbase);
425         return BULK_ERROR;
426     }
427     offset = 0;
428     while (length > 0) {
429         tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length);
430         code = (*dbase->read)(dbase, file, tbuffer, offset, tlen);
431         if (code != tlen) {
432             DBRELE(dbase);
433             return UIOERROR;
434         }
435         code = rx_Write(rxcall, tbuffer, tlen);
436         if (code != tlen) {
437             DBRELE(dbase);
438             return BULK_ERROR;
439         }
440         length -= tlen;
441         offset += tlen;
442     }
443     code = (*dbase->getlabel)(dbase, file, version);    /* return the dbase, too */
444     DBRELE(dbase);
445     return code;
446 }
447
448 SDISK_SendFile(rxcall, file, length, avers)
449     register struct rx_call *rxcall;
450     afs_int32 file;
451     afs_int32 length;
452     struct ubik_version *avers;
453 {
454     register afs_int32 code;
455     register struct ubik_dbase *dbase;
456     char tbuffer[256];
457     afs_int32 offset;
458     struct ubik_version tversion;
459     register int tlen;
460     struct rx_peer *tpeer;
461     struct rx_connection *tconn;
462     afs_uint32  otherHost;
463
464     /* send the file back to the requester */
465     
466     if (code = ubik_CheckAuth(rxcall)) {
467       goto failed;
468     }
469
470     /* next, we do a sanity check to see if the guy sending us the database is
471      * the guy we think is the sync site.  It turns out that we might not have
472      * decided yet that someone's the sync site, but they could have enough
473      * votes from others to be sync site anyway, and could send us the database
474      * in advance of getting our votes.  This is fine, what we're really trying
475      * to check is that some authenticated bogon isn't sending a random database
476      * into another configuration.  This could happen on a bad configuration
477      * screwup.  Thus, we only object if we're sure we know who the sync site
478      * is, and it ain't the guy talking to us.
479      */
480     offset = uvote_GetSyncSite();
481     tconn = rx_ConnectionOf(rxcall);
482     tpeer = rx_PeerOf(tconn);
483     otherHost = ubikGetPrimaryInterfaceAddr(rx_HostOf(tpeer));
484     if (offset && offset != otherHost ) {
485                         /* we *know* this is the wrong guy */
486         code = USYNC;
487         goto failed;
488     }
489
490     dbase = ubik_dbase;
491     DBHOLD(dbase);
492
493     /* abort any active trans that may scribble over the database */
494     urecovery_AbortAll(dbase);
495
496     ubik_print("Ubik: Synchronize database with server %s\n",
497                afs_inet_ntoa(otherHost));
498
499     offset = 0;
500     (*dbase->truncate) (dbase, file, 0);                /* truncate first */
501     tversion.epoch = 0; /* start off by labelling in-transit db as invalid */
502     tversion.counter = 0;
503     (*dbase->setlabel) (dbase, file, &tversion);        /* setlabel does sync */
504     while (length > 0) {
505         tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length);
506         code = rx_Read(rxcall, tbuffer, tlen);
507         if (code != tlen) {
508             DBRELE(dbase);
509             code = BULK_ERROR;
510             goto failed;
511         }
512         code = (*dbase->write)(dbase, file, tbuffer, offset, tlen);
513         if (code != tlen) {
514             DBRELE(dbase);
515             code = UIOERROR;
516             goto failed;
517         }
518         offset += tlen;
519         length -= tlen;
520     }
521
522     /* sync data first, then write label and resync (resync done by setlabel call).
523        This way, good label is only on good database. */
524     (*ubik_dbase->sync)(dbase, file);
525     code = (*ubik_dbase->setlabel)(dbase, file, avers);
526     memcpy(&ubik_dbase->version, avers, sizeof(struct ubik_version));
527     udisk_Invalidate(dbase, file); /* new dbase, flush disk buffers */
528     LWP_NoYieldSignal(&dbase->version);
529     DBRELE(dbase);
530 failed:
531     if (code) {
532        ubik_print("Ubik: Synchronize database with server %s failed (error = %d)\n", 
533                   afs_inet_ntoa(otherHost), code);
534     } else {
535        ubik_print("Ubik: Synchronize database completed\n");
536     }
537     return code;
538 }
539
540
541 SDISK_Probe(rxcall)
542     register struct rx_call *rxcall;
543 {
544     return 0;
545 }
546
547 /*
548 * Update remote machines addresses in my server list
549 * Send back my addresses to caller of this RPC
550 * Returns zero on success, else 1.
551 */
552 SDISK_UpdateInterfaceAddr(rxcall, inAddr, outAddr)
553 register struct rx_call *rxcall;
554 UbikInterfaceAddr       *inAddr, *outAddr;
555 {
556     struct ubik_server *ts, *tmp;
557     afs_uint32 remoteAddr;              /* in net byte order */
558     int    i, j, found=0, probableMatch=0;
559
560     /* copy the output parameters */
561     for ( i=0; i < UBIK_MAX_INTERFACE_ADDR; i++)
562         outAddr->hostAddr[i] = ntohl(ubik_host[i]);
563
564     remoteAddr = htonl(inAddr->hostAddr[0]);
565     for(ts = ubik_servers; ts; ts=ts->next)
566         if ( ts->addr[0] == remoteAddr ) /* both in net byte order */
567         {
568             probableMatch = 1;
569             break;
570         }
571
572     if ( probableMatch )                
573     {
574         /* verify that all addresses in the incoming RPC are
575         ** not part of other server entries in my CellServDB
576         */
577         for ( i=0; !found && (i<UBIK_MAX_INTERFACE_ADDR) 
578                                 && inAddr->hostAddr[i]; i++)
579         {
580             remoteAddr = htonl(inAddr->hostAddr[i]);
581             for(tmp = ubik_servers; (!found && tmp); tmp=tmp->next)
582             {
583                 if ( ts == tmp )        /* this is my server */ 
584                         continue;
585                 for ( j=0; (j<UBIK_MAX_INTERFACE_ADDR) && tmp->addr[j]; j++)
586                     if ( remoteAddr == tmp->addr[j] )
587                     {
588                         found = 1;
589                         break;
590                     }
591             }
592         }
593     }           /* if (probableMatch) */
594     
595     /* inconsistent addresses in CellServDB */
596     if ( !probableMatch || found )      
597     {
598         ubik_print("Inconsistent Cell Info from server: ");
599         for ( i=0; i < UBIK_MAX_INTERFACE_ADDR && inAddr->hostAddr[i]; i++)
600             ubik_print("%s ", afs_inet_ntoa(htonl(inAddr->hostAddr[i])));
601         ubik_print("\n");
602         printServerInfo();
603         return UBADHOST;
604     }
605
606     /* update our data structures */
607     for ( i=1; i < UBIK_MAX_INTERFACE_ADDR; i++)
608             ts->addr[i] = htonl(inAddr->hostAddr[i]);
609     
610     ubik_print("ubik: A Remote Server has addresses: ");
611     for ( i=0; i < UBIK_MAX_INTERFACE_ADDR && ts->addr[i]; i++)
612         ubik_print("%s ", afs_inet_ntoa(ts->addr[i]));
613     ubik_print("\n");
614
615     return 0;
616 }
617
618 void
619 printServerInfo()
620 {
621     struct ubik_server *ts;
622     int         i,j=1;
623
624     ubik_print("Local CellServDB:");
625     for ( ts=ubik_servers; ts; ts= ts->next, j++)
626     {
627         ubik_print("Server %d: ", j);
628         for ( i=0; (i<UBIK_MAX_INTERFACE_ADDR) && ts->addr[i]; i++)
629             ubik_print("%s ", afs_inet_ntoa(ts->addr[i]));
630     }
631     ubik_print("\n");
632 }
633
634 SDISK_SetVersion(rxcall, atid, oldversionp, newversionp)
635   struct rx_call      *rxcall;
636   struct ubik_tid     *atid;
637   struct ubik_version *oldversionp; 
638   struct ubik_version *newversionp; 
639 {
640   afs_int32               code=0;
641   struct ubik_dbase   *dbase;
642
643   if (code = ubik_CheckAuth(rxcall)) {
644      return(code);
645   }
646
647   if (!ubik_currentTrans) {
648      return USYNC;
649   }
650   /* sanity check to make sure only write trans appear here */
651   if (ubik_currentTrans->type != UBIK_WRITETRANS) {
652      return UBADTYPE;
653   }
654
655   /* Should not get this for the sync site */
656   if (ubeacon_AmSyncSite()) {
657      return UDEADLOCK;
658   }
659
660   dbase = ubik_currentTrans->dbase;
661   DBHOLD(dbase);
662   urecovery_CheckTid(atid);
663   if (!ubik_currentTrans) {
664      DBRELE(dbase);
665      return USYNC;
666   }
667
668   /* Set the label if its version matches the sync-site's */
669   if ((oldversionp->epoch   == ubik_dbVersion.epoch) &&
670       (oldversionp->counter == ubik_dbVersion.counter)) {
671      code = (*dbase->setlabel) (ubik_dbase, 0, newversionp);
672      if (!code) {
673         ubik_dbase->version = *newversionp;
674         ubik_dbVersion      = *newversionp;
675      }
676   } else {
677      code = USYNC;
678   }
679
680   DBRELE(dbase);
681   return code;
682 }