| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867 |
- /** BEGIN COPYRIGHT BLOCK
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2006 Red Hat, Inc.
- * All rights reserved.
- *
- * License: GPL (version 3 or any later version).
- * See LICENSE for details.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /*
- FILE : opCheck.c
- AUTHOR : Jean-Luc SCHWING
- VERSION : 1.0
- DATE : 04 May 1999
- DESCRIPTION :
- This file contains the functions used to manage and
- check the operations performed by the tool.
- These functions manages the operation list
- "mctx.opListTail", match an entry retrieved from the
- server to the attributes memorized for one operation,
- etc...
- LOCAL : None.
- */
- #include <pthread.h> /* Posix threads */
- #include <errno.h> /* errno, etc... */
- #include <stdlib.h> /* exit(), etc... */
- #include <unistd.h> /* sleep(), etc... */
- #include <stdio.h> /* printf(), etc... */
- #include <signal.h> /* sigset(), etc... */
- #include <string.h> /* strerror(), etc... */
- #include <sys/resource.h> /* setrlimit(), etc... */
- #include <lber.h> /* ldap C-API BER decl. */
- #include <ldap.h> /* ldap C-API decl. */
- #include <sys/poll.h> /* djani : while porting */
- #include <sys/socket.h> /* djani : while porting */
- #include <sys/types.h> /* djani : while porting */
- #include <netdb.h> /* djani : while porting */
- #include <netinet/in.h> /* djani : while porting */
- #ifdef LDAP_H_FROM_QA_WKA
- #include <proto-ldap.h> /* ldap C-API prototypes */
- #endif
- #include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
- #include "ldclt.h" /* This tool's include file */
- #include "remote.h" /* Definitions common with the slave */
- enum {SINGLE=0,FIRST,MIDDLE,LAST};
- /* ****************************************************************************
- FUNCTION : opDecOper
- PURPOSE : This function decodes an LDAP operation and return a
- printable string.
- INPUT : op = operation to decode
- OUTPUT : None.
- RETURN : The decoded string.
- DESCRIPTION :
- *****************************************************************************/
- char *
- opDecOper (
- int op)
- {
- switch (op)
- {
- case LDAP_REQ_MODIFY: return ("modify"); break;
- case LDAP_REQ_ADD: return ("add"); break;
- case LDAP_REQ_DELETE: return ("delete"); break;
- case LDAP_REQ_MODRDN: return ("modrdn"); break;
- default: return ("??unknown??"); break;
- }
- }
- /* ****************************************************************************
- FUNCTION : LDAPMod2attributes
- PURPOSE : Convert a LDAPMod-like array of attributes to the
- internal attributes array.
- INPUT : mods = LDAPMod array. If NULL, attribs[] is
- initiated as an empty array.
- OUTPUT : attribs = struct attribute array. This array is of
- MAX_ATTRIBS length.
- RETURN : -1 if error, 0 else.
- DESCRIPTION :
- *****************************************************************************/
- int
- LDAPMod2attributes (
- LDAPMod **mods,
- attribute *attribs)
- {
- int i; /* For the loop */
- /*
- * Maybe there is no mods ?? This occurs for rename operation, for example.
- */
- if (mods == NULL)
- {
- attribs[0].type = NULL;
- return (0);
- }
- /*
- * Process each entry
- */
- for (i=0 ; i< MAX_ATTRIBS && mods[i] != NULL ; i++)
- {
- attribs[i].type = strdup (mods[i]->mod_type);
- if (attribs[i].type == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("Error: cannot strdup(attribs[%d].type), error=%d (%s)\n",
- i, errno, strerror (errno)); /*JLS 06-03-00*/
- return (-1); /*JLS 06-03-00*/
- } /*JLS 06-03-00*/
- /*
- * Well, if it is a binary value, it is most likely an image
- * that is read by mmap and always available. Thus there is no reason
- * to copy it, just modify the pointers.
- */
- if (mods[i]->mod_op & LDAP_MOD_BVALUES)
- {
- attribs[i].dontFree = 1;
- attribs[i].length = mods[i]->mod_bvalues[0]->bv_len;
- attribs[i].value = mods[i]->mod_bvalues[0]->bv_val;
- }
- else
- {
- attribs[i].dontFree = 0;
- attribs[i].length = strlen (mods[i]->mod_values[0]);
- attribs[i].value = strdup (mods[i]->mod_values[0]);
- if (attribs[i].value == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("Error: cannot strdup(attribs[%d].value), error=%d (%s)\n",
- i, errno, strerror (errno)); /*JLS 06-03-00*/
- return (-1); /*JLS 06-03-00*/
- } /*JLS 06-03-00*/
- }
- }
- /*
- * Don't forget to mark the end !
- */
- if (i<MAX_ATTRIBS)
- attribs[i].type = NULL;
- return (0);
- }
- /* ****************************************************************************
- FUNCTION : freeAttributesArray
- PURPOSE : This function is targeted to free an array of
- struct attribute. It does not free the array itself,
- but only the types and values memorized in it.
- INPUT : attribs = array to free.
- OUTPUT : None.
- RETURN : -1 if error, 0 else.
- DESCRIPTION :
- *****************************************************************************/
- int
- freeAttributesArray (
- attribute *attribs)
- {
- int i; /* For the loop */
- for (i=0;i<MAX_ATTRIBS&&attribs[i].type != NULL;i++)
- {
- free (attribs[i].type);
- if (!(attribs[i].dontFree))
- free (attribs[i].value);
- }
- return (0);
- }
- /* ****************************************************************************
- FUNCTION : opAdd
- PURPOSE : Add a new operation to the list.
- INPUT : tttctx = thread context
- type = operation type
- dn = target's DN
- attribs = operation attributes
- newRdn = new rdn (valid for rename only)
- newParent = new parent (valid for rename only)
- OUTPUT : None.
- RETURN : -1 if error, 0 else.
- DESCRIPTION : Note that the attributes given in argument are
- directly memorized (i.e. no copy), hence they should
- *not* be freed by the calling function.
- *****************************************************************************/
- int
- opAdd (
- thread_context *tttctx,
- int type,
- char *dn,
- LDAPMod **attribs,
- char *newRdn,
- char *newParent)
- {
- int ret; /* Return value */
- oper *newOper; /* New operation to memorize */
- if (mctx.mode & VERY_VERBOSE)
- printf ("T%03d: opAdd (%s, %s)\n", tttctx->thrdNum, opDecOper(type), dn);
- /*
- * Go to protected section. This will enforce the correct sequencing
- * of the operations performed because the whole function is lock
- * for the threads.
- * Note: Maybe reduce the size of this section ? To be checked.
- */
- if ((ret = pthread_mutex_lock (&(mctx.opListTail_mutex))) != 0)
- {
- fprintf (stderr,
- "T%03d: cannot pthread_mutex_lock(opListTail), error=%d (%s)\n",
- tttctx->thrdNum, ret, strerror (ret));
- fflush (stderr);
- return (-1);
- }
- /*
- * Create the new cell
- */
- newOper = (oper *) malloc (sizeof (oper));
- if (newOper == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("T%03d: cannot malloc(newOper), error=%d (%s)\n", /*JLS 06-03-00*/
- tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
- return (-1); /*JLS 06-03-00*/
- } /*JLS 06-03-00*/
- newOper->next = NULL;
- newOper->type = type;
- newOper->skipped = mctx.slavesNb;
- newOper->dn = strdup (dn);
- if (newOper->dn == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf("T%03d: cannot strdup(newOper->dn), error=%d (%s)\n",/*JLS 06-03-00*/
- tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
- return (-1); /*JLS 06-03-00*/
- } /*JLS 06-03-00*/
- newOper->newRdn = (newRdn == NULL ? NULL : strdup (newRdn));
- if (newOper->newRdn == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("T%03d: cannot strdup(newOper->newRdn), error=%d (%s)\n",
- tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
- return (-1); /*JLS 06-03-00*/
- } /*JLS 06-03-00*/
- newOper->newParent = (newParent == NULL ? NULL : strdup (newParent));
- if (newOper->newParent == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("T%03d: cannot strdup(newOper->newParent), error=%d (%s)\n",
- tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
- return (-1); /*JLS 06-03-00*/
- } /*JLS 06-03-00*/
- if (LDAPMod2attributes (attribs, newOper->attribs) < 0)
- return (-1);
- /*
- * Don't forget to initiate this cell's mutex !
- */
- if ((ret = pthread_mutex_init(&(newOper->skipped_mutex), NULL)) != 0)
- {
- fprintf (stderr,
- "T%03d: cannot initiate skipped_mutex error=%d (%s)\n",
- tttctx->thrdNum, ret, strerror (ret));
- fflush (stderr);
- return (-1);
- }
- /*
- * Link the cell
- */
- mctx.opListTail->next = newOper;
- mctx.opListTail = newOper;
- /*
- * Release the mutex
- */
- if ((ret = pthread_mutex_unlock (&(mctx.opListTail_mutex))) != 0)
- {
- fprintf (stderr,
- "T%03d: cannot pthread_mutex_unlock(opListTail), error=%d (%s)\n",
- tttctx->thrdNum, ret, strerror (ret));
- fflush (stderr);
- return (-1);
- }
- return (0);
- }
- /* ****************************************************************************
- FUNCTION : opNext
- PURPOSE : Return the next available operation. May return NULL
- if no operation available.
- INPUT : ctctx = thread context
- OUTPUT : op = next operation. May be NULL.
- RETURN : -1 if error, 0 else.
- DESCRIPTION :
- *****************************************************************************/
- int
- opNext (
- check_context *ctctx,
- oper **op)
- {
- int ret; /* Return value */
- oper *newHead; /* The new head operation */
- /*
- * Maybe there is no new operation ?
- */
- if (ctctx->headListOp->next == NULL)
- {
- *op = NULL;
- if (mctx.mode & VERY_VERBOSE)
- printf ("C%03d: opNext --> NULL\n", ctctx->thrdNum);
- return (0);
- }
- /*
- * Ok, there is one new operation. Let's skip the head and
- * go to the new operation...
- */
- if ((ret = pthread_mutex_lock (&(ctctx->headListOp->skipped_mutex))) != 0)
- {
- fprintf (stderr,
- "C%03d: cannot pthread_mutex_lock(skipped_mutex), error=%d (%s)\n",
- ctctx->thrdNum, ret, strerror (ret));
- fflush (stderr);
- return (-1);
- }
- newHead = ctctx->headListOp->next;
- ctctx->headListOp->skipped--;
- /*
- * If there is another thread that has not skipped, let's move to the
- * next operation and unlock the counter.
- */
- if (ctctx->headListOp->skipped != 0)
- {
- if ((ret = pthread_mutex_unlock (&(ctctx->headListOp->skipped_mutex))) != 0)
- {
- fprintf (stderr,
- "C%03d: cannot pthread_mutex_unlock(skipped_mutex), error=%d (%s)\n",
- ctctx->thrdNum, ret, strerror (ret));
- fflush (stderr);
- return (-1);
- }
- }
- else
- {
- /*
- * Well, looks like we are the last thread to skip.... Let's free this
- * operation. BTW, there is no reason to unlock/release the mutex because
- * it will be destroyed !
- * Note: may be NULL when LDAP_REQ_DELETE for example.
- */
- if (ctctx->headListOp->attribs != NULL)
- if (freeAttributesArray (ctctx->headListOp->attribs) < 0)
- return (-1);
- if (ctctx->headListOp->dn != NULL)
- free (ctctx->headListOp->dn);
- if (ctctx->headListOp->newRdn != NULL)
- free (ctctx->headListOp->newRdn);
- if (ctctx->headListOp->newParent != NULL)
- free (ctctx->headListOp->newParent);
- free (ctctx->headListOp);
- }
- /*
- * End of function
- */
- *op = ctctx->headListOp = newHead;
- if (mctx.mode & VERY_VERBOSE)
- printf ("C%03d: opNext --> (%s, %s)\n",
- ctctx->thrdNum, opDecOper ((*op)->type), (*op)->dn);
- return (0);
- }
- /* ****************************************************************************
- FUNCTION : opRead
- PURPOSE : Read the n'th operation from the head.
- INPUT : ctctx = thread context
- num = number of the operation to retrieve
- OUTPUT : op = returned operation. May be NULL.
- RETURN : -1 if error, 0 else.
- DESCRIPTION :
- *****************************************************************************/
- int
- opRead (
- check_context *ctctx,
- int num,
- oper **op)
- {
- *op = ctctx->headListOp;
- while (num != 0)
- {
- /*
- * Maybe not enough entries in the list ?
- */
- if (*op == NULL)
- return (0);
- *op = (*op)->next;
- num--;
- }
- /*
- * If there, we got it :-)
- */
- return (0);
- }
- /* ****************************************************************************
- FUNCTION : thOperAdd
- PURPOSE : This function copies an operation to the late
- operation list
- INPUT : head list and operation to copy
- OUTPUT : None.
- RETURN : New head
- DESCRIPTION :
- *****************************************************************************/
- thoper *
- thOperAdd ( thoper *head, oper *elem, int f)
- {
- thoper *new,*t=head;
- int i;
- new=malloc(sizeof(thoper));
- if (new == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("Txxx: cannot malloc(new), error=%d (%s)\n", /*JLS 06-03-00*/
- errno, strerror (errno)); /*JLS 06-03-00*/
- ldcltExit (1); /*JLS 18-08-00*/
- } /*JLS 06-03-00*/
- new->next=NULL;
- new->first=f;
- new->type=elem->type;
- new->dn=strdup(elem->dn);
- if (elem->newRdn != NULL)
- new->newRdn=strdup(elem->newRdn);
- if (elem->newParent != NULL)
- new->newParent=strdup(elem->newParent);
- for(i=0;i<MAX_ATTRIBS&&elem->attribs[i].type;i++)
- {
- new->attribs[i].type=strdup(elem->attribs[i].type);
- if (new->attribs[i].type == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("Txxx: cannot strdup(new->attribs[%d].type), error=%d (%s)\n",
- errno, i, strerror (errno)); /*JLS 06-03-00*/
- ldcltExit (1); /*JLS 18-08-00*/
- } /*JLS 06-03-00*/
- new->attribs[i].length = elem->attribs[i].length;
- if((new->attribs[i].dontFree=elem->attribs[i].dontFree))
- new->attribs[i].value = elem->attribs[i].value;
- else
- {
- new->attribs[i].value = strdup(elem->attribs[i].value);
- if (new->attribs[i].value == NULL) /*JLS 06-03-00*/
- { /*JLS 06-03-00*/
- printf ("Txxx: cannot strdup(new->attribs[%d].value), error=%d (%s)\n",
- errno, i, strerror (errno)); /*JLS 06-03-00*/
- ldcltExit (1); /*JLS 18-08-00*/
- } /*JLS 06-03-00*/
- }
- }
- if(i<MAX_ATTRIBS)
- new->attribs[i].type=NULL;
- if(head==NULL)
- return new;
- for(t=head;t->next;)
- t=t->next;
- t->next=new;
- return head;
- }
- /* ****************************************************************************
- FUNCTION : thOperFree
- PURPOSE : This function frees memory for a late operation
- INPUT : Head of list and operation to delete
- OUTPUT : None.
- RETURN : new head
- DESCRIPTION :
- *****************************************************************************/
- thoper *
- thOperFree (thoper *head, thoper *elem)
- {
- thoper *t;
- freeAttributesArray(elem->attribs);
- free (elem->dn);
- if (elem->newRdn != NULL)
- free (elem->newRdn);
- if (elem->newParent != NULL)
- free (elem->newParent);
- if(head!=elem)
- {
- for(t=head;t->next!=elem;)
- t=t->next;
- t->next=t->next->next;
- }
- else
- head = head->next;
- free(elem);
- return head;
- }
- /* ****************************************************************************
- FUNCTION : opCheckLoop
- PURPOSE : This function is the per slave check function
- INPUT : arg = this check thread's check_context
- OUTPUT : None.
- RETURN : None.
- DESCRIPTION :
- *****************************************************************************/
- void *
- opCheckLoop ( void* arg)
- {
- struct check_context *cctx=(struct check_context *)arg;
- struct pollfd pfd;
- repconfirm *recOper;
- oper *myop;
- thoper *t;
- unsigned char recbuf[1500];
- int ret,i,timeout;
- int cnt; /* To count loops for timeout purpose */
- int fndlt; /* Found late operation */
- int nbRead; /* Nb char read() */
- int status; /* Thread status */ /*JLS 17-11-00*/
- recOper=(repconfirm*)recbuf;
- pfd.fd=cctx->sockfd;
- pfd.events=(POLLIN|POLLPRI);
- pfd.revents=0;
- cctx->status=INITIATED;
- if((timeout=mctx.timeout)<30)
- timeout=30;
- /*
- * First time in here?
- */
- if(cctx->calls==1)
- cctx->dcOper=NULL;
- while((ret=poll(&pfd,1,500))>=0)
- {
- if(ret)
- {
- /*
- * Exit if read error on the net
- */
- if ((nbRead = read (pfd.fd,recOper,sizeof(repconfirm)))<0)
- break;
- if (nbRead != sizeof(repconfirm))
- printf ("C%03d(%s): Partial header read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, sizeof(repconfirm));
- recOper->type=ntohl(recOper->type);
- recOper->res=ntohl(recOper->res);
- recOper->dnSize=ntohl(recOper->dnSize);
- /*
- * Beware of structure alignment
- */
- if((nbRead=read(pfd.fd,recOper->dn+sizeof(recOper->dn),recOper->dnSize))<0)
- break;
- if (nbRead != recOper->dnSize)
- printf ("C%03d(%s): Partial dn read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, recOper->dnSize);
- if (nbRead > (1500 - sizeof(repconfirm)))
- printf ("C%03d(%s): Read too much %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, 1500 - sizeof(repconfirm));
- cnt=0;
- cctx->nbOpRecv++;
- if(mctx.mode&VERY_VERBOSE)
- {
- printf("C%03d(%s): Rec %s\n",cctx->thrdNum,cctx->slaveName,recOper->dn);
- for(myop=cctx->headListOp->next;myop;myop=myop->next)
- printf("C%03d(%s): IN : %s\n",cctx->thrdNum,cctx->slaveName,myop->dn);
- for(t=cctx->dcOper;t;t=t->next)
- printf("C%03d(%s): LATE : %s\n",cctx->thrdNum,cctx->slaveName,t->dn);
- }
- /*
- * Do not tell me there was an error during replica...
- */
- if(recOper->res)
- {
- printf("C%03d(%s): Replica failed, op:%d(%s), dn=\"%s\" res=%d\n",
- cctx->thrdNum, cctx->slaveName,
- recOper->type, opDecOper(recOper->type),
- recOper->dn, recOper->res );
- switch (recOper->res)
- {
- case 32: cctx->nbRepFail32++ ; break;
- case 68: cctx->nbRepFail68++ ; break;
- default: cctx->nbRepFailX++ ; break;
- }
- }
- /*
- * Is this a late operation?
- */
- fndlt=0;
- if(cctx->dcOper)
- {
- for (i=1,t = cctx->dcOper;t;i++)
- if ((recOper->type!=t->type) || strcmp(recOper->dn,t->dn))
- t = t->next;
- else
- {
- /*
- * if this is a single operation: 132456
- */
- if(t->first==SINGLE)
- {
- /*
- * error.
- */
- printf("C%03d(%s): Late replica: op:%d(%s), dn=\"%s\"\n",
- cctx->thrdNum, cctx->slaveName,
- t->type, opDecOper(t->type), t->dn );
- cctx->nbLate++;
- } else if (t->first==MIDDLE)
- {
- /*
- * Middle of a series : 23546
- */
- printf("C%03d(%s): Early (%3d) op:%d(%s), dn=\"%s\"\n",
- cctx->thrdNum, cctx->slaveName,i,
- t->type, opDecOper(t->type), t->dn );
- cctx->nbEarly++;
-
- } else if(t->next)
- {
- /*
- * else maybe we are in a re-corrected situation.
- * we should receive the next one, now.
- */
- if(t->next->first!=LAST)
- t->next->first=FIRST;
- }
- cctx->dcOper = thOperFree (cctx->dcOper, t);
- fndlt=1;
- break;
- }
- }
- if(!fndlt)
- {
- /*
- * See if the operation we received is the same as the head
- */
- opRead(cctx,1,&myop);
- if (myop != NULL &&
- recOper->type==myop->type &&
- strcmp(recOper->dn,myop->dn) == 0)
- opNext(cctx,&myop);
- else
- {
- /*
- * Nope, look for it
- */
- for(i=2;opRead(cctx,i,&myop)==0;i++)
- if(myop)
- {
- if(recOper->type==myop->type &&
- strcmp(recOper->dn,myop->dn) == 0)
- {
- /*
- * Skip all between current head and this one
- */
- printf("C%03d(%s): Early (%3d) op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, i-1, recOper->type, opDecOper(recOper->type), recOper->dn );
- cctx->nbEarly++;
- opNext(cctx,&myop);
- /*
- * mark the first of the series as leader
- */
- cctx->dcOper=thOperAdd(cctx->dcOper,myop,
- i==2?SINGLE:FIRST);
- for(;i>2;i--)
- {
- opNext(cctx,&myop);
- /*
- * copy up until one before last
- */
- if(myop)
- thOperAdd(cctx->dcOper,myop,
- i==3?LAST:MIDDLE);
- }
- opNext(cctx,&myop);
- break;
- }
- } else break;
- if(!myop)
- {
- printf("C%03d(%s): Not on list op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, recOper->type, opDecOper(recOper->type), recOper->dn );
- cctx->nbNotOnList++;
- }
- }
- }
- }
- pfd.events=(POLLIN|POLLPRI);
- pfd.revents=0;
- /*
- * operations threads still running?
- */
- for(i=0;i<mctx.nbThreads;i++)
- { /*JLS 17-11-00*/
- if (getThreadStatus (&(tctx[i]), &status) < 0) /*JLS 17-11-00*/
- break; /*JLS 17-11-00*/
- if(status != DEAD) /*JLS 17-11-00*/
- {
- cnt=0;
- break;
- }
- } /*JLS 17-11-00*/
- /*
- * twice half a second...
- */
- if(++cnt>timeout*2)
- break;
- }
- if(mctx.mode&VERY_VERBOSE)
- printf("C%03d(%s): Exiting\n",cctx->thrdNum,cctx->slaveName);
- /*
- * Any operation left?
- */
- for(opNext(cctx,&myop);myop;opNext(cctx,&myop))
- {
- printf("Operation %d(%s) still on Queue for %s (%s)\n",myop->type,opDecOper(myop->type),cctx->slaveName,myop->dn);
- cctx->nbStillOnQ++;
- }
- for(t=cctx->dcOper;t;t=t->next)
- {
- printf("Lost op %d(%s) on %s (%s)\n",t->type,opDecOper(t->type),cctx->slaveName,t->dn);
- cctx->nbLostOp++;
- }
- close(cctx->sockfd);
- cctx->status=DEAD;
- pthread_exit(NULL);
- }
- /* ****************************************************************************
- FUNCTION : opCheckMain
- PURPOSE : This function is the main function of the check
- operation threads,
- INPUT : arg = NULL
- OUTPUT : None.
- RETURN : None.
- DESCRIPTION :
- *****************************************************************************/
- void *
- opCheckMain (
- void *arg)
- {
- struct sockaddr_in srvsaddr,claddr;
- struct hostent cltaddr;
- #ifdef LINUX
- struct hostent *stupidlinux=NULL;
- #endif
- struct linger lopt;
- uint32_t ipaddr;
- int newfd,sockfd,ncctx,i,err;
- char buffer[128];
- int retry; /* To retry on EINTR */
- /*
- * Initialization
- */
- srvsaddr.sin_addr.s_addr=htonl(INADDR_ANY);
- srvsaddr.sin_family=AF_INET;
- srvsaddr.sin_port=htons(masterPort);
- /*
- * Let's go !!!
- */
- if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
- {
- perror("Socket");
- ldcltExit(1); /*JLS 18-08-00*/
- }
- i=1;
- if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&i,sizeof(int))!=0)
- perror("Sockopt");
- if(bind(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=0)
- {
- perror("Bind");
- ldcltExit(1); /*JLS 18-08-00*/
- }
- if(listen(sockfd,1)!=0)
- perror("listen");
- for(ncctx=0;;)
- {
- i=sizeof(claddr);
- retry = 1;
- while (retry)
- {
- if ((newfd=accept(sockfd,(struct sockaddr *)&claddr,&i))>=0)
- retry = 0;
- else
- if (errno != EINTR)
- {
- perror("Accept");
- ldcltExit(1); /*JLS 18-08-00*/
- }
- }
- /*
- * get client's name
- */
- ipaddr=ntohl(claddr.sin_addr.s_addr);
- #ifdef LINUX
- gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
- buffer,128, &stupidlinux, &err);
- #else
- #if defined(HPUX) && defined(__LP64__)
- gethostbyaddr((char*)&ipaddr,sizeof(ipaddr),AF_INET);
- #else
- gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
- buffer,128,&err);
- #endif
- #endif
- i=1;
- if(setsockopt(newfd,IPPROTO_TCP, TCP_NODELAY,(void *)&i,sizeof(int))!=0)
- perror("Nagle");
- /*
- * Linger: when connection ends, send an RST instead of a FIN
- * This way the client will have a fail on the first write instead of
- * the second
- */
- lopt.l_onoff=1;
- lopt.l_linger=0;
- if(setsockopt(newfd,SOL_SOCKET,SO_LINGER,(void*)&lopt,sizeof(struct linger))<0)
- perror("Linger");
- /*
- * Search for an empty client slot. If a client reconnects, use the
- * same slot
- */
- for(i=0;i<mctx.slavesNb;i++)
- {
- if(cctx[i].calls==0)
- {
- i=ncctx++;
- break;
- }
- if(cctx[i].slaveName&&cctx[i].status==DEAD)
- if(strcmp(cctx[i].slaveName,cltaddr.h_name)==0)
- break;
- }
- if(i>=mctx.slavesNb)
- {
- fprintf (stderr, "ldclt: Too many slaves %s\n",cltaddr.h_name);
- close(newfd);
- continue;
- }
- cctx[i].sockfd=newfd;
- cctx[i].calls++;
- cctx[i].slaveName=strdup(cltaddr.h_name);
- if ((err = pthread_create (&(cctx[i].tid), NULL,
- opCheckLoop, (void *)&(cctx[i]))) != 0)
- {
- fprintf (stderr, "ldclt: %s\n", strerror (err));
- fprintf (stderr, "Error: cannot create thread opCheck for %s\n",
- cltaddr.h_name);
- fflush (stderr);
- }
- else
- mctx.slaveConn = 1;
- }
- close(sockfd);
- }
|