title: Creating new process for each request on SSL socket gives "TypeError: Cannot serialize socket object", but doing same with normal/non SSL socket works
body: <p>I am trying to use keys and certificate generated using java <code>keytool</code> in python server and java client. I have created key &amp; keystore, exported certificate, added certificate to truststore, converted keystore to standard pkcs format and then extracted key and certificate from pkcs to use in python server. (first three steps from <a href="https://docs.oracle.com/cd/E19830-01/819-4712/ablrb/index.html" rel="nofollow noreferrer">here</a> and last three steps from <a href="https://security.stackexchange.com/a/66865/89945">here</a>). This question is somewhat follow up of <a href="https://stackoverflow.com/questions/50860354/unable-to-perform-communication-between-java-client-and-python-server-with-ssl/50861563#50861563">this question</a> and detailed steps for generating key and certificate can be found in <a href="https://stackoverflow.com/questions/50860354/unable-to-perform-communication-between-java-client-and-python-server-with-ssl/50861563#50861563">that question</a>.</p>
  
  <p>My SSL server looks like this</p>
  
  <p><strong>server.py</strong></p>
  
  <pre><code>import socket
  import multiprocessing as mup
  import ssl
  
  def worker_ssl(data_socket, client_address):
      print("Inside worker")
      #some processing
  
  def start_server_ssl():
  
      socketObj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      server_address = ("127.0.0.1", 6000)
      socketObj.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      socketObj.bind(server_address)
      socketObj.listen(10)
  
      ssl_socket = ssl.wrap_socket(socketObj,
                              server_side = True,
                              certfile="cert.pem",
                              keyfile="key.pem")        
  
      while True:
          print("Waiting For Connections .........\n")
          try:
              data_socket, client_address = ssl_socket.accept()
  
              process = mup.Process(target=worker_ssl, args=(data_socket, client_address))            
              process.daemon = True
              process.start()
  
          except socket.error as msg:
              print (" [ERROR] : %s " % msg)
              continue
  
      socketObj.close()
      ssl_socket.shutdown(socket.SHUT_RDWR)
      ssl_socket.close()
  
  if __name__ == '__main__':
      start_server_ssl()
  </code></pre>
  
  <p>SSL Client looks like this:</p>
  
  <p><strong>Client4Py.java</strong></p>
  
  <pre><code>import java.io.BufferedWriter;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.OutputStreamWriter;
  import java.io.PrintWriter;
  import java.nio.charset.StandardCharsets;
  import java.security.KeyStore;
  
  import javax.net.ssl.KeyManagerFactory;
  import javax.net.ssl.SSLContext;
  import javax.net.ssl.SSLSocket;
  import javax.net.ssl.SSLSocketFactory;
  import javax.net.ssl.TrustManager;
  import javax.net.ssl.TrustManagerFactory;
  
  public class Client4Py {
      static KeyStore ks;
      static KeyManagerFactory kmf;
      static TrustManagerFactory tmf;
      static SSLContext sc;
      static TrustManager[] trustManagers;
  
      static {
          try {
              ks = KeyStore.getInstance("JKS");
              ks.load(new FileInputStream("D:\\javasslstores\\truststore.jks"), "passwd123".toCharArray());
  
              kmf = KeyManagerFactory.getInstance("SunX509");
              kmf.init(ks, "passwd123".toCharArray());
  
              tmf = TrustManagerFactory.getInstance("SunX509"); 
              tmf.init(ks);
  
              sc = SSLContext.getInstance("TLS"); 
  
              sc.init(null, tmf.getTrustManagers(), null);
          } catch (Exception e) {
              System.out.println(e.getMessage());
              System.out.println(e.getStackTrace());
          }
      }
  
      public static void main(String[] args) throws IOException {
          SSLSocketFactory ssf = sc.getSocketFactory();
          SSLSocket socket = (SSLSocket) ssf.createSocket("127.0.0.1", 6000);
          socket.startHandshake();
  
          PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),StandardCharsets.UTF_8)));
          //PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
  
          out.println("&lt;&lt;startMessage&gt;&gt;");
          out.println("Message from Client4Py");
          out.println("&lt;&lt;endMessage&gt;&gt;");
          out.flush();
  
          if (out.checkError())
              System.out.println(
                  "SSLSocketClient:  java.io.PrintWriter error");
  
          out.close();
          socket.close();
      }
  }
  </code></pre>
  
  <p>The output on server's console after first running server and then the client is as follows:</p>
  
  <pre><code>1    Waiting For Connections .........
  2    
  3    Traceback (most recent call last):
  4      File "D:\workspaces\workspace6\PythonServer\server.py", line 40, in &lt;module&gt;
  5        start_server_ssl()
  6      File "D:\workspaces\workspace6\PythonServer\server.py", line 29, in start_server_ssl
  7        process.start()
  8      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\process.py", line 105, in start
  9        self._popen = self._Popen(self)
  10      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\context.py", line 223, in _Popen
  11        return _default_context.get_context().Process._Popen(process_obj)
  12      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\context.py", line 322, in _Popen
  13        return Popen(process_obj)
  14      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\popen_spawn_win32.py", line 65, in __init__
  15        reduction.dump(process_obj, to_child)
  16      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\reduction.py", line 60, in dump
  17        ForkingPickler(file, protocol).dump(obj)
  18      File "D:\Programs\python\python-3.6.6-amd64\lib\socket.py", line 185, in __getstate__
  19        raise TypeError("Cannot serialize socket object")
  20    TypeError: Cannot serialize socket object
  21    Traceback (most recent call last):
  22      File "&lt;string&gt;", line 1, in &lt;module&gt;
  23      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\spawn.py", line 99, in spawn_main
  24        new_handle = reduction.steal_handle(parent_pid, pipe_handle)
  25      File "D:\Programs\python\python-3.6.6-amd64\lib\multiprocessing\reduction.py", line 87, in steal_handle
  26        _winapi.DUPLICATE_SAME_ACCESS | _winapi.DUPLICATE_CLOSE_SOURCE)
  27    PermissionError: [WinError 5] Access is denied
  </code></pre>
  
  <p>You can see on line 20, there is <code>TypeError: Cannot serialize socket object</code>. </p>
  
  <p><strong>Code starts working after removing all SSL stuffs</strong> </p>
  
  <p>When I comment call to <code>wrap_socket()</code>, replace <code>ssl_socket.accept()</code> with <code>socketObject.accept()</code> and comment <code>ssl_socket.shutdown()</code> and <code>close()</code>, the code starts working. It creates new process from <code>worker()</code> as desired and ends printing <code>Inside worker</code> on console. Here is the modified non SSL server:</p>
  
  <pre><code>import socket
  import multiprocessing as mup
  # import ssl
  
  def worker_ssl(data_socket, client_address):
      print("Inside worker")
      #some processing
  
  def start_server_ssl():
  
      socketObj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      server_address = ("127.0.0.1", 6000)
      socketObj.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      socketObj.bind(server_address)
      socketObj.listen(10)
  
  #     ssl_socket = ssl.wrap_socket(socketObj,
  #                             server_side = True,
  #                             certfile="cert.pem",
  #                             keyfile="key.pem")        
  
      while True:
          print("Waiting For Connections .........\n")
          try:
              data_socket, client_address = socketObj.accept()
  
              process = mup.Process(target=worker_ssl, args=(data_socket, client_address))            
              process.daemon = True
              process.start()
  
          except socket.error as msg:
              print (" [ERROR] : %s " % msg)
              continue
  
      socketObj.close()
  #     ssl_socket.shutdown(socket.SHUT_RDWR)
  #     ssl_socket.close()
  
  if __name__ == '__main__':
      start_server_ssl()
  </code></pre>