Detect ip of client?

I have a Mega 2560 and an Ethernet shield, and basically I'm prototyping an architectural lighting controller for my church that is controlled via a web interface. I would like to be able to have it password protected, I.e. client is presented with a text box and enters password before they are able to control anything. So I would need to be able to identify each client to see if they have logged on already or not. So is there a way to find a clients IP, or individually identify it?

Here is a thread that covers what you want.
http://arduino.cc/forum/index.php/topic,135082.0.html

Why not using HTTP authentication and checking the client's password at every request?

Yea I'm actually one step ahead of you on that. But how do you log the client out?

Define "log out". Do you want to deny access after some time? If you send the client a 4XX result code it will ask again for the credentials if that's what you want.

Well I had issues with browsers eternally remembering the password and stuff but I fixed it. I have gotten it where it has a list of logins on an SD card with permissions that it compares it to. So all I have to do now is change the page presented and stuff

Usually the browser remembers the credentials during runtime. If you quit the browser, it should forget all credentials the user not explicitly saved (and saving is possible for web forms too).
If you wanna circumvent that, send a random realm, because the browser stores the credentials for one realm and re-ask for them if the realm changes.

Ok. Heres my code so far:

#include <Base64.h>
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>
const byte slots = 20;
IPAddress clientIP[slots];
boolean IPUsed[slots];
boolean passEntered[slots];
int currClient;
boolean newClient;
int loginCount[slots];
char encoded[100];
char decoded[100];
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 6, 3, 2);
File accounts;
const char userHeader[] = "<user>";
const char userFooter[] = "</user>";
char permissions[slots];

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);

void setup()
{
    Serial.begin(115200);    
  pinMode(53, OUTPUT);     // change this to 53 on a mega
  pinMode(10, OUTPUT);     // change this to 53 on a mega
  digitalWrite(10,HIGH);
  Serial.print("Initializing SD card...");
  
  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  lcd.begin(16, 2);
  pinMode(8, OUTPUT);    
  Ethernet.begin(mac);
  server.begin();
  
  
    lcd.print("IP:");

  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    lcd.print(Ethernet.localIP()[thisByte], DEC);
    
    if(thisByte != 3)
      lcd.print("."); 
  }
}

void loop()
{
  
  EthernetClient client = server.available();
  if (client) {
    IPAddress temp;
    temp = client.remoteIP();
    Serial.println(temp);
    
    boolean matched = false;
    for(int i = 0; i < slots; i++)
    {
        if(temp == clientIP[i])
        {
          Serial.println("returning");
          newClient = false;
          loginCount[i] ++;
          matched = true;
          currClient = i;

        }
    }
    
    if(!matched)
    {
      for(int i = 0; i < slots; i++)
      {
        if(!IPUsed[i])
        {
          Serial.println("new");
          newClient = true;
          loginCount[i] = 0;
          clientIP[i] = temp;
          IPUsed[i] = true;
          currClient = i;
          passEntered[i] = false;
          return;
        }
      }
      
    }
    
    lcd.setCursor(0,1);
    lcd.print('C');
    lcd.print(currClient);
    lcd.print(':');
    lcd.println(clientIP[currClient]);
    boolean currentLineIsBlank = true;
    String buffer = "";  
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.print(c);   
        buffer+=c;       
        if (c == '\n' && currentLineIsBlank) {
         if(passEntered[currClient])
         {
           drawUser(client);
          
         }
         else
         {
          drawPass(client);
         }
         break;
        }
        if (c == '\n') {
          
          currentLineIsBlank = true;
          buffer="";       
        } else if (c == '\r') {  
          
          if((loginCount[currClient] > 1) && (buffer.indexOf("Authorization: Basic ") >= 0))
          {            
            for(int i = buffer.indexOf("Authorization: Basic ")+21; i < buffer.length()-1; i++)
            {
              encoded[i-(buffer.indexOf("Authorization: Basic ")+21)] = buffer[i];
            }
            
            base64_decode(decoded , encoded , buffer.length() - 21 - 1);
            
            accounts = SD.open("accounts.txt");
            if (accounts) 
            {
              Serial.print("reading accounts.txt...");
              int userStart = -1;
              int userEnd = -1;
              boolean failed = false;
             while(!passEntered[currClient] && !failed )
             {
              boolean found = false;
              unsigned long i = userStart + 1;
              while(!found)
              {
                if(!accounts.seek(i))
                {
                  found = true;
                  failed = true;
                }
                char buf[10];
                accounts.read(buf, 6);       
                if(strncmp(buf, userHeader, 6) == 0)
                {
                    userStart = i;
                    found = true;
                }
                i++;
              }
              found = false;
              i = userEnd + 1;
              while(!found)
              {
                if(!accounts.seek(i))
                {
                  found = true;
                  failed = true;
                }
                char buf[10];
                accounts.read(buf, 7);       
                if(strncmp(buf, userFooter, 7) == 0)
                {
                    userEnd = i;
                    found = true;
                }
                i++;
              }
              if(!failed)
              {
                accounts.seek(userStart + 6);
                passEntered[currClient] = true;
                i = 0;
                while(accounts.position() != userEnd-2)
                {
                  Serial.print(accounts.peek());
                  if(decoded[i] != accounts.read())
                  {
                    passEntered[currClient] = false;
                  }
                  i++;
                }
                if(passEntered[currClient])
                {
                  int tempPos = accounts.position();
                  accounts.seek(userEnd - 1);
                  permissions[currClient] = accounts.read();
                  accounts.seek(tempPos);
                }
              }




             }
              accounts.close();
             
            } else {
              // if the file didn't open, print an error:
              Serial.println("error opening test.txt");
            }

            
            
            
          }
          
          if( passEntered[currClient])
          {
            
            if(buffer.indexOf("GET /?status=1")>=0)
              digitalWrite(8,HIGH);  
            
            if(buffer.indexOf("GET /?status=0")>=0)
              digitalWrite(8,LOW);  
          }
        }
        else {
          
          currentLineIsBlank = false;
        }
      }
    }
    
    client.stop();
  }
}

void drawUser(EthernetClient client)
{
  client.println("HTTP/1.1 200 OK");
           client.println("Content-Type: text/html");
          client.println();
          

            client.print("<BODY BGCOLOR=#000000 TEXT=#FFFFFF LINK=#FFFFFF VLINK=#FFFFFF>");
            
            client.print("<font color='blue' size=7>Welcome  ");
            
            if(permissions[currClient] == 'u')
              client.print("user ");
              
            if(permissions[currClient] == 'a')
              client.print("admin ");
              
              
          
          
          client.print(currClient);
          
          client.print(" </font>");
          
          client.println("
");
          client.println("
");
          
          if (digitalRead(8)){  
            client.print(" LED is <font color='green'>ON</font>");
          }else{
            client.print(" LED is <font color='red'>OFF</font>");
          }
          client.println("
");
          
          client.print("<FORM action=\"http://");
          client.print(Ethernet.localIP()[0]);
          client.print(".");
          client.print(Ethernet.localIP()[1]);
          client.print(".");
          client.print(Ethernet.localIP()[2]);
          client.print(".");
          client.print(Ethernet.localIP()[3]);
          client.print("/\" >");
          
          client.print("<P> <INPUT type=\"radio\" name=\"status\" value=\"1\">ON");
          client.print("<P> <INPUT type=\"radio\" name=\"status\" value=\"0\">OFF");
          client.print("<P> <INPUT type=\"submit\" value=\"Submit\"> ");
          client.print("</FORM>");
          
}

void drawPass(EthernetClient client)
{
             client.println("HTTP/1.1 401 Access Denied");
          client.println("WWW-Authenticate: Basic realm=\"a\"");
          
          client.println("Content-Type: text/html");
          client.println();
          

            client.print("<BODY BGCOLOR=#000000 TEXT=#FFFFFF LINK=#FFFFFF VLINK=#FFFFFF>");
            client.print("ERROR: ACCESS DENIED");
}

Basically it is a password protected led on pin 8. all of the users are stored on a SD card in a file "accounts.txt" with the format of:
username:password:p where p is a for admin or u for user

    String buffer = "";

Unfortunately using the String class is a very bad idea. It fragments your available RAM in no time, especially if used the way you use it. Additionally there's a bug in the freeing of dynamically allocated memory in the current IDE versions which makes using the String class even worse. If you don't want to be forced to reset your Arduino every few requests you should eliminate the String class from your project.

Ok. I guess I need to whip up a function to replicate indexOf in a char array

EDIT:
Got it. Now for implementation

int findStr(char * strA, char * strB)
{
  int location = strstr(strA , strB)-strA+1;
  if(location<0)
  {
    return -1;
  }
  return location;
}

If you don't want to be forced to reset your Arduino every few requests you should eliminate the String class from your project.

I've got some simple server code that uses the String class and had the server respond to a client request 500,000+ times with out a crash. Perhaps your code is defective.

I've got some simple server code that uses the String class and had the server respond to a client request 500,000+ times with out a crash. Perhaps your code is defective.

If you are very cautious and know where the class is defective for en embedded environment, this is possible. But generally it's probably the worst decision of the Arduino makers to have this class included in the IDE. The way the OP uses the class he won't be able to answer 500'000 requests. And he does nothing the documentation says you shouldn't do.

pylon:

I've got some simple server code that uses the String class and had the server respond to a client request 500,000+ times with out a crash. Perhaps your code is defective.

If you are very cautious and know where the class is defective for en embedded environment, this is possible. But generally it's probably the worst decision of the Arduino makers to have this class included in the IDE. The way the OP uses the class he won't be able to answer 500'000 requests. And he does nothing the documentation says you shouldn't do.

Well, guess we will see if the deletion of the String class fixes the OP's issue. Specifically which String useage in the OP's origional posted code is causing his issue? Did the String memory location "go out of scope" in the OP's code? The issue you pointed to (below) may well fix any "bug" issue by emptying the memory location such that there is no longer memory that needs to be freeded in that location. I read closely the anti String posting and don't remember ever actually seeing an issue being fixed by the removal of String useage. I'll observe to see how this plays out.

    String buffer = "";

I read closely the anti String posting and don't remember ever actually seeing an issue being fixed by the removal of String useage.

I had several threads where the change from the String class to using character arrays fixed the problems.

Anyway, I didn't say that the line I posted was posing problems for the OP, that was just the indication that he uses the String class. Because I've seen lots of strange behaviors because of the usage of the String class, that's always the first thing I try to eliminate.

pylon:

I read closely the anti String posting and don't remember ever actually seeing an issue being fixed by the removal of String useage.

I had several threads where the change from the String class to using character arrays fixed the problems.

Anyway, I didn't say that the line I posted was posing problems for the OP, that was just the indication that he uses the String class. Because I've seen lots of strange behaviors because of the usage of the String class, that's always the first thing I try to eliminate.

Also DO NOT FLY ON AIRPLANES BECAUSE ONE CRASHED ONCE!!! I'm not a programmer, but I do look at the code where the Strings warnings are given, and the code posted usually does not involve the processes that supposedly invoke the "bug" as described by the "bug gurus". Giving String warnings that do not have to do with the issue being discussed is just a red flag for me that the people giving the warnings don't really understand the "bug" that they warning about.

I do not warn about airplanes when one of them crashed but when 60% of them crashed if the flight was longer than one hour, I'll take the ship.

I don't warn not to take the String class because I have a bad feeling but because I analyzed the code and brought that into the context of an MCU without a memory management unit like modern PCs have and with only very few kBs of RAM. Do the same and you'll get to the same conclusion.

In this thread the OP hasn't told us he has a specific problem. Nevertheless, in my opinion, I'm allowed to point him to potential problems that may arise from using the wrong libraries.

And I am a programmer, I also use the C++ string class in my programs for the PC but that's no reason to do the same in a completely different environment.