Moved core code up to oftest directory
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 9d5f77b..4f0690c 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -534,11 +534,7 @@
 # directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
-INPUT                  = "../src/python/oftest/protocol" \
-                         "../src/python/oftest/controller" \
-                         "../src/python/oftest/dataplane" \
-                         "../src/python/oftest/packet" \
-                         "../src/python/oftest"
+INPUT                  = "../src/python/oftest"
 
 # This tag can be used to specify the character encoding of the source files 
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
diff --git a/src/python/oftest/controller.py b/src/python/oftest/controller.py
index 25e5080..4262ca9 100644
--- a/src/python/oftest/controller.py
+++ b/src/python/oftest/controller.py
@@ -19,9 +19,6 @@
 @todo Set up reasonable logging facility
 """
 
-import sys
-sys.path.append("../protocol")
-sys.path.append("../")
 from oft_config import *
 import os
 import socket
@@ -32,6 +29,7 @@
 from message import *
 from parse import *
 from netutils import *
+from ofutils import *
 
 class Controller(Thread):
     """
@@ -58,7 +56,7 @@
     @var packets_total Total number of packets received
     @var packets_expired Number of packets popped from queue as queue full
     @var packets_handled Number of packets handled by something
-    @var state Debug indication of state
+    @var dbg_state Debug indication of state
     """
 
     def __init__(self, max_pkts=1024):
@@ -79,7 +77,7 @@
         self.passive = True
         self.packets_expired = 0
         self.packets_handled = 0
-        self.state = "init" # Debug
+        self.dbg_state = "init"
         self.listen_socket = None
         self.switch_socket = None
         self.switch_addr = None
@@ -92,6 +90,9 @@
         self.xid = None
         self.xid_response = None
 
+        # Connection condition variable to notify anyone waiting for a cxn
+        self.connect_cv = Condition()
+
     def dbg(self, level, string):
         debug_log("CTRL", self.debug_level, level, string)
 
@@ -107,8 +108,8 @@
 
         If already connected, will close the current connection
         """
-        oldstate = self.state
-        self.state = "connecting"
+        oldstate = self.dbg_state
+        self.dbg_state = "connecting"
         if self.connected:
             self.dbg(DEBUG_WARN, "Disconnect when already connected")
             self.disconnect()
@@ -116,7 +117,7 @@
         if not self.passive:
             print "Error in controller init: Active cxn not supported"
             # raise unsupported
-            self.state = oldstate
+            self.dbg_state = oldstate
             return False
 
         # FIXME: add error handling; try SocketServer?
@@ -128,17 +129,17 @@
             self.listen_socket.setsockopt(socket.SOL_SOCKET, 
                                           socket.SO_REUSEADDR, 1)
             self.listen_socket.bind((self.host, self.port))
-        self.state = "listening"
+        self.dbg_state = "listening"
         self.listen_socket.listen(LISTEN_QUEUE_SIZE)
         (self.switch_socket, self.switch_addr) = self.listen_socket.accept()
         if not self.switch_socket:
             self.socket_errors += 1
             self.dbg(DEBUG_WARN, "Failed on accept")
-            self.state = "error"
+            self.dbg_state = "error"
             return False
 
         self.connected = True
-        self.state = "connected"
+        self.dbg_state = "connected"
         self.dbg(DEBUG_INFO, "Got connection to " + str(self.switch_addr))
         return True
 
@@ -146,12 +147,14 @@
         """
         Disconnect the switch socket
         """
-        self.state = "disconnected"
+        self.dbg_state = "disconnecting"
         if not self.connected:
             self.dbg(DEBUG_INFO, "disconnect when not connected")
+            self.dbg_state = "disconnected"
             return
         self.switch_socket.close()
         self.connected = False
+        self.dbg_state = "disconnected"
 
     def _pkt_handler_check(self, pkt):
         """
@@ -186,6 +189,7 @@
         if self.xid:
             if hdr.xid == self.xid:
                 self.xid_response = msg
+                self.xid_cv.notify()
                 self.xid_cv.release()
                 return (True, None)
         self.xid_cv.release()
@@ -225,6 +229,10 @@
                     self.dbg(DEBUG_ERROR, 
                              "Controller thread error connecting; exit")
                     break
+            # Notify anyone waiting that a connection is made
+            self.connect_cv.acquire()
+            self.connect_cv.notify()
+            self.connect_cv.release()
             try:
                 pkt = self.switch_socket.recv(self.rcv_size)
                 if len(pkt) == 0:
@@ -242,7 +250,7 @@
                 if len(self.packets) >= self.max_pkts:
                     self.packets.pop(0)
                     self.packets_expired += 1
-                self.packets.append((msg, data))
+                self.packets.append((msg, pkt))
                 self.packets_total += 1
                 self.sync.release()
 
@@ -284,9 +292,10 @@
         @param exp_msg If set, return only when this type of message 
         is received.
 
-        @retval A pair (msg, data) where msg is a message object and data is
-        a string of any additional information following the 
-        parsed message.  
+        @retval A pair (msg, pkt) where msg is a message object and pkt
+        the string representing the packet as received from the socket.
+        This allows additional parsing by the receiver if necessary.
+
         The data members in the message are in host endian order.
         If an error occurs, None is returned
         """
@@ -297,12 +306,12 @@
 
         while len(self.packets) > 0:
             self.sync.acquire()
-            (msg, data) = self.packets.pop(0)
+            (msg, pkt) = self.packets.pop(0)
             self.sync.release()
             if not exp_msg or (exp_msg and (msg.header.type == exp_msg)):
-                return msg, data
+                return msg, pkt
 
-    def transact(self, msg, timeout=None):
+    def transact(self, msg, timeout=None, zero_xid=False):
         """
         Run a message transaction with the switch
 
@@ -312,11 +321,15 @@
 
         @param msg The message object to send; must not be a string
         @param timeout The timeout in seconds (?)
+        @param zero_xid Normally, if the XID is 0 an XID will be generated
+        for the message.  Set xero_xid to override this behavior
         @return The matching message object or None if unsuccessful
 
-        @todo Implement transact function for controller
         """
 
+        if not zero_xid and msg.header.xid == 0:
+            msg.header.xid = gen_xid()
+
         self.xid_cv.acquire()
         if self.xid:
             self.xid_cv.release()
@@ -328,10 +341,10 @@
         self.xid_response = None
         self.message_send(msg.pack())
         self.xid_cv.wait(timeout)
-        (msg, data) = self.xid_response
+        msg = self.xid_response
         self.xid_response = None
         self.xid_cv.release()
-        return (msg, data)
+        return msg
 
     def message_send(self, msg):
         """
@@ -354,7 +367,7 @@
     def __str__(self):
         string = "Controller:\n"
         string += "  connected       " + str(self.connected) + "\n"
-        string += "  state           " + self.state + "\n"
+        string += "  state           " + self.dbg_state + "\n"
         string += "  running         " + str(self.running) + "\n"
         string += "  switch_addr     " + str(self.switch_addr) + "\n"
         string += "  pending pkts    " + str(len(self.packets)) + "\n"
@@ -372,6 +385,34 @@
     def show(self):
         print str(self)
 
+    def connect_to_switch(self, timeout=None, send_hello=True):
+        """
+        Connect to switch
+
+        Block until a connection to a switch
+        is established or a timeout occurs.  Sends a hello message
+        once established.
+        @param timeout Timeout in seconds
+        @param send_hello If True, will send hello when connection established
+        @return True if successful, False otherwise
+        """
+        h = hello()
+        print "x1"
+        self.connect_cv.acquire()
+        if self.connected:
+            print "x2"
+            self.connect_cv.release()
+            return True
+
+        print "x3"
+        self.connect_cv.wait(timeout)
+        self.connect_cv.release()
+        print "x4"
+        if send_hello:
+            self.message_send(h.pack())
+            print "x5"
+        return self.connected
+
 def sample_handler(controller, msg, pkt):
     """
     Sample message handler
diff --git a/src/python/oftest/dataplane.py b/src/python/oftest/dataplane.py
index 90a5207..0462f5d 100644
--- a/src/python/oftest/dataplane.py
+++ b/src/python/oftest/dataplane.py
@@ -18,7 +18,7 @@
 import os
 import socket
 import time
-import promisc
+import netutils
 from threading import Thread
 from threading import Lock
 
diff --git a/src/python/oftest/netutils.py b/src/python/oftest/netutils.py
index f53c2e0..613ac66 100644
--- a/src/python/oftest/netutils.py
+++ b/src/python/oftest/netutils.py
@@ -1,7 +1,6 @@
-#!/usr/bin/env python
 
 """
-Network utilities for the OpenFlow controller
+Network utilities for the OpenFlow test framework
 """
 
 ###########################################################################
diff --git a/src/python/oftest/oft_config.py b/src/python/oftest/oft_config.py
index b6c14d3..af82455 100644
--- a/src/python/oftest/oft_config.py
+++ b/src/python/oftest/oft_config.py
@@ -79,6 +79,9 @@
 CONTROLLER_HOST_DEFAULT = ''
 CONTROLLER_PORT_DEFAULT = 6633
 
+# Timeout in seconds for initial connection
+INIT_CONNECT_TIMEOUT = 4
+
 # Number of switch connection requests to queue
 LISTEN_QUEUE_SIZE = 1
 
diff --git a/tools/munger/Makefile b/tools/munger/Makefile
index 43f02e2..4e979d2 100644
--- a/tools/munger/Makefile
+++ b/tools/munger/Makefile
@@ -10,7 +10,7 @@
 
 PYLIBOF_DIR = ${TOOLS_DIR}/pylibopenflow
 
-TARGET_DIR = ${TOP_DIR}/src/python/oftest/protocol
+TARGET_DIR = ${TOP_DIR}/src/python/oftest
 
 # Relative to pyopenflow-pythonize exec location
 OF_HEADER = include/openflow.h
@@ -49,6 +49,7 @@
 	mkdir -p lint
 	(cd ${TARGET_DIR} && pylint -e $(notdir $<)) > $@
 
+# Note that lint has issues with scapy syntax
 lint: ${LINT_FILES}
 
 # For now. just local source doc generated
diff --git a/tools/munger/scripts/action_gen.py b/tools/munger/scripts/action_gen.py
index 6f9d11a..8746faf 100644
--- a/tools/munger/scripts/action_gen.py
+++ b/tools/munger/scripts/action_gen.py
@@ -5,7 +5,7 @@
 
 import re
 import sys
-sys.path.append("../../src/python/oftest/protocol")
+sys.path.append("../../src/python/oftest")
 from cstruct import *
 from class_maps import class_to_members_map
 
diff --git a/tools/munger/scripts/error_gen.py b/tools/munger/scripts/error_gen.py
index e1c8ce7..7ee2d35 100644
--- a/tools/munger/scripts/error_gen.py
+++ b/tools/munger/scripts/error_gen.py
@@ -5,7 +5,7 @@
 
 import re
 import sys
-sys.path.append("../../src/python/oftest/protocol")
+sys.path.append("../../src/python/oftest")
 from cstruct import *
 from class_maps import class_to_members_map
 
diff --git a/tools/munger/scripts/message_gen.py b/tools/munger/scripts/message_gen.py
index 2a9f963..31665ca 100644
--- a/tools/munger/scripts/message_gen.py
+++ b/tools/munger/scripts/message_gen.py
@@ -80,7 +80,7 @@
 import re
 import string
 import sys
-sys.path.append("../../src/python/oftest/protocol")
+sys.path.append("../../src/python/oftest")
 from cstruct import *
 from class_maps import class_to_members_map
 
diff --git a/tools/munger/tests/msg_test.py b/tools/munger/tests/msg_test.py
index 720c608..e816cc1 100644
--- a/tools/munger/tests/msg_test.py
+++ b/tools/munger/tests/msg_test.py
@@ -1,5 +1,5 @@
 import sys
-sys.path.append('../../../src/python/oftest/protocol')
+sys.path.append('../../../src/python/oftest')
 
 from parse import of_message_parse
 from parse import of_header_parse