00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024 #include <time.h>
00025 #include <poll.h>
00026 #include "ha.h"
00027 #include "seas.h"
00028 #include "../../mem/mem.h"
00029 #include "../../mem/shm_mem.h"
00030
00031
00032
00033
00034 char *jain_ping_config=0;
00035 int jain_ping_period=0;
00036 int jain_pings_lost=0;
00037 int jain_ping_timeout=0;
00038
00039 char *servlet_ping_config=0;
00040 int servlet_ping_period=0;
00041 int servlet_pings_lost=0;
00042 int servlet_ping_timeout=0;
00043
00044 int use_ha=0;
00045 pid_t pinger_pid;
00046
00047 static inline int parse_ping(char * string,int *ping_period,int *pings_lost,int *ping_timeout);
00048 static inline int send_ping(struct as_entry *the_as,struct timeval *now);
00049
00050
00051
00052
00053
00054
00055 int prepare_ha(void)
00056 {
00057 use_ha=0;
00058 if(!(jain_ping_config || servlet_ping_config)){
00059 jain_pings_lost=servlet_pings_lost=0;
00060 return 0;
00061 }
00062 if(parse_ping(jain_ping_config,&jain_ping_period,&jain_pings_lost,&jain_ping_timeout)<0)
00063 goto error;
00064 if(parse_ping(servlet_ping_config,&servlet_ping_period,&servlet_pings_lost,&servlet_ping_timeout)<0)
00065 goto error;
00066 LM_DBG("jain: pinging period :%d max pings lost:%d ping timeout:%d\n",
00067 jain_ping_period,jain_pings_lost,jain_ping_timeout);
00068 LM_DBG("servlet: pinging period:%d max pings lost:%d ping timeout:%d\n",
00069 servlet_ping_period,servlet_pings_lost,servlet_ping_timeout);
00070 use_ha=1;
00071 return 1;
00072 error:
00073 return -1;
00074 }
00075
00076 int print_pingtable(struct ha *ta,int idx,int lock)
00077 {
00078 int i;
00079 if(lock)
00080 lock_get(ta->mutex);
00081 for(i=0;i<ta->size;i++){
00082 if((ta->begin+ta->count)>ta->size){
00083 if ((i<ta->begin && i<((ta->begin+ta->count)%ta->size)) || (i>=ta->begin && i<(ta->begin+ta->count)))
00084 fprintf(stderr,"*");
00085 else
00086 fprintf(stderr,"=");
00087 }else{
00088 if (i>=ta->begin && i<(ta->begin+ta->count))
00089 fprintf(stderr,"*");
00090 else
00091 fprintf(stderr,"=");
00092 }
00093 }
00094 if(lock)
00095 lock_release(ta->mutex);
00096 fprintf(stderr,"\n");
00097 for(i=0;i<ta->size;i++)
00098 if(i==idx)
00099 fprintf(stderr,"-");
00100 else
00101 fprintf(stderr,"%d",i);
00102 fprintf(stderr,"\n");
00103 return 0;
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 static inline int parse_ping(char * string,int *ping_period,int *pings_lost,int *ping_timeout)
00119 {
00120 char *ping_period_s,*pings_lost_s,*ping_timeout_s;
00121 ping_period_s=pings_lost_s=ping_timeout_s=(char *)0;
00122
00123 if(string==0 || *string==0){
00124 *ping_period=0;
00125 *pings_lost=0;
00126 *ping_timeout=0;
00127 return 0;
00128 }
00129
00130 if (((*string)<'0')||((*string)>'9')) {
00131 LM_ERR("malformed ping config string. Unparseable :[%s]\n",string);
00132 return -1;
00133 }
00134 ping_period_s=string;
00135 while(*string){
00136 if(*string == ':'){
00137 *string=0;
00138 if (!pings_lost_s && (*(string+1))) {
00139 pings_lost_s=string+1;
00140 }else if (!ping_timeout_s && (*(string+1))) {
00141 ping_timeout_s=string+1;
00142 }else{
00143 LM_ERR("malformed ping config string. Unparseable :[%s]\n",string);
00144 return -1;
00145 }
00146 }
00147 string++;
00148 }
00149 if (!(ping_period_s && pings_lost_s && ping_timeout_s)) {
00150 LM_ERR("malformed ping config string. Unparseable :[%s]\n",string);
00151 return -1;
00152 }
00153 *ping_period =atoi(ping_period_s);
00154 *pings_lost=atoi(pings_lost_s);
00155 *ping_timeout=atoi(ping_timeout_s);
00156 if (*ping_period<=0 || *pings_lost<=0 || *ping_timeout<=0) {
00157 return -1;
00158 }
00159 return 1;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 int spawn_pinger(void)
00171 {
00172 int n,next_jain,next_servlet,timeout;
00173 struct timeval now,last_jain,last_servlet;
00174 struct as_entry *as;
00175
00176 if ((pinger_pid=fork())<0) {
00177 LM_ERR("forking failed!\n");
00178 goto error;
00179 }else if(pinger_pid>0){
00180 return 0;
00181 }
00182 strcpy(whoami,"Pinger Process\n");
00183 is_dispatcher=0;
00184 my_as=0;
00185
00186 if(jain_ping_period && servlet_ping_period){
00187 next_jain=next_servlet=0;
00188 }else if(jain_ping_period){
00189 next_servlet=INT_MAX;
00190 next_jain=0;
00191 }else if(servlet_ping_period){
00192 next_jain=INT_MAX;
00193 next_servlet=0;
00194 }else{
00195 next_jain=next_servlet=INT_MAX;
00196 }
00197
00198 gettimeofday(&last_jain,NULL);
00199 memcpy(&last_servlet,&last_jain,sizeof(struct timeval));
00200
00201 while(1){
00202 gettimeofday(&now,NULL);
00203 if(next_jain!=INT_MAX){
00204 next_jain=jain_ping_period-((now.tv_sec-last_jain.tv_sec)*1000 + (now.tv_usec-last_jain.tv_usec)/1000);
00205 }
00206 if(next_servlet!=INT_MAX){
00207 next_servlet=servlet_ping_period-((now.tv_sec-last_servlet.tv_sec)*1000 + (now.tv_usec-last_servlet.tv_usec)/1000);
00208 }
00209
00210 timeout=next_jain<next_servlet?next_jain:next_servlet;
00211
00212 if ((n=poll(NULL,0,timeout<0?0:timeout))<0) {
00213 LM_ERR("poll returned %d\n",n);
00214 goto error;
00215 }else if(n==0){
00216 gettimeofday(&now,NULL);
00217 if (jain_ping_period && ((now.tv_sec-last_jain.tv_sec)*1000 + (now.tv_usec-last_jain.tv_usec)/1000)>=jain_ping_period) {
00218 gettimeofday(&last_jain,NULL);
00219 for(as=as_list;as;as=as->next){
00220 if(as->type == AS_TYPE && as->connected){
00221 send_ping(as,&now);
00222 }
00223 }
00224 }
00225 if (servlet_ping_period && ((now.tv_sec-last_servlet.tv_sec)*1000 + (now.tv_usec-last_servlet.tv_usec)/1000)>=servlet_ping_period) {
00226 gettimeofday(&last_servlet,NULL);
00227 for(as=as_list;as;as=as->next){
00228 if(as->type==AS_TYPE && as->connected){
00229 send_ping(as,&now);
00230 }
00231 }
00232 }
00233 }else{
00234 LM_ERR("bug:poll returned %d\n",n);
00235 goto error;
00236 }
00237 }
00238 return 0;
00239 error:
00240 return -1;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250 static inline int send_ping(struct as_entry *the_as,struct timeval *now)
00251 {
00252 char *the_ping;
00253 as_msg_p aping;
00254 int pinglen,retval;
00255 unsigned int seqno;
00256 struct ping *pingu;
00257
00258 aping=(as_msg_p)0;
00259 the_ping=(char *)0;
00260 retval=0;
00261 if (!(aping=shm_malloc(sizeof(as_msg_t)))) {
00262 LM_ERR("out of shm_mem for ping event\n");
00263 retval=-1;
00264 goto error;
00265 }
00266 if (!(the_ping=create_ping_event(&pinglen,0,&seqno))) {
00267 LM_ERR("Unable to create ping event\n");
00268 retval=-1;
00269 goto error;
00270 }
00271 aping->as=the_as;
00272 aping->msg=the_ping;
00273 aping->len=pinglen;
00274
00275 lock_get(the_as->u.as.jain_pings.mutex);
00276 {
00277 if(the_as->u.as.jain_pings.count==the_as->u.as.jain_pings.size){
00278 LM_ERR("Cant send ping because the pingtable is full (%d pings)\n",\
00279 the_as->u.as.jain_pings.count);
00280 retval=0;
00281 lock_release(the_as->u.as.jain_pings.mutex);
00282 goto error;
00283 }else{
00284 pingu=the_as->u.as.jain_pings.pings+the_as->u.as.jain_pings.end;
00285 the_as->u.as.jain_pings.end=(the_as->u.as.jain_pings.end+1)%the_as->u.as.jain_pings.size;
00286 the_as->u.as.jain_pings.count++;
00287 }
00288 memcpy(&pingu->sent,now,sizeof(struct timeval));
00289 pingu->id=seqno;
00290 }
00291 lock_release(the_as->u.as.jain_pings.mutex);
00292 again:
00293 if(0>write(write_pipe,&aping,sizeof(as_msg_p))){
00294 if(errno==EINTR){
00295 goto again;
00296 }else{
00297 LM_ERR("error sending ping\n");
00298 goto error;
00299 }
00300 }
00301 return 0;
00302 error:
00303 if(aping)
00304 shm_free(aping);
00305 if(the_ping)
00306 shm_free(the_ping);
00307 return retval;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317 inline int init_pingtable(struct ha *table,int timeout,int maxpings)
00318 {
00319 if(maxpings<=0)
00320 maxpings=1;
00321 table->begin=0;
00322 table->end=0;
00323 table->timed_out_pings=0;
00324 table->size=maxpings;
00325 table->timeout=timeout;
00326
00327 if (!(table->mutex=lock_alloc())){
00328 LM_ERR("Unable to allocate a lock for the ping table\n");
00329 goto error;
00330 }else
00331 lock_init(table->mutex);
00332 LM_ERR("alloc'ing %d bytes for %d pings\n",(int)(maxpings*sizeof(struct ping)),maxpings);
00333 if (0==(table->pings=shm_malloc(maxpings*sizeof(struct ping)))){
00334 LM_ERR("Unable to shm_malloc %d bytes for %d pings\n",(int)(maxpings*sizeof(struct ping)),maxpings);
00335 goto error;
00336 }else{
00337 memset(table->pings,0,(maxpings*sizeof(struct ping)));
00338 }
00339 return 0;
00340 error:
00341 destroy_pingtable(table);
00342 return -1;
00343 }
00344
00345 inline void destroy_pingtable(struct ha *table)
00346 {
00347 if(table->mutex){
00348 lock_dealloc(table->mutex);
00349 table->mutex=0;
00350 }
00351 if(table->pings){
00352 shm_free(table->pings);
00353 table->pings=0;
00354 }
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 char * create_ping_event(int *evt_len,int flags,unsigned int *seqno)
00372 {
00373 unsigned int i,k;
00374 char *buffer;
00375 static unsigned int ping_seqno=0;
00376
00377 if (!(buffer=shm_malloc(4+1+1+4+4))) {
00378 LM_ERR("out of shm for ping\n");
00379 return 0;
00380 }
00381 *evt_len=(4+1+1+4+4);
00382 ping_seqno++;
00383 *seqno=ping_seqno;
00384 i=htonl(14);
00385 memcpy(buffer,&i,4);
00386 k=4;
00387
00388 buffer[k++]=(unsigned char)PING_AC;
00389
00390 buffer[k++]=(unsigned char)0xFF;
00391
00392 flags=htonl(flags);
00393 memcpy(buffer+k,&flags,4);
00394 k+=4;
00395
00396 i=htonl(ping_seqno);
00397 memcpy(buffer+k,&i,4);
00398 k+=4;
00399 return buffer;
00400 }