/* $Header: /server/users/students/chow/mci/netresW/src/shn/RCS/twoprong.c,v 1.3 1995/07/28 12:29:52 chow Exp $ */ /* Output from p2c, the Pascal-to-C translator */ /* From input file "newp.pas" */ /* This program is available for research only. For commercial use, please check with chow@cs.uccs.edu. */ /* Project : NetRestore Algorithm Name : TWO PRONG - SELF HEALING NETWORK Programmed by : John Bicknell Date : 15 July 1992 Version : 1.0 This program models the Two Prong digital network restoration algorithm using NETSIM and other library routines. Date - Initials - Description of Modification --------------------------------------------- Revision History: ported to C by C. Edward Chow replace assign by fopen; replace GetTime and GetDate; remove release(heap..) add _strings_init(); _netsim_init(); _math_init(); remove pc specific function ClrScr(); _randomize(); 7/5/95 chow modify to read new file format 7/29/95 chow fix bug:finger pointer not updated in redirect_[gray,black](). */ #include #include #ifndef STRINGS_H #include "strings.h" #endif #ifndef NETSIM_H #include "netsim.h" #endif #ifndef LISTS_H #include "lists1.h" #endif #ifndef MATH_H #include "math.h" #endif #include /* #include */ /* Chow: needed for GetTime and GetDate */ /* chow: remote sys above since header file got moved */ #define NO_NODE 0 #define KMPERDEG 111.3194 /* km/deg */ #define LIGHTSPEED 299796.0 /* km/sec */ /* index of refraction for glass -- lightspeed / index = lightspeed in material */ #define BLACK_MSG " BLACK" #define GRAY_MSG " GRAY" #define BLACK_X_MSG "X BLACK" /* connected Black Msg */ #define GRAY_X_MSG "X GRAY" /* connected Gray Msg */ #define BT_BLACK_MSG "BT-BLACK" #define BT_GRAY_MSG " BT-GRAY" #define CANCEL_MSG " CANCEL" #define INBAND_MSG "*inband*" #define CONFIRM_MSG " confirm" #define TIME_UP_MSG " TIME UP" /* link description */ typedef struct linkdata { long dest; boolean active; float delay; long work, spare, xspare, swork; /*starting number of working lines*/ long sspare; /*starting number of spares*/ } linkdata; /* table data maintained by TWO PRONG algorithm */ typedef struct tablerec { long black; long bw; long gray; long inband, confirm; struct tablerec *next, *prev; } tablerec; /* TWO PRONG node states */ typedef enum { WHITE, BLACK_ORIGIN, BLACK, GRAY, GRAY_ORIGIN } nodestates; /* node state information for TWO PRONG */ typedef struct node { long id; long seqnum; float time; list links; Char name[16]; float msg_process_delay; nodestates state; float lat, long_; long tofix; /* these down specific to TWO PRONG */ tablerec *tablehead, *tabletail; long repeatlimit; } node; Static long maxrepeats = 13; /* to avoid looping */ Static boolean overwriteRL = false; Static float connectTime = 0.0; /* in sec */ Static boolean OVERWRITE_LINK_DISTANCE; Static long LINK_DISTANCE_IN_MILES = 0; /* 1 for link distance in miles 2 for link distance in km 0 for link distance field not used */ Static float NOISE_SIZE = 0.00001; /* multiplied by random 0..100 */ Static float PPTOVERRIDE = -1.0; static int PARALLEL_DCS = 0;/*default parallel DCS connection all in one batch*/ /* 1 for connecting one path at CROSS_CONNECT_TIME time */ /* k for connecting k paths at CROSS_CONNECT_TIME time */ Static int MSG_LENGTH = 8; /* assume fixed length 8 byte messages */ Static int TX_SPEED = 8; /* default transmission speed is 8 kbps */ Static float CROSS_CONNECT_TIME = 0.01; /*default DCS connection time 10msec*/ Static float transmit_delay = 0.0; Static float LINK_CHECK_SCALEFACTOR = 0.05; /* fraction of node msg process delay */ Static float STOP_TIME = 2.0; /* sec -- total run time of simulation */ Static float TIME_UP_TIME = 1.0; /* sec -- time allowed to find full restortion */ Static float REFRACINDEX = 1.5; Static boolean DEBUG = false; /* state display in via path printout */ Static Char statechar[5] = { ' ', ' ', ' ', ' ', ' ' }; Static long count; Static erec *ee; Static long i, j; Static boolean SaveEvents; Static list net; Static long netsize; Static symbol_node *nodename; Static FILE *log_; Static Char pathlist[256]; Static node *nextnode; Static boolean stop; Static symbol_node *options; Static Char result[256]; Static Char outfilename[81], infilename[81]; Static long break1, break2; Static Char break1str[21], break2str[21]; Static boolean redirect; Static long path_count, bw_found, bw_needed; Static boolean print_flag; Static long spare_used; Static long rstr_msg_count; Static long msg_count; Static float lastRestoreTime = 0.0; /* GetTime and GetDate probably are Turbo Pascal library routines */ /* replace that with the equivalent unix c library */ Void GetTime(hr, min, sec, csec) unsigned short hr, min, sec, csec; { struct timeval t; struct tm *local; /* note that tm_hour tm_min tm_sec are all int type, not short */ gettimeofday(&t, 0); local = localtime((time_t *) &t.tv_sec); hr = local->tm_hour; min = local->tm_min; sec = local->tm_sec; csec = t.tv_usec/10000L; } Void GetDate(yr, mon, day, dow) unsigned short yr, mon, day, dow; { struct timeval t; struct tm *local; gettimeofday(&t, 0); local = localtime((time_t *) &t.tv_sec); yr = local->tm_year; mon = local->tm_mon; day = local->tm_mday; dow = local->tm_wday; } long countSpare(path) Char *path; { long i; Char *p; i = 0; p = path; while (*p != 0) { if (*p == ' ') i++; p++; } return i; } Static Char *simtime2str(Result, v) Char *Result; float v; { Char s[256]; sprintf(s, "%8.5f", v); return strcpy(Result, s); } Static Char *int2str_(Result, i) Char *Result; long i; { Char s[6]; Char STR1[8]; i %= 1000; /* p2c: newp.pas, line 128: * Note: Using % for possibly-negative arguments [317] sprintf(s, "%12ld", i); if (i < 10) sprintf(s, "00%s", strcpy(STR1, s)); else { if (i < 100) sprintf(s, "0%s", strcpy(STR1, s)); } */ sprintf(s, "%0.3ld", i); return strcpy(Result, s); } Static float noise() { return 0.0; /* noise := random( 100 )*NOISE_SIZE; */ } Static Void simlog(s) Char *s; { fprintf(log_, "%s\n", s); } typedef long pathsequence[64]; Local Void eliminate_backtracks(p, c) long *p; long *c; { long tos, i, FORLIM; if (*c < 3) /* backtracking path impossible */ return; tos = 3; while (tos <= *c) { if (p[tos - 2] == p[tos]) { /* eliminate bracktrack nodes */ tos -= 2; *c -= 2; FORLIM = *c; /* left shift path to overwrite */ for (i = tos + 1; i <= FORLIM; i++) p[i] = p[i + 2]; } tos++; } } Local Void flood_msg(ev, n, cnode, bw) erec *ev; long n; node *cnode; long bw; { Char value[256]; long sent; long i; linkdata *clink; erec *hold; Char STR1[256]; Char STR3[256]; long FORLIM; find_symbol_def(value, ev->msg, "PATH"); sprintf(STR3, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 > maxrepeats) return; /* avoid flood with PATH length > maxrepeats */ init_symbol(&ev->msg, "PATH", STR3); sent = 0; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->active && clink->xspare != 0 && clink->dest != ev->src) { sent++; hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); hold->time = cnode->time + sent * cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, imin(bw, (long)clink->xspare))); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; clink->xspare -= imin((long)bw, (long)clink->xspare); } } /* update node time */ cnode->time += sent * cnode->msg_process_delay + i * cnode->msg_process_delay * LINK_CHECK_SCALEFACTOR; } /* flood_msg */ Local Void forward_msg(ev, n, cnode, destination, bw, mtype) erec *ev; long n; node *cnode; long destination; uchar bw; Char *mtype; { Char value[256]; linkdata *clink; erec *hold; Char STR1[256]; Char STR3[256]; hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); find_symbol_def(value, ev->msg, "PATH"); sprintf(STR3, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 > maxrepeats) return; /* avoid forward with PATH length > maxrepeats */ init_symbol(&hold->msg, "PATH", STR3); clink = (linkdata *)head(&cnode->links); while (clink->dest != destination) clink = (linkdata *)next(&cnode->links); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)bw)); init_symbol(&hold->msg, "TYPE", mtype); if (strcmp(mtype, INBAND_MSG) || strcmp(mtype, CONFIRM_MSG)) hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); else hold->time = ev->time + clink->delay + noise(); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; if (strcmp(mtype, INBAND_MSG) || strcmp(mtype, CONFIRM_MSG)) cnode->time += cnode->msg_process_delay; } /* forward_msg */ Local Void add_to_table(head, tail, black, bw, gray) tablerec **head, **tail; long black; uchar bw; long gray; { tablerec *temp; if (*head == NULL) { *head = (tablerec *)Malloc(sizeof(tablerec)); (*head)->black = black; (*head)->bw = bw; (*head)->gray = gray; (*head)->inband = 0; (*head)->confirm = 0; (*head)->next = NULL; (*head)->prev = NULL; *tail = *head; return; } temp = *tail; *tail = (tablerec *)Malloc(sizeof(tablerec)); (*tail)->black = black; (*tail)->bw = bw; (*tail)->gray = gray; (*tail)->inband = 0; (*tail)->confirm = 0; temp->next = *tail; (*tail)->next = NULL; (*tail)->prev = temp; } /* add_to_table */ Local Void insert_in_table(head, finger, tail, black, bw, gray) tablerec *head, *finger, **tail; long black; uchar bw; long gray; { tablerec *temp; if (finger == *tail) { add_to_table(&head, tail, black, bw, gray); return; } temp = (tablerec *)Malloc(sizeof(tablerec)); if (black > 256) printf("error inser_in_table: black >256\n"); temp->black = black; temp->bw = bw; temp->gray = gray; temp->inband = 0; temp->confirm = 0; temp->next = finger->next; finger->next->prev = temp; finger->next = temp; temp->prev = finger; } /* insert_in_table */ Local Void delete_from_table(head, finger, tail) tablerec **head, **finger, **tail; { tablerec *temp; if (*finger == *head && *finger == *tail) { Free(*finger); *head = NULL; *finger = NULL; *tail = NULL; return; } if (*finger == *tail) { *tail = (*tail)->prev; (*tail)->next = NULL; Free(*finger); *finger = NULL; return; } if (*finger == *head) { *head = (*head)->next; (*head)->prev = NULL; Free(*finger); *finger = *head; return; } temp = (*finger)->next; temp->prev = (*finger)->prev; (*finger)->prev->next = temp; Free(*finger); *finger = temp; /* finger <> head & finger <> tail */ } /* delete_from_table */ Local Void pack_table(cnode) node *cnode; { tablerec *pick, *finger, *match, *thumb; finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; thumb = finger; while (thumb != NULL) { match = thumb; thumb = match->next; if (match->black != pick->black || match->gray != pick->gray) continue; pick->bw += match->bw; pick->inband += match->inband; if (finger == match) finger = finger->next; delete_from_table(&cnode->tablehead, &match, &cnode->tabletail); } } } /* pack_table */ Local Void take_spares(cnode, firstDest, secondDest, bw) node *cnode; long firstDest, secondDest; uchar bw; { linkdata *clink; long i, FORLIM; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->dest == firstDest || clink->dest == secondDest) { clink->spare -= bw; clink->work += bw; } } } /* take_spares */ Local Void give_spares(cnode, firstDest, secondDest, bw) node *cnode; long firstDest, secondDest; uchar bw; { linkdata *clink; long i, FORLIM; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->dest == firstDest || clink->dest == secondDest) { clink->spare += bw; clink->work -= bw; } } } /* give_spares */ Local Void back_track_msg(ev, n, cnode, mtype) erec *ev; long n; node *cnode; Char *mtype; { uchar bw; tablerec *pick, *finger; Char value[256]; erec *hold; linkdata *clink; Char STR1[256]; Char STR3[256]; /* calculate connected bandwidth */ bw = 0; if (!strcmp(mtype, BLACK_MSG) || !strcmp(mtype, BLACK_X_MSG)) { finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black == ev->src && pick->gray != NO_NODE) bw += pick->bw; } /* while */ } else { finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray == ev->src && pick->black != NO_NODE) bw += pick->bw; } /* while */ } /* send back track message */ find_symbol_def(value, ev->msg, "PATH"); sprintf(STR3, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 > maxrepeats) return; /* avoid send backtrack msg with PATH length > maxrepeats */ init_symbol(&ev->msg, "PATH", STR3); hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); clink = (linkdata *)head(&cnode->links); while (clink->dest != ev->src) clink = (linkdata *)next(&cnode->links); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)bw)); if (!strcmp(mtype, BLACK_MSG) || !strcmp(mtype, BLACK_X_MSG)) init_symbol(&hold->msg, "TYPE", BT_BLACK_MSG); else init_symbol(&hold->msg, "TYPE", BT_GRAY_MSG); hold->next = ev->src; hold->src = n; hold->dst = ev->src; queue_event(hold); msg_count++; /* update node time */ cnode->time += cnode->msg_process_delay + noise(); } /* back_track_msg */ Local Void forward_back_track_msg(ev, n, cnode, mtype, dest) erec *ev; long n; node *cnode; Char *mtype; long dest; { uchar bw; tablerec *pick, *finger; Char value[256]; erec *hold; linkdata *clink; Char STR1[256]; Char STR3[256]; /* calculate connected bandwidth */ bw = 0; if (!strcmp(mtype, BT_BLACK_MSG)) { finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black == dest && pick->gray != NO_NODE) bw += pick->bw; } /* while */ } else { /*mtype = BT_GRAY_MSG*/ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray == dest && pick->black != NO_NODE) bw += pick->bw; } /* while */ } /* send back track message */ find_symbol_def(value, ev->msg, "PATH"); sprintf(STR3, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 > maxrepeats) return; /* avoid forward backtrack msg with PATH length > maxrepeats */ init_symbol(&ev->msg, "PATH", STR3); hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); clink = (linkdata *)head(&cnode->links); while (clink->dest != dest) clink = (linkdata *)next(&cnode->links); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)bw)); hold->next = dest; hold->src = n; hold->dst = dest; queue_event(hold); msg_count++; /* update node time */ cnode->time += cnode->msg_process_delay + noise(); } /* forward_back_track_msg */ Local Void redirect_gray(ev, cnode, n, source, srcnext, no_choice) erec *ev; node *cnode; long n; tablerec *source; tablerec **srcnext; long no_choice; { tablerec *finger, *pick; erec *hold; Char value[256]; linkdata *clink; Char STR1[256]; Char STR2[256], STR3[256]; /* try to match up with earlier black msgs */ finger = cnode->tablehead; while (finger != NULL && source->bw != 0) { pick = finger; finger = finger->next; if (pick->gray != NO_NODE || pick->black == source->gray || pick->black == no_choice) continue; if (pick->bw >= source->bw) { source->black = pick->black; pick->bw -= source->bw; if (pick->bw == 0) { if (pick == *srcnext) { if (pick->next == NULL) *srcnext = NULL; else *srcnext = pick->next; } delete_from_table(&cnode->tablehead, &pick, &cnode->tabletail); } take_spares(cnode, source->black, source->gray, source->bw); /* can use new forward */ /* forward new gray msg */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); find_symbol_def(value, ev->msg, "PATH"); sprintf(STR3, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 > maxrepeats) return; /* avoid redirect_gray msg with PATH length > maxrepeats */ init_symbol(&hold->msg, "PATH", STR3); clink = (linkdata *)head(&cnode->links); while (clink->dest != source->black) clink = (linkdata *)next(&cnode->links); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)source->bw)); init_symbol(&hold->msg, "TYPE", GRAY_X_MSG); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; cnode->time += cnode->msg_process_delay; return; } pick->gray = source->gray; take_spares(cnode, pick->black, pick->gray, pick->bw); /* use new forward */ /* forward new gray msg */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); find_symbol_def(value, ev->msg, "PATH"); sprintf(STR2, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR2)/4 > maxrepeats) return; /* avoid forward new gray msg with PATH length > maxrepeats */ init_symbol(&hold->msg, "PATH", STR2); clink = (linkdata *)head(&cnode->links); while (clink->dest != pick->black) clink = (linkdata *)next(&cnode->links); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)pick->bw)); init_symbol(&hold->msg, "TYPE", GRAY_X_MSG); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; cnode->time += cnode->msg_process_delay; source->bw -= pick->bw; } /* pick^.bw < bw */ } /* redirect_gray */ Local Void redirect_black(ev, cnode, n, source, srcnext, no_choice) erec *ev; node *cnode; long n; tablerec *source; tablerec **srcnext; long no_choice; { tablerec *finger, *pick; erec *hold; Char value[256]; linkdata *clink; Char STR1[256]; Char STR2[256], STR3[256]; /* try to match up with earlier gray msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black != NO_NODE || pick->gray == source->black || pick->gray == no_choice) continue; if (pick->bw >= source->bw) { source->gray = pick->gray; pick->bw -= source->bw; if (pick->bw == 0) { if (pick == *srcnext) { if (pick->next == NULL) *srcnext = NULL; else *srcnext = pick->next; } delete_from_table(&cnode->tablehead, &pick, &cnode->tabletail); } take_spares(cnode, source->black, source->gray, source->bw); /* can use new forward */ /* forward new black msg */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); find_symbol_def(value, ev->msg, "PATH"); sprintf(STR3, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 > maxrepeats) return; /* avoid forward new black msg with PATH length > maxrepeats */ init_symbol(&hold->msg, "PATH", STR3); clink = (linkdata *)head(&cnode->links); while (clink->dest != source->gray) clink = (linkdata *)next(&cnode->links); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)source->bw)); init_symbol(&hold->msg, "TYPE", BLACK_X_MSG); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; cnode->time += cnode->msg_process_delay; return; } pick->black = source->black; take_spares(cnode, pick->black, pick->gray, pick->bw); /* can use new forward */ /* forward new black msg */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); find_symbol_def(value, ev->msg, "PATH"); sprintf(STR2, "%s%s%c", value, int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR2)/4 > maxrepeats) return; /* avoid forward new black msg with PATH length > maxrepeats */ init_symbol(&hold->msg, "PATH", STR2); clink = (linkdata *)head(&cnode->links); while (clink->dest != pick->gray) clink = (linkdata *)next(&cnode->links); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)pick->bw)); init_symbol(&hold->msg, "TYPE", BLACK_X_MSG); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; cnode->time += cnode->msg_process_delay; source->bw -= pick->bw; } } /* redirect_black */ Static Void process(ev, n, cnode) erec *ev; long n; node *cnode; { tablerec *pick, *finger; long v, err, i, no_way; long sent; long bw; erec *hold; Char mtype[21]; linkdata *clink; tablerec *oldfinger, *grandfinger; long FORLIM; Char value[256]; Char STR1[256], STR2[256], STR3[256]; Char STR4[256]; /* check for simulation end */ if (ev->time == STOP_TIME) { stop = true; simlog(" "); sprintf(STR2, "Unrestored lines remaining: %s", int2str_(STR1, cnode->tofix)); simlog(STR2); return; } /* check for update of node local time */ if (ev->time > cnode->time) cnode->time = ev->time; /* time it takes to process incoming msg */ if (PPTOVERRIDE >= 0.0) cnode->time += PPTOVERRIDE + noise(); else cnode->time += cnode->msg_process_delay + noise(); /* determine msg type */ find_symbol_def(mtype, ev->msg, "TYPE"); /* check if "SIM" control messages */ if (!strcmp(mtype, " SIM")) { find_symbol_def(value, ev->msg, "ACTION"); if (strcmp(value, "BREAK")) /* set state & deactivate link */ return; /*which broke? */ err = (sscanf(find_symbol_def(STR1, ev->msg, "ID"), "%ld", &v) == 0); /* set BLACK_ORIGIN or GRAY_ORIGIN */ if (v <= n) { cnode->state = BLACK_ORIGIN; maxrepeats = cnode->repeatlimit; printf("Maximum repeat limit is set to %d\n", maxrepeats); /* init common msg fields */ init_symbol(&ev->msg, "TYPE", BLACK_MSG); /* queue event to stop simulation to BLACK_ORIGIN */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); init_symbol(&hold->msg, "TYPE", " STOP"); init_symbol(&hold->msg, "PATH", "SIMULATION TIMEOUT"); hold->time = STOP_TIME; hold->next = n; hold->src = 0; hold->dst = n; queue_event(hold); /* queue event to start cancellation to BLACK_ORIGIN if full restoration has not been achieved after one second */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); init_symbol(&hold->msg, "TYPE", " TIME UP"); init_symbol(&hold->msg, "PATH", "SIMULATION TIMEOUT"); hold->time = TIME_UP_TIME; hold->next = n; hold->src = 0; hold->dst = n; queue_event(hold); } else { cnode->state = GRAY_ORIGIN; /* init common msg fields */ init_symbol(&ev->msg, "TYPE", GRAY_MSG); } /* deactivate link & set channels to restore */ clink = (linkdata *)head(&cnode->links); if (clink == NULL) { printf("There is no span from %s to %s\n", break1str, break2str); exit(3); } while (clink->dest != v) { clink = (linkdata *)next(&cnode->links); if (clink == NULL) { printf("There is no span from %s to %s\n", break1str, break2str); exit(3); } } clink->active = false; cnode->tofix = clink->work; bw_needed = clink->work; if (cnode->state == BLACK_ORIGIN) printf("(%3d working channels lost)\n\n", bw_needed); clink->work = 0; clink->spare = 0; sprintf(STR2, "%s%c", int2str_(STR1, n), statechar[(long)cnode->state]); /* flood msgs */ /* init common msg fields */ init_symbol(&ev->msg, "PATH", STR2); init_symbol(&ev->msg, "SEQ#", int2str_(STR1, (long)cnode->seqnum)); /* do flood to "reasonable" nodes */ sent = 0; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->active && clink->xspare != 0) { /* send msg */ sent++; /* new msg creation */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); hold->time = cnode->time + sent * cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, imin(cnode->tofix, (long)clink->xspare))); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; clink->xspare -= imin(cnode->tofix, (long)clink->xspare); } } /* update node time */ cnode->time += sent * cnode->msg_process_delay + i * cnode->msg_process_delay * LINK_CHECK_SCALEFACTOR; return; /* don't need to process normal states */ } /*????*/ /* check for valid seq# & update as required */ err = (sscanf(find_symbol_def(STR1, ev->msg, "SEQ#"), "%ld", &v) == 0); if (v != cnode->seqnum && strcmp(mtype, CANCEL_MSG)) return; /* start of normal message processing... ***************** */ /* writeln ('count = ',count, ' node = ', cnode^.name, ' msg type = ', mtype); count := count + 1; */ if (cnode->state == BLACK && (!strcmp(mtype, BLACK_MSG) || !strcmp(mtype, BLACK_X_MSG))) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; /* clean out meaningless earlier gray msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray == ev->src && pick->black == NO_NODE) delete_from_table(&cnode->tablehead, &pick, &cnode->tabletail); else if (pick->gray == ev->src && pick->black != NO_NODE) { back_track_msg(ev, n, cnode, mtype); return; /* throw away strategy */ } } /* try to match up with earlier gray msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black != NO_NODE || pick->gray == ev->src) continue; if (pick->bw >= bw) { if (pick->bw != bw) insert_in_table(cnode->tablehead, pick, &cnode->tabletail, pick->black, pick->bw - bw, pick->gray); pick->black = ev->src; pick->bw = bw; take_spares(cnode, pick->black, pick->gray, bw); forward_msg(ev, n, cnode, pick->gray, bw, BLACK_X_MSG); if (strcmp(mtype, BLACK_X_MSG)) forward_msg(ev, n, cnode, pick->black, bw, GRAY_X_MSG); clink = (linkdata *)head(&cnode->links); while (clink->dest != pick->gray) clink = (linkdata *)next(&cnode->links); if (clink->xspare >= bw) clink->xspare -= bw; else clink->xspare = 0; pack_table(cnode); return; /* p2c: newp.pas: Note: Deleting unreachable code [255] */ } pick->black = ev->src; take_spares(cnode, pick->black, pick->gray, pick->bw); forward_msg(ev, n, cnode, pick->gray, pick->bw, BLACK_X_MSG); if (strcmp(mtype, BLACK_X_MSG)) forward_msg(ev, n, cnode, pick->black, pick->bw, GRAY_X_MSG); clink = (linkdata *)head(&cnode->links); while (clink->dest != pick->gray) clink = (linkdata *)next(&cnode->links); if (clink->xspare >= bw) clink->xspare -= pick->bw; else clink->xspare = 0; bw -= pick->bw; } /* get here if not all the bw can be matched up with grays */ if (!strcmp(mtype, BLACK_MSG)) add_to_table(&cnode->tablehead, &cnode->tabletail, ev->src, bw, (long)NO_NODE); flood_msg(ev, n, cnode, bw); pack_table(cnode); return; } /* BLACK node, BLACK msg or BLACK X msg*/ /* get bandwidth */ if (cnode->state == GRAY && (!strcmp(mtype, GRAY_MSG) || !strcmp(mtype, GRAY_X_MSG))) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; /* clean out meaningless earlier black msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black == ev->src && pick->gray == NO_NODE) delete_from_table(&cnode->tablehead, &pick, &cnode->tabletail); else if (pick->black == ev->src && pick->gray != NO_NODE) { back_track_msg(ev, n, cnode, mtype); return; /* throw away new msg */ } } /* try to match up with earlier black msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray != NO_NODE || pick->black == ev->src) continue; if (pick->bw >= bw) { if (pick->bw != bw) insert_in_table(cnode->tablehead, pick, &cnode->tabletail, pick->black, pick->bw - bw, pick->gray); pick->gray = ev->src; pick->bw = bw; take_spares(cnode, pick->black, pick->gray, bw); forward_msg(ev, n, cnode, pick->black, bw, GRAY_X_MSG); if (strcmp(mtype, GRAY_X_MSG)) forward_msg(ev, n, cnode, pick->gray, bw, BLACK_X_MSG); clink = (linkdata *)head(&cnode->links); while (clink->dest != pick->black) clink = (linkdata *)next(&cnode->links); if (clink->xspare >= bw) clink->xspare -= bw; else clink->xspare = 0; pack_table(cnode); return; /* p2c: newp.pas: Note: Deleting unreachable code [255] */ } pick->gray = ev->src; take_spares(cnode, pick->black, pick->gray, pick->bw); forward_msg(ev, n, cnode, pick->black, pick->bw, GRAY_X_MSG); if (strcmp(mtype, GRAY_X_MSG)) forward_msg(ev, n, cnode, pick->gray, pick->bw, BLACK_X_MSG); clink = (linkdata *)head(&cnode->links); while (clink->dest != pick->black) clink = (linkdata *)next(&cnode->links); if (clink->xspare >= bw) clink->xspare -= pick->bw; else clink->xspare = 0; bw -= pick->bw; } /* get here if not all the bw can be matched up with blacks */ if (!strcmp(mtype, GRAY_MSG)) add_to_table(&cnode->tablehead, &cnode->tabletail, (long)NO_NODE, bw, ev->src); flood_msg(ev, n, cnode, bw); pack_table(cnode); return; } /* GRAY node, GRAY msg or GRAY X msg*/ /* get bandwidth */ if (cnode->state == BLACK && (!strcmp(mtype, GRAY_MSG) || !strcmp(mtype, GRAY_X_MSG))) { /* clean out meaningless earlier black msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black == ev->src && pick->gray == NO_NODE) delete_from_table(&cnode->tablehead, &pick, &cnode->tabletail); else if (pick->black == ev->src && pick->gray != NO_NODE) { back_track_msg(ev, n, cnode, mtype); return; /* throw away new msg */ } } /* get bandwidth */ err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; /* try to match up with earlier black msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray != NO_NODE) continue; if (pick->bw >= bw) { if (pick->bw != bw) insert_in_table(cnode->tablehead, pick, &cnode->tabletail, pick->black, (uchar) (pick->bw - bw), pick->gray); pick->gray = ev->src; pick->bw = bw; take_spares(cnode, pick->black, pick->gray, bw); forward_msg(ev, n, cnode, pick->black, bw, GRAY_X_MSG); pack_table(cnode); return; } else { /* pick^.bw < bw */ pick->gray = ev->src; bw -= pick->bw; take_spares(cnode, pick->black, pick->gray, pick->bw); forward_msg(ev, n, cnode, pick->black, pick->bw, GRAY_X_MSG); continue; } } /* get here if not all the bw can be matched up with blacks */ if (!strcmp(mtype, GRAY_MSG)) add_to_table(&cnode->tablehead, &cnode->tabletail, (long)NO_NODE, bw, ev->src); back_track_msg(ev, n, cnode, mtype); pack_table(cnode); return; } /* BLACK node, GRAY msg or GRAY X msg*/ if (cnode->state == GRAY && (!strcmp(mtype, BLACK_MSG) || !strcmp(mtype, BLACK_X_MSG))) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; /* clean out meaningless earlier gray msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray == ev->src && pick->black == NO_NODE) delete_from_table(&cnode->tablehead, &pick, &cnode->tabletail); else if (pick->gray == ev->src && pick->black != NO_NODE) { back_track_msg(ev, n, cnode, mtype); return; /* throw away strategy */ } } /* try to match up with earlier gray msgs */ finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black != NO_NODE) continue; if (pick->bw >= bw) { if (pick->bw != bw) insert_in_table(cnode->tablehead, pick, &cnode->tabletail, pick->black, pick->bw - bw, pick->gray); pick->black = ev->src; pick->bw = bw; take_spares(cnode, pick->black, pick->gray, bw); forward_msg(ev, n, cnode, pick->gray, bw, BLACK_X_MSG); pack_table(cnode); return; } else { /* pick^.bw < bw */ pick->black = ev->src; bw -= pick->bw; take_spares(cnode, pick->black, pick->gray, pick->bw); forward_msg(ev, n, cnode, pick->gray, pick->bw, BLACK_X_MSG); continue; } } /* get here if not all the bw can be matched up with grays */ if (!strcmp(mtype, BLACK_MSG)) add_to_table(&cnode->tablehead, &cnode->tabletail, ev->src, bw, (long)NO_NODE); back_track_msg(ev, n, cnode, mtype); pack_table(cnode); return; } /* GRAY node, BLACK msg or BLACK X msg*/ /* get bandwidth */ if (cnode->state == BLACK && !strcmp(mtype, BT_BLACK_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray != ev->src || pick->black == NO_NODE) continue; if (pick->bw >= bw && bw > 0) { redirect = false; if (pick->bw != bw) { no_way = pick->gray; insert_in_table(cnode->tablehead, pick, &cnode->tabletail, pick->black, pick->bw - bw, (long)NO_NODE); redirect = true; } give_spares(cnode, pick->black, pick->gray, pick->bw - bw); pick->bw = bw; bw = 0; if (redirect) redirect_black(ev, cnode, n, pick->next, &finger, no_way); forward_back_track_msg(ev, n, cnode, mtype, pick->black); continue; } if (pick->bw < bw) { bw -= pick->bw; continue; } give_spares(cnode, pick->black, pick->gray, pick->bw); no_way = pick->gray; pick->gray = NO_NODE; redirect_black(ev, cnode, n, pick, &finger, no_way); forward_back_track_msg(ev, n, cnode, mtype, pick->black); } pack_table(cnode); return; } /* BLACK node, BT_BLACK_MSG */ /* get bandwidth */ if (cnode->state == GRAY && !strcmp(mtype, BT_GRAY_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; finger = cnode->tablehead; i = 0; pick = NULL; oldfinger = NULL; while (finger != NULL) { i++; grandfinger = oldfinger; oldfinger = pick; pick = finger; finger = finger->next; if (pick->black != ev->src || pick->gray == NO_NODE) continue; if (pick->bw >= bw && bw > 0) { redirect = false; if (pick->bw != bw) { no_way = pick->black; insert_in_table(cnode->tablehead, pick, &cnode->tabletail, (long)NO_NODE, pick->bw - bw, pick->gray); redirect = true; } give_spares(cnode, pick->black, pick->gray, pick->bw - bw); pick->bw = bw; bw = 0; if (redirect) { redirect_gray(ev, cnode, n, pick->next, &finger, no_way); } forward_back_track_msg(ev, n, cnode, mtype, pick->gray); continue; } if (pick->bw < bw) { bw -= pick->bw; continue; } give_spares(cnode, pick->black, pick->gray, pick->bw); no_way = pick->black; pick->black = NO_NODE; redirect_gray(ev, cnode, n, pick, &finger, no_way); /* chow: found that it is possible redirect_gray change the table and delete the entry pointed by finger, i.e. pick becomes the last entry. on sparc, the deleted entry will have garbage data. while DEC still maintain the data for short while, this is the reason why twoprong runs ok on DEC and run into problem on sparc The temporary fix is to check pick->next== null after return and set the finger accordingly. Here the permanent fix is to pass &finger to be changed by redirect_gray() if (pick->next == NULL) finger = NULL; */ forward_back_track_msg(ev, n, cnode, mtype, pick->gray); } pack_table(cnode); return; } /* GRAY node, BT_GRAY_MSG */ /* get bandwidth */ if (cnode->state == BLACK && !strcmp(mtype, BT_GRAY_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->black != ev->src || pick->gray == NO_NODE) continue; if (pick->bw >= bw && bw > 0) { redirect = false; if (pick->bw != bw) { no_way = pick->black; insert_in_table(cnode->tablehead, pick, &cnode->tabletail, (long)NO_NODE, pick->bw - bw, pick->gray); redirect = true; } give_spares(cnode, pick->black, pick->gray, pick->bw - bw); pick->bw = bw; bw = 0; if (redirect) redirect_gray(ev, cnode, n, pick->next, &finger, no_way); forward_back_track_msg(ev, n, cnode, mtype, pick->gray); continue; } if (pick->bw < bw) { bw -= pick->bw; continue; } give_spares(cnode, pick->black, pick->gray, pick->bw); no_way = pick->black; pick->black = NO_NODE; redirect_gray(ev, cnode, n, pick, &finger, no_way); if (pick->next == NULL) finger = NULL; forward_back_track_msg(ev, n, cnode, mtype, pick->gray); } pack_table(cnode); return; } /* BLACK node, BT_GRAY_MSG */ /* get bandwidth */ if (cnode->state == GRAY && !strcmp(mtype, BT_BLACK_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->gray != ev->src || pick->black == NO_NODE) continue; if (pick->bw >= bw && bw > 0) { redirect = false; if (pick->bw != bw) { no_way = pick->gray; insert_in_table(cnode->tablehead, pick, &cnode->tabletail, pick->black, pick->bw - bw, (long)NO_NODE); redirect = true; } give_spares(cnode, pick->black, pick->gray, pick->bw - bw); pick->bw = bw; bw = 0; if (redirect) redirect_black(ev, cnode, n, pick->next, &finger, no_way); forward_back_track_msg(ev, n, cnode, mtype, pick->black); continue; } if (pick->bw < bw) { bw -= pick->bw; continue; } give_spares(cnode, pick->black, pick->gray, pick->bw); no_way = pick->gray; pick->gray = NO_NODE; redirect_black(ev, cnode, n, pick, &finger, no_way); forward_back_track_msg(ev, n, cnode, mtype, pick->black); } pack_table(cnode); return; } /* GRAY node, BT_BLACK_MSG */ /* get bandwidth */ if (cnode->state == BLACK_ORIGIN && (!strcmp(mtype, GRAY_MSG) || !strcmp(mtype, GRAY_X_MSG))) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; /*send out mapping message*/ clink = (linkdata *)head(&cnode->links); while (clink->dest != ev->src) clink = (linkdata *)next(&cnode->links); hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); sprintf(STR2, "%s%c", int2str_(STR1, n), statechar[(long)cnode->state]); init_symbol(&hold->msg, "PATH", STR2); init_symbol(&hold->msg, "TYPE", INBAND_MSG); hold->time = cnode->time + cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)bw)); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; /* update node time */ cnode->time += cnode->msg_process_delay; return; } /* BLACK_ORIGIN node, GRAY_MSG or GRAY_X_MSG */ /* get bandwidth */ if ((cnode->state == BLACK || cnode->state == GRAY) && !strcmp(mtype, INBAND_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->bw - pick->inband >= bw && pick->black == ev->src && pick->gray != NO_NODE) { forward_msg(ev, n, cnode, pick->gray, bw, INBAND_MSG); pick->inband += bw; pack_table(cnode); return; } if (pick->bw - pick->inband > 0 && pick->black == ev->src && pick->gray != NO_NODE) { forward_msg(ev, n, cnode, pick->gray, pick->bw - pick->inband, INBAND_MSG); bw += pick->inband - pick->bw; pick->inband = pick->bw; } } /*while*/ pack_table(cnode); return; } /* BLACK node or GRAY node, INBAND MSG */ if ((cnode->state == BLACK || cnode->state == GRAY) && !strcmp(mtype, CONFIRM_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->inband - pick->confirm >= bw && pick->gray == ev->src) { if (pick->black != 0) { forward_msg(ev, n, cnode, pick->black, bw, CONFIRM_MSG); pick->confirm += bw; } return; } if (pick->inband - pick->confirm > 0 && pick->gray == ev->src) { forward_msg(ev, n, cnode, pick->black, pick->inband - pick->confirm, CONFIRM_MSG); bw += pick->confirm - pick->inband; pick->confirm = pick->inband; } } /*while*/ return; } /* BLACK node or GRAY node, CONFIRM MSG */ if (cnode->state == GRAY_ORIGIN && !strcmp(mtype, INBAND_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; if (cnode->tofix == 0) return; if (cnode->tofix != 0) { path_count++; printf("Path %2ld ", path_count); /* update fix info */ if (cnode->tofix > bw) { cnode->tofix -= bw; bw_found += bw; printf("(%2d bw)", bw); } else { printf("(%2d bw)", cnode->tofix); bw_found = bw_needed; bw = cnode->tofix; cnode->tofix = 0; } } if (PARALLEL_DCS == 0) connectTime = CROSS_CONNECT_TIME; else if (bw%PARALLEL_DCS) { connectTime = (bw/PARALLEL_DCS+1)*CROSS_CONNECT_TIME; } else { connectTime = (bw/PARALLEL_DCS)*CROSS_CONNECT_TIME; } if (cnode->time > lastRestoreTime) lastRestoreTime = cnode->time + connectTime; else lastRestoreTime = lastRestoreTime + connectTime; /* connect to be put off */ printf("%6.2f%% rstrd at ", bw_found * 100.0 / bw_needed); printf("%3.2f msec ---> ", lastRestoreTime*1000); find_symbol_def(pathlist, ee->msg, "PATH"); FORLIM = netsize; for (i = 0; i <= FORLIM; i++) strcpy(pathlist, replace_strs(STR2, pathlist, int2str_(STR1, i), find_symbol_def(STR3, nodename, int2str_(STR4, i)))); sprintf(STR1, "(%s%s)", pathlist, cnode->name); i=countSpare(STR1); printf("%s\n", STR1); spare_used +=i*bw; rstr_msg_count = msg_count; take_spares(cnode, ev->src, (long)NO_NODE, bw); init_symbol(&ev->msg, "PATH", ""); forward_msg(ev, n, cnode, ev->src, bw, CONFIRM_MSG); return; } if (cnode->state == WHITE && !strcmp(mtype, BLACK_MSG)) { /* set node state */ cnode->state = BLACK; /* get bandwidth */ err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; /* make table entry */ add_to_table(&cnode->tablehead, &cnode->tabletail, ev->src, bw, (long)NO_NODE); /* flood messages */ flood_msg(ev, n, cnode, bw); return; } /* WHITE node, BLACK msg */ if (cnode->state == WHITE && !strcmp(mtype, GRAY_MSG)) { /* set node state */ cnode->state = GRAY; /* get bandwidth */ find_symbol_def(STR1, ev->msg, "BW"); err = (sscanf(STR1, "%d", &i) == 0); bw = i; /* make table entry */ add_to_table(&cnode->tablehead, &cnode->tabletail, (long)NO_NODE, bw, ev->src); /* flood messages */ flood_msg(ev, n, cnode, bw); return; } /* WHITE node, GRAY msg */ if ((cnode->state == GRAY || cnode->state == BLACK) && !strcmp(mtype, CANCEL_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "SEQ#"), "%d", &cnode->seqnum) == 0); finger = cnode->tablehead; while (finger != NULL) { pick = finger; finger = finger->next; if (pick->confirm != pick->bw && pick->black != NO_NODE && pick->gray != NO_NODE) give_spares(cnode, pick->black, pick->gray, pick->bw - pick->confirm); } /* flood CANCEL msgs */ /* init common msg fields */ init_symbol(&ev->msg, "TYPE", CANCEL_MSG); sprintf(STR3, "%s%c", int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 <= maxrepeats) { /* avoid flood CANCEL msg with PATH length > maxrepeats */ init_symbol(&ev->msg, "PATH", STR3); init_symbol(&ee->msg, "SEQ#", int2str_(STR1, (long)cnode->seqnum)); /* do flood to "reasonable" nodes */ sent = 0; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->active && clink->sspare != 0) { /* send msg */ sent++; /* new msg creation */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); hold->time = cnode->time + sent * cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)(clink->work - clink->swork))); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; clink->xspare = clink->spare; } } /* update node time */ cnode->time += sent * cnode->msg_process_delay + i * cnode->msg_process_delay * LINK_CHECK_SCALEFACTOR; } cnode->state = WHITE; return; } if (cnode->state == BLACK_ORIGIN && !strcmp(mtype, CONFIRM_MSG)) { err = (sscanf(find_symbol_def(STR1, ev->msg, "BW"), "%d", &i) == 0); bw = i; take_spares(cnode, ev->src, (long)NO_NODE, bw); cnode->tofix -= bw; if (cnode->tofix != 0) return; cnode->seqnum++; /* bump seqnum */ /* flood CANCEL msgs */ /* init common msg fields */ init_symbol(&ev->msg, "TYPE", CANCEL_MSG); sprintf(STR3, "%s%c", int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 <= maxrepeats) { /* avoid flood CANCEL msg with PATH length > maxrepeats */ init_symbol(&ev->msg, "PATH", STR3); init_symbol(&ee->msg, "SEQ#", int2str_(STR1, (long)cnode->seqnum)); /* do flood to "reasonable" nodes */ sent = 0; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->active && clink->sspare != 0) { /* send msg */ sent++; /* new msg creation */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); hold->time = cnode->time + sent * cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)(clink->work - clink->swork))); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; clink->xspare = clink->spare; } } /* update node time */ cnode->time += sent * cnode->msg_process_delay + i * cnode->msg_process_delay * LINK_CHECK_SCALEFACTOR; } cnode->state = WHITE; return; } /*BLACK_ORIGIN, CONFIRM_MSG */ /*extract bw from message*/ if (cnode->state == GRAY_ORIGIN && !strcmp(mtype, CANCEL_MSG)) { cnode->state = WHITE; } /* GRAY_ORIGIN, CANCEL_MSG */ if (cnode->state != BLACK_ORIGIN || strcmp(mtype, TIME_UP_MSG)) { return; } /*BLACK_ORIGIN, TIME_UP_MSG */ cnode->seqnum++; /* bump seqnum */ /* flood CANCEL msgs */ /* init common msg fields */ init_symbol(&ev->msg, "TYPE", CANCEL_MSG); sprintf(STR3, "%s%c", int2str_(STR1, n), statechar[(long)cnode->state]); if (strlen(STR3)/4 <= maxrepeats) { /* avoid flood CANCEL msg with PATH length > maxrepeats */ init_symbol(&ev->msg, "PATH", STR3); init_symbol(&ee->msg, "SEQ#", int2str_(STR1, (long)cnode->seqnum)); /* do flood to "reasonable" nodes */ sent = 0; FORLIM = cnode->links.count; for (i = 1; i <= FORLIM; i++) { clink = (linkdata *)recall(&cnode->links, i); if (clink->active && clink->sspare != 0) { /* send msg */ sent++; /* new msg creation */ hold = (erec *)Malloc(sizeof(erec)); *hold = *ev; copy_symbols(&ev->msg, &hold->msg); hold->time = cnode->time + sent * cnode->msg_process_delay + clink->delay + noise(); init_symbol(&hold->msg, "BW", int2str_(STR1, (long)(clink->work - clink->swork))); hold->next = clink->dest; hold->src = n; hold->dst = clink->dest; queue_event(hold); msg_count++; clink->xspare = clink->spare; } } /* update node time */ cnode->time += sent * cnode->msg_process_delay + i * cnode->msg_process_delay * LINK_CHECK_SCALEFACTOR; } cnode->state = WHITE; /* pick^.bw < bw */ /* pick^.bw < bw */ /*bw = 0*/ /*bw = 0*/ /*bw = 0*/ /*bw = 0*/ } /* process */ Static Void init_nodes(s) Char *s; { FILE *netdef; Char line[256], tline[256]; long idx, jdx, err, linkcount; float distance; node *cnode, *idxnode, *jdxnode; linkdata *clink; Char STR1[256]; long FORLIM; Char *TEMP; long FORLIM1; double TEMP1, TEMP2; char type[20]; long V_Hcoord = 0; float linkdistance; /* get net file ready for read */ /* p2c: newp.pas, line 1777: Warning: * Don't know how to ASSIGN to a non-explicit file variable [207] netdef = NULL; assign(netdef, s); rewind(netdef); */ netdef = fopen( to_lower(STR1,s), "r"); /* define SIM node, mainly for logding purposes as source */ cnode = (node *)Malloc(sizeof(node)); strcpy(cnode->name, "SIM"); init_symbol(&nodename, int2str_(STR1, 0L), cnode->name); add(&net, (Anyptr)cnode, 0L); fscanf(netdef, "%ld %s%*[^\n]", &netsize, type); if (strcmp(type, "V_H2") == 0) { OVERWRITE_LINK_DISTANCE = true; V_Hcoord = 1; } else if (strcmp(type, "L_L2") == 0) { OVERWRITE_LINK_DISTANCE = true; V_Hcoord = 0; } else if (strcmp(type, "V_H2wSpanMiles") == 0) { LINK_DISTANCE_IN_MILES = 1; V_Hcoord = 1; printf("Overwrite Propagation delay using the span miles specified in each link.\n"); } else if (strcmp(type, "L_L2wSpanKms") == 0) { LINK_DISTANCE_IN_MILES = 2; V_Hcoord = 0; printf("Overwrite Propagation delay using the span km specified in each link.\n"); } else { printf("unrecongized file type=%s\n This program recognizes V_H2, L_L2, V_H2wSpanMiles, and L_L2wSpanKms.\n", type); } getc(netdef); FORLIM = netsize; /* for all nodes ... */ for (idx = 1; idx <= FORLIM; idx++) { cnode = (node *)Malloc(sizeof(node)); init_list(&cnode->links); cnode->tablehead = NULL; cnode->tabletail = NULL; cnode->time = 0.0; cnode->tofix = 0; cnode->seqnum = 0; fgets(line, 256, netdef); TEMP = strchr(line, '\n'); if (TEMP != NULL) *TEMP = 0; tokenize(tline, line); get_token(cnode->name, tline); init_symbol(&nodename, int2str_(STR1, idx), cnode->name); err = (sscanf(get_token(STR1, tline), "%d", &linkcount) == 0); err = (sscanf(get_token(STR1, tline), "%g", &cnode->msg_process_delay) == 0); cnode->state = 0; /* this field is now used for node specific repeat limit err = (sscanf(get_token(STR1, tline), "%d", (int *)(&cnode->state)) == 0); */ err = (sscanf(get_token(STR1, tline), "%d", &cnode->repeatlimit) == 0); if (overwriteRL) { cnode->repeatlimit = maxrepeats; if (DEBUG) printf("repeat limit of %s is overwritten to %d.\n", cnode->name, cnode->repeatlimit); } else if (cnode->repeatlimit == 0) { cnode->repeatlimit = maxrepeats; if (DEBUG) printf("repeat limit of %s is set to default value %d.\n", cnode->name, cnode->repeatlimit); } else { if (DEBUG) printf("repeat limit of %s is set to %d.\n", cnode->name, cnode->repeatlimit); if (cnode->repeatlimit > maxrepeats) maxrepeats = cnode->repeatlimit; } err = (sscanf(get_token(STR1, tline), "%g", &cnode->lat) == 0); err = (sscanf(get_token(STR1, tline), "%g", &cnode->long_) == 0); /* for all links... */ for (jdx = 1; jdx <= linkcount; jdx++) { clink = (linkdata *)Malloc(sizeof(linkdata)); fgets(line, 256, netdef); TEMP = strchr(line, '\n'); if (TEMP != NULL) *TEMP = 0; tokenize(tline, line); err = (sscanf(get_token(STR1, tline), "%ld", &clink->dest) == 0); clink->active = (strcmp(get_token(STR1, tline), "1") == 0); clink->delay = 0.0; err = (sscanf(get_token(STR1, tline), "%d", &clink->work) == 0); clink->swork = clink->work; err = (sscanf(get_token(STR1, tline), "%d", &clink->spare) == 0); clink->xspare = clink->spare; clink->sspare = clink->spare; if (!OVERWRITE_LINK_DISTANCE) { if (LINK_DISTANCE_IN_MILES != 0) err = (sscanf(get_token(STR1, tline), "%f", &linkdistance) == 0); if (err) { clink->delay = 0.0; printf("Error: the net file does not have link distance field\n" ); exit(1); } else { if (LINK_DISTANCE_IN_MILES == 1) { /* linkdistance field in miles, 1 mile = 1.6093km */ clink->delay = (linkdistance*1.6093)/(LIGHTSPEED/REFRACINDEX); } else { /* linkdistance field in km */ clink->delay = linkdistance / (LIGHTSPEED/REFRACINDEX); } if (DEBUG) { printf("linkdistance =%f, LIGHTSPEED=%f, REFRACINDEX=%f\n", linkdistance, LIGHTSPEED, REFRACINDEX); printf("link %d-%d (internalIDs) delay is set to %f seconds.\n", cnode->id, clink->dest, clink->delay); } } } else clink->delay = 0.0; add(&cnode->links, (Anyptr)clink, jdx); } add(&net, (Anyptr)cnode, idx); } FORLIM = netsize; /* calculate link delays based on relative distances */ for (idx = 1; idx <= FORLIM; idx++) { idxnode = (node *)recall(&net, idx); FORLIM1 = idxnode->links.count; for (jdx = 1; jdx <= FORLIM1; jdx++) { clink = (linkdata *)recall(&idxnode->links, jdx); if (clink->active) { jdxnode = (node *)recall(&net, clink->dest); TEMP1 = idxnode->lat - jdxnode->lat; TEMP2 = idxnode->long_ - jdxnode->long_; if (OVERWRITE_LINK_DISTANCE) { if (V_Hcoord == 1) { distance = sqrt((TEMP2*TEMP2+TEMP1*TEMP1)/10)*1.6; /* from Kershenbaum's Telecom. design text instrution manual */ clink->delay = distance / (LIGHTSPEED / REFRACINDEX); } else if (V_Hcoord == 0) { /* use longitude latitude */ distance = sqrt(TEMP2 * TEMP2 + TEMP1 * TEMP1); clink->delay = distance * KMPERDEG / (LIGHTSPEED / REFRACINDEX); } if (DEBUG) { printf("link %s-%s delay is overwritten/set to %f seconds.\n", cnode->name, jdxnode->name, clink->delay); } } } else clink->delay = 0.0; } } if (netdef != NULL) fclose(netdef); netdef = NULL; if (netdef != NULL) fclose(netdef); } Static Void log_network(header) boolean header; { long idx, jdx; node *cnode; linkdata *outlink; node *endnode; linkdata *inlink; unsigned short hr, min, sec, csec, yr, mon, day, dow; Char STR1[256], STR2[256], STR3[256], STR4[256]; long FORLIM; Char STR5[24]; long FORLIM1; Char STR6[94]; Char STR7[256]; Char STR8[56]; /* dump initial network configuration */ if (header) { GetTime(&hr, &min, &sec, &csec); GetDate(&yr, &mon, &day, &dow); sprintf(STR4, "Run Date: %s/%s", int2str_(STR1, (long)mon), int2str_(STR2, (long)day)); simlog(STR4); sprintf(STR3, "Run Time: %s:%s", int2str_(STR1, (long)hr), int2str_(STR2, (long)min)); simlog(STR3); } simlog(" "); sprintf(STR2, "NETWORK DESCRIPTION for %s", P_argv[1]); simlog(STR2); simlog(" "); if (header) simlog(" *AT SIMULATION START* "); else simlog(" *AT SIMULATION STOP* "); simlog(" "); FORLIM = netsize; for (idx = 1; idx <= FORLIM; idx++) { cnode = (node *)recall(&net, idx); sprintf(STR5, "* FROM: %s", cnode->name); simlog(STR5); FORLIM1 = cnode->links.count; for (jdx = 1; jdx <= FORLIM1; jdx++) { outlink = (linkdata *)recall(&cnode->links, jdx); endnode = (node *)recall(&net, outlink->dest); inlink = (linkdata *)head(&endnode->links); while (inlink->dest != idx) inlink = (linkdata *)next(&endnode->links); sprintf(STR3, " TO: %s OUT: %s (%s) IN: %s (%s)", endnode->name, int2str_(STR2, (long)outlink->work), int2str_(STR1, (long)outlink->spare), int2str_(STR4, (long)inlink->work), int2str_(STR7, (long)inlink->spare)); simlog(STR3); } simlog(" "); } if (!header) /* dump simulation parameters */ return; simlog(" "); simlog(" "); sprintf(STR1, " STOPTIME=%s", simtime2str(STR2, STOP_TIME)); simlog(STR1); sprintf(STR1, " LCS=%s", simtime2str(STR2, LINK_CHECK_SCALEFACTOR)); simlog(STR1); sprintf(STR1, " INDEX=%s", simtime2str(STR2, REFRACINDEX)); simlog(STR1); sprintf(STR1, " NOISE=%s", simtime2str(STR2, NOISE_SIZE)); simlog(STR1); sprintf(STR6, " OUT=%s", outfilename); simlog(STR6); simlog(" "); simlog(" "); sprintf(STR8, " BREAK=%s-%s", break1str, break2str); simlog(STR8); simlog(" "); simlog(" "); simlog(" "); simlog("START OF SIMULATION RUN: "); simlog(" "); simlog(" EV-TIME Q-WAIT"); simlog(" "); } main(argc, argv) int argc; Char *argv[]; { Char STR1[256], STR2[256]; long FORLIM; Char STR3[256]; Char STR4[256]; Char STR5[256], STR6[256]; Char STR7[256]; Char STR8[256], STR9[256]; Char STR10[256]; Char STR11[256]; Char STR12[256]; FILE *fp; Char *cp; long opt_bw_found, opt_spare_used; boolean found; _strings_init(); _netsim_init(); _math_init(); PASCAL_MAIN(argc, argv); log_ = NULL; /* The following two functions are PC specific ClrScr(); _randomize(); */ SaveEvents = false; stop = false; options = NULL; init_symbol(&options, "FIRST_PARAM", NOT_FOUND); init_symbol(&options, "STOPTIME=", "10.0"); init_symbol(&options, "TIMEOUT=", "0.25"); init_symbol(&options, "LCS=", "0.05"); init_symbol(&options, "2INDEX=", "1.5"); init_symbol(&options, "NOISE=", "0.00001"); init_symbol(&options, "MSG_LENGTH=", "8"); init_symbol(&options, "PPTOVERRIDE=", "-1.0"); init_symbol(&options, "OUT=", "NETSIM.OUT"); init_symbol(&options, "BREAK=", NOT_FOUND); init_symbol(&options, "DEBUG", NOT_FOUND); init_symbol(&options, "X_SPEED=", "8"); init_symbol(&options, "YPARALLEL_DCS=", "0"); init_symbol(&options, "WRITE_LINK=", NOT_FOUND); init_symbol(&options, "CROSS_CONNECT_TIME=", "0.01"); init_symbol(&options, "REPEATS=", NOT_FOUND); *result = '\0'; cli(result, &options, '/'); if (*result != '\0') puts(result); find_symbol_def(infilename, options, "FIRST_PARAM"); if (!strcmp(infilename, NOT_FOUND) || strlen(infilename) == 0) { printf("Required net definition filename found on command line!\n"); _Escape(0); } find_symbol_def(result, options, "BREAK="); if (!strcmp(result, NOT_FOUND)) { printf("Required field /BREAK= not found on command line!\n"); _Escape(0); } sprintf(break1str, "%.*s", strpos2(result, "-", 1) - 1, result); strsub(break2str, result, strpos2(result, "-", 1) + 1, strlen(result)); printf("TWOPRONG simulation result...with %s\n", infilename); printf("Break ocurred between node %s and node %s.\n", break1str, break2str); find_symbol_def(result, options, "REPEATS="); if (strcmp(result, NOT_FOUND)) { /* REPEAT LIMIT OVERWRITE option is specified in command line */ overwriteRL = true; i = (sscanf(find_symbol_def(STR2, options, "REPEATS="), "%d", &maxrepeats) == 0); printf("MAXREPEATS (longest explored signature path length) set to %d\n", maxrepeats); } i = (sscanf(find_symbol_def(STR2, options, "CROSS_CONNECT_TIME="), "%g", &CROSS_CONNECT_TIME) == 0); printf("CROSS_CONNECT_TIME is set to %g sec.\n", CROSS_CONNECT_TIME); i = (sscanf(find_symbol_def(result, options, "YPARALLEL_DCS="), "%d", &PARALLEL_DCS) == 0); if (PARALLEL_DCS == 0) printf("DCS is set to connect all found spare paths in %3.2f msec.\n", CROSS_CONNECT_TIME*1000); else if (PARALLEL_DCS == 1) printf("DCS is set to connect one spare path at a time in %3.2f msec.\n", CROSS_CONNECT_TIME*1000); else printf("DCS is set to connect %d spare path at in %3.2f msec.\n", PARALLEL_DCS, CROSS_CONNECT_TIME*1000); find_symbol_def(result, options, "WRITE_LINK"); if (!strcmp(result, NOT_FOUND)) { printf("Propagation delay is calculated using link distance specified in net file\n or using node location when link distance field not present.\n"); OVERWRITE_LINK_DISTANCE = false; } else { OVERWRITE_LINK_DISTANCE = true; printf("Propagation delay is calculated using distance between nodes\n"); } find_symbol_def(result, options, "DEBUG"); if (!strcmp(result, NOT_FOUND)) { printf("DEBUG is set to false\n"); } else { DEBUG = true; printf("DEBUG mode is turned on\n"); } i = (sscanf(find_symbol_def(STR2, options, "STOPTIME="), "%g", &STOP_TIME) == 0); i = (sscanf(find_symbol_def(STR2, options, "LCS="), "%g", &LINK_CHECK_SCALEFACTOR) == 0); i = (sscanf(find_symbol_def(STR2, options, "2INDEX="), "%g", &REFRACINDEX) == 0); printf("Refraction Index is set at %f.\n", REFRACINDEX); i = (sscanf(find_symbol_def(STR2, options, "PPTOVERRIDE="), "%g", &PPTOVERRIDE) == 0); if (PPTOVERRIDE != -1.0) printf("Protocol/Message processing time is overwritten/set to %f.\n", PPTOVERRIDE); i = (sscanf(find_symbol_def(STR2, options, "MSG_LENGTH="), "%d", &MSG_LENGTH) == 0); printf("Message length is set at %d bytes\n", MSG_LENGTH); i = (sscanf(find_symbol_def(result, options, "X_SPEED="), "%d", &TX_SPEED) == 0); printf("Transmission speed is set at %dKbps\n", TX_SPEED); transmit_delay = MSG_LENGTH*8/(TX_SPEED*1000.0); i = (sscanf(find_symbol_def(STR2, options, "NOISE="), "%g", &NOISE_SIZE) == 0); find_symbol_def(outfilename, options, "OUT="); find_symbol_def(infilename, options, "FIRST_PARAM"); log_ = fopen(outfilename, "w"); if (log_ != NULL) /* rewind(log_); */; else log_ = tmpfile(); if (log_ == NULL) _EscIO(FileNotFound); nodename = NULL; if (SaveEvents) set_save_mode(); init_list(&net); init_nodes(infilename); FORLIM = netsize; for (i = 1; i <= FORLIM; i++) { find_symbol_def(result, nodename, int2str_(STR1, i)); if (!strcmp(result, break1str)) break1 = i; if (!strcmp(result, break2str)) break2 = i; } if (break1 == 0) { printf("There is no such node %s in node1 of break specification.\n", break1str); exit(3); } if (break2 == 0) { printf("There is no such node %s in node2 of break specification.\n", break2str); exit(3); } log_network(true); ee = (erec *)Malloc(sizeof(erec)); ee->time = 0.0; ee->src = 0; ee->dst = break2; ee->next = break2; ee->msg = NULL; init_symbol(&ee->msg, "ID", int2str_(STR1, break1)); init_symbol(&ee->msg, "ACTION", "BREAK"); init_symbol(&ee->msg, "TYPE", " SIM"); init_symbol(&ee->msg, "SEQ#", "---"); init_symbol(&ee->msg, "BW", "---"); init_symbol(&ee->msg, "PATH", "INTERNAL FAULT DETECTION"); queue_event(ee); ee = (erec *)Malloc(sizeof(erec)); ee->time = 0.0; ee->src = 0; ee->dst = break1; ee->next = break1; ee->msg = NULL; init_symbol(&ee->msg, "ID", int2str_(STR1, break2)); init_symbol(&ee->msg, "ACTION", "BREAK"); init_symbol(&ee->msg, "TYPE", " SIM"); init_symbol(&ee->msg, "SEQ#", "---"); init_symbol(&ee->msg, "BW", "---"); init_symbol(&ee->msg, "PATH", "INTERNAL FAULT DETECTION"); queue_event(ee); path_count = 0; bw_found = 0; print_flag = true; do { ee = next_event(); if (ee != NULL) { nextnode = (node *)recall(&net, ee->next); sprintf(STR10, "%s %s %s -> %s of Type: %s BW: %s", simtime2str(STR1, ee->time), simtime2str(STR2, bounds(0.0, nextnode->time - ee->time, 1.0e30)), find_symbol_def(STR5, nodename, int2str_(STR4, ee->src)), find_symbol_def(STR6, nodename, int2str_(STR7, ee->next)), find_symbol_def(STR8, ee->msg, "TYPE"), find_symbol_def(STR9, ee->msg, "BW")); /* print event info */ simlog(STR10); /* extract & print path info */ /* find_symbol_def(pathlist, ee->msg, "PATH"); FORLIM = netsize; for (i = 0; i <= FORLIM; i++) strcpy(pathlist, replace_strs(STR10, pathlist, int2str_(STR3, i), find_symbol_def(STR11, nodename, int2str_(STR12, i)))); sprintf(STR10, " by %s", pathlist); simlog(STR10); */ /* do event processing at node */ process(ee, ee->next, nextnode); if (!SaveEvents) { /* release dynamic memeory */ release_all_symbols(&ee->msg); Free(ee); } } else stop = true; } while (!stop); to_lower(STR2, infilename); cp = STR2; while (*cp != '.' && cp < STR2 + strlen(STR2)) cp++; *cp = '\0'; /* got the prefix */ sprintf(STR3, "%s.dat.ls/%s_%scut.l", STR2, break1str, break2str); if (access(STR3, R_OK) == 0) { printf("access file %s\n", STR3); found = true; } else { sprintf(STR3, "%s.dat.ls/%s_%scut.l", STR2, break2str, break1str); printf("access file %s\n", STR3); if (access(STR3, R_OK) == 0) { found = true; } else { found = false; printf("optimal spare usage file not found\n"); } } if (found) { fp = fopen(STR3, "r"); while (fgets(STR4, 255, fp)!=NULL) { sscanf(STR4, "%s", STR5); STR5[24]='\0'; if (strcmp(STR5, "TOTAL_BANDWIDTH_RESTORED") == 0) { sscanf(STR5+25, "%d", &opt_bw_found); printf("optimal bandwidth that can be restored=%d\n", opt_bw_found); fgets(STR4, 255, fp); sscanf(STR4, "%s %d", STR5, &opt_spare_used); printf("optimal spare used =%d\n", opt_spare_used); break; } } sprintf(STR1, "%s-%s %d/%d=%6.2f%% @%f msgs=%d/%d PNE=%d/%d PLE=%d/%d\n", break1str, break2str, bw_found, bw_needed, bw_found*100.0/bw_needed, lastRestoreTime, rstr_msg_count, msg_count, bw_found, opt_bw_found, opt_spare_used, spare_used); } else { sprintf(STR1, "%s-%s %d/%d=%6.2f%% @%f msgs=%d/%d spares=%d\n", break1str, break2str, bw_found, bw_needed, bw_found*100.0/bw_needed, lastRestoreTime, rstr_msg_count, msg_count, spare_used); } printf("%s", STR1); fprintf(stderr, "%s", STR1); fp = fopen("netres.twop.res", "a"); if (fp == NULL) { fprintf(stderr, "can not open netres.twop.res\n"); } fprintf(fp, "%s", STR1); log_network(false); fflush(log_); P_ioresult = 0; if (log_ != NULL) fclose(log_); log_ = NULL; if (log_ != NULL) fclose(log_); exit(0); } /* End. */