Ein Programm ausführen wenn ein UDP-Paket eintrifft
Das folgende Programm wartet auf ein UDP-Paket an einem angegebenen Port. Sobald dort ein Paket eintrifft, wird ein Script oder Programm ausgeführt.
Aufruf
$ ./udpexecute 7777 /bin/echo works fine! udpexecute V1.00 works fine! works fine!
- 7777 ist das Port
- /bin/echo wird ausgeführt wenn ein Paket eintrifft
- works ist das erste Argument für /bin/echo
- fine! ist das zweite Argument für /bin/echo
Das angegebene Programm muss entweder ein ELF oder ein Script mit einem Shebang sein. echo allein funktioniert nicht, weil es ein Shell-Builtin ist.
Alle Argumente werden unverändert weitergereicht.
Source
Der Code sollte weitgehend selbsterklärend sein für Leute die C kennen, und schon einmal auf Linux entwickelt haben.
/******************************************************************************/ /* */ /* FILE: udpexecute.cpp */ /* */ /* Executes a program when a UDP packet is received */ /* ================================================ */ /* */ /* V1.00 24-APR-2018 Te */ /* */ /******************************************************************************/ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> /****************************/ int CreateSocket( int port ) /****************************/ { // Create a socket int sock = socket( AF_INET, SOCK_DGRAM, 0 ) ; if( sock == -1 ) { fprintf( stderr, "CreateSocket: socket failed\n" ) ; return -1 ; } // Bind it to the local address struct sockaddr_in address ; memset( &address, 0, sizeof(address) ) ; address.sin_family = AF_INET ; address.sin_addr.s_addr = htonl( INADDR_ANY ) ; address.sin_port = htons( port ) ; if( bind(sock,(struct sockaddr *)&address,sizeof(address)) == -1 ) { fprintf( stderr, "CreateSocket: bind failed\n" ) ; close( sock ) ; return -1 ; } return sock ; } /**********************************/ int main( int argc, char *argv[] ) /**********************************/ { fprintf( stderr, "udpexecute V1.00\n" ) ; if( argc < 3 ) { fprintf( stderr, "usage: %s port program [args]\n", argv[0] ) ; return 1 ; } int socket = CreateSocket( atoi(argv[1]) ) ; if( socket == -1 ) { fprintf( stderr, "error: can't create socket\n" ) ; return 2 ; } struct sockaddr_in address ; char line[256] ; int status ; int size ; for( ;; ) { socklen_t length = sizeof( address ) ; size = recvfrom( socket, line, sizeof(line), 0, (struct sockaddr *)&address, &length ) ; if( size < 1 ) { fprintf( stderr, "error: recvfrom failed\n" ) ; break ; } pid_t pid = fork() ; switch( pid ) { case -1: fprintf( stderr, "fork failed\n" ) ; break ; case 0: execv( argv[2], argv + 2 ) ; fprintf( stderr, "exec failed: %s\n", strerror(errno) ) ; break ; default: wait( &status ) ; break ; } } close( socket ) ; return 0 ; }
Build
Builden ist einfach:
g++ -o udpexecute udpexecute.cpp
Download
Source von udpexecuteUpdate vom 2. August 2020
Auf Anregung eines Users habe ich die Argumente durch den Inhalt des UDP-Pakets ersetzt. Das hat mich aber nicht so recht überzeugt, und deshalb gibt es jetzt eine Version mit Argumenten und zusätzlich dem Inhalt des Frames. Im gleichen Zug ist auch die IP-Adresse des Absenders hinzugekommen.
/******************************************************************************/ /* */ /* FILE: udpexecute.cpp */ /* */ /* Executes a program when a UDP packet is received */ /* ================================================ */ /* */ /* V1.00 24-APR-2018 Te */ /* V1.10 26-JUL-2020 Te Replaced arguments with content of UDP packet */ /* V1.20 02-AUG-2020 Te Added content and IP address to arguments */ /* */ /******************************************************************************/ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> /****************************/ int CreateSocket( int port ) /****************************/ { // Create a socket int sock = socket( AF_INET, SOCK_DGRAM, 0 ) ; if( sock == -1 ) { fprintf( stderr, "CreateSocket: socket failed\n" ) ; return -1 ; } // Bind it to the local address struct sockaddr_in address ; memset( &address, 0, sizeof(address) ) ; address.sin_family = AF_INET ; address.sin_addr.s_addr = htonl( INADDR_ANY ) ; address.sin_port = htons( port ) ; if( bind(sock,(struct sockaddr *)&address,sizeof(address)) == -1 ) { fprintf( stderr, "CreateSocket: bind failed\n" ) ; close( sock ) ; return -1 ; } return sock ; } /****************************************************************/ void Execute( int argc, char *argv[], char *line, in_addr addr ) /****************************************************************/ { int index = 0 ; char *args[argc+1] ; for( int i = 2; i < argc; i++ ) args[index++] = argv[i] ; args[index++] = line ; args[index++] = inet_ntoa( addr ) ; args[index] = NULL ; execv( args[0], args ) ; fprintf( stderr, "exec failed: %s\n", strerror(errno) ) ; } /**********************************/ int main( int argc, char *argv[] ) /**********************************/ { fprintf( stderr, "udpexecute V1.20\n" ) ; if( argc < 3 ) { fprintf( stderr, "usage: %s port program [args]\n", argv[0] ) ; return 1 ; } int socket = CreateSocket( atoi(argv[1]) ) ; if( socket == -1 ) { fprintf( stderr, "error: can't create socket\n" ) ; return 2 ; } struct sockaddr_in address ; char line[256] ; int status ; int size ; for( ;; ) { socklen_t length = sizeof( address ) ; size = recvfrom( socket, line, sizeof(line)-1, 0, (struct sockaddr *)&address, &length ) ; if( size < 1 ) { fprintf( stderr, "error: recvfrom failed\n" ) ; break ; } line[size] = '\0' ; pid_t pid = fork() ; switch( pid ) { case -1: fprintf( stderr, "fork failed\n" ) ; break ; case 0: Execute( argc, argv, line, address.sin_addr ) ; break ; default: wait( &status ) ; break ; } } close( socket ) ; return 0 ; }
Builden und Ausführen geht genau gleich wie bisher, aber das Programm bekommt zwei zusätzliche Argumente:
$ ./udpexecute 7777 /bin/echo hello udpexecute V1.20 hello world 192.168.1.60