Add method to validate a Client.

A client is invalid if it not connected to an agent or may become
invalid if the agent process changes.
diff --git a/browser/include/content_analysis/sdk/analysis_client.h b/browser/include/content_analysis/sdk/analysis_client.h
index c7c5da8..8bb8ddc 100644
--- a/browser/include/content_analysis/sdk/analysis_client.h
+++ b/browser/include/content_analysis/sdk/analysis_client.h
@@ -70,6 +70,10 @@
   // that match.
   virtual int CancelRequests(const ContentAnalysisCancelRequests& cancel) = 0;
 
+  // Checks to see if the client is still valid.  For example, the client can
+  // become invalid if the pipe broke due to an agent restart.
+  virtual bool IsValid() = 0;
+
  protected:
   Client() = default;
   Client(const Client& rhs) = delete;
diff --git a/browser/src/client_mac.cc b/browser/src/client_mac.cc
index fd0902e..41de1db 100644
--- a/browser/src/client_mac.cc
+++ b/browser/src/client_mac.cc
@@ -29,5 +29,9 @@
   return -1;
 }
 
+bool ClientMac::IsValid() {
+  return false;
+}
+
 }  // namespace sdk
 }  // namespace content_analysis
diff --git a/browser/src/client_mac.h b/browser/src/client_mac.h
index f3c640d..bdb46a4 100644
--- a/browser/src/client_mac.h
+++ b/browser/src/client_mac.h
@@ -20,6 +20,7 @@
            ContentAnalysisResponse* response) override;
   int Acknowledge(const ContentAnalysisAcknowledgement& ack) override;
   int CancelRequests(const ContentAnalysisCancelRequests& cancel) override;
+  bool IsValid() override;
 };
 
 }  // namespace sdk
diff --git a/browser/src/client_posix.cc b/browser/src/client_posix.cc
index bd62b84..5807d66 100644
--- a/browser/src/client_posix.cc
+++ b/browser/src/client_posix.cc
@@ -29,5 +29,9 @@
   return -1;
 }
 
+bool ClientPosix::IsValid() {
+  return false;
+}
+
 }  // namespace sdk
 }  // namespace content_analysis
diff --git a/browser/src/client_posix.h b/browser/src/client_posix.h
index 9e7666d..e5e6ed3 100644
--- a/browser/src/client_posix.h
+++ b/browser/src/client_posix.h
@@ -20,6 +20,7 @@
            ContentAnalysisResponse* response) override;
   int Acknowledge(const ContentAnalysisAcknowledgement& ack) override;
   int CancelRequests(const ContentAnalysisCancelRequests& cancel) override;
+  bool IsValid() override;
 };
 
 }  // namespace sdk
diff --git a/browser/src/client_win.cc b/browser/src/client_win.cc
index 9d3d7e8..3a93094 100644
--- a/browser/src/client_win.cc
+++ b/browser/src/client_win.cc
@@ -337,6 +337,22 @@
       ? 0 : -1;
 }
 
+bool ClientWin::IsValid() {
+  // The client is invalid if the pipe has not been created.
+  if (hPipe_ == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  // The client is invalid if the agent has changed since the client last
+  // connected.
+  unsigned long pid = 0;
+  if (!GetNamedPipeServerProcessId(hPipe_, &pid) || pid != agent_info().pid) {
+    return false;
+  }
+
+  return true;
+}
+
 // static
 DWORD ClientWin::ConnectToPipe(const std::string& pipename, HANDLE* handle) {
   // Get pointers to the Ntxxx functions.  This is required to use absolute
diff --git a/browser/src/client_win.h b/browser/src/client_win.h
index f4bdd83..fcfe9d2 100644
--- a/browser/src/client_win.h
+++ b/browser/src/client_win.h
@@ -23,6 +23,7 @@
            ContentAnalysisResponse* response) override;
   int Acknowledge(const ContentAnalysisAcknowledgement& ack) override;
   int CancelRequests(const ContentAnalysisCancelRequests& cancel) override;
+  bool IsValid() override;
 
  private:
   static DWORD ConnectToPipe(const std::string& pipename, HANDLE* handle);