int console_init() { int fd; /* Clean up */ ioctl(0, TIOCNOTTY, 0); close(0); close(1); close(2); setsid(); /* Reopen console */ if ((fd = open(_PATH_CONSOLE, O_RDWR)) < 0) { perror(_PATH_CONSOLE); return errno; } dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); ioctl(0, TIOCSCTTY, 1); tcsetpgrp(0, getpgrp()); set_term(0); return 0; }
SCREEN *_terminfo_new_screen(const char *term_type, FILE *out, FILE *in) { SCREEN *_newscr; ggLock(ncurses_lock); if ( term_type == NULL ) { term_type = getenv("TERM"); if ( term_type == NULL ) { term_type = "vt100"; } } { char *temp; temp = (char *)malloc(sizeof(char) * ( strlen(term_type) + 1 )); strcpy(temp, term_type); _newscr = newterm(temp, out, in); free(temp); } if ( _newscr == NULL ) { ggUnlock(ncurses_lock); } else { ncurses_screen = _newscr; set_term(_newscr); start_color(); cbreak(); noecho(); nonl(); timeout(0); meta(stdscr, TRUE); keypad(stdscr, TRUE); } return _newscr; }
static void cleanup(int sig) { /* * Actually, doing any sort of I/O from within an signal handler is * "unsafe". But we'll _try_ to clean up the screen and terminal * settings on the way out. */ if (!_nc_globals.cleanup_nested++ && (sig == SIGINT || sig == SIGQUIT)) { #if HAVE_SIGACTION || HAVE_SIGVEC sigaction_t act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = SIG_IGN; if (sigaction(sig, &act, NULL) == 0) #else if (signal(sig, SIG_IGN) != SIG_ERR) #endif { SCREEN *scan; for (each_screen(scan)) { if (scan->_ofp != 0 && isatty(fileno(scan->_ofp))) { scan->_cleanup = TRUE; scan->_outch = _nc_outch; } set_term(scan); endwin(); if (SP) SP->_endwin = FALSE; /* in case we have an atexit! */ } }
/* Add the IN->OUT mapping to TBL. OUT is potentially stored in the table. IN is used only here, so it need not be kept live afterwards. */ static void add_bytes (struct convtable *tbl, const struct charseq *in, struct charseq *out) { int n = 0; unsigned int byte; assert (in->nbytes > 0); byte = ((unsigned char *) in->bytes)[n]; while (n + 1 < in->nbytes) { if (is_term (tbl, byte) || tbl->val[byte].sub == NULL) { /* Note that we simply ignore a definition for a byte sequence which is also the prefix for a longer one. */ clear_term (tbl, byte); tbl->val[byte].sub = (struct convtable *) xcalloc (1, sizeof (struct convtable)); } tbl = tbl->val[byte].sub; byte = ((unsigned char *) in->bytes)[++n]; } /* Only add the new sequence if there is none yet and the byte sequence is not part of an even longer one. */ if (! is_term (tbl, byte) && tbl->val[byte].sub == NULL) { set_term (tbl, byte); tbl->val[byte].out = out; } }
/** \brief Show help file * * Read 'help.txt' and display it via 'less'. * Local 'help.txt' in actual directory overrides default file * in PKG_DATA_DIR */ int show_help(void) { int rc; char filename[] = "help.txt"; char *helpfile; char *cmdstr; if (g_access(filename, R_OK) == 0) { helpfile = g_strdup(filename); } else { helpfile = g_strconcat(PACKAGE_DATA_DIR, G_DIR_SEPARATOR_S, filename, NULL); if (g_access(helpfile, R_OK) != 0) { g_free(helpfile); return -1; } } cmdstr = g_strdup_printf("less %s", helpfile); endwin(); rc=system("clear"); rc=system(cmdstr); rc=system("clear"); g_free(helpfile); g_free(cmdstr); set_term(mainscreen); clear_display(); return 0; }
static int console_init(void) { int fd; /* Clean up */ ioctl(0, TIOCNOTTY, 0); close(0); close(1); close(2); setsid(); /* Reopen console */ if ((fd = open(_PATH_CONSOLE, O_RDWR)) < 0) { /* Avoid debug messages is redirected to socket packet if no exist a UART chip, added by honor, 2003-12-04 */ open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); perror(_PATH_CONSOLE); return errno; } dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); ioctl(0, TIOCSCTTY, 1); tcsetpgrp(0, getpgrp()); set_term(0); return 0; }
void split_open(void) { int i; #if DEBUG printf("split_open()\n"); #endif LineCount = -1; for (i=0; i<MAX_LINE_COUNT; i++) { strcpy(Lines[i], ""); } #ifndef NO_CURSES FILE *stdout2 = fopen("/dev/tty", "w"); if (!stdout2) fprintf(stderr, "split_open(): fopen() failed\n"); else { SCREEN *screen; if ((screen = newterm(NULL, stdout2, stdin))) { set_term(screen); raw(); noecho(); } else fprintf(stderr, "split_open(): newterm() failed\n"); } #endif }
static void cleanup(int sig) { /* * Actually, doing any sort of I/O from within an signal handler is * "unsafe". But we'll _try_ to clean up the screen and terminal * settings on the way out. */ if (sig == SIGINT || sig == SIGQUIT) { #if HAVE_SIGACTION || HAVE_SIGVEC sigaction_t act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = SIG_IGN; if (sigaction(sig, &act, (sigaction_t *)0) == 0) #else if (signal(sig, SIG_IGN) != SIG_ERR) #endif { SCREEN *scan = _nc_screen_chain; while(scan) { set_term(scan); endwin(); SP->_endwin = FALSE; /* in case we have an atexit! */ scan = scan->_next_screen; } } } exit(EXIT_FAILURE); }
/* * initscr -- * Initialize the current and standard screen. */ WINDOW * initscr(void) { const char *sp; /* * If My_term is set, or can't find a terminal in the environment, * use Def_term. */ if (My_term || (sp = getenv("TERM")) == NULL) sp = Def_term; /* LINTED const castaway; newterm does not modify sp! */ if ((_cursesi_screen = newterm((char *) sp, stdout, stdin)) == NULL) return NULL; __echoit = _cursesi_screen->echoit; __pfast = _cursesi_screen->pfast; __rawmode = _cursesi_screen->rawmode; __noqch = _cursesi_screen->noqch; COLS = _cursesi_screen->COLS; LINES = _cursesi_screen->LINES; COLORS = _cursesi_screen->COLORS; COLOR_PAIRS = _cursesi_screen->COLOR_PAIRS; __GT = _cursesi_screen->GT; __NONL = _cursesi_screen->NONL; __UPPERCASE = _cursesi_screen->UPPERCASE; set_term(_cursesi_screen); wrefresh(curscr); return (stdscr); }
/* * Allocates and initializes a new Screen. */ Screen *ScreenInit(Model *model) { const char *tty = "/dev/tty"; const char *term_type = 0; Screen *self = pg_malloc(sizeof(Screen)); memset(self, 0, sizeof(Screen)); self->model = model; memset(&self->key, 0, sizeof(Row)); /* * Open /dev/tty and set that up as the ncurses terminal. We use newterm * instead of initscr so that we can read row events from stdin. */ term_type = getenv("TERM"); if (term_type == NULL || *term_type == '\0') { term_type = "unknown"; } self->term_in = fopen(tty, "r"); if (self->term_in == NULL) { FATAL_ERROR("could not open %s", tty); } self->fd = fileno(self->term_in); self->nterm = newterm(term_type, stdout, self->term_in); set_term(self->nterm); /* make ncurses non blocking */ timeout(0); /* clear the tty internal state */ clear(); /* disable character echo */ noecho(); /* disable input line buffering */ cbreak(); /* hide cursor */ curs_set(0); /* enable extra keys */ keypad(stdscr, TRUE); /* updates the screen (should be blank now) */ refresh(); self->x_pos = 0; self->x_col = 0; self->pause = 0; return self; }
void _terminfo_select_screen(SCREEN *scr) { ggLock(ncurses_lock); if ( ncurses_screen != scr ) { set_term(scr); ncurses_screen = scr; } }
void handle_sigcont(int sig) { if (sig == SIGCONT) ft_init(); else { set_term(ft_glob(NULL)->sauv); signal(SIGTSTP, SIG_DFL); } }
static PyObject* py_set_term(PyObject *self, PyObject *args){ SCREEN *screen; if (!PyArg_ParseTuple(args, "l", &screen)) return NULL; Py_BEGIN_ALLOW_THREADS screen = set_term(screen); Py_END_ALLOW_THREADS return PyLong_FromVoidPtr(screen); }
static void setup_ncurses() { SCREEN* main_screen = newterm(term_type, stdout, term_in); set_term(main_screen); scrollok(stdscr, TRUE); // If enabled the window is scrolled up one line when reaching bottom idlok(stdscr, TRUE); // Use the hardware insert/delete line feature of terminals so equipped ncurses_active = TRUE; //printf("\t\t\t\t\tncurses set up.\n"); if (signal(SIGWINCH, catch_sigwinch) == SIG_ERR) { fputs("\t\t\t\t\tAn error occurred when setting up SIGWINCH signal handler.\n", stderr); } } // Done setting up ncurses
struct data_t *handle_request_vote(struct data_t *params[], int nparams, char **err, void *data) { struct server_context_t *s = (struct server_context_t *)data; struct request_vote_input_t *input = get_request_vote_input_params(params, nparams); if(!input) { *err = u_strdup("error while parsing input parameters"); log_fatal_and_exit(s, "RequestVote: error while parsing input parameters"); return NULL; } struct request_vote_output_t output; if(input->term < s->current_term) { //candidate has older term hence reject request` output.term = s->current_term; output.vote_granted = 0; } else { if(s->last_entry && (input->last_log_term < s->last_entry->term || (input->last_log_term == s->last_entry->term && input->last_log_index < s->last_entry->index))) { //candidate log is not up-to-date $5.4.1 //candidate is not up-to-date if its last //logs term is older or if they are equal //then this server has longer log output.term = s->current_term; output.vote_granted = 0; } else { if(input->term > s->current_term) { set_term(s, input->term); s->voted_for = input->candidate_id; save_state(s); output.term = s->current_term; output.vote_granted = 1; } else if(s->voted_for == 0) { //terms are equal mark the candidate //and this server didnt vote in this //election s->voted_for = input->candidate_id; save_state(s); output.term = s->current_term; output.vote_granted = 1; } else { //candidate has already voted in this term output.term = input->term; output.vote_granted = 0; } } } free(input); return make_request_vote_rpc_response(&output); }
use_screen(SCREEN *screen, NCURSES_SCREEN_CB func, void *data) { SCREEN *save_SP; int code = OK; T((T_CALLED("use_screen(%p,%p,%p)"), screen, func, data)); /* * FIXME - add a flag so a given thread can check if _it_ has already * recurred through this point, return an error if so. */ _nc_lock_global(curses); save_SP = SP; set_term(screen); code = func(screen, data); set_term(save_SP); _nc_unlock_global(curses); returnCode(code); }
Nscreen::Nscreen(){ //default constructor uses stdin and out this->numwindows = 1; scrptr = newterm("xterm",stdin,stdout); set_term(scrptr); getmaxyx(stdscr,MAX_Y, MAX_X); start_color(); init_pair(1,COLOR_WHITE,COLOR_BLUE); init_windows(); cw=0; }
static void request_vote_cb(struct data_t *result, char *err, void *data) { struct server_context_t *s = (struct server_context_t *)data; if(err) { //what should we do with bysentine errors? //LOG: fatal error. TODO: exit? return; } if(s->state != CANDIDATE) { return; } struct request_vote_output_t *vote = get_request_vote_output(result); if(!vote) { log_fatal_and_exit(s, "RequestVoteCallback: Response parsing failed"); return; } int pair_vote = vote->vote_granted; uint64_t pair_term = vote->term; free(vote); if(pair_vote && pair_term == s->current_term && s->state == CANDIDATE) { s->current_votes++; } else { if(pair_term > s->current_term) { set_term(s, pair_term); s->voted_for = 0; save_state(s); } return; } int votes_needed = s->quoram_size/2 + 1; if(s->current_votes == votes_needed) { s->state = LEADER; s->current_leader = s->id; DBG_LOG(LOG_INFO, "[%s][%d] Server is elected as the leader", ss[s->state], s->current_term); save_state(s); //reset timer such that election timeout does not occur //and heartbeat timeout occurs reset_timers(s, false, true); for(int i = 0; i < s->quoram_size - 1; i++) { if(s->last_entry) { s->next_index[i] = s->last_entry->index + 1; } else { s->next_index[i] = 1; } s->match_index[i] = 0; } send_heartbeat(s); } }
char init_window(t_wrk *wrk) { if ((wrk->screen = newterm(NULL, stderr, stdin)) == NULL) return (1); set_term(wrk->screen); wrk->selecta = 0; curs_set(0); keypad(stdscr, TRUE); wrk->arg->cursor = 1; wrk->cur = wrk->arg; wrk->x = 0; wrk->y = 0; wrk->pos = 0; return (0); }
int main(void) { SCREEN *s; s = newterm(NULL, stdout, stdin); set_term(s); addstr("Hello!"); refresh(); getch(); endwin(); return 0; }
void packet_init() { if (nopacket == 1) packetinterface = 0; set_term(mainscreen); // really needed? refreshp(); if ((nopacket == 0) && (packetinterface != 0)) { if (init_packet() == 0) packet(); else cleanup_telnet(); } }
static void cleanup(int sig) { /* * XXX signal race. * * 1) Walking the SCREEN list is unsafe, since all list management * is done without any signal blocking. * 2) On systems which have REENTRANT turned on, set_term() uses * _nc_lock_global() which could deadlock or misbehave in other ways. * 3) endwin() calls all sorts of stuff, many of which use stdio or * other library functions which are clearly unsafe. * 4) The comment about atexit() is wrong. atexit() should never be * called, because ... * 5) The call to exit() at the bottom is unsafe: exit() depends * depends on stdio being coherent (obviously it is not). stdio * could call free(), and also calls atexit() and dtor handlers, * which are probably not written to be safe. The signal handler * should be calling _exit(). */ if (!_nc_globals.cleanup_nested++ && (sig == SIGINT || sig == SIGQUIT)) { #if HAVE_SIGACTION || HAVE_SIGVEC sigaction_t act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = SIG_IGN; if (sigaction(sig, &act, NULL) == 0) #else if (signal(sig, SIG_IGN) != SIG_ERR) #endif { SCREEN *scan; for (each_screen(scan)) { if (scan->_ofp != 0 && isatty(fileno(scan->_ofp))) { scan->_cleanup = TRUE; scan->_outch = _nc_outch; } set_term(scan); endwin(); if (SP) SP->_endwin = FALSE; /* in case we have an atexit! */ } }
bool nCurse::Activate() { if (running) refresh(); else { s = newterm((char *) 0,stdout,stdin); if (s != NULL) { set_term(s); width = COLS; height = LINES; curs_set(0); //uncomment it to get rid of the cursor noecho(); cbreak();// Line buffering disabled. pass on everything nodelay(stdscr,1); keypad(stdscr, TRUE); running = true; } } return running; }
// setup void setup() { fdfile = fopen("/dev/lft0", "r+"); fullScreen=newterm("linux", fdfile, fdfile); set_term(fullScreen); simWin = newwin(SIMWINHEIGHT, 400, ySimPos, xSimPos); scrollok(simWin, TRUE); waddstr(simWin, "** Hang on a sec... just waiting for the uvm boat anchor demo to compile\n"); wmove(simWin, ++ySimPos, xSimPos); waddstr(simWin, "** and start running. You'll see something happen shortly...\n\n"); wmove(simWin, ++ySimPos, xSimPos); wrefresh(simWin); guiWin = newwin(GUIWINHEIGHT, 400, SIMWINHEIGHT+1, xSimPos); boat_anchor.setWindow(guiWin); boat_anchor.startingScene(); wrefresh(guiWin); }
int vdk_screen_resume(vdk_screen_t *screen) { int raster_type; if(screen == NULL) return -1; raster_type = vdk_object_get_raster_type(VDK_OBJECT(screen)); if(raster_type != VDK_RASTER_SCR) return -1; // check to see if screen is already active if(!(screen->state & VDK_SCREEN_PAUSED)) return -1; screen->state &= ~VDK_SCREEN_PAUSED; set_term(*(SCREEN**)screen); refresh(); _vdk_screen_update_metrics(VDK_OBJECT(screen)); return 0; }
int main(void) { FILE *termin,*termout; SCREEN *tp1,*tp2; char name[81]; /* Open terminal one for reading Open terminal two for writing */ termin = fopen(INTERM,"r"); termout = fopen(OUTTERM,"w"); if( termin==NULL || termout==NULL ) { puts("Unable to open terminal."); return(1); } /* set up the new terminal in NCurses */ tp2 = newterm(NULL,termout,termin); if( tp2 == NULL) { puts("Unable to open terminal window."); return(2); } /* NCurses is now started for the new terminal */ tp1 = set_term(tp2); printw("Welcome to Curses output on terminal %s.\n",OUTTERM); printw("You can type on terminal %s, and see it here.\n",INTERM); addstr("What is your name: "); refresh(); getnstr(name,80); printw("%s, glad to have you aboard!",name); refresh(); getch(); endwin(); return 0; }
static int _vdk_screen_dtor(vdk_object_t *object) { vdk_raster_t *raster; int raster_type; int retval; if(object == NULL) return -1; raster_type = vdk_object_get_raster_type(VDK_OBJECT(object)); if(raster_type != VDK_RASTER_SCR) return -1; raster = VDK_RASTER(object); // in order to tear down the screen it must first be activated set_term(raster->primitive.screen); endwin(); delscreen(raster->primitive.screen); // call the parent klass destructor retval = VDK_OBJECT(VDK_CONTEXT_KLASS)->dtor(object); return retval; }
/** * Ncurses Text User Interface * open_ncurses - open text window * close_ncurses - close text window */ int open_ncurses() { #ifdef HAVE_LIBNCURSESW int debug = 1; FILE *in = fopen( "/dev/stderr", "r" ); FILE *out = fopen( "/dev/stderr", "w" ); int terminal_x = 0; int terminal_y = 0; ptclscr = newterm(NULL, out, in); refresh(); if (!ptclscr) log_mesg(0, 1, 1, debug, "partclone ncurses initial error\n"); if (!set_term(ptclscr)) log_mesg(0, 1, 1, debug, "partclone ncurses set term error\n"); ptclscr_win = newwin(LINES, COLS, 0, 0); // check terminal width and height getmaxyx(ptclscr_win, terminal_y, terminal_x); // set window position int log_line = 12; int log_row = 60; int log_y_pos = (terminal_y-24)/2+2; int log_x_pos = (terminal_x-log_row)/2; int gap = 0; int p_line = 8; int p_row = log_row; int p_y_pos = log_y_pos+log_line+gap; int p_x_pos = log_x_pos; int size_ok = 1; if (terminal_y < (log_line+gap+p_line+3)) size_ok = 0; if (terminal_x < (log_row+2)) size_ok = 0; if (size_ok == 0) { log_mesg(0, 0, 0, debug, "Terminal width(%i) or height(%i) too small\n", terminal_x, terminal_y); return 0; } /// check color pair if (!has_colors()) { log_mesg(0, 0, 0, debug, "Terminal color error\n"); return 0; } if (start_color() != OK){ log_mesg(0, 0, 0, debug, "Terminal can't start color mode\n"); return 0; } /// define color init_pair(1, COLOR_WHITE, COLOR_BLUE); ///stdscr init_pair(2, COLOR_RED, COLOR_WHITE); ///sub window init_pair(3, COLOR_BLUE, COLOR_WHITE); ///sub window /// write background color bkgd(COLOR_PAIR(1)); wbkgd(ptclscr_win,COLOR_PAIR(2)); touchwin(ptclscr_win); refresh(); /// init main box attrset(COLOR_PAIR(2)); box_win = subwin(ptclscr_win, (log_line+gap+p_line+2), log_row+2, log_y_pos-1, log_x_pos-1); box(box_win, ACS_VLINE, ACS_HLINE); wrefresh(box_win); wbkgd(box_win, COLOR_PAIR(2)); mvprintw((log_y_pos-1), ((terminal_x-9)/2), " Partclone "); attroff(COLOR_PAIR(2)); attrset(COLOR_PAIR(3)); /// init log window log_win = subwin(ptclscr_win, log_line, log_row, log_y_pos, log_x_pos); wbkgd(log_win, COLOR_PAIR(3)); touchwin(log_win); refresh(); // init progress window p_win = subwin(ptclscr_win, p_line, p_row, p_y_pos, p_x_pos); wbkgd(p_win, COLOR_PAIR(3)); touchwin(p_win); refresh(); // init progress window bar_win = subwin(ptclscr_win, 1, p_row-10, p_y_pos+4, p_x_pos); wbkgd(bar_win, COLOR_PAIR(1)); touchwin(bar_win); refresh(); // init total block progress window tbar_win = subwin(ptclscr_win, 1, p_row-10, p_y_pos+7, p_x_pos); wbkgd(tbar_win, COLOR_PAIR(1)); touchwin(tbar_win); refresh(); scrollok(log_win, TRUE); if (touchwin(ptclscr_win) == ERR) return 0; refresh(); #endif return 1; }
static void election_timeout_callback(int fd, short event, void *arg) { struct server_context_t *s = (struct server_context_t *)arg; if(event & EV_TIMEOUT) { DBG_LOG(LOG_INFO, "[%s][%d] election timeout occurred", ss[s->state], s->current_term); //election timeout occurred -- do the candidate activities s->state = CANDIDATE; s->current_leader = -1; s->voted_for = s->id; s->current_term++; save_state(s); s->current_votes = 1; //reset the previous election timer and add new one such that //if split vote occurs we have one more election reset_timers(s, true, false); //check if quoram_size already equal to required majoriy int votes_needed = s->quoram_size/2 + 1; if(votes_needed == s->current_votes) { s->state = LEADER; s->current_leader = s->id; save_state(s); } else { //send RequestVote RPC to pairs struct request_vote_input_t *input = (struct request_vote_input_t *) malloc(sizeof(struct request_vote_input_t)); if(!input) { set_term(s, s->current_term - 1); return; } input->term = s->current_term; input->candidate_id = s->id; if(s->last_entry) { input->last_log_index = s->last_entry->index; input->last_log_term = s->last_entry->term; } else { input->last_log_index = 0; input->last_log_term = 0; } struct method_t *rpc = make_request_vote_rpc_method(input); if(!rpc) { free(input); set_term(s, s->current_term - 1); return; } for(int i = 0; i < s->quoram_size - 1; i++) { if(rpc_call(s->rpc_c, s->peers[i]->dest, rpc, request_vote_cb, s)) { //just log warning, as peers might go down DBG_LOG(LOG_WARN, "[%s][%d] RPC call failed for peer %d", ss[s->state], s->current_term, s->peers[i]->id); } } free(input); free_method_t(rpc); } //end else-if } }
static void append_entries_cb(struct data_t *result, char *err, void *data) { /* TODO: why we need to create and then free the data, cant we just * reuse the slots, especially in case of heartbeat message? */ struct append_entries_cb_data_t *cb_data = (struct append_entries_cb_data_t *)data; struct server_context_t *s = cb_data->s; int peer_index = cb_data->index; uint64_t first_index = cb_data->first_index; uint64_t last_index = cb_data->last_index; free(cb_data); if(err) { //LOG: fatal error. TODO: exit? DBG_LOG(LOG_DEBUG, "[%s][%d] FAIL append_entries_cb from peer_id = %d with err = %s" , ss[s->state], s->current_term, peer_index, err); return; } struct append_entries_output_t *res = get_append_entries_output(result); if(!res) { log_fatal_and_exit(s, "AppendEntriesCallback: Response parsing failed"); return; } uint64_t pair_term = res->term; int pair_success = res->success; free(res); if(pair_term > s->current_term) { set_term(s, pair_term); s->voted_for = 0; save_state(s); return; } if(s->state != LEADER) { return; } if(!pair_success) { DBG_LOG(LOG_DEBUG, "[%s][%d] FAIL append_entries_cb from peer_id = %d" , ss[s->state], s->current_term, peer_index); //TODO: send the client prev entry s->next_index[peer_index] = first_index - 1; } else { DBG_LOG(LOG_DEBUG, "[%s][%d] OK append_entries_cb from peer_id = %d" , ss[s->state], s->current_term, peer_index); s->next_index[peer_index] = last_index + 1; s->match_index[peer_index] = last_index; //If there exists an N such that N > commitIndex, a majority //of matchIndex[i] ≥ N, and log[N].term == currentTerm: //set commitIndex = N (§5.3, §5.4). if(s->match_index[peer_index] > s->commit_index) { int nOK[s->quoram_size - 1]; for(int i = 0; i < s->quoram_size - 1; i++) { nOK[i] = 0; } for(int i = 0; i < s->quoram_size - 1; i++) { for(int j = 0; j < s->quoram_size - 1; j++) { if(s->match_index[i] <= s->match_index[j]) { nOK[i]++; } } } int majority = (s->quoram_size/2); uint64_t N = s->commit_index; int minOKs = s->quoram_size; for(int i = 0; i < s->quoram_size - 1; i++) { if(nOK[i] >= majority && nOK[i] < minOKs) { minOKs = nOK[i]; if(s->match_index[i] > N) { N = s->match_index[i]; } } } if(N > s->commit_index) { struct log_entry_t *entryN = get_log_entry_at(s->log, N); //never commit entry from previous term (§5.4.2) if(entryN && (entryN->term == s->current_term)) { s->commit_index = N; commit_unapplied_entries(s, N); } } } } if(s->last_entry && s->last_entry->index >= s->next_index[peer_index]) { //send all the entries since next_index till some threshold //to this server if(send_append_entries(s, s->next_index[peer_index], peer_index)) { //LOG: fatal error. TODO: exit? } } }