1 /*
2 * atobj-rcvr.cc --
3 *
4 * member functions of
5 * - AtobjRcvr
6 *
7 * Copyright (c) 1997-2002 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * A. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * B. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * C. Neither the names of the copyright holders nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
23 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #ifndef ATOBJ_RCVR_CC
36 #define ATOBJ_RCVR_CC
37
38 #ifndef lint
39 static const char rcsid[] = "$Header: /usr/mash/src/repository/mash/mash-1/atobj/atobj-rcvr.cc,v 1.12 2003/11/19 19:20:14 aswan Exp $";
40 #endif
41
42 #include "mb/mb.h"
43 #include "mb/mb-nethost.h"
44 #include "rtp/inet.h"
45 #include "atobj/atobj-rcvr.h"
46 #include "atobj/atobj-sm.h"
47 #include "misc/str.h"
48
49 class AtobjSM;
50
51 static class AtObjRcvrClass : public TclClass {
52 public:
53 AtObjRcvrClass() : TclClass("Atobj_rcvr") {}
54 TclObject* create(int argc, const char*const* argv);
55 } atobjRcvr_class;
56
57 TclObject* AtObjRcvrClass::create(int argc, const char*const* argv)
58 {
59 // format:
60 // new AtobjRcvr <sess-mgr> [<uid-in-hex> <addr-in-hex>]
61 // (use local addr/getuid() if not specified)
62
63 // REVIEW: Tcl should start arg with 1!
64 const int cTclArgStart = 4; // first argument is at argv[4]
65 if (argc < cTclArgStart+1) {
66 SignalError(("wrong args, usage: new AtobjRcvr"
67 " <sess-mgr> [<uid-in-hex> <addr-in-hex>]"));
68 }
69 AtobjSM* pMgr = (AtobjSM*)TclObject::lookup(argv[cTclArgStart]);
70 SrcId sid;
71 if (argc < cTclArgStart+3) {
72 sid.ss_uid = getuid();
73 sid.ss_addr = LookupLocalAddr();
74 } else {
75 sid.ss_uid = strtoul(argv[cTclArgStart+1], (char **)NULL, 16);
76 sid.ss_addr = strtoul(argv[cTclArgStart+2], (char **)NULL, 16);
77 }
78 return (new AtobjRcvr(pMgr, sid));
79 }
80
81 AtobjRcvr::AtobjRcvr(AtobjSM *pSM, const SrcId& srcId)
82 // REVIEW: what is the use of 'hdrlen' in SRM?
83 : SRM_PacketHandler(0), nextAnmId_(1)
84 {
85 srcId_ = srcId;
86 pMgr_ = pSM;
87 phtAnimations_ = new Tcl_HashTable;
88
89 // the following must be true
90 // otherwise we would use garbage as part of the keys
91 assert( sizeof(AnimationId) == sizeof(char*) );
92 Tcl_InitHashTable(phtAnimations_, TCL_ONE_WORD_KEYS);
93
94 phtRequests_ = new Tcl_HashTable;
95 // keys are pointers
96 Tcl_InitHashTable(phtRequests_, TCL_ONE_WORD_KEYS);
97
98 phtReplies_ = new Tcl_HashTable;
99 // keys are pointers
100 Tcl_InitHashTable(phtReplies_, TCL_ONE_WORD_KEYS);
101 }
102
103 AtobjRcvr::~AtobjRcvr()
104 {
105 Tcl_HashSearch search;
106 Tcl_HashEntry *pEntry = Tcl_FirstHashEntry(phtAnimations_, &search);
107 while (pEntry) {
108 char *szAnmName = (char *)Tcl_GetHashValue(pEntry);
109 Tcl::instance().evalf("delete %s", szAnmName);
110 delete[] szAnmName;
111 pEntry = Tcl_NextHashEntry(&search);
112 }
113 Tcl_DeleteHashTable(phtAnimations_);
114 delete phtAnimations_;
115
116 pEntry = Tcl_FirstHashEntry(phtRequests_, &search);
117 while (pEntry) {
118 Atobj_request* pRequest =
119 (Atobj_request*) Tcl_GetHashValue(pEntry);
120 pRequest->cancel(); // cancel will delete the request
121 pEntry = Tcl_NextHashEntry(&search);
122 }
123 Tcl_DeleteHashTable(phtRequests_);
124 delete phtRequests_;
125
126 pEntry = Tcl_FirstHashEntry(phtReplies_, &search);
127 while (pEntry) {
128 Atobj_reply* pReply =
129 (Atobj_reply*) Tcl_GetHashValue(pEntry);
130 pReply->cancel(); // cancel will delete the reply
131 pEntry = Tcl_NextHashEntry(&search);
132 }
133 Tcl_DeleteHashTable(phtReplies_);
134 delete phtReplies_;
135 }
136
137 /*
138 *----------------------------------------------------------------------
139 *
140 * AtobjRcvr::create_animator --
141 *
142 * Creates a new animation
143 *
144 * Note: called by other member functions, return string will be stored
145 * as part of hash table and deleted at destruction time.
146 *
147 *----------------------------------------------------------------------
148 */
149 char* AtobjRcvr::create_animation(const AnimationId& anmId)
150 {
151 MB_DefTcl(tcl);
152 // REVIEW: figure out dynamic creation of objects with diff. types
153 tcl.evalf("%s new_animation %lu", name(), anmId);
154 char *sz = NULL;
155 ::AllocNCopy(&sz, tcl.result());
156 Trace(VERBOSE, ("new animation returns %s", sz));
157 return sz;
158 }
159
160 /*
161 *----------------------------------------------------------------------
162 *
163 * AtobjRcvr::define_animation --
164 *
165 * Creates an animation if we did not know about it yet, otherwise
166 * create a new one.
167 *
168 *----------------------------------------------------------------------
169 */
170
171 int AtobjRcvr::define_animation(const AnimationId& anmId)
172 {
173 int created;
174 char* szAnim;
175 Tcl_HashEntry *pEntry =
176 Tcl_CreateHashEntry(phtAnimations_, (char*)anmId, &created);
177 if (created) {
178 szAnim = create_animation(anmId);
179 assert(szAnim);
180 Tcl_SetHashValue(pEntry, (ClientData) szAnim);
181 }
182 return created;
183 }
184
185 /*
186 *----------------------------------------------------------------------
187 *
188 * AtobjRcvr::get_animation --
189 *
190 * returns the (tcl) name of an animation given anmId
191 * if animation not found, return NULL
192 *
193 *----------------------------------------------------------------------
194 */
195 const char* AtobjRcvr::get_animation(const AnimationId& anmId)
196 {
197 Tcl_HashEntry *pEntry = Tcl_FindHashEntry(phtAnimations_,
198 (char*)anmId);
199 if (!pEntry) return NULL;
200 else return (char*)Tcl_GetHashValue(pEntry);
201 }
202
203 /*
204 *----------------------------------------------------------------------
205 *
206 * AtobjRcvr::add_animation --
207 *
208 * Adds a new animation given its name, this is appropriate for local
209 * receivers
210 *
211 * szAnim : animation (tcl) name
212 * anmId : Id of the animation that we want to create
213 *
214 *----------------------------------------------------------------------
215 */
216
217 void AtobjRcvr::add_animation(const char* szAnim, const AnimationId& anmId)
218 {
219 int created;
220 Tcl_HashEntry *pEntry =
221 Tcl_CreateHashEntry(phtAnimations_, (char*)anmId, &created);
222
223 assert(created && "animation was added twice?");
224 assert(szAnim && "creating with null animation?");
225 char *szName;
226 ::AllocNCopy(&szName, szAnim);
227 Tcl_SetHashValue(pEntry, (ClientData) szName);
228
229 Tcl& tcl = Tcl::instance();
230 tcl.evalf("%s setAnmId %d", szAnim, anmId);
231 }
232
233 /*
234 *----------------------------------------------------------------------
235 *
236 * AtobjRcvr::next_ADU --
237 *
238 * return the next ADU from a animator
239 *
240 *----------------------------------------------------------------------
241 */
242 /*virtual*/
243 int AtobjRcvr::next_ADU(Byte *pb, int maxPktLen)
244 {
245 char* szADU=NULL;
246 AtoPkt_event* pPkt = (AtoPkt_event*) pb;
247
248 // For now we get data from animations in arbitrary order
249 // REVIEW: obviously we should poll them in a better sequence
250 Tcl& tcl = Tcl::instance();
251 Tcl_HashSearch search;
252 Tcl_HashEntry *pEntry=NULL;
253 for ( pEntry = Tcl_FirstHashEntry(phtAnimations_, &search);
254 pEntry != NULL;
255 pEntry = Tcl_NextHashEntry(&search) ) {
256
257 char *szAnmName = (char *)Tcl_GetHashValue(pEntry);
258 tcl.evalf("%s next_ADU %ld", szAnmName, maxPktLen);
259 szADU = tcl.result();
260 if (szADU[0] != cchNull) {
261 break;
262 }
263 pEntry = Tcl_NextHashEntry(&search);
264 }
265 if (!szADU) return 0;
266
267 AnimationId anmId =
268 (AnimationId) Tcl_GetHashKey(phtAnimations_, pEntry);
269
270 pPkt->pe_anmId = host2net(anmId);
271 // REVIEW: decide where eventids go
272 pPkt->pe_eventId = 0;
273 int strLen = PKT_ROUNDUP(strlen(szADU)+1);
274 pPkt->pe_strLen = host2net(strLen);
275 strcpy(pPkt->pe_achContent, szADU);
276 // zero out the rest of the string
277 for (int i=strlen(szADU); i<strLen; i++) {
278 pPkt->pe_achContent[i] = cchNull;
279 }
280 assert((int)sizeof(AtoPkt_event)+strLen <= maxPktLen);
281 return (sizeof(AtoPkt_event)+strLen);
282 }
283
284
285 /*
286 *----------------------------------------------------------------------
287 *
288 * AtobjRcvr::recv --
289 *
290 * The callback from SRM_PacketHandler
291 *
292 *----------------------------------------------------------------------
293 */
294
295 /*virtual*/
296 #ifdef MB_DEBUG
297 void AtobjRcvr::recv(Byte *pb, u_int len)
298 #else
299 void AtobjRcvr::recv(Byte *pb, u_int /* len */)
300 #endif
301 {
302 AtoPkt_event* pEvent=(AtoPkt_event*) pb;
303 AnimationId anmId = net2host(pEvent->pe_anmId);
304 // EventId evId = net2host(pEvent->pe_anmId);
305 // int len = net2host(pEvent->len);
306 // REVIEW: do something more efficient here
307 MB_DefTcl(tcl);
308 // REVIEW: check the length .... might not be null terminated...
309
310 // create it if not found
311 define_animation(anmId);
312 Trace(VERYVERBOSE, ("received %d bytes", len));
313 const char* szAnim = get_animation(anmId);
314 if (szAnim) {
315 char* szCmd = Concat3(szAnim, " recv_ADU ",
316 pEvent->pe_achContent);
317 tcl.eval(szCmd);
318 delete[] szCmd;
319 } else {
320 Trace(VERBOSE, ("ignoring data"));
321 }
322 }
323
324 /*
325 *----------------------------------------------------------------------
326 *
327 * AtobjRcvr::handleRequest --
328 *
329 * upcall to the animation to handle it
330 *
331 *----------------------------------------------------------------------
332 */
333 void AtobjRcvr::handleRequest(AtoPkt_request *pPkt)
334 {
335 AnimationId anmId = net2host(pPkt->pr_anmId);
336 int isNew = define_animation(anmId);
337 // if this is the first time we see this animation, no point
338 // handing it the request.
339 Tcl& tcl=Tcl::instance();
340 if (!isNew) {
341 const char* szAnim = get_animation(anmId);
342 tcl.evalf("%s handle_request %s", szAnim,
343 pPkt->pr_achContent);
344 }
345 }
346
347 /*
348 *----------------------------------------------------------------------
349 *
350 * AtobjRcvr::schedRequest --
351 *
352 * Creates a request object and schedules it
353 *
354 *----------------------------------------------------------------------
355 */
356 Atobj_request* AtobjRcvr::schedRequest(const AnimationId& anmId)
357 {
358 Atobj_request* pRequest = new Atobj_request(this, anmId);
359 int created;
360 Tcl_HashEntry *pEntry =
361 Tcl_CreateHashEntry(phtRequests_, (char*)pRequest, &created);
362 assert(created && "2 request at the same memory?");
363
364 assert(sizeof(anmId)==sizeof(ClientData));
365 Tcl_SetHashValue(pEntry, (ClientData)anmId);
366
367 pMgr_->schedRequest(pRequest, srcId_);
368 return pRequest;
369 }
370
371 /*
372 *----------------------------------------------------------------------
373 *
374 * AtobjRcvr::updateRequest --
375 *
376 * returns true if request is still needed, false otherwise
377 *
378 *----------------------------------------------------------------------
379 */
380 int AtobjRcvr::updateRequest(Atobj_request* pRequest,
381 const AnimationId& anmId)
382 {
383 const char* szAnmName = get_animation(anmId);
384 Tcl& tcl = Tcl::instance();
385 tcl.evalf("%s update_request %lu", szAnmName, pRequest);
386 int ret;
387 int ok = str2int(tcl.result(), ret);
388 assert(ok && "conversion error!");
389 return (int)ok;
390 }
391
392 /*
393 *----------------------------------------------------------------------
394 *
395 * AtobjRcvr::fillRequest --
396 *
397 * use an upcall to get request
398 *
399 *----------------------------------------------------------------------
400 */
401 u_int AtobjRcvr::fillRequest(Atobj_request* pRequest,
402 const AnimationId& anmId, Byte* pb, int len)
403 {
404 const char* szAnmName = get_animation(anmId);
405 Tcl& tcl = Tcl::instance();
406 tcl.evalf("%s fill_request %lu %d", szAnmName, pRequest,
407 len - sizeof(AtoPkt_request));
408 const char* szResult = tcl.result();
409 if (szResult[0]==cchNull)
410 return 0;
411
412 AtoPkt_request* pPkt = (AtoPkt_request*) pb;
413 host2net(srcId_, pPkt->pr_srcId);
414 Trace(VERYVERBOSE, ("(%x) filling rqt src=%d@%s", this, srcId_.ss_uid,
415 intoa(srcId_.ss_addr)));
416 pPkt->pr_anmId = host2net(anmId);
417
418 int strLen = PKT_ROUNDUP(strlen(szResult)+1);
419 strcpy(pPkt->pr_achContent, szResult);
420 // zero out the rest of the string
421 for (int i=strlen(szResult); i<strLen; i++) {
422 pPkt->pr_achContent[i] = cchNull;
423 }
424 assert((int)sizeof(AtoPkt_request)+strLen < len);
425 return (sizeof(AtoPkt_request)+strLen);
426 }
427
428 /*
429 *----------------------------------------------------------------------
430 *
431 * AtobjRcvr::cancelRequest --
432 *
433 * cancel an request, we notify the animation also in case the
434 * cancellation is due to # requests exceeding cMaxNumRequests
435 *
436 * return false on invalid id's or requests.
437 *
438 *----------------------------------------------------------------------
439 */
440 int AtobjRcvr::cancelRequest(Atobj_request* pRequest,
441 const AnimationId& anmId, int wantCallback)
442 {
443 Tcl_HashEntry *pEntry =
444 Tcl_FindHashEntry(phtRequests_, (char*)pRequest);
445 if (!pEntry) return FALSE;
446
447 if (wantCallback) {
448 const char* szAnmName = get_animation(anmId);
449 if (!szAnmName) return FALSE;
450
451 Tcl& tcl = Tcl::instance();
452 tcl.evalf("%s cancel_request %lu", szAnmName, (u_int)pRequest);
453 }
454
455 assert(pEntry && "cannot find request!");
456 Tcl_DeleteHashEntry(pEntry);
457 pRequest->cancel();
458 return TRUE;
459 }
460
461
462 /*
463 *----------------------------------------------------------------------
464 *
465 * AtobjRcvr::cancelReply --
466 *
467 * use an upcall to get an reply
468 *
469 * return false on invalid id's or requests.
470 *----------------------------------------------------------------------
471 */
472 int AtobjRcvr::cancelReply(Atobj_reply* pReply, const AnimationId& anmId)
473 {
474 Tcl_HashEntry *pEntry =
475 Tcl_FindHashEntry(phtReplies_, (char*)pReply);
476 if (!pEntry) return FALSE;
477
478 const char* szAnmName = get_animation(anmId);
479 if (!szAnmName) return FALSE;
480
481 Tcl& tcl = Tcl::instance();
482 tcl.evalf("%s cancel_reply %lu", szAnmName, (u_int)pReply);
483
484 assert(pEntry && "cannot find reply!");
485 Tcl_DeleteHashEntry(pEntry);
486 pReply->cancel();
487 return TRUE;
488 }
489
490
491 /*
492 *----------------------------------------------------------------------
493 *
494 * AtobjRcvr::schedReply --
495 *
496 * Creates a reply object and schedules it
497 *
498 *----------------------------------------------------------------------
499 */
500 Atobj_reply* AtobjRcvr::schedReply(const AnimationId& anmId)
501 {
502 Atobj_reply* pReply = new Atobj_reply(this, anmId);
503 int created;
504 Tcl_HashEntry *pEntry =
505 Tcl_CreateHashEntry(phtReplies_, (char*)pReply, &created);
506 assert(created && "2 reply at the same memory?");
507
508 assert(sizeof(anmId)==sizeof(ClientData));
509 Tcl_SetHashValue(pEntry, (ClientData)anmId);
510 pMgr_->schedReply(pReply, srcId_);
511
512 return pReply;
513 }
514
515
516 /*
517 *----------------------------------------------------------------------
518 *
519 * AtobjRcvr::handleReply --
520 *
521 * upcall to the animation to handle it
522 *
523 *----------------------------------------------------------------------
524 */
525 void AtobjRcvr::handleReply(AtoPkt_reply *pPkt)
526 {
527 AnimationId anmId = net2host(pPkt->pr_anmId);
528 define_animation(anmId);
529
530 const char* szAnim = get_animation(anmId);
531 char* szCmd=Concat3(szAnim, " handle_reply ", pPkt->pr_achContent);
532 Tcl::instance().eval(szCmd);
533 delete[] szCmd;
534 }
535
536 /*
537 *----------------------------------------------------------------------
538 *
539 * AtobjRcvr::fillReply --
540 *
541 * use an upcall to get an reply
542 *
543 *----------------------------------------------------------------------
544 */
545 u_int AtobjRcvr::fillReply(Atobj_reply* pReply,
546 const AnimationId& anmId, Byte* pb, int len)
547 {
548 const char* szAnmName = get_animation(anmId);
549 Tcl& tcl = Tcl::instance();
550 // -8 so that the rounding up is being taken care of
551 // REVIEW: less than -8 ?
552 tcl.evalf("%s fill_reply %lu %d", szAnmName, pReply,
553 len - sizeof(AtoPkt_reply)- 6);
554 const char* szResult = tcl.result();
555
556 if (szResult[0]==cchNull)
557 return 0;
558
559 AtoPkt_reply* pPkt = (AtoPkt_reply*) pb;
560 host2net(srcId_, pPkt->pr_srcId);
561 pPkt->pr_anmId = host2net(anmId);
562
563 int strLen = PKT_ROUNDUP(strlen(szResult)+1);
564 strcpy(pPkt->pr_achContent, szResult);
565 // zero out the rest of the string
566 for (int i=strlen(szResult); i<strLen; i++) {
567 pPkt->pr_achContent[i] = cchNull;
568 }
569 assert((int)sizeof(AtoPkt_reply) + strLen < len);
570 return (sizeof(AtoPkt_reply) + strLen);
571 }
572
573 /*
574 *----------------------------------------------------------------------
575 *
576 * AtobjRcvr::fillSA --
577 *
578 *----------------------------------------------------------------------
579 */
580 u_int AtobjRcvr::fillSA(Byte* pb)
581 {
582 /* REVIEW: modify this to take multiple animations */
583 Tcl_HashSearch hs;
584 Tcl_HashEntry *pEntry = Tcl_FirstHashEntry(phtAnimations_, &hs);
585 if (!pEntry) {
586 bzero(pb, sizeof(AtoPkt_SA));
587 return sizeof(AtoPkt_SA); // nothing
588 }
589
590 const char* szAnmName = (char*) Tcl_GetHashValue(pEntry);
591 AnimationId anmId =
592 (AnimationId) Tcl_GetHashKey(phtAnimations_, pEntry);
593 /* REVIEW: get the size right! */
594 Tcl& tcl = Tcl::instance();
595 tcl.evalf("%s fill_sa", szAnmName);
596 const char* szResult = tcl.result();
597 if (szResult[0]==cchNull) return 0;
598
599 AtoPkt_SA *pSA = (AtoPkt_SA *)pb;
600 host2net(srcId_, pSA->sa_srcId);
601 pSA->sa_anmId = host2net(anmId);
602 int strLen = PKT_ROUNDUP(strlen(szResult)+1);
603 strcpy(pSA->sa_achSA, szResult);
604 // zero out the rest of the string
605 for (int i=strlen(szResult); i<strLen; i++) {
606 pSA->sa_achSA[i] = cchNull;
607 }
608 assert(sizeof(AtoPkt_SA) + strLen < SRM_MTU);
609 return (sizeof(AtoPkt_SA) + strLen);
610 }
611
612
613 /*
614 *----------------------------------------------------------------------
615 *
616 * AtobjRcvr::handleSA --
617 *
618 *----------------------------------------------------------------------
619 */
620 void AtobjRcvr::handleSA(AtoPkt_SA* pSA)
621 {
622 AnimationId anmId = net2host(pSA->sa_anmId);
623 MB_DefTcl(tcl);
624 define_animation(anmId);
625 const char* szAnim = get_animation(anmId);
626 if (szAnim) {
627 char* szCmd = Concat3(szAnim, " handle_sa ",
628 pSA->sa_achSA);
629 tcl.eval(szCmd);
630 delete[] szCmd;
631 } else {
632 Trace(VERBOSE, ("ignoring data"));
633 }
634 }
635
636
637 /*virtual*/
638 int AtobjRcvr::command(int argc, const char*const* argv)
639 {
640 const char* cszUsage =
641 "wrong usage, should be: \n"
642 "$atobjRcvr begin_xmit len\n"
643 " add_animation anm_name [id]\n"
644 " sched_request anmId\n"
645 " sched_reply anmId\n"
646 " backoff_request reqId\n"
647 " cancel_request reqId anmId wantCallback\n"
648 " cancel_reply replyId anmId\n";
649 int len;
650
651 Tcl& tcl=Tcl::instance();
652 if (!strcmp(argv[1], "begin_xmit") && argc==3) {
653 if (str2int(argv[2], len)) {
654 len = PKT_ROUNDUP(len+1);
655 len += sizeof(AtoPkt_event);
656 pMgr_->begin_xmit(len);
657 } else {
658 goto err;
659 }
660 } else if (!strcmp(argv[1], "add_animation") && argc>=3) {
661 int id;
662 if (argc==4) {
663 if (!str2int(argv[3], id))
664 goto err;
665 }
666 id = nextAnmId_++;
667 add_animation(argv[2], id);
668 } else if (!strcmp(argv[1], "sched_request") && argc==3) {
669 int id;
670 if (!str2int(argv[2], id)) goto err;
671 Atobj_request* pRequest = schedRequest(id);
672 tcl.resultf("%lu", (u_int)pRequest);
673 } else if (!strcmp(argv[1], "backoff_request") && argc==3) {
674 int p;
675 if (!str2int(argv[2], p)) goto err;
676 Atobj_request* pRequest=(Atobj_request*)p;
677 pRequest->backoff();
678 } else if (!strcmp(argv[1], "cancel_request") && argc==5) {
679 int p, anmId, wantCallback;
680 if (!str2int(argv[2], p)) goto err;
681 Atobj_request* pRequest=(Atobj_request*)p;
682 if (!str2int(argv[3], anmId)) goto err;
683 if (!str2int(argv[4], wantCallback)) goto err;
684 if (!cancelRequest(pRequest, anmId, wantCallback)) {
685 Tcl_AddErrorInfo(tcl.interp(),
686 "cancel request failed");
687 return TCL_ERROR;
688 }
689 } else if (!strcmp(argv[1], "sched_reply") && argc==3) {
690 int id;
691 if (!str2int(argv[2], id)) goto err;
692 Atobj_reply* pReply = schedReply(id);
693 tcl.resultf("%lu", (u_int)pReply);
694 } else if (!strcmp(argv[1], "cancel_reply") && argc==4) {
695 int p, anmId;
696 if (!str2int(argv[2], p)) goto err;
697 Atobj_reply* pReply=(Atobj_reply*)p;
698 if (!str2int(argv[3], anmId)) goto err;
699 if (!cancelReply(pReply, anmId)) {
700 Tcl_AddErrorInfo(tcl.interp(),
701 "cancel reply failed");
702 return TCL_ERROR;
703 }
704 } else {
705 goto err;
706 }
707 return TCL_OK;
708
709 err:
710 // invalid parameter
711 Tcl_AddErrorInfo(tcl.interp(), (char *)cszUsage);
712 return TCL_ERROR;
713 }
714
715
716 #endif /* #ifdef ATOBJ_RCVR_CC */
717
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.