1 /* BLURB lgpl
2 
3                            Coda File System
4                               Release 5
5 
6           Copyright (c) 1987-1999 Carnegie Mellon University
7                   Additional copyrights listed below
8 
9 This  code  is  distributed "AS IS" without warranty of any kind under
10 the  terms of the  GNU  Library General Public Licence  Version 2,  as
11 shown in the file LICENSE. The technical and financial contributors to
12 Coda are listed in the file CREDITS.
13 
14                         Additional copyrights
15 
16 #*/
17 
18 /*
19                          IBM COPYRIGHT NOTICE
20 
21                           Copyright (C) 1986
22              International Business Machines Corporation
23                          All Rights Reserved
24 
25 This  file  contains  some  code identical to or derived from the 1986
26 version of the Andrew File System ("AFS"), which is owned by  the  IBM
27 Corporation.   This  code is provided "AS IS" and IBM does not warrant
28 that it is free of infringement of  any  intellectual  rights  of  any
29 third  party.    IBM  disclaims  liability of any kind for any damages
30 whatsoever resulting directly or indirectly from use of this  software
31 or  of  any  derivative work.  Carnegie Mellon University has obtained
32 permission to  modify,  distribute and sublicense this code,  which is
33 based on Version 2  of  AFS  and  does  not  contain  the features and
34 enhancements that are part of  Version 3 of  AFS.  Version 3 of AFS is
35 commercially   available   and  supported  by   Transarc  Corporation,
36 Pittsburgh, PA.
37 
38 */
39 
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <sys/time.h>
49 #include <assert.h>
50 #include "rpc2.private.h"
51 
52 
53 /* Routines to allocate and manipulate the doubly-linked circular lists
54 	used elsewhere in rpc2 */
55 
rpc2_Replenish(whichList,whichCount,elemSize,creationCount,magicNumber)56 void rpc2_Replenish(whichList, whichCount, elemSize, creationCount, magicNumber)
57     struct LinkEntry  **whichList;
58     long *whichCount;
59     long elemSize;	/* size of each element in the list */
60     long *creationCount;
61     long magicNumber;
62     /*  Routine to avoid using malloc() too often.
63 	Assumes *whichList is empty and grows it by 1 entry of size elemSize.
64 	Sets *whichCount to 1.
65 	Bumps creationCount by 1.
66     */
67     {
68 
69     *whichList = (struct LinkEntry *)malloc(elemSize);
70     assert(*whichList != NULL);
71     memset(*whichList, 0, elemSize);
72     (*whichList)->NextEntry = (*whichList)->PrevEntry = *whichList; /* 1-element circular list */
73     (*whichList)->MagicNumber = magicNumber;
74     (*whichList)->Qname = whichList;
75     *whichCount = 1;
76     (*creationCount)++;
77     }
78 
79 
80 /* Generic routine to move elements between lists Assumes p points to
81    an entry in the list pointed to by fromPtr.  Moves that entry to
82    the list pointed to by toPtr.  If p is NULL, an arbitrary entry in
83    the from list is selected as a victim and moved.  If toPtr is NULL,
84    the moved entry is made into a singleton list.  In all cases a
85    pointer to the moved entry is returned as the value of the
86    function.
87 
88 	*fromCount is decremented by one.
89 	*toCount is incremented by one.
90 
91    Frequently used routine -- optimize the hell out of it.  */
rpc2_MoveEntry(fromPtr,toPtr,p,fromCount,toCount)92 struct LinkEntry *rpc2_MoveEntry(fromPtr, toPtr, p, fromCount, toCount)
93     /* pointers to header pointers of from and to lists */
94     struct LinkEntry **fromPtr, **toPtr;
95     struct LinkEntry *p;	/* pointer to entry to be moved */
96     long *fromCount;		/* pointer to count of entries in from list */
97     long *toCount;		/* pointer to count of entries in to list */
98 
99 {
100     struct LinkEntry *victim;
101 
102     if (p == NULL)
103 	    victim = *fromPtr;
104     else
105 	    victim = p;
106     assert(victim->Qname == fromPtr);    /* sanity check for list corruption */
107 
108     /* first remove element from the first list */
109     if (victim == *fromPtr)
110 	    *fromPtr = victim->NextEntry;
111 
112     /* remque(victim); */
113     victim->PrevEntry->NextEntry = victim->NextEntry;
114     victim->NextEntry->PrevEntry = victim->PrevEntry;
115     victim->PrevEntry = victim->NextEntry = victim;
116 
117     if (victim == *fromPtr)
118 	    *fromPtr = NULL;
119     (*fromCount)--;
120 
121     /* make victim a singleton list */
122     victim->NextEntry = victim->PrevEntry = victim;
123 
124     /* then insert into second list */
125     if (*toPtr == NULL)
126         *toPtr = victim;
127     else {
128 	/* PrevEntry because semantics of insque() causes non-FIFO queue */
129         /* insque(victim, (*toPtr)->PrevEntry); */
130         victim->PrevEntry = (*toPtr)->PrevEntry;
131         victim->NextEntry = *toPtr;
132         (*toPtr)->PrevEntry->NextEntry = victim;
133         (*toPtr)->PrevEntry = victim;
134     }
135     victim->Qname = toPtr;
136     (*toCount)++;
137     return(victim);
138 }
139 
140 /* Allocates an SL entry and binds it to slConn */
rpc2_AllocSle(enum SL_Type slType,struct CEntry * slConn)141 struct SL_Entry *rpc2_AllocSle(enum SL_Type slType, struct CEntry *slConn)
142 {
143 	struct SL_Entry *sl, **tolist;
144 	long *tocount;
145 
146 	if (rpc2_SLFreeCount == 0)
147 		{
148 			rpc2_Replenish(&rpc2_SLFreeList, &rpc2_SLFreeCount,
149 				       sizeof(struct SL_Entry), &rpc2_SLCreationCount, OBJ_SLENTRY);
150 	}
151 
152     if (slType == REQ)
153 	{
154 	tolist = &rpc2_SLReqList;
155 	tocount = &rpc2_SLReqCount;
156 	}
157     else
158 	{
159 	tolist = &rpc2_SLList;
160 	tocount = &rpc2_SLCount;
161 	}
162 
163     sl = (struct SL_Entry *)rpc2_MoveEntry(&rpc2_SLFreeList,
164 	    tolist, NULL, &rpc2_SLFreeCount, tocount);
165 
166     assert(sl->MagicNumber == OBJ_SLENTRY);
167     sl->Type = slType;
168     if (slType != REQ && slConn != NULL) {
169 	    slConn->MySl = sl;
170 	    sl->Conn = slConn->UniqueCID;
171     }   else
172 	    sl->Conn = 0;
173 
174     return(sl);
175     }
176 
rpc2_FreeSle(INOUT struct SL_Entry ** sl)177 void rpc2_FreeSle(INOUT struct SL_Entry **sl)
178     /* Releases the SL_Entry pointed to by sl. Sets sl to NULL.
179        Removes binding between sl and its connection */
180 {
181     struct SL_Entry *tsl, **fromlist;
182     long *fromcount;
183     struct CEntry *ce;
184 
185     tsl = *sl;
186     assert(tsl->MagicNumber == OBJ_SLENTRY);
187 
188     if (tsl->Conn != 0) {
189 	ce = __rpc2_GetConn(tsl->Conn);
190 	if (ce) ce->MySl = NULL;
191     }
192 
193     if (tsl->Type == REQ) {
194 	fromlist = &rpc2_SLReqList;
195 	fromcount = &rpc2_SLReqCount;
196     } else {
197 	fromlist = &rpc2_SLList;
198 	fromcount = &rpc2_SLCount;
199     }
200 
201     rpc2_MoveEntry(fromlist, &rpc2_SLFreeList, tsl, fromcount, &rpc2_SLFreeCount);
202     *sl = NULL;
203 }
204 
rpc2_ActivateSle(selem,exptime)205 void rpc2_ActivateSle (selem, exptime)
206     struct SL_Entry *selem;
207     struct timeval *exptime;
208     {
209     struct TM_Elem *t, *oldt;
210 
211     assert(selem->MagicNumber == OBJ_SLENTRY);
212     selem->TElem.BackPointer = (char *)selem;
213     selem->ReturnCode = WAITING;
214 
215     t = &selem->TElem;
216 
217     if (exptime == NULL)
218     	{/* infinite timeout, don't add to timer chain */
219 	t->TotalTime.tv_sec = -1;
220 	t->TotalTime.tv_usec = -1;
221 	return;
222 	}
223 
224     t->TotalTime = *exptime; /* structure assignment */
225 
226     oldt = TM_GetEarliest(rpc2_TimerQueue);
227     /* if the new entry expires before any previous timeout, signal the socket
228      * listener to recheck the timerqueue (being able to rely on the
229      * availability of timercmp would be nice) */
230     if (!oldt || oldt->TimeLeft.tv_sec > t->TotalTime.tv_sec ||
231 	(oldt->TimeLeft.tv_sec == t->TotalTime.tv_sec &&
232 	 oldt->TimeLeft.tv_usec > t->TotalTime.tv_usec))
233 	IOMGR_Cancel(rpc2_SocketListenerPID);
234 
235     TM_Insert(rpc2_TimerQueue, t);
236     }
237 
rpc2_DeactivateSle(sl,rc)238 void rpc2_DeactivateSle(sl, rc)
239     struct SL_Entry *sl;
240     enum RetVal rc;
241     {
242     struct timeval *t;
243 
244     assert(sl->MagicNumber == OBJ_SLENTRY);
245 
246     sl->ReturnCode = rc;
247     t = &sl->TElem.TotalTime;
248     if (t->tv_sec == -1 && t->tv_usec == -1) return; /* not timed */
249     else {
250 	TM_Remove(rpc2_TimerQueue, &sl->TElem);
251 	t->tv_sec = t->tv_usec = -1;	/* keep routine idempotent */
252     }
253     }
254 
255 
rpc2_AllocSubsys()256 struct SubsysEntry *rpc2_AllocSubsys()
257     /* Allocates a new subsystem entry and returns a pointer to it.
258     	Returns NULL if unable to allocate such an entry.
259     */
260     {
261     struct SubsysEntry *ss;
262     if (rpc2_SSFreeCount == 0)
263     	rpc2_Replenish(&rpc2_SSFreeList,
264 		&rpc2_SSFreeCount, sizeof(struct SubsysEntry),
265 		&rpc2_SSCreationCount, OBJ_SSENTRY);
266     ss = (struct SubsysEntry *)rpc2_MoveEntry(&rpc2_SSFreeList,
267 	 &rpc2_SSList, NULL, &rpc2_SSFreeCount, &rpc2_SSCount);
268     assert(ss->MagicNumber == OBJ_SSENTRY);
269     return(ss);
270     }
271 
rpc2_FreeSubsys(whichSubsys)272 void rpc2_FreeSubsys(whichSubsys)
273     struct SubsysEntry **whichSubsys;
274     /* Releases the subsystem  entry pointed to by whichSubsys.
275 	Sets whichSubsys to NULL;  */
276 	{
277 	assert((*whichSubsys)->MagicNumber == OBJ_SSENTRY);
278 	rpc2_MoveEntry(&rpc2_SSList, &rpc2_SSFreeList, whichSubsys,
279 		    &rpc2_SSCount, &rpc2_SSFreeCount);
280 	*whichSubsys = NULL;
281 	}
282 
283 
284 
285 /* Moves packet whichPB to hold list from inuse list */
rpc2_HoldPacket(RPC2_PacketBuffer * whichPB)286 void rpc2_HoldPacket(RPC2_PacketBuffer *whichPB)
287 {
288 	assert(whichPB->Prefix.MagicNumber == OBJ_PACKETBUFFER);
289 	rpc2_MoveEntry(&rpc2_PBList, &rpc2_PBHoldList, whichPB,
290 		       &rpc2_PBCount, &rpc2_PBHoldCount);
291 	if (rpc2_HoldHWMark < rpc2_PBHoldCount)
292 		rpc2_HoldHWMark = rpc2_PBHoldCount;
293 }
294 
295 /* Moves packet whichPB to inuse list from hold list */
rpc2_UnholdPacket(RPC2_PacketBuffer * whichPB)296 void rpc2_UnholdPacket(RPC2_PacketBuffer *whichPB)
297 {
298 	assert(whichPB->Prefix.MagicNumber == OBJ_PACKETBUFFER);
299 	rpc2_MoveEntry(&rpc2_PBHoldList, &rpc2_PBList, whichPB,
300 		       &rpc2_PBHoldCount, &rpc2_PBCount);
301 }
302 
303 
304