getopt.c


/* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* #if !defined(lint) * static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94"; * #endif */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* declarations to provide consistent linkage */ extern char *optarg; extern int optind; extern int opterr; int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (EOF); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return (EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means EOF. */ if (optopt == (int)'-') return (EOF); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __FILE__, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __FILE__, optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ }

tkUnixInit.c


#ifdef WIN32 #include <windows.h> #endif #include <tcl.h> #include <tk.h> #include <string.h> int #if (TK_MAJOR_VERSION < 8) TkPlatformInit(Tcl_Interp *interp) #else TkpInit(Tcl_Interp *interp) #endif { Tcl_SetVar(interp, "tk_library", ".", TCL_GLOBAL_ONLY); #ifndef WIN32 { extern void TkCreateXEventSource(void); TkCreateXEventSource(); } #endif return (TCL_OK); } #if (TK_MAJOR_VERSION == 8) void TkpGetAppName(Tcl_Interp* interp, Tcl_DString* namePtr) { char *p, *name; #ifdef WIN32 int argc; char** argv; #endif name = Tcl_GetVar(interp, "argv0", TCL_GLOBAL_ONLY); #ifdef WIN32 if (name != NULL) { Tcl_SplitPath(name, &argc, &argv); if (argc > 0) { name = argv[argc-1]; p = strrchr(name, '.'); if (p != NULL) { *p = '\0'; } } else { name = NULL; } } #endif if ((name == NULL) || (*name == 0)) { name = "tk"; } #ifndef WIN32 else { p = strrchr(name, '/'); if (p != NULL) { name = p+1; } } #endif Tcl_DStringAppend(namePtr, name, -1); #ifdef WIN32 if (argv != NULL) { ckfree((char *)argv); } #endif } void TkpDisplayWarning(char* msg, char* title) { #ifdef WIN32 MessageBox(NULL, msg, title, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL | MB_SETFOREGROUND | MB_TOPMOST); #else Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel) { Tcl_Write(errChannel, title, -1); Tcl_Write(errChannel, ": ", 2); Tcl_Write(errChannel, msg, -1); Tcl_Write(errChannel, "\n", 1); } #endif } #endif

tkcompat.c


/* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * ------------------------------- * * Filename: tkcompat.c * * Description: * These are functions that are required for compiling with previous * versions of tcl or tk. * * @(#) $Header$ */ #ifndef TKCOMPAT_C #define TKCOMPAT_C #include "tk.h" #if TK_MAJOR_VERSION < 8 #include "tkcompat.h" /* *--------------------------------------------------------------------------- * * Tk_GetFontMetrics -- * * Returns overall ascent and descent metrics for the given font. * These values can be used to space multiple lines of text and * to align the baselines of text in different fonts. * */ void Tk_GetFontMetrics(Tk_Font pf, Tk_FontMetrics *fmPtr) { fmPtr->ascent = pf->ascent; fmPtr->descent = pf->descent; fmPtr->linespace = pf->ascent + pf->descent; } #endif /* (TK_MAJOR_VERSION < 8) */ #endif /* #ifdef TKCOMPAT_C */

win32.c


/* * Copyright (c) 1996 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Network Research * Group at Lawrence Berkeley National Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This module contributed by John Brezak <brezak@apollo.hp.com>. * January 31, 1996 */ #ifndef lint static char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include <assert.h> #include <io.h> #include <process.h> #include <fcntl.h> #include <windows.h> #include <malloc.h> #include <string.h> #include <stdio.h> #include <time.h> #include <winsock.h> #include <tk.h> #include <locale.h> /* forward declarations */ int WinGetUserName(ClientData, Tcl_Interp*, int ac, char**av); int WinGetHostName(ClientData, Tcl_Interp*, int ac, char**av); int WinPutRegistry(ClientData, Tcl_Interp*, int ac, char**av); int WinGetRegistry(ClientData, Tcl_Interp*, int ac, char**av); int WinExit(ClientData, Tcl_Interp*, int ac, char**av); void TkConsoleCreate(); int TkConsoleInit(Tcl_Interp* interp); #ifdef STATIC_TCLTK extern HINSTANCE Tk_GetHINSTANCE(); extern BOOL APIENTRY Tk_LibMain(HINSTANCE hInstance,DWORD reason,LPVOID reserved); extern BOOL APIENTRY Tcl_LibMain(HINSTANCE hInstance,DWORD reason,LPVOID reserved); void static_exit(void){ HINSTANCE hInstance = Tk_GetHINSTANCE(); Tcl_LibMain(hInstance, DLL_PROCESS_DETACH, NULL); Tk_LibMain(hInstance, DLL_PROCESS_DETACH, NULL); } #endif int strcasecmp(const char *s1, const char *s2) { return stricmp(s1, s2); } extern void TkWinXInit(HINSTANCE hInstance); extern int main(int argc, const char *argv[]); #ifndef STATIC_TCLTK extern int __argc; extern char **__argv; #endif static char argv0[255]; /* Buffer used to hold argv0. */ char *__progname = "nam"; void ShowMessage(int level, char *msg) { MessageBeep(level); MessageBox(NULL, msg, __progname, level | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); } int SetupConsole() { // stuff from knowledge base Q105305 (see that for details) // open a console and do the work around to get the console to work in all // cases int hCrt; FILE *hf=0; const COORD screenSz = {80, 2000}; /* size of console buffer */ AllocConsole(); hf=0; hCrt = _open_osfhandle( (long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); if (hCrt!=-1) hf = _fdopen(hCrt, "w"); if (hf!=0) *stdout = *hf; if (hCrt==-1 || hf==0 || 0!=setvbuf(stdout, NULL, _IONBF, 0)) { ShowMessage(MB_ICONINFORMATION, "unable to reroute stdout"); return FALSE; } SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), screenSz); hf=0; hCrt = _open_osfhandle( (long)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT); if (hCrt!=-1) hf = _fdopen(hCrt, "w"); if (hf!=0) *stderr = *hf; if (hCrt==-1 || hf==0 || 0!=setvbuf(stderr, NULL, _IONBF, 0)) { ShowMessage(MB_ICONINFORMATION, "reroute stderr failed in SetupConsole"); return FALSE; } hf=0; hCrt = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT); if (hCrt!=-1) hf = _fdopen(hCrt, "r"); if (hf!=0) *stdin = *hf; if (hCrt==-1 || hf==0 || 0!=setvbuf(stdin, NULL, _IONBF, 0)) { ShowMessage(MB_ICONINFORMATION, "reroute stdin failed in SetupConsole"); return FALSE; } return TRUE; } int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { char *p; WSADATA WSAdata; int retcode; #ifdef STATIC_TCLTK Tcl_LibMain(hInstance, DLL_PROCESS_ATTACH, NULL); Tk_LibMain(hInstance, DLL_PROCESS_ATTACH, NULL); atexit(static_exit); #endif setlocale(LC_ALL, "C"); /* XXX * initialize our socket interface plus the tcl 7.5 socket * interface (since they redefine some routines we call). * eventually we should just call the tcl sockets but at * the moment that's hard to set up since they only support * tcp in the notifier. */ if (WSAStartup(MAKEWORD (1, 1), &WSAdata)) { perror("Windows Sockets init failed"); abort(); } /* TclHasSockets(NULL); TkWinXInit(hInstance); */ /* * Increase the application queue size from default value of 8. * At the default value, cross application SendMessage of WM_KILLFOCUS * will fail because the handler will not be able to do a PostMessage! * This is only needed for Windows 3.x, since NT dynamically expands * the queue. */ SetMessageQueue(64); GetModuleFileName(NULL, argv0, 255); p = argv0; __progname = strrchr(p, '/'); if (__progname != NULL) { __progname++; } else { __progname = strrchr(p, '\\'); if (__progname != NULL) { __progname++; } else { __progname = p; } } if (__argc>1) { SetupConsole(); } retcode=main(__argc, (const char**)__argv); if (retcode!=0) { assert(FALSE); // don't die without letting user know why } return retcode; } static char szTemp[4096]; int outputErr(const char* szPrefix, Tcl_Interp* interp) { char *szError=Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); int l = strlen(szPrefix) + strlen(interp->result) + 2 + strlen(szError) + 1; char* szMsg = szTemp; if (l>4096) szMsg = (char*)malloc(l*sizeof(char)); strcpy(szMsg, szPrefix); // strcat(szMsg, interp->result); strcat(szMsg, "\n"); strcat(szMsg, szError); OutputDebugString(szMsg); ShowMessage(MB_ICONERROR, szMsg); assert(FALSE); if (szMsg != szTemp) free(szMsg); return 0; } void win_perror(const char *msg) { DWORD cMsgLen; CHAR *msgBuf; DWORD dwError = GetLastError(); cMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, NULL, dwError, MAKELANGID(0, SUBLANG_ENGLISH_US), (LPTSTR) &msgBuf, 512, NULL); if (!cMsgLen) fprintf(stderr, "%s%sError code %lu\n", msg?msg:"", msg?": ":"", dwError); else { fprintf(stderr, "%s%s%s\n", msg?msg:"", msg?": ":"", msgBuf); LocalFree((HLOCAL)msgBuf); } } #if 0 static char szTemp[4096]; int printf(const char *fmt, ...) { int retval; va_list ap; va_start (ap, fmt); retval = vsprintf(szTemp, fmt, ap); OutputDebugString(szTemp); ShowMessage(MB_ICONINFORMATION, szTemp); va_end (ap); return(retval); } int fprintf(FILE *f, const char *fmt, ...) { int retval; va_list ap; va_start (ap, fmt); if (f == stderr) { retval = vsprintf(szTemp, fmt, ap); OutputDebugString(szTemp); ShowMessage(MB_ICONERROR, szTemp); va_end (ap); } else retval = vfprintf(f, fmt, ap); return(retval); } void perror(const char *msg) { DWORD cMsgLen; CHAR *msgBuf; DWORD dwError = GetLastError(); cMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, NULL, dwError, MAKELANGID(0, SUBLANG_ENGLISH_US), (LPTSTR) &msgBuf, 512, NULL); if (!cMsgLen) fprintf(stderr, "%s%sError code %lu\n", msg?msg:"", msg?": ":"", dwError); else { fprintf(stderr, "%s%s%s\n", msg?msg:"", msg?": ":"", msgBuf); LocalFree((HLOCAL)msgBuf); } } int WinPutsCmd(clientData, interp, argc, argv) ClientData clientData; /* ConsoleInfo pointer. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { int i, newline; char *fileId; i = 1; newline = 1; if ((argc >= 2) && (strcmp(argv[1], "-nonewline") == 0)) { newline = 0; i++; } if ((i < (argc-3)) || (i >= argc)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?-nonewline? ?fileId? string\"", (char *) NULL); return TCL_ERROR; } /* * The code below provides backwards compatibility with an old * form of the command that is no longer recommended or documented. */ if (i == (argc-3)) { if (strncmp(argv[i+2], "nonewline", strlen(argv[i+2])) != 0) { Tcl_AppendResult(interp, "bad argument \"", argv[i+2], "\": should be \"nonewline\"", (char *) NULL); return TCL_ERROR; } newline = 0; } if (i == (argc-1)) { fileId = "stdout"; } else { fileId = argv[i]; i++; } if (strcmp(fileId, "stdout") == 0 || strcmp(fileId, "stderr") == 0) { char *result; int level; if (newline) { int len = strlen(argv[i]); result = ckalloc(len+2); memcpy(result, argv[i], len); result[len] = '\n'; result[len+1] = 0; } else { result = argv[i]; } if (strcmp(fileId, "stdout") == 0) { level = MB_ICONINFORMATION; } else { level = MB_ICONERROR; } OutputDebugString(result); ShowMessage(level, result); if (newline) ckfree(result); return TCL_OK; } else { extern int Tcl_PutsCmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv); return (Tcl_PutsCmd(clientData, interp, argc, argv)); } } #endif int WinGetUserName(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char *argv[]; /* Argument strings. */ { char user[256]; int size = sizeof(user); if (!GetUserName(user, &size)) { Tcl_AppendResult(interp, "GetUserName failed", NULL); return TCL_ERROR; } Tcl_AppendResult(interp, user, NULL); return TCL_OK; } int WinGetHostName(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char *argv[]; /* Argument strings. */ { char hostname[MAXGETHOSTSTRUCT]; if (SOCKET_ERROR == gethostname(hostname, MAXGETHOSTSTRUCT)) { Tcl_AddErrorInfo(interp, "gethostname failed!"); } Tcl_AppendResult(interp, hostname, NULL); return TCL_OK; } static HKEY regroot(root) char *root; { if (strcasecmp(root, "HKEY_LOCAL_MACHINE") == 0) return HKEY_LOCAL_MACHINE; else if (strcasecmp(root, "HKEY_CURRENT_USER") == 0) return HKEY_CURRENT_USER; else if (strcasecmp(root, "HKEY_USERS") == 0) return HKEY_USERS; else if (strcasecmp(root, "HKEY_CLASSES_ROOT") == 0) return HKEY_CLASSES_ROOT; else return NULL; } int WinGetRegistry(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { HKEY hKey, hRootKey; DWORD dwType; DWORD len, retCode; CHAR *regRoot, *regPath, *keyValue, *keyData; int retval = TCL_ERROR; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], "key value\"", (char *) NULL); return TCL_ERROR; } regRoot = argv[1]; keyValue = argv[2]; regPath = strchr(regRoot, '\\'); *regPath++ = '\0'; if ((hRootKey = regroot(regRoot)) == NULL) { Tcl_AppendResult(interp, "Unknown registry root \"", regRoot, "\"", NULL); return (TCL_ERROR); } retCode = RegOpenKeyEx(hRootKey, regPath, 0, KEY_READ, &hKey); if (retCode == ERROR_SUCCESS) { retCode = RegQueryValueEx(hKey, keyValue, NULL, &dwType, NULL, &len); if (retCode == ERROR_SUCCESS && dwType == REG_SZ && len) { keyData = (CHAR *) ckalloc(len); retCode = RegQueryValueEx(hKey, keyValue, NULL, NULL, keyData, &len); if (retCode == ERROR_SUCCESS) { Tcl_AppendResult(interp, keyData, NULL); free(keyData); retval = TCL_OK; } } RegCloseKey(hKey); } if (retval == TCL_ERROR) { Tcl_AppendResult(interp, "Cannot find registry entry \"", regRoot, "\\", regPath, "\\", keyValue, "\"", NULL); } return (retval); } int WinPutRegistry(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { HKEY hKey, hRootKey; DWORD retCode; CHAR *regRoot, *regPath, *keyValue, *keyData; DWORD new; int result = TCL_OK; if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], "key value data\"", (char *) NULL); return TCL_ERROR; } regRoot = argv[1]; keyValue = argv[2]; keyData = argv[3]; regPath = strchr(regRoot, '\\'); *regPath++ = '\0'; if ((hRootKey = regroot(regRoot)) == NULL) { Tcl_AppendResult(interp, "Unknown registry root \"", regRoot, "\"", NULL); return (TCL_ERROR); } retCode = RegCreateKeyEx(hRootKey, regPath, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &new); if (retCode == ERROR_SUCCESS) { retCode = RegSetValueEx(hKey, keyValue, 0, REG_SZ, keyData, strlen(keyData)); if (retCode != ERROR_SUCCESS) { Tcl_AppendResult(interp, "unable to set key \"", regRoot, "\\", regPath, "\" with value \"", keyValue, "\"", (char *) NULL); result = TCL_ERROR; } RegCloseKey(hKey); } else { Tcl_AppendResult(interp, "unable to create key \"", regRoot, "\\", regPath, "\"", (char *) NULL); result = TCL_ERROR; } return (result); } /* does everything the normal exit command does, but shows a dialog box if * there is an error so that the console does not vaporize */ int WinExit(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; { int value; char buffer[100]; if ((argc != 1) && (argc != 2)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?returnCode?\"", (char *) NULL); return TCL_ERROR; } if (argc == 1) { value = 0; } else if (Tcl_GetInt(interp, argv[1], &value) != TCL_OK) { return TCL_ERROR; } /* all the error information should be in the console, so just * show the message and wait for user input */ if (value != 0) { ShowMessage(MB_ICONERROR, "Application exiting with error!"); } /* call the usual (renamed) tcl exit command */ sprintf(buffer, "tcl_exit %d", value); Tcl_Eval(interp, buffer); /*NOTREACHED*/ return TCL_OK; } static char initScript[]= "proc init {} {\n\ global tcl_library tcl_platform tcl_version tcl_patchLevel env errorInfo\n\ global tcl_pkgPath\n\ rename init {}\n\ set errors {}\n\ proc tcl_envTraceProc {lo n1 n2 op} {\n\ global env\n\ set x $env($n2)\n\ set env($lo) $x\n\ set env([string toupper $lo]) $x\n\ }\n\ foreach p [array names env] {\n\ set u [string toupper $p]\n\ if {$u != $p} {\n\ switch -- $u {\n\ COMSPEC -\n\ PATH {\n\ if {![info exists env($u)]} {\n\ set env($u) $env($p)\n\ }\n\ trace variable env($p) w [list tcl_envTraceProc $p]\n\ trace variable env($u) w [list tcl_envTraceProc $p]\n\ }\n\ }\n\ }\n\ }\n\ if {![info exists env(COMSPEC)]} {\n\ if {$tcl_platform(os) == {Windows NT}} {\n\ set env(COMSPEC) cmd.exe\n\ } else {\n\ set env(COMSPEC) command.com\n\ }\n\ } \n\ }\n\ init\n"; int platformInit(Tcl_Interp* interp) { /* tcl.CreateCommand("puts", WinPutsCmd, (ClientData)0); */ Tcl_CreateCommand(interp, "getusername", WinGetUserName, (ClientData)0, (Tcl_CmdDeleteProc*)0); Tcl_CreateCommand(interp, "gethostname", WinGetHostName, (ClientData)0, (Tcl_CmdDeleteProc*)0); Tcl_CreateCommand(interp, "putregistry", WinPutRegistry, (ClientData)0, (Tcl_CmdDeleteProc*)0); Tcl_CreateCommand(interp, "getregistry", WinGetRegistry, (ClientData)0, (Tcl_CmdDeleteProc*)0); Tcl_Eval(interp, initScript); if (TCL_OK==Tcl_Eval(interp, "rename exit tcl_exit")) { Tcl_CreateCommand(interp, "exit", WinExit, (ClientData)0, (Tcl_CmdDeleteProc*)0); } else { fprintf(stderr, "rename of exit proc failed!"); } #if 0 /* * Initialize the console only if we are running as an interactive * application. */ { char* interactive; if ((interactive=Tcl_GetVar(interp, "tcl_interactive", TCL_GLOBAL_ONLY)) && !strcmp(interactive, "1")) { /* * Create the console channels and install them as the standard * channels. All I/O will be discarded until TkConsoleInit is * called to attach the console to a text widget. */ TkConsoleCreate(); if (TkConsoleInit(interp) == TCL_ERROR) { fprintf(stderr, "error calling TkConsoleInit\n"); } } } #endif return TCL_OK; }

xwd.c


/* * Stolen from X11R6's xwd.c * $XConsortium: xwd.c /main/64 1996/01/14 16:53:13 kaleb $ * by John Heidemann, 15-Dec-97. */ /* Copyright (c) 1987 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ /* * xwd.c MIT Project Athena, X Window system window raster image dumper. * * This program will dump a raster image of the contents of a window into a * file for output on graphics printers or for other uses. * * Author: Tony Della Fera, DEC * 17-Jun-85 * * Modification history: * * 11/14/86 Bill Wyatt, Smithsonian Astrophysical Observatory * - Removed Z format option, changing it to an XY option. Monochrome * windows will always dump in XY format. Color windows will dump * in Z format by default, but can be dumped in XY format with the * -xy option. * * 11/18/86 Bill Wyatt * - VERSION 6 is same as version 5 for monchrome. For colors, the * appropriate number of Color structs are dumped after the header, * which has the number of colors (=0 for monochrome) in place of the * V5 padding at the end. Up to 16-bit displays are supported. I * don't yet know how 24- to 32-bit displays will be handled under * the Version 11 protocol. * * 6/15/87 David Krikorian, MIT Project Athena * - VERSION 7 runs under the X Version 11 servers, while the previous * versions of xwd were are for X Version 10. This version is based * on xwd version 6, and should eventually have the same color * abilities. (Xwd V7 has yet to be tested on a color machine, so * all color-related code is commented out until color support * becomes practical.) */ /*% *% This is the format for commenting out color-related code until *% color can be supported. %*/ #include <stdio.h> #include <errno.h> #include <tk.h> #include <X11/Xos.h> #ifdef X_NOT_STDC_ENV extern int errno; #endif #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xmu/WinUtil.h> typedef unsigned long Pixel; /* Use our own... */ #include "XWDFile.h" /* * work-around solaris 2.6 problem: * SIZEOF is defined in Xmd.h, which is included by XWDFile.h * make sure we get the right (ansi) definition). */ #if defined(sun) && defined(__svr4__) #undef SIZEOF #define SIZEOF(x) sz_##x #endif /* work-around solaris 2.6 problem */ #ifndef SIZEOF #define SIZEOF(x) sz_##x #endif /* * Window_Dump: dump a window to a file which must already be open for * writting. */ static void outl(char *s) { } /* * Determine the pixmap size. */ static int Image_Size(image) XImage *image; { if (image->format != ZPixmap) return(image->bytes_per_line * image->height * image->depth); return(image->bytes_per_line * image->height); } #define lowbit(x) ((x) & (~(x) + 1)) static int ReadColors(tk,cmap,colors) Colormap cmap ; XColor **colors ; { Visual *vis = Tk_Visual(tk); int i,ncolors ; ncolors = vis->map_entries; if (!(*colors = (XColor *) Tcl_Alloc (sizeof(XColor) * ncolors))) { outl("Out of memory!"); exit(1); } if (vis->class == DirectColor || vis->class == TrueColor) { Pixel red, green, blue, red1, green1, blue1; red = green = blue = 0; red1 = lowbit(vis->red_mask); green1 = lowbit(vis->green_mask); blue1 = lowbit(vis->blue_mask); for (i=0; i<ncolors; i++) { (*colors)[i].pixel = red|green|blue; (*colors)[i].pad = 0; red += red1; if (red > vis->red_mask) red = 0; green += green1; if (green > vis->green_mask) green = 0; blue += blue1; if (blue > vis->blue_mask) blue = 0; } } else { for (i=0; i<ncolors; i++) { (*colors)[i].pixel = i; (*colors)[i].pad = 0; } } XQueryColors(Tk_Display(tk), cmap, *colors, ncolors); return(ncolors); } /* * Get the XColors of all pixels in image - returns # of colors */ static int Get_XColors(tk, colors) Tk_Window tk; XColor **colors; { int ncolors; Colormap cmap = Tk_Colormap(tk); #if 0 if (use_installed) /* assume the visual will be OK ... */ cmap = XListInstalledColormaps(dpy, win_info->root, &i)[0]; #endif 0 if (!cmap) return(0); ncolors = ReadColors(tk,cmap,colors) ; return ncolors ; } static void _swapshort (bp, n) register char *bp; register unsigned n; { register char c; register char *ep = bp + n; while (bp < ep) { c = *bp; *bp = *(bp + 1); bp++; *bp++ = c; } } static void _swaplong (bp, n) register char *bp; register unsigned n; { register char c; register char *ep = bp + n; register char *sp; while (bp < ep) { sp = bp + 3; c = *sp; *sp = *bp; *bp++ = c; sp = bp + 1; c = *sp; *sp = *bp; *bp++ = c; bp += 2; } } void xwd_Window_Dump(tk, offscreen, width, height, out) Tk_Window tk; Drawable offscreen; unsigned width, height; FILE *out; { unsigned long swaptest = 1; XColor *colors; unsigned buffer_size; int header_size; int ncolors, i; char *win_name = "a"; int win_name_size = 1; /* strlen("a") */ XImage *image; int absx, absy, x, y; XWDFileHeader header; XWDColor xwdcolor; int format = ZPixmap; int debug = 0; Display *dpy = Tk_Display(tk); Visual *vis; absx = absy = 0; image = XGetImage (dpy, offscreen, 0, 0, width, height, AllPlanes, format); if (!image) { fprintf (stderr, "%s: unable to get image at %dx%d+%d+%d\n", "xwd", width, height, x, y); exit (1); } /* * Determine the pixmap size. */ buffer_size = Image_Size(image); if (debug) outl("xwd: Getting Colors.\n"); ncolors = Get_XColors(tk, &colors); vis = Tk_Visual(tk); /* * Calculate header size. */ if (debug) outl("xwd: Calculating header size.\n"); header_size = SIZEOF(XWDheader) + win_name_size; /* * Write out header information. */ if (debug) outl("xwd: Constructing and dumping file header.\n"); header.header_size = (CARD32) header_size; header.file_version = (CARD32) XWD_FILE_VERSION; header.pixmap_format = (CARD32) format; header.pixmap_depth = (CARD32) image->depth; header.pixmap_width = (CARD32) image->width; header.pixmap_height = (CARD32) image->height; header.xoffset = (CARD32) image->xoffset; header.byte_order = (CARD32) image->byte_order; header.bitmap_unit = (CARD32) image->bitmap_unit; header.bitmap_bit_order = (CARD32) image->bitmap_bit_order; header.bitmap_pad = (CARD32) image->bitmap_pad; header.bits_per_pixel = (CARD32) image->bits_per_pixel; header.bytes_per_line = (CARD32) image->bytes_per_line; /**** header.visual_class = (CARD32) win_info.visual->class; header.red_mask = (CARD32) win_info.visual->red_mask; header.green_mask = (CARD32) win_info.visual->green_mask; header.blue_mask = (CARD32) win_info.visual->blue_mask; header.bits_per_rgb = (CARD32) win_info.visual->bits_per_rgb; header.colormap_entries = (CARD32) win_info.visual->map_entries; *****/ header.visual_class = (CARD32) vis->class; header.red_mask = (CARD32) vis->red_mask; header.green_mask = (CARD32) vis->green_mask; header.blue_mask = (CARD32) vis->blue_mask; header.bits_per_rgb = (CARD32) vis->bits_per_rgb; header.colormap_entries = (CARD32) vis->map_entries; header.ncolors = ncolors; header.window_width = (CARD32) width; header.window_height = (CARD32) height; header.window_x = absx; header.window_y = absy; header.window_bdrwidth = (CARD32) 0; if (*(char *) &swaptest) { _swaplong((char *) &header, sizeof(header)); for (i = 0; i < ncolors; i++) { _swaplong((char *) &colors[i].pixel, sizeof(long)); _swapshort((char *) &colors[i].red, 3 * sizeof(short)); } } if (fwrite((char *)&header, SIZEOF(XWDheader), 1, out) != 1 || fwrite(win_name, win_name_size, 1, out) != 1) { perror("xwd"); exit(1); } /* * Write out the color maps, if any */ /* if (debug) outl("xwd: Dumping %d colors.\n", ncolors); */ for (i = 0; i < ncolors; i++) { xwdcolor.pixel = colors[i].pixel; xwdcolor.red = colors[i].red; xwdcolor.green = colors[i].green; xwdcolor.blue = colors[i].blue; xwdcolor.flags = colors[i].flags; if (fwrite((char *) &xwdcolor, SIZEOF(XWDColor), 1, out) != 1) { perror("xwd"); exit(1); } } /* * Write out the buffer. */ /* if (debug) outl("xwd: Dumping pixmap. bufsize=%d\n",buffer_size); */ /* * This copying of the bit stream (data) to a file is to be replaced * by an Xlib call which hasn't been written yet. It is not clear * what other functions of xwd will be taken over by this (as yet) * non-existant X function. */ if (fwrite(image->data, (int) buffer_size, 1, out) != 1) { perror("xwd"); exit(1); } /* * free the color buffer. */ if(debug && ncolors > 0) outl("xwd: Freeing colors.\n"); if(ncolors > 0) Tcl_Free((char*)colors); /* * Free image */ XDestroyImage(image); } int xwd_Window_Dump_To_File( Tk_Window tk, Drawable offscreen, unsigned width, unsigned height, char *name) { FILE *f; if (!(f = fopen(name, "w"))) { fprintf(stderr, "cannot open %s", name); return TCL_ERROR; }; xwd_Window_Dump(tk, offscreen, width, height, f); fclose(f); return TCL_OK; }

address.cc


/* * Copyright (c) 1990-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Header$ */ #include <stdio.h> #include <stdlib.h> #include "tclcl.h" #include "address.h" #include "config.h" static class AddressClass : public TclClass { public: AddressClass() : TclClass("Address") {} TclObject* create(int, const char*const*) { return (new Address()); } } class_address; Address* Address::instance_; Address::Address() : PortShift_(0), PortMask_(0), McastShift_(0), McastMask_(0), levels_(0) { for (int i = 0; i < 10; i++) { NodeShift_[i] = 0; NodeMask_[i] = 0; } // setting instance_ should be in constructor, instead of Address:: if ((instance_ == 0) || (instance_ != this)) instance_ = this; } Address::~Address() { } int Address::command(int argc, const char*const* argv) { int i, c, temp=0; Tcl& tcl = Tcl::instance(); // if ((instance_ == 0) || (instance_ != this)) // instance_ = this; if (argc == 4) { if (strcmp(argv[1], "portbits-are") == 0) { PortShift_ = atoi(argv[2]); PortMask_ = atoi(argv[3]); return (TCL_OK); } if (strcmp(argv[1], "mcastbits-are") == 0) { McastShift_ = atoi(argv[2]); McastMask_ = atoi(argv[3]); return (TCL_OK); } } if (argc >= 4) { if (strcmp(argv[1], "add-hier") == 0) { /* * <address> add-hier <level> <mask> <shift> */ int level = atoi(argv[2]); int mask = atoi(argv[3]); int shift = atoi(argv[4]); if (levels_ < level) levels_ = level; NodeShift_[level] = shift; NodeMask_[level] = mask; return (TCL_OK); } if (strcmp(argv[1], "idsbits-are") == 0) { temp = (argc - 2)/2; if (levels_) { if (temp != levels_) { tcl.resultf("#idshiftbits don't match with #hier levels\n"); return (TCL_ERROR); } } else levels_ = temp; // NodeShift_ = new int[levels_]; for (i = 3, c = 1; c <= levels_; c++, i+=2) NodeShift_[c] = atoi(argv[i]); return (TCL_OK); } if (strcmp(argv[1], "idmbits-are") == 0) { temp = (argc - 2)/2; if (levels_) { if (temp != levels_) { tcl.resultf("#idmaskbits don't match with #hier levels\n"); return (TCL_ERROR); } } else levels_ = temp; // NodeMask_ = new int[levels_]; for (i = 3, c = 1; c <= levels_; c++, i+=2) NodeMask_[c] = atoi(argv[i]); return (TCL_OK); } } return TclObject::command(argc, argv); } char *Address::print_nodeaddr(int address) { int a; char temp[SMALL_LEN]; char str[SMALL_LEN]; char *addrstr; str[0] = '\0'; for (int i=1; i <= levels_; i++) { a = address >> NodeShift_[i]; if (levels_ > 1) a = a & NodeMask_[i]; sprintf(temp, "%d.", a); strcat(str, temp); } addrstr = new char[strlen(str)]; strcpy(addrstr, str); // printf("Nodeaddr - %s\n",addrstr); return(addrstr); } char *Address::print_portaddr(int address) { int a; char str[SMALL_LEN]; char *addrstr; str[0] = '\0'; a = address >> PortShift_; a = a & PortMask_; sprintf(str, "%d", a); addrstr = new char[strlen(str)]; strcpy(addrstr, str); // printf("Portaddr - %s\n",addrstr); return(addrstr); } // Convert address in string format to binary format (int). int Address::str2addr(char *str) { if (levels_ == 0) return atoi(str); char *delim = "."; char *tok; int addr; for (int i = 1; i <= levels_; i++) { if (i == 1) { tok = strtok(str, delim); addr = atoi(tok); } else { tok = strtok(NULL, delim); addr = set_word_field(addr, atoi(tok), NodeShift_[i], NodeMask_[i]); } } return addr; }

agent.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include "netview.h" #include "psview.h" #include "node.h" #include "feature.h" #include "agent.h" #include "edge.h" #include "paint.h" #include "monitor.h" #include "sincos.h" Agent::Agent(const char* name, double size) : Animation(0, 0), next_(0), AgentPartner_(NULL), size_(size), x_(0.), y_(0.), node_(0), features_(NULL), edge_(NULL), angle_(NO_ANGLE), anchor_(0), mark_(0), window_(20), windowInit_(1), maxcwnd_(0), packetSize_(210), interval_(0.0375), tracevar_(0), start_(0.0), stop_(10.0), produce_(0), flowcolor_(0), color_(0) { label_ = new char[strlen(name) + 1]; strcpy(label_, name); nn_ = atoi(name); /*XXX*/ paint_ = Paint::instance()->thin(); } float Agent::distance(float x, float y) const { return ((x_-x)*(x_-x) + (y_-y)*(y_-y)); } void
Agent::color(const char* name) { if (name[0] == 0) { if (color_) { delete []color_; color_ = 0; } return; } if (color_) delete []color_; color_ = new char[strlen(name) + 1]; strcpy(color_, name); } void Agent::size(double s) { size_ = s; update_bb(); } void Agent::update_bb() { double off = 0.5 * size_; /*XXX*/ bb_.xmin = x_ - off; bb_.ymin = y_ - off; bb_.xmax = x_ + off; bb_.ymax = y_ + off; } void Agent::add_feature(Feature* f) { f->next_ = features_; features_ = f; } Feature *Agent::find_feature(char *name) const { /*given a feature, remove it from an agent's feature list*/ Feature *ft; ft=features_; while (ft!=NULL) { if (strcmp(ft->name(), name)==0) return ft; ft=ft->next(); } return NULL; } void Agent::delete_feature(Feature* r) { /*given a feature, remove it from an agent's feature list*/ Feature *f1, *f2; f1=features_; f2=features_; while ((f1!=r)&&(f1!=NULL)) { f2=f1; f1=f1->next(); } if (f1==r) { f2->next(f1->next()); if (f1==features_) features_=f1->next(); } } void Agent::label(const char* name, int anchor) { delete label_; label_ = new char[strlen(name) + 1]; strcpy(label_, name); anchor_ = anchor; } void Agent::drawlabel(View* nv) const { /*XXX node number */ if (label_ != 0) nv->string(x_, y_, size_, label_, anchor_); } /* void Agent::drawlabel(PSView* nv) const { if (label_ != 0) nv->string(x_, y_, size_, label_, anchor_); } */ void Agent::flowcolor(const char* color) { if (color[0] == 0) { if (flowcolor_) { delete []flowcolor_; flowcolor_ = 0; } return; } if (flowcolor_) delete []flowcolor_; flowcolor_ = new char[strlen(color) + 1]; strcpy(flowcolor_, color); } void Agent::tracevar(const char* var) { if (var[0] == 0) { if (tracevar_) { delete []tracevar_; tracevar_ = 0; } return; } if (tracevar_) delete []tracevar_; tracevar_ = new char[strlen(var) + 1]; strcpy(tracevar_, var); } void Agent::reset(double) { paint_ = Paint::instance()->thick(); } void Agent::place(double x, double y) { x_ = x; y_ = y; mark_ = 1; update_bb(); } const char* Agent::info() const { static char text[128]; if(AgentPartner_!=NULL) { const char *i = AgentPartner_->name(); sprintf(text, "Peer: %s on %d", AgentPartner_->name(), AgentPartner_->node_->num()); } else { sprintf(text, "Agent: %s", label_); } return (text); } const char* Agent::getname() const { static char text[128]; sprintf(text, "a %s", label_); return (text); } void Agent::monitor(Monitor *m, double now, char *result, int len) { char buf[256]; Feature *f; monitor_=m; sprintf(result, "Agent: %s", label_); for(f=features_;f!=NULL;f=f->next()) { strcat(result, "\n"); f->monitor(now, buf, 255); if (strlen(result)+strlen(buf)<(unsigned int)len) strcat(result, buf); else { fprintf(stderr, "not enough space for monitor return string\n"); return; } } } BoxAgent::BoxAgent(const char* name, double size) : Agent(name, size) { BoxAgent::size(size); } void BoxAgent::size(double s) { Agent::size(s); double delta = 0.5 * s; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; update_bb(); } void BoxAgent::update_bb() { bb_.xmin = x0_; bb_.ymin = y0_; bb_.xmax = x1_; bb_.ymax = y1_; } int BoxAgent::inside(double, float px, float py) const { return (px >= x0_ && px <= x1_ && py >= y0_ && py <= y1_); } void BoxAgent::draw(View* nv, double ) const { nv->rect(x0_, y1_, x1_, y0_, paint_); if (label_ != 0) { // nv->string((x0_+x1_)/2, y1_, size_*0.75, label_, ANCHOR_NORTH); nv->string((x0_+x1_)/2, (y0_+y1_)/2, size_*0.75, label_, ANCHOR_CENTER); } if (monitor_!=NULL) monitor_->draw(nv, (x0_+x1_)/2, y0_); } /* void BoxAgent::draw(PSView* nv, double ) const { nv->rect(x0_, y1_, x1_, y0_, paint_); if (label_ != 0) { nv->string((x0_+x1_)/2, (y0_+y1_)/2, size_*0.75, label_, ANCHOR_CENTER); } } */ void BoxAgent::place(double x, double y) { Agent::place(x, y); double nsin, ncos; SINCOSPI(angle_, &nsin, &ncos); height_=0.75; /*XXX should really use the X-display width*/ width_=strlen(label_)/2; /* on solaris, sin(M_PI)!=0 !!!*/ if ((nsin<1.0e-8)&&(nsin>-1.0e-9)) { y0_ = y_ - size_*0.5*height_; y1_ = y_ + size_*0.5*height_; } else if (nsin > 0) { y0_ = y_; y1_ = y_ + size_*height_; } else { y0_ = y_ - size_*height_; y1_ = y_; } if ((ncos<1.0e-8)&&(ncos>-1.0e-9)) { x0_ = x_ - size_*width_*0.5; x1_ = x_ + size_*width_*0.5; } else if (ncos > 0) { x0_ = x_; x1_ = x_ + size_*width_; } else { x0_ = x_ - size_*width_; x1_ = x_; } update_bb(); } int Agent::saveAsNs(FILE *file) { if (!flowcolor_) flowcolor_ = "black"; // TCP source agents (TCP, TCP/Reno, etc) if ((AgentRole_ == SOURCE)&&(strcmp(name(), "CBR")!=0)) { fprintf(file, "\n$ns color %d \"%s\"\n",number_, flowcolor_); fprintf(file, "set agent%d [new Agent/%s] \n", number_, label_); fprintf(file, "$ns attach-agent $n(%d) $agent%d \n", node_->num(), number_); fprintf(file, "$agent%d set fid_ %d\n", number_, number_); fprintf(file, "$agent%d set window_ %d\n", number_, window_); fprintf(file, "$agent%d set windowInit_ %d\n", number_, windowInit_); fprintf(file, "$agent%d set maxcwnd_ %d\n", number_, maxcwnd_); if (tracevar_) { if ((strcmp(tracevar_, "cwnd_") == 0)||(strcmp(tracevar_, "ssthresh_")==0)) { fprintf(file, "$ns add-agent-trace $agent%d tcp\n", number_); fprintf(file, "$ns monitor-agent-trace $agent%d\n", number_); fprintf(file, "$agent%d set tracevar_ %s\n", number_, tracevar_); } } // CBR source agents } else if ((AgentRole_ == SOURCE)&&(strcmp(name(), "CBR")==0)) { fprintf(file, "\n$ns color %d \"%s\"\n",number_, flowcolor_); fprintf(file, "set agent%d [new Agent/%s] \n", number_, label_); fprintf(file, "$ns attach-agent $n(%d) $agent%d \n", node_->num(), number_); fprintf(file, "$agent%d set fid_ %d\n", number_, number_); fprintf(file, "$agent%d set packetSize_ %d\n", number_, packetSize_); fprintf(file, "$agent%d set interval_ %f\n", number_, interval_); // TCP/Full destination agents } else if ((AgentRole_ == DESTINATION)&&(strcmp(name(), "TCP/FullTcp")==0)){ fprintf(file, "\nset agent%d [new Agent/%s] \n", number_, label_); fprintf(file, "$ns attach-agent $n(%d) $agent%d \n", node_->num(), number_); fprintf(file, "$agent%d listen\n", number_); // all destination agents (TCPSink, TCPSink/DelAck, CBR, etc) } else { fprintf(file, "\nset agent%d [new Agent/%s] \n", number_, label_); fprintf(file, "$ns attach-agent $n(%d) $agent%d \n", node_->num(), number_); } return(0); } int Agent::saveAsEnam(FILE *file) { if ((AgentRole_ == 10)&&(strcmp(name(), "CBR")!=0)) { if (AgentPartner_ != NULL) fprintf(file, "##g -t * -l %s -r %d -s %d -c %s -i %d -w %d -m %d -t %s -b %f -p %d -o %f -n %d -u %d\n", label_, AgentRole_, node_->num(), flowcolor_, windowInit_, window_, maxcwnd_, tracevar_, start_, produce_, stop_, number_, AgentPartner_->number_); else fprintf(file, "##g -t * -l %s -r %d -s %d -c %s -i %d -w %d -m %d -t %s -b %f -p %d -o %f -n %d\n", label_, AgentRole_, node_->num(), flowcolor_, windowInit_, window_, maxcwnd_, tracevar_, start_, produce_, stop_, number_); } else if (((AgentRole_ == SOURCE)||(AgentRole_ == 10))&&(strcmp(name(), "CBR")==0)) { if (AgentPartner_ != NULL) fprintf(file, "##g -t * -l %s -r %d -s %d -c %s -k %d -v %f -b %f -o %f -n %d -u %d \n", label_, AgentRole_, node_->num(), flowcolor_, packetSize_, interval_, start_, stop_, number_, AgentPartner_->number_); else fprintf(file, "##g -t * -l %s -r %d -s %d -c %s -k %d -v %f -b %f -o %f -n %d -u %d \n", label_, AgentRole_, node_->num(), flowcolor_, packetSize_, interval_, start_, stop_, number_); } else { if (AgentPartner_ != NULL) fprintf(file, "##g -t * -l %s -r %d -s %d -n %d -u %d \n", label_, AgentRole_, node_->num(), number_, AgentPartner_->number_); else fprintf(file, "##g -t * -l %s -r %d -s %d -n %d\n", label_, AgentRole_, node_->num(), number_); } return(0); } const char* Agent::property() const { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); static char text[256]; char *p; //TCP source agents if ((AgentRole_ == SOURCE)&&(strcmp(name(), "CBR")!=0)) { p = text; sprintf(text, "{AGENT %d} ", number_); p = &text[strlen(text)]; sprintf(p, "{FLOW-COLOR %s} ", flowcolor_); p = &text[strlen(text)]; sprintf(p, "{WINDOW_INIT %d} ", windowInit_); p = &text[strlen(text)]; sprintf(p, "{WINDOW %d} ", window_); p = &text[strlen(text)]; sprintf(p, "{MAXCWND %d} ", maxcwnd_); p = &text[strlen(text)]; sprintf(p, "{TRACEVAR %s} ", tracevar_); p = &text[strlen(text)]; sprintf(p, "{START-AT %f} ", start_); p = &text[strlen(text)]; sprintf(p, "{PRODUCEMORE %f} ", produce_); p = &text[strlen(text)]; sprintf(p, "{STOP-AT %f} ", stop_); // CBR source agents } else if ((AgentRole_ == SOURCE)&&(strcmp(name(), "CBR")==0)) { p = text; sprintf(text, "{AGENT %d} ", number_); p = &text[strlen(text)]; sprintf(p, "{FLOW-COLOR %s} ", flowcolor_); p = &text[strlen(text)]; sprintf(p, "{PACKET_SIZE %d} ", packetSize_); p = &text[strlen(text)]; sprintf(p, "{INTERVAL %f} ", interval_); p = &text[strlen(text)]; sprintf(p, "{START-AT %f} ", start_); p = &text[strlen(text)]; sprintf(p, "{STOP-AT %f} ", stop_); // when choose destination agent or even source node before make a link between agents } else { p = text; sprintf(text, "{AGENT %s} ", label_); p = &text[strlen(text)]; sprintf(p, "{FORGET? Choosing_AgentPartner/Drawing_AgentLink}"); } return(text); }

anetmodel.cc


/* * Network model with automatic layout * * Layout code from nem by Elan Amir * * $Header$ */ #include <stdlib.h> #include <math.h> #include <float.h> #include "random.h" #include "view.h" #include "netview.h" #include "animation.h" #include "queue.h" #include "edge.h" #include "node.h" #include "agent.h" #include "sincos.h" #include "state.h" #include "packet.h" #include "anetmodel.h" class AutoNetworkModelClass : public TclClass { public: AutoNetworkModelClass() : TclClass("NetworkModel/Auto") {} TclObject* create(int argc, const char*const* argv) { if (argc < 5) return 0; return (new AutoNetModel(argv[4])); } } autonetworkmodel_class; int AutoNetModel::AUTO_ITERATIONS_ = 1; int AutoNetModel::INCR_ITERATIONS_ = 200; int AutoNetModel::RANDOM_SEED_ = 1; int AutoNetModel::recalc_ = 1; double AutoNetModel::INIT_TEMP_ = 0.30; // follow Elan's double AutoNetModel::MINX_ = 0.0; double AutoNetModel::MAXX_ = 1.0; double AutoNetModel::MINY_ = 0.0; double AutoNetModel::MAXY_ = 1.0; AutoNetModel::AutoNetModel(const char *animator) : NetModel(animator) { iterations_ = AUTO_ITERATIONS_; bind("KCa_", &kca_); bind("KCr_", &kcr_); bind("Recalc_", &recalc_); bind("INCR_ITERATIONS_", &INCR_ITERATIONS_); bind("AUTO_ITERATIONS_", &AUTO_ITERATIONS_); bind("RANDOM_SEED_", &RANDOM_SEED_); } AutoNetModel::~AutoNetModel() { } int
AutoNetModel::command(int argc, const char *const *argv) { if (argc == 2) { if (strcmp(argv[1], "layout") == 0) { /* * <net> layout * compute layout using Elan's nem */ layout(); return (TCL_OK); } if (strcmp(argv[1], "relayout") == 0) { relayout(); return (TCL_OK); } if (strcmp(argv[1], "reset") == 0) { reset_layout(); return (TCL_OK); } } return (NetModel::command(argc, argv)); } void AutoNetModel::reset_layout() { Node *n; Edge *e; initEmbedding(); for (n = nodes_; n != 0; n = n->next_) for (e = n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { p->redrawModel(); p->draw(); } } void AutoNetModel::initEmbedding() { Node *n; double maxx, maxy; Random::seed_heuristically(); maxx = MINX_ + (MAXX_-MINX_) * 0.4; maxy = MINY_ + (MAXY_-MINY_) * 0.4; // randomize nodes' position within square [(0,0), (1,1)] for (nNodes_ = 0, n = nodes_; n != 0; n = n->next_, nNodes_++) { n->place(Random::uniform(MINX_, maxx), Random::uniform(MINY_, maxy)); } //optk_ = kc_ * sqrt((MAXX_-MINX_)*(MAXY_-MINY_) / (double)nNodes); optka_ = kca_ * sqrt((MAXX_-MINX_)*(MAXY_-MINY_) / (double)nNodes_); optkr_ = kcr_ * sqrt((MAXX_-MINX_)*(MAXY_-MINY_) / (double)nNodes_); temp_ = INIT_TEMP_; } void AutoNetModel::placeEverything() { Node *n; // Should re-initialize nymin_ and nymax_ nymin_ = FLT_MAX; nymax_ = -FLT_MAX; for (n = nodes_; n != 0; n = n->next_) { for (Edge *e = n->links(); e != 0; e = e->next_) placeEdge(e, n); placeAllAgents(n); if (nymin_ > n->y()) nymin_ = n->y(); if (nymax_ < n->y()) nymax_ = n->y(); } // Place all routes for (n = nodes_; n != 0; n = n->next_) { n->clear_routes(); n->place_all_routes(); } } // do more passes void AutoNetModel::relayout() { Node *n; Edge *e; temp_ = INIT_TEMP_; for (n = nodes_; n != 0; n = n->next_) for (e = n->links(); e != 0; e = e->next_) e->unmark(); //weigh_subtrees(); //bifucate_graph(); // in case that the two constants changed optka_ = kca_ * sqrt((MAXX_-MINX_)*(MAXY_-MINY_) / (double)nNodes_); optkr_ = kcr_ * sqrt((MAXX_-MINX_)*(MAXY_-MINY_) / (double)nNodes_); for (int i = 0; i < 100; i++) { //alternate doses of vigorous shaking and letting it settle a little //seem to work best. if ((i==0)||(i==60)) temp_ = INIT_TEMP_; if ((i==50)||(i==70)) temp_ = INIT_TEMP_/4.0; if ((i<50)||((i>=60)&&(i<70))) { embed_phase1(); } else { embed_phase2(); } for (n = nodes_; n != 0; n = n->next_) for (e = n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { // XXX assume this means tk has been // initialized p->redrawModel(); p->draw(); } } } // do several passes of embedding void AutoNetModel::layout() { initEmbedding(); for (int i = 0; i < iterations_; i++) { embed_phase2(); } scale_estimate(); // find node size after layout placeEverything(); } void AutoNetModel::cool() { if (temp_ > 0.001) temp_ *= 0.95; else temp_ = 0.001; } void AutoNetModel::placeAllAgents(Node *src) const { // clear all marks and clear all angles for (Agent *a = src->agents(); a != NULL; a = a->next()) { a->mark(0), a->angle(NO_ANGLE); placeAgent(a, src); } } // we need to use edge length, instead of delay, to estimate scale void AutoNetModel::scale_estimate() { /* Determine the maximum link delay. */ double emax = 0., emean = 0., dist; Node *n; int edges=0; for (n = nodes_; n != 0; n = n->next_) { for (Edge* e = n->links(); e != 0; e = e->next_) { edges++; dist = n->distance(*(e->neighbor())); emean+=dist; if (dist > emax) emax = dist; } } emean/=edges; /*store this because we need it for monitors*/ node_size_ = node_sizefac_ * emean; /* * Check for missing node or edge sizes. If any are found, * compute a reasonable default based on the maximum edge * dimension. */ for (n = nodes_; n != 0; n = n->next_) { n->size(node_size_); for (Edge* e = n->links(); e != 0; e = e->next_) e->size(.03 * emean); } } // Fruchterman, T.M.J and Reingold, E.M., // Graph Drawing by Force-directed Placement, // Software-Practice and Experience, vol. 21(11), 1129-1164 (Nov. 91) // // Do one pass of embedding void AutoNetModel::embed_phase1() { Node *v, *u; Edge* e; double dx, dy, mag, f, minn, rx, ry; /* * Randomly jitter everything to try and break out of local minima */ for (v = nodes_; v != 0; v = v->next_) { v->displace(0., 0.); rx=0.1*(MAXX_-MINX_)* ((INIT_TEMP_-temp_)/INIT_TEMP_)* ((Random::random()&0xffff)/32768.0 - 1.0); ry=0.1*(MAXX_-MINX_)* ((INIT_TEMP_-temp_)/INIT_TEMP_)* ((Random::random()&0xffff)/32768.0 - 1.0); v->displace(rx,ry); } /* * Calculate repulsive forces between all vertices. */ for (v = nodes_; v != 0; v = v->next_) { for (u = nodes_; u != 0; u = u->next_) { if (u == v) continue; dx = v->x() - u->x(); dy = v->y() - u->y(); if (dx == 0 && dy == 0) dx = dy = 0.001; mag = sqrt(dx * dx + dy * dy); f = REP(mag, optkr_); v->displace(v->dx() + ((dx / mag) * f), v->dy() + ((dy / mag) * f)); } } /* * Limit the maximum displacement to the temperature temp; * and then prevent from being displaced outside frame. */ if (recalc_==1) { for (v = nodes_; v != 0; v = v->next_) { mag = sqrt(v->dx()*v->dx() + v->dy() * v->dy()); double posx = v->x(), posy = v->y(); if (mag != 0) { minn = min(mag, temp_); posx += v->dx() / mag * minn; posy += v->dy() / mag * minn; } v->place(posx, posy); v->displace(0.,0.); } } /* * Calculate attractive forces between neighbors. */ for (v = nodes_; v != 0; v = v->next_) { for (e = v->links(); e != 0; e = e->next_) { u = e->neighbor(); dx = v->x() - u->x(); dy = v->y() - u->y(); mag = sqrt(dx * dx + dy * dy); // XXX we consider single direction edge as // of single direction attraction. So we only // attract one node toward the other. If later // we have the other edge, the other node will be // attracted too. if (mag >= 0) { f = ATT(mag, optka_); v->displace(v->dx() - dx / mag * f, v->dy() - dy / mag * f); } } } /* * Limit the maximum displacement to the temperature temp; * and then prevent from being displaced outside frame. */ for (v = nodes_; v != 0; v = v->next_) { mag = sqrt(v->dx()*v->dx() + v->dy() * v->dy()); double posx = v->x(), posy = v->y(); if (mag != 0) { minn = min(mag, temp_); posx += v->dx() / mag * minn; posy += v->dy() / mag * minn; } #if 0 posx = min(MAXX_, max(MINX_, posx)); posy = min(MAXY_, max(MINY_, posy)); #endif v->place(posx, posy); #if 0 printf("Position of node %s: (%f, %f)\n", v->name(), posx, posy); #endif } /* Cool the temperature */ if (temp_ > 0.001) temp_ *= 0.95; else temp_ = 0.001; #if 0 printf("------------------------------\n"); #endif } void AutoNetModel::embed_phase2() { Node *v, *u; Edge* e; double dx, dy, mag, f, minn; /* * Calculate repulsive forces between all vertices. */ for (v = nodes_; v != 0; v = v->next_) { //XXX why not 0. as in paper? v->displace(0.,0.); for (u = nodes_; u != 0; u = u->next_) { if (u == v) continue; dx = v->x() - u->x(); dy = v->y() - u->y(); if (dx == 0 && dy == 0) dx = dy = 0.001; mag = sqrt(dx * dx + dy * dy); f = REP(mag, optkr_); if (f < 2*u->size()) { if (f<temp_) { f=2*u->size()/(mag/* *temp_*/); } else f=2*u->size()/mag; } v->displace(v->dx() + ((dx / mag) * f), v->dy() + ((dy / mag) * f)); } } /* * Limit the maximum displacement to the temperature temp; * and then prevent from being displaced outside frame. */ if (recalc_==1) { for (v = nodes_; v != 0; v = v->next_) { mag = sqrt(v->dx()*v->dx() + v->dy() * v->dy()); double posx = v->x(), posy = v->y(); if (mag != 0) { minn = min(mag, temp_); posx += v->dx() / mag * minn; posy += v->dy() / mag * minn; } v->place(posx, posy); v->displace(0.,0.); } } /* * Calculate attractive forces between neighbors. */ for (v = nodes_; v != 0; v = v->next_) { //if(v->mass()<=0) continue; for (e = v->links(); e != 0; e = e->next_) { u = e->neighbor(); //if(u->mass()<=0) continue; dx = v->x() - u->x(); dy = v->y() - u->y(); mag = sqrt(dx * dx + dy * dy); // XXX we consider single direction edge as // of single direction attraction. So we only // attract one node toward the other. If later // we have the other edge, the other node will be // attracted too. if (mag >= ((INIT_TEMP_-temp_)/INIT_TEMP_)*(e->length()+(v->size()+u->size())*0.75)) { f = ATT2(mag, optka_); v->displace(v->dx() - dx / mag * f, v->dy() - dy / mag * f); } } } /* * Limit the maximum displacement to the temperature temp; * and then prevent from being displaced outside frame. */ for (v = nodes_; v != 0; v = v->next_) { //if(v->mass()<=0) continue; mag = sqrt(v->dx()*v->dx() + v->dy() * v->dy()); double posx = v->x(), posy = v->y(); if (mag != 0) { minn = min(mag, temp_); posx += v->dx() * minn / mag; posy += v->dy() * minn / mag; } #if 0 posx = min(MAXX_, max(MINX_, posx)); posy = min(MAXY_, max(MINY_, posy)); #endif v->place(posx, posy); #if 0 printf("Position of node %s: (%f, %f)\n", v->name(), posx, posy); #endif } /* Cool the temperature */ if (temp_ > 0.001) temp_ *= 0.95; else temp_ = 0.001; #if 0 printf("------------------------------\n"); #endif } // packet handling stuff. use new packet void AutoNetModel::handle(const TraceEvent& e, double now, int direction) { switch (e.tt) { case 'a': { NetModel::handle(e, now, direction); // recalculate bounding box so that all agents will be within // view for (View *v = views_; v != 0; v = v->next_) v->redrawModel(); break; } default: NetModel::handle(e, now, direction); break; } } void AutoNetModel::bifucate_graph() { Node *n, *m; for (n = nodes_; n != 0; n = n->next_) { if (n->mass()<=0) continue; int remaining=0; for (m = nodes_; m != 0; m = m->next_) { if (m->mass()>0) remaining++; m->mark(0); } int depth=0; int result=2; while((result!=0)&&(result!=1)) { depth++; for (m = nodes_; m != 0; m = m->next_) { if (m->mass()>0) { m->mark(0); m->color("black"); } } result=mark_to_depth(n, depth); printf("depth: %d result: %d\n", depth, result); } if (result==1) { int ctr=0; for (m = nodes_; m != 0; m = m->next_) { if (m->marked()==1) ctr++; } printf("remaining: %d ctr: %d\n", remaining, ctr); if ((remaining-ctr>1)&&(ctr>1)&&(ctr<remaining/2)) { printf("success!\n"); for (m = nodes_; m != 0; m = m->next_) { if (m->marked()==1) { m->mass(-1); m->color("blue"); } } } } else { printf("failed at depth %d!\n", depth); } } } int AutoNetModel::mark_to_depth(Node *n, int depth) { int sum=0; if (depth==0) { n->mark(2); return 1; } if (n->marked()==2) sum--; n->mark(1); for(Edge *e = n->links(); e != 0; e = e->next_) { Node *dst=e->neighbor(); if ((dst->mass()>0)&&(dst->marked()==0)) sum+=mark_to_depth(dst, depth-1); } return sum; } void AutoNetModel::weigh_subtrees() { Node *n, *dst, *newdst; Edge* e; int nodes=0; for (n = nodes_; n != 0; n = n->next_) { n->mass(1); } for (n = nodes_; n != 0; n = n->next_) { int ctr=0; for (e = n->links(); e != 0; e = e->next_) ctr++; if (ctr==1) { dst=n->links()->neighbor(); dst->mass(2); n->mass(0); n->color("green"); nodes++; } while(ctr==1) { ctr=0; for (e = dst->links(); e != 0; e = e->next_) if (e->neighbor()->mass()==1) ctr++; if (ctr==1) { for (e = dst->links(); e != 0; e = e->next_) if (e->neighbor()->mass()==1) { newdst=e->neighbor(); newdst->mass(1+dst->mass()); dst->mass(0); dst->color("red"); nodes++; dst=newdst; break; } } } } printf("massless nodes: %d\n", nodes); nodes=0; for (n = nodes_; n != 0; n = n->next_) { if (n->mass()==0) { nodes++; n->color("grey"); } } printf("massless nodes: %d\n", nodes); } void AutoNetModel::place_subtrees() { Node *n, *dst; Edge* e; double angle; int nodes=0, did_something=1; double comx=0.0, comy=0.0, x, y; for (n = nodes_; n != 0; n = n->next_) { if (n->mass()!=0) { comx+=n->x(); comy+=n->y(); nodes++; } } comx/=nodes; comy/=nodes; printf("com at %.2f,%.2f\n", comx, comy); while (did_something) { did_something=0; for (n = nodes_; n != 0; n = n->next_) { if (n->mass()==0) { for (e = n->links(); e != 0; e = e->next_) if (e->neighbor()->mass()>0) { dst=e->neighbor(); n->mass(1); n->color("green"); x=dst->x(); y=dst->y(); if (y-comy!=0) angle=atan((x-comx)/(y-comy)); else angle=0; if (y-comy>0) angle+=M_PI; n->place(x-2*n->size()*sin(angle), y-2*n->size()*cos(angle)); did_something=1; break; } } } } }

animation.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <memory.h> #include <tcl.h> #include <math.h> #include <string.h> #include "animation.h" #include "paint.h" #include "monitor.h" unsigned int Animation::LASTID_ = 0; Tcl_HashTable *Animation::AniHash_ = 0; unsigned int Animation::nAniHash_ = 0; // Static method Animation*
Animation::find(unsigned int id) { Tcl_HashEntry *he = Tcl_FindHashEntry(AniHash_, (const char *)id); Animation *res = NULL; if (he != NULL) res = (Animation*) Tcl_GetHashValue(he); return res; } Animation::Animation(double tim, long offset) { paint_ = 0; oldPaint_ = 0; next_ = 0; prev_ = 0; si_.time = tim; si_.offset = offset; monitor_ = NULL; id_ = Animation::LASTID_++; tags_ = NULL; nTag_ = 0; aType_ = 0 ; bb_.clear(); if (Animation::AniHash_ == 0) { Animation::AniHash_ = new Tcl_HashTable; Tcl_InitHashTable(Animation::AniHash_, TCL_ONE_WORD_KEYS); } // Enter hash table for quick lookup and access int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(AniHash_, (const char *)id_, &newEntry); if (newEntry && (he != NULL)) { // Do not handle exception he == NULL. Don't know how. Tcl_SetHashValue(he, (ClientData)this); nAniHash_++; } } Animation::~Animation() { if (prev_ != 0) *prev_ = next_; if (next_ != 0) next_->prev_ = prev_; if (tags_ != NULL) delete tags_; // Remove from hash table Tcl_HashEntry *he = Tcl_FindHashEntry(AniHash_, (const char *)id_); if (he != NULL) { Tcl_DeleteHashEntry(he); nAniHash_--; } } void Animation::addTag(Animation *t) { if (tags_ == NULL) tags_ = new Animation* [AnimationTagIncrement]; else if (nTag_ % AnimationTagIncrement == 0) { // Increase tag array space Animation **tmp = new Animation* [nTag_+AnimationTagIncrement]; memcpy((char *)tmp, (char *)tags_, nTag_ * sizeof(Animation*)); delete tags_; tags_ = tmp; } tags_[nTag_++] = t; } void Animation::deleteTag(Animation *t) { for (int i = 0; i < nTag_; i++) { if (tags_[i] == t) { tags_[i] = tags_[nTag_ - 1]; nTag_ --; } } } void Animation::detach() { if (prev_ != 0) *prev_ = next_; if (next_ != 0) next_->prev_ = prev_; } void Animation::insert(Animation **head) { next_ = *head; if (next_ != 0) next_->prev_ = &next_; prev_ = head; *head = this; } void Animation::update(double /*now*/) { /* do nothing */ } void Animation::reset(double /*now*/) { /* do nothing */ } int Animation::inside(double /*now*/, float px, float py) const { // Why not use bbox to make a generic inside??? return bb_.inside(px, py); } float Animation::distance(float, float) const { // do nothing return HUGE_VAL; } const char* Animation::info() const { return (0); } const char* Animation::property() const { return (0); } const char* Animation::getname() const { return (0); } const char* Animation::getfid() const { return (0); } const char* Animation::getesrc() const { return (0); } const char* Animation::getedst() const { return (0); } const char* Animation::gettype() const { return (0); } void Animation::monitor(Monitor */*m*/, double /*now*/, char */*result*/, int /*len*/) { } MonState *Animation::monitor_state(void) { return NULL; } void Animation::color(char *color) { int pno = Paint::instance()->lookup(color, 3); if (pno < 0) { fprintf(stderr, "Animation::color: no such color: %s", color); return; } paint(pno); } void Animation::change_color(char *clr) { oldPaint_ = paint_; color(clr); } void Animation::toggle_color() { int pno = oldPaint_; oldPaint_ = paint_; paint_ = pno; } Animation* Animation::getLastTag() { if (nTag_ > 0) return tags_[0]->getLastTag(); else return this; }

animator.cc


// $Header$ #include "animator.h" class NetworkAnimatorClass : TclClass { public: NetworkAnimatorClass() : TclClass("Animator") {} TclObject* create(int, const char*const*) { return (new NetworkAnimator()); } } networkanimator_class; // We put it here in C++ because we need to keep a pointer to it // in NetModel, etc. int
NetworkAnimator::command(int argc, const char *const* argv) { // In case we want to put something here. return TclObject::command(argc, argv); }

drop.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #ifdef WIN32 #include <windows.h> #endif #include "netview.h" #include "drop.h" #include "monitor.h" Drop::Drop(float cx, float cy, float b, float size, double now, long offset, const PacketAttr& p) : Animation(now, offset), x_(cx), y_(cy), bot_(b), psize_(size), start_(now), pkt_(p), rot_(0) { curPos_ = CurPos(now); } Drop::~Drop() { if (monitor_!=NULL) { monitor_->delete_monitor_object(this); } } void Drop::draw(View* c, double now) const { /* XXX nuke array */ float fx[4], fy[4]; double yy = CurPos(now); if (rot_ & 2) { double d = (0.75 * 0.7071067812) * psize_; fx[0] = x_; fy[0] = yy - d; fx[1] = x_ - d; fy[1] = yy; fx[2] = x_; fy[2] = yy + d; fx[3] = x_ + d; fy[3] = yy; } else { double d = (0.75 * 0.5) * psize_; fx[0] = x_ - d; fy[0] = yy - d; fx[1] = x_ - d; fy[1] = yy + d; fx[2] = x_ + d; fy[2] = yy + d; fx[3] = x_ + d; fy[3] = yy - d; } // if ((pkt_.attr & 0x100) == 0) // c->fill(fx, fy, 4, paint_); // else // c->polygon(fx, fy, 4, paint_); c->fill(fx, fy, 4, paint_); if (monitor_!=NULL) { monitor_->draw(c, x_,yy); } } void
Drop::update(double now) { ++rot_; if (now < start_ || CurPos(now) < bot_) /* XXX */ delete this; else { curPos_ = CurPos(now); update_bb(); } } void Drop::update_bb() { double d = (0.75 * 0.7071067812) * psize_; bb_.xmin = x_ - d, bb_.xmax = x_ + d; bb_.ymin = curPos_ - d, bb_.ymax = curPos_ + d; } void Drop::reset(double now) { if (now < start_ || CurPos(now) < bot_) /* XXX */ delete this; else curPos_ = CurPos(now); } int Drop::inside(double now, float px, float py) const { //float minx, maxx, miny, maxy; double yy = CurPos(now); double d = (0.75 * 0.7071067812) * psize_; return (px >= x_ - d && px <= x_ + d && py >= yy - d && py <= yy + d); } double Drop::CurPos(double now) const { if ( bot_ < -10 ) return (y_ - (now - start_) * ( 0 - bot_)) ; //quick hack for wireless model else return (y_ - (now - start_)); } const char* Drop::info() const { static char text[128]; sprintf(text, "%s %d: %s\n dropped at %g\n %d bytes", pkt_.type, pkt_.id, pkt_.convid, start_, pkt_.size); return (text); } const char* Drop::getname() const { static char text[128]; sprintf(text, "d"); return (text); } void Drop::monitor(Monitor *m, double /*now*/, char *result, int /*len*/) { monitor_=m; sprintf(result, "%s %d: %s\n dropped at %g\n %d bytes", pkt_.type, pkt_.id, pkt_.convid, start_, pkt_.size); } MonState *Drop::monitor_state() { MonState *ms=new MonState; ms->type=MON_PACKET; ms->pkt.id=pkt_.id; return ms; }

edge.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include "config.h" #include "sincos.h" #include "edge.h" #include "node.h" #include "packet.h" #include "view.h" #include "netview.h" #include "psview.h" #include "transform.h" #include "paint.h" #include "monitor.h" #include "agent.h" Edge::Edge(Node* src, Node* dst, double ps, double bw, double delay, double length, double angle) : Animation(0, 0), src_(src->num()), dst_(dst->num()), neighbor_(dst), start_(src), x0_(0), y0_(0), //x1_(0), y1_(0), psize_(ps), angle_(angle), bandwidth_(bw), delay_(delay), length_(length), state_(UP), dlabel_(0), dcolor_(0), direction_(0), packets_(NULL), no_of_packets_(0), visible_(1), used_(0), last_packet_(NULL), marked_(0) { paint_ = Paint::instance()->thick(); if (length_==0) length_=delay_; // Set initial (x0,y0), (x1,y1) so that they reflect the current // angle. This enables netmodel to share the same placeEdge() and // placeAgent() with AutoNetModel. SINCOSPI(angle, &x1_, &y1_); } Edge::~Edge() { } float Edge::distance(float x, float y) const { // TODO: Look it up when back home... matrix_.imap(x, y); return y; } void
Edge::init_color(char *clr) { color(clr); dcolor(clr); oldPaint_ = paint_; } void Edge::set_down(char *color) { // If current color is down, don't change it again. // Assuming only one down color. User can change this behavior // by adding tcl code for link-up and link-down events. if (state_ == UP) { int pno = Paint::instance()->lookup(color, 3); oldPaint_ = paint_; paint_ = pno; state_ = DOWN; } } void Edge::set_up() { if (state_ == DOWN) { state_ = UP; toggle_color(); } } void Edge::place(double x0, double y0, double x1, double y1) { x0_ = x0; y0_ = y0; x1_ = x1; y1_ = y1; double dx = x1 - x0; double dy = y1 - y0; /*XXX*/ // delay should not be equal to edge's position // delay_ = sqrt(dx * dx + dy * dy); matrix_.clear(); matrix_.rotate((180 / M_PI) * atan2(dy, dx)); matrix_.translate(x0, y0); if (x1>x0) { bb_.xmin = x0; bb_.xmax = x1; } else { bb_.xmin = x1; bb_.xmax = x0; } if (y1>y0) { bb_.ymin = y0; bb_.ymax = y1; } else { bb_.ymin = y1; bb_.ymax = y0; } eb_.xmin = -0.1 * start_->size(); eb_.xmax = sqrt(dx*dx+dy*dy) + 0.1*neighbor_->size(); eb_.ymin = -0.1 * start_->size(); eb_.ymax = 0.1 * start_->size(); } void Edge::AddPacket(Packet *p) { p->next(packets_); if (packets_!=NULL) packets_->prev(p); p->prev(NULL); packets_=p; if (last_packet_==NULL) last_packet_=p; no_of_packets_++; #define PARANOID #ifdef PARANOID int ctr=0; for(Packet *tp=packets_;tp!=NULL;tp=tp->next()) { ctr++; if (ctr>no_of_packets_) abort(); } if (last_packet_->next()!=NULL) abort(); #ifdef DEBUG printf("AddPacket: %d->%d OK\n", src_, dst_); #endif #endif #undef PARANOID } void Edge::arrive_packet(Packet *p, double atime) { /*Trigger any arrival event at the node*/ neighbor_->arrive_packet(p, this, atime); } void Edge::DeletePacket(Packet *p) { /*Trigger any deletion event at the node*/ if (neighbor_) neighbor_->delete_packet(p); else return ; no_of_packets_--; if (last_packet_==p) { /*Normal case - it's the last packet*/ last_packet_ = p->prev(); if (packets_!=p) p->prev()->next(NULL); else packets_=NULL; } else { /*Abnormal case - need to search the list*/ Packet *tp; tp=packets_; while((tp!=p)&&(tp!=NULL)) { tp=tp->next(); } if (tp==p) { if (tp==packets_) /*it was the first packet*/ packets_=tp->next(); else tp->prev()->next(tp->next()); if (tp==last_packet_) { /*this shouldn't ever happen*/ fprintf(stderr, "**it happened\n"); last_packet_=tp->prev(); } else tp->next()->prev(tp->prev()); } } #define PARANOID #ifdef PARANOID int ctr=0; for(Packet *tp=packets_;tp!=NULL;tp=tp->next()) { ctr++; if (ctr>no_of_packets_) abort(); } if ((last_packet_!=NULL)&&(last_packet_->next()!=NULL)) abort(); #ifdef DEBUG printf("DeletePacket: %d->%d OK\n", src_, dst_); #endif #endif #undef PARANOID } void Edge::dlabel(const char* name) { if (name[0] == 0) { if (dlabel_) { delete []dlabel_; dlabel_ = 0; } return; } if (dlabel_) delete []dlabel_; dlabel_ = new char[strlen(name) + 1]; strcpy(dlabel_, name); } void Edge::dcolor(const char* name) { if (name[0] == 0) { if (dcolor_) { delete []dcolor_; dcolor_ = 0; } return; } if (dcolor_) delete []dcolor_; dcolor_ = new char[strlen(name) + 1]; strcpy(dcolor_, name); } void Edge::direction(const char* name) { if (name[0] == 0) { if (direction_) direction_ = 0; return; } if (!strcmp(name, "SOUTH")) direction_ = 1; else if (!strcmp(name, "NORTH")) direction_ = 2; else if (!strcmp(name, "EAST")) direction_ = 3; else if (!strcmp(name, "WEST")) direction_ = 4; else direction_ = 2; } void Edge::draw(View* view, double /*now*/) const { if (visible()) { view->line(x0_, y0_, x1_, y1_, paint_); } if (monitor_!=NULL) monitor_->draw(view, (x0_+x1_)/2, (y0_+y1_)/2); if (dlabel_ == 0) return; // Draw dynamic label switch (direction_) { case 0: view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0+psize_*1.5, psize_*2.3, dlabel_, direction_, dcolor_); break; case 1: view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0-psize_*1.5, psize_*2.3, dlabel_, direction_, dcolor_); break; case 2: view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0+psize_*1.5, psize_*2.3, dlabel_, direction_, dcolor_); break; case 3: view->string((x0_+x1_)/2.0-psize_*1.5, (y0_+y1_)/2.0, psize_*2.3, dlabel_, direction_, dcolor_); break; case 4: view->string((x0_+x1_)/2.0+psize_*1.5, (y0_+y1_)/2.0, psize_*2.3, dlabel_, direction_, dcolor_); break; default: view->string((x0_+x1_)/2.0, (y0_+y1_)/2.0+psize_*1.5, psize_*2.3, dlabel_, direction_, dcolor_); break; } } void Edge::reset(double) { // paint_ = Paint::instance()->thick(); no_of_packets_=0; packets_=NULL; last_packet_=NULL; } int Edge::inside(double, float px, float py) const { matrix_.imap(px, py); return eb_.inside(px, py); } int Edge::inside(float px, float py) const { matrix_.imap(px, py); return eb_.inside(px, py); } const char* Edge::info() const { static char text[128]; sprintf(text, "link %d-%d:\n bw: %g bits/sec\n delay: %g sec\n", src_, dst_, bandwidth_, delay_); return (text); } const char* Edge::property() const { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); static char text[256]; char *p; p = text; sprintf(text, "{LINK %d.%d} ", src_, dst_); // obj type and id p = &text[strlen(text)]; sprintf(p, "{COLOR %s} ", color->colorname); // color & value p = &text[strlen(text)]; sprintf(p, "{LABEL %s} ", dlabel_); // label $ value //p = &text[strlen(text)]; //sprintf(p, "{LABEL-DIRECTION %d} ", direction_); // label-direction $ value p = &text[strlen(text)]; sprintf(p, "{BANDWIDTH %f} ", bandwidth_); // size & value p = &text[strlen(text)]; sprintf(p, "{DELAY %f} ", delay_); // color & value return(text); } const char* Edge::getname() const { static char text[128]; sprintf(text, "l %d %d", src_, dst_); return (text); } void Edge::monitor(Monitor *m, double /*now*/, char *result, int /*len*/) { monitor_=m; sprintf(result, "link %d-%d:\n bw: %g bits/sec\n delay: %g sec", src_, dst_, bandwidth_, delay_); return; } int Edge::save(FILE *file) { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); char state[10]; double angle,length; float dx,dy; //Edges in the tracefile are bidirectional, so don't need to save //both unidirectional edges if (src_>dst_) return 0; if (state_==UP) strcpy(state, " -S UP"); else if (state_==DOWN) strcpy(state, " -S DOWN"); else state[0]='\0'; if (angle_<0) angle=180*(angle_+2*M_PI)/M_PI; else angle=180*(angle_/M_PI); dx=x0_-x1_; dy=y0_-y1_; length=sqrt(dx*dx+dy*dy); // printf("%d->%d, angle=%f (%fdeg)\n", src_, dst_, angle_, angle); fprintf(file, "l -t * -s %d -d %d -r %f -D %f -c %s -o %.1fdeg -l %f%s\n", src_, dst_, bandwidth_, delay_, color->colorname,angle, length, state); return 0; } int Edge::saveAsEnam(FILE *file) { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); char state[10]; double angle,length; float dx,dy; // XXX Should never set edge size outside scale_estimate()!!!! // psize_ = 25.0; // Edges in the tracefile are bidirectional, so don't need to save // both unidirectional edges if (src_>dst_) return 0; if (state_==UP) strcpy(state, " -S UP"); else if (state_==DOWN) strcpy(state, " -S DOWN"); else state[0]='\0'; if (angle_<0) angle=180*(angle_+2*M_PI)/M_PI; else angle=180*(angle_/M_PI); dx=x0_-x1_; dy=y0_-y1_; length=sqrt(dx*dx+dy*dy); // printf("%d->%d, angle=%f (%fdeg)\n", src_, dst_, angle_, angle); fprintf(file, "##l -t * -s %d -d %d -r %f -D %f -c %s -o %.1fdeg -l %f%s -b %s\n", src_, dst_, bandwidth_, delay_, color->colorname,angle, length, state, dlabel_); return 0; } int Edge::saveAsNs(FILE *file) { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); double angle,length; float dx,dy; //Edges in the tracefile are bidirectional, so don't need to save //both unidirectional edges if (src_>dst_) return 0; if (angle_<0) angle=180*(angle_+2*M_PI)/M_PI; else angle=180*(angle_/M_PI); dx=x0_-x1_; dy=y0_-y1_; length=sqrt(dx*dx+dy*dy); fprintf(file, "$ns duplex-link $n(%d) $n(%d) %fMb %fms DropTail\n", src_, dst_, bandwidth_/1000000.0, delay_*25000); fprintf(file, "$ns duplex-link-op $n(%d) $n(%d) color %s\n", src_, dst_, color->colorname); fprintf(file, "$ns duplex-link-op $n(%d) $n(%d) orient %.1fdeg\n", src_, dst_, angle); if(dlabel_) fprintf(file, "$ns duplex-link-op $n(%d) $n(%d) label %s\n", src_, dst_, dlabel_); if(direction_!=0) fprintf(file, "$ns duplex-link-op $n(%d) $n(%d) label-at %d\n", src_, dst_, direction_); fprintf(file, "\n"); return 0; }

editview.cc


/* * Copyright (c) 1997 by the University of Southern California * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation in source and binary forms for non-commercial purposes * and without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both the copyright notice and * this permission notice appear in supporting documentation. and that * any documentation, advertising materials, and other materials related * to such distribution and use acknowledge that the software was * developed by the University of Southern California, Information * Sciences Institute. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about * the suitability of this software for any purpose. THIS SOFTWARE IS * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Other copyrights might apply to parts of this software and are so * noted when applicable. * * $Header$ */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <ctype.h> #include <math.h> #include "view.h" #include "bbox.h" #include "netmodel.h" #include "editview.h" #include "tclcl.h" #include "paint.h" #include "tag.h" #include "agent.h" void
EditView::DeleteCmdProc(ClientData cd) { EditView *ev = (EditView *)cd; if (ev->tk_ != NULL) { Tk_DestroyWindow(ev->tk_); } } EditView::EditView(const char *name, NetModel* m) : NetView(name), defTag_(NULL) { if (tk_!=0) { Tcl& tcl = Tcl::instance(); cmd_ = Tcl_CreateCommand(tcl.interp(), Tk_PathName(tk_), command, (ClientData)this, DeleteCmdProc); } char str[256]; model_ = m; sprintf(str, "def%-u", (int)this); defTag_ = new Tag(str); model_->add_tag(defTag_); objType_ = NONE; } EditView::EditView(const char *name, NetModel* m, int width, int height) : NetView(name, SQUARE, width, height), defTag_(NULL) { if (tk_!=0) { Tcl& tcl = Tcl::instance(); cmd_ = Tcl_CreateCommand(tcl.interp(), Tk_PathName(tk_), command, (ClientData)this, DeleteCmdProc); } char str[256]; model_ = m; sprintf(str, "def%-u", (int)this); defTag_ = new Tag(name); model_->add_tag(defTag_); objType_ = NONE; } EditView::~EditView() { model_->remove_view(this); if (defTag_ != NULL) { model_->delete_tag(defTag_->name()); delete defTag_; defTag_ = NULL; } // Delete Tcl command created // Tcl& tcl = Tcl::instance(); // Tcl_DeleteCommandFromToken(tcl.interp(), cmd_); } int EditView::command(ClientData cd, Tcl_Interp* tcl, int argc, char **argv) { if (argc < 2) { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return (TCL_ERROR); } char c = argv[1][0]; int length = strlen(argv[1]); EditView *ev = (EditView *)cd; float cx, cy; int flag; // Following implements several useful interactive commands of // Tk's canvas. Their syntax and semantics are kept as close to // those of Tk canvas as possible. if ((c == 'c') && (strncmp(argv[1], "close", length) == 0)) { ev->destroy(); return TCL_OK; } else if ((c == 'd') && (strncmp(argv[1], "dctag", length) == 0)) { /* * <view> dctag * * Delete the current selection, start all over. */ if (ev->defTag_ != NULL) ev->defTag_->remove(); ev->draw(); return (TCL_OK); } else if ((c == 's') && (strncmp(argv[1], "setPoint", length) == 0)) { /* * <view> setPoint x y addFlag * * Select the object (if any) under point (x, y). If no such * object, set current point to (x, y) */ if (argc != 5) { Tcl_AppendResult(tcl, "wrong # args: should be \"", argv[0], " setPoint x y addFlag\"", (char *)NULL); return (TCL_ERROR); } cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); flag = strtol(argv[4], NULL, 10); return ev->cmdSetPoint(cx, cy, flag); } else if ((c == 'd') && (strncmp(argv[1], "deleteObj", length) == 0)) { cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdDeleteObj(cx, cy); } else if ((c == 'm') && (strncmp(argv[1], "moveTo", length) == 0)) { /* * <view> moveto x y * * Move the current selected object (if any) or the * rubber band to point (x, y) */ if (argc != 4) { Tcl_AppendResult(tcl, "wrong # args: should be \"", argv[0], " moveTo x y\"", (char *)NULL); return (TCL_ERROR); } cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdMoveTo(cx, cy); } else if ((c == 'r') && (strncmp(argv[1], "relPoint", length) == 0)) { /* * <view> relPoint x y * * If any object is selected, set the object's * position to point (x,y); otherwise set the rubber * band rectangle and select all the objects in that * rectangle Note: we need a default tag for the * selection in rubber band. */ if (argc != 4) { Tcl_AppendResult(tcl, "wrong # args: should be \"", argv[0], " relPoint x y\"", (char *)NULL); return (TCL_ERROR); } cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdReleasePoint(cx, cy); } else if ((c == 's') && (strncmp(argv[1], "setNodeProperty", length) == 0)) { /* * <view> setNodeProperty nodeid nodepropertyvalue properyname * */ int nodeid = atoi(argv[2]); int propertyname = atoi(argv[4]); return ev->cmdsetNodeProperty(nodeid, argv[3], propertyname); } else if ((c == 's') && (strncmp(argv[1], "setAgentProperty", length) == 0)) { /* * <view> setNodeProperty nodeid nodepropertyvalue properyname * */ int agentid = atoi(argv[2]); int propertyname = atoi(argv[4]); return ev->cmdsetAgentProperty(agentid, argv[3], propertyname); } else if ((c == 's') && (strncmp(argv[1], "setLinkProperty", length) == 0)) { /* * <view> setLinkProperty sid did propertyvalue properyname * */ int sid = atoi(argv[2]); int did = atoi(argv[3]); int propertyname = atoi(argv[5]); return ev->cmdsetLinkProperty(sid, did, argv[4], propertyname); } else if ((c == 'a') && (strncmp(argv[1], "addNode", length) == 0)) { /* * <view> addNode x y * * add a new Node under current (x,y) with default size */ cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdaddNode(cx, cy); } else if ((c == 'a') && (strncmp(argv[1], "addLink", length) == 0)) { /* * <view> addLink x y * * add a new Link if its start AND end point is inside of */ cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdaddLink(cx, cy); } else if ((c == 'a') && (strncmp(argv[1], "addAgent", length) == 0)) { /* * <view> addAgent x y agent * * add a new agent */ cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); char* agent = argv[4]; return ev->cmdaddAgent(cx, cy, agent); } else if ((c == 'g') && (strncmp(argv[1], "getObject", length) == 0)) { /* * <view> getObject x y * * return obj under current point */ cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdgetCurrentObj(cx, cy); } else if ((c == 'g') && (strncmp(argv[1], "getObjectProperty", length) == 0)) { /* * <view> getObjectPropert x y * * return obj property under current point */ cx = strtod(argv[2], NULL); cy = strtod(argv[3], NULL); return ev->cmdgetObjProperty(cx, cy); } else if ((c == 'v') && (strncmp(argv[1], "view_mode", length)==0)) { /* * <view> view_mode * * clear defTag_ and change to view mode */ ev->view_mode(); return TCL_OK; } return (NetView::command(cd, tcl, argc, argv)); } int EditView::cmdsetNodeProperty(int id, char *pv, int pn) { EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_->setNodeProperty(id,pv,pn); EditType oldt_; oldt_ = objType_; objType_ = END_OBJECT; draw(); objType_ = NONE; model_->update(model_->now()); objType_ = oldt_; return(TCL_OK); } int EditView::cmdsetAgentProperty(int id, char *pv, int pn) { EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_->setAgentProperty(id,pv,pn); draw(); return(TCL_OK); } int EditView::cmdsetLinkProperty(int sid, int did, char *pv, int pn) { EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_->setLinkProperty(sid,did, pv,pn); draw(); return(TCL_OK); } int EditView::cmdgetObjProperty(float cx, float cy) { Tcl& tcl = Tcl::instance(); matrix_.imap(cx, cy); Animation *p = model_->inside(cx, cy); if (p == NULL) { tcl.resultf("NONE"); } else { tcl.resultf("%s",p->property()); } return(TCL_OK); } int EditView::cmdgetCurrentObj(float cx, float cy) { Tcl& tcl = Tcl::instance(); matrix_.imap(cx, cy); Animation *p = model_->inside(cx, cy); if (p == NULL) { tcl.resultf("NONE"); } else { tcl.resultf("%s",p->info()); } return(TCL_OK); } // Note: all cx_ and cy_ below are in *window* coordinates int EditView::cmdaddLink(float cx, float cy) { Animation *p; static Animation *old_p; EditorNetModel* emodel_ = (EditorNetModel *)model_; cx_ = cx, cy_ = cy; matrix_.imap(cx, cy); //Do we have a node on current point ? p = model_->inside(cx, cy); if (p == NULL) { defTag_->remove(); if (objType_ == START_LINK) { objType_ = NONE; draw(); } return (TCL_OK); } if (p->classid() == ClassNodeID) { if (objType_ != START_LINK) { old_p = p; /* remember the orig node */ startSetObject(p, cx_, cy_); objType_ = START_LINK; } else if ((old_p == p)||(old_p->classid()!=ClassNodeID)) { objType_ = NONE; draw(); // to support making link by click-&-click objType_ = START_LINK; } else { // add a new link b/w the two nodes startSetObject(p, cx_, cy_); Node *src, *dst; src = (Node *)old_p; dst = (Node *)p; emodel_->addLink(src,dst); objType_ = END_OBJECT; // Erase old positions defTag_->draw(this, model_->now()); // At least we should redo scale estimation and // place everything defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_); model_->recalc(); model_->render(this); defTag_->remove(); objType_ = NONE; draw(); objType_ = NONE; } } else if (p->classid() == ClassAgentID) { if (objType_ != START_LINK) { old_p = p; startSetObject(p, cx_, cy_); objType_ = START_LINK; } else if ((old_p == p)||(old_p->classid()!=ClassAgentID)) { objType_ = NONE; draw(); // to support making agent-link by click-&-click objType_ = START_LINK; } else { startSetObject(p, cx_, cy_); Agent *src_agent, *dst_agent; src_agent = (Agent *)old_p; dst_agent = (Agent *)p; emodel_->addAgentLink(src_agent,dst_agent); objType_ = END_OBJECT; defTag_->draw(this, model_->now()); defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_); model_->recalc(); model_->render(this); defTag_->remove(); objType_ = NONE; draw(); } } else { objType_ = NONE; } return(TCL_OK); } int EditView::cmdaddAgent(float cx, float cy, char* agent) { Animation *p; EditorNetModel* emodel_ = (EditorNetModel *)model_; matrix_.imap(cx, cy); //Do we have a node on current point ? p = model_->inside(cx, cy); if (p == NULL) { defTag_->remove(); return (TCL_OK); } if (p->classid() == ClassNodeID) { Node *src; src = (Node *)p; emodel_->addAgent(src, agent, cx, cy); draw(); } else { return (TCL_OK); } return(TCL_OK); } // Note: all cx_ and cy_ below are in *window* coordinates int EditView::cmdaddNode(float cx, float cy) { matrix_.imap(cx, cy); EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_->addNode(cx, cy); draw(); return(TCL_OK); } int EditView::cmdDeleteObj(float cx, float cy) { // First of all, clean the old group cx_ = cx, cy_ = cy; // Do we have anything on current point? matrix_.imap(cx, cy); Animation *p = model_->inside(cx, cy); if (p == NULL) { defTag_->remove(); return (TCL_OK); } // Only nodes, links, and agents can be deleted if (p->isTagged()) { if (p->numTag() > 1) { fprintf(stderr, "Error: More than one tags for object %d!\n", p->id()); p = NULL; } else p = p->getLastTag(); } if ((p->classid() != ClassNodeID) && (p->classid() != ClassEdgeID) \ && (p->classid() != ClassAgentID)) p = NULL; if (p == NULL) { defTag_->remove(); } else { if (p->classid() == ClassNodeID) { Node *n = (Node *)p; EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_ -> removeNode(n); draw(); } if (p->classid() == ClassEdgeID) { Edge *e = (Edge *)p; EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_ -> removeLink(e); draw(); } if (p->classid() == ClassAgentID) { Agent *a = (Agent *)p; EditorNetModel* emodel_ = (EditorNetModel *)model_; emodel_ -> removeAgent(a); draw(); } } return (TCL_OK); } // Note: all cx_ and cy_ below are in *window* coordinates int EditView::cmdSetPoint(float cx, float cy, int bAdd) { // First of all, clean the old group cx_ = cx, cy_ = cy; // Do we have anything on current point? matrix_.imap(cx, cy); Animation *p = model_->inside(cx, cy); if (p == NULL) { defTag_->remove(); startRubberBand(cx_, cy_); return (TCL_OK); } if (p->isTagged()) { if (p->numTag() > 1) { fprintf(stderr, "Error: More than one tags for object %d!\n", p->id()); p = NULL; } else p = p->getLastTag(); } // Only nodes and tags can be moved if ((p->classid() != ClassNodeID) && (p->classid() != ClassTagID)) p = NULL; if (p == NULL) { defTag_->remove(); startRubberBand(cx_, cy_); } else { // If a single non-tag object is selected, or explicitly // instructed, remove the previous selection if (!bAdd && (p != defTag_)) defTag_->remove(); startSetObject(p, cx_, cy_); } return (TCL_OK); } int EditView::cmdMoveTo(float cx, float cy) { cx_ = cx, cy_ = cy; switch (objType_) { case START_RUBBERBAND: case MOVE_RUBBERBAND: oldx_ = rb_.xmax; oldy_ = rb_.ymax; rb_.xmax = cx_, rb_.ymax = cy_; objType_ = MOVE_RUBBERBAND; clip_ = rb_; clip_.adjust(); if (clip_.xmin > oldx_) clip_.xmin = oldx_; if (clip_.xmax < oldx_) clip_.xmax = oldx_; if (clip_.ymin > oldy_) clip_.ymin = oldy_; if (clip_.ymax < oldy_) clip_.ymax = oldy_; break; case START_OBJECT: case MOVE_OBJECT: { oldx_ = rb_.xmax; oldy_ = rb_.ymax; rb_.xmax = cx_, rb_.ymax = cy_; objType_ = MOVE_OBJECT; clip_.clear(); defTag_->merge(clip_); matrix_.map(clip_.xmin, clip_.ymin); matrix_.map(clip_.xmax, clip_.ymax); clip_.adjust(); // Actual move and final bbox computation is done in render break; case START_LINK: case MOVE_LINK: oldx_ = rb_.xmax; oldy_ = rb_.ymax; rb_.xmax = cx_, rb_.ymax = cy_; objType_ = MOVE_LINK; clip_ = rb_; clip_.adjust(); if (clip_.xmin > oldx_) clip_.xmin = oldx_; if (clip_.xmax < oldx_) clip_.xmax = oldx_; if (clip_.ymin > oldy_) clip_.ymin = oldy_; if (clip_.ymax < oldy_) clip_.ymax = oldy_; break; } default: // to avoid segmentation fault from click-n-dragging return (TCL_OK); // fprintf(stderr, "moveTo without any selection. \ // Please send your trace file to haoboy@isi.edu.\n"); // return (TCL_ERROR); } draw(); return (TCL_OK); } int EditView::cmdReleasePoint(float cx, float cy) { cx_ = cx, cy_ = cy; switch (objType_) { case START_RUBBERBAND: case MOVE_RUBBERBAND: { oldx_ = rb_.xmax; oldy_ = rb_.ymax; rb_.xmax = cx_, rb_.ymax = cy_; // Need to add the region to defTag_ clip_ = rb_; clip_.adjust(); BBox bb = clip_; matrix_.imap(bb.xmin, bb.ymin); matrix_.imap(bb.xmax, bb.ymax); bb.adjust(); model_->tagArea(bb, defTag_, 1); // We can do a total redraw objType_ = NONE; draw(); break; } case START_OBJECT: case MOVE_OBJECT: { oldx_ = rb_.xmax; oldy_ = rb_.ymax; rb_.xmax = cx_, rb_.ymax = cy_; clip_.clear(); defTag_->merge(clip_); matrix_.map(clip_.xmin, clip_.ymin); matrix_.map(clip_.xmax, clip_.ymax); clip_.adjust(); // Later in render() we'll compute the real bbox objType_ = END_OBJECT; draw(); objType_ = NONE; model_->update(model_->now()); break; } case START_LINK: case MOVE_LINK: { objType_ = START_LINK; draw(); model_->update(model_->now()); cmdaddLink(cx_, cy_); break; } default: // This cannot happen! // fprintf(stderr, "moveTo without any selection. // Please send your trace file to haoboy@isi.edu.\n"); objType_ = NONE; draw(); // return (TCL_ERROR); } return (TCL_OK); } void EditView::draw() { if (objType_ == NONE) View::draw(); else { // Ignore the cleaning part render(); // XXX Don't understand why clip's height and width need to // increase 3 to draw tagged objects correctly. XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_), background_,(int)clip_.xmin, (int)clip_.ymin, (int)clip_.width()+3, (int)clip_.height()+3, (int)clip_.xmin, (int)clip_.ymin); } } void EditView::xline(float x0, float y0, float x1, float y1, GC gc) { XDrawLine(Tk_Display(tk_), offscreen_, gc, (int) x0, (int) y0, (int) x1, (int) y1); } // Without transform. void EditView::xrect(float x0, float y0, float x1, float y1, GC gc) { int x = (int) floor(x0); int y = (int) floor(y0); int w = (int)(x1 - x0); if (w < 0) { x = (int) ceil(x1); w = -w; } int h = (int)(y1 - y0); if (h < 0) { h = -h; y = (int)ceil(y1); } XDrawRectangle(Tk_Display(tk_), offscreen_, gc, x, y, w, h); } void EditView::line(float x0, float y0, float x1, float y1, int color) { if (objType_ != NONE) View::line(x0, y0, x1, y1, Paint::instance()->xor()); else View::line(x0, y0, x1, y1, color); } void EditView::rect(float x0, float y0, float x1, float y1, int color) { if (objType_ != NONE) View::rect(x0, y0, x1, y1, Paint::instance()->xor()); else View::rect(x0, y0, x1, y1, color); } void EditView::polygon(const float* x, const float* y, int n, int color) { if (objType_ != NONE) View::polygon(x, y, n, Paint::instance()->xor()); else View::polygon(x, y, n, color); } void EditView::fill(const float* x, const float* y, int n, int color) { if (objType_ != NONE) View::fill(x, y, n, Paint::instance()->xor()); else View::fill(x, y, n, color); } void EditView::circle(float x, float y, float r, int color) { if (objType_ != NONE) View::circle(x, y, r, Paint::instance()->xor()); else View::circle(x, y, r, color); } // Do not display any string, because no xor font gc void EditView::string(float fx, float fy, float dim, const char* s, int anchor) { if (objType_ == NONE) View::string(fx, fy, dim, s, anchor); } void EditView::render() { // Here we can compute the clipping box for render Paint *paint = Paint::instance(); GC gc = paint->paint_to_gc(paint->xor()); switch (objType_) { case START_RUBBERBAND: // draw rubber band xrect(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc); break; case MOVE_RUBBERBAND: // erase previous rubberband xrect(rb_.xmin, rb_.ymin, oldx_, oldy_, gc); // draw new rubberband xrect(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc); break; case END_RUBBERBAND: // erase previous rubber band xrect(rb_.xmin, rb_.ymin, oldx_, oldy_, gc); // XXX Should draw the tag? model_->render(this); objType_ = NONE; break; case START_OBJECT: xrect(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc); // xor-draw all relevant objects defTag_->draw(this, model_->now()); break; case MOVE_OBJECT: // erase old positions first. if ((oldx_ == rb_.xmax) && (oldy_ == rb_.ymax)) return; defTag_->draw(this, model_->now()); // move these objects defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_); BBox bb; bb.clear(); defTag_->merge(bb); matrix_.imap(bb.xmin, bb.ymin); matrix_.imap(bb.xmax, bb.ymax); bb.adjust(); clip_.merge(bb); defTag_->draw(this, model_->now()); break; case END_OBJECT: // Erase old positions defTag_->draw(this, model_->now()); // At least we should redo scale estimation and // place everything defTag_->move(this, rb_.xmax - oldx_, rb_.ymax - oldy_); model_->recalc(); model_->render(this); objType_ = NONE; break; case START_LINK: line(link_start_x_, link_start_y_, link_end_x_, link_end_y_, 3); defTag_->draw(this, model_->now()); break; case MOVE_LINK: // erase previous link xline(rb_.xmin, rb_.ymin, oldx_, oldy_, gc); // draw new rubberband xline(rb_.xmin, rb_.ymin, rb_.xmax, rb_.ymax, gc); break; case END_LINK: // erase previous link xline(rb_.xmin, rb_.ymin, oldx_, oldy_, gc); // XXX Should draw the tag? model_->render(this); objType_ = NONE; break; default: // redraw model model_->render(this); return; } }

enetmodel.cc


// // Copyright (c) 1997,2000 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for non-commercial purposes // and without fee is hereby granted, provided that the above copyright // notice appear in all copies and that both the copyright notice and // this permission notice appear in supporting documentation. and that // any documentation, advertising materials, and other materials related // to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the University may not be used to // endorse or promote products derived from this software without // specific prior written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about // the suitability of this software for any purpose. THIS SOFTWARE IS // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // Other copyrights might apply to parts of this software and are so // noted when applicable. // // $Header$ // // Network model with Editor layout #include <stdlib.h> #include <math.h> #include <float.h> #include "random.h" #include "view.h" #include "netview.h" #include "animation.h" #include "queue.h" #include "edge.h" #include "node.h" #include "agent.h" #include "sincos.h" #include "state.h" #include "packet.h" #include "enetmodel.h" static int agent_number = 0; class EditorNetworkModelClass : public TclClass { public: EditorNetworkModelClass() : TclClass("NetworkModel/Editor") {} TclObject* create(int argc, const char*const* argv) { if (argc < 5) return 0; return (new EditorNetModel(argv[4])); } } editornetworkmodel_class; EditorNetModel::EditorNetModel(const char *editor) : NetModel(editor) { nID = 0; bind("Wpxmin_", &pxmin_); bind("Wpymin_", &pymin_); bind("Wpxmax_", &pxmax_); bind("Wpymax_", &pymax_); } EditorNetModel::~EditorNetModel() { } void
EditorNetModel::BoundingBox(BBox& bb) { // by default, 800X1000 internal drawing area bb.xmin = pxmin_; bb.ymin = pymin_; bb.xmax = pxmax_; bb.ymax = pymax_; for (Animation* a = drawables_; a != 0; a = a->next()) a->merge(bb); pxmin_ = bb.xmin; pymin_ = bb.ymin; pxmax_ = bb.xmax; pymax_ = bb.ymax; } int EditorNetModel::addNode(float cx, float cy) { /* * <net> node <name> <shape> <color> <addr> [<size>] * Create a node using the specified name * and the default size and insert it into this * NetModel's list of drawables. */ Node *n; static char name[TRACE_LINE_MAXLEN]; if (nID == 0 ) { for (n = nodes_; n != 0; n = n->next_) { if((n->num())>nID) nID = n->num(); } if (nID > 0) nID ++; } sprintf(name, "%d", nID); double size = 70; n = new CircleNode(name,size); n->init_color("black"); nID ++; //n->setaddr(addr); //addAddress(n->num(), addr); n->place(cx,cy); n->next_ = nodes_; nodes_ = n; n->insert(&drawables_); return (TCL_OK); } int EditorNetModel::addLink(Node *src, Node *dst) { double bw = 1000000.0; double delay = 0.002; double length = 0; double angle = 1.0; Edge *e = new Edge(src, dst, 25, bw, delay, length, angle); e->init_color("black"); enterEdge(e); e->insert(&drawables_); src->add_link(e); // tcl.resultf("%g", delay); // duplex link by default according to nam e = new Edge(dst, src, 25, bw, delay, length, angle); e->init_color("black"); enterEdge(e); e->insert(&drawables_); dst->add_link(e); return (TCL_OK); } int EditorNetModel::addAgent(Node *src, char *agent, float cx, float cy) { Node *n = lookupNode(src->num()); Agent *a; if (n==0) { return 0; } else { a = new BoxAgent(agent, n->size()); placeAgent(a, src); a->insert(&animations_); a->node_ = n; a->number_ = agent_number++; n->add_agent(a); } return (TCL_OK); } int EditorNetModel::addAgentLink(Agent *src_agent, Agent *dst_agent) { float src_x_, src_y_, dst_x_, dst_y_; src_x_ = src_agent->x(), src_y_ = src_agent->y(); dst_x_ = dst_agent->x(), dst_y_ = dst_agent->y(); if ((strcmp(src_agent->name(), "TCPSink")==0)|| \ (strcmp(src_agent->name(), "TCPSink/DelAck")==0)|| \ (strcmp(src_agent->name(), "TCPSink/Sack1")==0)) { src_agent->AgentRole_ = DESTINATION; dst_agent->AgentRole_ = SOURCE; } else { src_agent->AgentRole_ = SOURCE; dst_agent->AgentRole_ = DESTINATION; } dst_agent->AgentPartner_ = src_agent; src_agent->AgentPartner_ = dst_agent; return (TCL_OK); } void EditorNetModel::setNodeProperty(int id, char* pv, int pn) { Node *n = lookupNode(id); Agent *a; if (n == NULL) { fprintf(stderr, "Nonexisting node %d.\n", id); return; } switch (pn) { case 0: { double s = atof(pv); n->size(s); break; } case 1: //color { n->init_color(pv); break; } case 2: //label { if (strcmp(pv, "(null)") != 0) n->dlabel(pv); break; } } } void EditorNetModel::setAgentProperty(int id, char* pv, int pn) { Agent *a = lookupAgent(id); if (a == NULL) { fprintf(stderr, "Nonexisting agent %s.\n", id); return; } switch (pn) { case 0: // initial window size { int size = atoi(pv); a->windowInit(size); break; } case 1: // window size { int size = atoi(pv); a->window(size); break; } case 2: // maximum cwnd_ { int size = atoi(pv); a->maxcwnd(size); break; } case 3: // tracevar { a->tracevar(pv); break; } case 4: // start-at { float time = atof(pv); a->startAt(time); break; } case 5: // FTP producemore { int size = atoi(pv); a->produce(size); break; } case 6: // stop-at { float time = atof(pv); a->stopAt(time); break; } case 7: // Flow ID + Color { if ((strcmp(pv, "(null)") == 0) || (strcmp(pv, "") == 0)) { pv = "black"; a->flowcolor(pv); } else { a->flowcolor(pv); } break; } case 8: // CBR packetSize { int size = atoi(pv); a->packetSize(size); break; } case 9: // CBR interval { float size = atof(pv); a->interval(size); break; } } } void EditorNetModel::setLinkProperty(int sid,int did, char* pv, int pn) { EdgeHashNode *h = lookupEdge(sid, did); EdgeHashNode *g = lookupEdge(did, sid); if (h == NULL || g == NULL ) { fprintf(stderr, "Nonexisting link %d.%d\n", sid, did); return; } switch (pn) { case 0: //bandwidth { double s = atof(pv); (h->edge) -> setBW(s); (g->edge) -> setBW(s); break; } case 1: //color { //int color = atoi(pv); (h->edge)->init_color(pv); (g->edge)->init_color(pv); break; } case 2: //delay { double s = atof(pv); (h->edge) -> setDelay(s); (g->edge) -> setDelay(s); break; } case 3: //label { if (strcmp(pv, "(null)") != 0) { (h->edge) -> dlabel(pv); (g->edge) -> dlabel(pv); } break; } default: break; } } int EditorNetModel::command(int argc, const char *const *argv) { if (argc == 2) { if (strcmp(argv[1], "layout") == 0) { layout(); return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "saveasenam") == 0) { /* * <net> saveasenam filehandler */ saveAsEnam(argv[2]); return (TCL_OK); } if (strcmp(argv[1], "saveasns") == 0) { /* * <net> saveasns filehandler */ saveAsNs(argv[2]); return (TCL_OK); } } return (NetModel::command(argc, argv)); } void EditorNetModel::layout() { Node *n; for (n = nodes_; n != 0; n = n->next_) for (Edge* e = n->links(); e != 0; e = e->next_) placeEdge(e, n); } // XXX losing some editor's info int EditorNetModel::saveAsNs(const char *filename) { FILE *file; Node *n; Edge *e; Agent *a; int ret; file=fopen(filename, "a"); if (file==0) { fprintf(stderr, "nam: Couldn't open file: %s\n", filename); return -1; } fprintf(file, "\n#create ns\n"); fprintf(file, "set ns [new Simulator]\n"); fprintf(file, "$ns namtrace-all [open out.nam w]\n"); // save node info fprintf(file, "\n#node creation\n"); if (!nodes_) return 0; int i = nodes_->num(); int j = nodes_->next_->num(); // for consistent numbering between nam editor and nam if (i > j) { for (int k = 0; k <= i; k++) { for (n = nodes_; n != 0; n = n->next_) { if (k==n->num()) { ret = n->saveAsNs(file); if (ret!=0) { fclose(file); return -1; } fprintf(file, "\n"); } } } } else { for (n = nodes_; n != 0; n = n->next_) { ret = n->saveAsNs(file); if (ret!=0) { fclose(file); return -1; } fprintf(file, "\n"); } } // save link info fprintf(file, "#link creation\n"); for (n = nodes_; n != 0; n = n->next_) for(e= n->links(); e !=0; e = e->next_) { ret = e->saveAsNs(file); if (ret!=0) { fclose(file); return -1; } } // save agent info fprintf(file, "#agent creation\n"); for (n = nodes_; n != 0; n = n->next_) { for(a= n->agents(); a !=0; a = a->next_) { ret = a->saveAsNs(file); } } for (n = nodes_; n != 0; n = n->next_) { for(a= n->agents(); a !=0; a = a->next_) { if (a->AgentRole_ == SOURCE) { if (strcmp(a->name(), "CBR") == 0) { // CBR Traffic int src; src = a->number_; fprintf(file, "$ns connect $agent%d $agent%d \n\n", src, a->AgentPartner_->number_); fprintf(file, "$ns at %f \"$agent%d start\" \n", a->startAt(), src); fprintf(file, "$ns at %f \"$agent%d stop\" \n\n", a->stopAt(), src); } else { // TCP traffic int src; src = a->number_; fprintf(file, "$ns connect $agent%d $agent%d \n\n", src, a->AgentPartner_->number_); fprintf(file, "\nset ftp%d [new Application/FTP] \n", src); fprintf(file, "$ftp%d attach-agent $agent%d \n\n", src, src); if (a->produce()>0) { // ftp producemore option fprintf(file, "$ns at %f \"$ftp%d producemore %d\" \n", a->startAt(), src, a->produce()); } else { fprintf(file, "$ns at %f \"$ftp%d start\" \n", a->startAt(), src); fprintf(file, "$ns at %f \"$ftp%d stop\" \n\n", a->stopAt(), src); } } } } } fprintf(file, "#Run\n"); fprintf(file, "exec nam out.nam &\n"); fprintf(file, "$ns run\n"); return(fclose(file)); } int EditorNetModel::saveAsEnam(const char *filename) { FILE *file; Node *n; Edge *e; Agent *a; int ret; file=fopen(filename, "w"); if (file==0) { fprintf(stderr, "nam: Couldn't open file: %s\n", filename); return -1; } // save warning info fprintf(file, "## All lines starting with ## are created by nam editor.\n"); fprintf(file, "## Please do not try to edit them manually.\n"); // save version info fprintf(file, "##V -t * -v 1.0a7 -a 0\n"); // save page size fprintf(file, "##W -t * -x %f -y %f -X %f -Y %f\n",pxmin_, pymin_, pxmax_, pymax_); // save node information for (n = nodes_; n != 0; n = n->next_) { ret = n->saveAsEnam(file); if (ret!=0) { fclose(file); return -1; } } //save link information for (n = nodes_; n != 0; n = n->next_) for(e= n->links(); e !=0; e = e->next_) { ret = e->saveAsEnam(file); if (ret!=0) { fclose(file); return -1; } } // save agent information for (n = nodes_; n != 0; n = n->next_) for(a= n->agents(); a !=0; a = a->next_) { ret = a->saveAsEnam(file); if (ret!=0) { fclose(file); return -1; } } fprintf(file, "## Please do not try to edit this file above this line.\n\n"); return(fclose(file)); } void EditorNetModel::removeNode(Node *n) { Node *p,*q; p = nodes_; for (q = nodes_; q != 0; q = q->next_) { if ( n->num() == q->num() ) { // when deleting the last node if ( q->num() == nodes_->num() ) { nodes_=nodes_->next_; break; } else { p->next_ = q->next_; break; } } p = q; } q->detach(); // delete edge on the nodes_ for(Edge *e= q->links(); e !=0; e = e->next_) removeLink(e); // delete agents on the nodes_ for(Agent *a= q->agents(); a !=0; a = a->next_) removeAgent(a); delete q; } void EditorNetModel::removeLink(Edge *e) { int src = e->src(); int dst = e->dst(); EdgeHashNode *h = lookupEdge(src, dst); EdgeHashNode *g = lookupEdge(dst, src); if (h == 0 || g == 0) { // h,g = 0 or h,g !=0 return; } Edge* e1 = h->edge; Edge* e2 = g->edge; removeEdge(e1); removeEdge(e2); e1->detach(); e2->detach(); Node* srcnode = e1->start(); Node* dstnode = e2->start(); // it is a duplex by default srcnode->delete_link(e1); dstnode->delete_link(e2); delete e1; delete e2; } void EditorNetModel::removeAgent(Agent *a) { Node *n; n = a->node_; if (a->AgentPartner_!=NULL) { a->AgentPartner_->AgentPartner_ = NULL; a->AgentPartner_->AgentRole_ = 0; } n->delete_agent(a); a->detach(); delete a; }

feature.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #ifdef WIN32 #include <windows.h> #endif #include "netview.h" #include "agent.h" #include "node.h" #include "edge.h" #include "paint.h" #include "feature.h" Feature::Feature(Agent *a, const char* name) : Animation(0, 0), next_(0), x_(0.), y_(0.), agent_(a), anchor_(0), mark_(0) { varname_ = new char[strlen(name) + 1]; strcpy(varname_, name); paint_ = Paint::instance()->thick(); } void
Feature::size(double s) { size_ = s; update_bb(); } void Feature::update_bb() { double off = 0.5 * size_; /*XXX*/ bb_.xmin = x_ - off; bb_.ymin = y_ - off; bb_.xmax = x_ + off; bb_.ymax = y_ + off; } int Feature::inside(double, float px, float py) const { return (px >= bb_.xmin && px <= bb_.xmax && py >= bb_.ymin && py <= bb_.ymax); } const char* Feature::info() const { static char text[128]; sprintf(text, "%s", varname_); return (text); } void Feature::monitor(double /*now*/, char *result, int /*len*/) { sprintf(result, "This should not happen"); } void Feature::varname(const char* name, int anchor) { delete varname_; varname_ = new char[strlen(name) + 1]; strcpy(varname_, name); anchor_ = anchor; } void Feature::drawlabel(View* nv) const { /*XXX node number */ if (varname_ != 0) nv->string(x_, y_, size_, varname_, anchor_); } void Feature::reset(double) { paint_ = Paint::instance()->thick(); } void Feature::place(double x, double y) { x_ = x; y_ = y; mark_ = 1; update_bb(); } ListFeature::ListFeature(Agent *a, const char* name) : Feature(a,name), value_(NULL) { ListFeature::size(a->size()); } void ListFeature::set_feature(char *value) { if (value_!=NULL) delete value_; value_ = new char[strlen(value) + 1]; strcpy(value_, value); } void ListFeature::size(double s) { Feature::size(s); double delta = 0.5 * s; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } void ListFeature::monitor(double /*now*/, char *result, int /*len*/) { sprintf(result, "%s:%s", varname_, value_); } void ListFeature::draw(View* nv, double /*now*/) const { nv->rect(x0_, y0_, x1_, y1_, paint_); drawlabel(nv); } void ListFeature::place(double x, double y) { Feature::place(x, y); double delta = 0.5 * size_; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } VariableFeature::VariableFeature(Agent *a, const char* name) : Feature(a,name), value_(NULL) { VariableFeature::size(a->size()); } void VariableFeature::set_feature(char *value) { if (value_!=NULL) delete value_; value_ = new char[strlen(value) + 1]; strcpy(value_, value); } void VariableFeature::size(double s) { Feature::size(s); double delta = 0.5 * s; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } void VariableFeature::monitor(double /*now*/, char *result, int /*len*/) { sprintf(result, "%s:%s", varname_, value_); } void VariableFeature::draw(View* nv, double /*now*/) const { nv->rect(x0_, y0_, x1_, y1_, paint_); drawlabel(nv); } void VariableFeature::place(double x, double y) { Feature::place(x, y); double delta = 0.5 * size_; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } TimerFeature::TimerFeature(Agent *a, const char* name) : Feature(a,name) { TimerFeature::size(a->size()); } void TimerFeature::set_feature(double timer, int direction, double time_set) { timer_=timer; direction_=direction; time_set_=time_set; } void TimerFeature::size(double s) { Feature::size(s); double delta = 0.5 * s; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } void TimerFeature::monitor(double /*now*/, char *result, int /*len*/) { sprintf(result, "%s:%f", varname_, timer_); } void TimerFeature::draw(View* nv, double /*now*/) const { nv->rect(x0_, y0_, x1_, y1_, paint_); drawlabel(nv); } void TimerFeature::place(double x, double y) { Feature::place(x, y); double delta = 0.5 * size_; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; }

graphview.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <ctype.h> #include <math.h> #include "bbox.h" #include "graphview.h" #include "netgraph.h" #include "tclcl.h" #include "paint.h" #include "packet.h" GraphView::GraphView(const char* name, NetGraph* g) : View(name, NONSQUARE, 30, 30), next_(NULL), graph_(g) { Tcl& tcl = Tcl::instance(); tcl.CreateCommand(Tk_PathName(View::tk()), command, (ClientData)this, 0); } // void GraphView::draw() // { // if (offscreen_ == 0) // return; // XFillRectangle(Tk_Display(tk_), offscreen_, background_, // 0, 0, width_, height_); // graph_->render(this); // XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_), background_, // 0, 0, width_, height_, 0, 0); // } int
GraphView::command(ClientData cd, Tcl_Interp* tcl, int argc, char **argv) { //GraphView *gv = (GraphView *)cd; if (argc < 2) { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return (TCL_ERROR); } // printf("GraphView::command: %s\n", argv[1]); return (View::command(cd, tcl, argc, argv)); }

group.cc


/* * Copyright (c) 1997 by the University of Southern California * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation in source and binary forms for non-commercial purposes * and without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both the copyright notice and * this permission notice appear in supporting documentation. and that * any documentation, advertising materials, and other materials related * to such distribution and use acknowledge that the software was * developed by the University of Southern California, Information * Sciences Institute. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about * the suitability of this software for any purpose. THIS SOFTWARE IS * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Other copyrights might apply to parts of this software and are so * noted when applicable. * * $Header$ */ #include <string.h> #include "group.h" Group::Group(const char *name, unsigned int addr) : Animation(0, 0), size_(0), addr_(addr), name_(0) { if (name != NULL) if (*name != 0) { name_ = new char[strlen(name)+1]; strcpy(name_, name); } nodeHash_ = new Tcl_HashTable; Tcl_InitHashTable(nodeHash_, TCL_ONE_WORD_KEYS); } Group::~Group() { if (name_ != NULL) delete name_; Tcl_DeleteHashTable(nodeHash_); delete nodeHash_; } int
Group::join(int id) { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(nodeHash_, (const char *)id, &newEntry); if (he == NULL) return -1; if (newEntry) { Tcl_SetHashValue(he, (ClientData)id); size_++; } return 0; } void Group::leave(int id) { Tcl_HashEntry *he = Tcl_FindHashEntry(nodeHash_, (const char *)id); if (he != NULL) { Tcl_DeleteHashEntry(he); size_--; } } // Assume mbrs has at least size_ elements void Group::get_members(int *mbrs) { Tcl_HashEntry *he; Tcl_HashSearch hs; int i = 0; for (he = Tcl_FirstHashEntry(nodeHash_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs), i++) mbrs[i] = (int) Tcl_GetHashValue(he); } void Group::draw(View */*nv*/, double /*now*/) const { // Do nothing for now. Will add group visualization later. }

lan.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sincos.h" #include "config.h" #include "lan.h" #include "edge.h" #include "packet.h" #include "node.h" #include "view.h" #include "psview.h" #include "paint.h" #include "netmodel.h" #include "trace.h" LanLink::LanLink(Edge *e): edge_(e) { /*need to search through the destination node's links to find the link that's the twin of this one (i.e, same nodes, other direction) */ int lan=e->src(); Node *n=e->neighbor(); Edge *te=n->links(); while (te!=NULL) { if (te->dst()==lan) { pair_=te; break; } te=te->next_; } } int
LanLink::placed() { return edge_->neighbor()->marked(); } Lan::Lan(const char *name, NetModel *nm, double ps, double bw, double delay, double angle) : Animation(0,0), nm_(nm), links_(NULL), ps_(ps), bw_(bw), delay_(delay), angle_(angle), marked_(0), max_(0) { virtual_node_=new VirtualNode(name, this); name_ = new char[strlen(name) + 1]; strcpy(name_, name); ln_ = atoi(name); /*XXX*/ paint_ = Paint::instance()->thick(); dropHash_ = new Tcl_HashTable; // XXX: unique packet id == (src, dst, id). Its size may be changed later. Tcl_InitHashTable(dropHash_, 3); } Lan::~Lan() { if (dropHash_ != NULL) { Tcl_DeleteHashTable(dropHash_); delete dropHash_; } } float Lan::distance(float /*x*/, float /*y*/) const { // TODO: to be added return HUGE_VAL; } static int to_the_left(Edge *e, double angle, int incoming) { double ea=e->angle(); if (incoming) ea= 1.0 + ea; if (ea>2.0) ea-=2.0; double a=angle-ea; if (a<0) a+=2.0; if (a>1.0) { return 1; } else { return 0; } } void Lan::add_link(Edge *e) { int left=-1; int right=-1; LanLink *ll = new LanLink(e); ll->next(links_); links_=ll; virtual_node_->add_link(e); /*Keep track of how long the "bus" is*/ ll=links_; while (ll!=NULL) { if (to_the_left(ll->edge(), angle_,0)) { left++; } else { right++; } ll=ll->next(); } if (max_<left) max_=left; if (max_<right) max_=right; } void Lan::update_bb() { double s,c; SINCOSPI(angle_,&s,&c); bb_.xmin = x_ - size_*c, bb_.xmax = x_+size_*c*(2*max_+1); bb_.ymin = y_ - size_*s, bb_.ymax = y_+size_*s*(2*max_+1); } void Lan::draw(class View* nv, double /*time*/) const { double s,c; SINCOSPI(angle_,&s,&c); nv->line(x_-size_*c, y_-size_*s, x_+size_*c*(2*max_+1), y_+size_*s*(2*max_+1), paint_); } //void Lan::draw(class PSView* nv, double /*time*/) const { /* double s,c; SINCOSPI(angle_,&s,&c); nv->line(x_-size_*c, y_-size_*s, x_+size_*c*(2*max_+1), y_+size_*s*(2*max_+1), paint_); } */ void Lan::remove_drop(const TraceEvent &e) { int id[3]; id[0] = e.pe.src; id[1] = e.pe.dst; id[2] = e.pe.pkt.id; Tcl_HashEntry *he = Tcl_FindHashEntry(dropHash_, (const char *)id); if (he != NULL) { TraceEvent *pe = (TraceEvent *)Tcl_GetHashValue(he); delete pe; Tcl_DeleteHashEntry(he); } } void Lan::register_drop(const TraceEvent &e) { int newEntry = 1; int id[3]; id[0] = e.pe.src; id[1] = e.pe.dst; id[2] = e.pe.pkt.id; Tcl_HashEntry *he = Tcl_CreateHashEntry(dropHash_, (const char *)id, &newEntry); if (he == NULL) return; if (newEntry) { TraceEvent *pe = new TraceEvent; *pe = e; Tcl_SetHashValue(he, (ClientData)pe); } } void Lan::arrive_packet(Packet *p, Edge *e, double atime) { /*need to duplicate the packet on all other links except the arrival link*/ LanLink *l=links_; PacketAttr pkt; int id[3]; pkt.size=p->size(); pkt.id=p->id(); pkt.attr=p->attr(); strcpy(pkt.type,p->type()); strcpy(pkt.convid,p->convid()); while (l!=NULL) { Edge *ne=l->edge(); if (l->pair()!=e) { // Packet *np = nm_->newPacket(pkt, ne, atime); nm_->newPacket(pkt, ne, atime); id[0] = ne->src(); id[1] = ne->dst(); id[2] = p->id(); Tcl_HashEntry *he = Tcl_FindHashEntry(dropHash_, (const char *)id); if (he != NULL) { // This is a drop packet, fake a trace event and add a drop TraceEvent *pe = (TraceEvent *)Tcl_GetHashValue(he); pe->time = atime; // The fact that this trace event is still there implies that // we are going forwards. nm_->add_drop(*pe, atime, FORWARDS); delete pe; Tcl_DeleteHashEntry(he); } } l=l->next(); } rgb *color = Paint::instance()->paint_to_rgb(p->paint()); paint_ = Paint::instance()->lookup(color->colorname, 5); } void Lan::delete_packet(Packet *) { paint_ = Paint::instance()->thick(); } double Lan::x(Edge *e) const { double s,c; SINCOSPI(angle_,&s,&c); LanLink *l=links_; int incoming=-1; int left=-1; int right=-1; while (l!=NULL) { if (to_the_left(l->edge(), angle_,0)) { left++; } else { right++; } if (l->pair()==e) { incoming=1; break; } else if (l->edge()==e) { incoming=0; break; } l=l->next(); } if (to_the_left(e, angle_, incoming)) { return x_+c*left*2*size_; } else { return x_+c*right*2*size_; } } double Lan::y(Edge *e) const { double s,c; SINCOSPI(angle_,&s,&c); LanLink *l=links_; int incoming=-1; int left=-1; int right=-1; while (l!=NULL) { if (to_the_left(l->edge(), angle_,0)) { left++; } else { right++; } if (l->pair()==e) { incoming=1; break; } else if (l->edge()==e) { incoming=0; break; } l=l->next(); } if (to_the_left(e, angle_, incoming)) { return y_+s*left*2*size_; } else { return y_+s*right*2*size_; } } #ifdef NOTDEF Edge *Lan::lookupEdge(Node *n) { LanNode *ln=nodes_; while(ln!=NULL) { if (ln->node()==n) { return ln->e1_; } } return NULL; } #endif

main.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifndef WIN32 #include <unistd.h> #else #include <windows.h> #endif #include "netview.h" #include "tclcl.h" #include "trace.h" #include "paint.h" #include "state.h" extern "C" { #include <tk.h> } static void usage() { fprintf(stderr, "\ Usage: nam [-a -S -s -f init_script -d display -j jump -r rate -k initPort] \ <tracefile| -m tracefiles>\n\ \n\ -a: create a new nam instance\n\ -S: synchronize X\n\ -s: synchronize multiple traces\n -m: open multiple trace files at once\n -j: startup time\n\ -r: initial animation rate\n\ -f: initialization OTcl script\n\ -k: initial socket port number\n"); exit(1); } #ifdef WIN32 extern "C" int getopt(int, char**, char*); #endif extern "C" char *optarg; extern "C" int optind; const char* disparg(int argc, const char*const* argv, const char* optstr) { const char* display = 0; int op; while ((op = getopt(argc, (char**)argv, (char*)optstr)) != -1) { if (op == 'd') { display = optarg; break; } } optind = 1; return (display); } const char* namearg(int argc, const char*const* argv, const char* optstr) { const char* appname = 0; int op; while ((op = getopt(argc, (char**)argv, (char*)optstr)) != -1) { if (op == 'N') { appname = optarg; break; } } optind = 1; return (appname); } #include "bitmap/play.xbm" #include "bitmap/back.xbm" #include "bitmap/stop.xbm" #include "bitmap/eject.xbm" #include "bitmap/rew.xbm" #include "bitmap/ff.xbm" #include "bitmap/monitors.xbm" #include "bitmap/time.xbm" #include "bitmap/zoomin.xbm" #include "bitmap/zoomout.xbm" #include "bitmap/pullright.xbm" #include "bitmap/mark1.xbm" #include "bitmap/mark2.xbm" #include "bitmap/mark3.xbm" #include "bitmap/mark4.xbm" #include "bitmap/mark5.xbm" #include "bitmap/mark6.xbm" #include "bitmap/mark7.xbm" #include "bitmap/mark8.xbm" #include "bitmap/updir.xbm" //#include "bitmap/edit.xbm" #include "bitmap/nodeup.xbm" #include "bitmap/nodedown.xbm" #include "bitmap/select.xbm" #include "bitmap/addnode.xbm" #include "bitmap/addlink.xbm" #include "bitmap/cut.xbm" #include "bitmap/netedit.xbm" #include "bitmap/netview.xbm" void loadbitmaps(Tcl_Interp* tcl) { // Tk_DefineBitmap(tcl, Tk_GetUid("edit"), // edit_bits, edit_width, edit_height); Tk_DefineBitmap(tcl, Tk_GetUid("netedit"), netedit_bits, netedit_width, netedit_height); Tk_DefineBitmap(tcl, Tk_GetUid("netview"), netview_bits, netview_width, netview_height); Tk_DefineBitmap(tcl, Tk_GetUid("nodeup"), nodeup_bits, nodeup_width, nodeup_height); Tk_DefineBitmap(tcl, Tk_GetUid("nodedown"), nodedown_bits, nodedown_width, nodedown_height); Tk_DefineBitmap(tcl, Tk_GetUid("play"), play_bits, play_width, play_height); Tk_DefineBitmap(tcl, Tk_GetUid("back"), back_bits, back_width, back_height); Tk_DefineBitmap(tcl, Tk_GetUid("stop"), stop_bits, stop_width, stop_height); Tk_DefineBitmap(tcl, Tk_GetUid("eject"), eject_bits, eject_width, eject_height); Tk_DefineBitmap(tcl, Tk_GetUid("rew"), rew_bits, rew_width, rew_height); Tk_DefineBitmap(tcl, Tk_GetUid("ff"), ff_bits, ff_width, ff_height); Tk_DefineBitmap(tcl, Tk_GetUid("monitors"), monitors_bits, monitors_width, monitors_height); Tk_DefineBitmap(tcl, Tk_GetUid("time"), time_bits, time_width, time_height); Tk_DefineBitmap(tcl, Tk_GetUid("zoomin"), zoomin_bits, zoomin_width, zoomin_height); Tk_DefineBitmap(tcl, Tk_GetUid("zoomout"), zoomout_bits, zoomout_width, zoomout_height); Tk_DefineBitmap(tcl, Tk_GetUid("pullright"), pullright_bits, pullright_width, pullright_height); Tk_DefineBitmap(tcl, Tk_GetUid("select"), select_bits, select_width, select_height); Tk_DefineBitmap(tcl, Tk_GetUid("addnode"), addnode_bits, addnode_width, addnode_height); Tk_DefineBitmap(tcl, Tk_GetUid("addlink"), addlink_bits, addlink_width, addlink_height); Tk_DefineBitmap(tcl, Tk_GetUid("cut"), cut_bits, cut_width, cut_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark1"), mark1_bits, mark1_width, mark1_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark2"), mark2_bits, mark2_width, mark2_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark3"), mark3_bits, mark3_width, mark3_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark4"), mark4_bits, mark4_width, mark4_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark5"), mark5_bits, mark5_width, mark5_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark6"), mark6_bits, mark6_width, mark6_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark7"), mark7_bits, mark7_width, mark7_height); Tk_DefineBitmap(tcl, Tk_GetUid("mark8"), mark8_bits, mark8_width, mark8_height); Tk_DefineBitmap(tcl, Tk_GetUid("updir"), updir_bits, updir_width, updir_height); } void adios() { exit(0); } static int cmd_adios(ClientData , Tcl_Interp* , int , char **) { adios(); /*NOTREACHED*/ return (0); } extern "C" char version[]; static int cmd_version(ClientData , Tcl_Interp* tcl, int , char **) { tcl->result = version; return (TCL_OK); } char* parse_assignment(char* cp) { cp = strchr(cp, '='); if (cp != 0) { *cp = 0; return (cp + 1); } else return ("true"); } static void process_geometry(Tk_Window tk, char* geomArg) { /* * Valid formats: * <width>x<height>[+-]<x>[+-]<y> or * <width>x<height> or * [+-]x[+-]y */ Tcl &tcl = Tcl::instance(); const int numArgs = 4; char **geomArgv = new char*[numArgs]; for (int i = 0; i < numArgs; i++) geomArgv[i] = new char[80]; geomArgv[0][0] = '\0'; sprintf(geomArgv[1], "geometry"); sprintf(geomArgv[2], Tk_PathName(tk)); // previously optarg, changed to geomArg which is passed in sprintf(geomArgv[3], geomArg); if (Tk_WmCmd(tk, tcl.interp(), numArgs, geomArgv) != TCL_OK) { fprintf(stderr, "nam: %s\n", tcl.result()); exit(1); } delete geomArgv; } // What is it used for??? // extern "C" void Blt_Init(Tcl_Interp*); #ifdef WIN32 EXTERN int platformInit(Tcl_Interp* interp); #endif /* TkPlatformInit was moved to tkUnixInit.c */ #if defined(WIN32) && defined(STATIC_LIB) #include <tkWin.h> #include <stdlib.h> extern "C" { extern BOOL APIENTRY Tk_LibMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved); extern BOOL APIENTRY Tcl_LibMain(HINSTANCE hInstance, DWORD reason, LPVOID reserved); /* procedure to call before exiting to clean up */ void static_exit(void) { HINSTANCE hInstance = Tk_GetHINSTANCE(); Tcl_LibMain(hInstance, DLL_PROCESS_DETACH, NULL); Tk_LibMain(hInstance, DLL_PROCESS_DETACH, NULL); } } #endif /* defined(WIN32) && defined(STATIC_LIB) */ #ifdef HAVE_LIBTCLDBG extern "C" { extern int Tcldbg_Init(Tcl_Interp *); // hackorama } #endif void die(char *s) { fprintf(stderr, "%s", s); exit (1); } /*ARGSUSED*/ int main(int argc, char **argv) { const char* script = 0; // configurations to be loaded const char* optstr = "d:M:j:pG:r:u:X:t:i:P:g:N:c:S:f:asmk:zk:"; char multiple_traces = 0; /* * We have to initialize libtcl and libtk if we are under Win32 * and we are using static version of libtcl8.0p2 and libtk8.0p2. * Because in those distributions, Sun only supports DLL, but * not static lib. They require initializations in DllMain(). * The Berkeley folks (tecklee) built static versions by * forcing calls to DllMain() inside WinMain(). Because nam * is built as a console app in win32, we have to do those * initializations here, in main(). */ #if defined(WIN32) && defined(STATIC_LIB) HINSTANCE hInstance = GetModuleHandle(NULL); Tcl_LibMain(hInstance, DLL_PROCESS_ATTACH, NULL); Tk_LibMain(hInstance, DLL_PROCESS_ATTACH, NULL); atexit(static_exit); #endif /* * Process display option here before the rest of the options * because it's needed when creating the main application window. */ const char* display = disparg(argc, argv, optstr); // hold pointer to application name for send const char* appname = namearg(argc, argv, optstr); if (!appname) appname = "nam"; #ifdef notdef fprintf(stderr, "Application name is %s\n", appname); #endif Tcl_Interp *interp = Tcl_CreateInterp(); #if 0 if (Tcl_Init(interp) == TCL_ERROR) { printf("%s\n", interp->result); abort(); } #endif #if TCL_MAJOR_VERSION < 8 Tcl_SetVar(interp, "tcl_library", "./lib/tcl7.6", TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tk_library", "./lib/tk4.2", TCL_GLOBAL_ONLY); #else Tcl_SetVar(interp, "tcl_library", "./lib/tcl8.0", TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tk_library", "./lib/tk8.0", TCL_GLOBAL_ONLY); #endif if (Otcl_Init(interp) == TCL_ERROR) { printf("%s\n", interp->result); abort(); } #ifdef HAVE_LIBTCLDBG if (Tcldbg_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #endif Tcl::init(interp, appname); Tcl& tcl = Tcl::instance(); tcl.evalf(display? "set argv \"-name %s -display %s\"" : "set argv \"-name %s\"", appname, display, appname); Tk_Window tk = 0; #ifdef WIN32 Tcl_SetVar(interp, "tcl_library", ".", TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tk_library", ".", TCL_GLOBAL_ONLY); #endif if (Tk_Init(tcl.interp()) == TCL_OK) tk = Tk_MainWindow(tcl.interp()); if (tk == 0) { fprintf(stderr, "nam: %s\n", interp->result); Tcl_DeleteInterp(interp); exit(1); } tcl.tkmain(tk); extern EmbeddedTcl et_tk, et_nam; et_tk.load(); et_nam.load(); int op; int cacheSize = 100; char* graphInput = new char[256]; char* graphInterval = new char[256]; char* buf = new char[256]; char* args = new char[256]; graphInput[0] = graphInterval[0] = buf[0] = args[0] = 0; while ((op = getopt(argc, (char**)argv, (char*)optstr)) != -1) { switch (op) { default: usage(); case 'd': case 'N': /* already handled before */ break; /*XXX move to Tcl */ #ifdef notyet case 'M': tcl.add_option("movie", optarg); break; case 'p': tcl.add_option("pause", "1"); break; case 'G': tcl.add_option("granularity", optarg); break; case 'X': { const char* value = parse_assignment(optarg); tcl.add_option(optarg, value); } break; case 'P': /* Peer name, obsoleted */ sprintf(buf, "p %s ", optarg); strcat(args, buf); break; case 't': /* Use tkgraph. Must supply tkgraph input filename. */ sprintf(graphInput, "g %s ", optarg); strcat(args, graphInput); break; #endif case 'a': /* * Create a whole new instance. */ strcat(args, "a 1 "); break; case 'c': cacheSize = atoi(optarg); break; case 'f': case 'u': script = optarg; /* Also pass it to OTcl */ sprintf(buf, "f %s ", optarg); strcat(args, buf); break; case 'g': process_geometry(tk, optarg); break; case 'i': /* * Interval value for graph updates: default is * set by nam_init. */ sprintf(graphInterval, "i %s ", optarg); strcat(args, graphInterval); break; case 'j': /* Initial startup time */ sprintf(buf, "j %s ", optarg); strcat(args, buf); break; case 'k': /* Initial socket port number */ sprintf(buf, "k %s ", optarg); strcat(args, buf); break; case 'm': /* Multiple traces */ multiple_traces = 1; strcat(args, "m 1"); break; case 'r': /* Initial animation rate */ sprintf(buf, "r %s ", optarg); strcat(args, buf); break; case 's': /* synchronize all windows together */ strcat(args, "s 1 "); break; case 'z': /* set nam validation test on */ strcat(args, "z 1 "); break; #ifndef WIN32 case 'S': XSynchronize(Tk_Display(tk), True); break; #endif } } if (strlen(graphInterval) && !strlen(graphInput)) { fprintf(stderr, "nam: missing graph input file\n"); exit(1); } loadbitmaps(interp); char* tracename = NULL; /* trace file */ char* layoutname = NULL; /* layout/topology file */ /* * Linux libc-5.3.12 has a bug where if no arguments are processed * optind stays at zero. Work around that problem here. * The work-around seems harmless in other OSes so it's not ifdef'ed. */ if ((optind == -1) || (optind == 0)) optind = 1; /* * Make sure the base name of the trace and topology files * was specified. */ // if (argc - optind < 1) // usage(); tracename = argv[optind]; //XXX need to port this #ifndef WIN32 if ((tracename != NULL) && (!multiple_traces)) { if (access(tracename, R_OK) < 0) { tracename = new char[strlen(argv[optind]) + 4]; sprintf(tracename, "%s.nam", argv[optind]); } } #endif if ((argc - optind > 1) && (!multiple_traces)) { ++optind; layoutname = argv[optind]; //XXX need to port this #ifndef WIN32 if (access(layoutname, R_OK) < 0) { layoutname = new char[strlen(argv[optind]) + 5]; sprintf(layoutname, "%s.tcl", argv[optind]); } #endif } else if ((tracename != NULL) && (!multiple_traces)) { layoutname = new char[strlen(tracename) + 3]; strcpy(layoutname, tracename); char *cp = strrchr(layoutname, '.'); if (cp != 0) *cp = 0; strcat(layoutname, ".tcl"); } tcl.CreateCommand("adios", cmd_adios); tcl.CreateCommand("version", cmd_version); #ifdef WIN32 platformInit(interp); #endif #ifdef LAYOUTFILE if (layoutname != NULL) tcl.EvalFile(layoutname); #endif // XXX inappropriate to do initialization in this way? FILE *fp = fopen(".nam.tcl", "r"); if (fp != NULL) { fclose(fp); tcl.EvalFile(".nam.tcl"); } // User-supplied configuration files // option '-u' and '-f' are merged together // Evaluation is moved into OTcl // if (script != NULL) { // fp = fopen(script, "r"); // if (fp != NULL) { // fclose(fp); // tcl.EvalFile(script); // } else { // fprintf(stderr, "No configuration file %s\n", // script); // } // } Paint::init(); State::init(cacheSize); if (tracename != NULL) { for (int done = 0; (!done) && (tracename);) { #ifdef WIN32 tracename = strdup(tracename); if (*cp == '\\') *cp = '/'; #endif tcl.evalf("nam_init %s %s", tracename, args); if (multiple_traces) { tracename = argv[++optind]; } else done = 1; } } else tcl.evalf("nam_init \"\" %s", args); Tk_MainLoop(); return (0); }

monitor.cc


class Node; #include "config.h" #include "stdio.h" #include "monitor.h" #include "animation.h" #include "netview.h" #include "paint.h" Monitor::Monitor(int mon_num, Animation *a, double size) : mon_num_(mon_num), anim_(a), size_(size) { paint_=Paint::instance()->thin(); mon_state_=a->monitor_state(); sprintf(label_, "%d", mon_num); } Monitor::~Monitor() { if (mon_state_!=NULL) delete(mon_state_); } void
Monitor::update(double now, char *result, int len) { if (anim_!=NULL) anim_->monitor(this, now, result, len); else sprintf(result, "Not visible"); } void Monitor::size(double size) { size_=size; } /*XXX there must be a cleaner way to do this*/ /*we need coordinates from the animation itself, and information about the size of the whole model from the netmodel. Thus we have two draw methods, one from the animation that sets up data and one from the netmodel that actually does the drawing*/ void Monitor::draw(View */*nv*/, float x, float y) { x_=x; y_=y; } void Monitor::draw_monitor(View *nv, float ymin, float /*ymax*/) const { if (anim_==NULL) return; float delta = 0.5 * size_; nv->line(x_,y_,x_,ymin-delta,paint_); nv->rect(x_-delta, ymin-delta, x_+delta, ymin-(size_+delta), paint_); nv->string(x_, ymin-size_, size_, label_, ANCHOR_CENTER); } void Monitor::delete_monitor_object(Animation *m) { /*need to check this because we can sometimes hand a monitor over to a new animation just before the old animation calls this*/ if (anim_==m) anim_=NULL; }

nam_stream.cc


/* * Copyright (c) 1998 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * */ #include <stdlib.h> #include <sys/types.h> #ifdef WIN32 #include <limits.h> #else #include <values.h> #endif #include <assert.h> #ifndef WIN32 extern "C" off_t tell(); extern "C" double atof(); #endif #include <tclcl.h> #include "trace.h" #include "nam_stream.h" /**********************************************************************/ class NamStreamClass : public TclClass { public: NamStreamClass() : TclClass("NamStream") {} TclObject* create(int argc, const char*const* argv) { if (argc < 5) return 0; return NamStream::open(argv[4]); } } NamStream_class; int
NamStream::command(int argc, const char *const *argv) { Tcl& tcl = Tcl::instance(); if (0) { } else if (argc == 2 && strcmp(argv[1], "gets") == 0) { if (eof()) return TCL_ERROR; // return a line char *buf = tcl.buffer(); assert(4096 > TRACE_LINE_MAXLEN+1); // can the buffer handle us? gets(buf, TRACE_LINE_MAXLEN); buf[TRACE_LINE_MAXLEN] = 0; // paranoia tcl.result(buf); return TCL_OK; } else if (argc == 2 && strcmp(argv[1], "close") == 0) { close(); return TCL_OK; } else if (argc == 2 && strcmp(argv[1], "eof") == 0) { tcl.resultf("%d", eof()); return TCL_OK; }; return (TclObject::command(argc, argv)); } NamStream * NamStream::open(const char *fn) { if (strcmp(fn, "-") == 0 || strcmp(fn, "-.nam") == 0) { // XXX #if 1 return new NamStreamPipe(fn); #else fprintf(stderr, "nam does not currently support reading from stdin.\n"); return NULL; #endif }; if (strcmp(fn + strlen(fn) - 3, ".gz") == 0 || strcmp(fn + strlen(fn) - 2, ".Z") == 0) { #ifdef HAVE_ZLIB_H return new NamStreamCompressedFile(fn); #else /* ! HAVE_ZLIB */ fprintf(stderr, "nam not built with zlib; cannot read compressed files.\n"); return NULL; #endif /* HAVE_ZLIB */ }; /* hope we've got it now */ return new NamStreamFile(fn); } /* * rgets (gets in reverse order) * isn't used by nam, but probably should be. */ char * NamStream::rgets(char *buf, int len) { int ch; /* * prior-line \n current-line \n next-line * * Initially the cursor is on the n of next-line. * read in current-line (which is behind us) * return it * leave the cursor on c of current line. */ /* first make sure we back over the prior newline, if any */ if (seek(-1, SEEK_CUR) < 0) return NULL; ch = get_char(); if (seek(ch == '\n' ? -2 : -1, SEEK_CUR) < 0) return NULL; /* now loop backwards until we get to the newline separating * prior and current. */ off_t pos = tell(); for(;;) { ch = get_char(); if (ch == '\n') break; if (pos == 0) { // beginning of file if (seek(-1, SEEK_CUR) < 0) return NULL; break; } // back up a char & try again pos--; if (seek(-2, SEEK_CUR) < 0) return NULL; }; /* we're just passed the newline for prior-line, or we're at 0 */ /* read current-line, then reset the pointer there */ gets(buf, len); if (pos != seek(pos, SEEK_SET)) return NULL; return buf; } /**********************************************************************/ #if 0 NamStreamFile::NamStreamFile(int fd) : NamStream(fd) { file_ = fdopen(fd, "r"); is_open_ = (NULL != file_); } #endif /* 0 */ NamStreamFile::NamStreamFile(const char *fn) : NamStream(fn) { file_ = fopen(fn, "r"); is_open_ = (NULL != file_); if (!is_open_) perror(fn); } char * NamStreamFile::gets(char *buf, int len) { return fgets(buf, len, file_); } char NamStreamFile::get_char() { return getc(file_); } off_t NamStreamFile::seek(off_t offset, int whence) { if (0 == fseek(file_, offset, whence)) return ftell(file_); else return -1; } off_t NamStreamFile::tell() { return ftell(file_); } int NamStreamFile::close() { int e = fclose(file_); file_ = NULL; return e; } int NamStreamFile::eof() { return feof(file_); } int NamStreamFile::read(char *buf, int size) { return fread(buf, 1, size, file_); } /**********************************************************************/ #ifdef HAVE_ZLIB_H /* * Beware: * nam *requires* zlib-1.1.3, as we trip over bugs in 1.1.2's gz* functions. */ NamStreamCompressedFile::NamStreamCompressedFile(const char *fn) : NamStream(fn) { #ifndef ZLIB_VERSION die("zlib version not specified.\n"); int a, b, c; if (3 != sscanf(ZLIB_VERSION, "%d.%d.%d", &a, &b, &c)) { die("zlib version: unknown format.\n"); }; if (!(a > 1 || (a == 1 && b > 1) || (a == 1 && b == 1 && c >= 3))) die("zlib version is too old, nam requires 1.1.3.\n"); #endif file_ = gzopen(fn, "r"); is_open_ = (NULL != file_); } char * NamStreamCompressedFile::gets(char *buf, int len) { char *b = gzgets(file_, buf, len); return b; } char NamStreamCompressedFile::get_char() { return gzgetc(file_); } off_t NamStreamCompressedFile::seek(off_t offset, int whence) { if (whence == SEEK_END) { /* * zlib doesn't support SEEK_END :-< * Walk our way to the end-of-file. */ off_t p = gzseek(file_, 0, SEEK_SET), q; #define STEP (16*1024) char buf[STEP]; int count; for (;;) { /* * Sigh. We actually move all the bytes. XXX * (we can't lseek because we'd lseek * past eof without knowing). */ count = gzread(file_, buf, STEP); if (count <= 0) break; p += count; }; q = gztell(file_); assert (p == q); return q; } else { return gzseek(file_, offset, whence); }; } off_t NamStreamCompressedFile::tell() { return gztell(file_); } int NamStreamCompressedFile::close() { int e = gzclose(file_); file_ = NULL; return e; } int NamStreamCompressedFile::eof() { return gzeof(file_); } int NamStreamCompressedFile::read(char *buf, int size) { int e = gzread(file_, buf, size); return e; } #endif /* HAVE_ZLIB */ /**********************************************************************/ FILE *NamStreamPipe::persistent_front_ = 0; FILE *NamStreamPipe::persistent_back_ = 0; NamStreamPipe::NamStreamPipe(const char *fn) : NamStream(fn), front_(NULL), back_(NULL), back_len_(0) { /* * As a special hack for nam we never close the files * but instead keep them in persistent_*. * This allows nam to open/close/reopen stdin * while doing the right thing. * Better suggestions are welcome; restructuring nam's * front end (the Right Thing) was deemed harder. * * The really bad news about this hack is it makes this * code not at all re-entrant (although one only has one stdin). */ if (persistent_front_) { front_ = persistent_front_; back_ = persistent_back_; if (-1 == fseek(back_, 0, SEEK_END)) die("NamStreamPipe::NamStreamPipe fseek"); back_len_ = ftell(back_); if (-1 == fseek(back_, 0, SEEK_SET)) die("NamStreamPipe::NamStreamPipe fseek"); is_open_ = 1; } else { /* dup stdin */ persistent_front_ = front_ = fdopen(0, "r"); persistent_back_ = back_ = tmpfile(); is_open_ = front_ && back_; }; } void NamStreamPipe::insure_backing(off_t lim) { if (lim <= back_len_) return; if (feof(front_)) return; // read data up to lim off_t where = ftell(back_); // save where we were fseek(back_, 0, SEEK_END); #ifndef STEP #define STEP (16*1024) #endif char buf[STEP]; while (back_len_ < lim) { /* * We may need to set up the input * in some kind of non-blocking mode if * reading in STEP chunks is too bursty. */ ////////////////////////////////////////////////////////// //ARUN // int in_count = fread(buf, 1, STEP, front_); //Read in as much as we can, but don't block everything if there //isn't anything to read if(fgets(buf, STEP, front_) == NULL) break; //error or eof with no chars read in int in_count = strlen(buf); ///////////////////////////////////////////////////////// if (in_count <= 0) // error or eof break; int out_count = fwrite(buf, 1, in_count, back_); if (out_count == -1) perror("error writing NamStreamPipe backing file.\n"); else { if (out_count < in_count) fprintf(stderr, "NamStreamPipe::insure_backing: out of space for nam backing file (in /tmp)\n"); back_len_ += out_count; }; }; if (-1 == fseek(back_, where, SEEK_SET)) { die("fseek problem in NamStreamPipe::insure_backing.\n"); }; } char * NamStreamPipe::gets(char *buf, int len) { insure_backing(tell() + len); char *b = fgets(buf, len, back_); return b; } char NamStreamPipe::get_char() { insure_backing(tell() + 1); return getc(back_); } off_t NamStreamPipe::seek(off_t offset, int whence) { off_t lim; switch(whence) { case SEEK_SET: lim = offset; break; case SEEK_CUR: lim = tell() + offset; break; case SEEK_END: lim = MAXLONG; break; // XXX: MAXINT may not be max(off_t) } insure_backing(lim); if (0 == fseek(back_, offset, whence)) return ftell(back_); else return -1; } off_t NamStreamPipe::tell() { return ftell(back_); } int NamStreamPipe::close() { /* * Don't actually close them because we might need them later. */ int e = 0; // e = fclose(back_); // e = fclose(front_); back_ = front_ = NULL; return e; } int NamStreamPipe::eof() { if (feof(front_)) return feof(back_); else return 0; } int NamStreamPipe::read(char *buf, int len) { insure_backing(tell() + len); int e = fread(buf, 1, len, back_); return e; }

netgraph.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #include <ctype.h> #include <math.h> #include "config.h" #include "graphview.h" #include "netgraph.h" #include "paint.h" #include "sincos.h" #include "state.h" #include "bbox.h" #include <float.h> extern int lineno; //static int next_pat; /*XXX */ class NetworkGraphClass : public TclClass { public: NetworkGraphClass() : TclClass("NetworkGraph") {} TclObject* create(int /*argc*/, const char*const* /*argv*/) { return (new NetGraph); } } networkgraph_class; class EnergyNetworkGraphClass : public TclClass { public: EnergyNetworkGraphClass() : TclClass("EnergyNetworkGraph") {} TclObject* create(int /*argc*/, const char*const* /*argv*/) { return (new EnergyNetGraph); } } energynetworkgraph_class; class LinkNetworkGraphClass : public TclClass { public: LinkNetworkGraphClass() : TclClass("LinkNetworkGraph") {} TclObject* create(int /*argc*/, const char*const* /*argv*/) { return (new LinkNetGraph); } } linknetworkgraph_class; class FeatureNetworkGraphClass : public TclClass { public: FeatureNetworkGraphClass() : TclClass("FeatureNetworkGraph") {} TclObject* create(int /*argc*/, const char*const* /*argv*/) { return (new FeatureNetGraph); } } featurenetworkgraph_class; NetGraph::NetGraph() : views_(NULL), minx_(0), maxx_(0), miny_(0.0), maxy_(0.0), time_(0.0), tix_(-1) { int i; for (i = 0; i < MAX_GRAPH; i++) graphdata_[i]=0.0; Paint *paint = Paint::instance(); int p = paint->thin(); ncolors_ = 8; paint_ = new int[ncolors_]; for (i = 0; i < ncolors_; ++i) paint_[i] = p; paint_[1]=paint->lookup("red",1); } EnergyNetGraph::EnergyNetGraph() : NetGraph() { } LinkNetGraph::LinkNetGraph() : NetGraph(), src_(-1), dst_(-1) { } NetGraph::~NetGraph() { } EnergyNetGraph::~EnergyNetGraph() { } LinkNetGraph::~LinkNetGraph() { } void
NetGraph::update(double /*now*/) { } void NetGraph::update(double /*now*/, Animation* /*a*/) { } /* Reset all animations and queues to time 'now'. */ void NetGraph::reset(double /*now*/) { } void NetGraph::render(GraphView* view) { int i; if (miny_!=maxy_) { for(i=0;i<maxx_-minx_;i++) { if (scaleddata_[i]!=0) view->line(i, 0, i, scaleddata_[i], paint_[0]); } //draw the current time line view->line(tix_, 0, tix_, maxy_, paint_[1]); } else { view->string((double)minx_, 0.5, 0.5, "No such events found in tracefile.", ANCHOR_WEST); } } void NetGraph::BoundingBox(BBox& bb) { int i; minx_=int(bb.xmin); maxx_=int(bb.xmax); int newtix=int(time_*(maxx_-minx_)/(maxtime_-mintime_)); if (newtix!=tix_) { tix_=newtix; } for(i=0;i<maxx_-minx_;i++) { scaleddata_[i]=0.0; } maxy_=0.0; /*Note: storing the data in an array like this is quick, but introduces some aliasing effects in the scaling process. I think they're negligable for this purpose but if we really want to remove them we must store the unscaled data in a list instead*/ for(i=0;i<MAX_GRAPH;i++) { int ix = int(((float)(i*(maxx_-minx_)))/MAX_GRAPH); scaleddata_[ix]+=graphdata_[i]; if (scaleddata_[ix]>maxy_) maxy_=scaleddata_[ix]; } if (miny_!=maxy_) { bb.ymin=miny_; bb.ymax=maxy_; } else { bb.ymin=0.0; bb.ymax=1.0; } } /* Trace event handler. */ void NetGraph::handle(const TraceEvent& e, double /*now*/, int /*direction*/) { switch (e.tt) { case 'v': /* 'variable' -- just execute it as a tcl command */ break; case 'h': printf("hop\n"); break; case 'a': printf("agent\n"); break; case 'f': printf("feature\n"); break; case 'r': printf("receive\n"); break; case '+': printf("enqueue\n"); break; case '-': printf("dequeue\n"); break; case 'l': printf("link\n"); break; case 'n': printf("node\n"); break; case 'R': printf("Route\n"); break; case 'd': printf("drop\n"); break; } } /* Trace event handler. */ void EnergyNetGraph::handle(const TraceEvent& e, double /*now*/, int /*direction*/) { switch (e.tt) { case 'g': int timeix = int(((e.time-mintime_)*MAX_GRAPH)/(maxtime_-mintime_)); for (int i=timeix; i< MAX_GRAPH ; i++) graphdata_[i]+=1; if (graphdata_[timeix]>maxy_) maxy_=graphdata_[timeix]; break; } } /* Trace event handler. */ void LinkNetGraph::handle(const TraceEvent& e, double /*now*/, int /*direction*/) { switch (e.tt) { case 'h': if (gtype_==GR_BW) { if ((e.pe.src==src_) && (e.pe.dst==dst_)) { int timeix = int(((e.time-mintime_)*MAX_GRAPH)/(maxtime_-mintime_)); graphdata_[timeix]+=e.pe.pkt.size; if (graphdata_[timeix]>maxy_) maxy_=graphdata_[timeix]; } } break; case 'd': fflush(stdout); if (gtype_==GR_LOSS) { if ((e.pe.src==src_) && (e.pe.dst==dst_)) { fflush(stdout); int timeix = int(((e.time-mintime_)*MAX_GRAPH)/(maxtime_-mintime_)); graphdata_[timeix]+=1; if (graphdata_[timeix]>maxy_) maxy_=graphdata_[timeix]; } } break; } } int NetGraph::command(int argc, const char *const *argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "view") == 0) { /* * <net> view <viewName> * Create the window for the network layout/topology. */ GraphView *v = new GraphView(argv[2], this); v->next_ = views_; views_ = v; return (TCL_OK); } if (strcmp(argv[1], "settime") == 0) { if (argc == 3) { time_=atof(argv[2]); GraphView *view = views_; int newtix=int(time_*(maxx_-minx_)/(maxtime_-mintime_)); if (newtix!=tix_) { while(view!=NULL) { view->draw(); view=view->next_; } tix_=newtix; } return (TCL_OK); } else { tcl.resultf("\"%s\": arg mismatch", argv[0]); return (TCL_ERROR); } } } if (argc == 4 && strcmp(argv[1], "timerange") == 0) { mintime_=atof(argv[2]); maxtime_=atof(argv[3]); return (TCL_OK); } /* If no NetModel commands matched, try the Object commands. */ return (TclObject::command(argc, argv)); } int EnergyNetGraph::command(int argc, const char *const *argv) { return (NetGraph::command(argc, argv)); } int LinkNetGraph::command(int argc, const char *const *argv) { //Tcl& tcl = Tcl::instance(); if (argc == 4) { // printf("command: %s %s %s\n", argv[1],argv[2],argv[3]); if (strcmp(argv[1], "bw") == 0) { src_=atoi(argv[2]); dst_=atoi(argv[3]); gtype_=GR_BW; return (TCL_OK); } if (strcmp(argv[1], "loss") == 0) { src_=atoi(argv[2]); dst_=atoi(argv[3]); gtype_=GR_LOSS; return (TCL_OK); } } /* If no NetModel commands matched, try the Object commands. */ return (NetGraph::command(argc, argv)); } /************/ FeatureNetGraph::FeatureNetGraph() : NetGraph(), src_(-1), aname_(0), vname_(0), lastix_(0) { } FeatureNetGraph::~FeatureNetGraph() { } int FeatureNetGraph::command(int argc, const char *const *argv) { if (argc == 5) { if (strcmp(argv[1], "feature") == 0) { src_ = atoi(argv[2]); aname_ = new char[strlen(argv[3]) + 1]; strcpy(aname_, argv[3]); vname_ = new char[strlen(argv[4]) + 1]; strcpy(vname_, argv[4]); return(TCL_OK); } } return (NetGraph::command(argc, argv)); } void FeatureNetGraph::handle(const TraceEvent& e, double /*now*/, int /*direction*/) { switch (e.tt) { case 'f': // print the source, the agent, name, value // print records we care about if (src_ == e.fe.src && (strcmp(aname_, e.fe.feature.agent) == 0) && (strcmp(vname_, e.fe.feature.name) == 0)) { /* printf("Feature %d %s %s %s\n", e.fe.src, e.fe.feature.agent, e.fe.feature.name, e.fe.feature.value); */ /* start out doing what is done in LinkNetGraph::handle */ int timeix = int(((e.time-mintime_)*MAX_GRAPH)/(maxtime_-mintime_)); graphdata_[timeix]+=atof(e.fe.feature.value); // printf("%d %g\n", timeix, graphdata_[timeix]); if (graphdata_[timeix]>maxy_) maxy_=graphdata_[timeix]; /* fill in any points we may have missed */ int i; double lastval = graphdata_[lastix_]; for (i = lastix_ + 1; i < timeix; i++) { graphdata_[i] = lastval; } lastix_ = timeix; } break; default: break; } } /* following is a hack to get around the aliasing effects referred to * in the comments in NetGraph::BoundingBox. It works for those data * sets I've tested it with, but it could produce undesired results * in some cases. */ void FeatureNetGraph::BoundingBox(BBox& bb) { int i; minx_=int(bb.xmin); maxx_=int(bb.xmax); int newtix=int(time_*(maxx_-minx_)/(maxtime_-mintime_)); if (newtix!=tix_) { tix_=newtix; } for(i=0;i<maxx_-minx_;i++) { scaleddata_[i]=0.0; } maxy_=1.0; /*Note: storing the data in an array like this is quick, but introduces some aliasing effects in the scaling process. I think they're negligable for this purpose but if we really want to remove them we must store the unscaled data in a list instead*/ for(i=0;i<MAX_GRAPH;i++) { int ix = int(((float)(i*(maxx_-minx_)))/MAX_GRAPH); scaleddata_[ix]=graphdata_[i]; if (scaleddata_[ix]>maxy_) maxy_=scaleddata_[ix]; } if (miny_!=maxy_) { bb.ymin=miny_; bb.ymax=maxy_; } else { bb.ymin=0.0; bb.ymax=1.0; } }

netmodel.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <stdio.h> #include <ctype.h> #include <math.h> #include <tcl.h> #include <tclcl.h> #include "config.h" #include "netview.h" #include "psview.h" #include "testview.h" #include "animation.h" #include "group.h" #include "tag.h" #include "queue.h" #include "drop.h" #include "packet.h" #include "edge.h" #include "lan.h" #include "node.h" #include "agent.h" #include "feature.h" #include "route.h" #include "netmodel.h" #include "monitor.h" #include "trace.h" #include "paint.h" #include "sincos.h" #include "state.h" #include "editview.h" #include "address.h" #include "animator.h" #include <float.h> extern int lineno; // not used //static int next_pat; /*XXX */ double defsize = 0.; class NetworkModelClass : public TclClass { public: NetworkModelClass() : TclClass("NetworkModel") {} TclObject* create(int argc, const char*const* argv) { if (argc < 5) return 0; return (new NetModel(argv[4])); } } networkmodel_class; NetModel::NetModel(const char *animator) : TraceHandler(animator), drawables_(0), animations_(0), queues_(0) , selectedSrc_(-1), selectedDst_(-1), selectedFid_(-1) , hideSrc_(-1), hideDst_(-1), hideFid_(-1) , wireless_(0), colorSrc_(-1), colorDst_(-1), colorFid_(-1) ,selectedColor_(-1), showData_(1), showRouting_(1), showMac_(1) , resetf_(0), views_(0), nodes_(0), lans_(0), mon_count_(0), monitors_(NULL), nGroup_(0), nTag_(0), node_sizefac_(NODE_EDGE_RATIO) { int i; for (i = 0; i < EDGE_HASH_SIZE; ++i) hashtab_[i] = 0; for (i = 0; i < PTYPELEN; ++i) { selectedTraffic_[i] = '\0' ; colorTraffic_[i] = '\0' ; hideTraffic_[i] = '\0' ; } /*XXX*/ nymin_ = 1e6; nymax_ = -1e6; Paint *paint = Paint::instance(); int p = paint->thin(); // Initially 256 colors. Can be extended later. // See handling of otcl binding "color" nclass_ = 256; paintMask_ = 0xff; paint_ = new int[nclass_]; oldpaint_ = new int[nclass_]; for (i = 0; i < nclass_; ++i) { paint_[i] = p; oldpaint_[i] = p; } addrHash_ = new Tcl_HashTable; Tcl_InitHashTable(addrHash_, TCL_ONE_WORD_KEYS); grpHash_ = new Tcl_HashTable; Tcl_InitHashTable(grpHash_, TCL_ONE_WORD_KEYS); tagHash_ = new Tcl_HashTable; Tcl_InitHashTable(tagHash_, TCL_STRING_KEYS); objnameHash_ = new Tcl_HashTable; Tcl_InitHashTable(objnameHash_, TCL_STRING_KEYS); registerObjName("ALL", ClassAllID); registerObjName("ANIMATION", ClassAnimationID); registerObjName("NODE", ClassNodeID); registerObjName("PACKET", ClassPacketID); registerObjName("EDGE", ClassEdgeID); registerObjName("QUEUEITEM", ClassQueueItemID); registerObjName("LAN", ClassLanID); registerObjName("TAG", ClassTagID); registerObjName("AGENT", ClassAgentID); } NetModel::~NetModel() { // We should delete everything here, if we want deletable netmodel... delete paint_; Animation *a, *n; for (a = animations_; a != 0; a = n) { n = a->next(); delete a; } for (a = drawables_; a != 0; a = n) { n = a->next(); delete a; } Tcl_DeleteHashTable(grpHash_); delete grpHash_; Tcl_DeleteHashTable(tagHash_); delete tagHash_; Tcl_DeleteHashTable(objnameHash_); delete objnameHash_; } void
NetModel::update(double now) { Animation *a, *n; for (a = animations_; a != 0; a = n) { n = a->next(); a->update(now); } /* * Draw all animations and drawables on display to reflect * current time. */ now_ = now; for (View* p = views_; p != 0; p = p->next_) { p->draw(); } } void NetModel::update(double now, Animation* a) { // XXX Seems we should have a->update(now) here. a->update(now); for (View* p = views_; p != 0; p = p->next_) a->draw(p, now); } /* Reset all animations and queues to time 'now'. */ void NetModel::reset(double now) { Animation* a; for (a = animations_; a != 0; a = a->next()) a->reset(now); for (a = drawables_; a != 0; a = a->next()) a->reset(now); for (Queue* q = queues_; q != 0; q = q->next_) q->reset(now); } /* * Draw this NetModel's animations and drawables (nodes, edges, * packets, queues). */ void NetModel::render(View* view) { Animation *a; Monitor *m; for (a = drawables_; a != 0; a = a->next()) a->draw(view, now_); for (a = animations_; a != 0; a = a->next()) a->draw(view, now_); for(m=monitors_; m != NULL; m = m->next()) m->draw_monitor(view, nymin_, nymax_); } void NetModel::render(PSView* view) { Animation *a; for (a = drawables_; a != 0; a = a->next()) a->draw(view, now_); for (a = animations_; a != 0; a = a->next()) a->draw(view, now_); } void NetModel::render(TestView* view) { Animation *a; for (a = drawables_; a != 0; a = a->next()) a->draw(view, now_); for (a = animations_; a != 0; a = a->next()) a->draw(view, now_); } /* Return a pointer to the edge between 'src' and 'dst'. */ NetModel::EdgeHashNode* NetModel::lookupEdge(int src, int dst) const { EdgeHashNode* h; for (h = hashtab_[ehash(src, dst)]; h != 0; h = h->next) if (h->src == src && h->dst == dst) break; return (h); } int NetModel::addAddress(int id, int addr) const { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(addrHash_, (const char *)addr, &newEntry); if (he == NULL) return -1; if (newEntry) { Tcl_SetHashValue(he, (ClientData)id); } return 0; } int NetModel::addr2id(int addr) const { Tcl_HashEntry *he = Tcl_FindHashEntry(addrHash_, (const char *)addr); if (he == NULL) return -1; return (int)Tcl_GetHashValue(he); } void NetModel::enterEdge(Edge* e) { int src = e->src(); int dst = e->dst(); EdgeHashNode *h = lookupEdge(src, dst); if (h != 0) { /* XXX */ fprintf(stderr, "nam: duplicate edge (%d,%d)\n", src, dst); //exit(1); return; } h = new EdgeHashNode; h->src = src; h->dst = dst; h->queue = 0; h->edge = e; int k = ehash(src, dst); h->next = hashtab_[k]; hashtab_[k] = h; } void NetModel::removeEdge(Edge* e) { int src = e->src(); int dst = e->dst(); EdgeHashNode *h = lookupEdge(src, dst); if (h == 0) { /* XXX */ fprintf(stderr, "nam: trying to delete nonesisting edge (%d,%d)\n", src, dst); exit(1); } //XXX do we need to process queue ? leave it to the future 10/01/98 EdgeHashNode *f,*g; int k = ehash(src, dst); for (f = hashtab_[k]; f != 0; f = f->next) { if (h->src == f->src && h->dst == f->dst) { if (f == hashtab_[k]) { hashtab_[k] = f->next; break; } else { g->next = f->next; break; } } g = f; } delete h; } /* XXX Make this cheaper (i.e. cache it) */ void NetModel::BoundingBox(BBox& bb) { /* ANSI C limits, from float.h */ bb.xmin = bb.ymin = FLT_MAX; bb.xmax = bb.ymax = -FLT_MAX; for (Animation* a = drawables_; a != 0; a = a->next()) a->merge(bb); } /* Animation* NetModel::inside(double now, float px, float py) const { for (Animation* a = animations_; a != 0; a = a->next()) if (a->inside(now, px, py)) return (a); for (Animation* d = drawables_; d != 0; d = d->next()) if (d->inside(now, px, py)) return (d); return (0); } */ // Used exclusively for start_info() in nam.tcl. It ignores all tag objects // and therefore should *not* be used for editing. Animation* NetModel::inside(float px, float py) const { for (Animation* a = animations_; a != 0; a = a->next()) { if (a->type() == BPACKET) { BPacket* b = (BPacket* ) a ; if ((b->inside(px, py)) && (a->classid() != ClassTagID)) return (a); } else { if ((a->inside(px, py)) && (a->classid() != ClassTagID)) return (a); } } for (Animation* d = drawables_; d != 0; d = d->next()) { if ((d->inside(px, py) && (d->classid() != ClassTagID))) return (d); } return (0); } int NetModel::add_monitor(Animation *a) { Monitor *m = new Monitor(mon_count_, a, node_size_); m->next(monitors_); monitors_=m; return mon_count_++; } int NetModel::monitor(double now, int monitor, char *result, int len) { /*XXX should get rid of this search*/ for(Monitor *m=monitors_; m!=NULL; m=m->next()) { if (m->monitor_number()==monitor) { m->update(now, result, len); if (strlen(result)==0) delete_monitor(m); return 0; } } result[0]='\0'; return -1; } void NetModel::check_monitors(Animation *a) { /*A new animation just got created. Check to see if we should already*/ /*have a monitor on it*/ MonState *ms=a->monitor_state(); if (ms==NULL) return; for(Monitor *m=monitors_; m!=NULL; m=m->next()) { if ((m->mon_state_!=NULL)&&(m->mon_state_->type=ms->type)) { switch (ms->type) { case MON_PACKET: if (m->mon_state_->pkt.id==ms->pkt.id) { m->anim(a); delete ms; return; } break; case MON_ROUTE: if ((m->mon_state_->route.src==ms->route.src)&& (m->mon_state_->route.group==ms->route.group)) { m->anim(a); delete ms; return; } break; } } } } void NetModel::delete_monitor(int monitor) { /*this version of delete_monitor is called from the GUI*/ /*given a monitor, remove it from the model's monitor list*/ Monitor *tm1, *tm2; if (monitors_==NULL) return; tm1=monitors_; tm2=monitors_; while ((tm1!=NULL)&&(tm1->monitor_number()!=monitor)) { tm2=tm1; tm1=tm1->next(); } if (tm1!=NULL) { tm2->next(tm1->next()); if (tm1==monitors_) monitors_=tm1->next(); if (tm1->anim()!=NULL) tm1->anim()->remove_monitor(); delete tm1; } } void NetModel::delete_monitor(Monitor *m) { /*given a monitor, remove it from a node's agent list*/ Monitor *tm1, *tm2; if (monitors_==NULL) return; tm1=monitors_; tm2=monitors_; while ((tm1!=m)&&(tm1!=NULL)) { tm2=tm1; tm1=tm1->next(); } if (tm1!=NULL) { tm2->next(tm1->next()); if (tm1==monitors_) monitors_=tm1->next(); tm1->anim()->remove_monitor(); delete tm1; } } void NetModel::delete_monitor(Animation *a) { /*given a monitor, remove it from a node's agent list*/ /*this version gets called when an animation deletes itself*/ /*XXX animations sometimes get deleted when the packet changed link*/ Monitor *tm1, *tm2; if (monitors_==NULL) return; tm1=monitors_; tm2=monitors_; while ((tm1!=NULL)&&(tm1->anim()!=a)) { tm2=tm1; tm1=tm1->next(); } if (tm1!=NULL) { tm2->next(tm1->next()); if (tm1==monitors_) monitors_=tm1->next(); delete tm1; } } void NetModel::saveState(double tim) { State* state = State::instance(); StateInfo min; min.time = 10e6; min.offset = 0; Animation *a, *n; StateInfo si; /* * Update the animation list first to remove any unnecessary * objects in the list. */ for (a = animations_; a != 0; a = n) { n = a->next(); a->update(tim); } for (a = animations_; a != 0; a = n) { n = a->next(); si = a->stateInfo(); if (si.time < min.time) min = si; } if (min.offset) state->set(tim, min); } /* Trace event handler. */ void NetModel::handle(const TraceEvent& e, double now, int direction) { QueueItem *q; EdgeHashNode *ehn, *ehnrev; Edge* ep; Node *n; //Packet *p; Route *r; Agent *a; Feature *f; float x, y; int pno; double txtime; if (e.time > State::instance()->next()) saveState(e.time); switch (e.tt) { case 'v': /* 'variable' -- just execute it as a tcl command */ { if (nam_ == 0) { fprintf(stderr, "Couldn't evaluate %s without animator\n", e.image); break; } const char *p = e.image + e.ve.str; char *q = new char[strlen(nam_->name()) + strlen(p) + 2]; sprintf(q, "%s %s", nam_->name(), p); Tcl::instance().eval(q); delete []q; break; } case 'h': //traffic filter if (wireless_) { if (strcmp(e.pe.pkt.wtype,"AGT") == 0 ) return ; if (!showData_) { // filter out data packet if ((strcmp(e.pe.pkt.wtype,"RTR") == 0 ) || (strcmp(e.pe.pkt.wtype,"MAC") == 0 )) { if (((strcmp(e.pe.pkt.type,"cbr") == 0)|| (strcmp(e.pe.pkt.type,"tcp") == 0) || (strcmp(e.pe.pkt.type,"ack") == 0))) return ; } } if (!showRouting_){ // filter out routing packet if (strcmp(e.pe.pkt.wtype,"RTR") == 0 ) { if (!((strcmp(e.pe.pkt.type,"cbr") == 0)|| (strcmp(e.pe.pkt.type,"tcp") == 0) || (strcmp(e.pe.pkt.type,"ack") == 0))) return ; } } if (!showMac_){ // filter out routing packet if (strcmp(e.pe.pkt.wtype,"MAC") == 0 ) { if (!((strcmp(e.pe.pkt.type,"cbr") == 0)|| (strcmp(e.pe.pkt.type,"tcp") == 0) || (strcmp(e.pe.pkt.type,"ack") == 0))) return ; } } } //show only packet with same chracteristics as selected packet if (selectedSrc_ != -1) { //filter being trigger if (e.pe.pkt.esrc != selectedSrc_ ) return ; } if (selectedDst_ != -1) { if (e.pe.pkt.edst != selectedDst_ ) return ; } if (selectedFid_ != -1) { if (atoi(e.pe.pkt.convid) != selectedFid_ ) return ; } if (selectedTraffic_[0] != '\0') { if (strcmp(e.pe.pkt.type,selectedTraffic_) != 0 ) return ; } //hide packet with same chracteristics as selected packet if (hideSrc_ != -1) { //filter being trigger if (e.pe.pkt.esrc == hideSrc_ ) return ; } if (hideDst_ != -1) { if (e.pe.pkt.edst == hideDst_ ) return ; } if (hideFid_ != -1) { if (atoi(e.pe.pkt.convid) == hideFid_ ) return ; } if (hideTraffic_[0] != '\0') { if (strcmp(e.pe.pkt.type,hideTraffic_) == 0 ) return ; } //change the packet color on the fly if (selectedColor_ < 0 ) { Paint *paint = Paint::instance(); selectedColor_ = paint->lookup("black",1); } if (colorSrc_ != -1) { if (e.pe.pkt.esrc == colorSrc_ ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (colorDst_ != -1) { if (e.pe.pkt.edst == colorDst_ ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (colorFid_ != -1) { if (atoi(e.pe.pkt.convid) == colorFid_ ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (colorTraffic_[0] != '\0') { if (strcmp(e.pe.pkt.type,colorTraffic_) == 0 ) paint_[atoi(e.pe.pkt.convid)] = selectedColor_ ; } if (resetf_) paint_[atoi(e.pe.pkt.convid)] = oldpaint_[atoi(e.pe.pkt.convid)] ; if (e.pe.dst == -1) { //broadcasting //a quick hack to give fixed transmission + delay time for //broadcasting packet if ((direction==FORWARDS) && (e.time + BPACKET_TXT_TIME < now)) break ; if ((direction==BACKWARDS) && (e.time - BPACKET_TXT_TIME > now)) break ; n = lookupNode(e.pe.src); BPacket *p = new BPacket(n->x(), n->y(),e.pe.pkt, e.time,e.offset,direction); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); break; } if (direction==BACKWARDS) break; //ehn = lookupEdge(addr2id(e.pe.src), addr2id(e.pe.dst)); ehn = lookupEdge(e.pe.src, e.pe.dst); if (ehn == 0 || (ep = ehn->edge) == 0) return; /* * If the current packet will arrive at its destination * at a later time, insert the arrival into the queue * of animations and set its paint id (id for X graphics * context. */ txtime = ep->txtime(e.pe.pkt.size); if (e.time + txtime + ep->GetDelay() >= now) { /* XXX */ Packet *p = new Packet(ep, e.pe.pkt, e.time, txtime, e.offset); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); #ifdef DEBUG printf("packet %d sent from %d towards %d\n", e.pe.pkt.id, e.pe.src, e.pe.dst); #endif } break; case 'a': n = lookupNode(e.ae.src); if (n == 0) return; a = n->find_agent((char *) e.ae.agent.name); if ((direction==FORWARDS)&&(e.ae.agent.expired==0)) { if (a == NULL) { // will only create an agent if there isn't one already // there with the same name a = new BoxAgent(e.ae.agent.name, n->size()); a->insert(&animations_); n->add_agent(a); placeAgent(a, n); } } else { if (a != NULL) { n->delete_agent(a); delete a; } } break; case 'f': // We don't need any redraw for this, because it's always // displayed in monitors in a separate pane n = lookupNode(e.fe.src); if (n == 0) return; a = n->find_agent((char *)e.fe.feature.agent); if (a == 0) return; f = a->find_feature((char *)e.fe.feature.name); if (f == 0) { switch (e.fe.feature.type) { case 'v': f = new VariableFeature(a, e.fe.feature.name); break; case 'l': f = new ListFeature(a, e.fe.feature.name); break; case 's': case 'u': case 'd': f = new TimerFeature(a, e.fe.feature.name); break; } a->add_feature(f); } if (((direction==FORWARDS)&&(e.fe.feature.expired==0))|| ((direction==BACKWARDS)&&(strlen(e.fe.feature.oldvalue)>0))) { char *value; double time_set; if (direction==FORWARDS) { value=(char *)e.fe.feature.value; time_set=now; } else { value=(char *)e.fe.feature.oldvalue; /*XXX need an extra value here*/ time_set=0.0; } switch (e.fe.feature.type) { case 'v': case 'l': f->set_feature(value); break; case 's': f->set_feature(atof(value), TIMER_STOPPED, time_set); break; case 'u': f->set_feature(atof(value), TIMER_UP, time_set); break; case 'd': f->set_feature(atof(value), TIMER_DOWN, time_set); break; } } else { a->delete_feature(f); delete f; } break; case 'r': if (direction==FORWARDS) break; //ehn = lookupEdge(addr2id(e.pe.src), addr2id(e.pe.dst)); ehn = lookupEdge(e.pe.src, e.pe.dst); if (ehn == 0 || (ep = ehn->edge) == 0) return; /* * If the current packet will arrive at its destination * at a later time, insert the arrival into the queue * of animations and set its paint id (id for X graphics * context. */ txtime = ep->txtime(e.pe.pkt.size); if (e.time - (txtime + ep->GetDelay()) <= now) { /* XXX */ Packet *p = new Packet(ep, e.pe.pkt, e.time-(ep->GetDelay()+txtime), txtime, e.offset); p->insert(&animations_); p->paint(paint_[e.pe.pkt.attr & paintMask_]); check_monitors(p); } break; case '+': ehn = lookupEdge(e.pe.src, e.pe.dst); if (direction==FORWARDS) { if (ehn != 0 && ehn->queue != 0) { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); ehn->queue->enque(qi,QUEUE_TAIL); qi->insert(&animations_); check_monitors(qi); } } else { if (ehn != 0 && ehn->queue != 0) { q = ehn->queue->remove(e.pe.pkt); delete q; } } break; case '-': ehn = lookupEdge(e.pe.src, e.pe.dst); if (direction==FORWARDS) { if (ehn != 0 && ehn->queue != 0) { q = ehn->queue->remove(e.pe.pkt); delete q; } } else { if (ehn != 0 && ehn->queue != 0) { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); ehn->queue->enque(qi,QUEUE_HEAD); qi->insert(&animations_); check_monitors(qi); } } break; case 'E': { // Nothing for now Group *grp = lookupGroup(e.pe.dst); if (grp == NULL) { fprintf(stderr, "Packet destination group %d not found\n", e.pe.dst); return; } int *mbr = new int[grp->size()]; grp->get_members(mbr); for (int i = 0; i < grp->size(); i++) { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); n = lookupNode(mbr[i]); if (n == 0) { fprintf(stderr, "Group member %d not found\n", mbr[i]); return; } if (direction == FORWARDS) { n->queue()->enque(qi, QUEUE_TAIL); qi->insert(&animations_); check_monitors(qi); } else { qi = n->queue()->remove(e.pe.pkt); delete qi; } } delete mbr; break; } case 'D': { n = lookupNode(e.pe.dst); if (n == NULL) { fprintf(stderr, "Bad node id %d for session deque event\n", e.pe.dst); return; } if (direction == FORWARDS) { q = n->queue()->remove(e.pe.pkt); delete q; } else { QueueItem *qi = new QueueItem(e.pe.pkt, e.time, e.offset); qi->paint(paint_[e.pe.pkt.attr & paintMask_]); n->queue()->enque(qi, QUEUE_HEAD); qi->insert(&animations_); check_monitors(qi); } break; } case 'P': /* session drop */ /* Get packet to drop. */ if (direction==FORWARDS) { #ifdef DEBUG printf("drop on %d -> %d\n", e.pe.src, e.pe.dst); #endif n = lookupNode(e.pe.dst); if (n == 0) return; q=0; if (n->queue()!=0) { /* Remove packet from session queue */ q = n->queue()->remove(e.pe.pkt); if (q == 0) { /* No such packet in queue??? */ fprintf(stderr, "No packet drop %id in queue\n", e.pe.pkt.id); return; } #ifdef DEBUG printf("packet %d dropped from queue\n", e.pe.pkt.id); #endif q->position(x, y); pno = q->paint(); delete q; } /* * Compute the point at which the dropped packet disappears. * Let's just make this sufficiently far below the lowest * thing on the screen. * * Watch out for topologies that have all their nodes lined * up horizontally. In this case, nymin_ == nymax_ == 0. * Set the bottom to -0.028. This was chosen empirically. * The nam display was set to the maximum size and the lowest * position on the display was around -0.028. */ float bot; if (nymin_ == nymax_ && nymin_ == 0.) bot = -0.03; else bot = nymin_ - (nymax_ - nymin_); Drop *d = new Drop(x, y, bot, n->size()*0.5, /* This is a hack */ e.time, e.offset, e.pe.pkt); d->paint(pno); d->insert(&animations_); check_monitors(d); break; } else { /*direction is BACKWARDS - need to create the packet*/ } case 'G': { /* Group event */ Group *grp = lookupGroup(e.ge.src); if (grp == NULL) { grp = new Group(e.ge.grp.name, e.ge.src); add_group(grp); } if (e.ge.grp.flag == GROUP_EVENT_JOIN) { grp->join(e.ge.grp.mbr); // XXX // Hard-coded queue angle for session queues. :( // Create session queue here because they are not like // traditional queues which are created when nam // started. Group member may dynamically join/leave, // so may session queues. We create them here because // there's a 1-1 relationship between join and creating // session queues. n = lookupNode(e.ge.grp.mbr); if (n == NULL) { fprintf(stderr, "Bad node %d for group event\n", e.ge.grp.mbr); return; } // Need more consideration on the placement of these queues Queue *q = new Queue(0.5); q->next_ = queues_; queues_ = q; n->add_sess_queue(e.ge.src, q); } else if (e.ge.grp.flag == GROUP_EVENT_LEAVE) // No deletion of session queues. grp->leave(e.ge.grp.mbr); break; } case 'l': /*link event*/ ehn = lookupEdge(e.le.src, e.le.dst); ehnrev = lookupEdge(e.le.dst, e.le.src); /*note: many link events are bidirectional events so be careful to apply them to both a link and the reverse of it*/ if (ehn == 0) return; if (direction==FORWARDS) { // Always save the color before the last DOWN event if (strncmp(e.le.link.state, "DOWN", 4)==0) { ehn->edge->set_down("red"); ehnrev->edge->set_down("red"); } else if (strncmp(e.le.link.state, "UP", 2)==0) { /* XXX Assume an UP event always follows a DOWN event */ ehn->edge->set_up(); ehnrev->edge->set_up(); } else if (strncmp(e.le.link.state, "COLOR", 5) == 0) { ehn->edge->color((char *)e.le.link.color); ehnrev->edge->color((char *)e.le.link.color); } else if (strncmp(e.le.link.state, "DLABEL", 6) == 0) { ehn->edge->dlabel((char *)e.le.link.dlabel); ehnrev->edge->dlabel((char *)e.le.link.dlabel); } else if (strncmp(e.le.link.state, "DCOLOR", 6) == 0) { ehn->edge->dcolor((char *)e.le.link.dcolor); ehnrev->edge->dcolor((char *)e.le.link.dcolor); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.direction); ehnrev->edge->direction((char *)e.le.link.direction); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.direction); ehnrev->edge->direction((char *)e.le.link.direction); } } else { if (strncmp(e.le.link.state, "UP", 2)==0) { ehn->edge->set_down("red"); ehnrev->edge->set_down("red"); } else if (strncmp(e.le.link.state, "DOWN", 4)==0) { ehn->edge->set_up(); } else if (strncmp(e.le.link.state, "COLOR", 5) == 0) { ehn->edge->color((char *)e.le.link.oldColor); ehnrev->edge->color((char *)e.le.link.oldColor); } else if (strncmp(e.le.link.state, "DLABEL", 6) == 0) { ehn->edge->dlabel((char *)e.le.link.odlabel); ehnrev->edge->dlabel((char *)e.le.link.odlabel); } else if (strncmp(e.le.link.state, "DCOLOR", 6) == 0) { ehn->edge->dcolor((char *)e.le.link.odcolor); ehnrev->edge->dcolor((char *)e.le.link.odcolor); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.odirection); ehnrev->edge->direction((char *)e.le.link.odirection); } else if (strncmp(e.le.link.state, "DIRECTION", 9) == 0) { ehn->edge->direction((char *)e.le.link.odirection); ehnrev->edge->direction((char *)e.le.link.odirection); } } break; case 'n': /*node event*/ n = lookupNode(e.ne.src); if (n == 0) return; if (direction==FORWARDS) { if (strncmp(e.ne.node.state, "DOWN", 4)==0) { n->set_down("gray"); } else if (strncmp(e.ne.node.state, "UP", 2)==0) { n->set_up(); } else if (strncmp(e.ne.node.state, "COLOR", 5) == 0) { // normal color can be defined by user // XXX: why color is opposite when direction is opposite? n->color((char *)e.ne.node.color); n->lcolor((char *)e.ne.node.lcolor); } else if (strncmp(e.ne.node.state, "DLABEL", 6) == 0) { n->dlabel((char *)e.ne.node.dlabel); } else if (strncmp(e.ne.node.state, "DCOLOR", 6) == 0) { n->dcolor((char *)e.ne.node.dcolor); } else if (strncmp(e.ne.node.state, "DIRECTION", 9) == 0) { n->direction((char *)e.ne.node.direction); } } else { if (strncmp(e.ne.node.state, "UP", 4)==0) { n->set_down("gray"); } else if (strncmp(e.ne.node.state, "DOWN", 2)==0) { n->set_up(); } else if (strncmp(e.ne.node.state, "COLOR", 5) == 0) { n->color((char *)e.ne.node.oldColor); n->lcolor((char *)e.ne.node.olcolor); } else if (strncmp(e.ne.node.state, "DLABEL", 6) == 0) { n->dlabel((char *)e.ne.node.odlabel); } else if (strncmp(e.ne.node.state, "DCOLOR", 6) == 0) { n->dcolor((char *)e.ne.node.odcolor); } else if (strncmp(e.ne.node.state, "DIRECTION", 9) == 0) { n->direction((char *)e.ne.node.odirection); } } break; case 'm': /* node mark event */ NodeMark *cm; n = lookupNode(e.me.src); if (n == 0) return; cm = n->find_mark((char *) e.me.mark.name); if (direction == FORWARDS){ if (e.me.mark.expired == 0) { /* once created, a node mark cannot be changed*/ if (cm == NULL) n->add_mark((char *)e.me.mark.name, (char *)e.me.mark.color, (char *)e.me.mark.shape); } else /* expired */ n->delete_mark((char *)e.me.mark.name); } else { /* * backward: * (1) create it if expired == 1 * (2) delete it if expired == 0 */ if (e.me.mark.expired == 0) n->delete_mark((char *)e.me.mark.name); else { /* re-create the circle */ if (cm == NULL) n->add_mark((char *)e.me.mark.name, (char *)e.me.mark.color, (char *)e.me.mark.shape); } } break; case 'R': /*route event*/ if (((e.re.route.expired==0)&&(direction==FORWARDS))|| ((e.re.route.expired==1)&&(direction==BACKWARDS))) { /*this is a new route*/ n = lookupNode(e.re.src); if (n == 0) return; // XXX: What's these src and dst??? Are they id or address? */ ehn = lookupEdge(e.re.src, e.re.dst); if (ehn == 0) return; int oif=1; if (strncmp(e.re.route.mode, "iif", 3)==0) oif=0; r = new Route(n, ehn->edge, e.re.route.group, e.re.route.pktsrc, e.re.route.neg, oif, e.re.route.timeout, now); n->add_route(r); n->place_route(r); r->insert(&animations_); r->paint(paint_[e.re.route.group & paintMask_]); check_monitors(r); } else { /*an old route expired*/ n = lookupNode(e.re.src); if (n == 0) return; // XXX: What's these src and dst??? Are they id or address? */ ehn = lookupEdge(e.re.src, e.re.dst); if (ehn == 0) return; int oif=1; if (strncmp(e.re.route.mode, "iif", 3)==0) oif=0; r = n->find_route(ehn->edge, e.re.route.group, e.re.route.pktsrc, oif); if (r==0) { fprintf(stderr, "nam: attempt to delete non-existent route\n"); abort(); } n->delete_route(r); delete r; } break; case 'd': add_drop(e, now, direction); } } void NetModel::add_drop(const TraceEvent &e, double now, int direction) { EdgeHashNode *ehn; Edge *ep; QueueItem *q; Packet *p; Lan *lan; float x, y; double txtime; int pno; /* Get packet to drop. */ if (direction==FORWARDS) { #ifdef DEBUG printf("drop on %d -> %d\n", e.pe.src, e.pe.dst); #endif ehn = lookupEdge(e.pe.src, e.pe.dst); if (ehn == 0) return; q=0; if (ehn->queue!=0) { /*if there's a queue, try removing it from the queue first*/ /*queue drops are more common than link drops...*/ q = ehn->queue->remove(e.pe.pkt); } if (q == 0) { /*perhaps it's a link packet drop*/ p=lookupPacket(e.pe.src, e.pe.dst, e.pe.pkt.id); if (p!=NULL) { /*it was a link packet drop*/ #ifdef DEBUG printf("packet %d dropped on link %d->%d\n", e.pe.pkt.id, e.pe.src, e.pe.dst); #endif p->position(x, y, now); ehn->edge->DeletePacket(p); pno = p->paint(); delete p; } else if((lan = lookupLan(e.pe.src)) != NULL) { /* * If it's a Lan (selective) packet drop, which means * the packet is only dropped on some of the lan links, * register the packet on the lan and drop it when the * packet is actually transmitted to that lan link. * * When the packet is actually dropped, this function will be * called again, but at that time the packet will be actually * on the link and this code will not be executed. */ lan->register_drop(e); printf("packet %d will be dropped on lan link %d->%d\n", e.pe.pkt.id, e.pe.src, e.pe.dst); return; } else { /*probably it was a queue drop, but we're not displaying */ /*that queue*/ // It's possible that this packet is dropped directly from // the queue, even before the enqT_ module. In this case, // we should still produce a packet drop; we use the position // of the node to generate the drop. Node *s = lookupNode(e.pe.src); if (s == NULL) { fprintf(stderr, "add_drop(): cannot find src node.\n"); abort(); } x = s->x(), y = s->y(); pno = paint_[e.pe.pkt.attr & paintMask_]; } } else { #ifdef DEBUG printf("packet %d dropped from queue\n", e.pe.pkt.id); #endif q->position(x, y); pno = q->paint(); delete q; } /* * Compute the point at which the dropped packet disappears. * Let's just make this sufficiently far below the lowest * thing on the screen. * * Watch out for topologies that have all their nodes lined * up horizontally. In this case, nymin_ == nymax_ == 0. * Set the bottom to -0.028. This was chosen empirically. * The nam display was set to the maximum size and the lowest * position on the display was around -0.028. */ float bot; if (nymin_ == nymax_ && nymin_ == 0.) bot = -0.03; else bot = nymin_ - (nymax_ - nymin_); Drop *d = new Drop(x, y, bot, ehn->edge->PacketHeight(), e.time, e.offset, e.pe.pkt); d->paint(pno); d->insert(&animations_); check_monitors(d); return; } else { /*direction is BACKWARDS - need to create the packet*/ Lan *lan = lookupLan(e.pe.src); if (lan != NULL) { /* * We need to remove drop status in lans */ lan->remove_drop(e); printf("lan dropped packet %d is removed on lan link %d->%d\n", e.pe.pkt.id, e.pe.src, e.pe.dst); return; } } } void NetModel::addView(NetView* p) { p->next_ = views_; views_ = p; } Node *NetModel::lookupNode(int nn) const { for (Node* n = nodes_; n != 0; n = n->next_) if (n->num() == nn) return (n); /* XXX Do not exit, we need normal return. */ //fprintf(stderr, "nam: no such node %d\n", nn); //exit(1); return (0);// make visual c++ happy } void NetModel::removeNode(Node *n) { Node *p, *q; // Remove node n from nodes_ list, then delete it for (p = nodes_; p != 0; q = p, p = p->next_) if (p == n) break; if (p == nodes_) nodes_ = p->next_; else q->next_ = p->next_; delete p; } Agent *NetModel::lookupAgent(int id) const { for (Node* n = nodes_; n != 0; n = n->next_) for(Agent* a= n->agents(); a != 0; a = a->next_) if (a->number_ == id) return (a); return (0); } Lan *NetModel::lookupLan(int nn) const { for (Lan* l = lans_; l != 0; l = l->next_) if (l->num() == nn) return (l); /* XXX */ //fprintf(stderr, "nam: no such lan %d\n", nn); //exit(1); return (0);// make visual c++ happy } Packet *NetModel::newPacket(PacketAttr &pkt, Edge *e, double time) { /*this is called when we get a triggered event such as a packet getting duplicated within a LAN*/ Packet *p = new Packet(e, pkt, time, e->txtime(pkt.size), 0); p->insert(&animations_); p->paint(paint_[pkt.attr & paintMask_]); check_monitors(p); return p; } Packet *NetModel::lookupPacket(int src, int dst, int id) const { EdgeHashNode *h = lookupEdge(src, dst); if (h == 0) return NULL; int ctr=0; for (Packet *p=h->edge->packets(); p!=NULL; p=p->next()) { #define PARANOID #ifdef PARANOID ctr++; if (ctr>h->edge->no_of_packets()) abort(); #endif if (p->id() == id) return p; } /*have to fail silent or we can't cope with link drops when doing settime*/ return 0; } /* Do not delete groups, because they are not explicitly deleted */ int NetModel::add_group(Group *grp) { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(grpHash_, (const char *)grp->addr(), &newEntry); if (he == NULL) return -1; if (newEntry) { Tcl_SetHashValue(he, (ClientData)grp); nGroup_++; } return 0; } Group* NetModel::lookupGroup(unsigned int addr) { Tcl_HashEntry *he = Tcl_FindHashEntry(grpHash_, (const char *)addr); if (he == NULL) return NULL; return (Group *)Tcl_GetHashValue(he); } // Remove a view from the views link, but not delete it void NetModel::remove_view(View *v) { View *p, *q; p = q = views_; if (p == v) { views_ = p->next_; return; } while (p != NULL) { q = p; p = p->next_; if (p == v) { q->next_ = p->next_; return; } } } int NetModel::command(int argc, const char *const *argv) { Tcl& tcl = Tcl::instance(); int i; if (argc == 2) { if (strcmp(argv[1], "layout") == 0) { /* * <net> layout * Compute reasonable defaults for missing node or edge * sizes based on the maximum link delay. Lay out the * nodes and edges as specified in the layout file. */ scale_estimate(); placeEverything(); return (TCL_OK); } if (strcmp(argv[1], "showtrees") == 0) { /* * <net> showtrees */ color_subtrees(); for (View* p = views_; p != 0; p = p->next_) { p->draw(); } return (TCL_OK); } if (strcmp(argv[1],"resetFilter")==0) { resetf_ = 1 ; selectedSrc_ = -1 ; selectedDst_ = -1 ; selectedFid_ = -1 ; colorSrc_ = -1 ; colorDst_ = -1 ; colorFid_ = -1 ; hideSrc_ = -1 ; hideDst_ = -1 ; hideFid_ = -1 ; for (i = 0; i < PTYPELEN; ++i) { selectedTraffic_[i] = '\0' ; colorTraffic_[i] = '\0' ; hideTraffic_[i] = '\0' ; } return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "incr-nodesize") == 0) { /* * <net> incr-nodesize <factor> */ node_sizefac_ *= atof(argv[2]); for (Node *n = nodes_; n != 0; n = n->next_) for (Edge *e=n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { p->redrawModel(); p->draw(); } return (TCL_OK); } if (strcmp(argv[1], "decr-nodesize") == 0) { node_sizefac_ /= atof(argv[2]); for (Node *n = nodes_; n != 0; n = n->next_) for (Edge *e=n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { p->redrawModel(); p->draw(); } return(TCL_OK); } if (strcmp(argv[1], "view") == 0) { /* * <net> view <viewName> * Create the window for the network layout/topology. * Used for nam editor */ EditView *v = new EditView(argv[2], this, 300, 700); v->next_ = views_; views_ = v; return (TCL_OK); } if (strcmp(argv[1], "psview") == 0) { /* * <net> PSView <fileName> * Print the topology to a file */ PSView *v = new PSView(argv[2], this); v->render(); delete(v); return (TCL_OK); } if (strcmp(argv[1], "testview") == 0) { /* * Added for nam validation test */ TestView *v = new TestView(argv[2], this); v->render(); delete(v); return (TCL_OK); } if (strcmp(argv[1], "editview") == 0) { /* * <net> editview <viewname> */ EditView *v = new EditView(argv[2], this); // XXX should we insert it into views_??? v->next_ = views_; views_ = v; return (TCL_OK); } if (strcmp(argv[1],"savelayout")==0) { save_layout(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-traffic")==0) { strcpy(selectedTraffic_,argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-src")==0) { selectedSrc_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-dst")==0) { selectedDst_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-fid")==0) { selectedFid_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-traffic")==0) { strcpy(hideTraffic_,argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-src")==0) { hideSrc_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-dst")==0) { hideDst_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"hide-fid")==0) { hideFid_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-traffic")==0) { resetf_ = 0 ; strcpy(colorTraffic_,argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-src")==0) { resetf_ = 0 ; colorSrc_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-dst")==0) { resetf_ = 0 ; colorDst_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"color-fid")==0) { resetf_ = 0 ; colorFid_ = atoi(argv[2]); return (TCL_OK); } if (strcmp(argv[1],"select-color")==0) { Paint *paint = Paint::instance(); selectedColor_ = paint->lookup(argv[2], 1); if (selectedColor_ < 0) { fprintf(stderr,"%s color: no such color: %s\n", argv[0], argv[2]); selectedColor_ = paint->lookup("black",1); if (selectedColor_ < 0) { tcl.resultf("%s no black! - bailing"); return (TCL_ERROR); } } return (TCL_OK); } } else if (argc >= 4 && strcmp(argv[1], "node") == 0) { /* * <net> node <name> <shape> <color> <addr> [<size>] * Create a node using the specified name * and the default size and insert it into this * NetModel's list of drawables. */ double size = defsize; if (argc > 8) { wirelessNodeSize_ = size = atof(argv[6]); wireless_ = 1 ; } if (argc > 7) { size = atof(argv[6]); } // Enlarge wired node if the topology is a mixture of // wired and wireless network if ((wireless_) && (!size)) size = wirelessNodeSize_ ; /* * Check whether this node is already there. If so, * Delete it first */ Node *n = lookupNode(atoi(argv[2])); if (n != NULL) { fprintf(stderr, "duplicate node %s.\n", argv[2]); removeNode(n); } if (!strcmp(argv[3], "circle")) n = new CircleNode(argv[2], size); else if (!strcmp(argv[3], "box")) n = new BoxNode(argv[2], size); else n = new HexagonNode(argv[2], size); int addr = Address::instance().str2addr((char *)argv[5]); n->setaddr(addr); addAddress(n->num(), addr); n->init_color((char *)argv[4]); n->lcolor((char *)argv[7]); // dlabel initilization int dl_idx = -1; if (argc == 11) // Wireless with dlabel dl_idx = 10; else if (argc == 9) // Wired with dlabel dl_idx = 8; if (dl_idx > 0) n->dlabel((char *)argv[dl_idx]); // XXX xcor and ycor are ALWAYS the 8th and 9th arguments. if (argc > 9) { n->place(atof(argv[8]),atof(argv[9])); if (size != defsize) { n->size(size); } else { n->size(0.15); } } n->next_ = nodes_; nodes_ = n; n->insert(&drawables_); return (TCL_OK); } else if (argc >= 4 && strcmp(argv[1], "agent") == 0) { /* * <net> agent <label> <role> <node> <flowcolor> <winInit> * <win> <maxcwnd> * <tracevar> <start> <producemore> <stop> * <net> agent <label> <role> <node> <flowcolor> <packetSize> * <interval> <start> <stop> */ int node = atoi(argv[4]); int partner_num; Node *n = lookupNode(node); if (n == 0) { tcl.resultf("Node %d doesn't exist.", node); return (TCL_ERROR); } Agent *a = new BoxAgent((char *)argv[2], n->size()); if (a == 0) { tcl.resultf("Agent %s not exist at node %d", argv[2], node); return (TCL_ERROR); } placeAgent(a, n); a->node_ = n; n->add_agent(a); a->AgentRole_ = (atoi(argv[3])); if (a->AgentRole_ == 20) { a->number_ = (atoi(argv[5])); partner_num = (atoi(argv[6])); Agent *partner = lookupAgent(partner_num); if (partner) { a->AgentPartner_ = partner; partner->AgentPartner_ = a; } } else if ((a->AgentRole_ == 10) && (strcmp(argv[2], "CBR") == 0)) { if (strcmp(argv[5],"(null)")!=0) a->flowcolor((char *)argv[5]); a->packetSize(atoi(argv[6])); a->interval(atoi(argv[7])); a->startAt(atof(argv[8])); a->stopAt(atof(argv[9])); a->number_ = (atoi(argv[10])); partner_num = (atoi(argv[11])); Agent *partner = lookupAgent(partner_num); if (partner) { a->AgentPartner_ = partner; partner->AgentPartner_ = a; } } else if (a->AgentRole_ != 0) { if (strcmp(argv[5],"(null)")!=0) a->flowcolor((char *)argv[5]); a->windowInit(atoi(argv[6])); a->window(atoi(argv[7])); a->maxcwnd(atoi(argv[8])); a->tracevar((char *)argv[9]); a->startAt(atof(argv[10])); a->produce(atoi(argv[11])); a->stopAt(atof(argv[12])); a->number_ = (atoi(argv[13])); partner_num = (atoi(argv[14])); Agent *partner = lookupAgent(partner_num); if (partner) { a->AgentPartner_ = partner; partner->AgentPartner_ = a; } } a->insert(&animations_); return (TCL_OK); } else if (argc == 4) { if (strcmp(argv[1], "new_monitor_agent") == 0) { /* * <net> new_monitor_agent <node_id> <agent_name> */ int node = atoi(argv[2]); Node *n = lookupNode(node); if (n == 0) { tcl.resultf("Node %d doesn't exist.", node); return (TCL_ERROR); } Agent *a = n->find_agent((char *)argv[3]); if (a == 0) { tcl.resultf("Agent %s not exist at node %d", argv[3], node); return (TCL_ERROR); } tcl.resultf("%d", add_monitor(a)); return (TCL_OK); } if (strcmp(argv[1], "color") == 0) { /* * <net> color <packetClass> <colorName> * Display packets of the specified class using * the specified color. */ int c = atoi(argv[2]); // if ((unsigned int)c > 1024) { // tcl.resultf("%s color: class %d out of range", // argv[0], c); // return (TCL_ERROR); // } // Convert this color index to [0,255], so that // it matches correctly with packet flow ids. Paint *paint = Paint::instance(); if (c > nclass_) { int n, i; for (n = nclass_; n < c; n <<= 1); int *p = new int[n]; for (i = 0; i < nclass_; ++i) p[i] = paint_[i]; delete paint_; paint_ = p; nclass_ = n; paintMask_ = nclass_ - 1; int pno = paint->thin(); for (; i < n; ++i) paint_[i] = pno; } int pno = paint->lookup(argv[3], 1); if (pno < 0) { fprintf(stderr,"%s color: no such color: %s\n", argv[0], argv[3]); pno = paint->lookup("black",1); if (pno < 0) { tcl.resultf("%s no black! - bailing"); return (TCL_ERROR); } } paint_[c] = pno; oldpaint_[c] = pno; return (TCL_OK); } if (strcmp(argv[1], "ncolor") == 0) { /* * <net> ncolor <node> <colorName> * set color of node to the specified color. */ Paint *paint = Paint::instance(); Node *n = lookupNode(atoi(argv[2])); if (n == NULL) { fprintf(stderr, "No such node %s\n", argv[2]); exit(1); } int pno = paint->lookup(argv[3], 3); if (pno < 0) { fprintf(stderr,"%s ncolor: no such color: %s\n", argv[0], argv[3]); int pno = paint->lookup("black",1); if (pno < 0) { tcl.resultf("%s no black! - bailing"); return (TCL_ERROR); } } n->paint(pno); return (TCL_OK); } } else if (argc == 5) { if (strcmp(argv[1], "select-pkt") == 0) { selectPkt(atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); return(TCL_OK); } if (strcmp(argv[1], "lookupColorName") == 0) { /* * <net> lookupColorName red green blue * get color name from its rgb value */ Paint *paint = Paint::instance(); int r = atoi(argv[2]); int g = atoi(argv[3]); int b = atoi(argv[4]); tcl.resultf("%s",paint->lookupName(r,g,b)); return(TCL_OK); } if (strcmp(argv[1], "queue") == 0) { /* * <net> queue <src> <dst> <angle> * Create a queue for the edge from 'src' to 'dst'. * Add it to this NetModel's queue list. * Display the queue at the specified angle from * the edge to which it belongs. */ int src = atoi(argv[2]); int dst = atoi(argv[3]); EdgeHashNode *h = lookupEdge(src, dst); if (h == 0) { tcl.resultf("%s queue: no such edge (%d,%d)", argv[0], src, dst); return (TCL_ERROR); } /* XXX can we assume no duplicate queues? */ double angle = atof(argv[4]); Edge *e = h->edge; angle += e->angle(); Queue *q = new Queue(angle); h->queue = q; q->next_ = queues_; queues_ = q; return (TCL_OK); } if (strcmp(argv[1], "ecolor") == 0) { /* * <net> ecolor <src> <dst> <colorName> * set color of edge to the specified color. */ Paint *paint = Paint::instance(); EdgeHashNode* h = lookupEdge(atoi(argv[2]), atoi(argv[3])); if (h == 0) { tcl.resultf("%s ecolor: no such edge (%s,%s)", argv[0], argv[2], argv[3]); return (TCL_ERROR); } int pno = paint->lookup(argv[4], 3); if (pno < 0) { fprintf(stderr,"%s ncolor: no such color: %s\n", argv[0], argv[3]); pno = paint->lookup("black",1); if (pno < 0) { tcl.resultf("%s no black! - bailing"); return (TCL_ERROR); } } h->edge->paint(pno); return (TCL_OK); } if (strcmp(argv[1], "edlabel") == 0) { /* * <net> edlabel <src> <dst> <colorName> * set label of edge. */ EdgeHashNode* h = lookupEdge(atoi(argv[2]), atoi(argv[3])); if (h == 0) { tcl.resultf("%s ecolor: no such edge (%s,%s)", argv[0], argv[2], argv[3]); return (TCL_ERROR); } if (strcmp(argv[4],"(null)")!=0) { h->edge->dlabel((char *)argv[4]); // XXX Should never set edge size outside // scale_estimate()!!!! // h->edge->size(25.0); } return (TCL_OK); } if (strcmp(argv[1], "lanlink") == 0) { /* * <net> lanlink <src> <lan> <angle> * Create a link/edge between the specified source * and a lan. */ Node *src = lookupNode(atoi(argv[2])); Lan *lan = lookupLan(atoi(argv[3])); if (lan == NULL) { fprintf(stderr, "no such lan %s", argv[3]); exit(1); } double angle = atof(argv[4]); double bw=lan->bw(); double delay=(lan->delay())/2.0; Edge *e1 = new Edge(src, lan->virtual_node(), defsize, bw, delay, 0, angle+1); e1->init_color("black"); enterEdge(e1); e1->insert(&drawables_); src->add_link(e1); Edge *e2 = new Edge(lan->virtual_node(), src, defsize, bw, delay, 0, angle); e2->init_color("black"); enterEdge(e2); e2->insert(&drawables_); lan->add_link(e2); return (TCL_OK); } } else if (argc == 6) { if (strcmp(argv[1], "lan") == 0) { /* * <net> lan <name> <bandwidth> <delay> <angle> * Create a link/edge between the specified source * and destination. Add it to this NetModel's list * of drawables and to the source's list of links. */ double bw = atof(argv[3]); double delay = atof(argv[4]); double angle = atof(argv[5]); Lan *l = new Lan(argv[2], this, defsize, bw, delay, angle); l->next_=lans_; lans_=l; l->insert(&drawables_); Node *n=l->virtual_node(); n->next_ = nodes_; nodes_ = n; return (TCL_OK); } } else if (argc == 8) { if (strcmp(argv[1], "link") == 0) { /* * <net> link <src> <dst> <bandwidth> <delay> <angle> * Create a link/edge between the specified source * and destination. Add it to this NetModel's list * of drawables and to the source's list of links. */ Node *src, *dst; if ( !(src= lookupNode(atoi(argv[2]))) ) { tcl.resultf("node %s is not defined... ", argv[2]); return TCL_ERROR; } if ( !(dst= lookupNode(atoi(argv[3]))) ) { tcl.resultf("node %s is not defined... ", argv[3]); return TCL_ERROR; } double bw = atof(argv[4]); double delay = atof(argv[5]); double length = atof(argv[6]); //enlarge link if the topology is a mixture of //wired and wireless network if (wireless_) length = delay * WIRELESS_SCALE ; double angle = atof(argv[7]); Edge *e = new Edge(src, dst, defsize, bw, delay, length, angle); e->init_color("black"); enterEdge(e); e->insert(&drawables_); src->add_link(e); tcl.resultf("%g", delay); return (TCL_OK); } } /* If no NetModel commands matched, try the Object commands. */ return (TclObject::command(argc, argv)); } void NetModel::selectPkt(int sData, int sRoute, int sMac) { showData_ = sData; showRouting_ = sRoute; showMac_ = sMac; } // Place edges by their angles void NetModel::placeEdgeByAngle(Edge* e, Node* src) const { if (e->marked() == 0) { double nsin, ncos; Node *dst = e->neighbor(); SINCOSPI(e->angle(), &nsin, &ncos); double x0 = src->x(e) + src->size() * ncos * .75; double y0 = src->y(e) + src->size() * nsin * .75; double x1 = dst->x(e) - dst->size() * ncos * .75; double y1 = dst->y(e) - dst->size() * nsin * .75; e->place(x0, y0, x1, y1); /* Place the queue here too. */ EdgeHashNode *h = lookupEdge(e->src(), e->dst()); if (h->queue != 0) h->queue->place(e->size(), e->x0(), e->y0()); e->mark(); } } void NetModel::placeEdge(Edge* e, Node* src) const { if (e->marked() == 0) { double hyp, dx, dy; Node *dst = e->neighbor(); dx=dst->x(e)-src->x(e); dy=dst->y(e)-src->y(e); hyp=sqrt(dx*dx + dy*dy); e->setAngle(atan2(dy,dx)); double x0 = src->x(e) + src->size() * (dx/hyp) * .75; double y0 = src->y(e) + src->size() * (dy/hyp) * .75; double x1 = dst->x(e) - dst->size() * (dx/hyp) * .75; double y1 = dst->y(e) - dst->size() * (dy/hyp) * .75; e->place(x0, y0, x1, y1); /* Place the queue here too. */ EdgeHashNode *h = lookupEdge(e->src(), e->dst()); if (h->queue != 0) h->queue->place(e->size(), e->x0(), e->y0()); e->mark(); } } void NetModel::placeAgent(Agent *a, Node *src) const { double x0, y0, nsin, ncos; // XXX Stupid msvc cannot handle variable declaration in the MIDDLE // of a block. We have to put them here. :( Agent *agents; Edge *links; if (a->marked() == 0) { if (a->angle()==NO_ANGLE) { if (a->edge()==NULL) { /* determine where to put the label so it won't overlap a link (if possible) */ int choices[8], i, ix; for(i=0;i<8;i++) choices[i]=1; agents = src->agents(); while (agents!=NULL) { double angle = agents->angle(); if (angle<0) angle=angle+2*M_PI; ix=int(angle*4); if (ix < 8) choices[ix] = 0; agents=agents->next_; } links = src->links(); while (links!=NULL) { double angle = links->angle(); if (angle<0) angle=angle+2*M_PI; ix=int(angle*4); // ix=int(links->angle()*4); if (ix < 8) choices[ix]=0; links=links->next_; } if (choices[0]==1) a->angle(0); else if (choices[4]==1) a->angle(1.0); else if ((choices[1]==1)&&(choices[2]==1)) a->angle(0.5); else if ((choices[6]==1)&&(choices[7]==1)) a->angle(1.5); else if (choices[1]==1) a->angle(0.25); else a->angle(1.75); } else { a->angle(a->edge()->angle()+0.25); } } SINCOSPI(a->angle(), &nsin, &ncos); x0 = src->x() + src->size() * ncos * .75; y0 = src->y() + src->size() * nsin * .75; a->place(x0, y0); a->mark(1); } } void NetModel::set_wireless() { wireless_ = 1 ; for (Node *n = nodes_; n != 0; n = n->next_) for (Edge *e=n->links(); e != 0; e = e->next_) e->unmark(); scale_estimate(); placeEverything(); for (View *p = views_; p != 0; p = p->next_) if ((p->width() > 0) && (p->height() > 0)) { p->redrawModel(); p->draw(); } } /* * Compute reasonable defaults for missing node or edge sizes * based on the maximum link delay. */ void NetModel::scale_estimate() { /* Determine the maximum link delay. */ // XXX Must use length(). This is essential for appropriate // packet height when using a pre-made layout. double emax = 0.; Node *n; for (n = nodes_; n != 0; n = n->next_) { for (Edge* e = n->links(); e != 0; e = e->next_) if (e->length() > emax) emax = e->length(); } /*store this because we need it for monitors*/ node_size_ = node_sizefac_ * emax; /* * Check for missing node or edge sizes. If any are found, * compute a reasonable default based on the maximum edge * dimension. */ for (n = nodes_; n != 0; n = n->next_) { if (n->size() <= 0.) n->size(node_size_); for (Edge* e = n->links(); e != 0; e = e->next_) if (e->size() <= 0.) e->size(.03 * emax); } } void NetModel::placeEverything() { /* If there is no fixed node, anchor the first one entered at (0,0). */ Node *n; for (n = nodes_; n != 0; n = n->next_) { n->mark(0); n->clear_routes(); } if (nodes_) nodes_->place(0., 0.); int did_something; do { did_something = 0; for (n = nodes_; n != 0; n = n->next_) did_something |= traverse(n); } while (did_something); // Place edges for (n = nodes_; n != 0; n = n->next_) for (Edge* e = n->links(); e != 0; e = e->next_) placeEdgeByAngle(e, n); // After edges are laied out, place all routes. for (n = nodes_; n != 0; n = n->next_) n->place_all_routes(); } void NetModel::move(double& x, double& y, double angle, double d) const { double ncos, nsin; SINCOSPI(angle, &nsin, &ncos); x += d * ncos; y += d * nsin; } /* * Traverse node n's neighbors and place them based on the * delay of their links to n. The two branches of the if..else * are to handle unidirectional links -- we place ourselves if * we haven't been placed & our downstream neighbor has. */ int NetModel::traverse(Node* n) { int did_something = 0; for (Edge* e = n->links(); e != 0; e = e->next_) { Node *neighbor = e->neighbor(); double d = e->length() + (n->size() + neighbor->size()) * 0.75; if (n->marked() && !neighbor->marked()) { double x = n->x(e); double y = n->y(e); move(x, y, e->angle(), d); neighbor->place(x, y); did_something |= traverse(neighbor); if (nymax_ < y) nymax_ = y; if (nymin_ > y) nymin_ = y; } else if (!n->marked() && neighbor->marked()) { double x = neighbor->x(e); double y = neighbor->y(e); move(x, y, e->angle(), -d); n->place(x, y); did_something = 1; } } return (did_something); } int NetModel::save_layout(const char *filename) { FILE *file; Node *n; Edge *e; int ret; file=fopen(filename, "w"); if (file==0) { fprintf(stderr, "nam: Couldn't open file: %s\n", filename); return -1; } for (n = nodes_; n != 0; n = n->next_) { ret = n->save(file); if (ret!=0) { fclose(file); return -1; } } for (n = nodes_; n != 0; n = n->next_) for(e= n->links(); e !=0; e = e->next_) { ret = e->save(file); if (ret!=0) { fclose(file); return -1; } } return(fclose(file)); } void NetModel::color_subtrees() { Node *n, *dst, *prevdst, *newdst; Edge* e; for (n = nodes_; n != 0; n = n->next_) { int ctr=0; for (e = n->links(); e != 0; e = e->next_) ctr++; if (ctr==1) { n->color("grey"); n->links()->color("grey"); dst=n->links()->neighbor(); for (e = dst->links(); e != 0; e = e->next_) if (e->neighbor()==n) { e->color("grey"); break; } ctr=2; prevdst=n; while(ctr==2) { ctr=0; for (e = dst->links(); e != 0; e = e->next_) ctr++; if (ctr==2) { dst->color("grey"); dst->links()->color("grey"); for (e = dst->links(); e != 0; e = e->next_) if (e->neighbor()!=prevdst) { newdst=e->neighbor(); break; } e->color("grey"); for (e = newdst->links(); e != 0; e = e->next_) if (e->neighbor()==dst) { e->color("grey"); break; } prevdst=dst; dst=newdst; } } } } } int NetModel::add_tag(Tag *tag) { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(tagHash_, (const char *)tag->name(), &newEntry); if (he == NULL) return (TCL_ERROR); if (newEntry) { Tcl_SetHashValue(he, (ClientData)tag); nTag_++; } tag->insert(&drawables_); return (TCL_OK); } // Remove a tag from netmodel, and clear all its memberships but not // actually delete it void NetModel::delete_tag(const char *tn) { Tcl_HashEntry *he = Tcl_FindHashEntry(tagHash_, (const char *)tn); if (he != NULL) { // Do *NOT* delete tag here. Tcl_DeleteHashEntry(he); nTag_--; } } Tag* NetModel::lookupTag(const char *tn) { Tcl_HashEntry *he = Tcl_FindHashEntry(tagHash_, tn); if (he == NULL) return NULL; return (Tag *)Tcl_GetHashValue(he); } int NetModel::registerObjName(const char *name, int id) { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(objnameHash_, name, &newEntry); if (he == NULL) return (TCL_ERROR); if (newEntry) { Tcl_SetHashValue(he, (ClientData)id); nTag_++; } return (TCL_OK); } //XXX: maximum name length is 256. int NetModel::lookupObjname(const char *name) { #define STATIC_NAMELEN 256 char n[STATIC_NAMELEN]; size_t len = strlen(name); len = (len < STATIC_NAMELEN) ? len : STATIC_NAMELEN; for (size_t i = 0; i < len; i++) n[i] = toupper(name[i]); Tcl_HashEntry *he = Tcl_FindHashEntry(objnameHash_, n); if (he == NULL) return -1; return (int)Tcl_GetHashValue(he); #undef STATIC_NAMELEN } /* * Unite tag name space and animation id space: * * (1) if tag is a number, we'll first look it up in our * animation objects table. * (2) if tag is a string, it must be in the tag table */ Animation* NetModel::lookupTagOrID(const char *name) { char end[256]; if (name == NULL) return NULL; unsigned int id = (unsigned int)strtoul(name, (char **)&end, 0); if (*end != 0) // This must be a tag string name return lookupTag(name); else return Animation::find(id); } /* * Handling Tcl command "addtags" of EditView * * <view> addtag tag <searchSpec> arg... * * searchSpec can be: * all <ObjectType> * closest x y ?halo? * enclosed x1 y1 x2 y2 * overlapping x1 y1 x2 y2 * withTag tagOrID * specification copied from Tk's canvas * * If newTag isn't null, then first lookup the tag. If found, add * the searchSpec results to that tag, otherwise create a new tag * and add results to that tag. * Return error if newTag == NULL. * * Tagging policies, e.g., whether an object can simultaneously belong * to multiple tags, are left to the users. */ int NetModel::tagCmd(View *v, int argc, char **argv, char *newTag, char *cmdName) { Tag *tag = NULL; size_t length; Tcl& tcl = Tcl::instance(); int res = (TCL_OK), bNew = 0; if (newTag != NULL) { tag = (Tag *)lookupTagOrID(newTag); if ((tag != NULL) && (tag->classid() != ClassTagID)) { Tcl_AppendResult(tcl.interp(), newTag, "should be a tag ", (char *)NULL); return TCL_ERROR; } if (tag == NULL) { tag = new Tag(newTag); bNew = 1; } } int c = argv[0][0]; length = strlen(argv[0]); if ((c == 'a') && (strncmp(argv[0], "all", length) == 0) && (length >= 2)) { if (argc > 2) { Tcl_AppendResult(tcl.interp(), "wrong # args: should be \"", cmdName, " all ?Obj?", (char *) NULL); res = TCL_ERROR; goto error; } Animation *a; int objType = ClassAllID; if (argc == 2) { // Map object name to class id objType = lookupObjname(argv[1]); if (objType == -1) { Tcl_AppendResult(tcl.interp(), "Bad object name ", argv[1]); res = (TCL_ERROR); goto error; } } if (objType == ClassAllID) { for (a = animations_; a != NULL; a = a->next()) if (!a->isTagged()) tagObject(tag, a); for (a = drawables_; a != NULL; a = a->next()) if (!a->isTagged()) tagObject(tag, a); } else { for (a = animations_; a != NULL; a = a->next()) if (!a->isTagged() && a->classid() == objType) tagObject(tag, a); for (a = drawables_; a != NULL; a = a->next()) if (!a->isTagged() && a->classid() == objType) tagObject(tag, a); } } else if ((c == 'e') && (strncmp(argv[0], "enclosed", length) == 0)) { /* * enclosed x1 y1 x2 y2 */ if (argc != 5) { Tcl_AppendResult(tcl.interp(), "wrong # args: should be \"", cmdName, " enclosed x1 y1 x2 y2", (char *) NULL); res = TCL_ERROR; goto error; } BBox bb; // Translation/scaling will not change the order of bbox. :) if ((v->getCoord(argv[1], argv[2], bb.xmin, bb.ymin) != TCL_OK) || (v->getCoord(argv[3], argv[4], bb.xmax, bb.ymax)!=TCL_OK)) res = TCL_ERROR; else res = tagArea(bb, tag, 1); } else if ((c == 'o') && (strncmp(argv[0], "overlapping", length) == 0)) { /* * Overlapping x1 y1 x2 y2 */ if (argc != 5) { Tcl_AppendResult(tcl.interp(), "wrong # args: should be \"", cmdName, " overlapping x1 y1 x2 y2", (char *) NULL); res = TCL_ERROR; goto error; } BBox bb; // Translation/scaling will not change the order of bbox. :) if ((v->getCoord(argv[1], argv[2], bb.xmin, bb.ymin) != TCL_OK) || (v->getCoord(argv[3], argv[4], bb.xmax, bb.ymax)!=TCL_OK)) res = TCL_ERROR; else res = tagArea(bb, tag, 0); } else if ((c == 'w') && (strncmp(argv[0], "withtag", length) == 0)) { if (argc != 2) { Tcl_AppendResult(tcl.interp(), "wrong # args: should be \"", cmdName, " withtag tagOrId", (char *) NULL); res = TCL_ERROR; goto error; } // Find that tag or ID Animation *p = lookupTagOrID(argv[1]); if (p == NULL) { // Wrong tag Tcl_AppendResult(tcl.interp(), "wrong tag ", argv[1], (char *)NULL); res = TCL_ERROR; } else { // Label them as this tag tagObject(tag, p); } } else if ((c == 'c') && (strncmp(argv[0], "closest", length) == 0)) { float coords[2], halo; if ((argc < 3) || (argc > 5)) { Tcl_AppendResult(tcl.interp(), "wrong # args: should be \"", cmdName, " closest x y ?halo? ", (char *) NULL); res = TCL_ERROR; goto error; } if (v->getCoord(argv[1], argv[2], coords[0], coords[1]) != TCL_OK) { Tcl_AppendResult(tcl.interp(), "bad coordinates ", argv[1], " ", argv[2], (char *)NULL); res = TCL_ERROR; goto error; } if (argc > 3) { // XXX: It's impossible to convert length in // screen space to world space with translation // and scaling. We think it's in world space halo = strtod(argv[3], NULL); if (halo < 0.0) { Tcl_AppendResult(tcl.interp(), "can't have negative halo value \"", argv[3], "\"", (char *) NULL); res = TCL_ERROR; goto error; } } else { halo = 0.0; } Animation *p = findClosest(coords[0], coords[1], halo); if (p != NULL) tagObject(tag, p); else res = TCL_ERROR; } else { Tcl_AppendResult(tcl.interp(), "bad search command \"", argv[0], "\": must be above, all, below, closest, enclosed, ", "overlapping, or withtag", (char *) NULL); res = TCL_ERROR; goto error; } if (res == TCL_OK) { if (bNew) add_tag(tag); return TCL_OK; } error: if (tag != NULL) delete tag; return res; } Animation* NetModel::findClosest(float dx, float dy, double halo) { double closestDist; Animation *startPtr, *closestPtr, *itemPtr; BBox bb; startPtr = animations_; itemPtr = startPtr; if (itemPtr == NULL) { return NULL; } closestDist = itemPtr->distance(dx, dy) - halo; if (closestDist < 0.0) { closestDist = 0.0; } while (1) { double newDist; /* * Update the bounding box using itemPtr, which is the * new closest item. */ bb.xmin = dx - closestDist - halo - 1, bb.ymin = dy - closestDist - halo - 1, bb.xmax = dx + closestDist + halo + 1, bb.ymax = dy + closestDist + halo + 1; closestPtr = itemPtr; /* * Search for an item that beats the current closest * one. * Work circularly through the canvas's item list until * getting back to the starting item. */ while (1) { itemPtr = itemPtr->next(); if (itemPtr == NULL) { if (startPtr == animations_) { startPtr = drawables_; itemPtr = startPtr; } else return closestPtr; } if (itemPtr->isTagged()|| !itemPtr->bbox().overlap(bb)) continue; newDist = itemPtr->distance(dx, dy)-halo; if (newDist < 0.0) { newDist = 0.0; } if (newDist <= closestDist) { closestDist = newDist; break; } } } } void NetModel::tagObject(Tag *tag, Animation *obj) { Tcl& tcl = Tcl::instance(); if (tag == NULL) { char str[20]; sprintf(str, "No tag for %d", obj->id()); Tcl_AppendElement(tcl.interp(), str); return; } if (tag == obj) return; // Tag that object // XXX // Should we keep a tag list in each animation object so that // each object can find tags to which it belongs? tag->add(obj); } int NetModel::tagArea(BBox &bb, Tag *tag, int bEnclosed) { Animation *p; // Because the area is a rectangle, we only need to // find out all objects whose bounding boxes are // within/overlapping the given rectangle. if (bEnclosed == 0) { // overlapping and enclosed for (p = animations_; p != NULL; p = p->next()) if (!p->isTagged() && p->bbox().overlap(bb) && (p != tag)) tagObject(tag, p); for (p = drawables_; p != NULL; p = p->next()) if (!p->isTagged() && p->bbox().overlap(bb) && (p != tag)) tagObject(tag, p); } else { // enclosed only for (p = animations_; p != NULL; p = p->next()) if (!p->isTagged() && bb.inside(p->bbox()) && (p != tag)) tagObject(tag, p); for (p = drawables_; p != NULL; p = p->next()) if (!p->isTagged() && bb.inside(p->bbox()) && (p != tag)) tagObject(tag, p); } return TCL_OK; } int NetModel::deleteTagCmd(char *tagName, char *tagDel) { Tag *p; Animation *q = NULL; p = (Tag *)lookupTagOrID(tagName); if (tagDel != NULL) q = lookupTagOrID(tagDel); if (p == NULL) { Tcl_AppendResult(Tcl::instance().interp(), "bad tag ", tagName, (char *)NULL); return (TCL_ERROR); } if ((p->classid() != ClassTagID) || (p == q) || (q == NULL)){ // If given an ID, or given a group only // delete it and do nothing else delete p; return TCL_OK; } // Now delete tag p from object q q->deleteTag(p); return TCL_OK; } // XXX: Partial redraw is only working for EditView! Not for other // animation views for now. We need a method in each Animation object // to decide their "dirtiness" to make this redraw work. :( And the // computation of clipping box should be purely within NetModel but // not fed in externally void NetModel::render(EditView* view, BBox &bb) { Animation *a; for (a = drawables_; a != 0; a = a->next()) { if (!a->bbox().overlap(bb)) continue; a->draw(view, now_); } for (a = animations_; a != 0; a = a->next()) { if (!a->bbox().overlap(bb)) continue; a->draw(view, now_); } } void NetModel::moveNode(Node *n) { //fprintf(stderr, "Moving nodes can only be performed by NetModel.\n"); for (Edge *e = n->links(); e != 0; e = e->next_) { e->unmark(); placeEdge(e, n); Node *dst = e->neighbor(); // Should place reverse edges too Edge *p = dst->find_edge(n->num()); if (p != NULL) { p->unmark(); placeEdge(p, dst); } dst->clear_routes(); dst->place_all_routes(); } for (Agent *a = n->agents(); a != NULL; a = a->next()) { a->mark(0), a->angle(NO_ANGLE); placeAgent(a, n); } // Relayout all routes n->clear_routes(); n->place_all_routes(); }

netview.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <ctype.h> #include <math.h> #include "bbox.h" #include "netview.h" #include "netmodel.h" #include "tclcl.h" #include "paint.h" #include "packet.h" #include "xwd.h" // Why not use View's? View::render() is already a virtual function... //void NetView::draw() //{ // if (offscreen_ == 0) // return; // // XFillRectangle(Tk_Display(tk_), offscreen_, background_, // 0, 0, width_, height_); // model_->render(this); // XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_), background_, // 0, 0, width_, height_, 0, 0); //} int
NetView::record(char *file) { #ifndef WIN32 return xwd_Window_Dump_To_File(tk_, offscreen_, (unsigned) width_, (unsigned) height_, file); #else return TCL_ERROR; #endif } // Static call back function for tcl delete command callback void NetView::DeleteCmdProc(ClientData cd) { NetView *nv = (NetView *)cd; if (nv->tk_ != NULL) { Tk_DestroyWindow(nv->tk_); } } NetView::NetView(const char* name, NetModel* m) : View(name, SQUARE, 300, 200), model_(m) { if (tk_!=0) { Tcl& tcl = Tcl::instance(); cmd_ = Tcl_CreateCommand(tcl.interp(), Tk_PathName(View::tk()), command, (ClientData)this, DeleteCmdProc); } } // Do nothing. For derived classes only. NetView::NetView(const char* name) : View(name, SQUARE, 300, 200), model_(NULL), cmd_(NULL) { } NetView::NetView(const char* name, NetModel* m, int width, int heigth) : View(name, SQUARE, 300, 400), model_(NULL) { } NetView::~NetView() { model_->remove_view(this); // Delete Tcl command created Tcl& tcl = Tcl::instance(); Tcl_DeleteCommandFromToken(tcl.interp(), cmd_); } int NetView::command(ClientData cd, Tcl_Interp* tcl, int argc, char **argv) { if (argc < 2) { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return (TCL_ERROR); } if (strcmp(argv[1], "info") == 0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; //double now = atof(argv[2]); //int rootX, rootY; //Window root, child; //unsigned int state; int winX, winY; float px, py; /*XQueryPointer(Tk_Display(nv->tk_), Tk_WindowId(nv->tk_), &root, &child, &rootX, &rootY, &winX, &winY, &state);*/ winX=atoi(argv[3]); winY=atoi(argv[4]); nv->matrix_.imap(float(winX), float(winY), px, py); //if ((a = nv->model_->inside(now, px, py)) != 0) { if ((a = nv->model_->inside(px, py)) != 0) { tcl.result(a->info()); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "gettype")==0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; int winX, winY; float px, py; winX=atoi(argv[3]); winY=atoi(argv[4]); nv->matrix_.imap(float(winX), float(winY), px, py); if ((a = nv->model_->inside(px, py)) != 0) { const char *res=a->gettype(); if (res!=NULL) tcl.result(res); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "getfid")==0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; int winX, winY; float px, py; winX=atoi(argv[3]); winY=atoi(argv[4]); nv->matrix_.imap(float(winX), float(winY), px, py); if ((a = nv->model_->inside(px, py)) != 0) { const char *res=a->getfid(); if (res!=NULL) tcl.result(res); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "getesrc")==0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; int winX, winY; float px, py; winX=atoi(argv[3]); winY=atoi(argv[4]); nv->matrix_.imap(float(winX), float(winY), px, py); if ((a = nv->model_->inside(px, py)) != 0) { const char *res=a->getesrc(); if (res!=NULL) tcl.result(res); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "getedst")==0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; int winX, winY; float px, py; winX=atoi(argv[3]); winY=atoi(argv[4]); nv->matrix_.imap(float(winX), float(winY), px, py); if ((a = nv->model_->inside(px, py)) != 0) { const char *res=a->getedst(); if (res!=NULL) tcl.result(res); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "getname")==0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; //double now = atof(argv[2]); //Window root, child; //int rootX, rootY; //unsigned int state; int winX, winY; float px, py; /*XQueryPointer(Tk_Display(nv->tk_), Tk_WindowId(nv->tk_), &root, &child, &rootX, &rootY, &winX, &winY, &state); */ winX=atoi(argv[3]); winY=atoi(argv[4]); nv->matrix_.imap(float(winX), float(winY), px, py); //if ((a = nv->model_->inside(now, px, py)) != 0) { if ((a = nv->model_->inside(px, py)) != 0) { const char *res=a->getname(); if (res!=NULL) tcl.result(res); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "new_monitor") == 0) { if (argc == 5) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); Animation* a; //double now = atof(argv[2]); float px, py; nv->matrix_.imap(atof(argv[3]), atof(argv[4]), px, py); //if ((a = nv->model_->inside(now, px, py)) != 0) { if ((a = nv->model_->inside(px, py)) != 0) { char num[10]; int n = nv->model_->add_monitor(a); sprintf(num, "%d", n); tcl.result(num); return TCL_OK; } return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "delete_monitor") == 0) { if (argc == 3) { NetView *nv = (NetView *)cd; nv->model_->delete_monitor(atoi(argv[2])); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "monitor") == 0) { if (argc == 4) { NetView *nv = (NetView *)cd; Tcl& tcl = Tcl::instance(); //Animation* a; double now = atof(argv[2]); int monitor = atoi(argv[3]); char result[128]; nv->model_->monitor(now, monitor, result, 128); tcl.result(result); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "record_frame") == 0) { if (argc == 3) { NetView *nv = (NetView *)cd; return nv->record(argv[2]); } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "close") == 0) { NetView *nv = (NetView *)cd; nv->destroy(); return TCL_OK; } return (View::command(cd, tcl, argc, argv)); }

node.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <tcl.h> #include "view.h" #include "netview.h" #include "psview.h" #include "editview.h" #include "node.h" #include "queue.h" #include "feature.h" #include "agent.h" #include "edge.h" #include "route.h" #include "monitor.h" #include "lan.h" #include "paint.h" Node::Node(const char* name, double size) : Animation(0, 0), next_(0), queue_(0), size_(size), nsize_((float) size), x_(0.), y_(0.), x_vel_(0.), y_vel_(0.), starttime_(0.), endtime_(0.), links_(0), routes_(0), agents_(0), anchor_(0), mark_(0), state_(UP), nm_(NULL), nMark_(0), dlabel_(0), lcolor_(0), dcolor_(0), ncolor_(0), direction_(0) { label_ = new char[strlen(name) + 1]; strcpy(label_, name); addr_ = nn_ = atoi(name); /*XXX*/ paint_ = Paint::instance()->thick(); } Node::~Node() { if (nm_ != NULL) { NodeMark *p = nm_; nm_ = nm_->next; delete p; } delete label_; if (queue_ != NULL) delete queue_; } void
Node::init_color(char *clr) { color(clr); lcolor(clr); ncolor(clr); dcolor(clr); oldPaint_ = paint_; } void Node::set_down(char *color) { // If current color is down, don't change it again. // Assuming only one down color. User can change this behavior // by adding tcl code for link-up and link-down events. if (state_ == UP) { int pno = Paint::instance()->lookup(color, 3); oldPaint_ = paint_; paint_ = pno; state_ = DOWN; } } void Node::set_up() { if (state_ == DOWN) { state_ = UP; toggle_color(); } } float Node::distance(float x, float y) const { return ((x_-x) * (x_-x) + (y_-y) * (y_-y)); } void Node::size(double s) { size_ = s; update_bb(); } // We don't need one update_bb() for every derived class because their // sizes are all based on 0.5*size_. Otherwise we'll have to do update_bb // individually void Node::update_bb() { double off = 0.5 * size_ + NodeMarkScale * size_; // thick circles if (nMark_ > 0) off += nMark_ * NodeMarkScale * size_; /*XXX*/ bb_.xmin = x_ - off; bb_.ymin = y_ - off; bb_.xmax = x_ + off; bb_.ymax = y_ + off; } // Moved to Animation::inside(). Why not put a generic one based on BBox there? // //int Node::inside(double, float px, float py) const //{ // return (px >= bb_.xmin && px <= bb_.xmax && // py >= bb_.ymin && py <= bb_.ymax); //} const char* Node::info() const { static char text[128]; sprintf(text, "Node: %s", label_); return (text); } const char* Node::property() const { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); static char text[256]; char *p; p = text; sprintf(text, "{NODE %d} ", nn_); // obj type and id p = &text[strlen(text)]; sprintf(p, "{SIZE %f} ", size_); // size & value p = &text[strlen(text)]; sprintf(p, "{COLOR %s} ", color->colorname); // color & value p = &text[strlen(text)]; sprintf(p, "{LABEL %s} ", dlabel_); // label $ value return(text); } const char* Node::getname() const { static char text[128]; sprintf(text, "n %s", label_); return (text); } void Node::monitor(Monitor *m, double /*now*/, char *result, int /*len*/) { monitor_=m; sprintf(result, "Node: %s", label_); return; } void Node::add_link(Edge* e) { e->next_ = links_; links_ = e; } void Node::delete_link(Edge* e) { Edge *h, *k; h = links_; for (k = links_; k != 0; k = k->next_) { if (k->src() == e->src() && k->dst() == e->dst()) { if (k == links_) { links_ = k->next_; break; } else { h->next_ = k->next_; break; } } h = k; } } void Node::add_agent(Agent* a) { a->next_ = agents_; agents_ = a; } void Node::delete_agent(Agent* r) { /*given a agent, remove it from a node's agent list*/ Agent *ta1, *ta2; ta1=agents_; ta2=agents_; while ((ta1!=r)&&(ta1!=NULL)) { ta2=ta1; ta1=ta1->next(); } if (ta1==r) { ta2->next(ta1->next()); if (ta1==agents_) agents_=ta1->next(); } } Agent *Node::find_agent(char *name) const { Agent *ta=NULL; ta=agents_; while (ta!=NULL) { if (strcmp(ta->name(), name)==0) return ta; ta=ta->next(); } return NULL; } void Node::add_route(Route* r) { r->next_ = routes_; routes_ = r; } void Node::delete_route(Route* r) { /*given a route, remove it from a node's route list*/ Route *tr1, *tr2; tr1=routes_; tr2=routes_; while ((tr1!=r)&&(tr1!=NULL)) { tr2=tr1; tr1=tr1->next(); } if (tr1==r) { tr2->next(tr1->next()); if (tr1==routes_) routes_=tr1->next(); } if (routes_!=NULL) { /*need to reposition routes on this edge*/ Edge *e=tr1->edge(); int ctr=0; for (tr2=routes_;tr2!=NULL;tr2=tr2->next()) if (tr2->edge()==e) tr2->place(e->x0(), e->y0(), ctr++); } } Route *Node::find_route(Edge *e, int group, int pktsrc, int oif) const { Route *tr=NULL; tr=routes_; while (tr!=NULL) { if (tr->matching_route(e, group, pktsrc, oif)==1) return tr; tr=tr->next(); } return NULL; } void Node::place_route(Route *r) { if (r->node() != this) return; if (r->marked() == 0) { r->place(r->edge()->x0(), r->edge()->y0()); r->mark(1); } } // Used when topology is relayout void Node::place_all_routes() { Route *tr = routes_; while (tr != NULL) { place_route(tr); tr = tr->next(); } } // Clear mark on routes so we can replace them void Node::clear_routes() { Route *tr = routes_; while (tr != NULL) { tr->mark(0); tr = tr->next(); } } int Node::no_of_routes(Edge *e) const { Route *tr=routes_; int no_of_routes=0; while (tr!=NULL) { if (tr->edge()==e) no_of_routes++; tr=tr->next(); } return no_of_routes; } void Node::label(const char* name, int anchor) { delete label_; label_ = new char[strlen(name) + 1]; strcpy(label_, name); anchor_ = anchor; } void Node::lcolor(const char* name) { if (name[0] == 0) { if (lcolor_) { delete []lcolor_; lcolor_ = 0; } return; } if (lcolor_) delete []lcolor_; lcolor_ = new char[strlen(name) + 1]; strcpy(lcolor_, name); } void Node::dlabel(const char* name) { if (name[0] == 0) { if (dlabel_) { delete []dlabel_; dlabel_ = 0; } return; } if (dlabel_) delete []dlabel_; dlabel_ = new char[strlen(name) + 1]; strcpy(dlabel_, name); } void Node::dcolor(const char* name) { if (name[0] == 0) { if (dcolor_) { delete []dcolor_; dcolor_ = 0; } return; } if (dcolor_) delete []dcolor_; dcolor_ = new char[strlen(name) + 1]; strcpy(dcolor_, name); } void Node::ncolor(const char* name) { if (name[0] == 0) { if (ncolor_) { delete []ncolor_; ncolor_ = 0; } return; } if (ncolor_) delete []ncolor_; ncolor_ = new char[strlen(name) + 1]; strcpy(ncolor_, name); } void Node::direction(const char* name) { if (name[0] == 0) { if (direction_) { direction_ = 0; } return; } if (!strcmp(name, "EAST")) direction_ = 1; else if (!strcmp(name, "SOUTH")) direction_ = 2; else if (!strcmp(name, "WEST")) direction_ = 3; else if (!strcmp(name, "NORTH")) direction_ = 4; else direction_ = 0; } void Node::add_sess_queue(unsigned int, Queue *q) { if (queue_ != NULL) // Currently we only allow one queue per node return; queue_ = q; queue_->place(size_*0.5, x_+size_*.05, y_+size_*0.5); } NodeMark* Node::find_mark(char *name) { NodeMark *p = nm_; while (p != NULL) { if (strcmp(p->name, name) == 0) break; p = p->next; } return p; } int Node::add_mark(char *name, char *color, char *shape) { if (find_mark(name) != NULL) return 1; NodeMark *cm = new NodeMark(name); cm->color = Paint::instance()->lookup(color, 2); if (strcmp(shape, "circle") == 0) cm->shape = NodeMarkCircle; else if (strcmp(shape, "square") == 0) cm->shape = NodeMarkSquare; else if (strcmp(shape, "hexagon") == 0) cm->shape = NodeMarkHexagon; if (nm_ != NULL) cm->next = nm_; nm_ = cm; nMark_++; update_bb(); return 0; } void Node::delete_mark(char *name) { NodeMark **p; p = &nm_; while (*p != NULL) { if (strcmp((*p)->name, name) == 0) { NodeMark *q = *p; *p = (*p)->next; delete q; nMark_--; update_bb(); return; } p = &((*p)->next); } } void Node::update(double now) { if (now >= endtime_ || now <= starttime_ ) {return;} double xpos = xorig_ + (now - starttime_)*x_vel_; double ypos = yorig_ + (now - starttime_)*y_vel_; place(xpos,ypos); } void Node::draw_mark(View* nv) const { NodeMark *cm; double s = size_ * 0.7; for (cm = nm_; cm != NULL; cm = cm->next, s += size_ * NodeMarkScale) { switch (cm->shape) { case NodeMarkCircle: nv->circle(x_, y_, s, cm->color); break; case NodeMarkSquare: { double x[2], y[2]; x[0] = x_ - s, x[1] = x_ + s; y[0] = y_ - s, y[1] = y_ + s; nv->rect(x[0], y[0], x[1], y[1], cm->color); break; } case NodeMarkHexagon: { float x[6], y[6]; double qd = 0.5 * s; x[0] = x_ - s; y[0] = y_; x[1] = x_ - qd; y[1] = y_ + s; x[2] = x_ + qd; y[2] = y_ + s; x[3] = x_ + s; y[3] = y_; x[4] = x_ + qd; y[4] = y_ - s; x[5] = x_ - qd; y[5] = y_ - s; nv->polygon((float *)x, (float *)y, 6, cm->color); break; } } } } void Node::drawlabel(View* nv) const { /*XXX node number */ if (label_ != 0) nv->string(x_, y_, size_, label_, anchor_, lcolor_); if (monitor_!=NULL) monitor_->draw(nv, x_, y_-size_/2); if (dlabel_ != 0) { switch (direction_) { case 0: nv->string(x_, y_+size_, size_*0.7, dlabel_, 0, dcolor_); break; case 1: nv->string(x_-size_*1.5, y_, size_*0.7, dlabel_, 0, dcolor_); break; case 2: nv->string(x_, y_-size_, size_*0.7, dlabel_, 0, dcolor_); break; case 3: nv->string(x_+size_*1.5, y_, size_*0.7, dlabel_, 0, dcolor_); break; case 4: nv->string(x_, y_+size_, size_*0.7, dlabel_, 0, dcolor_); break; default: nv->string(x_, y_+size_, size_*0.7, dlabel_, 0, dcolor_); break; } } } void Node::reset(double) { //XXX why should reset to black??? // paint_ = Paint::instance()->thick(); } void Node::place(double x, double y) { x_ = x; y_ = y; mark_ = 1; update_bb(); // Should we place queues here too? if (queue_ != NULL) queue_->place(0.5 * size_, x_+0.5*size_, y_+0.5*size_); } // Move by a displacement in *window* coordinates void Node::move(EditView *v, float wdx, float wdy) { float cx, cy; // First get our position in window coordinates cx = x_, cy = y_; v->map(cx, cy); cx += wdx, cy += wdy; v->imap(cx, cy); place(cx, cy); // Because all placements are centrally organized by AutoNetModel, // we'll have to call back. :( v->moveNode(this); } Edge *Node::find_edge(int dst) const { for (Edge *e = links_; e != 0; e = e->next_) if (e->dst() == dst) return e; return NULL; } int Node::save(FILE *file) { char state[10]; // char colorname[20]; rgb *color; color=Paint::instance()->paint_to_rgb(paint_); if (state_==UP) strcpy(state, " -S UP"); else if (state_==DOWN) strcpy(state, " -S DOWN"); else state[0]='\0'; fprintf(file, "n -t * -s %d -v %s -c %s -z %f %s\n", nn_, style(), color->colorname, size_, state); return(0); } int Node::saveAsNs(FILE *file) { rgb *color; color=Paint::instance()->paint_to_rgb(paint_); fprintf(file, "set n(%d) [$ns node]\n",nn_); fprintf(file, "$n(%d) color \"%s\"\n",nn_,color->colorname); if (dlabel_) fprintf(file, "$ns at 0.0 \"$n(%d) label %s\"\n",nn_, dlabel_); return(0); } int Node::saveAsEnam(FILE *file) { char state[10]; rgb *color; color=Paint::instance()->paint_to_rgb(paint_); if (state_==UP) strcpy(state, " -S UP"); else if (state_==DOWN) strcpy(state, " -S DOWN"); else state[0]='\0'; fprintf(file, "##n -t * -s %d -v %s -c %s -i %s -b %s -z %f -x %f -y %f %s\n", nn_, style(), color->colorname, color->colorname, dlabel_, size_, x_, y_, state); return(0); } BoxNode::BoxNode(const char* name, double size) : Node(name, size) { BoxNode::size(size); } void BoxNode::size(double s) { Node::size(s); double delta = 0.5 * s; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } void BoxNode::draw(View* nv, double /*now*/) const { nv->rect(x0_, y0_, x1_, y1_, paint_); drawlabel(nv); draw_mark(nv); } void BoxNode::place(double x, double y) { Node::place(x, y); double delta = 0.5 * size_; x0_ = x_ - delta; y0_ = y_ - delta; x1_ = x_ + delta; y1_ = y_ + delta; } CircleNode::CircleNode(const char* name, double size) : Node(name, size) { CircleNode::size(size); } void CircleNode::size(double s) { Node::size(s); radius_ = 0.5 * s; } void CircleNode::draw(View* nv, double /*now*/) const { nv->circle(x_, y_, radius_, paint_); drawlabel(nv); draw_mark(nv); } HexagonNode::HexagonNode(const char* name, double size) : Node(name, size) { HexagonNode::size(size); } void HexagonNode::size(double s) { Node::size(s); double hd = 0.5 * s; double qd = 0.5 * hd; xpoly_[0] = x_ - hd; ypoly_[0] = y_; xpoly_[1] = x_ - qd; ypoly_[1] = y_ + hd; xpoly_[2] = x_ + qd; ypoly_[2] = y_ + hd; xpoly_[3] = x_ + hd; ypoly_[3] = y_; xpoly_[4] = x_ + qd; ypoly_[4] = y_ - hd; xpoly_[5] = x_ - qd; ypoly_[5] = y_ - hd; } void HexagonNode::draw(View* nv, double /*now*/) const { nv->polygon(xpoly_, ypoly_, 6, paint_); drawlabel(nv); draw_mark(nv); } void HexagonNode::place(double x, double y) { Node::place(x, y); double hd = 0.5 * size_; double qd = 0.5 * hd; xpoly_[0] = x_ - hd; ypoly_[0] = y_; xpoly_[1] = x_ - qd; ypoly_[1] = y_ + hd; xpoly_[2] = x_ + qd; ypoly_[2] = y_ + hd; xpoly_[3] = x_ + hd; ypoly_[3] = y_; xpoly_[4] = x_ + qd; ypoly_[4] = y_ - hd; xpoly_[5] = x_ - qd; ypoly_[5] = y_ - hd; } VirtualNode::VirtualNode(const char* name, Lan *lan) : Node(name, 0), lan_(lan) { } void VirtualNode::size(double s) { Node::size(0); lan_->size(s); } void VirtualNode::draw(View* /*nv*/, double /*now*/) const { printf("drawing vn at %f %f\n", x_, y_); } void VirtualNode::place(double x, double y) { Node::place(x, y); lan_->place(x, y); } void VirtualNode::arrive_packet(Packet *p, Edge *e, double atime) { lan_->arrive_packet(p,e,atime); } void VirtualNode::delete_packet(Packet *p) { lan_->delete_packet(p); } double VirtualNode::x(Edge *e) const { return lan_->x(e); } double VirtualNode::y(Edge *e) const { return lan_->y(e); }

packet.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #ifdef WIN32 #include <windows.h> #endif #include "transform.h" #include "view.h" #include "netview.h" #include "psview.h" #include "edge.h" #include "node.h" #include "packet.h" int Packet::count_ = 0; BPacket::BPacket(double x, double y ,const PacketAttr& p , double now, long offset, int direction ) : Animation(now, offset) { x_ = x ; y_ = y ; pkt_ = p ; if (direction == FORWARDS ) radius_ = MIN_RANGE ; else radius_ = MAX_RANGE ; // BACKWARD start_ = now ; direction_ = direction; aType_ = BPACKET; } void BPacket::draw(View* nv, double now) const { nv->circle(x_, y_,radius_,paint_); } void
BPacket::update(double now) { //250 is pre-calculate by using fixed two-way ground reflection //model with fixed transmission power 3.652e-10 if (direction_ == FORWARDS) { if (now < start_ || radius_ > MAX_RANGE) { delete this; } else { update_bb(); } } else { if ( now > start_ || radius_ < MIN_RANGE) { delete this; } else { update_bb(); } } } void BPacket::update_bb() { if (direction_ == FORWARDS) radius_ = radius_ + (MIN_RANGE/2) ; else radius_ = radius_ - (MIN_RANGE/2) ; } const char* BPacket::info() const { static char text[128]; sprintf(text, "%s %d: %s\n Sent at %.6f\n %d bytes\n", pkt_.type, pkt_.id, pkt_.convid, start_, pkt_.size); return (text); } const char* BPacket::getname() const { static char text[128]; sprintf(text, "p"); return (text); } void BPacket::monitor(Monitor *m, double , char *result, int ) { if (((direction_ == FORWARDS) && (radius_ > MAX_RANGE)) || ((direction_ == BACKWARDS) && (radius_ < MIN_RANGE)) ) { result[0] = '\0' ; return ; } monitor_=m; sprintf(result, "%s %d: %s\n Sent at %.6f\n %d bytes", pkt_.type, pkt_.id, pkt_.convid, start_, pkt_.size); } MonState *BPacket::monitor_state() { /*return any state we wish the monitor to remember after we're gone*/ MonState *ms=new MonState; ms->type=MON_PACKET; ms->pkt.id=pkt_.id; return ms; } int BPacket::inside(float px, float py) const { double dx = ((double) px - x_ ) ; double dy = ((double) py - y_ ) ; double d = sqrt(dx*dx + dy*dy) ; double dev = 1 ; if ((d <= (radius_ + dev)) && (d >= (radius_ - dev))) return 1 ; else return 0; } /* * Compute the start and end points of the packet in the one dimensional * time space [0, link delay]. */ inline int Packet::EndPoints(double now, double& tail, double& head) const { int doarrow; if (now < ta_) { head = now - ts_; doarrow = 1; } else { head = edge_->GetDelay(); doarrow = 0; } double t = now - tx_; tail = (t <= ts_) ? 0. : t - ts_; tail = tail * edge_->reallength() / edge_->delay(); head = head * edge_->reallength() / edge_->delay(); return (doarrow); } Packet::Packet(Edge *e, const PacketAttr& p, double s, double txtime, long offset ) : Animation(s, offset) { edge_ = e; e->AddPacket(this); pkt_ = p; ts_ = s; ta_ = s + e->GetDelay(); tx_ = txtime; arriving_ = 0; curTime_ = s; update_bb(); // Initial setup count_++; } Packet::~Packet() { if (monitor_!=NULL) { monitor_->delete_monitor_object(this); } count_--; } float Packet::distance(float /*x*/, float /*y*/) const { // TODO return HUGE_VAL; } /* * Compute the unit-space points for the packet polygon. * Return number of points in polygon. */ int Packet::ComputePolygon(double now, float ax[5], float ay[5]) const { double tail, head; int doarrow = EndPoints(now, tail, head); double deltap = head - tail; const Transform& m = edge_->transform(); double height = edge_->PacketHeight(); float bot = 0.2 * height; float top = 1.2 * height; float mid = 0.7 * height; /*XXX put some air between packet and link */ bot += 0.5 * height; top += 0.5 * height; mid += 0.5 * height; if (doarrow && deltap >= height) { /* packet with arrowhead */ m.map(tail, bot, ax[0], ay[0]); m.map(tail, top, ax[1], ay[1]); m.map(head - 0.75 * height, top, ax[2], ay[2]); m.map(head, mid, ax[3], ay[3]); m.map(head - 0.75 * height, bot, ax[4], ay[4]); return (5); } else { /* packet without arrowhead */ m.map(tail, bot, ax[0], ay[0]); m.map(tail, top, ax[1], ay[1]); m.map(head, top, ax[2], ay[2]); m.map(head, bot, ax[3], ay[3]); return (4); } } // Assuming that curTime_ is set correctly. This can be guaranteed since // the only way to adjust current time is through Packet::update(). void Packet::update_bb() { int npts; float x[5], y[5]; npts = ComputePolygon(curTime_, x, y); bb_.xmin = bb_.xmax = x[0]; bb_.ymin = bb_.ymax = y[0]; while (--npts > 0) { if (x[npts] < bb_.xmin) bb_.xmin = x[npts]; if (x[npts] > bb_.xmax) bb_.xmax = x[npts]; if (y[npts] < bb_.ymin) bb_.ymin = y[npts]; if (y[npts] > bb_.ymax) bb_.ymax = y[npts]; } } int Packet::inside(double now, float px, float py) const { int npts; float x[5], y[5]; BBox bb; if (now < ts_ || now > ta_ + tx_) return (0); npts = ComputePolygon(now, x, y); bb.xmin = bb.xmax = x[0]; bb.ymin = bb.ymax = y[0]; while (--npts > 0) { if (x[npts] < bb.xmin) bb.xmin = x[npts]; if (x[npts] > bb.xmax) bb.xmax = x[npts]; if (y[npts] < bb.ymin) bb.ymin = y[npts]; if (y[npts] > bb.ymax) bb.ymax = y[npts]; } return bb.inside(px, py); } const char* Packet::info() const { static char text[128]; sprintf(text, "%s %d: %s\n Sent at %.6f\n %d bytes\n", pkt_.type, pkt_.id, pkt_.convid, ts_, pkt_.size); return (text); } const char* Packet::gettype() const { static char text[128]; sprintf(text, "%s", pkt_.type); return (text); } const char* Packet::getfid() const { static char text[128]; sprintf(text, "%s", pkt_.convid); return (text); } const char* Packet::getesrc() const { static char text[128]; sprintf(text, "%d", pkt_.esrc); return (text); } const char* Packet::getedst() const { static char text[128]; sprintf(text, "%d", pkt_.edst); return (text); } const char* Packet::getname() const { static char text[128]; sprintf(text, "p"); return (text); } void Packet::monitor(Monitor *m, double , char *result, int ) { monitor_=m; sprintf(result, "%s %d: %s\n Sent at %.6f\n %d bytes", pkt_.type, pkt_.id, pkt_.convid, ts_, pkt_.size); } MonState *Packet::monitor_state() { /*return any state we wish the monitor to remember after we're gone*/ MonState *ms=new MonState; ms->type=MON_PACKET; ms->pkt.id=pkt_.id; return ms; } void Packet::RearrangePoints(View *v, int npts, float x[5], float y[5]) const { x[4] = (int) x[0] + 1; v->map(x[2], y[2]); v->map(x[1], y[1]); x[2] = (int) x[1] + 1; if (npts == 5) { v->map(x[3], y[3]); x[3] = x[2]; v->imap(x[3], y[3]); } v->imap(x[4], y[4]); v->imap(x[2], y[2]); } void Packet::CheckPolygon(View *v, int npts, float ax[5], float ay[5]) const { float x[5], y[5]; memcpy((char *)x, (char *)ax, npts * sizeof(float)); memcpy((char *)y, (char *)ay, npts * sizeof(float)); v->map(x[4], y[4]); v->map(x[0], y[0]); if ((x[4] > x[0]) && ((int)x[4] - (int)x[0] < 1)) { RearrangePoints(v, npts, x, y); memcpy((char *)ax, (char *)x, npts * sizeof(float)); memcpy((char *)ay, (char *)y, npts * sizeof(float)); } else if ((x[0] > x[4]) && (x[0] - x[4] < 1)) { float tmp; tmp = x[0], x[0] = x[4], x[4] = tmp; tmp = x[1], x[1] = x[2], x[2] = tmp; RearrangePoints(v, npts, x, y); tmp = x[0], x[0] = x[4], x[4] = tmp; tmp = x[1], x[1] = x[2], x[2] = tmp; memcpy((char *)ax, (char *)x, npts * sizeof(float)); memcpy((char *)ay, (char *)y, npts * sizeof(float)); } } void Packet::draw(View* nv, double now) const { /* XXX */ if (now < ts_ || now > ta_ + tx_) return; float x[5], y[5]; int npts; npts = ComputePolygon(now, x, y); //CheckPolygon(nv, npts, x, y); // Stupid way to decide fill/unfilled! // if ((pkt_.attr & 0x100) == 0) // nv->fill(x, y, npts, paint_); // else // nv->polygon(x, y, npts, paint_); nv->fill(x, y, npts, paint_); /*XXX stupid way to get size!*/ if (monitor_!=NULL) monitor_->draw(nv, x[0], y[0]); } /* void Packet::draw(PSView* nv, double now) const { if (now < ts_ || now > ta_ + tx_) return; float x[5], y[5]; int npts; npts = ComputePolygon(now, x, y); nv->fill(x, y, npts, paint_); } */ void Packet::update(double now) { if ((now > ta_)&&(arriving_==0)) { /*If the packet has started to arrive, trigger any arrival event for the edge*/ edge_->arrive_packet(this, ta_); arriving_=1; } if (now > ta_ + tx_ || now < ts_) { /* XXX this does not belong here */ #ifdef DEBUG printf("packet %d arrived from %d at %d\n", pkt_.id, edge_->src(), edge_->dst()); #endif /*remove this packet from the edge packet list*/ edge_->DeletePacket(this); delete this; } else { // Current time has changed, update its bounding box // XXX No clean way to keep its bb_ up-to-date. :( curTime_ = now; update_bb(); } } void Packet::position(float& x, float& y, double now) const { float xs[5], ys[5]; int npts; int i; /*XXX using ComputePolygon is overkill*/ npts = ComputePolygon(now, xs, ys); x=0;y=0; for(i=0;i<npts;i++) { x+=xs[i]; y+=ys[i]; } x/=npts; y/=npts; }

paint.cc


/* * Copyright (c) 1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #ifdef WIN32 #include <windows.h> #endif #include "config.h" #include "paint.h" #include "tclcl.h" Paint* Paint::instance_;
Paint::Paint() { Tcl& tcl = Tcl::instance(); Tk_Window tk = tcl.tkmain(); Tk_Uid bg = Tk_GetOption(tk, "viewBackground", NULL); XColor* p = Tk_GetColor(tcl.interp(), tk, bg); if (p == 0) abort(); background_ = p->pixel; XGCValues v; v.background = background_; v.foreground = background_; const unsigned long mask = GCForeground|GCBackground; gctab_ = new GC[PaintStaticGCSize]; rgb_ = new rgb[PaintStaticGCSize]; gcSize_ = PaintStaticGCSize; gctab_[0] = Tk_GetGC(tk, mask, &v); rgb_[0].colorname = strdup("black"); rgb_[0].red=p->red; rgb_[0].green=p->green; rgb_[0].blue=p->blue; ngc_ = 1; thick_ = lookup("black", 3); thin_ = lookup("black", 1); xor_ = lookupXor("black", 1); } void Paint::init() { instance_ = new Paint; } GC Paint::text_gc(Font fid, const char* color) { Tcl& tcl = Tcl::instance(); Tk_Window tk = tcl.tkmain(); XColor *p; if (color == NULL) p = Tk_GetColor(tcl.interp(), tk, "black"); else { Tk_Uid colorname; if (strcmp(color, "background") == 0) colorname = Tk_GetOption(tk, "viewBackground", NULL); else colorname = Tk_GetUid(color); p = Tk_GetColor(tcl.interp(), tk, colorname); } if (p == 0) return (0); XGCValues v; v.background = background_; v.foreground = p->pixel; v.line_width = 1; v.font = fid; const unsigned long mask = GCFont|GCForeground|GCBackground|GCLineWidth; return (Tk_GetGC(tk, mask, &v)); } char* Paint::lookupName(int r, int g, int b) { XColor color; Tcl& tcl = Tcl::instance(); Tk_Window tk = tcl.tkmain(); color.red = r; color.green = g; color.blue = b; XColor *p = Tk_GetColorByValue(tk,&color); return (Tk_NameOfColor(p)); } int Paint::lookup(const char * color, int linewidth) { Tcl& tcl = Tcl::instance(); Tk_Window tk = tcl.tkmain(); Tk_Uid colorname; if (strcmp(color, "background") == 0) colorname = Tk_GetOption(tk, "viewBackground", NULL); else colorname = Tk_GetUid(color); XColor* p = Tk_GetColor(tcl.interp(), tk, colorname); if (p == 0) { fprintf(stderr, "Nam: cannot find color %s, use default.\n", color); return (0); } XGCValues v; v.background = background_; v.foreground = p->pixel; v.line_width = linewidth; const unsigned long mask = GCForeground|GCBackground|GCLineWidth; GC gc = Tk_GetGC(tk, mask, &v); int i; for (i = 0; i < ngc_; ++i) if (gctab_[i] == gc) return (i); gctab_[i] = gc; rgb_[i].colorname = strdup(color); rgb_[i].red=p->red; rgb_[i].green=p->green; rgb_[i].blue=p->blue; ngc_ = i + 1; if (ngc_ >= gcSize_) // PaintStaticGCSize) adjust(); return (i); } int Paint::lookupXor(const char * color, int linewidth) { Tcl& tcl = Tcl::instance(); Tk_Window tk = tcl.tkmain(); Tk_Uid colorname; if (strcmp(color, "background") == 0) colorname = Tk_GetOption(tk, "background", NULL); else colorname = Tk_GetUid(color); XColor* p = Tk_GetColor(tcl.interp(), tk, colorname); if (p == 0) { fprintf(stderr, "Nam: cannot find color %s, use default.\n", color); return (0); } XGCValues v; v.background = background_; v.foreground = p->pixel ^ background_; v.line_width = linewidth; v.function = GXxor; const unsigned long mask = GCForeground|GCBackground|GCLineWidth|GCFunction; GC gc = Tk_GetGC(tk, mask, &v); int i; for (i = 0; i < ngc_; ++i) if (gctab_[i] == gc) return (i); gctab_[i] = gc; rgb_[i].colorname = strdup(color); rgb_[i].red=p->red; rgb_[i].green=p->green; rgb_[i].blue=p->blue; ngc_ = i + 1; if (ngc_ >= gcSize_) // PaintStaticGCSize) adjust(); return (i); } void Paint::adjust() { GC *tg = new GC[ngc_ + PaintGCIncrement]; rgb *tr = new rgb[ngc_ + PaintGCIncrement]; gcSize_ = ngc_ + PaintGCIncrement; memcpy((char *)tg, (char *)gctab_, sizeof(GC)*ngc_); memcpy((char *)tr, (char *)rgb_, sizeof(rgb)*ngc_); delete gctab_; delete rgb_; gctab_ = tg; rgb_ = tr; }

psview.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <ctype.h> #include <math.h> #include "bbox.h" #include "netview.h" #include "netmodel.h" #include "tclcl.h" #include "paint.h" #include "packet.h" #include "psview.h" void
PSView::zoom(float mag) { magnification_ *= mag; resize(width_, height_); } void PSView::resize(int width, int height) { width_ = width; height_ = height; matrix_.clear(); BBox bb; /*a model can choose to use these values, or can set its own*/ bb.xmin=0; bb.ymin=0; bb.xmax=width; bb.ymax=height; BoundingBox(bb); double x = (0.0-panx_)*width; double y = (0.0-pany_)*height; double w = width; double h = height; /* * Set up a transform that maps bb -> canvas. I.e, * bb -> unit square -> allocation, but which retains * the aspect ratio. Also, add a margin. */ double nw = bb.xmax - bb.xmin; double nh = bb.ymax - bb.ymin; /* * Grow a margin if we asked for square aspect ratio. */ double bbw; double bbh; if (aspect_==SQUARE) { bbw = 1.1 * nw; bbh = 1.1 * nh; } else { bbw = nw; bbh = nh; } #ifdef NOTDEF double tx = bb.xmin - 0.5 * (bbw - nw); double ty = bb.ymin - 0.5 * (bbh - nh); #endif /* * move base coordinate system to origin */ #ifdef NOTDEF matrix_.translate(-tx, -ty); #endif matrix_.translate(-bb.xmin, -bb.ymin); /* * flip vertical axis because X is backwards. */ double ws = w / bbw; double hs = h / bbh; if (aspect_==SQUARE) { if (ws <= hs) { matrix_.scale(ws, ws); scale_=ws; matrix_.translate(x, y + 0.5 * (h - ws * bbh)); } else { matrix_.scale(hs, hs); scale_=hs; matrix_.translate(x + 0.5 * (w - hs * bbw), y); } } else { matrix_.scale(ws, hs); matrix_.translate(x, y); } if ((width_<=0)||(height_<=0)) abort(); matrix_.scale(magnification_, magnification_); if (xscroll_!=NULL) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s set %f %f", xscroll_, panx_, panx_+(1.0/magnification_)); } if (yscroll_!=NULL) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s set %f %f", yscroll_, pany_, pany_+(1.0/magnification_)); } } void PSView::draw() { int xmin, ymin, xmax, ymax; BBox bb; BoundingBox(bb); matrix_.map(bb.xmin, bb.ymin, xmin, ymin); matrix_.map(bb.xmax, bb.ymax, xmax, ymax); /*Ensure we have a half inch border*/ xmin+=36; ymin+=36; xmax+=36; ymax+=36; file_ = fopen(name_, "w+"); fprintf(file_, "%%!PS-Adobe-2.0 EPSF-2.0\n"); fprintf(file_, "%%%%Creator: nam\n"); fprintf(file_, "%%%%DocumentFonts: Helvetica\n"); fprintf(file_, "%%%%BoundingBox: %d %d %d %d\n", xmin, ymin, xmax, ymax); fprintf(file_, "%%%%EndComments\n"); fprintf(file_, "gsave 36 36 translate\n"); fprintf(file_, "/namdict 20 dict def\n"); fprintf(file_, "namdict begin\n"); fprintf(file_, "/ft {/Helvetica findfont exch scalefont setfont\n"); fprintf(file_, "newpath 0 0 moveto (0) true charpath flattenpath\n"); fprintf(file_, "pathbbox /fh exch def pop pop pop} def\n"); fprintf(file_, "/center_show {/s exch def moveto s stringwidth\n"); fprintf(file_, "pop 2 div neg fh 2 div neg rmoveto s show} def\n"); fprintf(file_, "/north_show {/s exch def moveto s stringwidth\n"); fprintf(file_, "pop 2 div neg fh neg rmoveto s show} def\n"); fprintf(file_, "/south_show {/s exch def moveto s stringwidth\n"); fprintf(file_, "pop 2 div neg 0 rmoveto s show} def\n"); fprintf(file_, "/east_show {/s exch def moveto s stringwidth\n"); fprintf(file_, "pop neg fh 2 div neg rmoveto s show} def\n"); fprintf(file_, "/west_show {/s exch def moveto \n"); fprintf(file_, "0 fh 2 div neg rmoveto s show} def\n"); fprintf(file_, "/rect {newpath /h exch def /w exch def moveto\n"); fprintf(file_, "w 0 rlineto 0 h rlineto w neg 0 rlineto\n"); fprintf(file_, "0 h neg rlineto closepath stroke} def\n"); fprintf(file_, "/line {newpath moveto lineto stroke} def\n"); fprintf(file_, "/circle {newpath 0 360 arc stroke} def\n"); fprintf(file_, "end\n"); fprintf(file_, "%%%%EndProlog\n"); fprintf(file_, "namdict begin\n"); model_->render(this); fprintf(file_, "showpage\n"); fprintf(file_, "end\n"); fprintf(file_, "%%%%Trailer\n"); fclose(file_); } PSView::PSView(const char* name, NetModel* m) : View(name, SQUARE,200,200), model_(m), scale_(1.0) { name_=new char[strlen(name)+1]; strcpy(name_, name); resize(540,720); draw(); } extern void Parse(NetModel*, const char* layout); int PSView::command(ClientData cd, Tcl_Interp* tcl, int argc, char **argv) { PSView *pv = (PSView *)cd; if (argc < 2) { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return (TCL_ERROR); } if (strcmp(argv[1], "xscroll") == 0) { if (argc == 3) { pv->xscroll_=new char[strlen(argv[2])+1]; strcpy(pv->xscroll_, argv[2]); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "yscroll") == 0) { if (argc == 3) { pv->yscroll_=new char[strlen(argv[2])+1]; strcpy(pv->yscroll_, argv[2]); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "zoom") == 0) { if (argc == 3) { float mag=atof(argv[2]); if (mag>1.0) { pv->panx_+=(1.0-1.0/mag)/(2.0*pv->magnification_); pv->pany_+=(1.0-1.0/mag)/(2.0*pv->magnification_); } else { pv->panx_-=(1.0-mag)/(2.0*pv->magnification_*mag); pv->pany_-=(1.0-mag)/(2.0*pv->magnification_*mag); } pv->zoom(mag); pv->draw(); //pv->pan(panx, pany); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if ((strcmp(argv[1], "xview") == 0)||(strcmp(argv[1], "yview")==0)) { if ((argc==4)&&(strcmp(argv[2], "moveto")==0)) { if (strcmp(argv[1], "xview") == 0) pv->panx_=atof(argv[3]); else pv->pany_=atof(argv[3]); pv->resize(pv->width_, pv->height_); pv->draw(); } else if ((argc==5)&&(strcmp(argv[2], "scroll")==0)) { float step=atof(argv[3]); if (strcmp(argv[4], "units")==0) { step*=0.05/pv->magnification_; } else if (strcmp(argv[4], "pages")==0) { step*=0.8/pv->magnification_; } if (strcmp(argv[1], "xview") == 0) pv->panx_+=step; else pv->pany_+=step; pv->resize(pv->width_, pv->height_); pv->draw(); } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } return TCL_OK; } Tcl_AppendResult(tcl, "\"", argv[0], "\": unknown arg: ", argv[1], 0); return (TCL_ERROR); } void PSView::line(float x0, float y0, float x1, float y1, int paint) { float ax, ay; matrix_.map(x0, y0, ax, ay); float bx, by; matrix_.map(x1, y1, bx, by); #ifdef NOTDEF GC gc = Paint::instance()->paint_to_gc(paint); XDrawLine(Tk_Display(tk_), offscreen_, gc, ax, ay, bx, by); #endif rgb *color= Paint::instance()->paint_to_rgb(paint); fprintf(file_, "%.2f %.2f %.2f setrgbcolor\n", color->red/65536.0, color->green/65536.0, color->blue/65536.0); fprintf(file_, "%.1f %.1f %.1f %.1f line\n", ax, ay, bx, by); } void PSView::rect(float x0, float y0, float x1, float y1, int paint) { float x, y; matrix_.map(x0, y0, x, y); float xx, yy; matrix_.map(x1, y1, xx, yy); float w = xx - x; if (w < 0) { x = xx; w = -w; } float h = yy - y; if (h < 0) { h = -h; y = yy; } #ifdef NOTDEF GC gc = Paint::instance()->paint_to_gc(paint); XDrawRectangle(Tk_Display(tk_), offscreen_, gc, x, y, w, h); #endif if (x>0 && y>0) { rgb *color= Paint::instance()->paint_to_rgb(paint); fprintf(file_, "%.2f %.2f %.2f setrgbcolor\n", color->red/65536.0, color->green/65536.0, color->blue/65536.0); fprintf(file_, "%.1f %.1f %.1f %.1f rect\n", x, y, w, h); } } typedef struct floatpoint_s { float x, y; } floatpoint; void PSView::polygon(const float* x, const float* y, int n, int paint) { /*XXX*/ floatpoint pts[10]; int i; for (i = 0; i < n; ++i) { matrix_.map(x[i], y[i], pts[i].x, pts[i].y); } pts[n] = pts[0]; #ifdef NOTDEF GC gc = Paint::instance()->paint_to_gc(paint); XDrawLines(Tk_Display(tk_), offscreen_, gc, pts, n + 1, CoordModeOrigin); #endif fprintf(file_,"%%polygon\n"); rgb *color= Paint::instance()->paint_to_rgb(paint); fprintf(file_, "%.2f %.2f %.2f setrgbcolor\n", color->red/65536.0, color->green/65536.0, color->blue/65536.0); fprintf(file_, "newpath %.1f %.1f moveto\n", pts[0].x, pts[0].y); for(i=1; i<=n; i++) fprintf(file_, "%.1f %.1f lineto\n", pts[i].x, pts[i].y); fprintf(file_, "closepath stroke\n"); } void PSView::fill(const float* x, const float* y, int n, int paint) { /*XXX*/ floatpoint pts[10]; int i; for (i = 0; i < n; ++i) { matrix_.map(x[i], y[i], pts[i].x, pts[i].y); } pts[n] = pts[0]; #ifdef NOTDEF GC gc = Paint::instance()->paint_to_gc(paint); XFillPolygon(Tk_Display(tk_), offscreen_, gc, pts, n + 1, Convex, CoordModeOrigin); #endif fprintf(file_,"%%fill\n"); rgb *color= Paint::instance()->paint_to_rgb(paint); fprintf(file_, "%.2f %.2f %.2f setrgbcolor\n", color->red/65536.0, color->green/65536.0, color->blue/65536.0); fprintf(file_, "newpath %.1f %.1f moveto\n", pts[0].x, pts[0].y); for(i=1; i<=n; i++) fprintf(file_, "%.1f %.1f lineto\n", pts[i].x, pts[i].y); fprintf(file_, "fill\n"); } void PSView::circle(float x, float y, float r, int paint) { float tx, ty; matrix_.map(x, y, tx, ty); float tr, dummy; matrix_.map(x + r, y, tr, dummy); tr -= tx; #ifdef NOTDEF GC gc = Paint::instance()->paint_to_gc(paint); XDrawArc(Tk_Display(tk_), offscreen_, gc, tx, ty, tr, tr, 0, 64 * 360); #endif rgb *color= Paint::instance()->paint_to_rgb(paint); fprintf(file_, "%.2f %.2f %.2f setrgbcolor\n", color->red/65536.0, color->green/65536.0, color->blue/65536.0); fprintf(file_, "%.1f %.1f %.1f circle\n", tx, ty, tr); } // We'll ignore string color in PS view! void PSView::string(float fx, float fy, float dim, const char* s, int anchor, const char*) { float x, y; matrix_.map(fx, fy, x, y); float dummy, dlow, dhigh; matrix_.map(0., 0., dummy, dlow); matrix_.map(0., 0.6 * dim, dummy, dhigh); int d = int(dhigh - dlow); fprintf(file_, "%d ft\n", d); fprintf(file_, "0 0 0 setrgbcolor\n"); switch (anchor) { case ANCHOR_CENTER: fprintf(file_, "%.1f %.1f (%s) center_show\n", x, y, s); break; case ANCHOR_NORTH: fprintf(file_, "%.1f %.1f (%s) north_show\n", x, y, s); break; case ANCHOR_SOUTH: fprintf(file_, "%.1f %.1f (%s) south_show\n", x, y, s); break; case ANCHOR_WEST: fprintf(file_, "%.1f %.1f (%s) west_show\n", x, y, s); break; case ANCHOR_EAST: fprintf(file_, "%.1f %.1f (%s) east_show\n", x, y, s); break; } }

queue.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #ifdef WIN32 #include <windows.h> #endif #include "netview.h" #include "psview.h" #include "queue.h" #include "drop.h" #include "monitor.h" #include "sincos.h" QueueItem::QueueItem(const PacketAttr& p, double tim, long offset) : Animation(tim, offset), qnext_(0) { pkt_ = p; } QueueItem::~QueueItem() { if (monitor_!=NULL) { monitor_->delete_monitor_object(this); } } void QueueItem::draw(View* nv, double ) const { /* * only draw things that are within the bounding * box... otherwise, we might hang the display :( -kfall * note: this is an incomplete fix; there remains * a bug where the packets in the queue aren't erased * properly when this case triggers 8/8/99 */ BBox bb; nv->BoundingBox(bb); if (bb.inside(bb_)) { nv->fill(px_, py_, 4, paint_); if (monitor_!=NULL) monitor_->draw(nv, px_[0],py_[0]); } } float QueueItem::distance(float x, float y) const { float cx, cy; cx = (bb_.xmin + bb_.xmax) / 2; cy = (bb_.ymin + bb_.ymax) / 2; return ((cx-x) * (cx-x) + (cy-y)*(cy-y)); } void
QueueItem::position(float& x, float& y) { /* XXX this is stupid */ x = px_[0]; y = py_[0]; } void QueueItem::update_bb() { bb_.xmin = bb_.xmax = px_[0]; bb_.ymin = bb_.ymax = py_[0]; for (int i = 0; i < 4; i++) { if (px_[i] < bb_.xmin) bb_.xmin = px_[i]; if (px_[i] > bb_.xmax) bb_.xmax = px_[i]; if (py_[i] < bb_.ymin) bb_.ymin = py_[i]; if (py_[i] < bb_.ymax) bb_.ymax = py_[i]; } } void QueueItem::locate(float x, float y, float dx, float dy) { px_[0] = x; py_[0] = y; x += dy; y -= dx; px_[1] = x; py_[1] = y; x += dx; y += dy; px_[2] = x; py_[2] = y; x -= dy; y += dx; px_[3] = x; py_[3] = y; update_bb(); } const char* QueueItem::info() const { static char text[128]; sprintf(text, "%s %d: %s\n %d bytes\n", pkt_.type, pkt_.id, pkt_.convid, pkt_.size); return (text); } const char* QueueItem::getname() const { static char text[128]; sprintf(text, "p"); return (text); } void QueueItem::monitor(Monitor *m, double /*now*/, char *result, int /*len*/) { monitor_=m; sprintf(result, "%s %d: %s\n %d bytes\n", pkt_.type, pkt_.id, pkt_.convid, pkt_.size); } MonState *QueueItem::monitor_state() { /*return any state we wish the monitor to remember after we're gone*/ MonState *ms=new MonState; ms->type=MON_PACKET; ms->pkt.id=pkt_.id; return ms; } Queue::Queue(float angle) : cnt_(0), psize_(0.), nb_(0), angle_(angle) { head_ = 0; tail_ = &head_; } void Queue::place(double psize, double x, double y) { psize_ = psize; double qc, qs; SINCOSPI(angle_, &qs, &qc); dx_ = qc * psize_; dy_ = qs * psize_; px_ = 3 * dx_ / 4; py_ = 3 * dy_ / 4; qx_ = x + 2 * dx_; qy_ = y + 2 * dy_; } void Queue::relocate() { float x = qx_, y = qy_; for (QueueItem *q = head_; q != 0; q = q->qnext_) { q->locate(x, y, px_, py_); x += dx_; y += dy_; } } QueueItem *Queue::remove(const PacketAttr& p, int& pos) { QueueItem* q; pos = 0; for (QueueItem **pp = &head_; (q = *pp) != 0; pp = &q->qnext_) { ++pos; if (q->pkt_.id == p.id /* kfall && q->pkt_.attr == p.attr, see below */ && q->pkt_.size == p.size && strcmp(q->pkt_.convid, p.convid) == 0 && strcmp(q->pkt_.type, p.type)== 0) { --cnt_; nb_ -= q->pkt_.size; *pp = q->qnext_; if (*pp == 0) tail_ = pp; relocate(); return (q); } } return (0); /* * the removal of the attr comparison is needed * because when RED marks packets, the "-" records * have a different attrib than the corresponding "r" or * "+" records. If one looks for matching attribs, * then all of the packets drained from the queue * that have ecn marks on them are never actually * erased, leaving curious packets laying around * in the queue even when the outgoing link is idle * -kfall 8/8/99 */ } void Queue::enque(QueueItem *q, int mode) { /*add to the tail if time is running forwards, else add to the head*/ if (mode==QUEUE_TAIL) { *tail_ = q; tail_ = &q->qnext_; q->qnext_ = 0; ++cnt_; nb_ += q->pkt_.size; relocate(); } else if (mode==QUEUE_HEAD) { q->qnext_=head_; head_=q; ++cnt_; nb_ += q->pkt_.size; relocate(); } } void Queue::reset(double /*now*/) { while (head_ != 0) { QueueItem *n = head_->qnext_; delete head_; head_ = n; } head_ = 0; tail_ = &head_; cnt_ = 0; nb_ = 0; }

random.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1995 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * "@(#) $Header$ (LBL)"; */ #ifndef WIN32 #include <sys/time.h> #include "config.h" #include "random.h" RANDOM_RETURN_TYPE random() { printf("random() called in ns.\nRandom is not portable, please use Random::uniform() instead.\n"); abort(); } #endif WIN32

rng.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif /* new random number generator */ #ifndef WIN32 #include <sys/time.h> // for gettimeofday #include <unistd.h> #endif #include <stdio.h> #include "rng.h" #ifndef MAXINT #define MAXINT 2147483648 // XX [for now] #endif #if defined(sun) extern "C" { // XXX Why not include config.h? int atoi(...); // int gettimeofday(struct timeval*, struct timezone*); int gettimeofday(...); //fix to work on solaris as well } #endif /* * RNGImplementation */ /* * Generate a periodic sequence of pseudo-random numbers with * a period of 2^31 - 2. The generator is the "minimal standard" * multiplicative linear congruential generator of Park, S.K. and * Miller, K.W., "Random Number Generators: Good Ones are Hard to Find," * CACM 31:10, Oct. 88, pp. 1192-1201. * * The algorithm implemented is: Sn = (a*s) mod m. * The modulus m can be approximately factored as: m = a*q + r, * where q = m div a and r = m mod a. * * Then Sn = g(s) + m*d(s) * where g(s) = a(s mod q) - r(s div q) * and d(s) = (s div q) - ((a*s) div m) * * Observations: * - d(s) is either 0 or 1. * - both terms of g(s) are in 0, 1, 2, . . ., m - 1. * - |g(s)| <= m - 1. * - if g(s) > 0, d(s) = 0, else d(s) = 1. * - s mod q = s - k*q, where k = s div q. * * Thus Sn = a(s - k*q) - r*k, * if (Sn <= 0), then Sn += m. * * To test an implementation for A = 16807, M = 2^31-1, you should * get the following sequences for the given starting seeds: * * s0, s1, s2, s3, . . . , s10000, . . . , s551246 * 1, 16807, 282475249, 1622650073, . . . , 1043618065, . . . , 1003 * 1973272912, 1207871363, 531082850, 967423018 * * It is important to check for s10000 and s551246 with s0=1, to guard * against overflow. */ /* * The sparc assembly code [no longer here] is based on Carta, D.G., "Two Fast * Implementations of the 'Minimal Standard' Random Number * Generator," CACM 33:1, Jan. 90, pp. 87-88. * * ASSUME that "the product of two [signed 32-bit] integers (a, sn) * will occupy two [32-bit] registers (p, q)." * Thus: a*s = (2^31)p + q * * From the observation that: x = y mod z is but * x = z * the fraction part of (y/z), * Let: sn = m * Frac(as/m) * * For m = 2^31 - 1, * sn = (2^31 - 1) * Frac[as/(2^31 -1)] * = (2^31 - 1) * Frac[as(2^-31 + 2^-2(31) + 2^-3(31) + . . .)] * = (2^31 - 1) * Frac{[(2^31)p + q] [2^-31 + 2^-2(31) + 2^-3(31) + . . .]} * = (2^31 - 1) * Frac[p+(p+q)2^-31+(p+q)2^-2(31)+(p+q)3^(-31)+ . . .] * * if p+q < 2^31: * sn = (2^31 - 1) * Frac[p + a fraction + a fraction + a fraction + . . .] * = (2^31 - 1) * [(p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .] * = p + q * * otherwise: * sn = (2^31 - 1) * Frac[p + 1.frac . . .] * = (2^31 - 1) * (-1 + 1.frac . . .) * = (2^31 - 1) * [-1 + (p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .] * = p + q - 2^31 + 1 */ #define A 16807L /* multiplier, 7**5 */ #define M 2147483647L /* modulus, 2**31 - 1; both used in random */ #define INVERSE_M ((double)4.656612875e-10) /* (1.0/(double)M) */ long
RNGImplementation::next() { long L, H; L = A * (seed_ & 0xffff); H = A * (seed_ >> 16); seed_ = ((H & 0x7fff) << 16) + L; seed_ -= 0x7fffffff; seed_ += H >> 15; if (seed_ <= 0) { seed_ += 0x7fffffff; } return(seed_); } double RNGImplementation::next_double() { long i = next(); return i * INVERSE_M; } /* * RNG implements a nice front-end around RNGImplementation */ static class RNGClass : public TclClass { public: RNGClass() : TclClass("RNG") {} TclObject* create(int, const char*const*) { return(new RNG()); } } class_rng; /* default RNG */ RNG* RNG::default_ = NULL; int RNG::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "testint") == 0) { int n = atoi(argv[2]); tcl.resultf("%d", uniform(n)); return (TCL_OK); } if (strcmp(argv[1], "testdouble") == 0) { double d = atof(argv[2]); tcl.resultf("%6e", uniform(d)); return (TCL_OK); } if (strcmp(argv[1], "seed") == 0) { int s = atoi(argv[2]); // NEEDSWORK: should be a way to set seed to PRDEF_SEED_SORUCE if (s) { if (s <= 0 || (unsigned int)s >= MAXINT) { // MAXINT on freebsd is a ``black hole'' (it says at MAXINT). tcl.resultf("Setting random number seed to known bad value."); return TCL_ERROR; }; set_seed(RAW_SEED_SOURCE, s); } else set_seed(HEURISTIC_SEED_SOURCE, 0); return(TCL_OK); } } if (argc == 2) { if (strcmp(argv[1], "next-random") == 0) { tcl.resultf("%u", uniform_positive_int()); return(TCL_OK); } if (strcmp(argv[1], "seed") == 0) { tcl.resultf("%u", stream_.seed()); return(TCL_OK); } if (strcmp(argv[1], "default") == 0) { default_ = this; return(TCL_OK); } #if 0 if (strcmp(argv[1], "test") == 0) { if (test()) tcl.resultf("RNG test failed"); else tcl.resultf("RNG test passed"); return(TCL_OK); } #endif } return(TclObject::command(argc, argv)); } void RNG::set_seed(RNGSources source, int seed) { /* The following predefined seeds are evenly spaced around * the 2^31 cycle. Each is approximately 33,000,000 elements * apart. */ #define N_SEEDS_ 64 static long predef_seeds[N_SEEDS_] = { 1973272912L, 188312339L, 1072664641L, 694388766L, 2009044369L, 934100682L, 1972392646L, 1936856304L, 1598189534L, 1822174485L, 1871883252L, 558746720L, 605846893L, 1384311643L, 2081634991L, 1644999263L, 773370613L, 358485174L, 1996632795L, 1000004583L, 1769370802L, 1895218768L, 186872697L, 1859168769L, 349544396L, 1996610406L, 222735214L, 1334983095L, 144443207L, 720236707L, 762772169L, 437720306L, 939612284L, 425414105L, 1998078925L, 981631283L, 1024155645L, 822780843L, 701857417L, 960703545L, 2101442385L, 2125204119L, 2041095833L, 89865291L, 898723423L, 1859531344L, 764283187L, 1349341884L, 678622600L, 778794064L, 1319566104L, 1277478588L, 538474442L, 683102175L, 999157082L, 985046914L, 722594620L, 1695858027L, 1700738670L, 1995749838L, 1147024708L, 346983590L, 565528207L, 513791680L }; static long heuristic_sequence = 0; switch (source) { case RAW_SEED_SOURCE: // use it as it is break; case PREDEF_SEED_SOURCE: if (seed < 0 || seed >= N_SEEDS_) abort(); seed = predef_seeds[seed]; break; case HEURISTIC_SEED_SOURCE: timeval tv; gettimeofday(&tv, 0); heuristic_sequence++; // Always make sure we're different than last time. seed = (tv.tv_sec ^ tv.tv_usec ^ (heuristic_sequence << 8)) & 0x7fffffff; break; }; // set it // NEEDSWORK: should we throw out known bad seeds? // (are there any?) if (seed < 0) seed = -seed; stream_.set_seed(seed); // Toss away the first few values of heuristic seed. // In practice this makes sequential heuristic seeds // generate different first values. // // How many values to throw away should be the subject // of careful analysis. Until then, I just throw away // ``a bunch''. --johnh if (source == HEURISTIC_SEED_SOURCE) { int i; for (i = 0; i < 128; i++) { stream_.next(); }; }; } /* * RNGTest: * Make sure the RNG makes known values. * Optionally, print out some stuff. * * Simple test program: * #include "rng.h" * void main() { RNGTest test; test.verbose(); } */ #ifdef rng_test RNGTest::RNGTest() { RNG rng(RNG::RAW_SEED_SOURCE, 1L); int i; long r; for (i = 0; i < 10000; i++) r = rng.uniform_positive_int(); if (r != 1043618065L) abort(); for (i = 10000; i < 551246; i++) r = rng.uniform_positive_int(); if (r != 1003L) abort(); } void RNGTest::first_n(RNG::RNGSources source, long seed, int n) { RNG rng(source, seed); for (int i = 0; i < n; i++) { int r = rng.uniform_positive_int(); printf("%10d ", r); }; printf("\n"); } void RNGTest::verbose() { printf ("default: "); first_n(RNG::RAW_SEED_SOURCE, 1L, 5); int i; for (i = 0; i < 64; i++) { printf ("predef source %2d: ", i); first_n(RNG::PREDEF_SEED_SOURCE, i, 5); }; printf("heuristic seeds should be different from each other and on each run.\n"); for (i = 0; i < 64; i++) { printf ("heuristic source %2d: ", i); first_n(RNG::HEURISTIC_SEED_SOURCE, i, 5); }; } #endif /* rng_test */

route.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifdef WIN32 #include <windows.h> #endif #include "netview.h" #include "psview.h" #include "route.h" #include "feature.h" #include "agent.h" #include "edge.h" #include "node.h" #include "monitor.h" #include "paint.h" Route::Route(Node *n, Edge *e, int group, int pktsrc, int negcache, int oif, double timer, double now) : Animation(0, 0), next_(0), edge_(e), node_(n), group_(group), pktsrc_(pktsrc), timeout_(timer), timeset_(now), anchor_(0), mark_(0) { mode_=0; if (negcache==1) mode_|=NEG_CACHE; else mode_|=POS_CACHE; if (oif==1) mode_|=OIF; else mode_|=IIF; /*copy the transform matrix from the edge*/ angle_ = e->angle(); matrix_ = e->transform(); } Route::~Route() { if (monitor_!=NULL) { monitor_->delete_monitor_object(this); } } void
Route::update_bb() { bb_.xmin = x_[0]; bb_.xmax = x_[0]; bb_.ymin = y_[0]; bb_.ymax = y_[0]; for(int i=1;i<npts_;i++) { if (bb_.xmin>x_[i]) bb_.xmin=x_[i]; if (bb_.xmax<x_[i]) bb_.xmax=x_[i]; if (bb_.ymin>y_[i]) bb_.ymin=y_[i]; if (bb_.ymax<y_[i]) bb_.ymax=y_[i]; } } // Moved to Animation::inside() // int Route::inside(double /*now*/, float px, float py) const // { // float minx, maxx, miny, maxy; // minx=x_[0]; // maxx=x_[0]; // miny=y_[0]; // maxy=y_[0]; // for(int i=1;i<npts_;i++) // { // if (minx>x_[i]) minx=x_[i]; // if (maxx<x_[i]) maxx=x_[i]; // if (miny>y_[i]) miny=y_[i]; // if (maxy<y_[i]) maxy=y_[i]; // } // return ((minx<=px)&&(maxx>=px)&&(miny<=py)&&(maxy>=py)); // } void Route::place(double x0, double y0) { int ctr = node_->no_of_routes(edge_)-1; place(x0,y0,ctr); } void Route::place(double x0, double y0, int ctr) { float tx,ty; /*matrix was copied from the edge - don't need to set it up here*/ //double size=edge_->size(); double size = node_->size() * 0.2; double offset=size*2*(ctr); // XXX Make sure we have up-to-date information from the edge angle_ = edge_->angle(); matrix_ = edge_->transform(); matrix_.imap((float)x0,(float)y0, tx,ty); if ((mode_&POS_CACHE)>0) { if ((mode_&OIF)>0) { matrix_.map((float)tx+offset, (float)(ty+size), x_[0], y_[0]); matrix_.map((float)tx+offset, (float)(ty-size), x_[1], y_[1]); matrix_.map((float)(tx+offset+size*3), (float)ty, x_[2], y_[2]); } if ((mode_&IIF)>0) { matrix_.map((float)(tx+offset+size*2), (float)(ty+size), x_[0], y_[0]); matrix_.map((float)(tx+offset+size*2), (float)(ty-size), x_[1], y_[1]); matrix_.map((float)(tx+offset-size), (float)ty, x_[2], y_[2]); } npts_=3; } else { matrix_.map((float)(tx+offset), (float)(ty+size), x_[0], y_[0]); matrix_.map((float)(tx+offset+size), (float)(ty+size), x_[1], y_[1]); matrix_.map((float)(tx+offset+size), (float)(ty-size), x_[2], y_[2]); matrix_.map((float)(tx+offset), (float)(ty-size), x_[3], y_[3]); npts_=4; } update_bb(); } int Route::matching_route(Edge *e, int group, int pktsrc, int oif) const { if ((edge_==e)&&(group_==group)&&(pktsrc_==pktsrc)) { if (((oif==1)&&((mode_&OIF)>0)) || ((oif==0)&&((mode_&IIF)>0))) return 1; } return 0; } const char* Route::info() const { static char text[128]; static char source[64]; if (group_>=0) { if (pktsrc_<0) strcpy(source, "*"); else sprintf(source, "%d", pktsrc_); sprintf(text, "Multicast Route:\nSource:%s\nGroup:%d\nTimeout:%f", source, group_, curtimeout_); if ((mode_&NEG_CACHE)>0) strcat(text, "\nPrune Entry"); return (text); } else { sprintf(text, "Unicast Route:\nDestination:%d\nTimeout:%f", pktsrc_, curtimeout_); return (text); } } const char* Route::getname() const { static char text[128]; sprintf(text, "r"); return (text); } void Route::monitor(Monitor *m, double /*now*/, char *result, int len) { monitor_=m; strncpy(result, info(), len); } MonState *Route::monitor_state() { MonState *ms=new MonState; ms->type=MON_ROUTE; ms->route.src=pktsrc_; ms->route.group=group_; ms->route.node=node_; return ms; } void Route::draw(View *nv, double /*now*/) const { nv->fill(x_, y_, npts_, paint_); if (monitor_!=NULL) monitor_->draw(nv, (x_[0]+x_[2])/2, (y_[0]+y_[2])/2); } //void Route::draw(PSView *nv, double /*now*/) const /* { nv->fill(x_, y_, npts_, paint_); } */ void Route::update(double now) { curtimeout_=timeout_+timeset_-now; if (curtimeout_<0) curtimeout_=0; /*XXX could make a zero timeout delete the route*/ /* but this would make the tracefile unidirectional*/ } void Route::reset(double /*now*/) { node_->delete_route(this); delete this; }

state.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include "state.h" State* State::instance_; void
State::init(int s) { instance_ = new State(s); } State::State(int s) : cnt_(0), size_(s) { states = new StateItem[size_]; } /* Set the times at which state info should be saved. */ void State::setTimes(double mintime, double maxtime) { double incr = (maxtime - mintime) / size_; double tim = mintime; for (int i = 0; i < size_; i++) { tim += incr; states[i].time = tim; } } void State::get(double tim, StateInfo& s) { for (int i = cnt_-1; i >= 0; i--) if (states[i].time < tim) { s = states[i].si; return; } s.time = 0.; s.offset = 0; } void State::set(double tim, StateInfo& info) { if (cnt_ < size_) { states[cnt_].time = tim; states[cnt_++].si = info; } } /* Return the next time that state info should be saved. */ double State::next() { return (states[cnt_].time); }

tag.cc


// // Copyright (c) 1997 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for non-commercial purposes // and without fee is hereby granted, provided that the above copyright // notice appear in all copies and that both the copyright notice and // this permission notice appear in supporting documentation. and that // any documentation, advertising materials, and other materials related // to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the University may not be used to // endorse or promote products derived from this software without // specific prior written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about // the suitability of this software for any purpose. THIS SOFTWARE IS // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // Other copyrights might apply to parts of this software and are so // noted when applicable. // // $Header$ #ifdef WIN32 #include <windows.h> #endif #include <string.h> #include <tcl.h> #include "animation.h" #include "tag.h" #include "view.h" Tag::Tag() : Animation(0, 0), nMbr_(0), name_(NULL) { mbrHash_ = new Tcl_HashTable; Tcl_InitHashTable(mbrHash_, TCL_ONE_WORD_KEYS); } Tag::Tag(const char *name) : Animation(0, 0), nMbr_(0) { size_t len = strlen(name); if (len == 0) name_ = NULL; else { name_ = new char[len+1]; strcpy(name_, name); } mbrHash_ = new Tcl_HashTable; Tcl_InitHashTable(mbrHash_, TCL_ONE_WORD_KEYS); } Tag::~Tag() { remove(); Tcl_DeleteHashTable(mbrHash_); delete mbrHash_; if (name_ != NULL) delete []name_; } void
Tag::setname(const char *name) { if (name_ != NULL) delete name_; size_t len = strlen(name); if (len == 0) name_ = NULL; else { name_ = new char[len+1]; strcpy(name_, name); } } void Tag::add(Animation *a) { int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(mbrHash_,(const char *)a->id(), &newEntry); if (newEntry && (he != NULL)) { // Do not handle exception he == NULL. Don't know how. Tcl_SetHashValue(he, (ClientData)a); nMbr_++; a->merge(bb_); // Let that object know about this group a->addTag(this); } } void Tag::remove() { // Remove this tag from all its members Animation *p; Tcl_HashEntry *he; Tcl_HashSearch hs; int i = 0; for (he = Tcl_FirstHashEntry(mbrHash_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs), i++) { p = (Animation *) Tcl_GetHashValue(he); p->deleteTag(this); Tcl_DeleteHashEntry(he); nMbr_--; } bb_.clear(); } void Tag::remove(Animation *a) { Tcl_HashEntry *he = Tcl_FindHashEntry(mbrHash_, (const char *)a->id()); if (he != NULL) { a->deleteTag(this); Tcl_DeleteHashEntry(he); nMbr_--; update_bb(); } } void Tag::draw(View *v, double) const { // XXX don't draw anything except it's selected. Or draw // 4 black dots in the 4 corners. v->rect(bb_.xmin, bb_.ymin, bb_.xmax, bb_.ymax, Paint::instance()->thin()); } // Used for xor-draw only void Tag::xdraw(View *v, double now) const { // Draw every object of this group Tcl_HashEntry *he; Tcl_HashSearch hs; Animation *a; for (he = Tcl_FirstHashEntry(mbrHash_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs)) { a = (Animation *) Tcl_GetHashValue(he); a->draw(v, now); } } void Tag::update_bb(void) { Tcl_HashEntry *he; Tcl_HashSearch hs; Animation *a; bb_.clear(); for (he = Tcl_FirstHashEntry(mbrHash_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs)) { a = (Animation *) Tcl_GetHashValue(he); a->merge(bb_); } } void Tag::reset(double /*now*/) { } // Move this object and update bbox void Tag::move(EditView *v, float wdx, float wdy) { Tcl_HashEntry *he; Tcl_HashSearch hs; Animation *a; bb_.clear(); for (he = Tcl_FirstHashEntry(mbrHash_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs)) { a = (Animation *) Tcl_GetHashValue(he); a->move(v, wdx, wdy); a->merge(bb_); } // We do separate move for bb_ because } const char *Tag::info() const { static char str[256]; strcpy(str, "Tag"); return str; }

testview.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <ctype.h> #include <math.h> #include "bbox.h" #include "netview.h" #include "netmodel.h" #include "tclcl.h" #include "paint.h" #include "packet.h" #include "testview.h" void
TestView::resize(int width, int height) { width_ = width; height_ = height; matrix_.clear(); BBox bb; bb.xmin=0; bb.ymin=0; bb.xmax=width; bb.ymax=height; BoundingBox(bb); double x = (0.0-panx_)*width; double y = (0.0-pany_)*height; double w = width; double h = height; double nw = bb.xmax - bb.xmin; double nh = bb.ymax - bb.ymin; double bbw; double bbh; if (aspect_==SQUARE) { bbw = 1.1 * nw; bbh = 1.1 * nh; } else { bbw = nw; bbh = nh; } matrix_.translate(-bb.xmin, -bb.ymin); double ws = w / bbw; double hs = h / bbh; if (aspect_==SQUARE) { if (ws <= hs) { matrix_.scale(ws, ws); scale_=ws; matrix_.translate(x, y + 0.5 * (h - ws * bbh)); } else { matrix_.scale(hs, hs); scale_=hs; matrix_.translate(x + 0.5 * (w - hs * bbw), y); } } else { matrix_.scale(ws, hs); matrix_.translate(x, y); } if ((width_<=0)||(height_<=0)) abort(); matrix_.scale(magnification_, magnification_); } int count = 0; void TestView::draw() { int xmin, ymin, xmax, ymax; BBox bb; BoundingBox(bb); matrix_.map(bb.xmin, bb.ymin, xmin, ymin); matrix_.map(bb.xmax, bb.ymax, xmax, ymax); xmin+=36; ymin+=36; xmax+=36; ymax+=36; file_ = fopen(name_, "a"); fprintf(file_, "\n--- snapshot (%d) ---\n", count); count++; model_->render(this); fclose(file_); } TestView::TestView(const char* name, NetModel* m) : View(name, SQUARE,200,200), model_(m), scale_(1.0) { name_=new char[strlen(name)+1]; strcpy(name_, name); resize(540,720); draw(); } void TestView::line(float x0, float y0, float x1, float y1, int paint) { float ax, ay; matrix_.map(x0, y0, ax, ay); float bx, by; matrix_.map(x1, y1, bx, by); rgb *color= Paint::instance()->paint_to_rgb(paint); fprintf(file_, "half line "); fprintf(file_, "from <%.1f %.1f> to <%.1f %.1f>\n", ax, ay, bx, by); } void TestView::rect(float x0, float y0, float x1, float y1, int paint) { float x, y; matrix_.map(x0, y0, x, y); float xx, yy; matrix_.map(x1, y1, xx, yy); float w = xx - x; if (w < 0) { x = xx; w = -w; } float h = yy - y; if (h < 0) { h = -h; y = yy; } if (y>0) { fprintf(file_, "agent "); fprintf(file_, "at <x=%.1f y=%.1f> with <width=%.1f height=%.1f>\n", x, y, w, h); } } typedef struct floatpoint_s { float x, y; } floatpoint; void TestView::polygon(const float* x, const float* y, int n, int paint) { floatpoint pts[10]; int i; for (i = 0; i < n; ++i) { matrix_.map(x[i], y[i], pts[i].x, pts[i].y); } pts[n] = pts[0]; fprintf(file_,"polygon node "); fprintf(file_,"at <%.1f %.1f>\n", pts[0].x, pts[0].y); } void TestView::fill(const float* x, const float* y, int n, int paint) { floatpoint pts[10]; int i; for (i = 0; i < n; ++i) { matrix_.map(x[i], y[i], pts[i].x, pts[i].y); } pts[n] = pts[0]; fprintf(file_,"packet "); fprintf(file_, "at <%.1f %.1f>\n", pts[0].x, pts[0].y); } void TestView::circle(float x, float y, float r, int paint) { float tx, ty; matrix_.map(x, y, tx, ty); float tr, dummy; matrix_.map(x + r, y, tr, dummy); tr -= tx; fprintf(file_, "circle node "); fprintf(file_, "at <%.1f %.1f> with <radius %.1f>\n", tx, ty, tr); } void TestView::string(float fx, float fy, float dim, const char* s, int anchor, const char*) { float x, y; matrix_.map(fx, fy, x, y); float dummy, dlow, dhigh; matrix_.map(0., 0., dummy, dlow); matrix_.map(0., 0.6 * dim, dummy, dhigh); int d = int(dhigh - dlow); if(s!="") { switch (anchor) { case ANCHOR_CENTER: fprintf(file_, "with label (%s) at center <%.1f %.1f>\n", s, x, y); break; case ANCHOR_NORTH: fprintf(file_, "with label (%s) at north <%.1f %.1f>\n", s, x, y); break; case ANCHOR_SOUTH: fprintf(file_, "with label (%s) at south <%.1f %.1f>\n", s, x, y); break; case ANCHOR_WEST: fprintf(file_, "with label (%s) at west <%.1f %.1f>\n", s, x, y); break; case ANCHOR_EAST: fprintf(file_, "with label (%s) at east <%.1f %.1f>\n", s, x, y); break; } } }

trace.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #include <sys/types.h> #include <fcntl.h> #ifdef WIN32 #include <windows.h> #include <io.h> #else #include <unistd.h> #include <sys/file.h> #endif #include <sys/stat.h> #include <ctype.h> #include "trace.h" #include "state.h" #include "packet.h" #include "address.h" #include "nam_stream.h" extern double time_atof(const char*); class TraceClass : public TclClass { public: TraceClass() : TclClass("Trace") {} TclObject* create(int argc, const char*const* argv); } trace_class; TclObject*
TraceClass::create(int argc, const char*const* argv) { if (argc != 6) return (0); /* * Open the trace file for reading and read its first line * to be able to determine needed values: trace start time, * trace duration, etc. */ Trace* tr = new Trace(argv[4], argv[5]); if (!tr->valid()) { delete tr; /*XXX*/ tr = 0; } return (tr); } Trace::Trace(const char *fname, const char *animator) : handlers_(0), nam_(0), skipahead_mode_(0), count_(0) { nam_ = (NetworkAnimator *)TclObject::lookup(animator); strncpy(fileName_, fname, sizeof(fileName_)-1); fileName_[sizeof(fileName_)-1] = 0; nam_stream_ = NamStream::open(fileName_); if (!nam_stream_->is_ok()) { delete nam_stream_; nam_stream_ = NULL; perror("nam: fdopen"); // exit(1); return; // tr->valid() will check this } findLastLine(); /* * Go to the beginning of the file, read the first line and * save its contents. */ off_t pos = nam_stream_->seek(0, SEEK_SET); assert(pos == 0); /* * Minimum time on the nam time slider is the time of the first * trace event. */ mintime_ = nextTime(); now_ = mintime_; State::instance()->setTimes(mintime_, maxtime_); } int Trace::valid() { return (nam_stream_ && nam_stream_->is_ok()); } int Trace::ReadEvent(double now, TraceEvent& e) { /* * If specified time is after the next event's time, read * the next line and return 1. Otherwise, just return 0. */ if (direction_==FORWARDS) { if ((pending_.time != TIME_EOF) && (pending_.time < now)) { e = pending_; scan(); return (1); } } else { /*going backwards!*/ /* * two occasions: 1) pending_.time > now, * 2) pending_.time = -1, which means go to the end of file */ if ((pending_.time > now) || (pending_.time == TIME_EOF)) { e = pending_; scan(); if (pending_.time == TIME_EOF) pending_.time = TIME_BOF; return (1); } } return (0); } int Trace::NextLine() { static char buf[TRACE_LINE_MAXLEN]; int len, i, end; if (direction_==FORWARDS) { /*moving forwards through the trace file*/ nam_stream_->gets(pending_.image, sizeof(pending_.image)); if (nam_stream_->eof()) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s stopmaxtime %f", nam()->name(),pending_.time); return 0; } return(nam_stream_->tell()); } else { /*moving backwards through the trace file*/ /*XXX all this seeking around isn't exactly efficient*/ int pos = nam_stream_->tell(), delta = TRACE_LINE_MAXLEN, newpos; assert(pos != -1); if (pos < delta) delta = pos; if (delta == 0) return -1; newpos = nam_stream_->seek(-delta, SEEK_CUR); assert(newpos == pos-delta); len = nam_stream_->read(buf, delta); if (len < 0) return 0; buf[len]='\0'; for(i=len; i>=0; i--) { if (buf[i]=='\n') { buf[i]='\0'; break; } } end=i; for(;i>=0;i--) { if (buf[i]=='\n') { strncpy(pending_.image, &buf[i+1], sizeof(pending_.image)); newpos = nam_stream_->seek(end-len, SEEK_CUR); assert(newpos != -1); break; } } if (i == -1 && pos-delta == 0) // XXX: may skip first line when rewinding return -1; // signal EOF (actually, BOF) else return (nam_stream_->tell()); } } void Trace::scan() { /* * Read the next line in the trace file and store its contents * depending on line type. */ while (1) { int n; TraceEvent& p = pending_; char* cp = p.image; p.offset = NextLine(); if (p.offset <= 0) { pending_.time = TIME_EOF; return; } //++lineno_; switch (p.tt = *cp++) { case '#': /* comment */ case '\n': /* empty line */ case '\0': /* backward play empty line */ continue; case 'h': /* hop */ case 'r': /* receive */ case '+': /* enqueue */ case 'd': /* drop line */ case '-': /* dequeue line */ case 'E': /* session enqueue */ case 'D': /* session dequeue */ case 'P': /* session drop */ { if (packetscan(cp,&p.time,&p.pe)>=0) { return; } break; } case 'V': /* nam version */ continue; /* for future usage */ case 'W': /* wireless range */ continue; case 'N': /* namgraph use */ continue; /* for future usage */ case 'g': /* energy status */ return; /* for future usage */ case 'G': /* group event */ if (group_scan(cp, &p.time, &p.ge) >= 0) return; break; case 'v': /* v <-t> <time> <tcl expr> */ while (isspace(*cp)) cp++; if (*cp == '-') cp += 2; // skip '-t' n = sscanf(cp, " %lg", &p.time); if (n != 1) break; for (n = strlen(p.image); --n > 0; ) { if (! isspace(p.image[n])) { p.image[n+1] = 0; break; } } while (isspace(*cp)) ++cp; while (*cp && !isspace(*cp)) ++cp; while (isspace(*cp)) ++cp; p.ve.str = cp - p.image; return; case 'l': /*link event*/ if (linkscan(cp,&p.time,&p.le)>=0) { return; } break; case 'n': /*node event*/ if (nodescan(cp,&p.time,&p.ne)>=0) { return; } break; case 'm': /* node mark event */ if (nodemark_scan(cp, &p.time, &p.me) >= 0) return; break; case 'R': /*routing event*/ if (routescan(cp,&p.time,&p.re)>=0) { return; } break; case 'A': /* Hierarchical address space configuration */ case 'L': /*LAN link config - only in initialisation - ignore!*/ case 'X': /*LAN config - only in initialisation - ignore!*/ case 'q': /*queue config - only in initialisation - ignore!*/ case 'c': /*color table config - only in initialisation - ignore!*/ if (p.time < 0) p.time = 0; return; case 'a': /*agent event*/ if (agentscan(cp,&p.time,&p.ae)>=0) { //printf("agent: name: %s\n", p.ae.agent.name); return; } return; case 'f': /*feature event*/ if (featurescan(cp,&p.time,&p.fe)>=0) { //printf("feature: agent name: %s feature name: %s\n", // p.fe.feature.agent, // p.fe.feature.name); return; } return; default: fprintf(stderr, "nam: unknown event at offset %ld in `%s'\n", p.offset, fileName_); fprintf(stderr, "nam: `%s'\n", p.image); exit(1); } fprintf(stderr, "nam: badly formatted event at offset %ld in %s\n", p.offset, fileName_); for (n = strlen(p.image); --n > 0; ) { if (! isspace(p.image[n])) { p.image[n+1] = 0; break; } } fprintf(stderr, "nam: `%s'\n", p.image); exit(1); } /* NOTREACHED */ } char *Trace::parse_string_literal(char *orig, char *buffer) { char *tmp, *str; str=orig; if (*str=='"') { strncpy(buffer, str+1, MAXNAME); str=str+1; tmp=strchr(buffer, '"'); if (tmp!=NULL) str=strchr(str, '"'); else { tmp=strchr(buffer, '\n'); if (tmp!=NULL) str=strchr(str, '\n'); } if ((tmp!=NULL)&&(tmp-buffer<=MAXNAME)) { *tmp='\0'; } } else { strncpy(buffer, str, MAXNAME); tmp=strchr(buffer, ' '); if (tmp!=NULL) str=strchr(str, ' '); else { tmp=strchr(buffer, '\n'); if (tmp!=NULL) str=strchr(str, '\n'); } if ((tmp!=NULL)&&(tmp-buffer<=MAXNAME)) { *tmp='\0'; } } return str; } int Trace::packetscan(char *cp, double *time, PacketEvent *pe) { char *value; char *str=cp; int check=0; pe->pkt.convid[0]='\0'; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; if (*(str+1)==' ') value=str+2; switch (*str) { case 't': /*time*/ { check++; *time=atof(value); str+=2; break; } case 's': /*src*/ { char buf[MAXVALUE]; check++; // we need new space because strtok may damage the orig string parse_string_literal(value, buf); pe->src = atoi(buf); //pe->src = Address::instance().str2addr(buf); str+=2; break; } case 'd': /*dst*/ { char buf[MAXVALUE]; check++; parse_string_literal(value, buf); pe->dst = atoi(buf); //pe->dst = Address::instance().str2addr(buf); str+=2; break; } case 'e': /*extent*/ { check++; pe->pkt.size=atoi(value); str+=2; break; } case 'a': /*attr*/ { check++; pe->pkt.attr=atoi(value); str+=2; break; } case 'i': /*id*/ { check++; pe->pkt.id=atoi(value); str+=2; break; } case 'l': /*energy*/ { check++; pe->pkt.energy=atoi(value); str+=2; break; } case 'c': /*conversation*/ { char *tmp; check++; strncpy(pe->pkt.convid, value, CONVLEN); tmp=strchr(pe->pkt.convid, ' '); if (tmp==NULL) tmp=strchr(pe->pkt.convid, '\n'); if ((tmp!=NULL)&&(tmp-pe->pkt.convid<=CONVLEN)) *tmp='\0'; str+=strlen(pe->pkt.convid)+2; break; } case 'x': /*comment*/ { char *tmp; char *tmp1, *tmp2 , *tmp3; char tmpstr[CONVLEN]; strncpy(tmpstr, value, CONVLEN); tmp=strchr(tmpstr, '}'); if (tmp==NULL) tmp=strchr(tmpstr, '\n'); if ((tmp!=NULL)&&(tmp-tmpstr<=CONVLEN)) *tmp='\0'; str+=strlen(pe->pkt.convid)+2; //retrieve end2end source and destination tmp1=strchr(tmpstr, '.'); tmp2=strchr(tmpstr, ' '); *tmp1='\0'; tmp3=strchr(tmp2, '.'); *tmp3='\0'; pe->pkt.esrc=atoi(tmpstr+1); pe->pkt.edst=atoi(tmp2+1); break; } case 'p': /*packet type*/ { char *tmp; strncpy(pe->pkt.type, value, PTYPELEN); tmp=strchr(pe->pkt.type, ' '); if (tmp==NULL) tmp=strchr(pe->pkt.type, '\n'); if ((tmp!=NULL)&&(tmp-pe->pkt.type<=PTYPELEN)) *tmp='\0'; str+=strlen(pe->pkt.type)+2; break; } case 'k': /*packet type*/ { char *tmp; strncpy(pe->pkt.wtype, value, PTYPELEN); tmp=strchr(pe->pkt.wtype, ' '); if (tmp==NULL) tmp=strchr(pe->pkt.wtype, '\n'); if ((tmp!=NULL)&&(tmp-pe->pkt.wtype<=PTYPELEN)) *tmp='\0'; str+=strlen(pe->pkt.wtype)+2; break; } } } if (check<6) return -1; else return 0; } int Trace::linkscan(char *cp, double *time, LinkEvent *le) { char *str=cp; char *value; int check=0; le->link.dlabel[0] = le->link.odlabel[0] = 0; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; if (*(str+1)==' ') value=str+2; switch (*str) { case 'c': /* color */ check++; str = parse_string_literal(value, le->link.color); break; case 'o': /* old color, used for backtracing */ check++; str = parse_string_literal(value, le->link.oldColor); break; case 't': /*time*/ { if (strncmp(value, "*", 1)==0) { if (*time < 0) *time = 0; return 0; } check++; *time=atof(value); str+=2; break; } case 's': /*src*/ { check++; le->src=atoi(value); str+=2; break; } case 'd': /*dst*/ { check++; le->dst=atoi(value); str+=2; break; } case 'S': { /*link state*/ char *tmp; check++; strncpy(le->link.state, value, MAXVALUE); tmp=strchr(le->link.state, ' '); if (tmp==NULL) tmp=strchr(le->link.state, '\n'); if ((tmp!=NULL)&&(tmp-le->link.state<=MAXVALUE)) *tmp='\0'; str+=strlen(le->link.state)+2; break; } case 'l': { /* Label beneath a link (dlabel) */ check++; str = parse_string_literal(value, le->link.dlabel); break; } case 'L': { /* old dlabel, used for backtracking */ check++; str = parse_string_literal(value, le->link.odlabel); break; } case 'p': { /* locate label*/ check++; str = parse_string_literal(value, le->link.direction); break; } case 'P': { /* locate label, for backtracking*/ check++; str = parse_string_literal(value, le->link.odirection); break; } case 'e': { /* label color*/ check++; str = parse_string_literal(value, le->link.dcolor); break; } case 'E': { /* label color*/ check++; str = parse_string_literal(value, le->link.odcolor); break; } case 'r': case 'D': { /* move the pointer */ char *tmp; check++; tmp = strchr(value, ' '); if (tmp == NULL) { str = tmp; } else { size_t pos1 = strcspn(str, value); size_t pos2 = strcspn(str, tmp); str+=pos2-pos1+2; } break; } } } if (check<4) return -1; else return 0; } int Trace::group_scan(char *cp, double *time, GroupEvent *ge) { char *str=cp; char *value; int check=0; ge->grp.name[0] = 0; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; value=str+2; switch (*str) { case 't': { /* time */ check++; *time=atof(value); str=value+1; break; } case 'n': { /* group name, if any */ char *tmp; check++; if (*(value)=='"') { strncpy(ge->grp.name, value+1, MAXNAME); tmp=strchr(ge->grp.name, '"'); if (tmp==NULL) tmp=strchr(ge->grp.name, '\n'); if ((tmp!=NULL)&&(tmp-ge->grp.name<=MAXNAME)) *tmp='\0'; str+=strlen(ge->grp.name)+4; } else { strncpy(ge->grp.name, value, MAXNAME); tmp=strchr(ge->grp.name, ' '); if (tmp==NULL) tmp=strchr(ge->grp.name, '\n'); if ((tmp!=NULL)&&(tmp-ge->grp.name<=MAXNAME)) *tmp='\0'; str+=strlen(ge->grp.name)+2; } break; } case 'i': { /* node with which this mark is associated */ check++; ge->src = atoi(value); str+=2; break; } case 'a': { /* join */ check++; ge->grp.flag = GROUP_EVENT_JOIN; ge->grp.mbr = atoi(value); str = value + 1; break; } case 'x': { /* leave */ check++; ge->grp.flag = GROUP_EVENT_LEAVE; ge->grp.mbr = atoi(value); str = value + 1; break; } } } if (check<3) return -1; else return 0; } int Trace::nodemark_scan(char *cp, double *time, NodeMarkEvent *ne) { char *str=cp; char *value; int check=0; /* ne->dst=-1; */ ne->mark.expired = 0; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; value=str+2; switch (*str) { case 't': { /* time */ check++; *time=atof(value); str=value+1; break; } case 'n': { /* node mark name */ char *tmp; check++; if (*(value)=='"') { strncpy(ne->mark.name, value+1, MAXVALUE); tmp=strchr(ne->mark.name, '"'); if (tmp==NULL) tmp=strchr(ne->mark.name, '\n'); if ((tmp!=NULL)&&(tmp-ne->mark.name<=MAXVALUE)) *tmp='\0'; str+=strlen(ne->mark.name)+4; } else { strncpy(ne->mark.name, value, MAXVALUE); tmp=strchr(ne->mark.name, ' '); if (tmp==NULL) tmp=strchr(ne->mark.name, '\n'); if ((tmp!=NULL)&&(tmp-ne->mark.name<=MAXVALUE)) *tmp='\0'; str+=strlen(ne->mark.name)+2; } break; } case 's': { /* node with which this mark is associated */ check++; ne->src=atoi(value); str+=2; break; } case 'c': { /* color */ check++; str = parse_string_literal(value, ne->mark.color); break; } case 'h': { /* shape */ check++; str = parse_string_literal(value, ne->mark.shape); break; } case 'X': { /* expired? */ check++; ne->mark.expired = 1; break; } } } if (check<4) return -1; else return 0; } int Trace::nodescan(char *cp, double *time, NodeEvent *ne) { char *str=cp; char *value; int check=0; ne->dst=-1; ne->node.dlabel[0] = ne->node.odlabel[0] = 0; ne->node.lcolor[0] = 0; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; if (*(str+1)==' ') value=str+2; switch (*str) { case 'c': /* color */ check++; str = parse_string_literal(value, ne->node.color); break; case 'o': /* old color, used for backtracing */ check++; str = parse_string_literal(value, ne->node.oldColor); break; case 't': /*time*/ { if (strncmp(value,"*",1)==0) { if (*time < 0) *time = 0; return 0; } check++; *time=atof(value); str=value+1; break; } case 's': /*src*/ { check++; ne->src=atoi(value); str=value+1; break; } case 'd': /*dst*/ { ne->dst=atoi(value); str=value+1; break; } case 'S': { /*node state*/ char *tmp; check++; strncpy(ne->node.state, value, MAXNAME); tmp=strchr(ne->node.state, ' '); if (tmp==NULL) tmp=strchr(ne->node.state, '\n'); if ((tmp!=NULL)&&(tmp-ne->node.state<=MAXNAME)) *tmp='\0'; str+=strlen(ne->node.state)+2; break; } case 'a': { /* Node address */ char tmp[MAXVALUE]; check++; str = parse_string_literal(value, tmp); ne->node.addr = Address::instance().str2addr(tmp); break; } case 'l': { /* Label beneath a node (dlabel) */ check++; str = parse_string_literal(value, ne->node.dlabel); break; } case 'L': { /* old dlabel, used for backtracking */ check++; str = parse_string_literal(value, ne->node.odlabel); break; } case 'p': { /* locate label*/ check++; str = parse_string_literal(value, ne->node.direction); break; } case 'P': { /* locate label, for backtracking*/ check++; str = parse_string_literal(value, ne->node.odirection); break; } case 'i': { /* inside label color*/ check++; str = parse_string_literal(value, ne->node.lcolor); break; } case 'I': { /* inside label color -old */ check++; str = parse_string_literal(value, ne->node.olcolor); break; } case 'e': { /* label color*/ check++; str = parse_string_literal(value, ne->node.dcolor); break; } case 'E': { /* label color*/ check++; str = parse_string_literal(value, ne->node.odcolor); break; } case 'x': { /* code x loc */ check++; ne->x=atof(value); str=value+1; break; } case 'y': { /* node y loc */ check++; ne->y=atof(value); str=value+1; break; } case 'u': { /* code x velocity */ check++; ne->x_vel_=atof(value); str=value+1; break; } case 'v': { /* code y velocity */ check++; ne->y_vel_=atof(value); str=value+1; break; } case 'T': { /* node stop time */ check++; ne->stoptime=atof(value); str=value+1; break; } } } if (check<3) return -1; else return 0; } int Trace::agentscan(char *cp, double *time, AgentEvent *ae) { char *str=cp; char *value; int check=0; ae->dst=-1; ae->agent.expired=0; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; value=str+2; switch (*str) { case 't': /*time*/ { check++; *time=atof(value); str+=2; break; } case 's': /*src*/ { check++; ae->src=atoi(value); str+=2; break; } case 'd': /*dst*/ { ae->dst=atoi(value); str+=2; break; } case 'x': case 'X': /*this agent is to be deleted*/ { check++; ae->agent.expired=1; break; } case 'n': { /* agent name */ char *tmp; check++; if (*(value)=='"') { strncpy(ae->agent.name, value+1, MAXNAME); tmp=strchr(ae->agent.name, '"'); if (tmp==NULL) tmp=strchr(ae->agent.name, '\n'); if ((tmp!=NULL)&&(tmp-ae->agent.name<=MAXNAME)) *tmp='\0'; str+=strlen(ae->agent.name)+4; } else { strncpy(ae->agent.name, value, MAXNAME); tmp=strchr(ae->agent.name, ' '); if (tmp==NULL) tmp=strchr(ae->agent.name, '\n'); if ((tmp!=NULL)&&(tmp-ae->agent.name<=MAXNAME)) *tmp='\0'; str+=strlen(ae->agent.name)+2; } break; } } } if (check<3) return -1; else return 0; } int Trace::featurescan(char *cp, double *time, FeatureEvent *fe) { char *str=cp; char *value; int check=0; fe->dst=-1; fe->feature.expired=0; fe->feature.oldvalue[0]='\0'; fe->feature.value[0]='\0'; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; value=str+2; switch (*str) { case 't': /*time*/ { check++; *time=atof(value); str+=2; break; } case 's': /*src*/ { check++; fe->src=atoi(value); str+=2; break; } case 'd': /*dst*/ { fe->dst=atoi(value); str+=2; break; } case 'x': /*this feature is to be deleted*/ { fe->feature.expired=1; break; } case 'T': /*the type of the feature*/ { check++; fe->feature.type=*(value); str+=2; break; } case 'n': { //char *tmp; check++; str=parse_string_literal(value, fe->feature.name); // printf("n: %s\n", fe->feature.name); break; } case 'a': { //char *tmp, *tmp2; check++; str=parse_string_literal(value, fe->feature.agent); // printf("a: %s\n", fe->feature.agent); break; } case 'v': { check++; str=parse_string_literal(value, fe->feature.value); // printf("v: %s\n", fe->feature.value); break; } case 'o': { check++; str=parse_string_literal(value, fe->feature.oldvalue); break; } } } if (check<3) return -1; else return 0; } int Trace::routescan(char *cp, double *time, RouteEvent *re) { char *str=cp; char *value; int check=0; re->dst=-1; re->route.neg=0; re->route.expired=0; while(str!=NULL) { str=strchr(str,' '); if (str==NULL) break; while(*str==' ') str++; if (*str!='-') break; str++; value=str+2; switch (*str) { case 't': /*time*/ { check++; *time=atof(value); str+=2; break; } case 's': /*src*/ { check++; re->src=atoi(value); str+=2; break; } case 'd': /*dst*/ { check++; re->dst=atoi(value); str+=2; break; } case 'g': /*mcast group*/ { if (*(str+1)=='*') re->route.group=-1; else re->route.group=atoi(value); str+=2; break; } case 'p': /*packet src*/ { check++; if (*(str+1)=='*') re->route.pktsrc=-1; else re->route.pktsrc=atoi(value); str+=2; break; } case 'n': /*negative cache*/ { re->route.neg=1; break; } case 'x': /*this route just timed out*/ { re->route.expired=1; break; } case 'T': /*timeout*/ { re->route.timeout=atof(value); str+=2; break; } case 'm': { /*mode; typically iif or oif*/ char *tmp; strncpy(re->route.mode, value, MAXVALUE); tmp=strchr(re->route.mode, ' '); if (tmp==NULL) tmp=strchr(re->route.mode, '\n'); if ((tmp!=NULL)&&(tmp-re->route.mode<=MAXVALUE)) *tmp='\0'; str+=strlen(re->route.mode)+2; break; } } } if (check<4) return -1; else return 0; } /* * Go to the specified trace file's last line, verify that * the file isn't empty and that its last line is correctly * formatted. Compute the time interval for the entire trace * assuming it started at time 0. */ void Trace::findLastLine() { off_t pos; // should initialize it direction_ = FORWARDS; pending_.time = 0.0; pending_.image[0] = 0; /* * Fake it? */ if (!nam_stream_->seekable()) { maxtime_ = 0; return; } /* * If we can, find the end of time. */ char buf[TRACE_LINE_MAXLEN+1]; /* is there stuff in the file */ nam_stream_->seek(0, SEEK_END); if (nam_stream_->tell() <= 1) { fprintf(stderr, "nam: empty trace file `%s'.", fileName_); exit(1); } /* * If the file is larger than 'buf', go to the end of the file * at the point just large enough to fit into 'buf'. */ if (nam_stream_->tell() > (off_t)(sizeof(buf) - 1)) { pos = nam_stream_->seek(- (sizeof(buf) - 1), SEEK_CUR); assert(pos != -1); } else /* If the file is smaller than 'buf', go to the head of file */ nam_stream_->seek(0, SEEK_SET); int n = nam_stream_->read(buf, sizeof(buf) - 1); if (n < 0) { perror("read"); exit(1); } buf[n] = 0; /* * This next check is bogus, but zlib fails it. * Go figure. * Fortunately compressed files should not be seekable. */ pos = nam_stream_->tell(); assert(pos != -1); /* Error if the last line doesn't have '\n' in it. */ char *cp = strrchr(buf, '\n'); if (cp == 0) { fprintf(stderr, "nam: error, missing newline on the last line of `%s'.", fileName_); exit(1); } /* * Look for the first '\n' and check if the line following * it has the correct type, i.e., it starts with any of the * characters in [h+-dv]. */ *cp = 0; cp = strrchr(buf, '\n'); if (cp == 0 || strchr("h+-dvrRanlfDEGPAmVNXW", *++cp) == 0) { fprintf(stderr, "nam: error reading last line of `%s'.", fileName_); exit(1); } /* * Compute the time interval from the beginning of the trace * to the end. * XXX this should include the duration of the last event but * since we changed the format of 'size' from 'time' to * 'bytes', we can no longer figure this out. */ double time = 0.; (void)sscanf(++cp, " -t %lg", &time); maxtime_ = time; } /* Go to the beginning of the file, read the first line and process it. */ void Trace::rewind(long offset) { nam_stream_->seek(offset, SEEK_SET); //lineno_ = 0; scan(); } /* * Put the specified trace handler to the beginning of the trace * handler list. */ void Trace::addHandler(TraceHandler* th) { TraceHandlerList* p = new TraceHandlerList; p->th = th; p->next = handlers_; handlers_ = p; } /* Set the current trace time to 'now'. */ void Trace::settime(double now, int timeSliderClicked) { if (now < now_) { #ifdef OLDWAY for (TraceHandlerList* p = handlers_; p != 0; p = p->next) p->th->reset(now); StateInfo si; State::instance()->get(now, si); rewind(si.offset); #endif direction_=BACKWARDS; } else { direction_=FORWARDS; } now_ = now; /* * Scan the trace file until the event occurring at time 'now' * is read. For each event scanned, pass it on to all trace * handlers in the trace handler list so they can handle * them as needed. */ Tcl& tcl = Tcl::instance(); Tcl_Interp* interp = tcl.interp(); static char event[128]; TraceEvent e; while (ReadEvent(now, e)) { if (e.time == TIME_BOF) { // Reached the beginning of file during backtracking // Rewind to the beginning direction_ = FORWARDS; rewind(0); continue; } if (skipahead_mode_) { count_ = 0; skipahead_mode_ = 0; tcl.evalf("%s normalspeed", nam()->name()); } for (TraceHandlerList* p = handlers_; p != 0; p = p->next) p->th->handle(e, now, direction_); if (e.tt == 'h' && (e.pe.src == 0 || e.pe.dst == 0)) { sprintf(event, "%d %d %.6f %d/", e.pe.src, e.pe.dst, e.time, e.pe.pkt.id); if (timeSliderClicked) tcl.result((const char *)event); else Tcl_AppendResult(interp, event, 0); } } for (TraceHandlerList* p = handlers_; p != 0; p = p->next) p->th->update(now); if (Packet::count() == 0 && ++count_ == 2) { count_ = 0; skipahead_mode_ = 1; tcl.evalf("%s speedup %g", nam()->name(), pending_.time); } } /* * Process 'nam trace' commands: * mintime - return the trace start time * maxtime - return the trace duration * connect - add the specified trace handler to the trace handler list * settime - reset current time to specified time and adjust the * display as needed * nxtevent - read next event in trace file and animate from that point * reset - reset nam tracefile reading */ int Trace::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "mintime") == 0) { char* bp = tcl.buffer(); sprintf(bp, "%g", mintime_); tcl.result(bp); return (TCL_OK); } else if (strcmp(argv[1], "maxtime") == 0) { char* bp = tcl.buffer(); sprintf(bp, "%g", maxtime_); tcl.result(bp); return (TCL_OK); } else if (strcmp(argv[1], "nxtevent") == 0) { char* bp = tcl.buffer(); sprintf(bp, "%g", pending_.time); tcl.result(bp); return (TCL_OK); } else if (strcmp(argv[1], "reset") == 0) { nam_stream_->close(); nam_stream_ = NULL; nam_stream_ = NamStream::open(fileName_); if (nam_stream_->is_ok()) { delete nam_stream_; nam_stream_ = NULL; perror("nam: fdopen"); // exit(1); return TCL_ERROR; // tr->valid() will check this } return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "connect") == 0) { /* * Get the handler for the specified trace and * add it to the trace's list of handlers. */ TraceHandler* th = (TraceHandler*)TclObject::lookup(argv[2]); if (th == 0) { tcl.resultf("nam connect: no such trace %s", argv[2]); return (TCL_ERROR); } addHandler(th); return (TCL_OK); } } if (argc == 4 ) { if (strcmp(argv[1], "settime") == 0) { /* * Set current time to the specified time and update * the display to reflect the new current time. */ double now = atof(argv[2]); int timeSliderClicked = atoi(argv[3]); settime(now, timeSliderClicked); return (TCL_OK); } } return (TclObject::command(argc, argv)); }

tracehook.cc


/* * Copyright (c) 1997 University of Southern California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Information Sciences * Institute of the University of Southern California. * 4. Neither the name of the University nor of the Institute may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "tclcl.h" #include "trace.h" #include "tracehook.h" /*XXX */ class TraceHookClass : public TclClass { public: TraceHookClass() : TclClass("TraceHook") {} TclObject* create(int argc, const char*const* argv) { if (argc != 5) return (0); return (new TraceHook(argv[4])); } } tracehook_class; TraceHook::TraceHook(const char *animator) : TraceHandler(animator) { } TraceHook::~TraceHook() { } void
TraceHook::update(double /*now*/) { } void TraceHook::reset(double /*now*/) { } /* Trace event handler. */ void TraceHook::handle(const TraceEvent& e, double /*now*/, int /*direction*/) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s tracehooktcl {%s}", nam()->name(), e.image); } /* interface to Tcl */ int TraceHook::command(int argc, const char *const *argv) { return (TraceHandler::command(argc, argv)); }

transform.cc


/* * Copyright (c) 1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This code derived from InterViews library which is covered * by the copyright below. */ /* * Copyright (c) 1987, 1988, 1989, 1990, 1991 Stanford University * Copyright (c) 1991 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Stanford and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Stanford and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ /* * Implementation of transformation matrix operations. */ #include "sincos.h" #include "transform.h" static const double RADPERDEG = M_PI/180.0;
Transform::Transform() { clear(); } void Transform::clear() { identity_ = 1; mat00 = mat11 = 1; mat01 = mat10 = mat20 = mat21 = 0; } Transform::Transform(const Transform& t) { mat00 = t.mat00; mat01 = t.mat01; mat10 = t.mat10; mat11 = t.mat11; mat20 = t.mat20; mat21 = t.mat21; update(); } Transform::Transform(float a00, float a01, float a10, float a11, float a20, float a21) { mat00 = a00; mat01 = a01; mat10 = a10; mat11 = a11; mat20 = a20; mat21 = a21; update(); } int Transform::operator ==(const Transform& t) const { if (identity_) return t.identity_; if (t.identity_) return (0); return (mat00 == t.mat00 && mat01 == t.mat01 && mat10 == t.mat10 && mat11 == t.mat11 && mat20 == t.mat20 && mat21 == t.mat21); } int Transform::operator !=(const Transform& t) const { if (identity_) return (!t.identity_); if (t.identity_) return (1); return (mat00 != t.mat00 || mat01 != t.mat01 || mat10 != t.mat10 || mat11 != t.mat11 || mat20 != t.mat20 || mat21 != t.mat21); } Transform& Transform::operator =(const Transform& t) { mat00 = t.mat00; mat01 = t.mat01; mat10 = t.mat10; mat11 = t.mat11; mat20 = t.mat20; mat21 = t.mat21; update(); return (*this); } void Transform::update() { identity_ = ( mat00 == 1 && mat11 == 1 && mat01 == 0 && mat10 == 0 && mat20 == 0 && mat21 == 0 ); } void Transform::translate(float dx, float dy) { mat20 += dx; mat21 += dy; update(); } void Transform::scale(float sx, float sy) { mat00 *= sx; mat01 *= sy; mat10 *= sx; mat11 *= sy; mat20 *= sx; mat21 *= sy; update(); } void Transform::skew(float sx, float sy) { mat01 += mat00*sy; mat10 += mat11*sx; update(); } void Transform::rotate(float angle) { float tmp1, tmp2, m00, m01, m10, m11, m20, m21; angle *= RADPERDEG; tmp1 = cos(angle); tmp2 = sin(angle); m00 = mat00*tmp1; m01 = mat01*tmp2; m10 = mat10*tmp1; m11 = mat11*tmp2; m20 = mat20*tmp1; m21 = mat21*tmp2; mat01 = mat00*tmp2 + mat01*tmp1; mat11 = mat10*tmp2 + mat11*tmp1; mat21 = mat20*tmp2 + mat21*tmp1; mat00 = m00 - m01; mat10 = m10 - m11; mat20 = m20 - m21; update(); } void Transform::premultiply(const Transform& t) { float tmp1 = mat00; float tmp2 = mat10; mat00 = t.mat00*tmp1 + t.mat01*tmp2; mat10 = t.mat10*tmp1 + t.mat11*tmp2; mat20 += t.mat20*tmp1 + t.mat21*tmp2; tmp1 = mat01; tmp2 = mat11; mat01 = t.mat00*tmp1 + t.mat01*tmp2; mat11 = t.mat10*tmp1 + t.mat11*tmp2; mat21 += t.mat20*tmp1 + t.mat21*tmp2; update(); } void Transform::postmultiply(const Transform& t) { float tmp = mat00*t.mat01 + mat01*t.mat11; mat00 = mat00*t.mat00 + mat01*t.mat10; mat01 = tmp; tmp = mat10*t.mat01 + mat11*t.mat11; mat10 = mat10*t.mat00 + mat11*t.mat10; mat11 = tmp; tmp = mat20*t.mat01 + mat21*t.mat11; mat20 = mat20*t.mat00 + mat21*t.mat10; mat21 = tmp; mat20 += t.mat20; mat21 += t.mat21; update(); } void Transform::invert() { float d = det(); float t00 = mat00; float t20 = mat20; mat20 = (mat10*mat21 - mat11*mat20)/d; mat21 = (mat01*t20 - mat00*mat21)/d; mat00 = mat11/d; mat11 = t00/d; mat10 = -mat10/d; mat01 = -mat01/d; update(); } void Transform::map(float& x, float& y) const { float tx = x; x = tx*mat00 + y*mat10 + mat20; y = tx*mat01 + y*mat11 + mat21; } void Transform::map(float x, float y, float& tx, float& ty) const { tx = x*mat00 + y*mat10 + mat20; ty = x*mat01 + y*mat11 + mat21; } void Transform::imap(float& tx, float& ty) const { float d = det(); float a = (tx - mat20) / d; float b = (ty - mat21) / d; tx = a*mat11 - b*mat10; ty = b*mat00 - a*mat01; } void Transform::imap(float tx, float ty, float& x, float& y) const { float d = det(); float a = (tx - mat20) / d; float b = (ty - mat21) / d; x = a*mat11 - b*mat10; y = b*mat00 - a*mat01; }

view.cc


/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ (LBL) */ #include <stdlib.h> #ifdef WIN32 #include <windows.h> #endif #include <ctype.h> #include <math.h> #include <tclcl.h> #include "bbox.h" #include "netview.h" #include "netmodel.h" #include "tclcl.h" #include "paint.h" #include "packet.h" // Convert a string to world coordinates int
View::getCoord(char *strx, char *stry, float &dx, float &dy) { Tcl& tcl = Tcl::instance(); double tx, ty; if ((Tk_GetScreenMM(tcl.interp(), tk_, strx, &tx) != TCL_OK) || (Tk_GetScreenMM(tcl.interp(), tk_, stry, &ty) != TCL_OK)) { return TCL_ERROR; } tx *= pixelsPerMM_; ty *= pixelsPerMM_; dx = tx, dy = ty; matrix_.imap(dx, dy); return TCL_OK; } void View::zoom(float mag) { magnification_ *= mag; resize(width_, height_); } void View::resize(int width, int height) { width_ = width; height_ = height; matrix_.clear(); BBox bb; /*a model can choose to use these values, or can set its own*/ /* NetModel sets it to bb.clear(), while GraphView use this */ bb.xmin=0; bb.ymin=0; bb.xmax=width; bb.ymax=height; BoundingBox(bb); double x = (0.0-panx_)*width; double y = (0.0-pany_)*height; double w = width; double h = height; /* * Set up a transform that maps bb -> canvas. I.e, * bb -> unit square -> allocation, but which retains * the aspect ratio. Also, add a margin. */ double nw = bb.xmax - bb.xmin; double nh = bb.ymax - bb.ymin; /* * Grow a margin if we asked for square aspect ratio. */ double bbw; double bbh; if (aspect_==SQUARE) { bbw = 1.1 * nw; bbh = 1.1 * nh; } else { bbw = nw; bbh = nh; } double tx = bb.xmin - 0.5 * (bbw - nw); double ty = bb.ymin - 0.5 * (bbh - nh); /* * move base coordinate system to origin */ matrix_.translate(-tx, -ty); /* * flip vertical axis because X is backwards. */ matrix_.scale(1, -1.); matrix_.translate(0., bbh); double ws = w / bbw; double hs = h / bbh; if (aspect_==SQUARE) { if (ws <= hs) { matrix_.scale(ws, ws); matrix_.translate(x, y + 0.5 * (h - ws * bbh)); } else { matrix_.scale(hs, hs); matrix_.translate(x + 0.5 * (w - hs * bbw), y); } } else { matrix_.scale(ws, hs); matrix_.translate(x, y); } if (offscreen_ != 0) Tk_FreePixmap(Tk_Display(tk_), offscreen_); if ((width_<=0)||(height_<=0)) abort(); offscreen_ = Tk_GetPixmap(Tk_Display(tk_), Tk_WindowId(tk_), width_, height_, Tk_Depth(tk_)); matrix_.scale(magnification_, magnification_); if (xscroll_!=NULL) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s set %f %f", xscroll_, panx_, panx_+(1.0/magnification_)); } if (yscroll_!=NULL) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s set %f %f", yscroll_, pany_, pany_+(1.0/magnification_)); } pixelsPerMM_ = WidthOfScreen(Tk_Screen(tk_)) / WidthMMOfScreen(Tk_Screen(tk_)); if (!bClip_) { clip_.xmin = clip_.ymin = 0; clip_.xmax = width_; clip_.ymax = height_; } } void View::draw() { if (offscreen_ == 0) return; XFillRectangle(Tk_Display(tk_), offscreen_, background_, 0, 0, width_, height_); render(); XCopyArea(Tk_Display(tk_), offscreen_, Tk_WindowId(tk_), background_, 0, 0, width_, height_, 0, 0); } View::View(const char* name, int aspect, int width, int height) : next_(NULL), magnification_(1.0), panx_(0.0), pany_(0.0), aspect_(aspect), xscroll_(NULL), yscroll_(NULL), bClip_(0) { Tcl& tcl = Tcl::instance(); tk_ = Tk_CreateWindowFromPath(tcl.interp(), tcl.tkmain(), (char*)name, 0); if (tk_ != 0) { Tk_SetClass(tk_, "NetView"); /*XXX*/ /* Specify preferred window size. */ Tk_GeometryRequest(tk_, width, height); Tk_CreateEventHandler(tk_, ExposureMask|StructureNotifyMask, handle, (ClientData)this); Tk_MakeWindowExist(tk_); pixelsPerMM_ = WidthOfScreen(Tk_Screen(tk_)) / WidthMMOfScreen(Tk_Screen(tk_)); } else // Just a arbitrary initialization pixelsPerMM_ = 1; width_ = height_ = 0; background_ = Paint::instance()->background_gc(); offscreen_ = 0; load_fonts(); } View::~View() { /* * Do not do Tk_DestroyWindow() stuff. Should *never* use * delete <view> to destroy a view */ if (tk_ != 0) { if (offscreen_ != 0) Tk_FreePixmap(Tk_Display(tk_), offscreen_); free_fonts(); } tk_ = 0; } void View::setClipRect(BBox &b) { XRectangle rect; Paint* paint = Paint::instance(); clip_ = b; bClip_ = 1; clip_.xmin = clip_.ymin = 0; clip_.xmax = (float)width_; clip_.ymax = (float)height_; b.xrect(rect); #ifndef WIN32 for (int i = 0; i < paint->num_gc(); i++) { XSetClipRectangles(Tk_Display(tk_), paint->paint_to_gc(i), 0, 0, &rect, 1, Unsorted); } #endif } void View::clearClipRect() { Paint* paint = Paint::instance(); #ifndef WIN32 for (int i = 0; i < paint->num_gc(); i++) { // XXX Or should I set it to the whole window??? XSetClipRectangles(Tk_Display(tk_), paint->paint_to_gc(i), 0, 0, None, 1, Unsorted); } #endif bClip_ = 0; } void View::setFunction(int func) { Paint* paint = Paint::instance(); for (int i = 0; i < paint->num_gc(); i++) XSetFunction(Tk_Display(tk_), paint->paint_to_gc(i), func); } /* Handler for the Expose, DestroyNotify and ConfigureNotify events. */ void View::handle(ClientData cd, XEvent* ep) { View* nv = (View*)cd; switch (ep->type) { case Expose: if (ep->xexpose.count == 0) /*XXX*/ nv->draw(); break; case DestroyNotify: /*XXX kill ourself */ /*XXX: this should kill the viewer! */ /*XXX how about use delete this? */ if (nv->tk_ != 0) { if (nv->offscreen_ != 0) Tk_FreePixmap(Tk_Display(nv->tk_), nv->offscreen_); nv->free_fonts(); } nv->tk_ = 0; delete nv; break; case ConfigureNotify: if (nv->width_ != ep->xconfigure.width || nv->height_ != ep->xconfigure.height) { //if it gets smaller, there will be no expose event, //so we have to draw it outselves - mjh int smaller=0; if ((nv->width_ >= ep->xconfigure.width) && (nv->height_ >= ep->xconfigure.height)) smaller=1; nv->resize(ep->xconfigure.width, ep->xconfigure.height); if (smaller) nv->draw(); } break; } } int View::command(ClientData cd, Tcl_Interp* tcl, int argc, char **argv) { NetView *nv = (NetView *)cd; if (argc < 2) { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return (TCL_ERROR); } if (strcmp(argv[1], "xscroll") == 0) { if (argc == 3) { nv->xscroll_=new char[strlen(argv[2])+1]; strcpy(nv->xscroll_, argv[2]); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "yscroll") == 0) { if (argc == 3) { nv->yscroll_=new char[strlen(argv[2])+1]; strcpy(nv->yscroll_, argv[2]); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if (strcmp(argv[1], "zoom") == 0) { if (argc == 3) { float mag=atof(argv[2]); if (mag>1.0) { nv->panx_+=(1.0-1.0/mag)/(2.0*nv->magnification_); nv->pany_+=(1.0-1.0/mag)/(2.0*nv->magnification_); } else { nv->panx_-=(1.0-mag)/(2.0*nv->magnification_*mag); nv->pany_-=(1.0-mag)/(2.0*nv->magnification_*mag); } nv->zoom(mag); nv->draw(); //nv->pan(panx, pany); return TCL_OK; } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } } if ((strcmp(argv[1], "xview") == 0)||(strcmp(argv[1], "yview")==0)) { if ((argc==4)&&(strcmp(argv[2], "moveto")==0)) { if (strcmp(argv[1], "xview") == 0) nv->panx_=atof(argv[3]); else nv->pany_=atof(argv[3]); nv->resize(nv->width_, nv->height_); nv->draw(); } else if ((argc==5)&&(strcmp(argv[2], "scroll")==0)) { float step=atof(argv[3]); if (strcmp(argv[4], "units")==0) { step*=0.05/nv->magnification_; } else if (strcmp(argv[4], "pages")==0) { step*=0.8/nv->magnification_; } if (strcmp(argv[1], "xview") == 0) nv->panx_+=step; else nv->pany_+=step; nv->resize(nv->width_, nv->height_); nv->draw(); } else { Tcl_AppendResult(tcl, "\"", argv[0], "\": arg mismatch", 0); return TCL_ERROR; } return TCL_OK; } Tcl_AppendResult(tcl, "\"", argv[0], "\": unknown arg: ", argv[1], 0); return (TCL_ERROR); } void View::line(float x0, float y0, float x1, float y1, int paint) { int ax, ay; matrix_.map(x0, y0, ax, ay); int bx, by; matrix_.map(x1, y1, bx, by); GC gc = Paint::instance()->paint_to_gc(paint); XDrawLine(Tk_Display(tk_), offscreen_, gc, ax, ay, bx, by); } void View::rect(float x0, float y0, float x1, float y1, int paint) { int x, y; matrix_.map(x0, y0, x, y); int xx, yy; matrix_.map(x1, y1, xx, yy); int w = xx - x; if (w < 0) { x = xx; w = -w; } int h = yy - y; if (h < 0) { h = -h; y = yy; } GC gc = Paint::instance()->paint_to_gc(paint); XDrawRectangle(Tk_Display(tk_), offscreen_, gc, x, y, w, h); } void View::polygon(const float* x, const float* y, int n, int paint) { /*XXX*/ XPoint pts[10]; for (int i = 0; i < n; ++i) { float tx, ty; matrix_.map(x[i], y[i], tx, ty); pts[i].x = int(tx); pts[i].y = int(ty); } pts[n] = pts[0]; GC gc = Paint::instance()->paint_to_gc(paint); XDrawLines(Tk_Display(tk_), offscreen_, gc, pts, n + 1, CoordModeOrigin); } void View::fill(const float* x, const float* y, int n, int paint) { /*XXX*/ XPoint pts[10]; for (int i = 0; i < n; ++i) { float tx, ty; matrix_.map(x[i], y[i], tx, ty); pts[i].x = int(tx); pts[i].y = int(ty); } pts[n] = pts[0]; GC gc = Paint::instance()->paint_to_gc(paint); XFillPolygon(Tk_Display(tk_), offscreen_, gc, pts, n + 1, Convex, CoordModeOrigin); } void View::circle(float x, float y, float r, int paint) { int tx, ty; matrix_.map(x, y, tx, ty); int tr, dummy; matrix_.map(x + r, y, tr, dummy); tr -= tx; tx -= tr; ty -= tr; tr *= 2; GC gc = Paint::instance()->paint_to_gc(paint); XDrawArc(Tk_Display(tk_), offscreen_, gc, tx, ty, tr, tr, 0, 64 * 360); } static char* fontName[NFONT] = { "-adobe-times-medium-r-normal-*-8-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-10-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-12-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-18-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-20-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-24-*-*-*-*-*-*-*", "-adobe-times-medium-r-normal-*-34-*-*-*-*-*-*-*", }; //static Font* font[sizeof(fontName)/sizeof(fontName[0])]; /* Set the font structures using values in 'fontName' (defined above). */ void View::load_fonts() { if (tk_!=0) { Tcl_Interp* tcl = Tcl::instance().interp(); nfont_ = 0; for (int i = 0; i < NFONT; ++i) { fonts_[nfont_] = Tk_GetFont(tcl, tk_, fontName[i]); if (fonts_[nfont_] == 0) continue; font_gc_[nfont_] = Paint::instance()->text_gc(Tk_FontId(fonts_[nfont_])); ++nfont_; } if (nfont_ == 0) fprintf(stderr, "nam: warning no fonts found\n"); } } void View::free_fonts() { /*XXX Tk_FreeFontStruct*/ for (int i = 0; i < NFONT; i++) { Tk_FreeFont(fonts_[i]); } } int View::lookup_font(int d) { int i = nfont_; while (--i > 0) { Tk_Font f = fonts_[i]; Tk_FontMetrics p; Tk_GetFontMetrics(f, &p); if (d >= p.ascent + p.descent) return (i); } return (0); } void View::string(float fx, float fy, float dim, const char* s, int anchor, const char* color) { XColor ignore; if (nfont_ <= 0) return; int dummy; int dlow, dhigh; Tcl& tcl = Tcl::instance(); /*XXX this could be cached*/ matrix_.map(0., 0., dummy, dlow); matrix_.map(0., 0.9 * dim, dummy, dhigh); int d = dhigh - dlow; if (d < 0) d = -d; int font = lookup_font(d); Tk_Font f = fonts_[font]; Tk_FontMetrics p; Tk_GetFontMetrics(f, &p); int h = p.ascent; int len = strlen(s); int w = Tk_TextWidth(f, s, len); int x, y; matrix_.map(fx, fy, x, y); /* XXX still need to adjust for mismatch between d and actual height*/ switch (anchor) { case ANCHOR_CENTER: x -= w / 2; y += h / 2; break; case ANCHOR_NORTH: x -= w / 2; y += d; break; case ANCHOR_SOUTH: x -= w / 2; y -= h/2; break; case ANCHOR_WEST: y += h / 2; break; case ANCHOR_EAST: x -= w; y += h / 2; break; } // XXX Very very very bad hack. Should go through Paint::text_gc()!! Colormap cmap; Tk_Uid colorname; GC fgc = font_gc_[font]; // Font gc if (color != NULL) fgc = Paint::instance()->text_gc(Tk_FontId(fonts_[font]), color); Tk_DrawChars(Tk_Display(tk_), offscreen_, fgc, f, s, len, x, y); if (color != NULL) Tk_FreeGC(Tk_Display(tk_), fgc); // XXX We don't free the color allocated above. Hope it won't // be a problem! }

wnetmodel.cc


/* * Network model with Wireless layout * */ #include <stdlib.h> #include <math.h> #include <float.h> #include "random.h" #include "view.h" #include "netview.h" #include "animation.h" #include "queue.h" #include "edge.h" #include "node.h" #include "agent.h" #include "sincos.h" #include "state.h" #include "packet.h" #include "wnetmodel.h" class WirelessNetworkModelClass : public TclClass { public: WirelessNetworkModelClass() : TclClass("NetworkModel/Wireless") {} TclObject* create(int argc, const char*const* argv) { if (argc < 5) return 0; return (new WirelessNetModel(argv[4])); } } wirelessnetworkmodel_class; WirelessNetModel::WirelessNetModel(const char *animator) : edges_(0), NetModel(animator) { bind("Wpxmax_", &pxmax_); bind("Wpymax_", &pymax_); } WirelessNetModel::~WirelessNetModel() { } int
WirelessNetModel::command(int argc, const char *const *argv) { if (argc == 2) { if (strcmp(argv[1], "layout") == 0) { /* * <net> layout */ layout(); NetModel::set_wireless(); return (TCL_OK); } } if (argc == 5) { if (strcmp(argv[1], "select-pkt") == 0) { NetModel::selectPkt(atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); return (TCL_OK); } } return (NetModel::command(argc, argv)); } void WirelessNetModel::layout() { Node *n; for (n = nodes_; n != 0; n = n->next_) for (Edge* e = n->links(); e != 0; e = e->next_) placeEdge(e, n); nymax_ = pymax_ ; nymin_ = 0 ; } void WirelessNetModel::BoundingBox(BBox& bb) { bb.xmin = bb.ymin = 0; bb.xmax = pxmax_; bb.ymax = pymax_; for (Animation* a = drawables_; a != 0; a = a->next()) a->merge(bb); } void WirelessNetModel::update(double now) { Animation *a, *n; for (a = animations_; a != 0; a = n) { n = a->next(); a->update(now); } for (Node* x = nodes_; x != 0; x = x->next_) { x->update(now); moveNode(x); } /* * Draw all animations and drawables on display to reflect * current time. */ now_ = now; for (View* p = views_; p != 0; p = p->next_) { p->draw(); } } void WirelessNetModel::moveNode(Node *n) { for (Edge *e = n->links(); e != 0; e = e->next_) { e->unmark(); placeEdge(e, n); Node *dst = e->neighbor(); // Should place reverse edges too Edge *p = dst->find_edge(n->num()); if (p != NULL) { p->unmark(); placeEdge(p, dst); } } for (Agent *a = n->agents(); a != NULL; a = a->next()) { a->mark(0), a->angle(NO_ANGLE); placeAgent(a, n); } } // we need to place edge using the edge's real angle, instead of the // given one void WirelessNetModel::placeEdge(Edge* e, Node* src) const { if (e->marked() == 0) { double hyp, dx, dy; Node *dst = e->neighbor(); dx=dst->x()-src->x(); dy=dst->y()-src->y(); hyp=sqrt(dx*dx + dy*dy); // e->setAngle(atan2(dy,dx)); double x0 = src->x() + src->size() * (dx/hyp) * .75; double y0 = src->y() + src->size() * (dy/hyp) * .75; double x1 = dst->x() - dst->size() * (dx/hyp) * .75; double y1 = dst->y() - dst->size() * (dy/hyp) * .75; e->place(x0, y0, x1, y1); /* Place the queue here too. */ EdgeHashNode *h = lookupEdge(e->src(), e->dst()); if (h != 0) { if (h->queue != 0) h->queue->place(e->size(), e->x0(), e->y0()); } e->mark(); } } // packet handling stuff. use new packet void WirelessNetModel::handle(const TraceEvent& e, double now, int direction) { EdgeHashNode *ehn, *ehnrev; Edge* ep ; Edge* newEdge ; double txtime; Node *src, *dst; switch (e.tt) { case 'a': { NetModel::handle(e, now, direction); // recalculate bounding box so that all agents will be within // view for (View *v = views_; v != 0; v = v->next_) v->redrawModel(); break; } case 'n': { NetModel::handle(e, now, direction); // no need to reposition node if the node event // is only for color change if (strncmp(e.ne.node.state, "COLOR", 5) == 0) return ; // placing the node position Node *n = lookupNode(e.ne.src); if (n == 0) return; n->place(e.ne.x,e.ne.y); n->placeorig(e.ne.x,e.ne.y); n->setstart(now); n->setend(e.ne.stoptime+now); n->setvelocity(e.ne.x_vel_, e.ne.y_vel_); moveNode(n); break; } case 'd': { if ( !(src= lookupNode(e.pe.src)) ) { fprintf(stderr,"node %d is not defined... ", e.pe.src); break; } if ( !(dst= lookupNode(e.pe.dst)) ) { if (e.pe.dst != -1) { //broadcasting address fprintf(stderr,"node %d is not defined... ", e.pe.dst); break; } } if (e.pe.pkt.energy == 3) src->color("green"); if (e.pe.pkt.energy == 2) src->color("yellow"); if (e.pe.pkt.energy == 1) src->color("red"); if (e.pe.pkt.energy == 0) src->color("black"); NetModel::handle(e, now, direction); break; } case 'r': { if ( !(src= lookupNode(e.pe.src)) ) { fprintf(stderr, "node %d is not defined... ", e.pe.src); break; } if ( !(dst= lookupNode(e.pe.dst)) ) { if (e.pe.dst != -1) { //broadcasting address fprintf(stderr,"node %d is not defined... ", e.pe.dst); break; } } if (e.pe.pkt.energy == 3) src->color("green"); if (e.pe.pkt.energy == 2) src->color("yellow"); if (e.pe.pkt.energy == 1) src->color("red"); if (e.pe.pkt.energy == 0) src->color("black"); NetModel::handle(e, now, direction); break; } case 'h': case '+': case '_': { if ( !(src= lookupNode(e.pe.src)) ) { fprintf(stderr, "node %d is not defined... ", e.pe.src); break; } else src->size(src->nsize()); if ( !(dst= lookupNode(e.pe.dst)) ) { if (e.pe.dst != -1) { //broadcasting address fprintf(stderr,"node %d is not defined... ", e.pe.dst); break; } else { if (e.pe.pkt.energy == 3) src->color("green"); if (e.pe.pkt.energy == 2) src->color("yellow"); if (e.pe.pkt.energy == 1) src->color("red"); if (e.pe.pkt.energy == 0) src->color("black"); NetModel::handle(e, now, direction); break; } } else dst->size(dst->nsize()); if (e.pe.pkt.energy == 3) src->color("green"); if (e.pe.pkt.energy == 2) src->color("yellow"); if (e.pe.pkt.energy == 1) src->color("red"); if (e.pe.pkt.energy == 0) src->color("black"); ehn = lookupEdge(e.pe.src, e.pe.dst); if (ehn == 0 ) { double bw = 1000000 ; double delay = 1.0000000000000008e-02 ; double length = 0 ; double dsize = 3 ; double angle = 8.275783586691418e-313 ; newEdge = new Edge(src, dst, dsize, bw, delay, length, angle); newEdge->init_color("black"); newEdge->visible(0); enterEdge(newEdge); newEdge->insert(&drawables_); src->add_link(newEdge); } NetModel::handle(e, now, direction); break; } case 'l': { if ((strncmp(e.le.link.state, "in", 2)==0) || (strncmp(e.le.link.state, "out", 3)==0)) { /* wireless process: dynamic link */ if (strncmp(e.le.link.state, "in", 2)==0) { if (direction==FORWARDS) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s add_link {%s}", name(), e.image); } else { // remove the link removeLink(e); } } if (strncmp(e.le.link.state, "out", 3)==0) { if (direction==FORWARDS) { removeLink(e); } else { Tcl& tcl = Tcl::instance(); tcl.evalf("%s add_link {%s}", name(), e.image); } } } else { NetModel::handle(e, now, direction); } break; } default: NetModel::handle(e, now, direction); break; } } void WirelessNetModel::addToEdgePool(Edge* e) { WEdgeList* p = new WEdgeList; p->wEdge = e; p->next = edges_ ; edges_ = p; } Edge* WirelessNetModel::removeFromEdgePool() { if (edges_) { WEdgeList* p = edges_ ; edges_ = p->next; Edge* w = p->wEdge ; delete p ; return w ; } else return (Edge*) 0 ; } void WirelessNetModel::removeLink(const TraceEvent& e) { int src = e.le.src; int dst = e.le.dst; EdgeHashNode *h = lookupEdge(src, dst); EdgeHashNode *g = lookupEdge(dst, src); if (h == 0 || g == 0) { // h,g = 0 or h,g !=0 return; } Edge* e1 = h->edge; Edge* e2 = g->edge; removeEdge(e1); removeEdge(e2); e1->detach(); e2->detach(); Node* srcnode = e1->start(); Node* dstnode = e2->start(); // it is a duplex by default srcnode->delete_link(e1); dstnode->delete_link(e2); delete e1; delete e2; } void WirelessNetModel::removeLink(int src, int dst) { EdgeHashNode *h = lookupEdge(src, dst); if (h == 0 ) return; Edge* e1 = h->edge; if (e1 == 0) return ; e1->dec_usage(); if (e1->used() != 0) return; removeEdge(e1); e1->detach(); Node* srcnode = e1->start(); srcnode->delete_link(e1); delete e1; }

global.tcl