*/
/********************************************************/
/* */
+/* Procedure to free memory used by contact */
+/* */
+/********************************************************/
+PUBLIC CONTYP *tcp_freecontact(CONTYP *contact)
+
+{
+if (contact!=(CONTYP *)0) {
+ if (contact->channel>=0)
+ (void) close(contact->channel);
+ if (contact->peerip!=(char *)0)
+ (void) free(contact->peerip);
+ if (contact->locname!=(char *)0)
+ (void) free(contact->locname);
+ (void) free(contact);
+ contact=(CONTYP *)0;
+ }
+return contact;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
/* Procedure to send data to a tcp socket. */
/* return the number of character transmitted, is */
/* unable to send char return -1; */
errno=EAGAIN;
switch (errno) {
case EAGAIN :
- sent=send(contact->channel,buffer,parnum,MSG_DONTWAIT);
+ sent=send(contact->channel,buffer,parnum,0);
break;
default :
(void) fprintf(stderr,"Got '%02d' error=<%s> (errno='%d')\n",
case 1 : //waiting from contact
if ((contact->channel=soc_accept(binding,&addr))<0) {
(void) rou_alert(0,"%s Unable to open contact",OPEP);
- (void) free(contact);
- contact=(CONTYP *)0;
+ contact=tcp_freecontact(contact);
phase=999; //no contact
}
break;
- case 2 : //send signon to contact
+ case 2 : //check socket components
+ contact->locname=soc_getaddrname(contact->channel,true);
+ contact->peerip=soc_getaddrname(contact->channel,false);
+ if ((contact->locname==(char *)0)||(contact->peerip==(char *)0)) {
+ (void) rou_alert(0,"%s Unable to establish contact entities",OPEP);
+ contact=tcp_freecontact(contact);
+ phase=999; //no identity
+ }
+ break;
+ case 3 : //contact is good sending signon
if (contact!=(CONTYP *)0) { //always
- #define FMT "220 %s ESMTP %s-%s;\n"
+ #define FMT "%d %s ESMTP %s-%s; %s%s"
char signon[100];
- (void) snprintf(signon,sizeof(signon),FMT,"test",appname,rou_getversion());
+ (void) snprintf(signon,sizeof(signon),FMT,
+ SIGNON,contact->locname,
+ appname,rou_getversion(),
+ rou_ascsysstamp(time((time_t *)0)),CRLF);
if (tcp_write(contact,signon,strlen(signon))<0) {
(void) rou_alert(0,"%s Unable to send signon to remote",OPEP);
- (void) free(contact);
- contact=(CONTYP *)0;
+ contact=tcp_freecontact(contact);
phase=999; //no contact
}
#undef FMT
typedef struct {
int channel; //exchange channel handle
+ char *locname; //socket local hostname
+ char *peerip; //socket remote peer IP
SOCKADDR addr; //remote address (see getnameinfo)
SOCTYP *binding;//established contact context
}CONTYP;
+//procedure to free contact
+extern CONTYP *tcp_freecontact(CONTYP *contact);
+
//Transmit formated data to the contact channel
extern int tcp_write(CONTYP *contact,char *buffer,int parnum);
{
#define OPEP "modrec.c:contact"
-#define TESTL 30
+#define TESTL 8
CONTYP *contact;
int phase;
if ((hangup==true)||(reload==true))
break;
- printf("send string\n");
sprintf(buffer,"Remote pid=%d iter=%d/%d\n",getpid(),i,TESTL);
sent=tcp_write(contact,buffer,strlen(buffer));
- printf("string sent '%d'\n",sent);
if (sent<0) {
(void) rou_alert(0,"%s, Unable to send data to remote",OPEP);
break;
phase=0; //lets continue to check childs
break;
default : //SAFE Guard
- while (maxretry>0) {
- int remain;
-
- remain=0;
- for (int i=0;i<binding->iteration;i++) {
- (void) prc_nozombie();
- if (childs[i]==(pid_t)0)
- continue;
- if (prc_checkprocess(childs[i])==false) {
- childs[i]=(pid_t)0;
- continue;
- }
- remain++;
- (void) kill(childs[i],SIGTERM);
- }
- if (remain==0)
- break;
- (void) sleep(1);
- maxretry--;
- }
+ (void) prc_killchilds(childs,binding->iteration,maxretry);
proceed=false;
break;
}
#define OPEP "modrec.c:rec_handlesmtp"
#define LINE "---------------------------------"
-int maxretry; //how long checking sub process to be out
+pid_t *childs;
+int nbrbind;
SOCTYP **bindings;
int phase;
_Bool proceed;
-maxretry=30; //5 seconds max retry
+childs=(pid_t)0;
bindings=(SOCTYP **)0;
bindings=soc_mkbindinf(bindings,pro_smtp,"127.0.0.1","2525",3);
bindings=soc_mkbindinf(bindings,pro_smtp,"192.219.254.70","2525",3);
bindings=soc_mkbindinf(bindings,pro_smtp,"127.0.0.26","2626",1);
+nbrbind=rou_nbrlist((void **)bindings);
phase=0;
proceed=true;
+if (nbrbind==0) {
+ (void) rou_alert(0,"No bindings definition found! (config?)");
+ proceed=false;
+ }
while (proceed==true) {
switch (phase) {
case 0 : //looping forever email receiving processes
(void) rou_alert(0,LINE);
(void) prc_settitle("Emlrec Daemon");
(void) rou_alert(0,"Starting Emlrec daemon");
- if (bindings==(SOCTYP **)0) {
- (void) rou_alert(0,"No bindings definition found!");
- phase=999; //No need to go further
- }
+ childs=(pid_t *)calloc(nbrbind,sizeof(pid_t));
break;
case 1 : //Opening ALL channels
- for (SOCTYP **ptr=bindings;(*ptr)!=(SOCTYP *)0;ptr++) {
+ for (int i=0;i<nbrbind;i++) {
(void) prc_nozombie();
- if ((*ptr)->waiter==(pid_t)0)
+ if (childs[i]==(pid_t)0)
continue;
- if (prc_checkprocess((*ptr)->waiter)==false)
- (*ptr)->waiter=(pid_t)0;
+ if (prc_checkprocess(childs[i])==false)
+ childs[i]=(pid_t)0;
}
break;
case 2 : //starting restarting all waiter process
- for (SOCTYP **ptr=bindings;(*ptr)!=(SOCTYP *)0;ptr++) {
+ for (int i=0;i<nbrbind;i++) {
int offset;
offset=random()%10;
- if ((*ptr)->waiter!=(pid_t)0)
+ if (childs[i]!=(pid_t)0)
continue;
- (*ptr)->waiter=fork();
- if ((*ptr)->waiter==(pid_t)0) {
+ childs[i]=fork();
+ if (childs[i]==(pid_t)0) {
(void) closelog();
- (void) startwaiter(*ptr,offset);
+ (void) startwaiter(bindings[i],offset);
(void) exit(0);
}
(void) usleep(10000); //avoid avalanche
if ((hangup==false)&&(reload==false))
phase=0; //Normal process, lets restart
break;
- case 4 : //we got a signal
- for (SOCTYP **ptr=bindings;(*ptr)!=(SOCTYP *)0;ptr++) {
- if ((*ptr)->waiter==(pid_t)0)
- continue;
- if (prc_checkprocess((*ptr)->waiter)==false) {
- (*ptr)->waiter=(pid_t)0;
- continue;
- }
- if ((hangup==true)||(reload==true))
- (void) kill((*ptr)->waiter,SIGTERM);
- }
- break;
- case 5 : //making sur all waiter procees are gone
- maxretry--;
- (void) sleep(1);
- //(void) rou_alert(0,"JMPDBG cleanup! maxretry='%d'",maxretry);
- for (SOCTYP **ptr=bindings;(*ptr)!=(SOCTYP *)0;ptr++) {
- (void) prc_nozombie();
- if ((*ptr)->waiter==(pid_t)0)
- continue;
- if (prc_checkprocess((*ptr)->waiter)==true) {
- if (maxretry>0)
- phase--; //retrying
- }
- else
- (*ptr)->waiter=(pid_t)0;
- }
+ case 4 : //we got a signal, kill all childs
+ (void) prc_killchilds(childs,nbrbind,10);
break;
default : //SAFE Guard
(void) rou_alert(0,"Stopping Emlrec daemon");
(void) rou_alert(0,LINE);
+ if (childs!=(pid_t *)0)
+ (void) free(childs);
proceed=false;
break;
}
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
+#include <time.h>
#include <unistd.h>
#include "subrou.h"
//version definition
#define VERSION "0.3"
-#define RELEASE "14"
+#define RELEASE "15"
//Public variables
PUBLIC int debug=0; //debug level
return dropzone;
}
/*
+\f
+*/
+/********************************************************/
+/* */
+/* Procedure to transform the local system time in */
+/* ASCII time stamp. */
+/* Stored in STATIC memory area. */
+/* */
+/********************************************************/
+char *rou_ascsysstamp(time_t curtime)
+
+{
+#define TSTAMP "%a, %d %b %Y %T %z"
+
+static char ascstamp[100];
+
+(void) strftime(ascstamp,sizeof(ascstamp),TSTAMP,localtime(&curtime));
+return ascstamp;
+}
+/*
^L
*/
/********************************************************/
*/
/********************************************************/
/* */
-/* Subroutine to get add a pointer (not null) */
+/* Subroutine to count the number of items within */
+/* a list of pointer. */
+/* */
+/********************************************************/
+PUBLIC int rou_nbrlist(void **list)
+
+
+{
+int num;
+
+num=0;
+if (list!=(void **)0) {
+ while (*list!=(void *)0) {
+ num++;
+ list++;
+ }
+ }
+return num;
+}
+/*
+\f
+*/
+/********************************************************/
+/* */
+/* Subroutine to add a pointer (not null) */
/* to a list of pointer. */
/* */
/********************************************************/
//--- Routines implemented within subrou.c ---------
+//transform local system time in ASCII stamp.
+extern char *rou_ascsysstamp(time_t curtime);
+
//return program version
extern const char *rou_getversion();
//a NULL pointer
extern char *rou_freestr(char *str);
+//to return the number of element within a list
+extern int rou_nbrlist(void **list);
+
//to add a not null pointer to a list of pointer
extern void **rou_addlist(void **list,void *entry);
#ifndef UNIEML
#define UNIEML
+#define CRLF "\r\n" //EOL within SMTP protocol
#define SIGNON 220 //signon information
//homework to be done before starting/stopping module.
*/
/********************************************************/
/* */
+/* procedure to kill a set of process within a */
+/* list, return return the number of process */
+/* still up; */
+/* */
+/********************************************************/
+PUBLIC _Bool prc_killchilds(pid_t *childs,int num,int maxretry)
+
+{
+int remain;
+
+remain=num;
+while (maxretry>0) {
+ remain=0;
+ for (int i=0;i<num;i++) {
+ (void) prc_nozombie();
+ if (childs[i]==(pid_t)0)
+ continue;
+ if (prc_checkprocess(childs[i])==false) {
+ childs[i]=(pid_t)0;
+ continue;
+ }
+ remain++;
+ (void) kill(childs[i],SIGTERM);
+ }
+ if (remain==0)
+ break;
+ (void) sleep(1);
+ maxretry--;
+ }
+return remain;
+}
+/*
+^L
+*/
+/********************************************************/
+/* */
/* Procedure to set/unset a lock */
/* return true if successful, */
/* false otherwise. */
//routine to check if a proces is still up and running
extern _Bool prc_checkprocess(pid_t pidnumber);
+//Routine to kill a list of subprocess
+extern _Bool prc_killchilds(pid_t *childs,int num,int maxretry);
+
//lock application (to avoid running multiple daemon)
extern _Bool prc_locking(const char *lockname,int lock,int tentative);
/* Procedure fine the hostname related to an */
/* address, if local is true return the local */
/* hostname. */
+/* if trouble, return a NULL pointer. */
/* */
/********************************************************/
-PUBLIC char *soc_getaddrname(int handle,_Bool local,const char *unknown)
+PUBLIC char *soc_getaddrname(int handle,_Bool local)
{
#define OPEP "unisoc.c:soc_getaddrname"
int status;
char host[NI_MAXHOST];
-name=(char *)unknown;
-if (name==(char *)0)
- name="NO_HOST_NAME";
+name=(char *)0;
taille=sizeof(connip);
if (local==true) {
if ((status=getsockname(handle,&connip,&taille))==0) {
if (getnameinfo(&connip,taille,host,sizeof(host),(char *)0,0,NI_NAMEREQD)==0)
- name=host;
+ name=strdup(host);
}
}
else {
if ((status=getpeername(handle,&connip,&taille))==0) {
if (getnameinfo(&connip,taille,host,sizeof(host),(char *)0,0,NI_NUMERICHOST)==0)
- name=host;
+ name=strdup(host);
}
}
if (status<0) {
break;
}
}
-return strdup(name);
+return name;
#undef OPEP
}
/*
time_t lasttry; //successful binding last time
int iteration; //number of soc slot used on the IP
int handle; //connexion handle
- pid_t waiter; //binding manager
}SOCTYP;
//procedure to get peer or local name related to a socket
-extern char *soc_getaddrname(int handle,_Bool local,const char *unknown);
+extern char *soc_getaddrname(int handle,_Bool local);
//procedure to free all memory used by a TCP socket
//definition (once closed)