Example #1
0
    def handshake(self, conn, env):

        peer_id   = env['HTTP_X_MIFCHO_ID']

        res_status      = 200                       # Regular connection
        res_status_msg  = 'OK'
        res_headers     = [
          ('X-Mifcho-Id', self.cm.identifier)
        ]
                                                    # "Reversed" connection
        reverse = env.get('HTTP_UPGRADE') == 'mifcho-reverse/0.1'

        if reverse:
            res_status      = 101
            res_status_msg  = 'Switching Protocol'

            res_headers.append(('Upgrade', env['HTTP_UPGRADE']))

        try:                                      # Inform peer

            messages.send_response(
              conn,
              res_status,
              res_status_msg,
              'HTTP/1.1',
              res_headers
            )

        except:
            logging.error('Failed sending response to "handshake".')
            raise

        if reverse: # Store for later use (tunnel requests)
            self.cm.add_peer(PeerInfo(peer_id, conn))
Example #2
0
  def work(self, env):
      
    conn = env['mifcho.conn']
    
    opened_sockets = []
    for bo in self.cm.opened:
      try:
        opened_sockets.append({'sockname': bo.getsockname(), 'peername':bo.getpeername()})
      except:
        opened_sockets.append({'sockname': 'Not connected', 'peername':'Not connected'})

    serializable_perf = {
      'peers':          [repr(peer) for peer in self.cm.peers],
      'bound_sockets':  [{'sockname': bs.getsockname()} for bs in self.cm.bound],
      'opened_sockets': opened_sockets,
      'perf_log':       [x for x in self.cm.performance_collector.log()]
    }

    try:
      res_body = json.dumps(serializable_perf)
      res_headers = [('Content-Length', len(res_body)),
                     ('Content-Type', 'text/html'),
                     ('Access-Control-Allow-Origin', '*')]

      messages.send_response(conn, 200, 'OK', 'HTTP/1.1', res_headers)
      conn.sendall(res_body)

      self.cm.teardown(conn)
    except:
      logging.debug('Something went wrong', exc_info=3)
Example #3
0
 def tunnel(self, conn, env):
     
     logging.debug('TUNNEL')
     
     if 'HTTP_X_MIFCHO_TUNNEL_ID' in env: # We requested the tunnel
         
         logging.debug('We requested the tunnel...')
         
         tunnel = self.cm.tunnels[env['HTTP_X_MIFCHO_TUNNEL_ID']]
         tunnel.peer_connection = conn
         
         messages.send_response(conn,
             code      = 101,
             message   = 'Switching Protocols',
             headers   = [
               ('X-Mifcho-Id', env['mifcho.id'])
             ]
         )
         
         tunnel.event.set()
         
     else:   # We did not request the tunnel so this is an indirect tunnel carrier.
         
         logging.debug('We did not request it...')
         ep_address = (
             env['HTTP_X_MIFCHO_TUNNEL_ENDPOINTHOST'],
             int(headers['X_MIFCHO_TUNNEL_ENDPOINTPORT'])
         )        
         
         ep_conn = self.cm.connect(ep_address)
         
         if conn and ep_conn:
             
             logging.debug('Successfully contacted endpoint...')
             tunnel    = Tunnel.fromconnections(conn, ep_conn)
             tunnel.id = str(uuid.uuid4())
             
             self.cm.add_tunnel(tunnel)
             
             messages.send_response(conn,
                 code      = 101,
                 message   = 'Switching Protocols',
                 headers   = [
                   ('X-Mifcho-Id', self.cm.identifier)
                 ]
             )            
         
             pipe = Piper(self.cm, conn, ep_conn, 4096, sink_recovery=(ep_address, None))
             pipe.start()
             self.cm.pipes.append(pipe)
         else:
             logging.error('Failed connecting to endpoint [%s].' % repr(address))
             self.cm.teardown(conn)
Example #4
0
 def start_response(status, response_headers, exc_info=None):
     
     status          = status
     headers_sent    = response_headers
     
     messages.send_response(    
         conn,
         int(status.split(' ')[0]),
         message =status.split(' ')[1],
         version ='HTTP/1.1',
         headers = response_headers
     )
     return write
Example #5
0
    def same_origin_sec(self, conn):

        # Doing options
        res_headers = [
            ('Server', '%s/%s' % (self.server_name, self.server_ver)),
            ('Access-Control-Allow-Origin',   ','.join(self.ac_origins)),
            ('Access-Control-Allow-Methods',  ','.join(self.ac_methods)),
            ('Access-Control-Allow-Headers',  ','.join(self.ac_headers)),
            ('Access-Control-Max-Age', repr(self.ac_max_age)),
            ('Content-Length', '0'),
            ('Connection', 'Keep-Alive')
        ]
        messages.send_response(conn, 200, 'OK', self.http_ver, res_headers)
Example #6
0
    def _ws_handshake(self, env):
        
        conn = env['mifcho.conn']
        
        headers = [
            ('Upgrade',             'WebSocket'),
            ('Connection',          'Upgrade'),
            ('Sec-WebSocket-Origin',    env['HTTP_ORIGIN']),
            ('Sec-WebSocket-Protocol',  'sample'),
            ('Sec-WebSocket-Location',  'ws://%s%s' % (env['HTTP_HOST'], env['PATH_INFO'])),            
        ]
        
        key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
        key2 = env['HTTP_SEC_WEBSOCKET_KEY2'],
        key3 = conn.recv(8)
        
        server_key = websocket.keys_to_md5(key1, key2, key3)
        
        messages.send_response(
            conn,
            101,
            'Web Socket Protocol Handshake',
            'HTTP/1.1',
            headers
        )
        conn.send(server_key)

        # Grab connection parameters
        
        ep_stuff  = None
        peer_id   = None
        req_path  = env['PATH_INFO'].split('/')

        if len(req_path) == 4:  # Directly
            ep_stuff = (_, _, ep_host, ep_port) = req_path

        elif len(req_path) == 5: # Via Peer
            ep_stuff = (_, _, ep_host, ep_port, peer_id) = req_path
        else:
            logging.error('Invalid path! %s' % repr(data))

        if ep_stuff:
            ep_address = (ep_host, int(ep_port))

            # Initiate endpoint connection
            vnc_conn = self.cm.connect(ep_address, peer_id)
            
        sink_recovery = (ep_address, peer_id)
        return (conn, vnc_conn, sink_recovery)
Example #7
0
  def work(self, env):

    conn = env['mifcho.conn']

    path = self.path_prefix + os.sep + "/".join(env['PATH_INFO'].split('?')[0].split('/')[2:])

    status      = 404
    status_msg  = 'File Not Found'
    res_body    = '404 - File Not Found'
    content_type = ('Content-Type', 'text/plain')

    if os.path.exists(path):

      status      = 200
      status_msg  = 'OK'
      
      if os.path.isdir(path):
        res_body = pprint.pformat(os.listdir(path))
      else:
        fd = open(path)
        res_body = fd.read()
        fd.close()

      content_type    = ('Content-Type', mimetypes.guess_type(path)[0])
    
    res_headers = [
      ('Content-Length', len(res_body)),
      content_type,
      ('Access-Control-Allow-Origin', '*')
    ]

    messages.send_response(
      conn,
      status,
      status_msg,
      'HTTP/1.1',
      res_headers
    )
    if res_body:
      conn.sendall(res_body)
    
    try:
      conn.close()
    except:
      logging.debug('Something went wrong when trying to close socket.', exc_info=3)
Example #8
0
    def work(self, env):
        
        conn = env['mifcho.conn']

        i = 0;

        try:
            
            if env['REQUEST_METHOD'] == 'GET' and string.find(env['PATH_INFO'], 'create') > -1:

                ep_stuff  = None
                prefix  = ''
                method  = ''
                rid     = 0
                wait    = 50                    
                ep_host = ''
                ep_port = 0
                peer_id = None
                req_path  = env['PATH_INFO'].split('/')

                if len(req_path) == 7:  # Directly
                    ep_stuff = ( _, prefix, method, rid, wait, ep_host, ep_port ) = req_path
                    
                elif len(req_path) == 8: # Via Peer
                    ep_stuff = ( _, prefix, method, rid, wait, ep_host, ep_port, peer_id ) = req_path
                    
                else:
                    logging.error('Invalid path! %s' % repr(data))
                
                rid         = int(rid)
                wait        = int(wait)
                ep_address  = (ep_host, int(ep_port))

                # Assume failure, overwritten on successful connect
                sid = ''
                ep_status = 404
                ep_status_msg = 'Connection Denied.'

                # Try and connect to end-point
                try:
                    vnc_conn = self.cm.connect(ep_address, peer_id)

                    if not vnc_conn:
                        logging.error('Could not connect to endpoint!')

                    sid = "%d" % uuid.uuid1().int
                    ep_status = 200
                    ep_status_msg = 'OK'
                    
                    pipe = HobsVncPiper(self.cm, None, vnc_conn, sink_recovery=(ep_address, peer_id))
                    
                    HobsHandler.hobs_sessions[sid] = {'rid': rid, 'wait': wait, 'pipe':pipe}
                    pipe.start()

                except:
                    logging.error('Error when connecting to end-point host %s' % repr(ep_address), exc_info=3)

                headers = [ ('Content-Length', len(sid)),
                            ('Access-Control-Allow-Origin', '*')
                          ]
                messages.send_response(conn, ep_status, ep_status_msg, 'HTTP/1.1', headers)
                conn.sendall(sid)

            # Receive data that should be forwarded
            elif env['REQUEST_METHOD'] == 'POST' and string.find(env['PATH_INFO'], 'session') > -1:

                hobs  = HobsHandler._HOBS_SESSION_SEND.search(env['PATH_INFO'])
                sid   = hobs.group(1)                
                rid   = int(hobs.group(2))
                
                session = HobsHandler.hobs_sessions[sid]
                if (session['rid']+1) == rid:
                    session['rid'] = rid
                else:
                    logging.error('Incorrect RID, %d, %d.' % (rid, session['rid']))

                req_txt = ''
                
                if len(env['wsgi.input']) > 0:
                    
                    #stuff it into the piper                    
                    session['pipe'].hobs_in_queue.put(env['wsgi.input'])
                    
                headers = [
                    ('Content-Length',  '0'),
                    ('Access-Control-Allow-Origin', '*')
                ]

                messages.send_response(conn, 200, 'OK', 'HTTP/1.1', headers)

            # GET, hang on to this until we have something to send...
            elif env['REQUEST_METHOD'] == 'GET' and string.find(env['PATH_INFO'], 'session') > -1:

                hobs  = HobsHandler._HOBS_SESSION_RECV.search(env['PATH_INFO'])
                sid   = hobs.group(1)

                data = []
                q = HobsHandler.hobs_sessions[sid]['pipe'].hobs_out_queue

                # Grab data until buffer is empty
                block   = False
                timeout = 0

                while self.running:

                    # This is so far the best strategy... but it seems way too inefficient... severe latency issues..
                    try:
                        # Get from piper queue
                        data.append(q.get(block, timeout)) # NOTE: This blocking halt delays the exit of mifcho
                        q.task_done()

                        if len(data) > 0 and block: # Data arrived while blocking, timeout is "reset"
                            block   = False
                            timeout = 0

                    except Queue.Empty:

                        if len(data)>0: # Buffer has been sucked dry
                            break

                        elif block:     # No data and we have already blocked and timed out
                            break

                        else:       # No data so block until data is available or timeout exceeds
                            block = True
                            timeout = 30
            
                buf = base64.b64encode(''.join(data))
                headers = [
                            ('Content-Length', str(len(buf))),
                            ('Content-Type',    'text/plain'),
                            ('Access-Control-Allow-Origin', '*')
                          ]
                
                messages.send_response(conn, 200, 'OK', 'HTTP/1.1', headers)
                conn.sendall(buf)
            else:
                logging.error('Unsupported HOBS request! %s.' % (repr(req_uri)))

        except:
            logging.error('Something went terribly wrong in the Hobs-handling...', exc_info=3)
        
        i += 1

        self.cm.teardown(conn)