/* k8056ned UDP SERVER By FG 2011 v1.3d */ /* Usage : k8056netd [-h] [-v] [-V] [-d device] [-p PORT] */
/* -- Synoptique -- */ /* On Demonize */ /* Ecoute Port */ /* Si données */ /* Appel le fils */ /* Verification */ /* Mise en forme */ /* transmission vers k8056 */ /* tue le fils */ /* retour ecoute */
/* modif 369 et 373 pf_net par af_net + IPPROTO_UDP + verbose dans la console debug dans le syslog */
/*------------------------------------------------------------------------------*/ /* Includes */ /*------------------------------------------------------------------------------*/
#include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <netdb.h> #include <errno.h> #include <arpa/inet.h> #include <unistd.h> #include <termios.h> #include <math.h> #include <fcntl.h> #include <pwd.h> #include <signal.h> #include <syslog.h>
/*------------------------------------------------------------------------------*/ /* Definitions */ /*------------------------------------------------------------------------------*/ #define MSGSIZE 2 #define BAUDRATE B2400 #define NPACK 10 /* Change this to whatever your daemon is called */ #define DAEMON_NAME "k8056netd"
/* Change this to the user under which to run */ #define RUN_AS_USER "root"
#define EXIT_SUCCESS 0 #define EXIT_FAILURE 1
/*------------------------------------------------------------------------------*/ /* Variables */ /*------------------------------------------------------------------------------*/ struct termios oldtio, newtio ; int k8056_port ; char k8056_device[16] = "/dev/k8056" ; /* default device. */ unsigned char k8056_instruction = 'E'; unsigned char k8056_addr = 1 ; unsigned char k8056_relay_address = '0' ; int k8056_trame_number = 5 ; /* Increase value with a long serial cable or in wireless operation. */ int verbose = 0 ; int debug = 0 ; char cmd[6] ; int Taillecmd ;
int sockfd, cc; unsigned int addr_in_size; u_short portnum = 12345; struct sockaddr_in *my_addr, *from; char *msg; u_long fromaddr;
/*------------------------------------------------------------------------------*/ /* Affiche l'aide */ /*------------------------------------------------------------------------------*/ void usage (void) { printf("\nk8056ned Usage: k8056netd [-h] [-v] [-V] [-d device] [-p PORT] \n"); printf(" Pour plus de details utiliser l'aide: k8056netd -h\n\n"); printf(" Version 1.3c\n\n"); }
void help (void) { printf("\nk8056netd controle la carte 'Velleman K8056' via UDP (Version Francaise par FOURNIER Ghislain - 2011 \n\n"); printf("Usage: k8056netd [-h] [-v] [-d device] [-p PORT] \n\n"); printf(" -h : Aide\n"); printf(" -v : Mode verbeux\n"); printf(" -V : Debug\n"); printf(" -d device : Rs232 port, par defaut /dev/k8056 (A faire: : ln -s /dev/ttyS0 /dev/k8056 par exemple)\n"); printf(" -p port : UDP port, par defaut 180472 \n"); printf(" ** Command examples **\n"); printf(" k8056netd -d /dev/ttyS14 -p 1234 : Controle la carte sur port série /dev/ttyS14, recoie les données sur le port udp 1234.\n\n"); printf(" Version 1.3c\n\n"); }
/*------------------------------------------------------------------------------*/ /* Ouverture port serie */ /*------------------------------------------------------------------------------*/ void initserie (void) { if (verbose) printf("Ouverture du port\n"); if (debug) syslog( LOG_INFO, "Ouverture du port serie" ); k8056_port = open(k8056_device, O_RDWR | O_NOCTTY ); if (k8056_port < 0) { if (verbose) { fprintf(stderr, "Erreur d'ouverture du peripherique %s !\n", k8056_device) ; } exit(-1); } tcgetattr(k8056_port,&oldtio); /* Sauvegarde des parametres courants du port */
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD; newtio.c_oflag = 0; tcflush(k8056_port, TCOFLUSH); /* Flushes written but not transmitted. */ tcsetattr(k8056_port, TCSANOW, &newtio); }
/*------------------------------------------------------------------------------*/ /* Checksum (complement à 2 de la somme de 4 octets + 1) */ /*------------------------------------------------------------------------------*/ unsigned char checksum(char cmd[]) { unsigned char checksum ; /* Ex. VB: checksum = ( 255 - ( ( ( (a+b+c+d / 256 ) - Int( (13 + cmd[1] + cmd[2] + cmd[3]) / 256 ) ) * 256 ) ) + 1 ; */ /* ( 255 - ((a+b+c+d) modulo 256) ) + 1 Calcul de checkum (complement à 2 de la somme de 4 octets + 1). */ if (verbose) printf("Calcul Checksum\n"); checksum = ~((13 + cmd[1] + cmd[2] + cmd[3]) & 0xFF) + 1 ; return checksum ; }
/*------------------------------------------------------------------------------*/ /* SendCommand Send command to k8056 card */ /*------------------------------------------------------------------------------*/ void SendCommand(char cmd[]) { if (debug) syslog( LOG_INFO, "Send command to k8056" ); int i ; tcflush(k8056_port, TCOFLUSH) ; /* Flushes written but not transmitted. */ for (i=0 ; i < k8056_trame_number ; i++) { write(k8056_port, cmd, 5) ; if (verbose) printf(". %d \n",i) ; if (verbose) { printf(" Donnees envoyer = %s \n",cmd) ; Taillecmd = strlen (cmd); printf(" Taille Donnees = %d \n",Taillecmd) ; } if (verbose) printf("Ecriture sur le port\n"); if (verbose) printf("Pause entre deux Ecriture\n"); usleep(5000) ; } }
/*------------------------------------------------------------------------------*/ /* Parse de la ligne de commande pour les arguments otionnels */ /*------------------------------------------------------------------------------*/ char parse_cmdline(int argc,char *argv[]) { int helpflg=0; int errflg=0; int c;
while ((c = getopt(argc, argv, "d:p:hvV")) != EOF) { switch (c) { case 'd': strcpy(k8056_device, optarg) ; break; case 'p': portnum = atoi(optarg); break; case 'v': verbose = 1; break; case 'V': debug = 1; break; case 'h': helpflg++; break; case '?': errflg++; break; } if (helpflg) /* Aide */ { help(); exit (1); } } //if (optind < 2 || errflg) /* Usage */ if (errflg) /* Usage */ { usage(); exit (1); } return 1; }
/*------------------------------------------------------------------------------*/ /* Preparation a l'envoi des données */ /*------------------------------------------------------------------------------*/ void sendserie(char msg[]) {
if (verbose) { printf(" Données reçues = %d \n",msg[0]) ; }
if (verbose) { fprintf(stdout,"Réception de %s port %d: %s\n", (gethostbyaddr((char *)&fromaddr, sizeof(fromaddr), PF_INET))->h_name, from->sin_port,msg); }
if (verbose) printf("Envoi commande vers la carte k8056:\n Port: %s, Addresse carte: %d, Instruction: %c, Relais #%c\n" , k8056_device, k8056_addr, msg[0], msg[1]) ;
cmd[0] = 13 ; /* 13 */ cmd[1] = k8056_addr ; /* Adresse */ cmd[2] = msg[0] ; /* Instruction */ cmd[3] = msg[1] ; /* # relais, addresse ou status */ cmd[4] = checksum(cmd) ; /* Checksum */
if (verbose) printf(" Checksum = %d\n", checksum(cmd)) ;
SendCommand(cmd) ; if (debug) syslog( LOG_INFO, "Send command fait" );
/* Fermeture port serie */ tcsetattr(k8056_port, TCSANOW, &oldtio); /* Sauvegarde des anciens parametres du port */ if (verbose) printf("Fermeture du port\n"); close(k8056_port); if (verbose) printf("Pause entre deux commandes\n"); usleep(300000) ; /* Pause entre 2 commandes. */ if (verbose) printf("Fait\n"); if (verbose) printf(".\n");
}
/*------------------------------------------------------------------------------*/ /* Gestion des zombies */ /*------------------------------------------------------------------------------*/ static void child_handler(int signum) { switch(signum) { case SIGALRM: exit(EXIT_FAILURE); break; case SIGUSR1: exit(EXIT_SUCCESS); break; case SIGCHLD: exit(EXIT_FAILURE); break; } }
/*------------------------------------------------------------------------------*/ /* Daemonization */ /*------------------------------------------------------------------------------*/ static void daemonize( const char *lockfile ) { pid_t pid, sid, parent; int lfp = -1;
/* already a daemon */ if ( getppid() == 1 ) return;
/* Create the lock file as the current user */ if ( lockfile && lockfile[0] ) { lfp = open(lockfile,O_RDWR|O_CREAT,0640); if ( lfp < 0 ) { syslog( LOG_ERR, "unable to create lock file %s, code=%d (%s)", lockfile, errno, strerror(errno) ); exit(EXIT_FAILURE); } }
/* Drop user if there is one, and we were run as root */ if ( getuid() == 0 || geteuid() == 0 ) { struct passwd *pw = getpwnam(RUN_AS_USER); if ( pw ) { syslog( LOG_NOTICE, "setting user to " RUN_AS_USER ); setuid( pw->pw_uid ); } }
/* Trap signals that we expect to recieve */ signal(SIGCHLD,child_handler); signal(SIGUSR1,child_handler); signal(SIGALRM,child_handler);
/* Fork off the parent process */ pid = fork(); if (pid < 0) { syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)", errno, strerror(errno) ); exit(EXIT_FAILURE); } /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) {
/* Wait for confirmation from the child via SIGTERM or SIGCHLD, or for two seconds to elapse (SIGALRM). pause() should not return. */ alarm(2); pause();
exit(EXIT_FAILURE); }
/* At this point we are executing as the child process */ parent = getppid();
/* Cancel certain signals */ signal(SIGCHLD,SIG_DFL); /* A child process dies */ signal(SIGTSTP,SIG_IGN); /* Various TTY signals */ signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */ signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
/* Change the file mode mask */ umask(0222);
/* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { syslog( LOG_ERR, "unable to create a new session, code %d (%s)", errno, strerror(errno) ); exit(EXIT_FAILURE); }
/* Change the current working directory. This prevents the current directory from being locked; hence not being able to remove it. */ if ((chdir("/")) < 0) { syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)", "/", errno, strerror(errno) ); exit(EXIT_FAILURE); }
/* Redirect standard files to /dev/null */ freopen( "/dev/null", "r", stdin); freopen( "/dev/null", "w", stdout); freopen( "/dev/null", "w", stderr);
/* Tell the parent process that we are A-okay */ kill( parent, SIGUSR1 ); }
/*------------------------------------------------------------------------------*/ /* MAIN Ecoute reception données UDP */ /*------------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { /* Initialize the logging interface */ openlog( DAEMON_NAME, LOG_PID, LOG_LOCAL5 ); syslog( LOG_INFO, "starting k8056netd" );
/* One may wish to process command line arguments here */ parse_cmdline(argc,argv) ;
addr_in_size = sizeof(struct sockaddr_in);
// Détournement du signal émis à la mort du fils (il ne reste pas zombie) // signal(SIGCHLD, SIG_IGN);
msg = (char *)malloc(MSGSIZE);
from = (struct sockaddr_in *)malloc(addr_in_size); my_addr = (struct sockaddr_in *)malloc(addr_in_size);
memset((char *)my_addr,(char)0,addr_in_size); my_addr->sin_family = AF_INET; my_addr->sin_addr.s_addr = htonl(INADDR_ANY); my_addr->sin_port = htons(portnum);
if((sockfd = socket (PF_INET, SOCK_DGRAM, 0)) < 0){
if (verbose) fprintf(stderr,"Erreur %d dans socket: %s\n",errno,strerror(errno)); exit(errno); };
if(bind(sockfd, (struct sockaddr *)my_addr, addr_in_size) < 0){ if (verbose) fprintf(stderr,"Erreur %d dans bind: %s\n",errno,strerror(errno)); if(errno != EADDRINUSE) exit(errno); };
/* On daemonize */ if (debug) syslog( LOG_INFO, "daemonize k8056netd" ); daemonize( "/var/lock/" DAEMON_NAME );
/* Now we are a daemon -- do the work for which we were paid */
if (verbose) fprintf(stdout,"Prêt a reçevoir\n"); if (debug) syslog( LOG_INFO, "On ecoute le port UDP" ); while(1){ if (debug) syslog( LOG_INFO, "On est dans la boucle" ); if((cc = recvfrom (sockfd,msg,MSGSIZE,0,(struct sockaddr *)from, &addr_in_size)) == -1){ if (verbose) fprintf(stderr,"Erreur %d dans recvfrom: %s\n", errno,strerror(errno)); exit(errno); };
fromaddr = from->sin_addr.s_addr; msg[cc] = '\0';
if (verbose) fprintf(stdout,"Reçue de %s port %d: %s\n", (gethostbyaddr((char *)&fromaddr, sizeof(fromaddr), PF_INET))->h_name, from->sin_port,msg);
if (debug) syslog( LOG_INFO, "Reçue de %s port %d: %s\n", (gethostbyaddr((char *)&fromaddr, sizeof(fromaddr), PF_INET))->h_name, from->sin_port,msg); /* Ouverture port serie */ initserie() ; if (debug) syslog( LOG_INFO, "init serie fait" );
/* Formate msg vers cmd et envoie */ sendserie(msg); if (debug) syslog( LOG_INFO, "Send serie fait" );
/* on attend avant de revenir a l'ecoute */ sleep(3); if (debug) syslog( LOG_INFO, "On repart" ); // signal(SIGCHLD,SigCatcher); /* Finish up */ if (debug) syslog( LOG_NOTICE, "terminated" ); closelog();
} /* Quitt... */ if (verbose) printf("----- ICI ON SORT -----\n");
return 0;
}
/*------------------------------------------------------------------------------*/
|