/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/win32/win32.c (maintained by: DF6LN) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>= 'A') && (*s <= 'Z')) *s += 'a'-'A'; s++; } return(p); } /* String in Grossbuchstaben umwandeln - aus DJGPP GNU-Paket fuer MS-DOS von D.J. Delorie */ char * strupr(char *s) { char *p = s; while (*s) { if ((*s >= 'a') && (*s <= 'z')) *s += 'A'-'a'; s++; } return(p); } /************************************************************************/ /* */ /* Als Ersatz fuer die Funktionen "findfirst" und "findnext" (bei DOS) */ /* werden die Funktionen "xfindfirst" und "xfindnext" verwendet. Hier */ /* wird nur der fuer TNN benoetigte Teil in die Struktur ffblk einge- */ /* tragen. Der zuletzt gefundene Filename muss in ffblk->ff_name erhal- */ /* ten bleiben, weil dieser beim Aufruf von "xfindnext" gesucht wird. */ /* */ /************************************************************************/ int xfindfirst(const char *pathname, struct ffblk *ffblk, int attrib) { char *fnpoi; DIR *dp; struct dirent *dirp; int retval; strcpy(ffblk->ff_path, pathname); /* Filename incl. Pfad */ normfname(ffblk->ff_path); /* '\\' -> '/' */ fnpoi = strrchr(ffblk->ff_path, FILE_SEP); /* Pfad angegeben? */ if (fnpoi == NULL) /* - nein .. */ { strcpy(ffblk->ff_find, ffblk->ff_path); /* Filename kopieren */ strcpy(ffblk->ff_path, textpath); /* default: textpath */ } else /* mit Pfad */ { if (fnpoi == ffblk->ff_path+strlen(ffblk->ff_path)) /* ohne Name */ return(-1); /* Unsinn */ strcpy(ffblk->ff_find, ++fnpoi); /* nur Filename */ *fnpoi = NUL; /* Filename im Pfad loeschen */ } if ((dp = opendir(ffblk->ff_path)) == NULL) /* Directory vorhanden? */ return(-1); retval = -1; /* default: nix gefunden */ while ((dirp = readdir(dp)) != NULL) /* Eintrag vorhanden? */ { if ((fnmatch(ffblk->ff_find, dirp->d_name, FNM_PATHNAME|FNM_PERIOD) != 0)) continue; strcpy(ffblk->ff_name, dirp->d_name); setfiletime(ffblk); retval = 0; break; } closedir(dp); return(retval); } /************************************************************************/ /* */ /* Erst den zuletzt gefundenen Eintrag suchen (steht in ffblk->ff_name) */ /* und den darauffolgenden passenden Eintrag zurueckmelden. */ /* */ /************************************************************************/ int xfindnext(struct ffblk *ffblk) { DIR *dp; struct dirent *dirp; int retval; if ((dp = opendir(ffblk->ff_path)) == NULL) return(-1); retval = -1; /* default: nix gefunden */ while ((dirp = readdir(dp)) != NULL) { if ((fnmatch(ffblk->ff_name, dirp->d_name, FNM_PATHNAME|FNM_PERIOD) != 0)) continue; retval = 1; break; } if (retval == 1) { retval = -1; /* default: nix gefunden */ while ((dirp = readdir(dp)) != NULL) { if ((fnmatch(ffblk->ff_find, dirp->d_name, FNM_PATHNAME|FNM_PERIOD) != 0)) continue; strcpy(ffblk->ff_name, dirp->d_name); setfiletime(ffblk); retval = 0; break; } } closedir(dp); return(retval); } /************************************************************************/ /* */ /* Bei xfindfirst und xfindnext Datum und Uhrzeit im Fileblock setzen */ /* */ /************************************************************************/ static void setfiletime(struct ffblk *ffblk) { struct stat filestat; struct tm *filetime; struct stat FSize; char fn[MAXPATH]; sprintf(fn, "%s%s", ffblk->ff_path, ffblk->ff_name); stat(fn, &filestat); filetime = gmtime(&filestat.st_mtime); ffblk->ff_ftime = ((filetime->tm_sec / 2) & 0x1f) + ((filetime->tm_min & 0x3f) << 5) + ((filetime->tm_hour & 0x1f) << 11); ffblk->ff_fdate = (filetime->tm_mday & 0x1f) + (((filetime->tm_mon & 0x0f) + 1) << 5) + (((filetime->tm_year - 80) & 0x7f) << 9); if (!stat(ffblk->ff_name, &FSize)) ffblk->ff_fsize = FSize.st_size; } /************************************************************************/ /* */ /* Ermitteln des freien Festplattenplatzes in Bytes. */ /* */ /* Damit es fuer grosse Festplatten keinen Ueberlauf gibt (Rueckgabe */ /* ist vom Typ LONG), wird ab 1GB freiem Speicher immer 1GB zurueck- */ /* gemeldet - sieht da jemand Probleme? */ /* */ /************************************************************************/ LONG getdiskfree(char *path) { DWORD free = 0; GetDiskFreeSpace("C:\\", NULL, NULL, NULL, &free); return(free); } /************************************************************************/ /* */ /* Fuer das erweiterte AUTOBIN-Protokoll wird die File-Zeit in einem */ /* Bitfeld gespeichert (s. Doku zu DPBOX), wie es BC++ bei dem Befehl */ /* getftime verwendet. Hier wird die Win32-Zeit der letzten Aenderung */ /* verwendet. */ /* */ /************************************************************************/ int getftime(int handle, struct ftime *ftimep) { struct stat filestat; struct tm *filetime; if (fstat(handle, &filestat) == -1) return(-1); filetime = gmtime(&filestat.st_mtime); ftimep->ft_tsec = filetime->tm_sec / 2; ftimep->ft_min = filetime->tm_min; ftimep->ft_hour = filetime->tm_hour; ftimep->ft_day = filetime->tm_mday; ftimep->ft_month = filetime->tm_mon + 1; ftimep->ft_year = filetime->tm_year - 80; return(0); } /************************************************************************/ /* */ /* 10ms-Ticker updaten */ /* */ /************************************************************************/ void update_timer(void) { fd_set rmask; fd_set wmask; struct timeval timevalue; int max_fd = 0; int count; register int i; int len; char buffer[1024]; static UWORD roundcounter = 1; #ifndef NO_WATCHDOG int lasttic10 = tic10; #endif gettimeofday(&tv, &tz); tic10 = (tv.tv_sec - tv_old.tv_sec) * 100 + (tv.tv_usec - tv_old.tv_usec) / 10000; #ifndef NO_WATCHDOG if (tic10 - lasttic10) if (write(watch_dog[1], "\0", 1) != 1) exit(1); #endif FD_ZERO(&rmask); FD_ZERO(&wmask); FD_SET((unsigned)consolefd, &rmask); /* Eingabe Console */ max_fd = 1; if (kiss_active) { for (i = 0; i < L1PNUM; ++i) { if (l1port[i].kisslink < 0) continue; #ifdef VANESSA if (l1port[i].kisstype == KISS_VAN) continue; #endif #ifdef AX_IPX if (l1port[i].kisstype == KISS_IPX) continue; #endif #ifdef AX25IP if (l1port[i].kisstype == KISS_AXIP) continue; #endif #ifdef KERNELIF if ( (l1port[i].kisstype == KISS_KAX25) || (l1port[i].kisstype == KISS_KAX25KJD)) continue; #endif #ifdef SIXPACK if (l1port[i].kisstype == KISS_6PACK) continue; #endif if (l1port[i].port_active) { FD_SET((unsigned)l1port[i].kisslink, &wmask); if (l1port[i].kisslink > max_fd -1) max_fd = l1port[i].kisslink + 1; } } } /* fuer alle Interfaces die benutzten Filedescriptoren fuer select() */ /* ermitteln und eintragen */ for (i = 0; i < L1PNUM; ++i) { /* nur aktive Ports bearbeiten */ if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) #ifdef SIXPACK || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ #endif ) continue; /* Interfacetypen durchgehen */ } /* for(...) */ timevalue.tv_usec = 10000; timevalue.tv_sec = 0; if (++roundcounter < maxrounds) /* schon genug Runden vergangen? */ timevalue.tv_usec = 0; else roundcounter = 0; /* Durchlaufzaehler ruecksetzen */ count = select(max_fd, &rmask, NULL, NULL, &timevalue); if (count == -1) return; /* alle Ports durchgehen */ for (i = 0; i < L1PNUM; ++i) { /* unbenutzte Ports nicht bearbeiten */ if ( (l1port[i].kisslink < 0) || (l1port[i].port_active != TRUE) #ifdef SIXPACK || (l1port[i].kisstype == KISS_6PACK) /* der hat hier nichts zu suchen */ #endif ) continue; } if (kiss_active) { for (i = 0; i < L1PNUM; ++i) { if (l1port[i].kisslink == -1) continue; #ifdef AX25IP if (l1port[i].kisstype == KISS_AXIP) continue; #endif #ifdef SIXPACK if (l1port[i].kisstype == KISS_6PACK) continue; #endif if (l1port[i].port_active) if (FD_ISSET(l1port[i].kisslink, &wmask)) if ((len = read(l1port[i].kisslink, buffer, 1024)) != 0) framedata_to_queue(i, buffer, len); } } } /************************************************************************/ /* */ /* Rechner neu starten */ /* */ /************************************************************************/ void reboot_system(void) { exit_all(); /* Hierher wird man wohl nur kommen, wenn tnn nicht als root gestartet */ /* wurde. Nun gibt es 2 Moeglichkeiten: entweder wir starten von vorne, */ /* weil die Resourcen ja breits freigegeben wurden, oder aber wir */ /* beenden das Programm, weil das ja mehr oder weniger gefordert wurde. */ /* Sinnvoller ist es wohl, wenn wir das Programm verlassen, in der */ /* Hoffnung, dass es danach regulaer von einem Batch erneut gestartet */ /* wird. Das ist jedenfalls besser, als nix zu tun. */ Break(); exit(1); } /************************************************************************/ /* */ /* Shell-Befehl - Win32-spezifischer Teil: */ /* Das gewuenschte Programm wird als Hintergrundprozess gestartet. */ /* */ /************************************************************************/ BOOLEAN tnnshell(char *cmdline) { return(TRUE); } /************************************************************************/ /* */ /* Pruefen, ob Kind-Prozesse beendet sind (vom Sysop gestartete externe */ /* Programme). Bei Zeitueberschreitung wird das Programm mit einer */ /* entsprechenden Fehlermeldung abgebrochen. */ /* */ /************************************************************************/ void shellsrv(void) { } /************************************************************************/ /* */ /* Daten von der Shell abholen und zum User bringen */ /* */ /************************************************************************/ void shell_to_user(void) { } /************************************************************************/ /* */ /* User-Eingabe in mhdp verarbeiten */ /* */ /************************************************************************/ BOOLEAN l7tosh(MBHEAD *mhdp) { if (userpo->status == US_EXTP) /* externer Prozess aktiv? */ { if (userpo->child_iactive == FALSE) { dealmb(mhdp); /* Abbruchzeile ignorieren */ userpo->mbhd = NULL; kill((pid_t *)(userpo->child_pid), SIGKILL); /* Abbruch (Watchdog) */ putmsg("SHELL ABORTED by User\r"); userpo->child_pid = 0; /* Prozess ist fertig */ userpo->child_fd = -1; userpo->child_iactive = FALSE; userpo->child_timeout = 0; userpo->status = US_CCP; return(TRUE); } return (TRUE); } return (FALSE); } /************************************************************************/ /* */ /* Filenamen pruefen */ /* */ /************************************************************************/ BOOLEAN good_file_name(const char *file) { return(TRUE); } /************************************************************************/ /* */ /* */ /************************************************************************/ void tnnexec(char *file) { char filename[MAXPATH+1]; strncpy(filename, file, MAXPATH); filename[MAXPATH] = 0; if (xaccess(filename,0)==0) { l1exit(); /* bei DOS16 -> done_umb() */ exit_timer(); exit_hardware(); execl(filename, filename, NULL); perror("EXEC"); HALT("tnnexec"); } } /************************************************************************/ /* */ /* */ /************************************************************************/ /* Winsocket Initialisieren. */ static int startWinsock(void) { WSADATA wsa; return WSAStartup(MAKEWORD(2,0),&wsa); } void init_console(void) { console_titel(); #ifdef L1TCPIP /* Interface Initialisieren. */ InitIFC(); #endif /* L1TCPIP */ setvbuf(stdout, NULL, _IONBF, 0); /* Ausgabe ungepuffert */ /* Winsocket Initialisieren. */ if (startWinsock()) { #ifdef SPEECH printf(speech_message(334)); #else printf("Error: Winsock cannot be initialized!\r"); #endif return; } if ((consolefd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return; consfile = stdout; } /************************************************************************/ /* */ /* */ /************************************************************************/ void exit_console(void) { } /************************************************************************/ /* */ /* */ /************************************************************************/ void hputc(char c) { if (!ishmod) { /* keine Ausgaben im Hostmode */ if (c == CR) /* nur fuer PC/Console notwenig! */ putchar('\n'); else putchar(c); } } /* return if character available */ BOOLEAN ishget() { if (kbhit()) { if (ishmod) hgetc(); /* im Hostmode Console ignorieren */ else return(TRUE); /* im Terminalmode melden, dass was da ist */ } return(FALSE); /* keine Umleitung, also auch nix da */ } /* return if output to console is stopped */ BOOLEAN ishput(void) { return(FALSE); } /* get one character from console */ char hgetc(void) { #define Prefix 0 #define ALT_X '-' char retval = 0; if (kbhit()) { if ((retval = getch()) == Prefix) { if (getch() == ALT_X) quit_program(0); } } return(retval); } /************************************************************************/ /* */ /* */ /************************************************************************/ BOOLEAN init_hardware(int argc, char *argv[]) { int scanned = 1; umask(0); time(&sys_time); /* Kommandozeilenparameter auswerten */ /* Den Verbose-Modus schon hier feststellen */ while (scanned < argc) { /* Parameter "-v" (ausfuehrlichere Meldungen) */ if (strcmp(argv[scanned], "-v") == 0) { bVerbose = TRUE; } ++scanned; } VMSG("--- Verbose logging started !\n"); VMSG("--- Reading ini-file ...\n"); if (read_init_file(argc, argv)) return(TRUE); /* if (tnn_errfile[0] != NUL) { } */ VMSG("--- Allocating mem for %u buffers ...\n", tnn_buffers); RAMBOT = (char *)malloc(tnn_buffers * sizeof(MAX_BUFFER)); RAMTOP = RAMBOT + tnn_buffers * sizeof(MAX_BUFFER); if (RAMBOT == NULL) { VMSG("!!! Allocation mem for %ld buffers failed, trying to allocate for %u buffers now ...\n", tnn_buffers, TNN_BUFFERS); RAMBOT = (char *)malloc(TNN_BUFFERS * sizeof(MAX_BUFFER)); RAMTOP = RAMBOT + TNN_BUFFERS * sizeof(MAX_BUFFER); if (RAMBOT == NULL) { fprintf(stderr, "malloc for buffers failed\n"); exit(1); } else tnn_buffers = TNN_BUFFERS; } if (kiss_active) { VMSG("--- Initializing KISS-interfaces ...\n"); if (init_kisslink()) { free(RAMBOT); Break(); exit(1); } } #ifndef NO_WATCHDOG VMSG("--- Initializing watchdog ...\n"); watchdog_init(); #endif VMSG("--- Installing signal-handlers ...\n"); #ifdef DEBUG_MODUS signal(SIGSEGV, sigsegv); signal(SIGTERM, sigterm); signal(SIGPIPE, SigPipe); #endif signal(SIGHUP, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); gettimeofday(&tv, &tz); tv_old = tv; return(FALSE); } #ifndef NO_WATCHDOG /************************************************************************/ /* */ /* Watchdog - ein vom TNN-Hauptprogramm unabhaengiger Prozess muss */ /* regelmaessig vom Hauptprogramm Daten erhalten. Bleiben diese Daten */ /* laenger als 60s aus, wird TNN beendet. */ /* */ /************************************************************************/ static void watchdog_init(void) { } #endif /************************************************************************/ /* */ /* */ /************************************************************************/ void exit_hardware(void) { free(RAMBOT); if (kiss_active) exit_kisslink(); } #ifdef DEBUG_MODUS /************************************************************************/ /* Signalbehandlungsfunktion fuer das Signal SIGTERM */ /************************************************************************/ static void sigterm(int signo) { signal(SIGTERM, SIG_IGN); printf("sigterm\n"); quit_program(-1); } void sigsegv(int signo) { signal(SIGSEGV, SIG_IGN); printf("\nTheNetNode verursachte einen unbekannten Systemfehler!!!\n"); printf("Letzte Funktion war: %s\n", lastfunc); Break(); quit_program(-1); } /************************************************************************/ /* */ /* Signalbehandlungsfunktion fuer das Signal SIGPIPE */ /* */ /* Ursache, in bereits geschlossene Socket-Verbindung schreiben/lesen. */ /* */ /************************************************************************/ void SigPipe(int signo) { signal(SIGPIPE, SIG_IGN); Break(); } #endif /************************************************************************/ /* */ /* */ /************************************************************************/ int exit_all(void) { exit_mh(); /* MH-Liste sichern */ save_stat(); save_configuration(); personalmanager(SAVE, NULL, NULL); /* Pers. Daten fuer Convers */ /* noch laufende Shells killen */ for (userpo = (USRBLK *) usccpl.head; userpo != (USRBLK *) &usccpl; userpo = (USRBLK *) userpo->unext) { if (userpo->status != US_EXTP) /* externer Prozess aktiv? */ continue; kill((pid_t *)(userpo->child_pid), SIGKILL); /* Abbruch */ } /* Buffer freigeben */ free(RAMBOT); /* Ab hier stehen keine Buffer mehr zur Verfuegung, alles was mit Buffern */ /* zu tun hat, gibt nun nen Segfault ! */ if (kiss_active) exit_kisslink(); printf("\r\n"); return(0); } static void message_handler(void) { printf("\a\a\n\n*** ACHTUNG ***\n" "TheNetNode beenden mit ESC QUIT Enter im Konsolen-Fenster !!!.\n"); } BOOL CtrlHandler( DWORD fdwCtrlType ) { switch( fdwCtrlType ) { case CTRL_C_EVENT: message_handler(); return( TRUE ); // CTRL-CLOSE: confirm that the user wants to exit. case CTRL_CLOSE_EVENT: message_handler(); return( TRUE ); // Pass other signals to the next handler. case CTRL_BREAK_EVENT: message_handler(); return FALSE; case CTRL_LOGOFF_EVENT: message_handler(); return FALSE; case CTRL_SHUTDOWN_EVENT: message_handler(); return FALSE; #ifdef DEBUG_MDOUS case SIGSEGV: sigsegv(fdwCtrlType); return FALSE; #endif default: return FALSE; } } void console_titel(void) { TCHAR szOldTitle[MAX_PATH]; TCHAR szNewTitle[MAX_PATH]; char call[10]; call2str(call,myid); if( GetConsoleTitle(szOldTitle, MAX_PATH) ) { wsprintf(szNewTitle, TEXT("%s%s)"), signon,call); if( !SetConsoleTitle(szNewTitle) ) printf("SetConsoleTitle failed (%d)\n", GetLastError()); } } /* Code vom Stefan DAC922. */ void gettimeofdaywindows(struct timeval *tv, struct timezone *tz) { SYSTEMTIME systm; FILETIME ftm; LONGLONG ll; GetSystemTime(&systm); if (!SystemTimeToFileTime(&systm,&ftm)) exit(1); ll = (LONGLONG) ftm.dwHighDateTime; ll <<= 32; ll |= (LONGLONG) ftm.dwLowDateTime; ll -= 116444736000000000; ll /= 10000000; tv->tv_sec = (long) ll; tv->tv_usec = (long) systm.wMilliseconds * 1000; } void kill(HANDLE Handle, WORD flag) { TerminateProcess(Handle, flag); _endthread(); } /* Ersatz fuer "system("pause"), bei Fernsteuerung */ /* eines Knotens kann man schlecht eine Taste druecken. */ void Break(void) { time_t lasttime; time_t now; now = time(NULL); lasttime = time(NULL); while (lasttime + 10 > now) { now = time(NULL); } } #ifdef L1TCPIP /* Pruefe auf TCPIP-Port's */ int CheckPortTCP(int port) { switch(kissmode(port)) { #ifdef L1TELNET case KISS_TELNET : return(TRUE); #endif /* L1TELNET */ #ifdef L1HTTPD case KISS_HTTPD : return(TRUE); #endif /* L1HTTPD */ #ifdef L1IPCONV case KISS_IPCONV : return(TRUE); #endif /* L1IPCONV */ #ifdef L1IRC case KISS_IRC : return(TRUE); #endif /* L1IRC */ default : return(FALSE); } return(FALSE); } #endif /* L1TCPIP */ /* Dummy-Funktionen */ ULONG coreleft(void) { return(FALSE); } void init_timer(void) {} void DIinc(void) {} void decEI(void) {} void exit_timer(void) {} void init_rs232(void) {} /* End of os/win32/win32.c */