void check_arguments() { if (oj_solution.sid == 0) { FM_LOG_FATAL("Miss parameter: solution id"); exit(EXIT_MISS_PARAM); } if (oj_solution.pid == 0) { FM_LOG_FATAL("Miss parameter: problem id"); exit(EXIT_MISS_PARAM); } if (strlen(data_dir_root) == 0) { FM_LOG_FATAL("Miss parameter: data directory"); exit(EXIT_MISS_PARAM); } switch (oj_solution.lang) { case LANG_C99: case LANG_C11: case LANG_CPP98: case LANG_CPP11: case LANG_CPP14: case LANG_CPP17: case LANG_PASCAL: case LANG_JAVA: case LANG_PYTHON27: case LANG_PYTHON3: case LANG_KOTLIN: break; default: FM_LOG_FATAL("Unknown language id: %d", oj_solution.lang); exit(EXIT_BAD_PARAM); } }
void set_compile_limit() { if (oj_solution.lang == LANG_JAVA || oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3 || oj_solution.lang == LANG_KOTLIN) return; rlimit lim{}; lim.rlim_cur = lim.rlim_max = compile_time_limit / 1000; if (setrlimit(RLIMIT_CPU, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_CPU failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } if (EXIT_SUCCESS != malarm(ITIMER_REAL, compile_time_limit)) { FM_LOG_FATAL("malarm for compiler failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } lim.rlim_cur = lim.rlim_max = compile_memory_limit * STD_MB; if (setrlimit(RLIMIT_AS, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_AS failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } lim.rlim_cur = lim.rlim_max = compile_fsize_limit * STD_MB; if (setrlimit(RLIMIT_FSIZE, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_FSIZE failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } FM_LOG_DEBUG("set compile limit ok"); }
// Run spj int oj_compare_output_spj(const char *file_in, // std input file const char *file_out, // std output file const char *file_user, // user output file const char *spj_exec) // path of spj { FM_LOG_TRACE("start compare spj"); pid_t pid_spj = fork(); // create a child process for spj if (pid_spj < 0) { FM_LOG_FATAL("fork for spj failed: %s", strerror(errno)); exit(EXIT_COMPARE_SPJ); } else if (pid_spj == 0) { // child process log_add_info("spj"); // Set spj timeout if (EXIT_SUCCESS == malarm(ITIMER_REAL, spj_time_limit)) { FM_LOG_TRACE("load spj: %s", spj_exec); execlp(spj_exec, spj_exec, file_in, file_out, file_user, NULL); FM_LOG_FATAL("execute spj failed"); exit(EXIT_COMPARE_SPJ_FORK); } else { FM_LOG_FATAL("malarm for spj failed: %s", strerror(errno)); exit(EXIT_COMPARE_SPJ); } } else { int status = 0; if (waitpid(pid_spj, &status, 0) < 0) { FM_LOG_FATAL("waitpid for spj failed: %s", strerror(errno)); exit(EXIT_COMPARE_SPJ); } if (WIFEXITED(status)) { switch (WEXITSTATUS(status)) { case SPJ_AC: return OJ_AC; case SPJ_PE: return OJ_PE; case SPJ_WA: return OJ_WA; default: return OJ_VE; } } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGALRM) { // recv SIGNALRM FM_LOG_WARNING("spj: time out"); } else { // spj RE FM_LOG_WARNING("unkown termination, status = %d", status); } } return OJ_VE; }
int main(int argc, char *argv[]) { log_open("./core_log.txt"); //或许写成参数更好,懒得写了 atexit(output_result); //退出程序时的回调函数,用于输出判题结果 //为了构建沙盒,必须要有root权限 if (geteuid() != 0) { FM_LOG_FATAL("You must run this program as root."); exit(JUDGE_CONF::EXIT_UNPRIVILEGED); } parse_arguments(argc, argv); JUDGE_CONF::JUDGE_TIME_LIMIT += PROBLEM::time_limit; if (EXIT_SUCCESS != malarm(ITIMER_REAL, JUDGE_CONF::JUDGE_TIME_LIMIT)) { FM_LOG_WARNING("Set the alarm for this judge program failed, %d: %s", errno, strerror(errno)); exit(JUDGE_CONF::EXIT_VERY_FIRST); } signal(SIGALRM, timeout); compiler_source_code(); judge(); if (PROBLEM::spj) { run_spj(); } else { if (PROBLEM::result == JUDGE_CONF::SE) PROBLEM::result = compare_output(PROBLEM::output_file, PROBLEM::exec_output); } return 0; }
/* fmPlatformCfgSchedulerGetTokenList * \ingroup intPlatform * * \desc Configure the scheduler token list for manual mode based * on the given switch. * * \param[in] sw is the switch on which to operate. * * \param[out] schedTokenList is a pointer to the caller-supplied * scheduler token list structure and should be filled * with the scheduler properties of the specified switch. * Refer to fm_schedulerToken for details on the limits * of certains structure fields and which fields * are required. * * \return the number of tokens configured in the schedTokenList. * \return 0 if no configuration token were found in the properties. * *****************************************************************************/ fm_int fmPlatformCfgSchedulerGetTokenList(fm_int sw, fm_schedulerToken *schedTokenList) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "No support for scheduler manual mode\n"); FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, 0); } /* end fmPlatformCfgSchedulerGetTokenList */
void io_redirect(const char *input_file, const char *stdout_file, const char *stderr_file) { // io_redirect stdin = freopen(input_file, "r", stdin); stdout = freopen(stdout_file, "w", stdout); stderr = freopen(stderr_file, "a+", stderr); if (stdin == nullptr || stdout == nullptr || stderr == nullptr) { FM_LOG_FATAL("error freopen: stdin(%p) stdout(%p), stderr(%p)", stdin, stdout, stderr); exit(EXIT_PRE_JUDGE); } FM_LOG_TRACE("io redirect ok!"); }
int main(int argc, char *argv[], char *envp[]) { if (nice(10) == -1) { // increase nice value(decrease pripority) FM_LOG_WARNING("increase nice value failed: %s", strerror(errno)); } init(); parse_arguments(argc, argv); if (geteuid() == 0) { // effective user is not root FM_LOG_FATAL("please do not run as root, run as judge"); exit(EXIT_PRIVILEGED); } if (EXIT_SUCCESS != chdir(oj_solution.work_dir)) { // change current directory FM_LOG_FATAL("chdir(%s) failed: %s", oj_solution.work_dir, strerror(errno)); exit(EXIT_CHDIR); } FM_LOG_DEBUG("\n\x1b[31m----- Power Judge 1.0 -----\x1b[0m"); judge_time_limit += oj_solution.time_limit; judge_time_limit *= get_num_of_test(); if (EXIT_SUCCESS != malarm(ITIMER_REAL, judge_time_limit)) { FM_LOG_FATAL("set alarm for judge failed: %s", strerror(errno)); exit(EXIT_VERY_FIRST); } if (signal(SIGALRM, timeout_hander) == SIG_ERR) { // install signal hander for timeout FM_LOG_FATAL("cannot handle SIGALRM"); exit(EXIT_VERY_FIRST); } init_connet(); compile(); run_solution(); close_connet(); return 0; }
void set_security_option() { if (oj_solution.lang != LANG_JAVA && oj_solution.lang != LANG_KOTLIN #ifdef FAST_JUDGE && oj_solution.lang != LANG_PYTHON3 && oj_solution.lang != LANG_PYTHON27 #endif ) { char cwd[PATH_SIZE]; char *tmp = getcwd(cwd, PATH_SIZE - 1); if (tmp == nullptr) { FM_LOG_FATAL("getcwd failed: %s", strerror(errno)); exit(EXIT_SET_SECURITY); } // chroot, current directory will be the root dir if (EXIT_SUCCESS != chroot(cwd)) { FM_LOG_FATAL("chroot(%s) failed: %s", cwd, strerror(errno)); exit(EXIT_SET_SECURITY); } FM_LOG_DEBUG("chroot(%s)", cwd); } FM_LOG_TRACE("set_security_option ok"); }
void set_limit(off_t fsize) { rlimit lim{}; // Set CPU time limit round up, raise SIGXCPU lim.rlim_max = (oj_solution.time_limit + 999) / 1000 + 1; lim.rlim_cur = lim.rlim_max; if (setrlimit(RLIMIT_CPU, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_CPU failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } if (oj_solution.lang <= LANG_PASCAL) { // Memory control, raise SIGSEGV lim.rlim_cur = lim.rlim_max = (STD_MB << 10) + oj_solution.memory_limit * STD_KB; if (setrlimit(RLIMIT_AS, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_AS failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } } // Stack space, raise SIGSEGV lim.rlim_cur = lim.rlim_max = stack_size_limit * STD_KB; if (setrlimit(RLIMIT_STACK, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_STACK failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } // Output file size limit, raise SIGXFSZ lim.rlim_cur = lim.rlim_max = (rlim_t) (4 * MAX_LOG_FILE_SIZE); if (setrlimit(RLIMIT_FSIZE, &lim) < 0) { FM_LOG_FATAL("setrlimit RLIMIT_FSIZE failed: %s", strerror(errno)); exit(EXIT_SET_LIMIT); } FM_LOG_DEBUG("File size limit: %d", lim.rlim_max); FM_LOG_TRACE("set execute limit ok"); }
void check_pid() { pid_t otherpid; FM_LOG_NOTICE("pid file: %s", PID_FILE); pfh = pidfile_open(PID_FILE, 0644, &otherpid); if (pfh == nullptr) { if (errno == EEXIST) { FM_LOG_FATAL("Daemon already running, pid: %jd", (intmax_t) otherpid); exit(EXIT_FAILURE); } /* If we cannot create pidfile from other reasons, only warn. */ FM_LOG_WARNING("Cannot open or create pidfile"); } }
int get_num_of_test() { struct dirent **namelist; int num_of_test; num_of_test = scandir(oj_solution.data_dir, &namelist, data_filter, alphasort); if (num_of_test < 0) { FM_LOG_FATAL("scan data directory failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_DAA); } for (int i = 0; i < num_of_test; ++i) { free(namelist[i]); } free(namelist); return num_of_test; }
/* fmPlatformGetSchedulerConfigMode * \ingroup intPlatform * * \desc Get the scheduler configuration mode for the given switch. * * \param[in] sw is the switch on which to operate. * * \return the scheduler configuration mode for the specified switch. * *****************************************************************************/ fm_schedulerConfigMode fmPlatformGetSchedulerConfigMode(fm_int sw) { fm_platformCfgSwitch *swCfg; swCfg = FM_PLAT_GET_SWITCH_CFG(sw); if (swCfg->schedListSelect == FM_AAD_API_PLATFORM_SCHED_LIST_SELECT) { return (FM_SCHED_INIT_MODE_AUTOMATIC); } else { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "No support for scheduler manual mode\n"); return (FM_SCHED_INIT_MODE_MANUAL); } } /* end fmPlatformGetSchedulerConfigMode */
/** fm10000FastMaintenanceTask * \ingroup intFastMaint * * \desc Chip-specific fast maintenance thread. * * \note The caller has ensured that the switch is UP and has * taken the switch protection lock. * * \param[in] sw is the switch on which to operate * * \param[in] args is the thread argument pointer. * * \return None. * *****************************************************************************/ void * fm10000FastMaintenanceTask(fm_int sw, void *args) { fm_status err; FM_NOT_USED(args); fm10000MacUsedTableSweeper(sw); err = fm10000MTablePeriodicMaintenance(sw); if (err != FM_OK) { FM_LOG_FATAL(FM_LOG_CAT_EVENT_FAST_MAINT, "MTableMaintenance returned error: %s\n" , fmErrorMsg(err)); } return NULL; } /* end fm10000FastMaintenanceTask */
/** fmSendParityErrorEvent * \ingroup intParity * * \desc Send a Parity error event to the upper layer. * * \param[in] sw is the switch on which to operate. * * \param[in] parityEvent contains the parity event error information. * * \param[in] eventHandler points to the event handler to which the * parity event should be sent. * * \return Should never exit. * *****************************************************************************/ fm_status fmSendParityErrorEvent(fm_int sw, fm_eventParityError parityEvent, fm_thread * eventHandler) { fm_status err; fm_event * eventPtr; fm_eventParityError *parityErrEvent; FM_LOG_ENTRY(FM_LOG_CAT_PARITY, "sw=%d ParityEvent=%p\n", sw, (void *) &parityEvent); eventPtr = fmAllocateEvent(sw, FM_EVID_SYSTEM, FM_EVENT_PARITY_ERROR, FM_EVENT_PRIORITY_LOW); if (eventPtr == NULL) { FM_LOG_FATAL(FM_LOG_CAT_PARITY, "Out of event buffers\n"); FM_LOG_EXIT(FM_LOG_CAT_PARITY, FM_ERR_NO_EVENTS_AVAILABLE); } /* Init event structure */ parityErrEvent = &eventPtr->info.fpParityErrorEvent; FM_MEMCPY_S( parityErrEvent, sizeof(*parityErrEvent), &parityEvent, sizeof(parityEvent) ); err = fmSendThreadEvent(eventHandler, eventPtr); if (err != FM_OK) { /* Free the event since we could not send it to thread */ fmReleaseEvent(eventPtr); } FM_LOG_EXIT(FM_LOG_CAT_PARITY, err); } /* end fmSendParityErrorEvent */
bool judge(const char *input_file, const char *output_file_std, const char *stdout_file_executive, const char *stderr_file_executive) { rusage rused{}; pid_t executor = fork(); // create a child process for executor if (executor < 0) { FM_LOG_FATAL("fork executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } else if (executor == 0) { // child process log_add_info("executor"); off_t fsize = file_size(output_file_std); // io redirect, must before set_security_option() io_redirect(input_file, stdout_file_executive, stderr_file_executive); // chroot & setuid set_security_option(); // set memory, time and file size limit etc. set_limit(fsize); // must after set_security_option() FM_LOG_DEBUG("time limit: %d, time limit addtion: %d", oj_solution.time_limit, time_limit_addtion); uint64_t real_time_limit = oj_solution.time_limit + time_limit_addtion; // time fix // set real time alarm if (EXIT_SUCCESS != malarm(ITIMER_REAL, real_time_limit)) { FM_LOG_FATAL("malarm for executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } FM_LOG_TRACE("begin execute"); if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { FM_LOG_FATAL("Trace executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_PTRACE); } // load program if (oj_solution.lang == LANG_JAVA) { print_executor(EXEC_J); execvp(EXEC_J[0], (char *const *) EXEC_J); } else if (oj_solution.lang == LANG_KOTLIN) { print_executor(EXEC_KT); execvp(EXEC_KT[0], (char *const *) EXEC_KT); } else if (oj_solution.lang == LANG_PYTHON27) { print_executor(EXEC_PY27); #ifdef FAST_JUDGE execvp(EXEC_PY27[0], (char * const *) EXEC_PY27); #else execv(EXEC_PY27[0], (char *const *) EXEC_PY27); #endif } else if (oj_solution.lang == LANG_PYTHON3) { print_executor(EXEC_PY3); #ifdef FAST_JUDGE execvp(EXEC_PY3[0], (char * const *) EXEC_PY3); #else execv(EXEC_PY3[0], (char *const *) EXEC_PY3); #endif } else { execl("./Main", "./Main", NULL); } // exec error FM_LOG_FATAL("exec error"); exit(EXIT_PRE_JUDGE_EXECLP); } else { // Judger int status = 0; user_regs_struct regs{}; stderr = freopen("error.txt", "a+", stderr); init_syscalls(oj_solution.lang); while (true) { if (wait4(executor, &status, 0, &rused) < 0) { FM_LOG_FATAL("wait4 executor failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } if (WIFEXITED(status)) { if ((oj_solution.lang != LANG_JAVA && oj_solution.lang != LANG_KOTLIN) || WEXITSTATUS(status) == EXIT_SUCCESS) { // AC PE WA FM_LOG_TRACE("normal quit"); int result; if (oj_solution.spj) { // use SPJ result = oj_compare_output_spj(input_file, output_file_std, stdout_file_executive, oj_solution.spj_exe_file); } else { // compare file result = oj_compare_output(output_file_std, stdout_file_executive); } // WA if (result == OJ_WA) { oj_solution.result = OJ_WA; } else if (oj_solution.result != OJ_PE) { // previous case is AC oj_solution.result = result; // AC or PE } else /* (oj_solution.result == OJ_PE) */ { // previous case is PE oj_solution.result = OJ_PE; } FM_LOG_NOTICE("case result: %d, problem result: %d", result, oj_solution.result); } else { // not return 0 oj_solution.result = OJ_RE; FM_LOG_NOTICE("abnormal quit, exit_code: %d", WEXITSTATUS(status)); } break; } // RE/TLE/OLE if (WIFSIGNALED(status) || (WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)) { int signo = 0; if (WIFSIGNALED(status)) { signo = WTERMSIG(status); FM_LOG_NOTICE("child process killed by signal %d, %s", signo, strsignal(signo)); } else { signo = WSTOPSIG(status); FM_LOG_NOTICE("child process stopped by signal %d, %s", signo, strsignal(signo)); } switch (signo) { // Ignore case SIGCHLD: oj_solution.result = OJ_AC; break; // TLE case SIGALRM: // alarm() and setitimer(ITIMER_REAL) case SIGVTALRM: // setitimer(ITIMER_VIRTUAL) case SIGXCPU: // exceeds soft processor limit oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded: %s", strsignal(signo)); break; // OLE case SIGXFSZ: // exceeds file size limit oj_solution.result = OJ_OLE; FM_LOG_TRACE("Output Limit Exceeded"); break; // RE case SIGSEGV: // segmentation violation case SIGFPE: // any arithmetic exception case SIGBUS: // the process incurs a hardware fault case SIGABRT: // abort() function case SIGKILL: // exceeds hard processor limit default: oj_solution.result = OJ_RE; FILE *fp = fopen(stderr_file_executive, "a+"); if (fp == nullptr) { fprintf(stderr, "%s\n", strsignal(signo)); FM_LOG_WARNING("Runtime Error: %s", strsignal(signo)); } else { fprintf(fp, "%s\n", strsignal(signo)); fclose(fp); } break; } // end of swtich kill(executor, SIGKILL); break; } // end of "if (WIFSIGNALED(status) ...)" oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); // TODO(power): check why memory exceed too much if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; kill(executor, SIGKILL); break; } // check syscall if (ptrace(PTRACE_GETREGS, executor, NULL, ®s) < 0) { FM_LOG_FATAL("ptrace(PTRACE_GETREGS) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } int syscall_id = 0; #ifdef __i386__ syscall_id = (int)regs.orig_eax; #else syscall_id = (int) regs.orig_rax; #endif if (syscall_id > 0 && !is_valid_syscall(syscall_id)) { oj_solution.result = OJ_RF; FM_LOG_FATAL("restricted function, syscall_id: %d", syscall_id); kill(executor, SIGKILL); break; } if (ptrace(PTRACE_SYSCALL, executor, NULL, NULL) < 0) { FM_LOG_FATAL("ptrace(PTRACE_SYSCALL) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } } // end of while } // end of fork for judge process oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; FM_LOG_NOTICE("memory limit exceeded: %d (fault: %d * %d)", oj_solution.memory_usage, rused.ru_minflt, page_size); } oj_solution.time_usage = std::max(oj_solution.time_usage, (unsigned long) rused.ru_utime.tv_sec * 1000 + rused.ru_utime.tv_usec / 1000); if (oj_solution.time_usage > oj_solution.time_limit) { oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded"); } if (oj_solution.result != OJ_AC) { if (oj_solution.judge_type == ACM) { FM_LOG_NOTICE("not AC/PE, no need to continue"); } if (oj_solution.result == OJ_TLE) { oj_solution.time_usage = oj_solution.time_limit; } else if (oj_solution.result == OJ_WA) { if (oj_solution.lang == LANG_JAVA) { // TODO: kotlin fix_java_result(stdout_file_executive, stderr_file_executive); } else if ((oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) && file_size(stderr_file_executive)) { oj_solution.result = OJ_RE; FM_LOG_TRACE("Runtime Error"); } } return false; } return true; }
void run_solution() { FM_LOG_DEBUG("run_solution"); #ifndef FAST_JUDGE if (oj_solution.lang == LANG_PYTHON27) { copy_python_runtime_python2(oj_solution.work_dir); FM_LOG_DEBUG("copy_python_runtime"); } else if (oj_solution.lang == LANG_PYTHON3) { copy_python_runtime_python3(oj_solution.work_dir); FM_LOG_DEBUG("copy_python_runtime"); } #endif check_spj(); struct dirent **namelist; int num_of_test; num_of_test = scandir(oj_solution.data_dir, &namelist, data_filter, alphasort); if (num_of_test < 0) { FM_LOG_FATAL("scan data directory failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_DAA); } int first_failed_test = 0; char input_file[PATH_SIZE]; char output_file_std[PATH_SIZE]; char stdout_file_executive[PATH_SIZE]; char stderr_file_executive[PATH_SIZE]; snprintf(stderr_file_executive, PATH_SIZE, "%s/stderr_executive.txt", oj_solution.work_dir); FM_LOG_DEBUG("start run solution (%d cases)", num_of_test); for (int i = 0; i < num_of_test; ++i) { update_solution_status(oj_solution.cid, oj_solution.sid, OJ_RUN, i + 1); prepare_files(namelist[i]->d_name, input_file, output_file_std, stdout_file_executive); FM_LOG_TRACE("run case: %d", i + 1); bool result = judge(input_file, output_file_std, stdout_file_executive, stderr_file_executive); if (oj_solution.result != OJ_AC && !first_failed_test) { first_failed_test = i + 1; } if (!result && oj_solution.judge_type == ACM) { break; } } for (int i = 0; i < num_of_test; ++i) { free(namelist[i]); } free(namelist); #ifndef FAST_JUDGE if (oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) { clean_workdir(oj_solution.work_dir); } #endif output_acm_result(oj_solution.result, oj_solution.time_usage, oj_solution.memory_usage, first_failed_test); }
void run(oj_solution_t &oj_solution) { if (oj_solution.cid > 0) { snprintf(oj_solution.work_dir, PATH_SIZE, "%s/c%d", oj_config.temp_dir, oj_solution.cid); } else { strncpy(oj_solution.work_dir, oj_config.temp_dir, strlen(oj_config.temp_dir) + 1); } char stderr_file[PATH_SIZE]; snprintf(stderr_file, PATH_SIZE, "%s/%s/error.txt", oj_solution.work_dir, oj_solution.sid); FM_LOG_NOTICE("/usr/local/bin/powerjudge -s %s -p %s -l %s -t %s -m %s -w %s -D %s", oj_solution.sid, oj_solution.pid, oj_solution.language, oj_solution.time_limit, oj_solution.memory_limit, oj_solution.work_dir, oj_config.data_dir); pid_t pid = fork(); if (pid < 0) { FM_LOG_FATAL("fork judger failed: %s", strerror(errno)); SendQueue.push(std::make_pair(EXIT_FORK_ERROR, oj_solution)); } else if (pid == 0) { execl("/usr/local/bin/powerjudge", "/usr/local/bin/powerjudge", "-s", oj_solution.sid, "-p", oj_solution.pid, "-l", oj_solution.language, "-t", oj_solution.time_limit, "-m", oj_solution.memory_limit, "-w", oj_solution.work_dir, "-D", oj_config.data_dir, "-c", std::to_string(oj_solution.cid).c_str(), NULL); stderr = freopen(stderr_file, "a+", stderr); FM_LOG_FATAL("exec error: %s", strerror(errno)); SendQueue.push(std::make_pair(EXIT_EXEC_ERROR, oj_solution)); } else { int status = 0; FM_LOG_TRACE("process ID=%d", pid); if (waitpid(pid, &status, WUNTRACED) == -1) { FM_LOG_FATAL("waitpid for judger failed: %s", strerror(errno)); } if (WIFEXITED(status)) // normal termination { if (EXIT_SUCCESS == WEXITSTATUS(status)) { FM_LOG_DEBUG("judge succeeded"); SendQueue.push(std::make_pair(EXIT_OK, oj_solution)); } else if (EXIT_COMPILE_ERROR == WEXITSTATUS(status)) { FM_LOG_TRACE("compile error"); SendQueue.push(std::make_pair(EXIT_OK, oj_solution)); } else if (EXIT_JUDGE == WEXITSTATUS(status)) { FM_LOG_TRACE("judge error"); SendQueue.push(std::make_pair(OJ_SE, oj_solution)); } else { FM_LOG_TRACE("judge error"); SendQueue.push(std::make_pair(WEXITSTATUS(status), oj_solution)); } } else { if (WIFSIGNALED(status)) // killed by signal { int signo = WTERMSIG(status); FM_LOG_WARNING("judger killed by signal: %s", strsignal(signo)); SendQueue.push(std::make_pair(signo, oj_solution)); } else if (WIFSTOPPED(status)) // stopped by signal { int signo = WSTOPSIG(status); FM_LOG_FATAL("judger stopped by signal: %s\n", strsignal(signo)); SendQueue.push(std::make_pair(signo, oj_solution)); } else { FM_LOG_FATAL("judger stopped with unknown reason, status(%d)", status); SendQueue.push(std::make_pair(EXIT_UNKNOWN, oj_solution)); } } } }
/* * #error "This make CE" * #warning "Just warning message" * #include </dev/core> * #include </dev/zero> * #include </dev/random> * #include </etc/passwd> * #include <../../../etc/passwd> * egrep '^\s*#include\s*[<"][./].*[>"]' Main.cc */ void compile() { update_solution_status(oj_solution.cid, oj_solution.sid, OJ_COM, 0); char stdout_compiler[PATH_SIZE]; char stderr_compiler[PATH_SIZE]; snprintf(stdout_compiler, PATH_SIZE, "%s/stdout_compiler.txt", oj_solution.work_dir); snprintf(stderr_compiler, PATH_SIZE, "%s/stderr_compiler.txt", oj_solution.work_dir); pid_t compiler = fork(); // create a child process for compiler if (compiler < 0) { FM_LOG_FATAL("fork compiler failed: %s", strerror(errno)); exit(EXIT_FORK_COMPILER); } else if (compiler == 0) { // child process: run compiler log_add_info("compiler"); set_compile_limit(); stdout = freopen(stdout_compiler, "w", stdout); stderr = freopen(stderr_compiler, "w", stderr); if (stdout == nullptr || stderr == nullptr) { FM_LOG_FATAL("error freopen: stdout(%p), stderr(%p)", stdout, stderr); exit(EXIT_COMPILE_IO); } print_user_group(); print_word_dir(); switch (oj_solution.lang) { case LANG_C99: print_compiler(CP_C99); execvp(CP_C99[0], (char *const *) CP_C99); break; case LANG_C11: print_compiler(CP_C11); execvp(CP_C11[0], (char *const *) CP_C11); break; case LANG_CPP98: print_compiler(CP_CC98); execvp(CP_CC98[0], (char *const *) CP_CC98); break; case LANG_CPP11: print_compiler(CP_CC11); execvp(CP_CC11[0], (char *const *) CP_CC11); break; case LANG_CPP14: print_compiler(CP_CC14); execvp(CP_CC14[0], (char *const *) CP_CC14); break; case LANG_CPP17: print_compiler(CP_CC98); execvp(CP_CC98[0], (char *const *) CP_CC17); break; case LANG_PASCAL: print_compiler(CP_PAS); execvp(CP_PAS[0], (char *const *) CP_PAS); break; case LANG_JAVA: print_compiler(CP_J); execvp(CP_J[0], (char *const *) CP_J); break; case LANG_PYTHON27: print_compiler(CP_PY27); execvp(CP_PY27[0], (char *const *) CP_PY27); break; case LANG_PYTHON3: print_compiler(CP_PY3); execvp(CP_PY3[0], (char *const *) CP_PY3); break; case LANG_KOTLIN: print_compiler(CP_KT); execvp(CP_KT[0], (char *const *) CP_KT); break; default: FM_LOG_FATAL("Unknown language %d", oj_solution.lang); break; } // execvp error FM_LOG_FATAL("execvp compiler error"); exit(EXIT_COMPILE_EXEC); } else { // parent process: Judger int status = 0; if (waitpid(compiler, &status, WUNTRACED) == -1) { FM_LOG_FATAL("waitpid for compiler failed: %s", strerror(errno)); exit(EXIT_COMPILE_ERROR); // SE } FM_LOG_DEBUG("compiler finished"); if ((oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) && file_size(stderr_compiler)) { FM_LOG_TRACE("compile error"); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_OK); } if (WIFEXITED(status)) { // normal termination if (EXIT_SUCCESS == WEXITSTATUS(status)) { FM_LOG_DEBUG("compile succeeded"); } else if (GCC_COMPILE_ERROR == WEXITSTATUS(status)) { FM_LOG_TRACE("compile error"); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_OK); } else { if (fix_gcc_result(stderr_compiler)) { FM_LOG_WARNING("Compiler Limit Exceeded!"); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_OK); } else { FM_LOG_FATAL("compiler unknown exit status %d", WEXITSTATUS(status)); output_acm_result(OJ_CE, 0, 0, 0); exit(EXIT_COMPILE_ERROR); } } } else { if (WIFSIGNALED(status)) { // killed by signal int signo = WTERMSIG(status); FM_LOG_WARNING("Compiler Limit Exceeded: %s", strsignal(signo)); output_acm_result(OJ_CE, 0, 0, 0); stderr = freopen(stderr_compiler, "w", stderr); fprintf(stderr, "Compiler Limit Exceeded: %s\n", strsignal(signo)); exit(EXIT_OK); } else if (WIFSTOPPED(status)) { // stopped by signal int signo = WSTOPSIG(status); FM_LOG_FATAL("stopped by signal: %s\n", strsignal(signo)); } else { FM_LOG_FATAL("unknown stop reason, status(%d)", status); } exit(EXIT_COMPILE_ERROR); // SE } } }
void timeout_hander(int signo) { if (signo == SIGALRM) { FM_LOG_FATAL("Judge Timeout"); exit(EXIT_TIMEOUT); } }
int main(int argc, char *argv[], char *envp[]) { log_open(LOG_FILE); FM_LOG_TRACE("---"); check_pid(); int sockfd; socklen_t clilen; struct sockaddr_in serv_addr{}; struct sockaddr_in cli_addr{}; const char *cfg_file; if (argc > 1) { cfg_file = argv[1]; } else { cfg_file = DEFAULT_CFG_FILE; } read_config(cfg_file); FM_LOG_TRACE("read_config"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { fatal_error("ERROR opening socket"); } FM_LOG_TRACE("socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; if (inet_aton(oj_config.ip, &serv_addr.sin_addr) == 0) { serv_addr.sin_addr.s_addr = INADDR_ANY; } serv_addr.sin_port = htons(oj_config.port); FM_LOG_NOTICE("IP address: %s %s", oj_config.ip, inet_ntoa(serv_addr.sin_addr)); FM_LOG_NOTICE("port: %d %d", oj_config.port, ntohs(serv_addr.sin_port)); int yes = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { fatal_error("setsockopt SO_REUSEADDR failed"); } if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { fatal_error("ERROR on binding"); } FM_LOG_TRACE("bind"); clilen = sizeof(cli_addr); if (listen(sockfd, oj_config.backlog) < 0) { fatal_error("ERROR on listening"); } FM_LOG_NOTICE("listen backlog: %d", oj_config.backlog); if (daemon(0, 0) == -1) { FM_LOG_FATAL("Cannot daemonize"); pidfile_remove(pfh); exit(EXIT_FAILURE); } print_word_dir(); print_user_group(); pidfile_write(pfh); struct sigaction sa{}; sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGTERM, &sa, nullptr) == -1) { // install signal hander for timeout FM_LOG_FATAL("cannot handle SIGTERM"); exit(EXIT_FAILURE); } else { FM_LOG_DEBUG("set signal_handler"); } for (int i = 0; i < oj_config.thread_num; i++) { std::thread t(ThreadWork); t.detach(); } FM_LOG_NOTICE("thread count: %d", oj_config.thread_num); std::thread(SendWork).detach(); while (isRunning) { int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd != -1) { work(newsockfd, cli_addr); } } pidfile_remove(pfh); close(sockfd); return 0; }
/** fmCreateNetworkClient * \ingroup platformUtil * * \desc Creates a network client socket. * * \param[out] socketInfo points to the information structure for the * client socket. * * \param[in] type is the type of socket to create. * * \param[in] host points to a string specifying the hostname. * * \param[in] port is the port number. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCreateNetworkClient(fm_socket * socketInfo, fm_socketType type, fm_text host, fm_int port) { struct hostent h; struct hostent *hp; fm_int errResult; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; char buf[FM_GETHOSTBYNAME_BUF_SIZE]; int herrno; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, port=%d\n", (void *) socketInfo, port); if (!socketInfo) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } FM_CLEAR(*socketInfo); if (type == FM_SOCKET_TYPE_TCP) { socketInfo->sock = socket(AF_INET, SOCK_STREAM, 0); } else if (type == FM_SOCKET_TYPE_UDP) { socketInfo->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } if (socketInfo->sock == -1) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Unable to create socket type %d\n", type); FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_FAIL); } FM_CLEAR(socketInfo->address); socketInfo->address.sin_family = AF_INET; if ((gethostbyname_r(host, &h, buf, FM_GETHOSTBYNAME_BUF_SIZE, &hp, &herrno) != 0) || (hp == NULL)) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Unable to resolve hostname: %s\n", host); } FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, !hp); FM_MEMCPY_S(&socketInfo->address.sin_addr.s_addr, sizeof(socketInfo->address.sin_addr.s_addr), hp->h_addr, hp->h_length); socketInfo->address.sin_port = htons(port); if (type == FM_SOCKET_TYPE_TCP) { errResult = connect(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult != 0); } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmCreateNetworkClient */
void parse_arguments(int argc, char *argv[]) { int opt; while ((opt = getopt(argc, argv, "s:p:t:m:l:w:d:D:j:c:")) != -1) { switch (opt) { case 's': // Solution ID oj_solution.sid = atoi(optarg); break; case 'p': // Problem ID oj_solution.pid = atoi(optarg); break; case 'l': // Language ID oj_solution.lang = atoi(optarg); break; case 'j': // judge type oj_solution.judge_type = atoi(optarg); break; case 't': // Time limit oj_solution.time_limit = (unsigned int) atoi(optarg); break; case 'm': // Memory limit oj_solution.memory_limit = (unsigned int) atoi(optarg); break; case 'w': case 'd': // Work directory if (realpath(optarg, work_dir_root) == nullptr) { fprintf(stderr, "resolve work dir failed:%s\n", strerror(errno)); exit(EXIT_BAD_PARAM); } break; case 'D': // Data directory if (realpath(optarg, data_dir_root) == nullptr) { fprintf(stderr, "resolve data dir failed: %s\n", strerror(errno)); exit(EXIT_BAD_PARAM); } break; case 'c': // Contest ID oj_solution.cid = atoi(optarg); break; default: fprintf(stderr, "unknown option provided: -%c %s\n", opt, optarg); exit(EXIT_BAD_PARAM); } } char buff[PATH_SIZE]; snprintf(buff, PATH_SIZE, "%s/oj-judge.log", work_dir_root); check_and_rename_log(buff); log_open(buff); check_arguments(); snprintf(oj_solution.work_dir, PATH_SIZE, "%s/%d", work_dir_root, oj_solution.sid); snprintf(oj_solution.data_dir, PATH_SIZE, "%s/%d", data_dir_root, oj_solution.pid); char source_file[PATH_SIZE]; snprintf(source_file, PATH_SIZE, "%s/Main.%s", oj_solution.work_dir, lang_ext[oj_solution.lang]); if (access(source_file, F_OK) == -1) { FM_LOG_FATAL("Source code file is missing."); exit(EXIT_NO_SOURCE_CODE); } if (oj_solution.lang == LANG_JAVA) { oj_solution.memory_limit *= java_memory_factor; oj_solution.time_limit *= java_time_factor; } else if (oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) { oj_solution.memory_limit *= python_memory_factor; oj_solution.time_limit *= python_time_factor; } else if (oj_solution.lang == LANG_KOTLIN) { oj_solution.memory_limit *= kotlin_memory_factor; oj_solution.time_limit *= kotlin_time_factor; } snprintf(buff, PATH_SIZE, "%s/last", work_dir_root); unlink(buff); if (symlink(oj_solution.work_dir, buff) == -1) { FM_LOG_NOTICE("make symlink for %s failed: %s", buff, strerror(errno)); } print_solution(); }
void send_multi_result(char *file_path, oj_solution_t &oj_solution) { FM_LOG_TRACE("send_multi_result"); CURL *curl; CURLM *multi_handle; int still_running = 1; struct curl_httppost *formpost = nullptr; struct curl_httppost *lastptr = nullptr; struct curl_slist *headerlist = nullptr; static const char buf[] = "Expect:"; const size_t size = 25; char data[size] = {0}; curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "sid", CURLFORM_COPYCONTENTS, oj_solution.sid, CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "token", CURLFORM_COPYCONTENTS, oj_solution.token, CURLFORM_END); snprintf(data, size, "%d", oj_solution.cid); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "cid", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.result); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "result", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.time_usage); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "time", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.memory_usage); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "memory", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.test); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "test", CURLFORM_COPYCONTENTS, data, CURLFORM_END); if (file_path != NULL && access(file_path, F_OK) != -1) { truncate_upload_file(file_path); FM_LOG_NOTICE("will upload error file %s", file_path); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "error", CURLFORM_FILE, file_path, CURLFORM_END); } FM_LOG_TRACE("try curl_easy_init"); curl = curl_easy_init(); multi_handle = curl_multi_init(); headerlist = curl_slist_append(headerlist, buf); if (curl && multi_handle) { FM_LOG_TRACE("curl_multi_init OK"); curl_easy_setopt(curl, CURLOPT_URL, oj_config.api_url); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); curl_multi_add_handle(multi_handle, curl); curl_multi_perform(multi_handle, &still_running); do { struct timeval timeout{}; int rc; /* select() return code */ CURLMcode mc; /* curl_multi_fdset() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if (curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if (timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mc != CURLM_OK) { fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); break; } if (maxfd == -1) { #ifdef _WIN32 Sleep(100); rc = 0; #else /* Portable sleep for platforms other than Windows. */ struct timeval wait = {0, 100 * 1000}; /* 100ms */ rc = select(0, NULL, NULL, NULL, &wait); #endif } else { /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */ rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); } switch (rc) { case -1: /* select error */ break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform(multi_handle, &still_running); break; } } while (still_running); curl_multi_cleanup(multi_handle); curl_easy_cleanup(curl); curl_formfree(formpost); curl_slist_free_all(headerlist); FM_LOG_DEBUG("send_multi_result finished"); } else { FM_LOG_FATAL("cannot init curl: %s", strerror(errno)); update_system_error(EXIT_CURL_ERROR, oj_solution); } }
/** fmIsRawPacketSocketDeviceOperational * \ingroup intPlatformCommon * * \desc If raw packet socket was initialized, it verifies that * the underlying network device is operational. * * \param[in] sw refers to the switch number to send packets to. * * \param[out] isRawSocket is a pointer to a variable specifying if raw * socket is used. * * \param[out] mtu is a pointer to a variable storing mtu value of * the raw sockets network device. * * \return TRUE if either raw packet socket was not initialized or * raw packet socket is initialized and the underlying network * device is operational. * \return FALSE if raw packet socket is initialized and the underlying * network device is not operational. * *****************************************************************************/ fm_bool fmIsRawPacketSocketDeviceOperational(fm_int sw, fm_bool *isRawSocket, fm_int * mtu) { fm_switch *switchPtr; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; struct ifreq ifr; FM_LOG_ENTRY(FM_LOG_CAT_PLATFORM, "sw=%d\n", sw); switchPtr = GET_SWITCH_PTR(sw); if (isRawSocket != NULL) { *isRawSocket = FM_DISABLED; } if (switchPtr->isRawSocketInitialized == FM_DISABLED) { FM_LOG_EXIT_CUSTOM(FM_LOG_CAT_PLATFORM, TRUE, "No raw packet socket\n"); } FM_STRNCPY_S(ifr.ifr_name, IF_NAMESIZE, GET_PLAT_STATE(sw)->ifaceName, IF_NAMESIZE); if (ioctl(GET_PLAT_STATE(sw)->rawSocket, SIOCGIFFLAGS, &ifr) == -1) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to get socket %d flags for device %s: %s\n", GET_PLAT_STATE(sw)->rawSocket, ifr.ifr_name, strErrBuf); } else { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to get socket %d flags for device %s: %d\n", GET_PLAT_STATE(sw)->rawSocket, ifr.ifr_name, errno); } FM_LOG_EXIT_CUSTOM(FM_LOG_CAT_PLATFORM, FALSE, "Not operational\n"); } if ((ifr.ifr_flags & IFF_RUNNING) == 0) { FM_LOG_WARNING(FM_LOG_CAT_PLATFORM, "Network device %s resources are not allocated.\n", ifr.ifr_name); FM_LOG_EXIT_CUSTOM(FM_LOG_CAT_PLATFORM, FALSE, "Not operational\n"); } if (ioctl(GET_PLAT_STATE(sw)->rawSocket, SIOCGIFMTU, &ifr) == -1) { FM_LOG_WARNING(FM_LOG_CAT_SWITCH, "WARNING: failed to read netdev MTU\n"); FM_LOG_EXIT_CUSTOM(FM_LOG_CAT_PLATFORM, FALSE, "MTU could not be retrieved\n"); } if ( (isRawSocket != NULL) && (mtu != NULL) ) { *isRawSocket = FM_ENABLED; *mtu = ifr.ifr_mtu; } FM_LOG_EXIT_CUSTOM(FM_LOG_CAT_PLATFORM, TRUE, "Operational\n"); } /* fmIsRawPacketSocketDeviceOperational */
/** fmWaitForNetworkEvent * \ingroup platformUtil * * \desc Waits for network events. * * \param[out] sockets points to an array of active and inactive sockets. * This function can activate inactive sockets when a client * attempts to make a connection. The array must be maxSockets * in length. * * \param[in] numSockets is the current number of active sockets; it must * be in the range [1..maxSockets). * * \param[in] maxSockets is the maximum number of sockets this function * can activate. * * \param[out] eventReceived points to an array where this function places * the network event type for each active socket. The array * must be maxSockets elements in length. * * \param[in] timeout is the amount of time to wait for a network event. * Set to ''FM_WAIT_FOREVER'' to wait indefinitely. * * \return FM_OK if successful. * \return Other ''Status Codes'' as appropriate in case of failure. * *****************************************************************************/ fm_status fmWaitForNetworkEvent(fm_socket ** sockets, fm_int * numSockets, fm_int maxSockets, fm_int * eventReceived, fm_timestamp *timeout) { fm_int currNumSockets; fm_int errResult; fm_int i; fm_int j; fm_int slot; fm_bool doIncrement; struct pollfd fds[FM_MAX_FDS_NUM] = { {0} }; fm_int fdsCnt; socklen_t addrLen = SOCKET_ADDRLEN; struct timeval ts; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "sockets=%p, numSockets=%p(%d), maxSockets=%d, " "eventReceived=%p, timeout=%p\n", (void *) sockets, (void *) numSockets, (numSockets ? *numSockets : -1), maxSockets, (void *) eventReceived, (void *) timeout); if ((!sockets || !eventReceived || !numSockets || (*numSockets == 0) || \ (maxSockets > FM_MAX_FDS_NUM) || (*numSockets > FM_MAX_FDS_NUM))) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } currNumSockets = *numSockets; for ( i = 0, fdsCnt = 0 ; i < currNumSockets ; i++ ) { #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Watching descriptor %d\n", sockets[i]->sock); #endif if (sockets[i]->type != FM_SOCKET_TYPE_CLOSED) { fds[fdsCnt].fd = sockets[i]->sock; fds[fdsCnt].events = POLLIN; fds[fdsCnt].revents = 0; fdsCnt++; } } if (timeout != FM_WAIT_FOREVER) { FM_CLEAR(ts); ts.tv_sec = (int) timeout->sec; ts.tv_usec = (int) timeout->usec; } errResult = poll(fds, fdsCnt, ((timeout == FM_WAIT_FOREVER) ? -1 : \ ((ts.tv_sec * 1000) + (ts.tv_usec / 1000)) )); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); for ( i = 0, fdsCnt = 0 ; i < currNumSockets ; i++, fdsCnt++) { /* Default case */ eventReceived[i] = FM_NETWORK_EVENT_NONE; if (sockets[i]->type != FM_SOCKET_TYPE_CLOSED && fds[fdsCnt].revents & POLLIN) { /* Handle TCP connection on server socket */ if ((sockets[i]->type == FM_SOCKET_TYPE_TCP) && (sockets[i]->serverPort > 0)) { doIncrement = TRUE; slot = *numSockets; for ( j = 0 ; j < currNumSockets ; j++ ) { if (sockets[j]->type == FM_SOCKET_TYPE_CLOSED) { doIncrement = FALSE; slot = j; break; } } if (slot >= maxSockets) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Not enough socket slots left to accept client\n"); break; } FM_CLEAR(*sockets[slot]); sockets[slot]->sock = accept(sockets[i]->sock, (struct sockaddr *) &sockets[slot]->address, &addrLen); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, sockets[slot]->sock == -1); sockets[slot]->type = FM_SOCKET_TYPE_TCP; eventReceived[i] = FM_NETWORK_EVENT_NEW_CLIENT; #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Handled new client connection\n"); #endif if (doIncrement) { (*numSockets)++; } break; } else { eventReceived[i] = FM_NETWORK_EVENT_DATA_AVAILABLE; #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Data available on client #%d\n", i - 1); #endif } } } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmWaitForNetworkEvent */
/** fmRawPacketSocketHandlingInitialize * \ingroup intPlatformCommon * * \desc Initializes the raw packet socket transfer module. * * \param[in] sw is the switch number to initialize. * * \param[in] hasFcs is TRUE if the packet includes the FCS field. * * \param[in] iface is a string containing the netdev's interface name * through which the packets should be sent / received. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmRawPacketSocketHandlingInitialize(fm_int sw, fm_bool hasFcs, fm_text iface) { fm_status err = FM_OK; fm_int rawSock = -1; struct ifreq ifr; struct sockaddr_ll sa; struct ethtool_value ethValue; #ifdef ENABLE_TIMESTAMP struct ifreq hwtstamp; struct hwtstamp_config hwconfig; struct hwtstamp_config hwconfig_requested; fm_int val; socklen_t len; fm_int so_timestamping_flags; struct cmsghdr * cmsg; #endif char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; fm_switch *switchPtr; FM_LOG_ENTRY(FM_LOG_CAT_PLATFORM, "sw=%d hasFcs=%s\n", sw, FM_BOOLSTRING(hasFcs)); if (iface == NULL) { err = FM_ERR_INVALID_ARGUMENT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err); } err = fmGenericPacketHandlingInitializeV2(sw, hasFcs); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err); /* initialize the raw packet socket */ rawSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_XDSA)); if (rawSock == -1) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "couldn't create raw packet socket\n"); err = FM_FAIL; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err); } /* retrieve ethernet interface index */ FM_STRNCPY_S(ifr.ifr_name, IF_NAMESIZE, iface, IF_NAMESIZE); if (ioctl(rawSock, SIOCGIFINDEX, &ifr) == -1) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to retrieve index for interface %s\n", iface); err = FM_ERR_INVALID_ARGUMENT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err); } /* initialize sockaddr_ll */ FM_CLEAR(sa); sa.sll_family = PF_PACKET; sa.sll_protocol = htons(ETH_P_XDSA); sa.sll_ifindex = ifr.ifr_ifindex; if (bind(rawSock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to bind to the raw packet socket\n"); err = FM_FAIL; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err); } #ifdef ENABLE_TIMESTAMP /*Set timestamp related configurations */ FM_CLEAR(hwconfig); FM_CLEAR(hwconfig_requested); FM_CLEAR(hwtstamp); strncpy(hwtstamp.ifr_name, iface, IF_NAMESIZE); hwtstamp.ifr_data = (void *)&hwconfig; hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; hwconfig_requested = hwconfig; errno = 0; if (ioctl(rawSock, SIOCSHWTSTAMP, &hwtstamp) < 0) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to configure RX hardware timestamp for all" " received packets. Error: %s\n", strErrBuf); } else { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to configure RX hardware timestamp for all" " received packets. Error: %d\n", errno); } } FM_LOG_DEBUG(FM_LOG_CAT_PLATFORM, "SIOCSHWTSTAMP: tx_type %d requested, got %d; " " rx_filter %d requested, got %d\n", hwconfig_requested.tx_type, hwconfig.tx_type, hwconfig_requested.rx_filter, hwconfig.rx_filter); so_timestamping_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE; if (setsockopt(rawSock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_flags, sizeof(so_timestamping_flags)) < 0) { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to set timestamping on socket\n"); /* Continue without timestamp */ } len = sizeof(val); errno = 0; if (getsockopt(rawSock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to retrieve SO_TIMESTAMPING socket options." " Error %s", strErrBuf); } else { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to retrieve SO_TIMESTAMPING socket options." " Error %d", errno); } } else { FM_LOG_DEBUG(FM_LOG_CAT_PLATFORM, "SO_TIMESTAMPING %d\n", val); if (val != so_timestamping_flags) { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Expected value %d but retrieved %d\n", so_timestamping_flags, val); } } #endif /* Set the Driver in ies-tagging mode on management PEP */ ethValue.cmd = ETHTOOL_SPFLAGS; ethValue.data = ETHTOOL_PRV_FLAG_IES; ifr.ifr_data = (void*) ðValue; if (ioctl(rawSock, SIOCETHTOOL, &ifr) == -1) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to set ies-tagging: %s\n", strErrBuf); } else { FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, "Failed to set ies-tagging: %d\n", errno); } } if (ioctl(rawSock, SIOCGIFFLAGS, &ifr) == -1) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to get socket flags: %s\n", strErrBuf); } else { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to get socket flags: %d\n", errno); } err = FM_FAIL; FM_LOG_ABORT(FM_LOG_CAT_PLATFORM, err); } if ((ifr.ifr_flags & IFF_UP) == 0) { /* Bring the NIC up */ ifr.ifr_flags |= IFF_UP; if (ioctl(rawSock, SIOCSIFFLAGS, &ifr) == -1) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to bring up: %s\n", strErrBuf); } else { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Failed to bring up: %d\n", errno); } err = FM_FAIL; FM_LOG_ABORT(FM_LOG_CAT_PLATFORM, err); } } GET_PLAT_STATE(sw)->rawSocket = rawSock; FM_STRNCPY_S(GET_PLAT_STATE(sw)->ifaceName, IF_NAMESIZE, iface, IF_NAMESIZE); /* Create the receive packet thread */ err = fmCreateThread("raw_packet_socket receive", FM_EVENT_QUEUE_SIZE_NONE, &fmRawPacketSocketReceivePackets, &(GET_PLAT_STATE(sw)->sw), GET_PLAT_RAW_LISTENER(sw)); switchPtr = GET_SWITCH_PTR(sw); if (switchPtr) { switchPtr->isRawSocketInitialized = FM_ENABLED; } ABORT: if ( (err != FM_OK) && (rawSock != -1) ) { close(rawSock); } FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, err); } /* end fmRawPacketSocketHandlingInitialize */
/** fmRawPacketSocketSendPackets * \ingroup intPlatformCommon * * \desc When called, iterates through the packet queue and * continues to send packets until either the queue empties. * * \param[in] sw refers to the switch number to send packets to. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmRawPacketSocketSendPackets(fm_int sw) { fm_status err = FM_OK; fm_switch * switchPtr; fm_packetHandlingState *pktState; fm_packetQueue * txQueue; fm_packetEntry * packet; fm_int32 rc; fm_buffer *sendBuf; struct msghdr msg; struct iovec iov[UIO_MAXIOV]; fm_islTag islTag; fm_uint32 fcs; fm_uint64 rawTS; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; struct ifreq ifr; FM_LOG_ENTRY(FM_LOG_CAT_EVENT_PKT_TX, "sw = %d\n", sw); switchPtr = GET_SWITCH_PTR(sw); pktState = GET_PLAT_PKT_STATE(sw); if (GET_PLAT_STATE(sw)->rawSocket <= 0) { FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_TX, "Socket is not initialized.\n"); FM_LOG_EXIT(FM_LOG_CAT_EVENT_PKT_TX, FM_ERR_UNINITIALIZED); } /* initialize the message header */ FM_CLEAR(msg); msg.msg_name = NULL; /* Optional field */ msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 0; msg.msg_flags = 0; FM_STRNCPY_S(ifr.ifr_name, IF_NAMESIZE, GET_PLAT_STATE(sw)->ifaceName, IF_NAMESIZE); txQueue = &pktState->txQueue; fmPacketQueueLock(txQueue); if (ioctl(GET_PLAT_STATE(sw)->rawSocket, SIOCGIFFLAGS, &ifr) == -1) { strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_FATAL(FM_LOG_CAT_EVENT_PKT_TX, "Failed to get socket %d flags for device %s: %s\n", GET_PLAT_STATE(sw)->rawSocket, ifr.ifr_name, strErrBuf); } else { FM_LOG_FATAL(FM_LOG_CAT_EVENT_PKT_TX, "Failed to get socket %d flags for device %s: %d\n", GET_PLAT_STATE(sw)->rawSocket, ifr.ifr_name, errno); } switchPtr->transmitterLock = TRUE; err = FM_FAIL; FM_LOG_ABORT(FM_LOG_CAT_EVENT_PKT_TX, err); } if ((ifr.ifr_flags & IFF_RUNNING) == 0) { FM_LOG_WARNING(FM_LOG_CAT_EVENT_PKT_TX, "Network device %s resources are not allocated.\n", ifr.ifr_name); switchPtr->transmitterLock = TRUE; err = FM_FAIL; FM_LOG_ABORT(FM_LOG_CAT_EVENT_PKT_TX, err); } /* Iterate through the packets in the tx queue */ for ( ; txQueue->pullIndex != txQueue->pushIndex ; txQueue->pullIndex = (txQueue->pullIndex + 1) % FM_PACKET_QUEUE_SIZE) { packet = &txQueue->packetQueueList[txQueue->pullIndex]; FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_TX, "sending packet in slot %d, length=%d tag=%d fcs=%08x\n", txQueue->pullIndex, packet->length, packet->suppressVlanTag, packet->fcsVal); msg.msg_iovlen = 0; /* Add the 8 byte timetag iovec. Note that the value is ignored * by the driver as it gets overwritten by the PEP. */ rawTS = 0; iov[msg.msg_iovlen].iov_base = &rawTS; iov[msg.msg_iovlen].iov_len = sizeof(rawTS); msg.msg_iovlen++; if (packet->islTagFormat == FM_ISL_TAG_F56) { /* Add the FTAG (F56) iovec */ islTag.f56.tag[0] = htonl(packet->islTag.f56.tag[0]); islTag.f56.tag[1] = htonl(packet->islTag.f56.tag[1]); iov[msg.msg_iovlen].iov_base = &islTag.f56.tag[0]; iov[msg.msg_iovlen].iov_len = FM_F56_BYTE_LEN; msg.msg_iovlen++; } /* iterate through all buffers */ for ( sendBuf = packet->packet ; sendBuf ; sendBuf = sendBuf->next ) { /* if first buffer ... */ if (sendBuf == packet->packet) { /* Cannot modify the send buffer, since the same buffer can be * used multiple times to send to multiple ports */ /* second iovec is the mac header */ iov[msg.msg_iovlen].iov_base = sendBuf->data; iov[msg.msg_iovlen].iov_len = FM_MAC_HDR_BYTE_LEN; msg.msg_iovlen++; if (packet->islTagFormat == FM_ISL_TAG_F64) { /* Insert the F64 ISL tag */ islTag.f64.tag[0] = htonl(packet->islTag.f64.tag[0]); islTag.f64.tag[1] = htonl(packet->islTag.f64.tag[1]); iov[msg.msg_iovlen].iov_base = &islTag.f64.tag[0]; iov[msg.msg_iovlen].iov_len = FM_F64_BYTE_LEN; msg.msg_iovlen++; } /* Third is the data in the first chain */ if (packet->suppressVlanTag) { iov[msg.msg_iovlen].iov_base = &sendBuf->data[4]; iov[msg.msg_iovlen].iov_len = sendBuf->len-16; msg.msg_iovlen++; } else { iov[msg.msg_iovlen].iov_base = &sendBuf->data[3]; iov[msg.msg_iovlen].iov_len = sendBuf->len-12; msg.msg_iovlen++; } } else { /* The rest of the chain */ iov[msg.msg_iovlen].iov_base = sendBuf->data; iov[msg.msg_iovlen].iov_len = sendBuf->len; msg.msg_iovlen++; } } /* end for (...) */ /* Append user-supplied FCS value to packet. */ if (pktState->sendUserFcs) { fcs = htonl(packet->fcsVal); iov[msg.msg_iovlen].iov_base = &fcs; iov[msg.msg_iovlen].iov_len = sizeof(fcs); msg.msg_iovlen++; } /* now send it to the driver */ errno = 0; rc = sendmsg(GET_PLAT_STATE(sw)->rawSocket, &msg, MSG_DONTWAIT); if (rc == -1) { switchPtr->transmitterLock = TRUE; if (errno != EWOULDBLOCK) { err = FM_FAIL; FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_TX, "rawSocket %d\n", GET_PLAT_STATE(sw)->rawSocket); strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno); if (strErrNum == 0) { FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_TX, "sendmsg failed: %s - errno %d\n", strErrBuf, errno); } else { FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_TX, "sendmsg failed - errno %d\n", errno); } } if (errno == EMSGSIZE) { switchPtr->transmitterLock = FALSE; } else { goto ABORT; } } else { FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_TX, "%d bytes were sent\n", rc); switchPtr->transmitterLock = FALSE; fmDbgDiagCountIncr(sw, FM_CTR_TX_PKT_COMPLETE, 1); } /************************************************** * free buffer only when * (1) sending to a single port; * or (2) this is the last packet of multiple * identical packets **************************************************/ if (packet->freePacketBuffer) { /* ignore the error code since it's better to continue */ (void) fmFreeBufferChain(sw, packet->packet); fmDbgGlobalDiagCountIncr(FM_GLOBAL_CTR_TX_BUFFER_FREES, 1); } } ABORT: fmPacketQueueUnlock(txQueue); FM_LOG_EXIT(FM_LOG_CAT_EVENT_PKT_TX, err); } /* end fmRawPacketSocketSendPackets */
int oj_compare_output(const char *file_out, const char *file_user) { FM_LOG_TRACE("start compare"); FILE *fp_std = fopen(file_out, "r"); if (fp_std == nullptr) { FM_LOG_FATAL("open standard output file (%s) failed: %s", file_out, strerror(errno)); exit(EXIT_COMPARE); } FILE *fp_exe = fopen(file_user, "r"); if (fp_exe == nullptr) { FM_LOG_FATAL("open user output file (%s) failed: %s", file_user, strerror(errno)); exit(EXIT_COMPARE); } int a, b, Na = 0, Nb = 0; enum { AC = OJ_AC, PE = OJ_PE, WA = OJ_WA } status = AC; while (true) { /* * Windows / DOS uses '\r\n'; * Unix / Linux / OS X uses '\n'; * Macs before OS X use '\r'; * TODO(power): out file with '\r' line ending get incorrect PE */ while ((a = fgetc(fp_std)) == '\r') {} while ((b = fgetc(fp_exe)) == '\r') {} Na++, Nb++; // deal with '\r' and '\n' if (a == '\r') a = '\n'; if (b == '\r') b = '\n'; if (feof(fp_std) && feof(fp_exe)) { break; } else if (feof(fp_std) || feof(fp_exe)) { // deal with tailing white spaces FILE *fp_tmp; if (feof(fp_std)) { FM_LOG_TRACE("std out file ended"); if (!is_space_char(b)) { FM_LOG_TRACE("WA exe['%c':0x%x @%d]", b, b, Nb); status = WA; break; } fp_tmp = fp_exe; } else { /* feof(fp_exe) */ FM_LOG_TRACE("user out file ended"); if (!is_space_char(a)) { FM_LOG_TRACE("WA std['%c':0x%x @%d]", a, a, Na); status = WA; break; } fp_tmp = fp_std; } int c; while (c = fgetc(fp_tmp), c != EOF) { if (c == '\r') c = '\n'; if (!is_space_char(c)) { FM_LOG_TRACE("WA ['%c':0x%x]", c, c); status = WA; break; } } break; } if (a != b) { status = PE; if (is_space_char(a) && is_space_char(b)) { continue; } if (is_space_char(a)) { ungetc(b, fp_exe); Nb--; } else if (is_space_char(b)) { ungetc(a, fp_std); Na--; } else { FM_LOG_TRACE("WA ['%c':0x%x @%d] : ['%c':0x%x @%d]", a, a, Na, b, b, Nb); status = WA; break; } } } // end of while fclose(fp_std); fclose(fp_exe); if (status == WA || status == PE) { make_diff_out2(file_out, file_user, oj_solution.work_dir, file_out); } FM_LOG_TRACE("compare finished, result=%s", status == AC ? "AC" : (status == PE ? "PE" : "WA")); return status; }
fm_status fmDbgSwitchSelfTest(fm_int sw, fm_bool ctrlState) { fm_status err; fm_status testResult = FM_FAIL; fm_switch *switchPtr; fm_bool switchLocked = FALSE; FM_LOG_ENTRY_API(FM_LOG_CAT_SWITCH, "sw=%d\n", sw); VALIDATE_SWITCH_LOCK(sw); /* Take write access to the switch lock */ err = LOCK_SWITCH(sw); if (err != FM_OK) { FM_LOG_FATAL(FM_LOG_CAT_SWITCH, "Unable to capture switch write lock %p for switch %d\n", (void *) fmRootApi->fmSwitchLockTable[sw], sw); goto ABORT; } switchLocked = TRUE; /* return error if switch is not found. */ if (!fmRootApi->fmSwitchStateTable[sw]) { err = FM_ERR_INVALID_SWITCH; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_SWITCH, err); } switchPtr = fmRootApi->fmSwitchStateTable[sw]; /* Do not perform test on a SWAG or a member of a SWAG. */ if (switchPtr->switchFamily == FM_SWITCH_FAMILY_SWAG || switchPtr->swag >= 0) { err = FM_ERR_INVALID_SWITCH; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_SWITCH, err); } if (ctrlState) { /************************************************** * First bring the switch down. This will clear * all API soft state and delete VLANs, LAGs, * multicast groups, routes, etc. **************************************************/ err = fmSetSwitchState(sw, FALSE); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_SWITCH, err); /************************************************** * Now bring the switch back up so we can perform * the memory test. **************************************************/ err = fmSetSwitchState(sw, TRUE); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_SWITCH, err); } UNLOCK_SWITCH(sw); switchLocked = FALSE; /************************************************** * Now perform the test. **************************************************/ FM_API_CALL_FAMILY(testResult, switchPtr->DbgSwitchSelfTest, sw); if (ctrlState) { /************************************************** * Bring switch down again. We have a test result, * so ignore the return code when calling * fmSetSwitchState since we only care about the * test result now. **************************************************/ fmSetSwitchState(sw, FALSE); } ABORT: if (switchLocked) { UNLOCK_SWITCH(sw); } if (err == FM_OK) { err = testResult; } FM_LOG_EXIT_API(FM_LOG_CAT_SWITCH, err); } /* end fmDbgSwitchSelfTest */