Eine Frage des guten Codes

Hallo zusammen.

Vor ein paar Tagen habe ich festgestellt das meine VPN Verbiundungen ab einer bestimmten
Verbindungszahl nicht mehr aufgebaut wurden. Das Problem war einfach das die Bandbreite
für den gleichzeitigen Aufbau von n Verbindungen nicht reicht.
Die Lösung, recht einfach: Die Verbindungen einfach mit einem bestimmten Zeitabstand voneinander Starten.

Zum Starten einer Verbindung muss man auf der Kommandozeile folgenden Befehl eingeben:

Code:
   > ipsec auto --up "verbindungsname"

Die Sache ist nur die, dass nun solange auf der Kommandozeile Meldungen gemacht werden bis der Befehl erfogreich ausgeführt wurde. Das bedeutet aber auch das solange dies nicht der Fall ist, der Befehl aktiv ist und die Konsole blockiert.

Man kann dem Befehl auch einfach mit STRG-C abrrechen, damit wird die Verbindung dann im Hintergrund automatisch weiter ausgeführt.

( JA ICH WEISS VIEL BLA BLA ! :) )

Also gut ich wollte ein Programm schreiben das folgendes machen sollte:
1 Einlesen der Datei /etc/ipsec.conf
2 Suchen aller Verbindungsnamen (haben immer folgendes Format: "conn name\n")
3 Für jeden Verbindungsname ipsec auto --up "verbindungsname" ausführen
4 Diesen Befehl nach einer gewissen Zeit beenden

Schritt 3 und 4 sollen dabei für jeden gefunden Verbindungsnamen ausgeführt werden.

Folgendes ist dabei herausgekommen:

Code:
#include <pthread.h>
#include "eighdr.h"   //Enthält nur ein paar Makros und Funktions-Prototypen 
                      //benötigt wird aber nur fehler_meld
#include <signal.h>

#define WAIT_TIME 12  //Zeitintervall in dem die Verbindungen gestartet werden
#define BUFFER 255

void vpn();
void chomp(char *);

pid_t pid;
char  *connection;

int main(){
   pthread_t thread;
   FILE  *fz;     
      
   char buffer[BUFFER];
   char *tok;
   char *exclude1 = "block";   
   char *exclude2 = "private";   
   char *exclude3 = "private-or-clear";   
   char *exclude4 = "clear-or-private";   
   char *exclude5 = "clear";   
   char *exclude6 = "packetdefault";
      
   // ipsec .conf Datei öffnen
   if( (fz = fopen("/etc/ipsec.conf", "r")) == NULL)
      fehler_meld(FATAL_SYS, "Konnte ipsec.conf nicht öffen\n");
      
      //Datei Zeilenweise auslesen
      while( fgets(buffer,BUFFER, fz) != NULL ) {
         // Ersten Token aus String exrtrahieren
         tok = strtok(buffer, " ");
           
         // Prüfen ob Zeile eine Verbindungsdefinition ist
         // (erster Token muss gleich "conn" sein)
         if( strcmp(tok, "conn") != 0 )
            continue;
         
         // Verbindungsname extrahieren   
         connection = strtok(NULL, " ");
         // vom Verbindungsname "\n" entfernen
         chomp(connection);
         
         // Verbindungen die ausgelassen werden sollen werden hier
         // heraus gefiltert.
         if( strcmp(connection,exclude1) == 0 ||      
             strcmp(connection,exclude2) == 0 || 
             strcmp(connection,exclude3) == 0 ||
             strcmp(connection,exclude4) == 0 ||
             strcmp(connection,exclude5) == 0 ||
             strcmp(connection,exclude6) == 0
         ) continue;         
   
         if(pthread_create(&thread, NULL, (void *)&vpn, (void *) NULL) != 0) 
            fehler_meld(FATAL_SYS, "Fehler bei Thread Erstellung......");
   
         // Auf Beendigung des Threads warten.
         pthread_join(thread, NULL);
   } 
   
   return(0);
}

void vpn() {
   
   // fork() für execl aufrufen
   if( (pid = fork()) < 0 )
      fehler_meld(FATAL_SYS, "Fehler bei fork()\n");
            
   if(pid==0){
      printf("Starte Verbindung %s...\n", connection);       
   
      // Standartausgabe unterdrücken
      if (freopen("/dev/null", "a", stdout) != stdout)
            fehler_meld(FATAL_SYS, "Fehler bei freopen mit stdout");
            
         // Auszuführender Befehl
         char cmd[100] = "ipsec auto --up ";
         
         // Argument für Befehl anhängen
         strcat(cmd, connection);
         
         // Befehl ausführen
         execl("/bin/sh", "sh", "-c", cmd, NULL);
   }
   else{
      // WAIT_TIME warten und danach Prozess der durch execl 
      // überlagert wird beenden
      sleep(WAIT_TIME);
      kill(pid, SIGINT);
      
      //Thread verlassen.
      pthread_exit((void *) 0);
   }
}

void chomp(char *str) {
   size_t p=strlen(str);
   /* \n mit \0 überschreiben */
   str[p-1]='\0';
}

Dieses Programm Funtkioniert auch einwandfrei, aber ich Frage mich nur ob der Aufwand nicht einfach viel zu groß ist und ob man das Problem nicht in einer etwas eleganteren Art und Weise hätte Lösen können.

Ich habe z.B auch versucht ohne Threads auszukommen aber dann hatte ich immer Probleme damit die
Verbindungsnamen zu übergeben etc.


Ich danke schon einmal im Voraus für hoffentlich kommende Kommentare

MFG Blackbird
 
Hallo,
so wie ich das beurteilen kann startest du für jeden Verbindungsnamen eine neue Verbindung
wartest 12 Sekunden und tötest die dann wieder, right?
Da frag ich mich wieso du überhaupt Threads und fork verwendest?
Kannst du nicht einfach eine Schleife mit all den gewünschten Verbindungen
durchlaufen lassen, die den Prozess ipsec jeweils in deiner Schleife von der Shell
aus mittels "&" und der Funktion system() im Hintergrund starten, in deinem Programm 12 sec
warten, den Prozess wieder töten, und dann die Schleife bei dem nächsten Verbindungsnamen
neu beginnen?
Wenn ich da was falsch verstanden hab dann sorry...

Gruß

RedWing

P.S. Das sollte sich auch mit einem Shellskript erledigen lassen, denke ich...
 
Zuletzt bearbeitet:
Stimmt das könnte ich so machen habe das Programm aber zum Üben mal ein wenig komplexer gemacht, außer das mit den Threads war nicht beabsichtigt.
Wollte eigentlich nur mit fork() auskommen aber da hatte ich Probleme die Verbindunsnamen zu übergeben.

Ich meine system() ist ja auch eigentlich nichts anderes als ein fork() und ein exec().
Wenn ich aber nur system() benutze woher soll ich denn dann die PID des ipsec Prozesses wissen diese wird ja nicht von system zurück gegeben?

mfg Blackbird
 
Wenn ich aber nur system() benutze woher soll ich denn dann die PID des ipsec Prozesses wissen diese wird ja nicht von system zurück gegeben?

Die brauchst du nicht...

Um den Prozess zu töten einfach wieder ein system("killall processname"); ;)

Fork gibt dir ja auch nicht die PID des eigentlich von dir mit execl gestarteten Prozess zurück
sondern nur die ID des Kindprozesses deines Programmes.

Gruß

RedWing
 
Hier ist zwar ein C/C++ Forum, abe ich denke sowas könnte man mit PERL eleganter lösen, da PERL auch Thread- und Prozesshandling unterstützt.

Gruß Daniel
 
Wenn du einen fork() ausführst dann liefert dir fork() für den Vaterprozess die PID des neuen Kindprozesses zurück und für den Kindprozess 0. Wenn du nun im Kindprozess execl aufrufst dann wird der Kindprozess mit dem Prozess der den ipsec Befehl ausführt überlagert und besitzt damit auch die selbe PID.
Also bekomme ich von fork() genau die PID zurück um dem ipsec Befehl zu beenden!

Aber was macht denn system("killall processname") und was muss für processname angeben werden?
 
Hi Daniel,
von Perl habe ich gerade ein wenig Pause :-), habe eine WEB-CGI Verwaltung für ISDN und VPN Verbindungen unter Linux geschrieben wobei alle Verbindungsdaten aus einer LDAP Datenbank kommen und auf beliebigen Linux Rechnern eingetragen werden können.

Habe mehr als 6000 Zeilen dafür gecodet :rolleyes:
Aber der Nachteil bei Threads unter Perl ist erstens der das sie nicht ganz so effizient sind, aber vor allem immer die Module installiert werden müssen!
 
blackbirdthefirst hat gesagt.:
Wenn du einen fork() ausführst dann liefert dir fork() für den Vaterprozess die PID des neuen Kindprozesses zurück und für den Kindprozess 0. Wenn du nun im Kindprozess execl aufrufst dann wird der Kindprozess mit dem Prozess der den ipsec Befehl ausführt überlagert und besitzt damit auch die selbe PID.
Also bekomme ich von fork() genau die PID zurück um dem ipsec Befehl zu beenden!
Ja da is klar
Aber was macht denn system("killall processname") und was muss für processname angeben werden?
Code:
man killall
für processname = ipsec

Gruß

RedWing
 
Zurück