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