[pan2: 211/268] fixed win32 openssl support, works now, please test, too.



commit 566616fb1c7c624d508441fcf9f5deb9cbd66c73
Author: Heinrich MÃller <sphemuel stud informatik uni-erlangen de>
Date:   Sat Nov 26 19:31:02 2011 +0100

    fixed win32 openssl support, works now, please test, too.

 pan/gui/post-ui.cc               |    1 +
 pan/tasks/nntp-pool.cc           |    5 ++-
 pan/tasks/queue.cc               |   16 +++++-
 pan/tasks/socket-impl-gio.cc     |   16 ++----
 pan/tasks/socket-impl-main.cc    |   50 +++++++++++++++---
 pan/tasks/socket-impl-main.h     |   20 +++++++
 pan/tasks/socket-impl-openssl.cc |  112 ++++++++++++++++++++++++--------------
 pan/tasks/socket-impl-openssl.h  |    4 ++
 8 files changed, 161 insertions(+), 63 deletions(-)
---
diff --git a/pan/gui/post-ui.cc b/pan/gui/post-ui.cc
index 986e637..f8aba9c 100644
--- a/pan/gui/post-ui.cc
+++ b/pan/gui/post-ui.cc
@@ -445,6 +445,7 @@ namespace
   }
 }
 
+#undef DEFAULT_CHARSET
 #define DEFAULT_CHARSET  "UTF-8"
 
 void
diff --git a/pan/tasks/nntp-pool.cc b/pan/tasks/nntp-pool.cc
index f928a4a..f0b85ae 100644
--- a/pan/tasks/nntp-pool.cc
+++ b/pan/tasks/nntp-pool.cc
@@ -108,6 +108,7 @@ NNTP_Pool :: check_out ()
   NNTP * nntp (0);
 
   foreach (pool_items_t, _pool_items, it) {
+    debug("pool item "<<it->is_checked_in<<" "<<it->nntp);
     if (it->is_checked_in) {
       nntp = it->nntp;
       it->is_checked_in = false;
@@ -164,11 +165,13 @@ NNTP_Pool :: check_in (NNTP * nntp, Health health)
 ***/
 
 void
-NNTP_Pool :: on_socket_created (const StringView  & host UNUSED,
+NNTP_Pool :: on_socket_created (const StringView  & host,
                                 int                 port UNUSED,
                                 bool                ok,
                                 Socket            * socket)
 {
+
+  debug("on socket created "<<host<<" "<<ok<<" "<<socket);
   if (!ok)
   {
     delete socket;
diff --git a/pan/tasks/queue.cc b/pan/tasks/queue.cc
index 5717439..05a833f 100644
--- a/pan/tasks/queue.cc
+++ b/pan/tasks/queue.cc
@@ -312,17 +312,19 @@ Queue :: process_task (Task * task)
   }
   else if (state._work == Task::PAUSED)
   {
+    debug("paused");
     TaskUpload* t = dynamic_cast<TaskUpload*>(task);
     if (t)
       give_task_an_upload_slot(t);
 
-    TaskArticle* t2 = dynamic_cast<TaskArticle*>(task);
-    if (t2)
-      give_task_a_download_slot(t2);
+//    TaskArticle* t2 = dynamic_cast<TaskArticle*>(task);
+//    if (t2)
+//      give_task_a_download_slot(t2);
 
   }
   else if (state._work == Task::NEED_DECODER)
   {
+
     if (!_decoder_task)
       give_task_a_decoder (task);
   }
@@ -334,6 +336,7 @@ Queue :: process_task (Task * task)
 
   else while (_is_online && (state._work == Task::NEED_NNTP))
   {
+    debug("online");
     // make the requests...
     const Task::State::unique_servers_t& servers (state._servers);
     foreach_const (Task::State::unique_servers_t, servers, it)
@@ -344,14 +347,21 @@ Queue :: process_task (Task * task)
 
     Quark server;
     if (!find_best_server (servers, server))
+    {
+      debug("break");
       break;
+    }
 
     NNTP * nntp (get_pool(server).check_out ());
     if (!nntp)
+    {
+      debug("break");
       break;
+    }
 
     give_task_a_connection (task, nntp);
   }
+  debug("end loop");
 }
 
 /***
diff --git a/pan/tasks/socket-impl-gio.cc b/pan/tasks/socket-impl-gio.cc
index 6e66a01..73ff733 100644
--- a/pan/tasks/socket-impl-gio.cc
+++ b/pan/tasks/socket-impl-gio.cc
@@ -17,7 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/* #define DEBUG_SOCKET_IO */
+ #define DEBUG_SOCKET_IO
 
 /******
 *******
@@ -41,6 +41,7 @@ extern "C" {
 
 #ifdef G_OS_WIN32
   // this #define is necessary for mingw
+  #undef _WIN32_WINNT
   #define _WIN32_WINNT 0x0501
   #include <ws2tcpip.h>
   #undef gai_strerror
@@ -224,10 +225,9 @@ namespace
 #else
     channel = g_io_channel_win32_new_socket (sockfd);
 #endif
-    if (g_io_channel_get_encoding (channel) != NULL)
-      g_io_channel_set_encoding (channel, NULL, NULL);
+    g_io_channel_set_encoding (channel, NULL, NULL);
     g_io_channel_set_buffered (channel, true);
-    g_io_channel_set_line_term (channel, "\n", 1);
+//    g_io_channel_set_line_term (channel, "\n", 1);
     return channel;
   }
 }
@@ -286,6 +286,7 @@ GIOChannelSocket :: open (const StringView& address, int port, std::string& setm
 {
   _host.assign (address.str, address.len);
   _channel = create_channel (address, port, setme_err);
+  debug("SocketSSL open "<<_channel);
   return _channel != 0;
 }
 
@@ -447,12 +448,7 @@ GIOChannelSocket :: gio_func (GIOChannel   * channel,
   else // G_IO_IN or G_IO_OUT
   {
     const DoResult result = (cond & G_IO_IN) ? do_read () : do_write ();
-    /* I keep reading about crashes due to this check on OSX.
-     * _abort_flag is never set so this won't cause a problem.
-     * could be a bug in gcc 4.2.1.
-     */
-    /*if (_abort_flag)        _listener->on_socket_abort (this);
-    else*/ if (result == IO_ERR)   _listener->on_socket_error (this);
+    if (result == IO_ERR)   _listener->on_socket_error (this);
     else if (result == IO_READ)  set_watch_mode (READ_NOW);
     else if (result == IO_WRITE) set_watch_mode (WRITE_NOW);
   }
diff --git a/pan/tasks/socket-impl-main.cc b/pan/tasks/socket-impl-main.cc
index 5ab8156..d08089c 100644
--- a/pan/tasks/socket-impl-main.cc
+++ b/pan/tasks/socket-impl-main.cc
@@ -46,10 +46,19 @@
 #include <pan/general/string-view.h>
 #include "socket-impl-main.h"
 
+#ifdef G_OS_WIN32
+  #undef _WIN32_WINNT
+  #define _WIN32_WINNT 0x0501
+  #include <ws2tcpip.h>
+  #undef gai_strerror
+#endif
+
 using namespace pan;
 
-namespace pan
+namespace
 {
+  const unsigned int TIMEOUT_SECS (10);
+
   struct ThreadWorker : public WorkerPool::Worker,
                         public WorkerPool::Worker::Listener
   {
@@ -74,6 +83,13 @@ namespace pan
       server(s), host(h), port(p), listener(l), ok(false), socket(0), use_ssl(false) {}
 #endif
 
+    static gboolean handshake_done_cb(gpointer g)
+    {
+      GIOChannelSocketSSL* ssl (static_cast<GIOChannelSocketSSL*>(g));
+      if (ssl->get_done()) return false;
+      return true;
+    }
+
     void do_work ()
     {
 #ifdef HAVE_OPENSSL
@@ -98,27 +114,47 @@ namespace pan
   };
 }
 
-
 #ifdef HAVE_OPENSSL
+
+// TODO remove this later if it works with GMutex
+#ifdef G_OS_WIN32
+  #define MUTEX_TYPE HANDLE
+  #define MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
+  #define MUTEX_UNLOCK(x) ReleaseMutex(x)
+  #define THREAD_ID GetCurrentThreadId( )
+#else
+  #define MUTEX_TYPE Mutex
+  #define MUTEX_LOCK(x) x.lock()
+  #define MUTEX_UNLOCK(x) x.unlock()
+  #define THREAD_ID pthread_self( )
+#endif
+  #define MUTEX_SETUP(x) (x) = new MUTEX_TYPE[CRYPTO_num_locks()];
+  #define MUTEX_CLEANUP(x) delete [] x
 namespace
 {
-  static Mutex* mutex;
+  static MUTEX_TYPE* mutex;
 
   void gio_lock(int mode, int type, const char *file, int line)
   {
     if (mode & CRYPTO_LOCK)
-      mutex[type].lock();
+      MUTEX_LOCK(mutex[type]);//.lock();
     else
-      mutex[type].unlock();
+      MUTEX_UNLOCK(mutex[type]);//.unlock();
   }
 
   void ssl_thread_setup() {
-    mutex = new Mutex[CRYPTO_num_locks()];
+    MUTEX_SETUP(mutex);
+#ifdef G_OS_WIN32
+    for (int i = 0; i < CRYPTO_num_locks(); ++i) mutex[i] = CreateMutex(NULL, FALSE, NULL);
+#endif
     CRYPTO_set_locking_callback(gio_lock);
   }
 
   void ssl_thread_cleanup() {
-    delete [] mutex;
+#ifdef G_OS_WIN32
+    for (int i = 0; i < CRYPTO_num_locks(); ++i) CloseHandle(mutex[i]);
+#endif
+    MUTEX_CLEANUP(mutex);
     CRYPTO_set_locking_callback(0);
   }
 
diff --git a/pan/tasks/socket-impl-main.h b/pan/tasks/socket-impl-main.h
index 683d2b6..d76bcf0 100644
--- a/pan/tasks/socket-impl-main.h
+++ b/pan/tasks/socket-impl-main.h
@@ -156,6 +156,26 @@ namespace pan
                                   Socket::Creator::Listener * listener,
                                   bool               use_ssl);
 
+      struct Listener
+      {
+        virtual ~Listener() {}
+        /* functions that other listeners listen on */
+        virtual void on_handshake_done (X509* cert UNUSED, std::string server UNUSED, std::string cert_name UNUSED, int nr UNUSED) = 0;
+      };
+
+      typedef std::set<Listener*> listeners_t;
+      listeners_t _listeners;
+
+      void add_listener (Listener * l)    { _listeners.insert(l); }
+      void remove_listener (Listener * l) { _listeners.erase(l);  }
+
+      /* notify functions for listener list */
+      void handshake_done (X509* c, std::string server, std::string cn, int nr)
+      {
+        for (listeners_t::iterator it(_listeners.begin()), end(_listeners.end()); it!=end; ++it)
+          (*it)->on_handshake_done (c, server, cn, nr);
+      }
+
   };
 
 }
diff --git a/pan/tasks/socket-impl-openssl.cc b/pan/tasks/socket-impl-openssl.cc
index 60f38bb..31b0dc4 100644
--- a/pan/tasks/socket-impl-openssl.cc
+++ b/pan/tasks/socket-impl-openssl.cc
@@ -21,7 +21,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-/* #define DEBUG_SOCKET_IO */
+#define DEBUG_SOCKET_IO
 
 /******
 *******
@@ -36,6 +36,10 @@
 extern "C" {
   #include <unistd.h>
   #include <glib/gi18n.h>
+  #include <errno.h>
+  #include <fcntl.h>
+  #include <sys/time.h>
+  #include <sys/types.h>
 }
 
 #include <pan/usenet-utils/ssl-utils.h>
@@ -46,8 +50,10 @@ extern "C" {
 
 #ifdef G_OS_WIN32
   // this #define is necessary for mingw
+  #undef _WIN32_WINNT
   #define _WIN32_WINNT 0x0501
   #include <ws2tcpip.h>
+  #include <winsock2.h>
   #undef gai_strerror
 
   #define gai_strerror(i) gai_strerror_does_not_link (i)
@@ -116,6 +122,7 @@ GIOChannelSocketSSL :: GIOChannelSocketSSL (const Quark& server, SSL_CTX* ctx, C
    _channel (0),
    _tag_watch (0),
    _tag_timeout (0),
+   _handshake_timeout_tag(0),
    _listener (0),
    _out_buf (g_string_new (0)),
    _in_buf (g_string_new (0)),
@@ -123,7 +130,8 @@ GIOChannelSocketSSL :: GIOChannelSocketSSL (const Quark& server, SSL_CTX* ctx, C
    _ctx(ctx),
    _certstore(cs),
    _rehandshake(false),
-   _server(server)
+   _server(server),
+   _done(false)
 {
   debug ("GIOChannelSocketSSL ctor " << (void*)this);
   cs.add_listener(this);
@@ -178,6 +186,7 @@ GIOChannelSocketSSL :: create_channel (const StringView& host_in, int port, std:
       server.sin_port = htons(port);
       ++i;
       err = ::connect (sockfd,(struct sockaddr*)&server, sizeof(server));
+      debug ("connect "<<err<<" "<<i);
     }
 
     if (err) {
@@ -250,14 +259,17 @@ GIOChannelSocketSSL :: create_channel (const StringView& host_in, int port, std:
   GIOChannel * channel (0);
 #ifndef G_OS_WIN32
   channel = g_io_channel_unix_new (sockfd);
+  g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, 0);
 #else
   channel = g_io_channel_win32_new_socket (sockfd);
 #endif
   if (g_io_channel_get_encoding (channel) != 0)
     g_io_channel_set_encoding (channel, 0, 0);
-  g_io_channel_set_buffered (channel, true);
+  g_io_channel_set_buffered (channel,true);
   g_io_channel_set_line_term (channel, "\n", 1);
-  return ssl_get_iochannel(channel);
+  GIOChannel* ret (ssl_get_iochannel(channel));
+  debug ("SocketSSL "<<ret);
+  return ret;
 }
 
 namespace
@@ -291,7 +303,6 @@ namespace
     g_io_channel_unref(chan->giochan);
     SSL_shutdown(chan->ssl);
     SSL_free(chan->ssl);
-//    std::cerr<<"ssl free\n";
     g_free(chan);
   }
 }
@@ -301,10 +312,11 @@ GIOChannelSocketSSL :: ~GIOChannelSocketSSL ()
 
   _certstore.remove_listener(this);
 
-//  std::cerr << LINE_ID << " destroying socket " << this <<std::endl;
+  std::cerr << LINE_ID << " destroying socket " << this <<std::endl;
 
   remove_source (_tag_watch);
   remove_source (_tag_timeout);
+  remove_source (_handshake_timeout_tag);
 
   if (_channel)
   {
@@ -358,6 +370,29 @@ GIOChannelSocketSSL :: write_command (const StringView& command, Socket::Listene
 namespace
 {
 
+  static void set_blocking(SSL * ssl, bool val)
+  {
+    int fd, flags;
+    /* SSL_get_rfd returns -1 on error */
+    if(fd = SSL_get_fd(ssl))
+    {
+#ifndef G_OS_WIN32
+      flags = fcntl(fd, F_GETFL);
+      if (!val)
+        flags |= O_NONBLOCK;
+      else
+        flags &= ~O_NONBLOCK;
+      fcntl(fd, F_SETFL, flags);
+    }
+#else
+      u_long block(val ? 0 : 1);
+      ioctlsocket(fd, FIONBIO, &block);
+    }
+#endif
+
+  }
+
+
   static GIOStatus ssl_errno(gint e)
   {
     switch(e)
@@ -394,12 +429,11 @@ namespace
     mydata.cert_name = CertStore::build_cert_name(host);
     mydata.server = server;
     SSL_set_ex_data(chan->ssl, SSL_get_fd(chan->ssl), &mydata);
+    SSL_set_verify(chan->ssl,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
 
     if (session) ret = SSL_set_session(chan->ssl, session);
 //    if (rehandshake)
 //    {
-////    SSL_set_verify(ssl,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
-//
 //      /* Stop the client from just resuming the un-authenticated session */
 //      SSL_set_session_id_context(chan->ssl, (void *)&s_server_auth_session_id_context, sizeof(s_server_auth_session_id_context));
 //
@@ -414,36 +448,40 @@ namespace
     ret = SSL_connect(chan->ssl);
     if (ret <= 0) {
       err = SSL_get_error(chan->ssl, ret);
+      return ret;
       switch (err) {
         case SSL_ERROR_WANT_READ:
-          return 1;
+          debug("SSL handshake failed: wants to read");
+           if (SSL_pending (chan->ssl)) return 1;
+           return 1;
         case SSL_ERROR_WANT_WRITE:
+          debug("SSL handshake failed: wants to write");
+          if (SSL_pending (chan->ssl)) return 1;
           return 3;
         case SSL_ERROR_ZERO_RETURN:
-//          g_warning("SSL handshake failed: %s", "server closed connection");
+          debug("SSL handshake failed: server closed connection");
           return -1;
         case SSL_ERROR_SYSCALL:
           errstr = ERR_reason_error_string(ERR_get_error());
           if (errstr == NULL && ret == -1)
             errstr = strerror(errno);
-//          g_warning("SSL handshake failed: %s", errstr != NULL ? errstr : "server closed connection unexpectedly");
+          debug("SSL handshake failed: "<<(errstr != NULL ? errstr : "server closed connection unexpectedly"));
           return -1;
         default:
           errstr = ERR_reason_error_string(ERR_get_error());
-//          g_warning("SSL handshake failed: %s", errstr != NULL ? errstr : "unknown SSL error");
+          debug("SSL handshake failed: "<<(errstr != NULL ? errstr : "unknown SSL error"));
           return -1;
       }
     }
 
     cert = SSL_get_peer_certificate(chan->ssl);
     if (!cert) {
-      g_warning("SSL server supplied no certificate");
+      debug("SSL server supplied no certificate");
       return -1;
     }
 
     ret = !chan->verify || ssl_verify(chan->ssl, chan->ctx, host.c_str(), cert);
     X509_free(cert);
-
     return ret ? 0 : -1;
 
   }
@@ -457,9 +495,8 @@ namespace
   {
 
     GIOSSLChannel *chan = (GIOSSLChannel *)handle;
-
     gint err;
-    size_t tmp_size(4096*128);
+    const size_t tmp_size(4096*128);
     char tmp[tmp_size];
     g_string_set_size(g,0);
 
@@ -687,10 +724,8 @@ GIOChannelSocketSSL :: gio_func (GIOChannel   * channel,
 
 gboolean
 GIOChannelSocketSSL :: gio_func (GIOChannel   * channel,
-                              GIOCondition   cond)
+                                 GIOCondition   cond)
 {
-  debug ("gio_func: sock " << this << ", channel " << channel << ", cond " << cond);
-
   set_watch_mode (IGNORE_NOW);
 
   if (_abort_flag)
@@ -704,17 +739,14 @@ GIOChannelSocketSSL :: gio_func (GIOChannel   * channel,
   else // G_IO_IN or G_IO_OUT
   {
     const DoResult result = (cond & G_IO_IN) ? do_read () : do_write ();
-    /* I keep reading about crashes due to this check on OSX.
-     * _abort_flag is never set so this won't cause a problem.
-     * could be a bug in gcc 4.2.1.
-     */
-    /*if (_abort_flag)        _listener->on_socket_abort (this);
-    else*/ if (result == IO_ERR)   _listener->on_socket_error (this);
+    if (result == IO_ERR)   _listener->on_socket_error (this);
     else if (result == IO_READ)  set_watch_mode (READ_NOW);
     else if (result == IO_WRITE) set_watch_mode (WRITE_NOW);
   }
 
-  return false; // set_watch_now(IGNORE) cleared the tag that called this func
+  debug ("gio_func: sock " << this << ", channel " << channel << ", cond " << (cond==G_IO_IN ? "IN" : "OUT"));
+
+  return false; // set_watch_mode(IGNORE) cleared the tag that called this func
 }
 
 namespace
@@ -725,7 +757,8 @@ namespace
 void
 GIOChannelSocketSSL :: set_watch_mode (WatchMode mode)
 {
-  debug ("socket " << this << " calling set_watch_mode " << mode << "; _channel is " << _channel);
+  GIOSSLChannel *chan = (GIOSSLChannel *)_channel;
+  debug ("socket " << this << " calling set_watch_mode " << mode << "; _channel is " << chan->giochan);
   remove_source (_tag_watch);
   remove_source (_tag_timeout);
 
@@ -734,30 +767,29 @@ GIOChannelSocketSSL :: set_watch_mode (WatchMode mode)
   {
     case IGNORE_NOW:
       // don't add any watches
-      debug("channel " << _channel << " setting mode **IGNORE**");
+      debug("channel " << chan->giochan << " setting mode **IGNORE**");
       break;
 
     case READ_NOW:
-      debug("channel " << _channel << " setting mode read");
+      debug("channel " << chan->giochan << " setting mode read");
       cond = (int)G_IO_IN | (int)G_IO_ERR | (int)G_IO_HUP | (int)G_IO_NVAL;
-      _tag_watch = g_io_add_watch (_channel, (GIOCondition)cond, gio_func, this);
+      _tag_watch = g_io_add_watch (chan->giochan, (GIOCondition)cond, gio_func, this);
       _tag_timeout = g_timeout_add (TIMEOUT_SECS*1000, timeout_func, this);
       _io_performed = false;
       break;
 
     case WRITE_NOW:
-      debug("channel " << _channel << " setting mode write");
+      debug("channel " << chan->giochan << " setting mode write");
       cond = (int)G_IO_OUT | (int)G_IO_ERR | (int)G_IO_HUP | (int)G_IO_NVAL;
-      _tag_watch = g_io_add_watch (_channel, (GIOCondition)cond, gio_func, this);
+      _tag_watch = g_io_add_watch (chan->giochan, (GIOCondition)cond, gio_func, this);
       _tag_timeout = g_timeout_add (TIMEOUT_SECS*1000, timeout_func, this);
       _io_performed = false;
       break;
   }
 
-  debug ("set_watch_mode " << mode << ": _tag_watch is now " << _tag_watch);
+  debug ("set_watch_mode " << (mode==READ_NOW?"READ":mode==WRITE_NOW?"WRITE":"IGNORE") << ": _tag_watch is now " << _tag_watch);
 }
 
-
 GIOChannel *
 GIOChannelSocketSSL :: ssl_get_iochannel(GIOChannel *handle, gboolean verify)
 {
@@ -804,17 +836,13 @@ GIOChannelSocketSSL :: ssl_get_iochannel(GIOChannel *handle, gboolean verify)
   gchan->read_buf = g_string_sized_new(4096*128);
 
   int ret;
-#ifndef G_OS_WIN32
-  if ((ret = ssl_handshake(_server, gchan, this, &_certstore,
-                           _host, _session, _rehandshake)) == 0)
+  set_blocking(ssl, true);
+  if (ssl_handshake(_server, gchan, this, &_certstore,_host, _session,_rehandshake) == 0)
   {
-    g_io_channel_set_flags (handle, G_IO_FLAG_NONBLOCK, 0);
+    set_blocking(chan->ssl, false);
     return gchan;
   }
-#else
-  while (ssl_handshake(_server, gchan, this, &_certstore,_host, _session, _rehandshake)!=0) ;
-  return gchan;
-#endif
+  set_blocking(chan->ssl, false);
   return 0;
 }
 
diff --git a/pan/tasks/socket-impl-openssl.h b/pan/tasks/socket-impl-openssl.h
index 3de0c55..ddacd0c 100644
--- a/pan/tasks/socket-impl-openssl.h
+++ b/pan/tasks/socket-impl-openssl.h
@@ -67,6 +67,7 @@ namespace pan
       GIOChannel * _channel;
       unsigned int _tag_watch;
       unsigned int _tag_timeout;
+      unsigned int _handshake_timeout_tag;
       Socket::Listener * _listener;
       GString * _out_buf;
       GString * _in_buf;
@@ -78,9 +79,11 @@ namespace pan
       SSL_SESSION* _session;
       bool _rehandshake;
       Quark _server;
+      bool _done;
 
     public:
       void set_rehandshake (bool setme) { _rehandshake = setme; }
+      bool get_done() { return _done; }
 
     private:
       enum WatchMode { READ_NOW, WRITE_NOW, IGNORE_NOW };
@@ -101,6 +104,7 @@ namespace pan
 
     private:
       GIOChannel* ssl_get_iochannel(GIOChannel *handle, gboolean verify=true);
+      static gboolean handshake_cb(gpointer ptr);
 
 #else
   class GIOChannelSocketSSL



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]