Thread: Race Condition Help

  1. #1
    ‡ †hë Ö†hÈr sîÐè ‡ Nor's Avatar
    Join Date
    Nov 2001
    Posts
    299

    Race Condition Help

    I wrote a program to read my apache HTTP logs and generate a .htaccess file banning ip's
    which break the terms and conditions of my server.
    I have had no problem for weeks until today.

    My server was under heavy load (for me) with about 70 clients browsing at once.
    I reviewed my logs and noted a violation of the t&c so I ran my .htaccess generator to update
    the ban list. When I did the program produced some very unexpected output.

    My client which done nothing to meet my ban criteria was included in the deny section of the
    htaccess file.

    I restored my previous ban listing and started debugging my program.

    I've been able to reproduce the results. and determined the bug is a "race condition"
    I'm using fstream.getline() to access the log file.

    below is the portion of code which I believe the bug is in.
    the full program can be seen here -Attachment 8747-

    With a empty log file and a the program in an infinite loop I can cause the error by access my
    test server with internet explorer.

    I can't figure out why its happening.
    Its like fstream.getline() is giving me the same line of input over and over.

    Any advice???

    Code:
    void GenerateBanList(char* argv[]){ 
    	char lineBuffer[1024];
    	char seed[] = "400 - ";
    	BanEntry tmp;
    	int x;
    	size_t size = 0;
    	size_t count;
    #ifndef _DEBUG
    //save space
    #endif
    	AccessLog_file.clear();
    	AccessLog_file.open( argv[1], std::ios::in);
    	if( !AccessLog_file.is_open() ){
    		std::cout << " Error opening Access Log :" << argv[1] << "\n";
    		exit(0);
    	}
    	while( !AccessLog_file.eof() ){
    		memset(lineBuffer, 0, sizeof(lineBuffer));
    /*error*/	AccessLog_file.getline(lineBuffer, sizeof(lineBuffer)-1);
    		count = AccessLog_file.gcount();
    		if( count == 0)
    			continue;
    			
    		size+= count;
    
    		tmp = StringToBan(lineBuffer);
    		x = FindIpInVector(tmp);
    		
    		switch(tmp.code){
    			case 400:
    			case 401:
    			case 404:
    
    				if(x == -1){
    					banlist.push_back(tmp);
    				}else{
    					banlist[x].count++;
    					#ifdef _DEBUG
    					//save space
    					#endif
    				}
    				break;
    			default:
    				break;
    		}
    	}
    	AccessLog_file.close();
    	if(size != LastFileSize){
    		IsModified = true;
    		LastFileSize = size;
    		std::cout << ".";
    	}
    }
    i've compiled on vista64, vista32 and xp32
    same issue.
    Visual Studio 2003.net
    Try to help all less knowledgeable than yourself, within
    the limits provided by time, complexity and tolerance.
    - Nor

  2. #2
    Malum in se abachler's Avatar
    Join Date
    Apr 2007
    Posts
    3,195
    Try using a CRITICAL_SECTION.

  3. #3
    ‡ †hë Ö†hÈr sîÐè ‡ Nor's Avatar
    Join Date
    Nov 2001
    Posts
    299
    Thank you abachler.
    MSDN for "InitializeCriticalSection" states
    For similar synchronization between the threads of different processes, use a mutex object.
    Since my HTTP service is running under a different process then I should use a mutex right?.

    Also, how could I port the resource locking to a Linux box?
    My primary server runs Slackware 12.
    Thanks
    Try to help all less knowledgeable than yourself, within
    the limits provided by time, complexity and tolerance.
    - Nor

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    I have no idea where your race is, but the usual method to implement simple interprocess locking is to use a lock file:

    Code:
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    // Return value >= 0 if the lock was acquired, < 0 if not.
    // If lock fails to acquire, wait a few ticks then try again.
    int lockfile_lock(const char *path)
    {
        return open(path, O_CREAT | O_EXCL);
    }
    
    // Unlocks the lock previously granted by lockfile_lock()
    void lockfile_unlock(const char *path, int fd)
    {
        unlink(path);
        close(fd);
    }
    The path is basically a unique identifier for the lock. Use something like "/tmp/xxxxxx". No data is written to the lock file, but it is created and exists for the duration of the lock.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problems reading entered race times C
    By loopymoo26 in forum C Programming
    Replies: 12
    Last Post: 05-23-2009, 07:38 AM
  2. SDL Condition variables.
    By antex in forum Game Programming
    Replies: 3
    Last Post: 11-11-2005, 07:11 AM
  3. Looping condition
    By Chaplin27 in forum C++ Programming
    Replies: 3
    Last Post: 05-29-2005, 02:06 PM
  4. Race condition: getting multiple threads to cooperate
    By FlyingDutchMan in forum C++ Programming
    Replies: 10
    Last Post: 03-31-2005, 05:53 AM
  5. Race condition
    By Roaring_Tiger in forum C Programming
    Replies: 5
    Last Post: 10-24-2004, 09:42 PM