merged from dev to tizen 76/11176/1
authorkh5325.kim <kh5325.kim@samsung.com>
Tue, 22 Oct 2013 05:25:26 +0000 (14:25 +0900)
committerkh5325.kim <kh5325.kim@samsung.com>
Tue, 22 Oct 2013 05:25:26 +0000 (14:25 +0900)
Change-Id: I883731a41b81baf46b2a60cb893896a3930e0e58
Signed-off-by: kh5325.kim <kh5325.kim@samsung.com>
71 files changed:
.gitignore [new file with mode: 0644]
Makefile
deps/libusb/AUTHORS [new file with mode: 0644]
deps/libusb/COPYING [new file with mode: 0644]
deps/libusb/LICENSE [new file with mode: 0644]
deps/libusb/Makefile [new file with mode: 0644]
deps/libusb/darwin.c [new file with mode: 0644]
deps/libusb/descriptors.c [new file with mode: 0644]
deps/libusb/error.c [new file with mode: 0644]
deps/libusb/error.h [new file with mode: 0644]
deps/libusb/linux.c [new file with mode: 0644]
deps/libusb/linux.h [new file with mode: 0644]
deps/libusb/usb.c [new file with mode: 0644]
deps/libusb/usb.h [new file with mode: 0644]
deps/libusb/usbi.h [new file with mode: 0644]
deps/libusb/windows.c [new file with mode: 0755]
deps/libusb/winusb.h [new file with mode: 0755]
package/changelog
package/pkginfo.manifest
package/sdb.install.linux
package/sdb.install.macos-64
package/sdb.install.windows
package/sdb.remove.linux
package/sdb.remove.macos-64
package/sdb.remove.windows
src/command_function.c
src/command_function.h
src/commandline.c
src/common_modules.h [new file with mode: 0644]
src/device_vendors.c [new file with mode: 0644]
src/device_vendors.h [new file with mode: 0644]
src/fdevent.c [changed mode: 0644->0755]
src/fdevent.h [changed mode: 0644->0755]
src/fdevent_backend.h [changed mode: 0644->0755]
src/fdevent_unix.c [changed mode: 0644->0755]
src/fdevent_windows.c [changed mode: 0644->0755]
src/file_sync_client.c
src/file_sync_functions.c
src/file_sync_functions.h
src/file_sync_service.h [changed mode: 0644->0755]
src/linkedlist.c
src/linkedlist.h
src/listener.c [new file with mode: 0644]
src/listener.h [new file with mode: 0644]
src/log.c [new file with mode: 0644]
src/log.h [new file with mode: 0644]
src/memutils.c [new file with mode: 0644]
src/memutils.h [new file with mode: 0644]
src/sdb.c
src/sdb.h
src/sdb_client.c
src/sdb_client.h
src/sdb_constants.c
src/sdb_constants.h
src/sdb_map.c [new file with mode: 0644]
src/sdb_map.h [new file with mode: 0644]
src/sdb_model.c
src/sockets.c [changed mode: 0644->0755]
src/sockets.h [new file with mode: 0644]
src/strutils.c [changed mode: 0644->0755]
src/transport.c
src/transport.h [changed mode: 0644->0755]
src/transport_local.c [changed mode: 0644->0755]
src/transport_usb.c [changed mode: 0644->0755]
src/usb_darwin.c [new file with mode: 0755]
src/usb_linux.c [changed mode: 0755->0644]
src/utils.c [changed mode: 0644->0755]
src/utils.h
src/utils_backend.h [changed mode: 0644->0755]
src/utils_unix.c [changed mode: 0644->0755]
src/utils_windows.c [changed mode: 0644->0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..71f1d5f
--- /dev/null
@@ -0,0 +1,16 @@
+sdb_*.tar.gz
+sdb_*_*.zip
+sdb.package.*
+
+usb-connection-for-ssh_*_*.zip
+usb-connection-for-ssh.package.*
+
+*.bak
+bin/
+prebuilt/
+src/sdbwinapi/buildfre_win7_x86.log
+src/sdbwinapi/buildfre_win7_x86.wrn
+src/sdbwinapi/objfre_win7_x86/
+src/sdbwinusbapi/buildfre_win7_x86.log
+src/sdbwinusbapi/buildfre_win7_x86.wrn
+src/sdbwinusbapi/objfre_win7_x86/
index 4a0f5fceb88bb279946da4aac30913987b04e74b..fc83b0528d0a6a4006240459407895a64fd8bd6d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,9 @@
 
 #
 HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1)
+LBITS := $(shell getconf LONG_BIT)
+OBJDIR := bin
+MODULE := sdb
 
 # sdb host tool
 # =========================================================
@@ -12,26 +15,27 @@ HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1)
 ifeq ($(HOST_OS),darwin)
        CC := clang
 endif
-
 #
 ifeq ($(HOST_OS),linux)
        LOCAL_USB_SRC :=  src/usb_linux.c
        LOCAL_UTIL_SRC := src/utils_unix.c
        LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c
-       LOCAL_LFLAGS := -lrt -lpthread
+       LOCAL_LFLAGS := -lrt -lpthread -ludev
        LOCAL_CFLAGS := -DOS_LINUX -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1 -D_FILE_OFFSET_BITS=64
+       HAS_LIBUSB := false
 endif
 
 ifeq ($(HOST_OS),darwin)
-       LOCAL_USB_SRC := src/libusb/darwin.c src/sdb_usb.c src/libusb/error.c src/libusb/usb.c src/libusb/descriptors.c
+       LOCAL_USB_SRC := src/usb_darwin.c
        LOCAL_UTIL_SRC := src/utils_unix.c
        LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c
        LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
        LOCAL_CFLAGS := -DOS_DARWIN -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -mmacosx-version-min=10.4 -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1
+       HAS_LIBUSB := false
 endif
 
 ifeq ($(HOST_OS),mingw32)
-       LOCAL_USB_SRC := src/libusb/windows.c
+       LOCAL_USB_SRC := deps/libusb/windows.c
        LOCAL_UTIL_SRC := src/utils_windows.c
        LOCAL_OTHER_SRC := src/fdevent.c  src/fdevent_windows.c
        LOCAL_CFLAGS := -DOS_WINDOWS
@@ -49,18 +53,22 @@ SDB_SRC_FILES := \
        src/commandline.c \
        src/sdb_client.c \
        src/sockets.c \
-       src/services.c \
        src/file_sync_client.c \
        $(LOCAL_USB_SRC) \
+       src/device_vendors.c \
        $(LOCAL_UTIL_SRC) \
        $(LOCAL_OTHER_SRC) \
        src/utils.c \
        src/strutils.c \
+       src/memutils.c \
        src/linkedlist.c \
        src/sdb_model.c \
        src/sdb_constants.c \
        src/file_sync_functions.c \
-       src/command_function.c
+       src/command_function.c \
+       src/log.c \
+       src/listener.c \
+       src/sdb_map.c
 
 SDB_CFLAGS := -O2 -g -Wall -Wno-unused-parameter
 SDB_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
@@ -69,16 +77,15 @@ SDB_CFLAGS += $(LOCAL_CFLAGS)
 SDB_LFLAGS := $(LOCAL_LFLAGS)
 STATIC_LFLAGS := $(LOCAL_STATIC_LFLAGS)
 
-OBJDIR := bin
-
-MODULE := sdb
-
 all : $(MODULE)
 
 sdb : $(SDB_SRC_FILES)
-       rm -rf $(OBJDIR)
        mkdir -p $(OBJDIR)
+ifeq ($(HAS_LIBUSB),true)
+       make -C ./deps/libusb
+       make install -C ./deps/libusb
+endif
        $(CC) $(SDB_CFLAGS) -o $(OBJDIR)/$(MODULE) $(SDB_SRC_FILES) $(LOCAL_IFLAGS) $(SDB_LFLAGS) $(STATIC_LFLAGS)
 
 clean :
-       rm -rf $(OBJDIR)/*
+       rm -rf $(OBJDIR)
diff --git a/deps/libusb/AUTHORS b/deps/libusb/AUTHORS
new file mode 100644 (file)
index 0000000..d2beff9
--- /dev/null
@@ -0,0 +1,2 @@
+Daniel Drake <dsd@gentoo.org>
+
diff --git a/deps/libusb/COPYING b/deps/libusb/COPYING
new file mode 100644 (file)
index 0000000..5ab7695
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/deps/libusb/LICENSE b/deps/libusb/LICENSE
new file mode 100644 (file)
index 0000000..f98680a
--- /dev/null
@@ -0,0 +1,47 @@
+libusb is covered by the LGPL:
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+----
+
+Alternatively, the files usb.h.in and/or usb.h may be licensed under the
+BSD license:
+
+Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/deps/libusb/Makefile b/deps/libusb/Makefile
new file mode 100644 (file)
index 0000000..bb6054f
--- /dev/null
@@ -0,0 +1,42 @@
+#
+#
+# Makefile for libusb
+#
+
+#
+HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1)
+
+# =========================================================
+
+ifeq ($(HOST_OS),darwin)
+       CC := /Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/bin/llvm-gcc-4.2
+else
+       CC := gcc
+endif
+
+#
+ifeq ($(HOST_OS),linux)
+       LOCAL_USB_SRC :=  linux.c error.c usb.c descriptors.c
+       LOCAL_LFLAGS := -lrt -lpthread
+       LOCAL_CFLAGS := -DOS_LINUX
+endif
+
+ifeq ($(HOST_OS),darwin)
+       LOCAL_USB_SRC := darwin.c error.c usb.c descriptors.c
+       LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+       LOCAL_CFLAGS := -DOS_DARWIN -mmacosx-version-min=10.4
+endif
+
+MODULE = libusb.so
+
+all : $(MODULE)
+
+$(MODULE) : $(LOCAL_USB_SRC)
+       $(CC) -o $(MODULE) -fPIC $(LOCAL_USB_SRC) $(LOCAL_LFLAGS) $(LOCAL_CFLAGS) -shared
+
+install :
+       mkdir -p ../../bin
+       cp $(MODULE) ../../bin
+clean :
+       rm -rf $(MODULE)
+       rm -rf *.o
diff --git a/deps/libusb/darwin.c b/deps/libusb/darwin.c
new file mode 100644 (file)
index 0000000..c330eb0
--- /dev/null
@@ -0,0 +1,1329 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Darwin/MacOS X Support
+ *
+ * (c) 2002-2007 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * (07/25/2007):
+ *   - Added a fix to ignore buggy (virtual?) hubs.
+ * (06/26/2006):
+ *   - Bulk functions no longer use async transfer functions.
+ * (04/17/2005):
+ *   - Lots of minor fixes.
+ *   - Endpoint table now made by claim_interface to fix a bug.
+ *   - Merged Read/Write to make modifications easier.
+ * (03/25/2005):
+ *   - Fixed a bug when using asynchronous callbacks within a multi-threaded application.
+ * (03/14/2005):
+ *   - Added an endpoint table to speed up bulk transfers.
+ * 0.1.11 (02/22/2005):
+ *   - Updated error checking in read/write routines to check completion codes.
+ *   - Updated set_configuration so that the open interface is reclaimed before completion.
+ *   - Fixed several typos.
+ * 0.1.8 (01/12/2004):
+ *   - Fixed several memory leaks.
+ *   - Readded 10.0 support
+ *   - Added support for USB fuctions defined in 10.3 and above
+ * (01/02/2003):
+ *   - Applied a patch by Philip Edelbrock <phil@edgedesign.us> that fixes a bug in usb_control_msg.
+ * (12/16/2003):
+ *   - Even better error printing.
+ *   - Devices that cannot be opened can have their interfaces opened.
+ * 0.1.6 (05/12/2002):
+ *   - Fixed problem where libusb holds resources after program completion.
+ *   - Mouse should no longer freeze up now.
+ * 0.1.2 (02/13/2002):
+ *   - Bulk functions should work properly now.
+ * 0.1.1 (02/11/2002):
+ *   - Fixed major bug (device and interface need to be released after use)
+ * 0.1.0 (01/06/2002):
+ *   - Tested driver with gphoto (works great as long as Image Capture isn't running)
+ * 0.1d  (01/04/2002):
+ *   - Implimented clear_halt and resetep
+ *   - Uploaded to CVS.
+ * 0.1b  (01/04/2002):
+ *   - Added usb_debug line to bulk read and write function.
+ * 0.1a  (01/03/2002):
+ *   - Driver mostly completed using the macosx driver I wrote for my rioutil software.
+ *
+ * Derived from Linux version by Richard Tobin.
+ * Also partly derived from BSD version.
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* standard includes for darwin/os10 (IOKit) */
+#include <mach/mach_port.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include "usbi.h"
+
+/* some defines */
+/* IOUSBInterfaceInferface */
+#if defined (kIOUSBInterfaceInterfaceID220)
+
+// #warning "libusb being compiled for 10.4 or later"
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+#elif defined (kIOUSBInterfaceInterfaceID197)
+
+// #warning "libusb being compiled for 10.3 or later"
+#define usb_interface_t IOUSBInterfaceInterface197
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+#define InterfaceVersion 197
+
+#elif defined (kIOUSBInterfaceInterfaceID190)
+
+// #warning "libusb being compiled for 10.2 or later"
+#define usb_interface_t IOUSBInterfaceInterface190
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+#define InterfaceVersion 190
+
+#elif defined (kIOUSBInterfaceInterfaceID182)
+
+// #warning "libusb being compiled for 10.1 or later"
+#define usb_interface_t IOUSBInterfaceInterface182
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+#define InterfaceVersion 182
+
+#else
+
+/* No timeout functions available! Time to upgrade your os. */
+#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up"
+#define usb_interface_t IOUSBInterfaceInterface
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID
+#define LIBUSB_NO_TIMEOUT_INTERFACE
+#define InterfaceVersion 180
+
+#endif
+
+/* IOUSBDeviceInterface */
+#if defined (kIOUSBDeviceInterfaceID197)
+
+#define usb_device_t    IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+#elif defined (kIOUSBDeviceInterfaceID187)
+
+#define usb_device_t    IOUSBDeviceInterface187
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+#define DeviceVersion 187
+
+#elif defined (kIOUSBDeviceInterfaceID182)
+
+#define usb_device_t    IOUSBDeviceInterface182
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+#define DeviceVersion 182
+
+#else
+
+#define usb_device_t    IOUSBDeviceInterface
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID
+#define LIBUSB_NO_TIMEOUT_DEVICE
+#define LIBUSB_NO_SEIZE_DEVICE
+#define DeviceVersion 180
+
+#endif
+
+typedef IOReturn io_return_t;
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+typedef SInt32 s_int32_t;
+typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+                                   IOAsyncCallback1 callback, void *refcon);
+typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+                                      UInt32 noDataTimeout, UInt32 completionTimeout,
+                                      IOAsyncCallback1 callback, void *refcon);
+
+#if !defined(IO_OBJECT_NULL)
+#define IO_OBJECT_NULL ((io_object_t)0)
+#endif
+
+struct darwin_dev_handle {
+  usb_device_t **device;
+  usb_interface_t **interface;
+  int open;
+
+  /* stored translation table for pipes to endpoints */
+  int num_endpoints;
+  unsigned char *endpoint_addrs;
+};
+
+static IONotificationPortRef gNotifyPort;
+static mach_port_t masterPort = MACH_PORT_NULL;
+
+static void darwin_cleanup (void)
+{
+  IONotificationPortDestroy(gNotifyPort);
+  mach_port_deallocate(mach_task_self(), masterPort);
+}
+
+static char *darwin_error_str (int result) {
+  switch (result) {
+  case kIOReturnSuccess:
+    return "no error";
+  case kIOReturnNotOpen:
+    return "device not opened for exclusive access";
+  case kIOReturnNoDevice:
+    return "no connection to an IOService";
+  case kIOUSBNoAsyncPortErr:
+    return "no async port has been opened for interface";
+  case kIOReturnExclusiveAccess:
+    return "another process has device opened for exclusive access";
+  case kIOUSBPipeStalled:
+    return "pipe is stalled";
+  case kIOReturnError:
+    return "could not establish a connection to the Darwin kernel";
+  case kIOUSBTransactionTimeout:
+    return "transaction timed out";
+  case kIOReturnBadArgument:
+    return "invalid argument";
+  case kIOReturnAborted:
+    return "transaction aborted";
+  case kIOReturnNotResponding:
+    return "device not responding";
+  default:
+    return "unknown error";
+  }
+}
+
+/* not a valid errorno outside darwin.c */
+#define LUSBDARWINSTALL (ELAST+1)
+
+static int darwin_to_errno (int result) {
+  switch (result) {
+  case kIOReturnSuccess:
+    return 0;
+  case kIOReturnNotOpen:
+    return EBADF;
+  case kIOReturnNoDevice:
+  case kIOUSBNoAsyncPortErr:
+    return ENXIO;
+  case kIOReturnExclusiveAccess:
+    return EBUSY;
+  case kIOUSBPipeStalled:
+    return LUSBDARWINSTALL;
+  case kIOReturnBadArgument:
+    return EINVAL;
+  case kIOUSBTransactionTimeout:
+    return ETIMEDOUT;
+  case kIOReturnNotResponding:
+    return EIO;
+  case kIOReturnError:
+  default:
+    return 1;
+  }
+}
+
+static int usb_setup_iterator (io_iterator_t *deviceIterator)
+{
+  int result;
+  CFMutableDictionaryRef matchingDict;
+
+  /* set up the matching dictionary for class IOUSBDevice and its subclasses.
+     It will be consumed by the IOServiceGetMatchingServices call */
+  if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
+    darwin_cleanup ();
+    
+    USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n");
+  }
+
+  result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator);
+  matchingDict = NULL;
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n",
+                  darwin_error_str(result));
+
+  return 0;
+}
+
+static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp)
+{
+  io_cf_plugin_ref_t *plugInInterface = NULL;
+  usb_device_t **device;
+  io_service_t usbDevice;
+  long result, score;
+
+  if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator)))
+    return NULL;
+  
+  result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID, &plugInInterface,
+                                            &score);
+  
+  result = IOObjectRelease(usbDevice);
+  if (result || !plugInInterface)
+    return NULL;
+  
+  (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
+                                    (LPVOID)&device);
+  
+  (*plugInInterface)->Stop(plugInInterface);
+  IODestroyPlugInInterface (plugInInterface);
+  plugInInterface = NULL;
+  
+  (*(device))->GetLocationID(device, locationp);
+
+  return device;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result;
+  io_iterator_t deviceIterator;
+
+  usb_device_t **darwin_device;
+
+  UInt32 location = *((UInt32 *)dev->device->dev);
+  UInt32 dlocation;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if (masterPort == MACH_PORT_NULL)
+    USB_ERROR(-EINVAL);
+
+  device = calloc(1, sizeof(struct darwin_dev_handle));
+  if (!device)
+    USB_ERROR(-ENOMEM);
+
+  if (usb_debug > 3)
+    fprintf(stderr, "usb_os_open: %04x:%04x\n",
+           dev->device->descriptor.idVendor,
+           dev->device->descriptor.idProduct);
+
+  if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+    return result;
+
+  /* This port of libusb uses locations to keep track of devices. */
+  while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) {
+    if (dlocation == location)
+      break;
+
+    (*darwin_device)->Release(darwin_device);
+  }
+
+  IOObjectRelease(deviceIterator);
+  device->device = darwin_device;
+
+  if (device->device == NULL)
+    USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!");
+
+#if !defined (LIBUSB_NO_SEIZE_DEVICE)
+  result = (*(device->device))->USBDeviceOpenSeize (device->device);
+#else
+  /* No Seize in OS X 10.0 (Darwin 1.4) */
+  result = (*(device->device))->USBDeviceOpen (device->device);
+#endif
+
+  if (result != kIOReturnSuccess) {
+    switch (result) {
+    case kIOReturnExclusiveAccess:
+      if (usb_debug > 0)
+       fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result));
+      break;
+    default:
+      (*(device->device))->Release (device->device);
+      USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s",
+                   darwin_error_str(result));
+    }
+    
+    device->open = 0;
+  } else
+    device->open = 1;
+    
+  dev->impl_info = device;
+  dev->interface = -1;
+  dev->altsetting = -1;
+
+  device->num_endpoints  = 0;
+  device->endpoint_addrs = NULL;
+
+  return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  usb_release_interface(dev, dev->interface);
+
+  if (usb_debug > 3)
+    fprintf(stderr, "usb_os_close: %04x:%04x\n",
+           dev->device->descriptor.idVendor,
+           dev->device->descriptor.idProduct);
+
+  if (device->open == 1)
+    result = (*(device->device))->USBDeviceClose(device->device);
+  else
+    result = kIOReturnSuccess;
+
+  /* device may not need to be released, but if it has to... */
+  (*(device->device))->Release(device->device);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result));
+
+  free (device);
+
+  return 0;
+}
+
+static int get_endpoints (struct darwin_dev_handle *device)
+{
+  io_return_t ret;
+
+  u_int8_t numep, direction, number;
+  u_int8_t dont_care1, dont_care3;
+  u_int16_t dont_care2;
+
+  int i;
+
+  if (device == NULL || device->interface == NULL)
+    return -EINVAL;
+
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n");
+
+  /* retrieve the total number of endpoints on this interface */
+  ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep);
+  if ( ret ) {
+    if ( usb_debug > 1 )
+      fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface );
+
+    USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" );
+  }
+
+  free (device->endpoint_addrs);
+  device->endpoint_addrs = calloc (sizeof (unsigned char), numep);
+
+  /* iterate through pipe references */
+  for (i = 1 ; i <= numep ; i++) {
+    ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number,
+                                                   &dont_care1, &dont_care2, &dont_care3);
+
+    if (ret != kIOReturnSuccess) {
+      fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n",
+              i );
+      USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret));
+    }
+
+    if (usb_debug > 1)
+      fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number);
+
+    device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) |
+                                    (number & USB_ENDPOINT_ADDRESS_MASK));
+  }
+
+  device->num_endpoints = numep;
+
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n");
+  
+  return 0;
+}
+
+static int claim_interface (usb_dev_handle *dev, int interface)
+{
+  io_iterator_t interface_iterator;
+  io_service_t  usbInterface = IO_OBJECT_NULL;
+  io_return_t result;
+  io_cf_plugin_ref_t *plugInInterface = NULL;
+
+  IOUSBFindInterfaceRequest request;
+
+  struct darwin_dev_handle *device;
+  long score;
+  int current_interface;
+
+  device = dev->impl_info;
+
+  request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+  request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+  request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+  result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+                  darwin_error_str(result));
+
+  for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) {
+    usbInterface = IOIteratorNext(interface_iterator);
+    if ( usb_debug > 3 )
+      fprintf ( stderr, "Interface %d of device is 0x%08x\n",
+               current_interface, usbInterface );
+  }
+
+  current_interface--;
+
+  /* the interface iterator is no longer needed, release it */
+  IOObjectRelease(interface_iterator);
+
+  if (!usbInterface) {
+    u_int8_t nConfig;                       /* Index of configuration to use */
+    IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */
+    /* Only a composite class device with no vendor-specific driver will
+       be configured. Otherwise, we need to do it ourselves, or there
+       will be no interfaces for the device. */
+
+    if ( usb_debug > 3 )
+      fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" );
+
+    result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig );
+    if (result != kIOReturnSuccess)
+      USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s",
+                   darwin_error_str(result));
+    
+    if (nConfig < 1)
+      USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations");
+    else if ( nConfig > 1 && usb_debug > 0 )
+      fprintf ( stderr, "claim_interface: device has more than one"
+               " configuration, using the first (warning)\n" );
+
+    if ( usb_debug > 3 )
+      fprintf ( stderr, "claim_interface: device has %d configuration%s\n",
+               (int)nConfig, (nConfig>1?"s":"") );
+
+    /* Always use the first configuration */
+    result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc );
+    if (result != kIOReturnSuccess) {
+      if (device->open == 1) {
+        (*(device->device))->USBDeviceClose ( (device->device) );
+        (*(device->device))->Release ( (device->device) );
+      }
+
+      USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s",
+                   darwin_error_str(result));
+    } else if ( usb_debug > 3 )
+      fprintf ( stderr, "claim_interface: configuration value is %d\n",
+               configDesc->bConfigurationValue );
+
+    if (device->open == 1) {
+      result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue );
+
+      if (result != kIOReturnSuccess) {
+       (*(device->device))->USBDeviceClose ( (device->device) );
+       (*(device->device))->Release ( (device->device) );
+
+       USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s",
+                     darwin_error_str(result));
+      }
+
+      dev->config = configDesc->bConfigurationValue;
+    }
+    
+    request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+    request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+    request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+    request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+    /* Now go back and get the chosen interface */
+    result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+    if (result != kIOReturnSuccess)
+      USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+                    darwin_error_str(result));
+
+    for (current_interface = 0 ; current_interface <= interface ; current_interface++) {
+      usbInterface = IOIteratorNext(interface_iterator);
+
+      if ( usb_debug > 3 )
+       fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n",
+                 current_interface, usbInterface );
+    }
+    current_interface--;
+
+    /* the interface iterator is no longer needed, release it */
+    IOObjectRelease(interface_iterator);
+
+    if (!usbInterface)
+      USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL");
+  }
+
+  result = IOCreatePlugInInterfaceForService(usbInterface,
+                                            kIOUSBInterfaceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID,
+                                            &plugInInterface, &score);
+  /* No longer need the usbInterface object after getting the plug-in */
+  result = IOObjectRelease(usbInterface);
+  if (result || !plugInInterface)
+    USB_ERROR(-ENOENT);
+
+  /* Now create the device interface for the interface */
+  result = (*plugInInterface)->QueryInterface(plugInInterface,
+                                             CFUUIDGetUUIDBytes(InterfaceInterfaceID),
+                                             (LPVOID) &device->interface);
+
+  /* No longer need the intermediate plug-in */
+  (*plugInInterface)->Stop(plugInInterface);
+  IODestroyPlugInInterface (plugInInterface);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s",
+                 darwin_error_str(result));
+
+  if (!device->interface)
+    USB_ERROR(-EACCES);
+
+  if ( usb_debug > 3 )
+    fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n",
+             current_interface, device->interface);
+
+  /* claim the interface */
+  result = (*(device->interface))->USBInterfaceOpen(device->interface);
+  if (result)
+    USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s",
+                 darwin_error_str(result));
+
+  result = get_endpoints (device);
+
+  if (result) {
+    /* this should not happen */
+    usb_release_interface (dev, interface);
+    USB_ERROR_STR ( result, "claim_interface: could not build endpoint table");
+  }
+
+  return 0;
+}
+
+int usb_set_configuration (usb_dev_handle *dev, int configuration)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+  int interface;
+
+  if ( usb_debug > 3 )
+    fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration );
+
+  if (!dev)
+    USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" );
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" );
+
+  /* Setting configuration will invalidate the interface, so we need
+     to reclaim it. First, dispose of existing interface, if any. */
+  interface = dev->interface;
+
+  if ( device->interface )
+    usb_release_interface(dev, dev->interface);
+
+  result = (*(device->device))->SetConfiguration(device->device, configuration);
+
+  if (result)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s",
+                 darwin_error_str(result));
+
+  /* Reclaim interface */
+  if (interface != -1)
+    result = usb_claim_interface (dev, interface);
+
+  dev->config = configuration;
+
+  return result;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+  struct darwin_dev_handle *device = dev->impl_info;
+
+  io_return_t result;
+
+  if ( usb_debug > 3 )
+    fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface );
+
+  if (!device)
+    USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" );
+
+  if (!(device->device))
+    USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" );
+
+  /* If we have already claimed an interface, release it */
+  if ( device->interface )
+    usb_release_interface(dev, dev->interface);
+
+  result = claim_interface ( dev, interface );
+  if ( result )
+    USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" );
+
+  dev->interface = interface;
+
+  /* interface is claimed and async IO is set up: return 0 */
+  return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    return 0;
+
+  result = (*(device->interface))->USBInterfaceClose(device->interface);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s",
+                 darwin_error_str(result));
+
+  result = (*(device->interface))->Release(device->interface);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s",
+                 darwin_error_str(result));
+
+  device->interface = NULL;
+
+  free (device->endpoint_addrs);
+
+  device->num_endpoints  = 0;
+  device->endpoint_addrs = NULL;
+
+  dev->interface = -1;
+  dev->altsetting = -1;
+
+  return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+  struct darwin_dev_handle *device;
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed");
+
+  result = (*(device->interface))->SetAlternateInterface(device->interface, alternate);
+
+  if (result)
+    USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface");
+
+  dev->altsetting = alternate;
+
+  result = get_endpoints (device);
+  if (result) {
+    /* this should not happen */
+    USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table");
+  }
+
+  return 0;
+}
+
+/* simple function that figures out what pipeRef is associated with an endpoint */
+static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep)
+{
+  int i;
+
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n");
+
+  for (i = 0 ; i < device->num_endpoints ; i++)
+    if (device->endpoint_addrs[i] == ep)
+      return i + 1;
+
+  /* No pipe found with the correct endpoint address */
+  if (usb_debug > 1)
+    fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep);
+  
+  return -1;
+}
+
+static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  int pipeRef;
+
+  u_int8_t  transferType, direction, number, interval;
+  u_int16_t maxPacketSize;
+
+  if (!dev)
+    USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" );
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" );
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened");
+
+
+  /* Set up transfer */
+  if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+    USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" );
+
+  (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+                                            &transferType, &maxPacketSize, &interval);
+  /* Transfer set up complete */
+
+  if (usb_debug > 0)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep);
+
+  /* Do bulk transfer */
+  if (transferType == kUSBInterrupt && usb_debug > 3)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE)
+  if ( transferType != kUSBInterrupt) {
+    if (usb_bt_read != 0)
+      result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout);
+    else
+      result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout);
+
+    /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */
+    if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled)
+      usb_clear_halt (dev, ep);
+  } else
+#endif
+  {
+    if (usb_bt_read != 0)
+      result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size);
+    else
+      result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size);
+  }
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result));
+
+  return size;
+}
+
+#if 0
+/* NOT USED */
+/* argument to handle multiple parameters to rw_completed */
+struct rw_complete_arg {
+  UInt32        io_size;
+  IOReturn      result;
+  CFRunLoopRef  cf_loop;
+};
+
+static void rw_completed(void *refcon, io_return_t result, void *io_size)
+{
+  struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon;
+
+  if (usb_debug > 2)
+    fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result),
+           (UInt32)io_size, result);
+
+  rw_arg->io_size = (UInt32)io_size;
+  rw_arg->result  = result;
+
+  CFRunLoopStop(rw_arg->cf_loop);
+}
+
+static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout,
+                             rw_async_func_t rw_async, rw_async_to_func_t rw_async_to)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  CFRunLoopSourceRef cfSource;
+  int pipeRef;
+
+  struct rw_complete_arg rw_arg;
+
+  u_int8_t  transferType;
+
+  /* None of the values below are used in libusb for bulk transfers */
+  u_int8_t  direction, number, interval;
+  u_int16_t maxPacketSize;
+
+  if (!dev)
+    USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" );
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" );
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened");
+
+
+  /* Set up transfer */
+  if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+    USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" );
+
+  (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+                                            &transferType, &maxPacketSize, &interval);
+
+  bzero((void *)&rw_arg, sizeof(struct rw_complete_arg));
+  rw_arg.cf_loop = CFRunLoopGetCurrent();
+  CFRetain (rw_arg.cf_loop);
+
+  (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource);
+  CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
+  /* Transfer set up complete */
+
+  if (usb_debug > 0)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n",
+            size, ep);
+
+  /* Bulk transfer */
+  if (transferType == kUSBInterrupt && usb_debug > 3)
+    fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+  if ( transferType != kUSBInterrupt && rw_async_to != NULL)
+
+    result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout,
+                         (IOAsyncCallback1)rw_completed, (void *)&rw_arg);
+  else
+    result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed,
+                      (void *)&rw_arg);
+
+  if (result == kIOReturnSuccess) {
+    /* wait for write to complete */
+    if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) {
+      (*(device->interface))->AbortPipe(device->interface, pipeRef);
+      CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */
+      if (usb_debug)
+       fprintf(stderr, "usb_bulk_transfer: timed out\n");
+    }
+  }
+
+  CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
+  CFRelease (rw_arg.cf_loop);
+  
+  /* Check the return code of both the write and completion functions. */
+  if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess && 
+      rw_arg.result != kIOReturnAborted) ) {
+    int error_code;
+    char *error_str;
+
+    if (result == kIOReturnSuccess) {
+      error_code = darwin_to_errno (rw_arg.result);
+      error_str  = darwin_error_str (rw_arg.result);
+    } else {
+      error_code = darwin_to_errno(result);
+      error_str  = darwin_error_str (result);
+    }
+    
+    if (transferType != kUSBInterrupt && rw_async_to != NULL)
+      USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str);
+    else
+      USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str);
+  }
+
+  return rw_arg.io_size;
+}
+#endif
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+  int result;
+  
+  if (dev == NULL || dev->impl_info == NULL)
+    return -EINVAL;
+
+  if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0)
+    USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)");
+  
+  return result;
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+  int result;
+  
+  if (dev == NULL || dev->impl_info == NULL)
+    return -EINVAL;
+
+  ep |= 0x80;
+
+  if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0)
+    USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)");
+  
+  return result;
+}
+
+/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  return usb_bulk_write (dev, ep, bytes, size, timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  return usb_bulk_read (dev, ep, bytes, size, timeout);
+}
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+                   int value, int index, char *bytes, int size, int timeout)
+{
+  struct darwin_dev_handle *device = dev->impl_info;
+
+  io_return_t result;
+
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+  IOUSBDevRequestTO urequest;
+#else
+  IOUSBDevRequest urequest;
+#endif
+
+  if (usb_debug >= 3)
+    fprintf(stderr, "libusb/darwin.c usb_control_msg (device: %s): %d %d %d %d %p %d %d\n",
+            dev->device->filename, requesttype, request, value, index, bytes, size, timeout);
+
+  bzero(&urequest, sizeof(urequest));
+
+  urequest.bmRequestType = requesttype;
+  urequest.bRequest = request;
+  urequest.wValue = value;
+  urequest.wIndex = index;
+  urequest.wLength = size;
+  urequest.pData = bytes;
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+  urequest.completionTimeout = timeout;
+  urequest.noDataTimeout = timeout;
+
+  result = (*(device->device))->DeviceRequestTO(device->device, &urequest);
+#else
+  result = (*(device->device))->DeviceRequest(device->device, &urequest);
+#endif
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "libusb/darwin.c usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result));
+
+  /* Bytes transfered is stored in the wLenDone field*/
+  return urequest.wLenDone;
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+  struct usb_bus *fbus = NULL;
+
+  io_iterator_t deviceIterator;
+  io_return_t result;
+
+  usb_device_t **device;
+
+  UInt32 location;
+
+  char buf[20];
+  int i = 1;
+
+  /* Create a master port for communication with IOKit (this should
+     have been created if the user called usb_init() )*/
+  if (masterPort == MACH_PORT_NULL) {
+    usb_init ();
+
+    if (masterPort == MACH_PORT_NULL)
+      USB_ERROR(-ENOENT);
+  }
+
+  if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+    return result;
+
+  while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+    struct usb_bus *bus;
+
+    if (location & 0x00ffffff)
+      continue;
+
+    bus = calloc(1, sizeof(struct usb_bus));
+    if (bus == NULL)
+      USB_ERROR(-ENOMEM);
+    
+    sprintf(buf, "%03i", i++);
+    bus->location = location;
+
+    strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
+    bus->dirname[sizeof(bus->dirname) - 1] = 0;
+    
+    LIST_ADD(fbus, bus);
+    
+    if (usb_debug >= 2)
+      fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+
+    (*(device))->Release(device);
+  }
+
+  IOObjectRelease(deviceIterator);
+
+  *busses = fbus;
+
+  return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+  struct usb_device *fdev = NULL;
+
+  io_iterator_t deviceIterator;
+  io_return_t result;
+
+  usb_device_t **device;
+
+  u_int16_t address;
+  UInt32 location;
+  UInt32 bus_loc = bus->location;
+  int devnum;
+
+  /* for use in retrieving device description */
+  IOUSBDevRequest req;
+
+  /* a master port should have been created by usb_os_init */
+  if (masterPort == MACH_PORT_NULL)
+    USB_ERROR(-ENOENT);
+
+  if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+    return result;
+
+  /* Set up request for device descriptor */
+  req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+  req.bRequest = kUSBRqGetDescriptor;
+  req.wValue = kUSBDeviceDesc << 8;
+  req.wIndex = 0;
+  req.wLength = sizeof(IOUSBDeviceDescriptor);
+
+  devnum = 0;
+
+  while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+    unsigned char device_desc[DEVICE_DESC_LENGTH];
+    UInt8 bDeviceClass, bDeviceSubClass;
+    UInt16 idVendor, idProduct;
+
+    result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address);
+
+    if (result == kIOReturnSuccess) {
+      (*(device))->GetDeviceClass (device, &bDeviceClass);
+      (*(device))->GetDeviceSubClass (device, &bDeviceSubClass);
+      (*(device))->GetDeviceProduct (device, &idProduct);
+      (*(device))->GetDeviceVendor (device, &idVendor);
+
+      if ((location >> 24) == (bus_loc >> 24)) {
+       struct usb_device *dev;
+
+       if (usb_debug >= 2)
+         fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found USB device on bus 0x%08lx: 0x%08lx\n",
+                 bus_loc, location);
+
+       dev = calloc(1, sizeof(struct usb_device));
+       if (dev == NULL)
+         USB_ERROR(-ENOMEM);
+
+       dev->bus = bus;
+
+       /* retrieve device descriptor */
+       req.pData = device_desc;
+       result = (*(device))->DeviceRequest(device, &req);
+
+       if (result != kIOReturnSuccess) {
+         free (dev);
+
+         if (usb_debug)
+           fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device descriptor: %s. Skipping device.\n",
+                    darwin_error_str(result));
+       
+         /* release the device now */
+         (*(device))->Release(device);
+         continue; /* can't continue without a descriptor */
+       }
+
+       usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
+
+       /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices */
+       if (dev->descriptor.idProduct != idProduct) {
+         free (dev);
+
+         if (usb_debug)
+           fprintf (stderr, "libusb/darwin.c usb_os_find_devices: idProduct from iokit does not match idProduct in descriptor. Skipping device\n");
+
+         /* release the device now */
+          (*(device))->Release(device);
+          continue; /* can't continue without a descriptor */
+       }
+
+       dev->devnum = devnum++;
+
+       sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass);
+
+       dev->dev = (USBDeviceAddress *) calloc (1, 4);
+       if (dev->dev == NULL)
+         USB_ERROR(-ENOMEM);
+
+       memcpy(dev->dev, &location, 4);
+
+       LIST_ADD(fdev, dev);
+
+       if (usb_debug >= 2)
+         fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found %s on %s at location 0x%08lx\n",
+                 dev->filename, bus->dirname, location);
+      }
+    } else if (usb_debug)
+      fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device address: %s\n",
+              darwin_error_str(result));
+
+    /* release the device now */
+    (*(device))->Release(device);
+  }
+
+  IOObjectRelease(deviceIterator);
+
+  *devices = fdev;
+
+  if (usb_debug)
+    fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Complete\n");
+
+  return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+  /* Nothing yet */
+  return 0;
+}
+
+void usb_os_init(void)
+{
+  if (masterPort == MACH_PORT_NULL) {
+    IOMasterPort(masterPort, &masterPort);
+    
+    gNotifyPort = IONotificationPortCreate(masterPort);
+  }
+}
+
+void usb_os_cleanup (void)
+{
+  if (masterPort != MACH_PORT_NULL)
+    darwin_cleanup ();
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  int pipeRef;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed");
+
+  if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+    USB_ERROR(-EINVAL);
+
+  result = (*(device->interface))->ResetPipe(device->interface, pipeRef);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result));
+
+  return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+  struct darwin_dev_handle *device;
+
+  io_return_t result = -1;
+
+  int pipeRef;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  /* interface is not open */
+  if (!device->interface)
+    USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed");
+
+  if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+    USB_ERROR(-EINVAL);
+
+#if (InterfaceVersion < 190)
+  result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef);
+#else
+  /* newer versions of darwin support clearing additional bits on the device's endpoint */
+  result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef);
+#endif
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result));
+
+  return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+  struct darwin_dev_handle *device;
+  
+  io_return_t result;
+
+  if (!dev)
+    USB_ERROR(-ENXIO);
+
+  if ((device = dev->impl_info) == NULL)
+    USB_ERROR(-ENOENT);
+
+  if (!device->device)
+    USB_ERROR_STR(-ENOENT, "usb_reset: no such device");
+
+  result = (*(device->device))->ResetDevice(device->device);
+
+  if (result != kIOReturnSuccess)
+    USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result));
+  
+  return 0;
+}
diff --git a/deps/libusb/descriptors.c b/deps/libusb/descriptors.c
new file mode 100644 (file)
index 0000000..f7fc784
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Parses descriptors
+ *
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "usbi.h"
+
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+       unsigned char type, unsigned char index, void *buf, int size)
+{
+  memset(buf, 0, size);
+
+  return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                        (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+       unsigned char index, void *buf, int size)
+{
+  memset(buf, 0, size);
+
+  return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                        (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest)
+{
+  unsigned char *sp = source, *dp = dest;
+  uint16_t w;
+  uint32_t d;
+  char *cp;
+
+  for (cp = description; *cp; cp++) {
+    switch (*cp) {
+    case 'b':  /* 8-bit byte */
+      *dp++ = *sp++;
+      break;
+    case 'w':  /* 16-bit word, convert from little endian to CPU */
+      w = (sp[1] << 8) | sp[0]; sp += 2;
+      dp += ((unsigned long)dp & 1);   /* Align to word boundary */
+      *((uint16_t *)dp) = w; dp += 2;
+      break;
+    case 'd':  /* 32-bit dword, convert from little endian to CPU */
+      d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4;
+      dp += ((unsigned long)dp & 2);   /* Align to dword boundary */
+      *((uint32_t *)dp) = d; dp += 4;
+      break;
+    /* These two characters are undocumented and just a hack for Linux */
+    case 'W':  /* 16-bit word, keep CPU endianess */
+      dp += ((unsigned long)dp & 1);   /* Align to word boundary */
+      memcpy(dp, sp, 2); sp += 2; dp += 2;
+      break;
+    case 'D':  /* 32-bit dword, keep CPU endianess */
+      dp += ((unsigned long)dp & 2);   /* Align to dword boundary */
+      memcpy(dp, sp, 4); sp += 4; dp += 4;
+      break;
+    }
+  }
+
+  return sp - source;
+}
+
+/*
+ * This code looks surprisingly similar to the code I wrote for the Linux
+ * kernel. It's not a coincidence :)
+ */
+
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
+{
+  struct usb_descriptor_header header;
+  unsigned char *begin;
+  int parsed = 0, len, numskipped;
+
+  usb_parse_descriptor(buffer, "bb", &header);
+
+  /* Everything should be fine being passed into here, but we sanity */
+  /*  check JIC */
+  if (header.bLength > size) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "ran out of descriptors parsing\n");
+    return -1;
+  }
+                
+  if (header.bDescriptorType != USB_DT_ENDPOINT) {
+    if (usb_debug >= 2)
+      fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n",
+         header.bDescriptorType, USB_DT_ENDPOINT);
+    return parsed;
+  }
+
+  if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
+    usb_parse_descriptor(buffer, "bbbbwbbb", endpoint);
+  else if (header.bLength >= ENDPOINT_DESC_LENGTH)
+    usb_parse_descriptor(buffer, "bbbbwb", endpoint);
+
+  buffer += header.bLength;
+  size -= header.bLength;
+  parsed += header.bLength;
+
+  /* Skip over the rest of the Class Specific or Vendor Specific */
+  /*  descriptors */
+  begin = buffer;
+  numskipped = 0;
+  while (size >= DESC_HEADER_LENGTH) {
+    usb_parse_descriptor(buffer, "bb", &header);
+
+    if (header.bLength < 2) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+      return -1;
+    }
+
+    /* If we find another "proper" descriptor then we're done  */
+    if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+        (header.bDescriptorType == USB_DT_INTERFACE) ||
+        (header.bDescriptorType == USB_DT_CONFIG) ||
+        (header.bDescriptorType == USB_DT_DEVICE))
+      break;
+
+    if (usb_debug >= 1)
+      fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+    numskipped++;
+
+    buffer += header.bLength;
+    size -= header.bLength;
+    parsed += header.bLength;
+  }
+
+  if (numskipped && usb_debug >= 2)
+    fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+  /* Copy any unknown descriptors into a storage area for drivers */
+  /*  to later parse */
+  len = (int)(buffer - begin);
+  if (!len) {
+    endpoint->extra = NULL;
+    endpoint->extralen = 0;
+    return parsed;
+  }
+
+  endpoint->extra = malloc(len);
+  if (!endpoint->extra) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n");
+    endpoint->extralen = 0;
+    return parsed;
+  }
+
+  memcpy(endpoint->extra, begin, len);
+  endpoint->extralen = len;
+
+  return parsed;
+}
+
+static int usb_parse_interface(struct usb_interface *interface,
+       unsigned char *buffer, int size)
+{
+  int i, len, numskipped, retval, parsed = 0;
+  struct usb_descriptor_header header;
+  struct usb_interface_descriptor *ifp;
+  unsigned char *begin;
+
+  interface->num_altsetting = 0;
+
+  while (size >= INTERFACE_DESC_LENGTH) {
+    interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1));
+    if (!interface->altsetting) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "couldn't malloc interface->altsetting\n");
+      return -1;
+    }
+
+    ifp = interface->altsetting + interface->num_altsetting;
+    interface->num_altsetting++;
+
+    usb_parse_descriptor(buffer, "bbbbbbbbb", ifp);
+
+    /* Skip over the interface */
+    buffer += ifp->bLength;
+    parsed += ifp->bLength;
+    size -= ifp->bLength;
+
+    begin = buffer;
+    numskipped = 0;
+
+    /* Skip over any interface, class or vendor descriptors */
+    while (size >= DESC_HEADER_LENGTH) {
+      usb_parse_descriptor(buffer, "bb", &header);
+
+      if (header.bLength < 2) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+        return -1;
+      }
+
+      /* If we find another "proper" descriptor then we're done */
+      if ((header.bDescriptorType == USB_DT_INTERFACE) ||
+          (header.bDescriptorType == USB_DT_ENDPOINT) ||
+          (header.bDescriptorType == USB_DT_CONFIG) ||
+          (header.bDescriptorType == USB_DT_DEVICE))
+        break;
+
+      numskipped++;
+
+      buffer += header.bLength;
+      parsed += header.bLength;
+      size -= header.bLength;
+    }
+
+    if (numskipped && usb_debug >= 2)
+      fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped);
+
+    /* Copy any unknown descriptors into a storage area for */
+    /*  drivers to later parse */
+    len = (int)(buffer - begin);
+    if (!len) {
+      ifp->extra = NULL;
+      ifp->extralen = 0;
+    } else {
+      ifp->extra = malloc(len);
+      if (!ifp->extra) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n");
+        ifp->extralen = 0;
+        return -1;
+      }
+      memcpy(ifp->extra, begin, len);
+      ifp->extralen = len;
+    }
+
+    /* Did we hit an unexpected descriptor? */
+    usb_parse_descriptor(buffer, "bb", &header);
+    if ((size >= DESC_HEADER_LENGTH) &&
+        ((header.bDescriptorType == USB_DT_CONFIG) ||
+        (header.bDescriptorType == USB_DT_DEVICE)))
+      return parsed;
+
+    if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "too many endpoints\n");
+      return -1;
+    }
+
+    if (ifp->bNumEndpoints > 0) {
+      ifp->endpoint = (struct usb_endpoint_descriptor *)
+                       malloc(ifp->bNumEndpoints *
+                       sizeof(struct usb_endpoint_descriptor));
+      if (!ifp->endpoint) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n");
+        return -1;      
+      }
+
+      memset(ifp->endpoint, 0, ifp->bNumEndpoints *
+             sizeof(struct usb_endpoint_descriptor));
+
+      for (i = 0; i < ifp->bNumEndpoints; i++) {
+        usb_parse_descriptor(buffer, "bb", &header);
+  
+        if (header.bLength > size) {
+          if (usb_debug >= 1)
+            fprintf(stderr, "ran out of descriptors parsing\n");
+          return -1;
+        }
+                
+        retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
+        if (retval < 0)
+          return retval;
+
+        buffer += retval;
+        parsed += retval;
+        size -= retval;
+      }
+    } else
+      ifp->endpoint = NULL;
+
+    /* We check to see if it's an alternate to this one */
+    ifp = (struct usb_interface_descriptor *)buffer;
+    if (size < USB_DT_INTERFACE_SIZE ||
+        ifp->bDescriptorType != USB_DT_INTERFACE ||
+        !ifp->bAlternateSetting)
+      return parsed;
+  }
+
+  return parsed;
+}
+
+int usb_parse_configuration(struct usb_config_descriptor *config,
+       unsigned char *buffer)
+{
+  int i, retval, size;
+  struct usb_descriptor_header header;
+
+  usb_parse_descriptor(buffer, "bbwbbbbb", config);
+  size = config->wTotalLength;
+
+  if (config->bNumInterfaces > USB_MAXINTERFACES) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "too many interfaces\n");
+    return -1;
+  }
+
+  config->interface = (struct usb_interface *)
+                       malloc(config->bNumInterfaces *
+                       sizeof(struct usb_interface));
+  if (!config->interface) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "out of memory\n");
+    return -1;      
+  }
+
+  memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface));
+
+  buffer += config->bLength;
+  size -= config->bLength;
+        
+  config->extra = NULL;
+  config->extralen = 0;
+
+  for (i = 0; i < config->bNumInterfaces; i++) {
+    int numskipped, len;
+    unsigned char *begin;
+
+    /* Skip over the rest of the Class Specific or Vendor */
+    /*  Specific descriptors */
+    begin = buffer;
+    numskipped = 0;
+    while (size >= DESC_HEADER_LENGTH) {
+      usb_parse_descriptor(buffer, "bb", &header);
+
+      if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+        return -1;
+      }
+
+      /* If we find another "proper" descriptor then we're done */
+      if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+          (header.bDescriptorType == USB_DT_INTERFACE) ||
+          (header.bDescriptorType == USB_DT_CONFIG) ||
+          (header.bDescriptorType == USB_DT_DEVICE))
+        break;
+
+      if (usb_debug >= 2)
+        fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+      numskipped++;
+
+      buffer += header.bLength;
+      size -= header.bLength;
+    }
+
+    if (numskipped && usb_debug >= 2)
+      fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+    /* Copy any unknown descriptors into a storage area for */
+    /*  drivers to later parse */
+    len = (int)(buffer - begin);
+    if (len) {
+      /* FIXME: We should realloc and append here */
+      if (!config->extralen) {
+        config->extra = malloc(len);
+        if (!config->extra) {
+          if (usb_debug >= 1)
+            fprintf(stderr, "couldn't allocate memory for config extra descriptors\n");
+          config->extralen = 0;
+          return -1;
+        }
+
+        memcpy(config->extra, begin, len);
+        config->extralen = len;
+      }
+    }
+
+    retval = usb_parse_interface(config->interface + i, buffer, size);
+    if (retval < 0)
+      return retval;
+
+    buffer += retval;
+    size -= retval;
+  }
+
+  return size;
+}
+
+void usb_destroy_configuration(struct usb_device *dev)
+{
+  int c, i, j, k;
+        
+  if (!dev->config)
+    return;
+
+  for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+    struct usb_config_descriptor *cf = &dev->config[c];
+
+    if (!cf->interface)
+      continue;
+
+    for (i = 0; i < cf->bNumInterfaces; i++) {
+      struct usb_interface *ifp = &cf->interface[i];
+                                
+      if (!ifp->altsetting)
+        continue;
+
+      for (j = 0; j < ifp->num_altsetting; j++) {
+        struct usb_interface_descriptor *as = &ifp->altsetting[j];
+                                        
+        if (as->extra)
+          free(as->extra);
+
+        if (!as->endpoint)
+          continue;
+                                        
+        for (k = 0; k < as->bNumEndpoints; k++) {
+          if (as->endpoint[k].extra)
+            free(as->endpoint[k].extra);
+        }       
+        free(as->endpoint);
+      }
+
+      free(ifp->altsetting);
+    }
+
+    free(cf->interface);
+  }
+
+  free(dev->config);
+}
+
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev)
+{
+  struct usb_device *dev = udev->device;
+  int i;
+
+  if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG);
+    return;
+  }
+
+  if (dev->descriptor.bNumConfigurations < 1) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1);
+    return;
+  }
+
+  dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+  if (!dev->config) {
+    if (usb_debug >= 1)
+      fprintf(stderr, "Unable to allocate memory for config descriptor\n");
+    return;
+  }
+
+  memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+       sizeof(struct usb_config_descriptor));
+
+  for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+    unsigned char buffer[8], *bigbuffer;
+    struct usb_config_descriptor config;
+    int res;
+
+    /* Get the first 8 bytes so we can figure out what the total length is */
+    res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8);
+    if (res < 8) {
+      if (usb_debug >= 1) {
+        if (res < 0)
+          fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+        else
+          fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res);
+      }
+
+      goto err;
+    }
+
+    usb_parse_descriptor(buffer, "bbw", &config);
+
+    bigbuffer = malloc(config.wTotalLength);
+    if (!bigbuffer) {
+      if (usb_debug >= 1)
+        fprintf(stderr, "Unable to allocate memory for descriptors\n");
+      goto err;
+    }
+
+    res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength);
+    if (res < config.wTotalLength) {
+      if (usb_debug >= 1) {
+        if (res < 0)
+          fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+        else
+          fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res);
+      }
+
+      free(bigbuffer);
+      goto err;
+    }
+
+    res = usb_parse_configuration(&dev->config[i], bigbuffer);
+    if (usb_debug >= 2) {
+      if (res > 0)
+        fprintf(stderr, "Descriptor data still left\n");
+      else if (res < 0)
+        fprintf(stderr, "Unable to parse descriptors\n");
+    }
+
+    free(bigbuffer);
+  }
+
+  return;
+
+err:
+  free(dev->config);
+
+  dev->config = NULL;
+}
+
diff --git a/deps/libusb/error.c b/deps/libusb/error.c
new file mode 100644 (file)
index 0000000..9212e86
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * USB Error messages
+ *
+ * Copyright (c) 2000-2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "usb.h"
+#include "error.h"
+
+char usb_error_str[1024] = "";
+int usb_error_errno = 0;
+usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE;
+
+char *usb_strerror(void)
+{
+  switch (usb_error_type) {
+  case USB_ERROR_TYPE_NONE:
+    return "No error";
+  case USB_ERROR_TYPE_STRING:
+    return usb_error_str;
+  case USB_ERROR_TYPE_ERRNO:
+    if (usb_error_errno > -USB_ERROR_BEGIN)
+      return strerror(usb_error_errno);
+    else
+      /* Any error we don't know falls under here */
+      return "Unknown error";
+  }
+
+  return "Unknown error";
+}
+
diff --git a/deps/libusb/error.h b/deps/libusb/error.h
new file mode 100644 (file)
index 0000000..c980e22
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ERROR_H_
+#define _ERROR_H_
+
+typedef enum {
+  USB_ERROR_TYPE_NONE = 0,
+  USB_ERROR_TYPE_STRING,
+  USB_ERROR_TYPE_ERRNO,
+} usb_error_type_t;
+
+extern char usb_error_str[1024];
+extern int usb_error_errno;
+extern usb_error_type_t usb_error_type;
+
+#define USB_ERROR(x) \
+       do { \
+          usb_error_type = USB_ERROR_TYPE_ERRNO; \
+          usb_error_errno = x; \
+         return x; \
+       } while (0)
+
+#define USB_ERROR_STR(x, format, args...) \
+       do { \
+         usb_error_type = USB_ERROR_TYPE_STRING; \
+         snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+          if (usb_debug >= 2) \
+            fprintf(stderr, "USB error: %s\n", usb_error_str); \
+         return x; \
+       } while (0)
+
+#endif /* _ERROR_H_ */
+
diff --git a/deps/libusb/linux.c b/deps/libusb/linux.c
new file mode 100644 (file)
index 0000000..6b13afb
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Linux USB support
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h>    /* getenv, etc */
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <dirent.h>
+
+#include "linux.h"
+#include "usbi.h"
+
+static char usb_path[PATH_MAX + 1] = "";
+
+static int device_open(struct usb_device *dev)
+{
+  char filename[PATH_MAX + 1];
+  int fd;
+
+  snprintf(filename, sizeof(filename) - 1, "%s/%s/%s",
+    usb_path, dev->bus->dirname, dev->filename);
+
+  fd = open(filename, O_RDWR);
+  if (fd < 0) {
+    fd = open(filename, O_RDONLY);
+    if (fd < 0)
+      USB_ERROR_STR(-errno, "failed to open %s: %s",
+       filename, strerror(errno));
+  }
+
+  return fd;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+  dev->fd = device_open(dev->device);
+
+  return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+  if (dev->fd < 0)
+    return 0;
+
+  if (close(dev->fd) == -1)
+    /* Failing trying to close a file really isn't an error, so return 0 */
+    USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
+       strerror(errno));
+
+  return 0;
+}
+
+int usb_set_configuration(usb_dev_handle *dev, int configuration)
+{
+  int ret;
+
+  ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration);
+  if (ret < 0)
+    USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
+       strerror(errno));
+
+  dev->config = configuration;
+
+  return 0;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+  int ret;
+
+  ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);
+  if (ret < 0) {
+    if (errno == EBUSY && usb_debug > 0)
+      fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename);
+
+    USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface,
+       strerror(errno));
+  }
+
+  dev->interface = interface;
+
+  return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+  int ret;
+
+  ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface);
+  if (ret < 0)
+    USB_ERROR_STR(-errno, "could not release intf %d: %s", interface,
+       strerror(errno));
+
+  dev->interface = -1;
+
+  return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+  int ret;
+  struct usb_setinterface setintf;
+
+  if (dev->interface < 0)
+    USB_ERROR(-EINVAL);
+
+  setintf.interface = dev->interface;
+  setintf.altsetting = alternate;
+
+  ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);
+  if (ret < 0)
+    USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
+       dev->interface, alternate, strerror(errno));
+
+  dev->altsetting = alternate;
+
+  return 0;
+}
+
+/*
+ * Linux usbfs has a limit of one page size for synchronous bulk read/write.
+ * 4096 is the most portable maximum we can do for now.
+ * Linux usbfs has a limit of 16KB for the URB interface. We use this now
+ * to get better performance for USB 2.0 devices.
+ */
+#define MAX_READ_WRITE (16 * 1024)
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+       int value, int index, char *bytes, int size, int timeout)
+{
+  struct usb_ctrltransfer ctrl;
+  int ret;
+
+  ctrl.bRequestType = requesttype;
+  ctrl.bRequest = request;
+  ctrl.wValue = value;
+  ctrl.wIndex = index;
+  ctrl.wLength = size;
+
+  ctrl.data = bytes;
+  ctrl.timeout = timeout;
+
+  ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl);
+  if (ret < 0)
+    USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno));
+
+  return ret;
+}
+
+#define URB_USERCONTEXT_COOKIE         ((void *)0x1)
+
+/* Reading and writing are the same except for the endpoint */
+static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype,
+       char *bytes, int size, int timeout)
+{
+  struct usb_urb urb;
+  int bytesdone = 0, requested;
+  struct timeval tv, tv_ref, tv_now;
+  struct usb_urb *context;
+  int ret, waiting;
+
+  /*
+   * HACK: The use of urb.usercontext is a hack to get threaded applications
+   * sort of working again. Threaded support is still not recommended, but
+   * this should allow applications to work in the common cases. Basically,
+   * if we get the completion for an URB we're not waiting for, then we update
+   * the usercontext pointer to 1 for the other threads URB and it will see
+   * the change after it wakes up from the the timeout. Ugly, but it works.
+   */
+
+  /*
+   * Get actual time, and add the timeout value. The result is the absolute
+   * time where we have to quit waiting for an message.
+   */
+  gettimeofday(&tv_ref, NULL);
+  tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000;
+  tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000;
+
+  if (tv_ref.tv_usec > 1000000) {
+    tv_ref.tv_usec -= 1000000;
+    tv_ref.tv_sec++;
+  }
+
+  do {
+    fd_set writefds;
+
+    requested = size - bytesdone;
+    if (requested > MAX_READ_WRITE)
+      requested = MAX_READ_WRITE;
+
+    urb.type = urbtype;
+    urb.endpoint = ep;
+    urb.flags = 0;
+    urb.buffer = bytes + bytesdone;
+    urb.buffer_length = requested;
+    urb.signr = 0;
+    urb.actual_length = 0;
+    urb.number_of_packets = 0; /* don't do isochronous yet */
+    urb.usercontext = NULL;
+
+    ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);
+    if (ret < 0) {
+      USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno));
+      return ret;
+    }
+
+    FD_ZERO(&writefds);
+    FD_SET(dev->fd, &writefds);
+
+restart:
+    waiting = 1;
+    context = NULL;
+    while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) {
+      tv.tv_sec = 0;
+      tv.tv_usec = 1000; // 1 msec
+      select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
+
+      if (timeout) {
+        /* compare with actual time, as the select timeout is not that precise */
+        gettimeofday(&tv_now, NULL);
+
+        if ((tv_now.tv_sec > tv_ref.tv_sec) ||
+            ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
+          waiting = 0;
+      }
+    }
+
+    if (context && context != &urb) {
+      context->usercontext = URB_USERCONTEXT_COOKIE;
+      /* We need to restart since we got a successful URB, but not ours */
+      goto restart;
+    }
+
+    /*
+     * If there was an error, that wasn't EAGAIN (no completion), then
+     * something happened during the reaping and we should return that
+     * error now
+     */
+    if (ret < 0 && !urb.usercontext && errno != EAGAIN)
+      USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno));
+
+    bytesdone += urb.actual_length;
+  } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
+
+  /* If the URB didn't complete in success or error, then let's unlink it */
+  if (ret < 0 && !urb.usercontext) {
+    int rc;
+
+    if (!waiting)
+      rc = -ETIMEDOUT;
+    else
+      rc = urb.status;
+
+    ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb);
+    if (ret < 0 && errno != EINVAL && usb_debug >= 1)
+      fprintf(stderr, "error discarding URB: %s", strerror(errno));
+
+    /*
+     * When the URB is unlinked, it gets moved to the completed list and
+     * then we need to reap it or else the next time we call this function,
+     * we'll get the previous completion and exit early
+     */
+    ioctl(dev->fd, IOCTL_USB_REAPURB, &context);
+
+    return rc;
+  }
+
+  return bytesdone;
+}
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  /* Ensure the endpoint address is correct */
+  return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
+               timeout);
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  /* Ensure the endpoint address is correct */
+  ep |= USB_ENDPOINT_IN;
+  return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
+               timeout);
+}
+
+/*
+ * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked
+ * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need
+ * to lookup the endpoint packet size and packetize appropriately here.
+ */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  /* Ensure the endpoint address is correct */
+  return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
+               timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout)
+{
+  /* Ensure the endpoint address is correct */
+  ep |= USB_ENDPOINT_IN;
+  return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
+               timeout);
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+  struct usb_bus *fbus = NULL;
+  DIR *dir;
+  struct dirent *entry;
+
+  dir = opendir(usb_path);
+  if (!dir)
+    USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path,
+       strerror(errno));
+
+  while ((entry = readdir(dir)) != NULL) {
+    struct usb_bus *bus;
+
+    /* Skip anything starting with a . */
+    if (entry->d_name[0] == '.')
+      continue;
+
+    if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) {
+      if (usb_debug >= 2)
+        fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n",
+               entry->d_name);
+      continue;
+    }
+
+    bus = malloc(sizeof(*bus));
+    if (!bus)
+      USB_ERROR(-ENOMEM);
+
+    memset((void *)bus, 0, sizeof(*bus));
+
+    strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1);
+    bus->dirname[sizeof(bus->dirname) - 1] = 0;
+
+    LIST_ADD(fbus, bus);
+
+    if (usb_debug >= 2)
+       fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+  }
+
+  closedir(dir);
+
+  *busses = fbus;
+
+  return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+  struct usb_device *fdev = NULL;
+  DIR *dir;
+  struct dirent *entry;
+  char dirpath[PATH_MAX + 1];
+
+  snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);
+
+  dir = opendir(dirpath);
+  if (!dir)
+    USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath,
+       strerror(errno));
+
+  while ((entry = readdir(dir)) != NULL) {
+    unsigned char device_desc[DEVICE_DESC_LENGTH];
+    char filename[PATH_MAX + 1];
+    struct usb_device *dev;
+    struct usb_connectinfo connectinfo;
+    int i, fd, ret;
+
+    /* Skip anything starting with a . */
+    if (entry->d_name[0] == '.')
+      continue;
+
+    dev = malloc(sizeof(*dev));
+    if (!dev)
+      USB_ERROR(-ENOMEM);
+
+    memset((void *)dev, 0, sizeof(*dev));
+
+    dev->bus = bus;
+
+    strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1);
+    dev->filename[sizeof(dev->filename) - 1] = 0;
+
+    snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name);
+    fd = open(filename, O_RDWR);
+    if (fd < 0) {
+      fd = open(filename, O_RDONLY);
+      if (fd < 0) {
+        if (usb_debug >= 2)
+          fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n",
+                  filename);
+
+        free(dev);
+        continue;
+      }
+    }
+
+    /* Get the device number */
+    ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);
+    if (ret < 0) {
+      if (usb_debug)
+        fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n");
+    } else
+      dev->devnum = connectinfo.devnum;
+
+    ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);
+    if (ret < 0) {
+      if (usb_debug)
+        fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n");
+
+      free(dev);
+
+      goto err;
+    }
+
+    /*
+     * Linux kernel converts the words in this descriptor to CPU endian, so
+     * we use the undocumented W character for usb_parse_descriptor() that
+     * doesn't convert endianess when parsing the descriptor
+     */
+    usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor);
+
+    LIST_ADD(fdev, dev);
+
+    if (usb_debug >= 2)
+      fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
+               dev->filename, bus->dirname);
+
+    /* Now try to fetch the rest of the descriptors */
+    if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
+      /* Silent since we'll try again later */
+      goto err;
+
+    if (dev->descriptor.bNumConfigurations < 1)
+      /* Silent since we'll try again later */
+      goto err;
+
+    dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+    if (!dev->config)
+      /* Silent since we'll try again later */
+      goto err;
+
+    memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+          sizeof(struct usb_config_descriptor));
+
+    for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+      unsigned char buffer[8], *bigbuffer;
+      struct usb_config_descriptor config;
+
+      /* Get the first 8 bytes so we can figure out what the total length is */
+      ret = read(fd, (void *)buffer, 8);
+      if (ret < 8) {
+        if (usb_debug >= 1) {
+          if (ret < 0)
+            fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
+          else
+            fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret);
+        }
+
+        goto err;
+      }
+
+      usb_parse_descriptor(buffer, "bbw", &config);
+
+      bigbuffer = malloc(config.wTotalLength);
+      if (!bigbuffer) {
+        if (usb_debug >= 1)
+          fprintf(stderr, "Unable to allocate memory for descriptors\n");
+        goto err;
+      }
+
+      /* Read the rest of the config descriptor */
+      memcpy(bigbuffer, buffer, 8);
+
+      ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8);
+      if (ret < config.wTotalLength - 8) {
+        if (usb_debug >= 1) {
+          if (ret < 0)
+            fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
+          else
+            fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret);
+        }
+
+        free(bigbuffer);
+        goto err;
+      }
+
+      ret = usb_parse_configuration(&dev->config[i], bigbuffer);
+      if (usb_debug >= 2) {
+        if (ret > 0)
+          fprintf(stderr, "Descriptor data still left\n");
+        else if (ret < 0)
+          fprintf(stderr, "Unable to parse descriptors\n");
+      }
+
+      free(bigbuffer);
+    }
+
+err:
+    close(fd);
+  }
+
+  closedir(dir);
+
+  *devices = fdev;
+
+  return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+  struct usb_device *dev, *devices[256];
+  struct usb_ioctl command;
+  int ret, i, i1;
+
+  /* Create a list of devices first */
+  memset(devices, 0, sizeof(devices));
+  for (dev = bus->devices; dev; dev = dev->next)
+    if (dev->devnum)
+      devices[dev->devnum] = dev;
+
+  /* Now fetch the children for each device */
+  for (dev = bus->devices; dev; dev = dev->next) {
+    struct usb_hub_portinfo portinfo;
+    int fd;
+
+    fd = device_open(dev);
+    if (fd < 0)
+      continue;
+
+    /* Query the hub driver for the children of this device */
+    if (dev->config && dev->config->interface && dev->config->interface->altsetting)
+      command.ifno = dev->config->interface->altsetting->bInterfaceNumber;
+    else
+      command.ifno = 0;
+    command.ioctl_code = IOCTL_USB_HUB_PORTINFO;
+    command.data = &portinfo;
+    ret = ioctl(fd, IOCTL_USB_IOCTL, &command);
+    if (ret < 0) {
+      /* errno == ENOSYS means the device probably wasn't a hub */
+      if (errno != ENOSYS && usb_debug > 1)
+        fprintf(stderr, "error obtaining child information: %s\n",
+               strerror(errno));
+
+      close(fd);
+      continue;
+    }
+
+    dev->num_children = 0;
+    for (i = 0; i < portinfo.numports; i++)
+      if (portinfo.port[i])
+        dev->num_children++;
+
+    /* Free any old children first */
+    free(dev->children);
+
+    dev->children = malloc(sizeof(struct usb_device *) * dev->num_children);
+    if (!dev->children) {
+      if (usb_debug > 1)
+        fprintf(stderr, "error allocating %zu bytes memory for dev->children\n",
+                sizeof(struct usb_device *) * dev->num_children);
+
+      dev->num_children = 0;
+      close(fd);
+      continue;
+    }
+
+    for (i = 0, i1 = 0; i < portinfo.numports; i++) {
+      if (!portinfo.port[i])
+        continue;
+
+      dev->children[i1++] = devices[portinfo.port[i]];
+
+      devices[portinfo.port[i]] = NULL;
+    }
+
+    close(fd);
+  }
+
+  /*
+   * There should be one device left in the devices list and that should be
+   * the root device
+   */
+  for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+    if (devices[i])
+      bus->root_dev = devices[i];
+  }
+
+  return 0;
+}
+
+static int check_usb_vfs(const char *dirname)
+{
+  DIR *dir;
+  struct dirent *entry;
+  int found = 0;
+
+  dir = opendir(dirname);
+  if (!dir)
+    return 0;
+
+  while ((entry = readdir(dir)) != NULL) {
+    /* Skip anything starting with a . */
+    if (entry->d_name[0] == '.')
+      continue;
+
+    /* We assume if we find any files that it must be the right place */
+    found = 1;
+    break;
+  }
+
+  closedir(dir);
+
+  return found;
+}
+
+void usb_os_init(void)
+{
+  /* Find the path to the virtual filesystem */
+  if (getenv("USB_DEVFS_PATH")) {
+    if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) {
+      strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1);
+      usb_path[sizeof(usb_path) - 1] = 0;
+    } else if (usb_debug)
+      fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n");
+  }
+
+  if (!usb_path[0]) {
+    if (check_usb_vfs("/dev/bus/usb")) {
+      strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1);
+      usb_path[sizeof(usb_path) - 1] = 0;
+    } else if (check_usb_vfs("/proc/bus/usb")) {
+      strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1);
+      usb_path[sizeof(usb_path) - 1] = 0;
+    } else
+      usb_path[0] = 0; /* No path, no USB support */
+  }
+
+  if (usb_debug) {
+    if (usb_path[0])
+      fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path);
+    else
+      fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n");
+  }
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+  int ret;
+
+  ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep);
+  if (ret)
+    USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep,
+       strerror(errno));
+
+  return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+  int ret;
+
+  ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep);
+  if (ret)
+    USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep,
+       strerror(errno));
+
+  return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+  int ret;
+
+  ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL);
+  if (ret)
+     USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno));
+
+  return 0;
+}
+
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+       unsigned int namelen)
+{
+  struct usb_getdriver getdrv;
+  int ret;
+
+  getdrv.interface = interface;
+  ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv);
+  if (ret)
+    USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno));
+
+  strncpy(name, getdrv.driver, namelen - 1);
+  name[namelen - 1] = 0;
+
+  return 0;
+}
+
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
+{
+  struct usb_ioctl command;
+  int ret;
+
+  command.ifno = interface;
+  command.ioctl_code = IOCTL_USB_DISCONNECT;
+  command.data = NULL;
+
+  ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command);
+  if (ret)
+    USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s",
+        interface, strerror(errno));
+
+  return 0;
+}
+
diff --git a/deps/libusb/linux.h b/deps/libusb/linux.h
new file mode 100644 (file)
index 0000000..e544c09
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __LINUX_H__
+#define __LINUX_H__
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+struct usb_ctrltransfer {
+       /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
+       u_int8_t  bRequestType;
+       u_int8_t  bRequest;
+       u_int16_t wValue;
+       u_int16_t wIndex;
+       u_int16_t wLength;
+
+       u_int32_t timeout;      /* in milliseconds */
+
+       /* pointer to data */
+       void *data;
+};
+
+struct usb_bulktransfer {
+       /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
+       unsigned int ep;
+       unsigned int len;
+       unsigned int timeout;   /* in milliseconds */
+
+       /* pointer to data */
+       void *data;
+};
+
+struct usb_setinterface {
+       /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
+       unsigned int interface;
+       unsigned int altsetting;
+};
+
+#define USB_MAXDRIVERNAME 255
+
+struct usb_getdriver {
+       unsigned int interface;
+       char driver[USB_MAXDRIVERNAME + 1];
+};
+
+#define USB_URB_DISABLE_SPD    1
+#define USB_URB_ISO_ASAP       2
+#define USB_URB_QUEUE_BULK     0x10
+
+#define USB_URB_TYPE_ISO       0
+#define USB_URB_TYPE_INTERRUPT 1
+#define USB_URB_TYPE_CONTROL   2
+#define USB_URB_TYPE_BULK      3
+
+struct usb_iso_packet_desc {
+       unsigned int length;
+       unsigned int actual_length;
+       unsigned int status;
+};
+
+struct usb_urb {
+       unsigned char type;
+       unsigned char endpoint;
+       int status;
+       unsigned int flags;
+       void *buffer;
+       int buffer_length;
+       int actual_length;
+       int start_frame;
+       int number_of_packets;
+       int error_count;
+       unsigned int signr;  /* signal to be sent on error, -1 if none should be sent */
+       void *usercontext;
+       struct usb_iso_packet_desc iso_frame_desc[0];
+};
+
+struct usb_connectinfo {
+       unsigned int devnum;
+       unsigned char slow;
+};
+
+struct usb_ioctl {
+       int ifno;       /* interface 0..N ; negative numbers reserved */
+       int ioctl_code; /* MUST encode size + direction of data so the
+                        * macros in <asm/ioctl.h> give correct values */
+       void *data;     /* param buffer (in, or out) */
+};
+
+struct usb_hub_portinfo {
+       unsigned char numports;
+       unsigned char port[127];        /* port to device num mapping */
+};
+
+#define IOCTL_USB_CONTROL      _IOWR('U', 0, struct usb_ctrltransfer)
+#define IOCTL_USB_BULK         _IOWR('U', 2, struct usb_bulktransfer)
+#define IOCTL_USB_RESETEP      _IOR('U', 3, unsigned int)
+#define IOCTL_USB_SETINTF      _IOR('U', 4, struct usb_setinterface)
+#define IOCTL_USB_SETCONFIG    _IOR('U', 5, unsigned int)
+#define IOCTL_USB_GETDRIVER    _IOW('U', 8, struct usb_getdriver)
+#define IOCTL_USB_SUBMITURB    _IOR('U', 10, struct usb_urb)
+#define IOCTL_USB_DISCARDURB   _IO('U', 11)
+#define IOCTL_USB_REAPURB      _IOW('U', 12, void *)
+#define IOCTL_USB_REAPURBNDELAY        _IOW('U', 13, void *)
+#define IOCTL_USB_CLAIMINTF    _IOR('U', 15, unsigned int)
+#define IOCTL_USB_RELEASEINTF  _IOR('U', 16, unsigned int)
+#define IOCTL_USB_CONNECTINFO  _IOW('U', 17, struct usb_connectinfo)
+#define IOCTL_USB_IOCTL         _IOWR('U', 18, struct usb_ioctl)
+#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct usb_hub_portinfo)
+#define IOCTL_USB_RESET                _IO('U', 20)
+#define IOCTL_USB_CLEAR_HALT   _IOR('U', 21, unsigned int)
+#define IOCTL_USB_DISCONNECT   _IO('U', 22)
+#define IOCTL_USB_CONNECT      _IO('U', 23)
+
+/*
+ * IOCTL_USB_HUB_PORTINFO, IOCTL_USB_DISCONNECT and IOCTL_USB_CONNECT
+ * all work via IOCTL_USB_IOCTL
+ */
+
+#endif
+
diff --git a/deps/libusb/usb.c b/deps/libusb/usb.c
new file mode 100644 (file)
index 0000000..ea4b375
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Main API entry point
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h>    /* getenv */
+#include <stdio.h>     /* stderr */
+#include <string.h>    /* strcmp */
+#include <errno.h>
+
+#include "usbi.h"
+
+int usb_debug = 0;
+struct usb_bus *usb_busses = NULL;
+
+int usb_find_busses(void)
+{
+  struct usb_bus *busses, *bus;
+  int ret, changes = 0;
+
+  ret = usb_os_find_busses(&busses);
+  if (ret < 0)
+    return ret;
+
+  /*
+   * Now walk through all of the busses we know about and compare against
+   * this new list. Any duplicates will be removed from the new list.
+   * If we don't find it in the new list, the bus was removed. Any
+   * busses still in the new list, are new to us.
+   */
+  bus = usb_busses;
+  while (bus) {
+    int found = 0;
+    struct usb_bus *nbus, *tbus = bus->next;
+
+    nbus = busses;
+    while (nbus) {
+      struct usb_bus *tnbus = nbus->next;
+
+      if (!strcmp(bus->dirname, nbus->dirname)) {
+        /* Remove it from the new busses list */
+        LIST_DEL(busses, nbus);
+
+        usb_free_bus(nbus);
+        found = 1;
+        break;
+      }
+
+      nbus = tnbus;
+    }
+
+    if (!found) {
+      /* The bus was removed from the system */
+      LIST_DEL(usb_busses, bus);
+      usb_free_bus(bus);
+      changes++;
+    }
+
+    bus = tbus;
+  }
+
+  /*
+   * Anything on the *busses list is new. So add them to usb_busses and
+   * process them like the new bus it is.
+   */
+  bus = busses;
+  while (bus) {
+    struct usb_bus *tbus = bus->next;
+
+    /*
+     * Remove it from the temporary list first and add it to the real
+     * usb_busses list.
+     */
+    LIST_DEL(busses, bus);
+
+    LIST_ADD(usb_busses, bus);
+
+    changes++;
+
+    bus = tbus;
+  }
+
+  return changes;
+}
+
+int usb_find_devices(void)
+{
+  struct usb_bus *bus;
+  int ret, changes = 0;
+
+  for (bus = usb_busses; bus; bus = bus->next) {
+    struct usb_device *devices, *dev;
+
+    /* Find all of the devices and put them into a temporary list */
+    ret = usb_os_find_devices(bus, &devices);
+    if (ret < 0)
+      return ret;
+
+    /*
+     * Now walk through all of the devices we know about and compare
+     * against this new list. Any duplicates will be removed from the new
+     * list. If we don't find it in the new list, the device was removed.
+     * Any devices still in the new list, are new to us.
+     */
+    dev = bus->devices;
+    while (dev) {
+      int found = 0;
+      struct usb_device *ndev, *tdev = dev->next;
+
+      ndev = devices;
+      while (ndev) {
+        struct usb_device *tndev = ndev->next;
+
+        if (!strcmp(dev->filename, ndev->filename)) {
+          /* Remove it from the new devices list */
+          LIST_DEL(devices, ndev);
+
+          usb_free_dev(ndev);
+          found = 1;
+          break;
+        }
+
+        ndev = tndev;
+      }
+
+      if (!found) {
+        /* The device was removed from the system */
+        LIST_DEL(bus->devices, dev);
+        usb_free_dev(dev);
+        changes++;
+      }
+
+      dev = tdev;
+    }
+
+    /*
+     * Anything on the *devices list is new. So add them to bus->devices and
+     * process them like the new device it is.
+     */
+    dev = devices;
+    while (dev) {
+      struct usb_device *tdev = dev->next;
+
+      /*
+       * Remove it from the temporary list first and add it to the real
+       * bus->devices list.
+       */
+      LIST_DEL(devices, dev);
+
+      LIST_ADD(bus->devices, dev);
+
+      /*
+       * Some ports fetch the descriptors on scanning (like Linux) so we don't
+       * need to fetch them again.
+       */
+      if (!dev->config) {
+        usb_dev_handle *udev;
+
+        udev = usb_open(dev);
+        if (udev) {
+          usb_fetch_and_parse_descriptors(udev);
+
+          usb_close(udev);
+        }
+      }
+
+      changes++;
+
+      dev = tdev;
+    }
+
+    usb_os_determine_children(bus);
+  }
+
+  return changes;
+}
+
+void usb_set_debug(int level)
+{
+  if (usb_debug || level)
+    fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
+       level, level ? "on" : "off");
+
+  usb_debug = level;
+}
+
+void usb_init(void)
+{
+  if (getenv("USB_DEBUG"))
+    usb_set_debug(atoi(getenv("USB_DEBUG")));
+
+  usb_os_init();
+}
+
+usb_dev_handle *usb_open(struct usb_device *dev)
+{
+  usb_dev_handle *udev;
+
+  udev = malloc(sizeof(*udev));
+  if (!udev)
+    return NULL;
+
+  udev->fd = -1;
+  udev->device = dev;
+  udev->bus = dev->bus;
+  udev->config = udev->interface = udev->altsetting = -1;
+
+  if (usb_os_open(udev) < 0) {
+    free(udev);
+    return NULL;
+  }
+
+  return udev;
+}
+
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+       size_t buflen)
+{
+  /*
+   * We can't use usb_get_descriptor() because it's lacking the index
+   * parameter. This will be fixed in libusb 1.0
+   */
+  return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                       (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
+}
+
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
+{
+  char tbuf[255];      /* Some devices choke on size > 255 */
+  int ret, langid, si, di;
+
+  /*
+   * Asking for the zero'th index is special - it returns a string
+   * descriptor that contains all the language IDs supported by the
+   * device. Typically there aren't many - often only one. The
+   * language IDs are 16 bit numbers, and they start at the third byte
+   * in the descriptor. See USB 2.0 specification, section 9.6.7, for
+   * more information on this. */
+  ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
+  if (ret < 0)
+    return ret;
+
+  if (ret < 4)
+    return -EIO;
+
+  langid = tbuf[2] | (tbuf[3] << 8);
+
+  ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
+  if (ret < 0)
+    return ret;
+
+  if (tbuf[1] != USB_DT_STRING)
+    return -EIO;
+
+  if (tbuf[0] > ret)
+    return -EFBIG;
+
+  for (di = 0, si = 2; si < tbuf[0]; si += 2) {
+    if (di >= (buflen - 1))
+      break;
+
+    if (tbuf[si + 1])  /* high byte */
+      buf[di++] = '?';
+    else
+      buf[di++] = tbuf[si];
+  }
+
+  buf[di] = 0;
+
+  return di;
+}
+
+int usb_close(usb_dev_handle *dev)
+{
+  int ret;
+
+  ret = usb_os_close(dev);
+  free(dev);
+
+  return ret;
+}
+
+struct usb_device *usb_device(usb_dev_handle *dev)
+{
+  return dev->device;
+}
+
+void usb_free_dev(struct usb_device *dev)
+{
+  usb_destroy_configuration(dev);
+  free(dev->children);
+  free(dev);
+}
+
+struct usb_bus *usb_get_busses(void)
+{
+  return usb_busses;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+  free(bus);
+}
+
diff --git a/deps/libusb/usb.h b/deps/libusb/usb.h
new file mode 100644 (file)
index 0000000..35955b7
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Prototypes, structure definitions and macros.
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ *
+ * This file (and only this file) may alternatively be licensed under the
+ * BSD license as well, read LICENSE for details.
+ */
+#ifndef __USB_H__
+#define __USB_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <dirent.h>
+
+/*
+ * USB spec information
+ *
+ * This is all stuff grabbed from various USB specs and is pretty much
+ * not subject to change
+ */
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_PTP                  6
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_DATA                 10
+#define USB_CLASS_VENDOR_SPEC          0xff
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+
+#define USB_DT_HID                     0x21
+#define USB_DT_REPORT                  0x22
+#define USB_DT_PHYSICAL                        0x23
+#define USB_DT_HUB                     0x29
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE             18
+#define USB_DT_CONFIG_SIZE             9
+#define USB_DT_INTERFACE_SIZE          9
+#define USB_DT_ENDPOINT_SIZE           7
+#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE         7
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+};
+
+/* String descriptor */
+struct usb_string_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+       unsigned short wData[1];
+};
+
+/* HID descriptor */
+struct usb_hid_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+       unsigned short bcdHID;
+       unsigned char  bCountryCode;
+       unsigned char  bNumDescriptors;
+       /* unsigned char  bReportDescriptorType; */
+       /* unsigned short wDescriptorLength; */
+       /* ... */
+};
+
+/* Endpoint descriptor */
+#define USB_MAXENDPOINTS       32
+struct usb_endpoint_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+       unsigned char  bEndpointAddress;
+       unsigned char  bmAttributes;
+       unsigned short wMaxPacketSize;
+       unsigned char  bInterval;
+       unsigned char  bRefresh;
+       unsigned char  bSynchAddress;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+#define USB_ENDPOINT_ADDRESS_MASK      0x0f    /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK          0x80
+
+#define USB_ENDPOINT_TYPE_MASK         0x03    /* in bmAttributes */
+#define USB_ENDPOINT_TYPE_CONTROL      0
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS  1
+#define USB_ENDPOINT_TYPE_BULK         2
+#define USB_ENDPOINT_TYPE_INTERRUPT    3
+
+/* Interface descriptor */
+#define USB_MAXINTERFACES      32
+struct usb_interface_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+       unsigned char  bInterfaceNumber;
+       unsigned char  bAlternateSetting;
+       unsigned char  bNumEndpoints;
+       unsigned char  bInterfaceClass;
+       unsigned char  bInterfaceSubClass;
+       unsigned char  bInterfaceProtocol;
+       unsigned char  iInterface;
+
+       struct usb_endpoint_descriptor *endpoint;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+#define USB_MAXALTSETTING      128     /* Hard limit */
+struct usb_interface {
+       struct usb_interface_descriptor *altsetting;
+
+       int num_altsetting;
+};
+
+/* Configuration descriptor information.. */
+#define USB_MAXCONFIG          8
+struct usb_config_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+       unsigned short wTotalLength;
+       unsigned char  bNumInterfaces;
+       unsigned char  bConfigurationValue;
+       unsigned char  iConfiguration;
+       unsigned char  bmAttributes;
+       unsigned char  MaxPower;
+
+       struct usb_interface *interface;
+
+       unsigned char *extra;   /* Extra descriptors */
+       int extralen;
+};
+
+/* Device descriptor */
+struct usb_device_descriptor {
+       unsigned char  bLength;
+       unsigned char  bDescriptorType;
+       unsigned short bcdUSB;
+       unsigned char  bDeviceClass;
+       unsigned char  bDeviceSubClass;
+       unsigned char  bDeviceProtocol;
+       unsigned char  bMaxPacketSize0;
+       unsigned short idVendor;
+       unsigned short idProduct;
+       unsigned short bcdDevice;
+       unsigned char  iManufacturer;
+       unsigned char  iProduct;
+       unsigned char  iSerialNumber;
+       unsigned char  bNumConfigurations;
+};
+
+struct usb_ctrl_setup {
+       unsigned char  bRequestType;
+       unsigned char  bRequest;
+       unsigned short wValue;
+       unsigned short wIndex;
+       unsigned short wLength;
+};
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+/* 0x02 is reserved */
+#define USB_REQ_SET_FEATURE            0x03
+/* 0x04 is reserved */
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+
+/*
+ * Various libusb API related stuff
+ */
+
+#define USB_ENDPOINT_IN                        0x80
+#define USB_ENDPOINT_OUT               0x00
+
+/* Error codes */
+#define USB_ERROR_BEGIN                        500000
+
+/*
+ * This is supposed to look weird. This file is generated from autoconf
+ * and I didn't want to make this too complicated.
+ */
+#if _BIGENDIAN
+#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0)
+#else
+#define USB_LE16_TO_CPU(x)
+#endif
+
+/* Data types */
+struct usb_device;
+struct usb_bus;
+
+/*
+ * To maintain compatibility with applications already built with libusb,
+ * we must only add entries to the end of this structure. NEVER delete or
+ * move members and only change types if you really know what you're doing.
+ */
+struct usb_device {
+  struct usb_device *next, *prev;
+
+  char filename[PATH_MAX + 1];
+
+  struct usb_bus *bus;
+
+  struct usb_device_descriptor descriptor;
+  struct usb_config_descriptor *config;
+
+  void *dev;           /* Darwin support */
+
+  unsigned char devnum;
+
+  unsigned char num_children;
+  struct usb_device **children;
+};
+
+struct usb_bus {
+  struct usb_bus *next, *prev;
+
+  char dirname[PATH_MAX + 1];
+
+  struct usb_device *devices;
+  unsigned long location;
+
+  struct usb_device *root_dev;
+};
+
+struct usb_dev_handle;
+typedef struct usb_dev_handle usb_dev_handle;
+
+/* Variables */
+extern struct usb_bus *usb_busses;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+/* usb.c */
+usb_dev_handle *usb_open(struct usb_device *dev);
+int usb_close(usb_dev_handle *dev);
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+       size_t buflen);
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf,
+       size_t buflen);
+
+/* descriptors.c */
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+       unsigned char type, unsigned char index, void *buf, int size);
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+       unsigned char index, void *buf, int size);
+
+/* <arch>.c */
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout);
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+       int timeout);
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+        int timeout);
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+        int timeout);
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+       int value, int index, char *bytes, int size, int timeout);
+int usb_set_configuration(usb_dev_handle *dev, int configuration);
+int usb_claim_interface(usb_dev_handle *dev, int interface);
+int usb_release_interface(usb_dev_handle *dev, int interface);
+int usb_set_altinterface(usb_dev_handle *dev, int alternate);
+int usb_resetep(usb_dev_handle *dev, unsigned int ep);
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
+int usb_reset(usb_dev_handle *dev);
+
+#if LINUX_API
+#define LIBUSB_HAS_GET_DRIVER_NP 1
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+       unsigned int namelen);
+#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
+#endif
+
+char *usb_strerror(void);
+
+void usb_init(void);
+void usb_set_debug(int level);
+int usb_find_busses(void);
+int usb_find_devices(void);
+struct usb_device *usb_device(usb_dev_handle *dev);
+struct usb_bus *usb_get_busses(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_H__ */
+
diff --git a/deps/libusb/usbi.h b/deps/libusb/usbi.h
new file mode 100644 (file)
index 0000000..d71b5c4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _USBI_H_
+#define _USBI_H_
+
+#include "usb.h"
+
+#include "error.h"
+
+extern int usb_debug;
+
+/* Some quick and generic macros for the simple kind of lists we use */
+#define LIST_ADD(begin, ent) \
+       do { \
+         if (begin) { \
+           ent->next = begin; \
+           ent->next->prev = ent; \
+         } else \
+           ent->next = NULL; \
+         ent->prev = NULL; \
+         begin = ent; \
+       } while(0)
+
+#define LIST_DEL(begin, ent) \
+       do { \
+         if (ent->prev) \
+           ent->prev->next = ent->next; \
+         else \
+           begin = ent->next; \
+         if (ent->next) \
+           ent->next->prev = ent->prev; \
+         ent->prev = NULL; \
+         ent->next = NULL; \
+       } while (0)
+
+#define DESC_HEADER_LENGTH             2
+#define DEVICE_DESC_LENGTH             18
+#define CONFIG_DESC_LENGTH             9
+#define INTERFACE_DESC_LENGTH          9
+#define ENDPOINT_DESC_LENGTH           7
+#define ENDPOINT_AUDIO_DESC_LENGTH     9
+
+struct usb_dev_handle {
+  int fd;
+
+  struct usb_bus *bus;
+  struct usb_device *device;
+
+  int config;
+  int interface;
+  int altsetting;
+
+  /* Added by RMT so implementations can store other per-open-device data */
+  void *impl_info;
+};
+
+/* descriptors.c */
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest);
+int usb_parse_configuration(struct usb_config_descriptor *config,
+       unsigned char *buffer);
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev);
+void usb_destroy_configuration(struct usb_device *dev);
+
+/* OS specific routines */
+int usb_os_find_busses(struct usb_bus **busses);
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices);
+int usb_os_determine_children(struct usb_bus *bus);
+void usb_os_init(void);
+int usb_os_open(usb_dev_handle *dev);
+int usb_os_close(usb_dev_handle *dev);
+
+void usb_free_dev(struct usb_device *dev);
+void usb_free_bus(struct usb_bus *bus);
+
+#endif /* _USBI_H_ */
+
diff --git a/deps/libusb/windows.c b/deps/libusb/windows.c
new file mode 100755 (executable)
index 0000000..0afbef9
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <windows.h>
+#include <setupapi.h>
+#include <winerror.h>
+#include "winusb.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include "fdevent.h"
+#include "utils.h"
+#include "strutils.h"
+#include "linkedlist.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "sdb.h"
+#include "sdb_usb.h"
+
+struct usb_handle {
+    LIST_NODE* node;
+
+    HANDLE hnd;
+    WINUSB_INTERFACE_HANDLE fd;
+    char unique_node_path[PATH_MAX+1]; //MAX_DEVICE_ID_LEN <device-ID>\<instance-specific-ID>
+    UCHAR end_point[2];
+    unsigned int zero_mask;
+};
+usb_handle *usb_open(const char *device_path);
+int win_usb_close(usb_handle *dev);
+int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen);
+void *device_poll_thread(void* unused);
+int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout);
+void do_lsusb(void);
+
+// Class ID assigned to the device by aNdrOiduSb.sys
+static const GUID TIZEN_CLASSID = {0x9ca29f37, 0xdd62, 0x4aad, {0x82, 0x65, 0xcf, 0xf7, 0x88, 0xc8, 0xba, 0x89}};
+
+static LIST_NODE* handle_list = NULL;
+
+SDB_MUTEX_DEFINE( usb_lock );
+
+
+// winusb.dll entrypoints
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetOverlappedResult, (WINUSB_INTERFACE_HANDLE, LPOVERLAPPED, LPDWORD, BOOL));
+
+void win_usb_init(void) {
+    // Initialize DLL functions
+    if (!WinUsb_Initialize) {
+        DLL_LOAD(winusb.dll, WinUsb_Initialize);
+        DLL_LOAD(winusb.dll, WinUsb_Free);
+        DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface);
+        DLL_LOAD(winusb.dll, WinUsb_GetDescriptor);
+        DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings);
+        DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation);
+        DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting);
+        DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting);
+        DLL_LOAD(winusb.dll, WinUsb_QueryPipe);
+        DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy);
+        DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy);
+        DLL_LOAD(winusb.dll, WinUsb_ReadPipe);
+        DLL_LOAD(winusb.dll, WinUsb_WritePipe);
+        DLL_LOAD(winusb.dll, WinUsb_ControlTransfer);
+        DLL_LOAD(winusb.dll, WinUsb_ResetPipe);
+        DLL_LOAD(winusb.dll, WinUsb_AbortPipe);
+        DLL_LOAD(winusb.dll, WinUsb_FlushPipe);
+        DLL_LOAD(winusb.dll, WinUsb_GetOverlappedResult);
+    }
+}
+
+int is_device_registered(const char *node_path)
+{
+    int r = 0;
+    sdb_mutex_lock(&usb_lock, "usb is_device_registered");
+
+    LIST_NODE* cur_ptr = handle_list;
+    while(cur_ptr != NULL) {
+       usb_handle* usb = cur_ptr->data;
+       cur_ptr = cur_ptr->next_ptr;
+
+       if(!strcmp(usb->unique_node_path, node_path)) {
+               r = 1;
+               break;
+       }
+    }
+    sdb_mutex_unlock(&usb_lock, "usb is_device_registered");
+    return r;
+}
+
+usb_handle *usb_open(const char *device_path) {
+    // Allocate storage for handles
+    usb_handle* usb = calloc(1, sizeof(usb_handle));
+    s_strncpy(usb->unique_node_path, device_path, sizeof(usb->unique_node_path));
+
+    // Open generic handle to device
+    HANDLE hnd = CreateFile(device_path, GENERIC_WRITE | GENERIC_READ,
+            FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING,
+            FILE_FLAG_OVERLAPPED, NULL);
+
+    if (INVALID_HANDLE_VALUE == hnd) {
+        D("fail to create device file: %s due to: %d\n", device_path, GetLastError());
+       return NULL;
+    }
+
+    // Initialize WinUSB for this device and get a WinUSB handle for it
+    WINUSB_INTERFACE_HANDLE fd;
+    if (!WinUsb_Initialize(hnd, &fd)) {
+        return NULL;
+    }
+
+    // fetch USB device descriptor
+    USB_DEVICE_DESCRIPTOR         usb_device_descriptor;
+    unsigned long bytes_written;
+
+    if (!WinUsb_GetDescriptor(fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0,
+            (PUCHAR)&usb_device_descriptor, sizeof(usb_device_descriptor), &bytes_written)) {
+        return NULL;
+    }
+
+    USB_INTERFACE_DESCRIPTOR      usb_interface_descriptor;
+
+    // fetch usb interface descriptor
+    UCHAR interface_number;
+    if (!WinUsb_GetCurrentAlternateSetting(fd, &interface_number)) {
+        return NULL;
+    }
+
+    if (!WinUsb_QueryInterfaceSettings(fd, interface_number, &usb_interface_descriptor)) {
+        return NULL;
+    }
+
+    if (2 != usb_interface_descriptor.bNumEndpoints) {
+        D("the number of endpoint should be two\n");
+        return NULL;
+    }
+
+    if (!is_sdb_interface(usb_device_descriptor.idVendor, usb_interface_descriptor.bInterfaceClass, usb_interface_descriptor.bInterfaceSubClass,
+            usb_interface_descriptor.bInterfaceProtocol)) {
+        return NULL;
+    }
+    UCHAR endpoint_index = 0;
+
+    for (endpoint_index = 0; endpoint_index < usb_interface_descriptor.bNumEndpoints; endpoint_index++) {
+        // fetch endpoint information
+        WINUSB_PIPE_INFORMATION pipe_info;
+        if (!WinUsb_QueryPipe(fd, interface_number, endpoint_index, &pipe_info)) {
+            return NULL;
+        }
+
+        if(usb_interface_descriptor.bInterfaceProtocol == 0x01) {
+            if (endpoint_index == 0) {
+                usb->zero_mask = pipe_info.MaximumPacketSize - 1;
+            }
+        }
+        // only interested in bulk type
+        if (UsbdPipeTypeBulk == pipe_info.PipeType) {
+            if (USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) {
+                D("builk in endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId);
+                usb->end_point[0] = pipe_info.PipeId;
+            }
+
+            if (USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) {
+                D("builk out endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId);
+                usb->end_point[1] = pipe_info.PipeId;
+            }
+
+        }
+    }
+    usb->hnd = hnd;
+    usb->fd = fd;
+
+    return usb;
+}
+
+int register_device(usb_handle *hnd) {
+    if (is_device_registered(hnd->unique_node_path)) {
+        return 0;
+    }
+
+    sdb_mutex_lock(&usb_lock, "usb register_device");
+
+    hnd->node = prepend(&handle_list, hnd);
+
+    sdb_mutex_unlock(&usb_lock, "usb register_device");
+
+    return 1;
+}
+
+int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen) {
+    unsigned char temp[MAXIMUM_USB_STRING_LENGTH];
+
+    ULONG actlen = 0;
+    //0x0409 for English (US)
+    if (!WinUsb_GetDescriptor(dev->fd, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409, temp, sizeof(temp), &actlen)) {
+        return -GetLastError();
+    }
+    // Skip first two bytes of result (descriptor id and length), then take
+    // every other byte as a cheap way to convert Unicode to ASCII
+    unsigned int i, j;
+    for (i = 2, j = 0; i < actlen && j < (buflen - 1); i += 2, ++j)
+        buf[j] = temp[i];
+    buf[j] = '\0';
+
+    return strlen(buf);
+}
+
+static int get_serial_number(usb_handle *dev, char *buf, int buflen) {
+    USB_DEVICE_DESCRIPTOR         usb_device_descriptor;
+    ULONG actlen = 0;
+
+    if (!WinUsb_GetDescriptor(dev->fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (unsigned char*) &usb_device_descriptor,
+            sizeof(usb_device_descriptor), &actlen)) {
+        return 0;
+    }
+
+    return usb_get_string_simple(dev, usb_device_descriptor.iSerialNumber, buf, buflen);
+}
+
+int usb_find_devices(GUID deviceClassID) {
+    SP_DEVINFO_DATA deviceInfoData;
+    char devicePath[PATH_MAX + 1];
+    BOOL bResult = TRUE;
+    PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
+    int index = 0;
+
+    // from http://msdn.microsoft.com/en-us/library/windows/hardware/ff540174(v=vs.85).aspx
+    // Get information about all the installed devices for the specified device interface class.
+    HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&deviceClassID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+    if (hDeviceInfo == INVALID_HANDLE_VALUE) {
+        D("fail to find any device: %d\n", GetLastError());
+        return 0;
+    }
+
+    //Enumerate all the device interfaces in the device information set.
+    deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+
+    for (index = 0; ; index++) {
+
+        //Get information about the device interface.
+        SP_DEVICE_INTERFACE_DATA interfaceData;
+        interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
+
+        bResult = SetupDiEnumDeviceInterfaces(hDeviceInfo, NULL, &deviceClassID, index, &interfaceData);
+        // Check if last item
+        if (GetLastError() == ERROR_NO_MORE_ITEMS) {
+            break;
+        }
+
+        //Check for some other error
+        if (!bResult)
+        {
+            D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
+            break;
+        }
+
+        // Determine required size for interface detail data
+        ULONG requiredLength = 0;
+
+        //Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA
+        //which we need to allocate, so we have to call this function twice.
+        //First to get the size so that we know how much to allocate
+        //Second, the actual call with the allocated buffer
+        bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL);
+
+        //Check for some other error
+        if (!bResult) {
+            if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (requiredLength > 0)) {
+                // Allocate storage for interface detail data
+                detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredLength);
+
+                if (detailData == NULL) {
+                    D("fail to allocate memory\n");
+                    break;
+                }
+            } else {
+                D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
+                break;
+            }
+        }
+
+        // Finally, do fetch interface detail data
+        detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+        //Now call it with the correct size and allocated buffer
+        bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, detailData, requiredLength, NULL,
+                &deviceInfoData);
+
+        //Check for some other error
+        if (!bResult) {
+            D("fail to setdup get device interface detail: %d\n", GetLastError());
+            if (detailData != NULL) {
+                free(detailData);
+            }
+            break;
+        }
+
+        //copy device path
+        s_strncpy(devicePath, detailData->DevicePath, sizeof(devicePath));
+
+        if (detailData != NULL) {
+            free(detailData);
+        }
+
+        if (!is_device_registered(devicePath)) {
+            struct usb_handle *hnd = usb_open(devicePath);
+            if (hnd != NULL) {
+                char serial[256];
+                if (get_serial_number(hnd, serial, sizeof(serial)) > 0) {
+                    D("register usb for: %s\n", serial);
+                    if (register_device(hnd)) {
+                        register_usb_transport(hnd, serial);
+                    } else {
+                        D("fail to register usb\n");
+                        win_usb_close(hnd);
+                        free(hnd);
+                    }
+                } else {
+                    D("fail to get usb serial name: kick? close?\n");
+                    win_usb_close(hnd);
+                    free(hnd);
+                }
+            }
+        }
+    }
+    //  Cleanup
+    bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo);
+
+    return bResult;
+}
+
+void* device_poll_thread(void* sleep_msec) {
+    D("Created device thread\n");
+
+    int  mseconds = (int) sleep_msec;
+    while (1) {
+        do_lsusb();
+        sdb_sleep_ms(mseconds);
+    }
+
+    return NULL;
+}
+
+void sdb_usb_init() {
+    sdb_thread_t tid;
+
+    win_usb_init();
+    if (sdb_thread_create(&tid, device_poll_thread, (void*)3000)) {
+        LOG_FATAL("cannot create input thread\n");
+    }
+}
+
+void sdb_usb_cleanup() {
+    D("TODO: not imple yet\n");
+}
+
+int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout) {
+    ULONG tmp = timeout;
+    UCHAR endpoint;
+
+    if (is_read) {
+        endpoint = handle->end_point[0];
+    } else {
+        endpoint = handle->end_point[1];
+    }
+    if (handle->fd == NULL) {
+        D("invalid handle\n");
+        return 0;
+    }
+
+    // do not complete within the specified time-out interval
+    if (!WinUsb_SetPipePolicy(handle->fd, endpoint, PIPE_TRANSFER_TIMEOUT, sizeof(tmp), &tmp)) {
+        D("fail to set timeout\n");
+        SetLastError(ERROR_SEM_TIMEOUT);
+        return 0;
+    }
+
+    // manual reset must be true (second param) as the reset occurs in read
+
+    OVERLAPPED overlapped;
+    ZeroMemory(&overlapped, sizeof(overlapped));
+    overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+    BOOL ret = TRUE;
+    ULONG transferred = 0;
+
+    if (is_read) {
+        ret = WinUsb_ReadPipe(handle->fd, endpoint, (UCHAR*) data, length, &transferred, &overlapped);
+    } else {
+        ret = WinUsb_WritePipe(handle->fd, endpoint, (UCHAR*) data, length, &transferred, &overlapped);
+    }
+
+    if (!ret && (ERROR_IO_PENDING != GetLastError())) {
+        if (NULL != overlapped.hEvent){
+            CloseHandle(overlapped.hEvent);
+        }
+        D("pipe error: (%ld/ld) error:%d\n", length, transferred, GetLastError());
+        return 0;
+    }
+
+    // wait for the operation to be IO completed
+    ret = WinUsb_GetOverlappedResult(handle->fd, &overlapped, &transferred, TRUE);
+
+    if (ret && (NULL != actual_length)) {
+        *actual_length = transferred;
+    }
+
+    if (NULL != overlapped.hEvent) {
+        CloseHandle(overlapped.hEvent);
+    }
+
+    return ret ? 1 : 0;
+}
+
+int sdb_usb_write(usb_handle* handle, const void* data, int len) {
+    unsigned long time_out = 5000;//5000;
+    unsigned long written = 0;
+    int ret;
+
+    D("+sdb_usb_write %d\n", len);
+
+    if (NULL != handle) {
+        ret = usb_bulk_transfer(handle, FALSE, (void*)data, (unsigned long)len, &written, time_out);
+        int saved_errno = GetLastError();
+        D("sdb_usb_write got(ret:%d): %ld, expected: %d, errno: %d\n",ret, written, len, saved_errno);
+
+        if (ret) {
+            if (written == (unsigned long) len) {
+                if (handle->zero_mask && (len & handle->zero_mask) == 0) {
+                    // Send a zero length packet
+                    usb_bulk_transfer(handle, FALSE, (void*)data, 0, &written, time_out);
+                }
+                return 0;
+            }
+        } else {
+            // assume ERROR_INVALID_HANDLE indicates we are disconnected
+            if (saved_errno == ERROR_INVALID_HANDLE) {
+                sdb_usb_kick(handle);
+            }
+        }
+        errno = saved_errno;
+    } else {
+        D("usb_write NULL handle\n");
+        SetLastError(ERROR_INVALID_HANDLE);
+    }
+
+    D("-sdb_usb_write failed: %d\n", errno);
+
+    return -1;
+}
+
+int sdb_usb_read(usb_handle *handle, void* data, int len) {
+    unsigned long n = 0;
+    int ret;
+
+    D("+sdb_usb_read %d\n", len);
+    if (NULL != handle) {
+        while (len > 0) {
+            int xfer = (len > 4096) ? 4096 : len;
+            ret = usb_bulk_transfer(handle, TRUE, (void*)data, (unsigned long)xfer, &n, (unsigned long)0);
+            int saved_errno = GetLastError();
+            D("sdb_usb_read got(ret:%d): %ld, expected: %d, errno: %d\n", ret, n, xfer, saved_errno);
+
+            if (ret) {
+                data += n;
+                len -= n;
+
+                if (len == 0)
+                    return 0;
+            } else {
+                // assume ERROR_INVALID_HANDLE indicates we are disconnected
+                if (saved_errno == ERROR_INVALID_HANDLE) {
+                    sdb_usb_kick(handle);
+                }
+                break;
+            }
+            errno = saved_errno;
+        }
+    } else {
+        D("sdb_usb_read NULL handle\n");
+        SetLastError(ERROR_INVALID_HANDLE);
+    }
+
+    D("-sdb_usb_read failed: %d\n", errno);
+
+    return -1;
+}
+
+int win_usb_close(usb_handle *handle) {
+    D("+usb win_usb_close\n");
+    if (NULL != handle) {
+        if (NULL != handle->fd) {
+            WinUsb_Free(handle->fd);
+            handle->fd = NULL;
+        }
+        if (NULL != handle->hnd) {
+            CloseHandle(handle->hnd);
+            handle->hnd = NULL;
+        }
+        handle = NULL;
+    }
+    D("-usb win_usb_close\n");
+    return 0;
+}
+
+void sdb_usb_kick(usb_handle* handle) {
+    D("+sdb_usb_kick: %p\n", handle);
+    // called from transport remote kick if already registered
+    // so only clean for win usb handle resources
+    sdb_mutex_lock(&usb_lock, "usb sdb_usb_kick");
+    win_usb_close(handle);
+    sdb_mutex_unlock(&usb_lock , "usb sdb_usb_kick");
+    D("-sdb_usb_kick: %p\n", handle);
+}
+
+int sdb_usb_close(usb_handle* handle) {
+    D("+sdb_usb_close: %p\n", handle);
+    if (NULL != handle) {
+        sdb_mutex_lock(&usb_lock, "usb sdb_usb_close");
+        remove_node(&handle_list, handle->node, NULL);
+        sdb_mutex_unlock(&usb_lock, "usb sdb_usb_close");
+    }
+    D("-sdb_usb_close: %p\n", handle);
+    return 0;
+}
+
+void do_lsusb() {
+    usb_find_devices(TIZEN_CLASSID);
+}
diff --git a/deps/libusb/winusb.h b/deps/libusb/winusb.h
new file mode 100755 (executable)
index 0000000..8e5cf8a
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __WINUSB_H
+#define __WINUSB_H
+
+#include "ddk/usb100.h"
+#include "ddk/usbioctl.h"
+
+// Windows API default is uppercase - ugh!
+#if !defined(bool)
+#define bool BOOLEAN
+#endif
+#if !defined(true)
+#define true TRUE
+#endif
+#if !defined(false)
+#define false FALSE
+#endif
+
+
+/*
+ * Some of the EX stuff is not yet in MinGW => define it
+ */
+#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX
+#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
+#endif
+
+#ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
+        CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \
+        METHOD_BUFFERED, FILE_ANY_ACCESS)
+#endif
+
+#ifndef USB_NODE_CONNECTION_INFORMATION_EX
+typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
+        ULONG ConnectionIndex;
+        USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+        UCHAR CurrentConfigurationValue;
+        UCHAR Speed;
+        BOOLEAN DeviceIsHub;
+        USHORT DeviceAddress;
+        ULONG NumberOfOpenPipes;
+        USB_CONNECTION_STATUS ConnectionStatus;
+        USB_PIPE_INFO PipeList[0];
+} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
+#endif
+
+#ifndef USB_HUB_CAP_FLAGS
+typedef union _USB_HUB_CAP_FLAGS {
+        ULONG ul;
+        struct {
+                ULONG HubIsHighSpeedCapable:1;
+                ULONG HubIsHighSpeed:1;
+                ULONG HubIsMultiTtCapable:1;
+                ULONG HubIsMultiTt:1;
+                ULONG HubIsRoot:1;
+                ULONG HubIsArmedWakeOnConnect:1;
+                ULONG ReservedMBZ:26;
+        };
+} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS;
+#endif
+
+#ifndef USB_HUB_CAPABILITIES_EX
+typedef struct _USB_HUB_CAPABILITIES_EX {
+        USB_HUB_CAP_FLAGS CapabilityFlags;
+} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX;
+#endif
+
+#ifndef USB_GET_HUB_CAPABILITIES_EX
+#define USB_GET_HUB_CAPABILITIES_EX 276
+#endif
+
+#ifndef IOCTL_USB_GET_HUB_CAPABILITIES_EX
+#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \
+        CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, \
+        METHOD_BUFFERED, FILE_ANY_ACCESS )
+#endif
+
+/*
+ * WinUSB macros - from libusb-win32 1.x
+ */
+
+#define DLL_DECLARE(api, ret, name, args) \
+   typedef ret (api * __dll_##name##_t)args; \
+   static __dll_##name##_t name
+
+#define DLL_LOAD(dll, name)                                   \
+  do {                                                        \
+  HMODULE h = GetModuleHandle(#dll);                          \
+  if(!h)                                                      \
+    h = LoadLibrary(#dll);                                    \
+  if(!h)                                                      \
+    break;                                                    \
+  if((name = (__dll_##name##_t)GetProcAddress(h, #name)))     \
+    break;                                                    \
+  if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \
+    break;                                                    \
+  if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \
+    break;                                                    \
+  } while(0)
+
+
+/* winusb.dll interface */
+
+#define SHORT_PACKET_TERMINATE  0x01
+#define AUTO_CLEAR_STALL        0x02
+#define PIPE_TRANSFER_TIMEOUT   0x03
+#define IGNORE_SHORT_PACKETS    0x04
+#define ALLOW_PARTIAL_READS     0x05
+#define AUTO_FLUSH              0x06
+#define RAW_IO                  0x07
+#define MAXIMUM_TRANSFER_SIZE   0x08
+#define AUTO_SUSPEND            0x81
+#define SUSPEND_DELAY           0x83
+#define DEVICE_SPEED            0x01
+#define LowSpeed                0x01
+#define FullSpeed               0x02
+#define HighSpeed               0x03
+
+typedef enum _USBD_PIPE_TYPE {
+        UsbdPipeTypeControl,
+        UsbdPipeTypeIsochronous,
+        UsbdPipeTypeBulk,
+        UsbdPipeTypeInterrupt
+} USBD_PIPE_TYPE;
+
+typedef struct {
+  USBD_PIPE_TYPE PipeType;
+  UCHAR          PipeId;
+  USHORT         MaximumPacketSize;
+  UCHAR          Interval;
+} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
+
+#pragma pack(1)
+typedef struct {
+  UCHAR  RequestType;
+  UCHAR  Request;
+  USHORT Value;
+  USHORT Index;
+  USHORT Length;
+} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
+#pragma pack()
+
+typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
+
+#endif // __WINUSB_H
index 254939748c6721766763e57c2223df7192d7edf0..164ccd9453bf44cee082404bbf30ba8c7cf349c1 100644 (file)
@@ -1,51 +1,60 @@
+* 2.2.20
+- fix offline bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-16 21:35
+* 2.2.19
+- fix device undetected bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-16 20:36
+* 2.2.18
+- Fix duplicated target bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-16 13:50
 * 2.2.17
-- change compiler to llvm
-== yoonki.park <yoonki.park@samsung.com> 2013-07-15
+- fix pull/ push bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-14 20:06
 * 2.2.16
-- fixed build script for tsudo
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-15
+- fix bugs about sdb test cases
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-01
 * 2.2.15
-- give abs path to tsudo
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-12
+- version up for refactoring test
+== ho.namkoong <ho.namkoong@samsung.com> 2013-08-23
 * 2.2.14
-- Change PATH_MAX in Windows 256 -> 4096
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
+- version up 2.2.14
+== ho.namkoong <ho.namkoong@samsung.com> 2013-08-07
 * 2.2.13
-- echo stdout in install script
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
+- version up 2.2.13
+== ho.namkoong <ho.namkoong@samsung.com> 2013-08-05
 * 2.2.12
-- use tsudo instead of gksudo
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
+- fix socket close bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-24
 * 2.2.11
-- Fixed sdbd version checking without rpm query
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-08
+- fix web debugging bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-24
 * 2.2.10
-- Fixed argument append util for da/oprofile command
-== kh5325.kim <kh5325.kim@samsung.com> 2013-07-08
+- fix forward bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-24
 * 2.2.9
-- Fix pull/push message
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-04
+- remove setting sdb path
+== yoonki.park <yoonki.park@samsung.com> 2013-07-23
 * 2.2.8
-- Fix window install bug
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-28
+- fixed to install on windows
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-22
 * 2.2.7
-- rollback linux usb control
-== ho.namkoong <yoonki.park@samsung.com> 2013-06-25
+- fixed to add sdb path to windows shell
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-19
 * 2.2.6
-- change lstat to stat for treating link file as regular file
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-24
+- change PATH_MAX in Windows 256 -> 4096
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
 * 2.2.5
-- modify debug launchpad applied sdbd version
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-24
+- use tsudo
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
 * 2.2.4
-- change sdb version in help page
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-23
+- use libusb.so
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
 * 2.2.3
-- remove printf in lauchapp
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-23
+- fix da and oprofile arg appending bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-04
 * 2.2.2
-- apply debug launch pad
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-23
+- sdb for tizen2.2
+== yoonki.park <yoonki.park@samsung.com> 2013-07-04
 * 2.2.1
 - fixed crash on Windows
 == yoonki.park <yoonki.park@samsung.com> 2013-06-21
index 7ce81c8487f9773c0039f22847de9a029ac36a84..edea43b34477d40b9a8b8b99a9b9c72a12254f7a 100644 (file)
@@ -1,4 +1,4 @@
-Version:2.2.17
+Version:2.2.20
 Source:sdb
 Maintainer:Kangho Kim <kh5325.kim@samsung.com>, Yoonki Park<yoonki.park@samsung.com>, Hyunsik Noh<hyunsik.noh@samsung.com>, Gun Kim<gune.kim@samsung.com>, Ho Namkoong<ho.namkoong@samsung.com>, Taeyoung Son<taeyoung2.son@samsung.com>
 
index 456cba75d3a1fd23442caeea859c1ab5acfdca35..256b648ac0f9e894591c854cbcd7478cae7de06e 100755 (executable)
@@ -1,54 +1,3 @@
 #!/bin/bash -ex
 
-## Set sdb's environment path
-bashrc=${HOME}/.bashrc
-if [ -f ${bashrc} ]; then
-    s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"`
-else
-    s=
-fi
-
-if [ "x${s}" = "x" ]; then
-cat >> ${bashrc} << END
-## Tizen SDK configuration
-# This is generated by Tizen SDK. Please do not modify by yourself.
-# Set sdb environment path
-export PATH=\$PATH:${INSTALLED_PATH}/tools
-## End Tizen SDK configuration
-END
-fi
-
-source ${HOME}/.bashrc
-
-# set udev rules file
-
-TMP_FILE=99-samsung-device.rules
-echo "# Add a udev rules when you want to develop a Tizen application with your device." >> $TMP_FILE
-echo "# Use this format to add each vendor to the file:" >> $TMP_FILE
-echo "# SUBSYSTEM==\"usb\", ATTR{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE
-echo "# In the example, the vendor ID is for Samsung manufacture. The mode specifies read/write permissions, and group defines which Unix group owns the device node." >> $TMP_FILE
-echo "#" >> $TMP_FILE
-echo "# Contact : Kangho Kim <kh5325.kim@samsung.com>, Yoonki Park<yoonki.park@samsung.com>, Ho Namkoong <ho.namkoong@samsung.com>" >> $TMP_FILE
-echo "# See also udev(7) for an overview of rule syntax." >> $TMP_FILE
-echo "" >> $TMP_FILE
-echo "# Samsung" >> $TMP_FILE
-echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE
-echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6863\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE
-
-chmod +x $TMP_FILE
-CURRENT_DIR=`pwd`
-
-if [ -z "$TSUDO" ]; then
-    if [ -f /usr/bin/gksudo ]
-        then gksudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/
-        else if [ -f /usr/bin/sudo ]
-            then sudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/
-        fi
-    fi
-    exit 0
-else
-    $TSUDO -m "Enter your password to install sdb." mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/
-    exit 0
-fi
-
 exit 0
index 08a8365e16ce9e7b118a50142bac13a86daf46f0..256b648ac0f9e894591c854cbcd7478cae7de06e 100755 (executable)
@@ -1,24 +1,3 @@
 #!/bin/bash -ex
 
-## Set sdb's environment path
-
-bashrc=${HOME}/.bashrc
-if [ -f ${bashrc} ]; then
-    s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"`
-else
-    s=
-fi
-
-if [ "x${s}" = "x" ]; then
-cat >> ${bashrc} << END
-## Tizen SDK configuration
-# This is generated by Tizen SDK. Please do not modify by yourself.
-# Set sdb environment path
-export PATH=\$PATH:${INSTALLED_PATH}/tools
-## End Tizen SDK configuration
-END
-fi
-
-source ${HOME}/.bashrc
-
 exit 0
index 02753b76eb28c3faa5dc1b8083b66c93c3e158b0..83cb140ebd7fd0e2affeced2a0c8d97b16755592 100644 (file)
@@ -1,5 +1 @@
 @echo off
-
-echo "setting path..."
-setx -m PATH "%PATH%;${INSTALLED_PATH}\tools
-exit 0
index b849590fb019912b136225d4d9bfdf991598ba27..8f3cbf8c0aecd8e8ea37167079394fbdec320e0b 100755 (executable)
@@ -2,35 +2,23 @@
 SDB_PATH=tools/sdb
 ${INSTALLED_PATH}/${SDB_PATH} kill-server
 rm -rf ${INSTALLED_PATH}/${SDB_PATH}
-## remove sdb environment path
-s=`cat ${HOME}/.bashrc | grep -n "## Tizen SDK configuration" | cut -f1 -d":"`
 
-if [ "x${s}" = "x" ] ; then
-       exit 0
-fi
+UDEV_RULE=/etc/udev/rules.d/99-samsung-device.rules
 
-if [ ${s} -ge 0 ] ; then
-       e=`cat ${HOME}/.bashrc | grep -n "## End Tizen SDK configuration" | cut -f1 -d":"`
-       if [ $e -ge $s ] ; then
-               cp ${HOME}/.bashrc ${HOME}/.bashrc.tizen
-               sed "${s},${e}d" ${HOME}/.bashrc > ${HOME}/.bashrc.swap
-               mv ${HOME}/.bashrc.swap ${HOME}/.bashrc
-               source ${HOME}/.bashrc
-       fi
+if [ ! -f ${UDEV_RULE} ]; then
+    exit 0
 fi
-
 ## remove udev rule file
-
 if [ -z "$TSUDO" ]; then
     if [ -f /usr/bin/gksudo ]
-        then gksudo rm -rf /etc/udev/rules.d/99-samsung-device.rules
+        then gksudo rm -rf ${UDEV_RULE}
         else if [ -f /usr/bin/sudo ]
-            then sudo rm -rf /etc/udev/rules.d/99-samsung-device.rules
+            then sudo rm -rf ${UDEV_RULE}
         fi
     fi
     exit 0
 else
-    $TSUDO -m "Enter your password to uninstall sdb." rm -rf /etc/udev/rules.d/99-samsung-device.rules
+    $TSUDO -m "Enter your password to uninstall sdb." rm -rf ${UDEV_RULE}
     exit 0
 fi
 
index 763231734d62c3e34aa8ae0c4cdaa9179b3d4db5..10a8ddaa4a369abd6fe224afd6159477e8cf4067 100755 (executable)
@@ -2,21 +2,5 @@
 SDB_PATH=tools/sdb
 ${INSTALLED_PATH}/${SDB_PATH} kill-server
 rm -rf ${INSTALLED_PATH}/${SDB_PATH}
-## remove sdb environment path
-s=`cat ${HOME}/.bashrc | grep -n "## Tizen SDK configuration" | cut -f1 -d":"`
-
-if [ "x${s}" = "x" ] ; then
-       exit 1
-fi
-
-if [ ${s} -ge 0 ] ; then
-       e=`cat ${HOME}/.bashrc | grep -n "## End Tizen SDK configuration" | cut -f1 -d":"`
-       if [ $e -ge $s ] ; then
-               cp ${HOME}/.bashrc ${HOME}/.bashrc.tizen
-               sed "${s},${e}d" ${HOME}/.bashrc > ${HOME}/.bashrc.swap
-               mv ${HOME}/.bashrc.swap ${HOME}/.bashrc
-               source ${HOME}/.bashrc
-       fi
-fi
 
 exit 0
index 1c3c6646c52913a61c53f0aa4081a42fe45f97d1..1d845d3afea3cd31fedffc37e9463ea43c5e3c94 100644 (file)
@@ -1,8 +1,18 @@
 @echo off
 
-set execute_path=tools
-%INSTALLED_PATH%\%execute_path%\sdb.exe kill-server
-del %INSTALLED_PATH%\%execute_path%\sdb.exe
-del %INSTALLED_PATH%\%execute_path%\ansicon.exe
-del %INSTALLED_PATH%\%execute_path%\ANSI32.dll
-exit 0
+set SDB_PATH=%INSTALLED_PATH%\tools
+
+%SDB_PATH%\sdb.exe kill-server
+del %SDB_PATH%\sdb.exe
+del %SDB_PATH%\ansicon.exe
+del %SDB_PATH%\ANSI32.dll
+
+::echo "removing sdb path..."
+
+::set replace=
+::set search=%SDB_PATH%
+::set subject=%PATH%
+:: update path
+::call set subject=%%subject:%search%=%replace%%%
+::setx -m PATH "%subject%"
+exit 0
\ No newline at end of file
index 47f3eb11db0c5e303eb09da4597353f5c30ed7eb..f17051619b5ea00421b4ad478d24a492b9507622 100644 (file)
@@ -28,7 +28,6 @@
 #include <limits.h>
 #include "utils.h"
 #include "fdevent.h"
-#include "sdb.h"
 
 #include "commandline.h"
 #include "command_function.h"
 #include "strutils.h"
 #include "file_sync_client.h"
 #include "file_sync_functions.h"
+#include "common_modules.h"
+
+#include "log.h"
+#include "sdb.h"
 
 static const char *SDK_TOOL_PATH="/home/developer/sdk_tools";
 static const char *APP_PATH_PREFIX="/opt/apps";
@@ -295,6 +298,23 @@ int __connect(int argc, char ** argv, void** extargv) {
     }
 }
 
+int device_con(int argc, char ** argv, void** extargv) {
+
+    char *tmp;
+    char full_cmd[PATH_MAX];
+
+    snprintf(full_cmd, sizeof full_cmd, "host:device_con:%s:%s", argv[1], argv[2]);
+    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
+    tmp = sdb_query(full_cmd, extargv);
+
+    if(tmp != NULL) {
+        printf("%s", tmp);
+        return 0;
+    }
+
+    return 1;
+}
+
 int get_state_serialno(int argc, char ** argv, void** extargv) {
     char* serial = (char *)extargv[0];
     transport_type* ttype = (transport_type*)extargv[1];
@@ -340,8 +360,11 @@ int status_window(int argc, char ** argv, void** extargv) {
 #else
     int  fd;
     fd = unix_open("/dev/null", O_WRONLY);
-    dup2(fd, 2);
-    sdb_close(fd);
+
+    if(fd >= 0) {
+        dup2(fd, 2);
+        sdb_close(fd);
+    }
 #endif
 
     format_host_command(full_cmd, sizeof full_cmd, "get-state", *ttype, serial);
@@ -487,23 +510,20 @@ int shell(int argc, char ** argv, void** extargv) {
                 strcat(buf, "\"");
         }
 
-        for(;;) {
-            D("interactive shell loop. buff=%s\n", buf);
-            fd = sdb_connect(buf, extargv);
-            if(fd >= 0) {
-                D("about to read_and_dump(fd=%d)\n", fd);
-                read_and_dump(fd);
-                D("read_and_dump() done.\n");
-                sdb_close(fd);
-                r = 0;
-            } else {
-                r = 1;
-            }
-
-            D("interactive shell loop. return r=%d\n", r);
-            return r;
+        D("interactive shell loop. buff=%s\n", buf);
+        fd = sdb_connect(buf, extargv);
+        if(fd >= 0) {
+            D("about to read_and_dump(fd=%d)\n", fd);
+            read_and_dump(fd);
+            D("read_and_dump() done.\n");
+            sdb_close(fd);
+            r = 0;
+        } else {
+            r = 1;
         }
-        return 1;
+
+        D("interactive shell loop. return r=%d\n", r);
+        return r;
 }
 
 int forkserver(int argc, char** argv, void** extargv) {
index f9c6801f795ebb369cbb62fca31fdcb4a5b808df..42816ee569e58675d0c84918fc6152881866ee1b 100644 (file)
 #define  TRACE_TAG  TRACE_SDB
 
 #ifdef OS_WINDOWS
+#undef PATH_MAX
 #define PATH_MAX 4096
 #endif
 
-
 int da(int argc, char ** argv, void** extargv);
 int oprofile(int argc, char ** argv, void** extargv);
 int launch(int argc, char ** argv, void** extargv);
 int devices(int argc, char ** argv, void** extargv);
 int __disconnect(int argc, char ** argv, void** extargv);
 int __connect(int argc, char ** argv, void** extargv);
+int device_con(int argc, char ** argv, void** extargv);
 int get_state_serialno(int argc, char ** argv, void** extargv);
 int root(int argc, char ** argv, void** extargv);
 int status_window(int argc, char ** argv, void** extargv);
index 6f0d9fb95a73815673fa0b574ef53a197e1879cc..a761805c4228be6425d570d7f28c182af610d18d 100755 (executable)
 #include <termios.h>
 #endif
 #include "utils.h"
-#include "sdb.h"
 #include "sdb_client.h"
 #include "file_sync_service.h"
-
+#include "log.h"
 
 #include "linkedlist.h"
 #include "sdb_constants.h"
@@ -100,6 +99,7 @@ void read_and_dump(int fd)
         fwrite(buf, 1, len, stdout);
         fflush(stdout);
     }
+
 }
 
 static void *stdin_read_thread(void *x)
@@ -135,7 +135,6 @@ static void *stdin_read_thread(void *x)
                     stdin_raw_restore(INPUT_FD, tio_save);
                     free(tio_save);
 #endif
-                    free(args);
                     exit(0);
                     }
                 }
@@ -272,17 +271,17 @@ static void create_opt_list(LIST_NODE** opt_list) {
     OPTION* serial = NULL;
     create_option(&serial, COMMANDLINE_SERIAL_LONG_OPT, COMMANDLINE_SERIAL_SHORT_OPT, COMMANDLINE_SERIAL_DESC,
             COMMANDLINE_SERIAL_DESC_SIZE, COMMANDLINE_SERIAL_ARG_DESC, COMMANDLINE_SERIAL_HAS_ARG);
-    append(opt_list, serial);
+    prepend(opt_list, serial);
 
     OPTION* device = NULL;
     create_option(&device, COMMANDLINE_DEVICE_LONG_OPT, COMMANDLINE_DEVICE_SHORT_OPT, COMMANDLINE_DEVICE_DESC,
             COMMANDLINE_DEVICES_DESC_SIZE, EMPTY_STRING, COMMANDLINE_DEVICE_HAS_ARG);
-    append(opt_list, device);
+    prepend(opt_list, device);
 
     OPTION* emulator = NULL;
     create_option(&emulator, COMMANDLINE_EMULATOR_LONG_OPT, COMMANDLINE_EMULATOR_SHORT_OPT, COMMANDLINE_EMULATOR_DESC,
             COMMANDLINE_EMULATOR_DESC_SIZE, EMPTY_STRING, COMMANDLINE_EMULATOR_HAS_ARG);
-    append(opt_list, emulator);
+    prepend(opt_list, emulator);
 }
 
 static void create_cmd_list(LIST_NODE** cmd_list) {
@@ -290,112 +289,119 @@ static void create_cmd_list(LIST_NODE** cmd_list) {
     COMMAND* devices_cmd = NULL;
     create_command(&devices_cmd, COMMANDLINE_DEVICES_NAME, COMMANDLINE_DEVICES_DESC,
             COMMANDLINE_DEVICES_DESC_SIZE, EMPTY_STRING, devices, COMMANDLINE_DEVICES_MAX_ARG, COMMANDLINE_DEVICES_MIN_ARG);
-    append(cmd_list, devices_cmd);
+    prepend(cmd_list, devices_cmd);
 
     COMMAND* connect_cmd = NULL;
     create_command(&connect_cmd, COMMANDLINE_CONNECT_NAME, COMMANDLINE_CONNECT_DESC,
             COMMANDLINE_CONNECT_DESC_SIZE, COMMANDLINE_CONNECT_ARG_DESC, __connect, COMMANDLINE_CONNECT_MAX_ARG, COMMANDLINE_CONNECT_MIN_ARG);
-    append(cmd_list, connect_cmd);
+    prepend(cmd_list, connect_cmd);
 
+    //TODO REMOTE_DEVICE_CONNECT security issue should be resolved first
+#if 0
+    COMMAND* device_con_cmd = NULL;
+    create_command(&device_con_cmd, COMMANDLINE_DEVICE_CON_NAME, COMMANDLINE_DEVICE_CON_DESC,
+            COMMANDLINE_DEVICE_CON_DESC_SIZE, COMMANDLINE_DEVICE_CON_ARG_DESC, device_con, COMMANDLINE_DEVICE_CON_MAX_ARG, COMMANDLINE_DEVICE_CON_MIN_ARG);
+    prepend(cmd_list, device_con_cmd);
+#endif
     COMMAND* disconnect_cmd = NULL;
     create_command(&disconnect_cmd, COMMANDLINE_DISCONNECT_NAME, COMMANDLINE_DISCONNECT_DESC,
             COMMANDLINE_DISCONNECT_DESC_SIZE, COMMANDLINE_DISCONNECT_ARG_DESC, __disconnect, COMMANDLINE_DISCONNECT_MAX_ARG, COMMANDLINE_DISCONNECT_MIN_ARG);
-    append(cmd_list, disconnect_cmd);
+    prepend(cmd_list, disconnect_cmd);
 
     COMMAND* push_cmd = NULL;
     create_command(&push_cmd, COMMANDLINE_PUSH_NAME, COMMANDLINE_PUSH_DESC,
             COMMANDLINE_PUSH_DESC_SIZE, COMMANDLINE_PUSH_ARG_DESC, push, COMMANDLINE_PUSH_MAX_ARG, COMMANDLINE_PUSH_MIN_ARG);
-    append(cmd_list, push_cmd);
+    prepend(cmd_list, push_cmd);
 
     COMMAND* pull_cmd = NULL;
     create_command(&pull_cmd, COMMANDLINE_PULL_NAME, COMMANDLINE_PULL_DESC,
             COMMANDLINE_PULL_DESC_SIZE, COMMANDLINE_PULL_ARG_DESC, pull, COMMANDLINE_PULL_MAX_ARG, COMMANDLINE_PULL_MIN_ARG);
-    append(cmd_list, pull_cmd);
+    prepend(cmd_list, pull_cmd);
 
     COMMAND* shell_cmd = NULL;
     create_command(&shell_cmd, COMMANDLINE_SHELL_NAME, COMMANDLINE_SHELL_DESC,
             COMMANDLINE_SHELL_DESC_SIZE, COMMANDLINE_SHELL_ARG_DESC, shell, COMMANDLINE_SHELL_MAX_ARG, COMMANDLINE_SHELL_MIN_ARG);
-    append(cmd_list, shell_cmd);
+    prepend(cmd_list, shell_cmd);
 
     COMMAND* dlog_cmd = NULL;
     create_command(&dlog_cmd, COMMANDLINE_DLOG_NAME, COMMANDLINE_DLOG_DESC,
             COMMANDLINE_DLOG_DESC_SIZE, COMMANDLINE_DLOG_ARG_DESC, dlog, COMMANDLINE_DLOG_MAX_ARG, COMMANDLINE_DLOG_MIN_ARG);
-    append(cmd_list, dlog_cmd);
+    prepend(cmd_list, dlog_cmd);
 
     COMMAND* install_cmd = NULL;
     create_command(&install_cmd, COMMANDLINE_INSTALL_NAME, COMMANDLINE_INSTALL_DESC,
             COMMANDLINE_INSTALL_DESC_SIZE, COMMANDLINE_INSTALL_ARG_DESC, install, COMMANDLINE_INSTALL_MAX_ARG, COMMANDLINE_INSTALL_MIN_ARG);
-    append(cmd_list, install_cmd);
+    prepend(cmd_list, install_cmd);
 
     COMMAND* uninstall_cmd = NULL;
     create_command(&uninstall_cmd, COMMANDLINE_UNINSTALL_NAME, COMMANDLINE_UNINSTALL_DESC,
             COMMANDLINE_UNINSTALL_DESC_SIZE, COMMANDLINE_UNINSTALL_ARG_DESC, uninstall, COMMANDLINE_UNINSTALL_MAX_ARG, COMMANDLINE_UNINSTALL_MIN_ARG);
-    append(cmd_list, uninstall_cmd);
+    prepend(cmd_list, uninstall_cmd);
 
     COMMAND* forward_cmd = NULL;
     create_command(&forward_cmd, COMMANDLINE_FORWARD_NAME, COMMANDLINE_FORWARD_DESC,
             COMMANDLINE_FORWARD_DESC_SIZE, COMMANDLINE_FORWARD_ARG_DESC, forward, COMMANDLINE_FORWARD_MAX_ARG, COMMANDLINE_FORWARD_MIN_ARG);
-    append(cmd_list, forward_cmd);
+    prepend(cmd_list, forward_cmd);
 
     COMMAND* help_cmd = NULL;
     create_command(&help_cmd, COMMANDLINE_HELP_NAME, COMMANDLINE_HELP_DESC,
             COMMANDLINE_HELP_DESC_SIZE, EMPTY_STRING, NULL, 0, 0);
-    append(cmd_list, help_cmd);
+    prepend(cmd_list, help_cmd);
 
     COMMAND* version_cmd = NULL;
     create_command(&version_cmd, COMMANDLINE_VERSION_NAME, COMMANDLINE_VERSION_DESC,
             COMMANDLINE_VERSION_DESC_SIZE, EMPTY_STRING, version, COMMANDLINE_VERSION_MAX_ARG, COMMANDLINE_VERSION_MIN_ARG);
-    append(cmd_list, version_cmd);
+    prepend(cmd_list, version_cmd);
 
     COMMAND* sserver_cmd = NULL;
     create_command(&sserver_cmd, COMMANDLINE_SSERVER_NAME, COMMANDLINE_SSERVER_DESC,
             COMMANDLINE_SSERVER_DESC_SIZE, EMPTY_STRING, start_server, COMMANDLINE_SSERVER_MAX_ARG, COMMANDLINE_SSERVER_MIN_ARG);
-    append(cmd_list, sserver_cmd);
+    prepend(cmd_list, sserver_cmd);
 
     COMMAND* kserver_cmd = NULL;
     create_command(&kserver_cmd, COMMANDLINE_KSERVER_NAME, COMMANDLINE_KSERVER_DESC,
             COMMANDLINE_KSERVER_DESC_SIZE, EMPTY_STRING, kill_server, COMMANDLINE_KSERVER_MAX_ARG, COMMANDLINE_KSERVER_MIN_ARG);
-    append(cmd_list, kserver_cmd);
+    prepend(cmd_list, kserver_cmd);
 
     COMMAND* gstate_cmd = NULL;
     create_command(&gstate_cmd, COMMANDLINE_GSTATE_NAME, COMMANDLINE_GSTATE_DESC,
             COMMANDLINE_GSTATE_DESC_SIZE, EMPTY_STRING, get_state_serialno, COMMANDLINE_GSTATE_MAX_ARG, COMMANDLINE_GSTATE_MIN_ARG);
-    append(cmd_list, gstate_cmd);
+    prepend(cmd_list, gstate_cmd);
 
     COMMAND* gserial_cmd = NULL;
     create_command(&gserial_cmd, COMMANDLINE_GSERIAL_NAME, COMMANDLINE_GSERIAL_DESC,
             COMMANDLINE_GSERIAL_DESC_SIZE, EMPTY_STRING, get_state_serialno, COMMANDLINE_GSERIAL_MAX_ARG, COMMANDLINE_GSERIAL_MIN_ARG);
-    append(cmd_list, gserial_cmd);
+    prepend(cmd_list, gserial_cmd);
 
     COMMAND* swindow_cmd = NULL;
     create_command(&swindow_cmd, COMMANDLINE_SWINDOW_NAME, COMMANDLINE_SWINDOW_DESC,
             COMMANDLINE_SWINDOW_DESC_SIZE, EMPTY_STRING, status_window, COMMANDLINE_SWINDOW_MAX_ARG, COMMANDLINE_SWINDOW_MIN_ARG);
-    append(cmd_list, swindow_cmd);
+    prepend(cmd_list, swindow_cmd);
 
     COMMAND* root_cmd = NULL;
     create_command(&root_cmd, COMMANDLINE_ROOT_NAME, COMMANDLINE_ROOT_DESC,
             COMMANDLINE_ROOT_DESC_SIZE, COMMANDLINE_ROOT_ARG_DESC, root, COMMANDLINE_ROOT_MAX_ARG, COMMANDLINE_ROOT_MIN_ARG);
-    append(cmd_list, root_cmd);
+    prepend(cmd_list, root_cmd);
 
     COMMAND* launch_cmd = NULL;
     create_command(&launch_cmd, COMMANDLINE_LAUNCH_NAME, NULL,
             0, EMPTY_STRING, launch, COMMANDLINE_LAUNCH_MAX_ARG, COMMANDLINE_LAUNCH_MIN_ARG);
-    append(cmd_list, launch_cmd);
+    prepend(cmd_list, launch_cmd);
 
     COMMAND* forkserver_cmd = NULL;
     create_command(&forkserver_cmd, COMMANDLINE_FORKSERVER_NAME, NULL,
             0, EMPTY_STRING, forkserver, COMMANDLINE_FORKSERVER_MAX_ARG, COMMANDLINE_FORKSERVER_MIN_ARG);
-    append(cmd_list, forkserver_cmd);
+    prepend(cmd_list, forkserver_cmd);
 
     COMMAND* oprofile_cmd = NULL;
     create_command(&oprofile_cmd, COMMANDLINE_OPROFILE_NAME, NULL,
             0, EMPTY_STRING, oprofile, COMMANDLINE_OPROFILE_MAX_ARG, COMMANDLINE_OPROFILE_MIN_ARG);
-    append(cmd_list, oprofile_cmd);
+    prepend(cmd_list, oprofile_cmd);
 
     COMMAND* da_cmd = NULL;
     create_command(&da_cmd , COMMANDLINE_DA_NAME, NULL,
             0, EMPTY_STRING, da, COMMANDLINE_DA_MAX_ARG, COMMANDLINE_DA_MIN_ARG);
-    append(cmd_list, da_cmd );
+    prepend(cmd_list, da_cmd );
 }
 
 int process_cmdline(int argc, char** argv) {
@@ -469,10 +475,16 @@ int process_cmdline(int argc, char** argv) {
 
         if(argc < minargs + 1) {
             fprintf(stderr, "%s command has following args: %s, and it requires at least %d arguments\n", argv[0],  command->argdesc, minargs);
+            if (serial != NULL) {
+                free(serial);
+            }
             return 1;
         }
         if(argc > maxargs + 1 && maxargs > -1) {
             fprintf(stderr, "command %s require at most %d arguments\n", argv[0], maxargs);
+            if (serial != NULL) {
+                free(serial);
+            }
             return 1;
         }
         extraarg[0] = serial;
@@ -485,6 +497,9 @@ int process_cmdline(int argc, char** argv) {
     }
 
     print_help(opt_list, cmd_list);
+    if (serial != NULL) {
+        free(serial);
+    }
     return 1;
 }
 
@@ -501,6 +516,7 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) {
     char* help_str = (char*)malloc(sizeof(char)*append_len*3);
     while(curptr != NULL) {
         OPTION* opt = (OPTION*)curptr->data;
+        curptr = curptr->next_ptr;
         const char** des = opt->desc;
         if(des != NULL) {
             snprintf(help_str, append_len*3, "  -%s, --%s %s", opt->shortopt, opt->longopt, opt->argdesc);
@@ -512,21 +528,20 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) {
                 snprintf(append_str, append_len - opt_len + 1, "%s", HELP_APPEND_STR);
                 fprintf(stderr, "%s%s", help_str, append_str);
             }
+            int array_len = opt->desc_size;
+            fprintf(stderr, "- %s\n", des[0]);
+            int i = 1;
+            for(; i< array_len; i++) {
+                fprintf(stderr, "%s  %s\n", HELP_APPEND_STR, des[i]);
+            }
         }
-
-        int array_len = opt->desc_size;
-        fprintf(stderr, "- %s\n", des[0]);
-        int i = 1;
-        for(; i< array_len; i++) {
-            fprintf(stderr, "%s  %s\n", HELP_APPEND_STR, des[i]);
-        }
-        curptr = curptr->next_ptr;
     }
     fprintf(stderr, "\n commands:\n");
 
     curptr = cmdlist;
     while(curptr != NULL) {
         COMMAND* cmd = (COMMAND*)curptr ->data;
+        curptr = curptr->next_ptr;
         const char** des = cmd->desc;
         if(des != NULL) {
             snprintf(help_str, append_len*3, "  sdb %s %s", cmd->name, cmd->argdesc);
@@ -545,10 +560,10 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) {
                 fprintf(stderr, "%s  %s\n", HELP_APPEND_STR, des[i]);
             }
         }
-        curptr = curptr->next_ptr;
     }
 
-
+    free(append_str);
+    free(help_str);
 }
 
 
diff --git a/src/common_modules.h b/src/common_modules.h
new file mode 100644 (file)
index 0000000..260cb4f
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef COMMON_MODULES_H_
+#define COMMON_MODULES_H_
+
+#include "linkedlist.h"
+#include "fdevent.h"
+#include "sdb_usb.h"
+
+#define MAX_PAYLOAD 4096
+#define CHUNK_SIZE (64*1024)
+#define DEFAULT_SDB_PORT 26099
+
+#define A_VERSION 0x0100000
+
+#define SDB_VERSION_MAJOR 2
+#define SDB_VERSION_MINOR 2
+
+#define SDB_SERVER_VERSION    6
+
+extern MAP hex_map;
+
+typedef struct message MESSAGE;
+struct message {
+    unsigned command;       /* command identifier constant      */
+    unsigned arg0;          /* first argument                   */
+    unsigned arg1;          /* second argument                  */
+    unsigned data_length;   /* length of payload (0 is allowed) */
+    unsigned data_check;    /* checksum of data payload         */
+    unsigned magic;         /* command ^ 0xffffffff             */
+};
+
+typedef struct packet PACKET;
+struct packet
+{
+    LIST_NODE* node;
+
+    unsigned len;
+    void *ptr;
+
+    MESSAGE msg;
+    unsigned char data[MAX_PAYLOAD];
+};
+
+typedef enum transport_type {
+        kTransportUsb,
+        kTransportLocal,
+        kTransportAny,
+        kTransportRemoteDevCon
+} transport_type;
+
+typedef struct transport TRANSPORT;
+struct transport
+{
+    LIST_NODE* node;
+    //list for remote sockets which wait for CNXN
+    LIST_NODE* remote_cnxn_socket;
+
+    int (*read_from_remote)(TRANSPORT* t, void* data, int len);
+    int (*write_to_remote)(PACKET *p, TRANSPORT *t);
+    void (*close)(TRANSPORT *t);
+    void (*kick)(TRANSPORT *t);
+
+    int connection_state;
+    transport_type type;
+
+    usb_handle *usb;
+    int sfd;
+
+    char *serial;
+    int sdb_port;
+    char *device_name;
+
+    int          kicked;
+    unsigned req;
+    unsigned res;
+};
+
+typedef struct listener LISTENER;
+struct listener
+{
+    LIST_NODE* node;
+
+    FD_EVENT fde;
+    int fd;
+
+    const char *local_name;
+    const char *connect_to;
+    TRANSPORT *transport;
+};
+
+typedef struct t_packet T_PACKET;
+struct t_packet {
+    TRANSPORT* t;
+    PACKET* p;
+};
+
+typedef struct socket SDB_SOCKET;
+struct socket {
+    int status;
+    LIST_NODE* node;
+
+    unsigned local_id;
+    unsigned remote_id;
+
+    int    closing;
+    FD_EVENT fde;
+    int fd;
+
+    LIST_NODE* pkt_list;
+    TRANSPORT *transport;
+
+    PACKET* read_packet;
+};
+
+int readx(int fd, void *ptr, size_t len);
+int writex(int fd, const void *ptr, size_t len);
+
+#endif /* SDB_TYPES_H_ */
diff --git a/src/device_vendors.c b/src/device_vendors.c
new file mode 100644 (file)
index 0000000..5faa95e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include "device_vendors.h"
+#include "log.h"
+
+
+VENDOR tizen_device_vendors[] = {
+    {"samsung", 0x04e8} //1256
+};
+
+
+void init_device_vendors(void)
+{
+    LOG_FIXME("should implement later\n");
+    vendor_total_cnt = (sizeof(tizen_device_vendors)/sizeof(VENDOR));
+}
diff --git a/src/device_vendors.h b/src/device_vendors.h
new file mode 100644 (file)
index 0000000..476198b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DEVICE_VENDORS_H
+#define __DEVICE_VENDORS_H
+
+#define VENDOR_COUNT_MAX         64
+
+typedef struct
+{
+  const char *vendor;
+  int id;
+} VENDOR;
+
+VENDOR tizen_device_vendors[VENDOR_COUNT_MAX];
+
+unsigned  vendor_total_cnt;
+
+void init_device_vendors(void);
+
+#endif
old mode 100644 (file)
new mode 100755 (executable)
index 32dd05f..826cb8f
 #include "fdevent_backend.h"
 #include "transport.h"
 #include "utils.h"
+#include "fdevent.h"
+#include "log.h"
 
-#if defined(OS_LINUX)
-const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend;
-#elif defined(OS_DARWIN)
+#ifndef OS_WINDOWS
+int max_select = 0;
 const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend;
-#elif defined(OS_WINDOWS)
-const struct fdevent_os_backend* fdevent_backend = &fdevent_windows_backend;
-#define  WIN32_FH_BASE    100
 #else
-#error "unsupported OS"
+const struct fdevent_os_backend* fdevent_backend = &fdevent_windows_backend;
 #endif
 
-fdevent list_pending = {
-    .next = &list_pending,
-    .prev = &list_pending,
-};
+#define TRACE_TAG TRACE_SDB
 
-fdevent **fd_table = 0;
-int fd_table_max = 0;
-
-void _fatal(const char *fn, const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "%s:", fn);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-    abort();
-}
+MAP event_map;
 
-void fdevent_register(fdevent *fde)
-{
 #if defined(OS_WINDOWS)
-    int  fd = fde->fd - WIN32_FH_BASE;
-#else
-    int  fd = fde->fd;
+MAP sdb_handle_map;
+HANDLE socket_event_handle[WIN32_MAX_FHS];
+int event_location_to_fd[WIN32_MAX_FHS];
+int current_socket_location = 0;
 #endif
 
+void fdevent_register(FD_EVENT *fde)
+{
+       int fd = fde->fd;
+
     if(fd < 0) {
-        FATAL("bogus negative fd (%d)\n", fde->fd);
+        LOG_FATAL("bogus negative fd (%d)\n", fd);
     }
 
-    if(fd >= fd_table_max) {
-        int oldmax = fd_table_max;
-        if(fde->fd > 32000) {
-            FATAL("bogus huuuuge fd (%d)\n", fde->fd);
-        }
-        if(fd_table_max == 0) {
-            fdevent_backend->fdevent_init();
-            fd_table_max = 256;
-        }
-        while(fd_table_max <= fd) {
-            fd_table_max *= 2;
-        }
-        fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
-        if(fd_table == 0) {
-            FATAL("could not expand fd_table to %d entries\n", fd_table_max);
-        }
-        memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
+    if(fd > 32000) {
+        LOG_FATAL("bogus huuuuge FD(%d)\n", fd);
+    }
+    else {
+       fdevent_map_put(fd, fde);
     }
-
-    fd_table[fd] = fde;
 }
 
-void fdevent_unregister(fdevent *fde)
+void fdevent_unregister(FD_EVENT *fde)
 {
-#if defined(OS_WINDOWS)
-    int  fd = fde->fd - WIN32_FH_BASE;
-#else
-    int  fd = fde->fd;
-#endif
-    if((fd < 0) || (fd >= fd_table_max)) {
-        FATAL("fd out of range (%d)\n", fde->fd);
-    }
+    int fd = fde->fd;
 
-    if(fd_table[fd] != fde) {
-        FATAL("fd_table out of sync");
+    if((fd < 0)) {
+        LOG_FATAL("fdevent out of range FD(%d)\n", fd);
     }
-
-    fd_table[fd] = 0;
-
-    if(!(fde->state & FDE_DONT_CLOSE)) {
-        dump_fde(fde, "close");
-        sdb_close(fde->fd);
+    else if(fdevent_map_get(fd) != fde) {
+        LOG_FATAL("fd event out of sync");
     }
-}
-
-void fdevent_plist_enqueue(fdevent *node)
-{
-    fdevent *list = &list_pending;
-
-    node->next = list;
-    node->prev = list->prev;
-    node->prev->next = node;
-    list->prev = node;
-}
-
-void fdevent_plist_remove(fdevent *node)
-{
-    node->prev->next = node->next;
-    node->next->prev = node->prev;
-    node->next = 0;
-    node->prev = 0;
-}
-
-fdevent *fdevent_plist_dequeue(void)
-{
-    fdevent *list = &list_pending;
-    fdevent *node = list->next;
-
-    if(node == list) return 0;
-
-    list->next = node->next;
-    list->next->prev = list;
-    node->next = 0;
-    node->prev = 0;
-
-    return node;
-}
-
-fdevent *fdevent_create(int fd, fd_func func, void *arg)
-{
-    fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
-    if(fde == 0) return 0;
-    fdevent_install(fde, fd, func, arg);
-    fde->state |= FDE_CREATED;
-    return fde;
-}
-
-void fdevent_destroy(fdevent *fde)
-{
-    if(fde == 0) return;
-    if(!(fde->state & FDE_CREATED)) {
-        FATAL("fde %p not created by fdevent_create()\n", fde);
+    else {
+        fdevent_map_remove(fd);
+        sdb_close(fde->fd);
     }
-    fdevent_remove(fde);
 }
 
-void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
+void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg)
 {
-    memset(fde, 0, sizeof(fdevent));
-    fde->state = FDE_ACTIVE;
+    D("FD(%d)\n", fd);
+    memset(fde, 0, sizeof(FD_EVENT));
     fde->fd = fd;
-    fde->force_eof = 0;
     fde->func = func;
     fde->arg = arg;
+    fde->events = 0;
 
 #ifndef OS_WINDOWS
     fcntl(fd, F_SETFL, O_NONBLOCK);
+    if(fd >= max_select) {
+        max_select = fd + 1;
+    }
 #endif
     fdevent_register(fde);
-    dump_fde(fde, "connect");
-    fdevent_backend->fdevent_connect(fde);
-    fde->state |= FDE_ACTIVE;
 }
 
-void fdevent_remove(fdevent *fde)
+void fdevent_remove(FD_EVENT *fde)
 {
-    if(fde->state & FDE_PENDING) {
-        fdevent_plist_remove(fde);
-    }
-
-    if(fde->state & FDE_ACTIVE) {
-        fdevent_backend->fdevent_disconnect(fde);
-        dump_fde(fde, "disconnect");
-        fdevent_unregister(fde);
-    }
-
-    fde->state = 0;
+    fdevent_backend->fdevent_disconnect(fde);
+    fdevent_unregister(fde);
     fde->events = 0;
 }
 
-
-void fdevent_set(fdevent *fde, unsigned events)
-{
-    events &= FDE_EVENTMASK;
-
-    if((fde->state & FDE_EVENTMASK) == events) return;
-
-    if(fde->state & FDE_ACTIVE) {
-        fdevent_backend->fdevent_update(fde, events);
-        dump_fde(fde, "update");
-    }
-
-    fde->state = (fde->state & FDE_STATEMASK) | events;
-
-    if(fde->state & FDE_PENDING) {
-            /* if we're pending, make sure
-            ** we don't signal an event that
-            ** is no longer wanted.
-            */
-        fde->events &= (~events);
-        if(fde->events == 0) {
-            fdevent_plist_remove(fde);
-            fde->state &= (~FDE_PENDING);
-        }
-    }
-}
-
-void fdevent_add(fdevent *fde, unsigned events) {
-    fdevent_set(fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
+FD_EVENT* fdevent_map_get(int _key) {
+       MAP_KEY key;
+       key.key_int = _key;
+       return map_get(&event_map, key);
 }
 
-void fdevent_del(fdevent *fde, unsigned events) {
-    fdevent_set(fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
+void fdevent_map_put(int _key, FD_EVENT* _value) {
+       MAP_KEY key;
+       key.key_int = _key;
+       map_put(&event_map, key, _value);
 }
 
-void fdevent_loop()
-{
-    fdevent_backend->fdevent_loop();
+void fdevent_map_remove(int _key) {
+       MAP_KEY key;
+       key.key_int = _key;
+       map_remove(&event_map, key);
 }
old mode 100644 (file)
new mode 100755 (executable)
index 6bb2d4b..2e876be
 #define __FDEVENT_H
 
 #include <stdint.h>  /* for int64_t */
+#include "linkedlist.h"
+#include "sdb_map.h"
 
 /* events that may be observed */
-#define FDE_READ              0x0001
-#define FDE_WRITE             0x0002
-#define FDE_ERROR             0x0004
-#define FDE_TIMEOUT           0x0008
+#define FDE_READ              1
+#define FDE_WRITE             2
 
+#define FDE_MASK              3
 
-#define FDE_EVENTMASK  0x00ff
-#define FDE_STATEMASK  0xff00
-
-#define FDE_ACTIVE     0x0100
-#define FDE_PENDING    0x0200
-#define FDE_CREATED    0x0400
+typedef struct fd_event FD_EVENT;
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
 
-/* features that may be set (via the events set/add/del interface) */
-#define FDE_DONT_CLOSE        0x0080
+struct fd_event
+{
+    LIST_NODE* node;
 
-typedef struct fdevent fdevent;
+    int fd;
+    unsigned events;
 
-typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+    fd_func func;
+    void *arg;
+};
 
-/* Allocate and initialize a new fdevent object
- * Note: use FD_TIMER as 'fd' to create a fd-less object
- * (used to implement timers).
-*/
-fdevent *fdevent_create(int fd, fd_func func, void *arg);
+int fdevent_wakeup_send;
+int fdevent_wakeup_recv;
 
-/* Uninitialize and deallocate an fdevent object that was
-** created by fdevent_create()
-*/
-void fdevent_destroy(fdevent *fde);
+FD_EVENT fdevent_wakeup_fde;
 
 /* Initialize an fdevent object that was externally allocated
 */
-void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
+void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg);
 
 /* Uninitialize an fdevent object that was initialized by
 ** fdevent_install()
 */
-void fdevent_remove(fdevent *item);
+void fdevent_remove(FD_EVENT *item);
 
-/* Change which events should cause notifications
-*/
-void fdevent_set(fdevent *fde, unsigned events);
-void fdevent_add(fdevent *fde, unsigned events);
-void fdevent_del(fdevent *fde, unsigned events);
+#define EVENT_MAP_SIZE 256
 
-void fdevent_set_timeout(fdevent *fde, int64_t  timeout_ms);
+extern MAP event_map;
 
-/* loop forever, handling events.
+FD_EVENT* fdevent_map_get(int key);
+void fdevent_map_put(int key, FD_EVENT* value);
+void fdevent_map_remove(int key);
+
+/* Change which events should cause notifications
 */
-void fdevent_loop();
 
-struct fdevent 
-{
-    fdevent *next;
-    fdevent *prev;
+#define FDEVENT_SET(fde, events)    \
+        fdevent_backend->fdevent_update(fde, events)
 
-    int fd;
-    int force_eof;
+#define FDEVENT_ADD(fde, _events)    \
+        fdevent_backend->fdevent_update(fde, (fde)->events | _events)
 
-    unsigned short state;
-    unsigned short events;
+#define FDEVENT_DEL(fde, _events)    \
+        fdevent_backend->fdevent_update(fde, (fde)->events & ~_events)
 
-    fd_func func;
-    void *arg;
+#define FDEVENT_LOOP()  \
+        fdevent_backend->fdevent_loop()
+
+struct fdevent_os_backend {
+    void (*fdevent_loop)(void);
+    void (*fdevent_disconnect)(FD_EVENT *fde);
+    void (*fdevent_update)(FD_EVENT *fde, unsigned events);
 };
 
+extern const struct fdevent_os_backend* fdevent_backend;
+#ifndef OS_WINDOWS
+extern int max_select;
+extern const struct fdevent_os_backend fdevent_unix_backend;
+#else
+extern const struct fdevent_os_backend fdevent_windows_backend;
+#endif
+
+#if defined(OS_WINDOWS)
+#include <windows.h>
+
+#define  WIN32_MAX_FHS    128
+extern MAP sdb_handle_map;
+extern HANDLE socket_event_handle[];
+extern int event_location_to_fd[];
+extern int current_socket_location;
+#endif
 
 #endif
old mode 100644 (file)
new mode 100755 (executable)
index 3213f58..851243b
 #define __FDEVENT_I_H
 
 #include "fdevent.h"
-
-extern fdevent list_pending;
-extern fdevent **fd_table;
+extern FD_EVENT **fd_table;
 extern int fd_table_max;
 
-void fdevent_plist_enqueue(fdevent *node);
-void fdevent_plist_remove(fdevent *node);
-fdevent *fdevent_plist_dequeue(void);
-void fdevent_register(fdevent *fde);
-void fdevent_unregister(fdevent *fde);
-
-void _fatal(const char *fn, const char *fmt, ...);
-#define FATAL(x...) _fatal(__FUNCTION__, x)
-
-#if DEBUG
-void dump_fde(fdevent *fde, const char *info)
-{
-    fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
-            fde->state & FDE_READ ? 'R' : ' ',
-            fde->state & FDE_WRITE ? 'W' : ' ',
-            fde->state & FDE_ERROR ? 'E' : ' ',
-            info);
-}
-#else
-#define dump_fde(fde, info) do { } while(0)
-#endif
-
-struct fdevent_os_backend {
-    // human-readable name
-    const char *name;
-    void (*fdevent_loop)(void);
-    void (*fdevent_init)(void);
-    void (*fdevent_connect)(fdevent *fde);
-    void (*fdevent_disconnect)(fdevent *fde);
-    void (*fdevent_update)(fdevent *fde, unsigned events);
-};
-
-extern const struct fdevent_os_backend* fdevent_backend;
-extern const struct fdevent_os_backend fdevent_unix_backend;
-extern const struct fdevent_os_backend fdevent_windows_backend;
+FD_EVENT *fdevent_plist_dequeue(void);
+void fdevent_register(FD_EVENT *fde);
+void fdevent_unregister(FD_EVENT *fde);
 
 #endif
old mode 100644 (file)
new mode 100755 (executable)
index d5b6807..01f5baa
@@ -30,8 +30,8 @@
 #include "fdevent_backend.h"
 #include "transport.h"
 #include "utils.h"
+#include "log.h"
 
-#define D(...) ((void)0)
 // This socket is used when a subproc shell service exists.
 // It wakes up the fdevent_loop() and cause the correct handling
 // of the shell's pseudo-tty master. I.e. force close it.
@@ -39,293 +39,112 @@ int SHELL_EXIT_NOTIFY_FD = -1;
 
 #include <sys/select.h>
 
+#define FD_CLR_ALL(fde) \
+        FD_CLR(fde->fd, &fds_read); \
+        FD_CLR(fde->fd, &fds_write);
 
-static fd_set read_fds;
-static fd_set write_fds;
-static fd_set error_fds;
+static fd_set fds_write;
+static fd_set fds_read;
 
-static int select_n = 0;
-
-static void _fdevent_init(void)
-{
-    FD_ZERO(&read_fds);
-    FD_ZERO(&write_fds);
-    FD_ZERO(&error_fds);
-}
-
-static void _fdevent_connect(fdevent *fde)
-{
-    if(fde->fd >= select_n) {
-        select_n = fde->fd + 1;
-    }
-}
-
-static void _fdevent_disconnect(fdevent *fde)
-{
-    int i, n;
-
-    FD_CLR(fde->fd, &read_fds);
-    FD_CLR(fde->fd, &write_fds);
-    FD_CLR(fde->fd, &error_fds);
-
-    for(n = 0, i = 0; i < select_n; i++) {
-        if(fd_table[i] != 0) n = i;
-    }
-    select_n = n + 1;
-}
-
-static void _fdevent_update(fdevent *fde, unsigned events)
+static void _fdevent_disconnect(FD_EVENT *fde)
 {
-    if(events & FDE_READ) {
-        FD_SET(fde->fd, &read_fds);
-    } else {
-        FD_CLR(fde->fd, &read_fds);
-    }
-    if(events & FDE_WRITE) {
-        FD_SET(fde->fd, &write_fds);
-    } else {
-        FD_CLR(fde->fd, &write_fds);
-    }
-    if(events & FDE_ERROR) {
-        FD_SET(fde->fd, &error_fds);
-    } else {
-        FD_CLR(fde->fd, &error_fds);
-    }
-
-    fde->state = (fde->state & FDE_STATEMASK) | events;
-}
-
-/* Looks at fd_table[] for bad FDs and sets bit in fds.
-** Returns the number of bad FDs.
-*/
-static int fdevent_fd_check(fd_set *fds)
-{
-    int i, n = 0;
-    fdevent *fde;
-
-    for(i = 0; i < select_n; i++) {
-        fde = fd_table[i];
-        if(fde == 0) continue;
-        if(fcntl(i, F_GETFL, NULL) < 0) {
-            FD_SET(i, fds);
-            n++;
-            // fde->state |= FDE_DONT_CLOSE;
-
+    FD_CLR_ALL(fde);
+    //selectn should be reset
+    int fd = fde->fd;
+    if(fd  >= max_select -1) {
+        int i = fd - 1;
+        while(i > -1) {
+            if(fdevent_map_get(i) !=  NULL) {
+                max_select = i+1;
+                break;
+            }
+            --i;
         }
     }
-    return n;
 }
 
-#if !DEBUG
-static inline void dump_all_fds(const char *extra_msg) {}
-#else
-static void dump_all_fds(const char *extra_msg)
+static void _fdevent_update(FD_EVENT *fde, unsigned events)
 {
-int i;
-    fdevent *fde;
-    // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
-    char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
-    size_t max_chars = FD_SETSIZE * 6 + 1;
-    int printed_out;
-#define SAFE_SPRINTF(...)                                                    \
-    do {                                                                     \
-        printed_out = snprintf(pb, max_chars, __VA_ARGS__);                  \
-        if (printed_out <= 0) {                                              \
-            D("... snprintf failed.\n");                                     \
-            return;                                                          \
-        }                                                                    \
-        if (max_chars < (unsigned int)printed_out) {                         \
-            D("... snprintf out of space.\n");                               \
-            return;                                                          \
-        }                                                                    \
-        pb += printed_out;                                                   \
-        max_chars -= printed_out;                                            \
-    } while(0)
-
-    for(i = 0; i < select_n; i++) {
-        fde = fd_table[i];
-        SAFE_SPRINTF("%d", i);
-        if(fde == 0) {
-            SAFE_SPRINTF("? ");
-            continue;
-        }
-        if(fcntl(i, F_GETFL, NULL) < 0) {
-            SAFE_SPRINTF("b");
-        }
-        SAFE_SPRINTF(" ");
+    if(fde->events == events) {
+        return;
     }
-    D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
-}
-#endif
 
-static int _fdevent_process()
-{
-    int i, n;
-    fdevent *fde;
-    unsigned events;
-    fd_set rfd, wfd, efd;
+    int fd = fde->fd;
+    events = events & FDE_MASK;
+    fde->events = events;
 
-    memcpy(&rfd, &read_fds, sizeof(fd_set));
-    memcpy(&wfd, &write_fds, sizeof(fd_set));
-    memcpy(&efd, &error_fds, sizeof(fd_set));
-
-    dump_all_fds("pre select()");
-
-    n = select(select_n, &rfd, &wfd, &efd, NULL);
-    int saved_errno = errno;
-    D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
-
-    dump_all_fds("post select()");
-
-    if(n < 0) {
-        switch(saved_errno) {
-        case EINTR: return -1;
-        case EBADF:
-            // Can't trust the FD sets after an error.
-            FD_ZERO(&wfd);
-            FD_ZERO(&efd);
-            FD_ZERO(&rfd);
+    switch (events ) {
+        case FDE_READ:
+            FD_SET(fd, &fds_read);
+            FD_CLR(fd, &fds_write);
+            break;
+        case FDE_WRITE:
+            FD_SET(fd, &fds_write);
+            FD_CLR(fd, &fds_read);
+            break;
+        case 0:
+            FD_CLR(fd, &fds_read);
+            FD_CLR(fd, &fds_write);
             break;
         default:
-            D("Unexpected select() error=%d\n", saved_errno);
-            return 0;
-        }
-    }
-    if(n <= 0) {
-        // We fake a read, as the rest of the code assumes
-        // that errors will be detected at that point.
-        n = fdevent_fd_check(&rfd);
-    }
-
-    for(i = 0; (i < select_n) && (n > 0); i++) {
-        events = 0;
-        if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
-        if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
-        if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
-
-        if(events) {
-            fde = fd_table[i];
-            if(fde == 0)
-              FATAL("missing fde for fd %d\n", i);
-
-            fde->events |= events;
-
-            D("got events fde->fd=%d events=%04x, state=%04x\n",
-                fde->fd, fde->events, fde->state);
-            if(fde->state & FDE_PENDING) continue;
-            fde->state |= FDE_PENDING;
-            fdevent_plist_enqueue(fde);
-        }
-    }
-
-    return 0;
-}
-
-static void fdevent_call_fdfunc(fdevent* fde)
-{
-    unsigned events = fde->events;
-    fde->events = 0;
-    if(!(fde->state & FDE_PENDING)) return;
-    fde->state &= (~FDE_PENDING);
-    dump_fde(fde, "callback");
-    fde->func(fde->fd, events, fde->arg);
-}
-
-static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
-{
-
-    D("subproc handling on fd=%d ev=%04x\n", fd, ev);
-
-    // Hook oneself back into the fde's suitable for select() on read.
-    if((fd < 0) || (fd >= fd_table_max)) {
-        FATAL("fd %d out of range for fd_table \n", fd);
-    }
-    fdevent *fde = fd_table[fd];
-    fdevent_add(fde, FDE_READ);
-
-    if(ev & FDE_READ){
-      int subproc_fd;
-
-      if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
-          FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
-      }
-      if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
-          D("subproc_fd %d out of range 0, fd_table_max=%d\n",
-            subproc_fd, fd_table_max);
-          return;
-      }
-      fdevent *subproc_fde = fd_table[subproc_fd];
-      if(!subproc_fde) {
-          D("subproc_fd %d cleared from fd_table\n", subproc_fd);
-          return;
-      }
-      if(subproc_fde->fd != subproc_fd) {
-          // Already reallocated?
-          D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
-          return;
-      }
-
-      subproc_fde->force_eof = 1;
-
-      int rcount = 0;
-      ioctl(subproc_fd, FIONREAD, &rcount);
-      D("subproc with fd=%d  has rcount=%d err=%d\n",
-        subproc_fd, rcount, errno);
-
-      if(rcount) {
-        // If there is data left, it will show up in the select().
-        // This works because there is no other thread reading that
-        // data when in this fd_func().
-        return;
-      }
-
-      D("subproc_fde.state=%04x\n", subproc_fde->state);
-      subproc_fde->events |= FDE_READ;
-      if(subproc_fde->state & FDE_PENDING) {
-        return;
-      }
-      subproc_fde->state |= FDE_PENDING;
-      fdevent_call_fdfunc(subproc_fde);
-    }
-}
-
-static void fdevent_subproc_setup()
-{
-    int s[2];
-
-    if(sdb_socketpair(s)) {
-        FATAL("cannot create shell-exit socket-pair\n");
+            FD_SET(fd, &fds_read);
+            FD_SET(fd, &fds_write);
+            break;
     }
-    SHELL_EXIT_NOTIFY_FD = s[0];
-    fdevent *fde;
-    fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
-    if(!fde)
-      FATAL("cannot create fdevent for shell-exit handler\n");
-    fdevent_add(fde, FDE_READ);
 }
 
 static void _fdevent_loop()
 {
-    fdevent *fde;
-    fdevent_subproc_setup();
+    while(1) {
+        fd_set rfd, wfd;
 
-    for(;;) {
-        D("--- ---- waiting for events\n");
+        memcpy(&rfd, &fds_read, sizeof(fd_set));
+        memcpy(&wfd, &fds_write, sizeof(fd_set));
 
-        if (_fdevent_process() < 0) {
-            return;
+        LOG_INFO("before select function, max_select %d\n", max_select);
+        int n = select(max_select, &rfd, &wfd, NULL, NULL);
+        LOG_INFO("%d events happens\n", n);
+
+        if(n < 0) {
+            LOG_ERROR("fatal error happens in select loop errno %d, strerr %s\n", errno, strerror(errno));
+            FD_ZERO(&wfd);
+            FD_ZERO(&rfd);
+            continue;
+        }
+        if(n == 0) {
+            LOG_ERROR("select returns 0\n");
+            continue;
         }
 
-        while((fde = fdevent_plist_dequeue())) {
-            fdevent_call_fdfunc(fde);
+        int i = 0;
+        while( i < max_select) {
+            unsigned events = 0;
+
+            if(FD_ISSET(i, &rfd)) {
+                events |= FDE_READ;
+            }
+            if(FD_ISSET(i, &wfd)) {
+                events |= FDE_WRITE;
+            }
+
+            if(events) {
+                LOG_INFO("FD(%d) got events=%04x\n", i, events);
+                FD_EVENT* fde = fdevent_map_get(i);
+                if(fde == NULL) {
+                    LOG_INFO("fdevent FD(%d) may be already closed\n", i);
+                    i++;
+                    continue;
+                }
+                events |= fde->events;
+                fde->func(fde->fd, events, fde->arg);
+                LOG_INFO("FD(%d) finished\n");
+            }
+            i++;
         }
     }
 }
 
 const struct fdevent_os_backend fdevent_unix_backend = {
-    .name = "unix fdevent",
-    .fdevent_init = _fdevent_init,
-    .fdevent_connect = _fdevent_connect,
     .fdevent_disconnect = _fdevent_disconnect,
     .fdevent_update = _fdevent_update,
     .fdevent_loop = _fdevent_loop
old mode 100644 (file)
new mode 100755 (executable)
index 5f750a4..60ee720
 #include "utils_backend.h"
 #include "fdevent_backend.h"
 #include "transport.h"
+#include "log.h"
 
-#define D(...) ((void)0)
+static void alloc_event(SDB_SOCK_HANDLE* h) {
+       LOG_INFO("FD(%d), LOCATION(%d)\n", h->handle.fd, current_socket_location);
+    HANDLE event = WSACreateEvent();
+    socket_event_handle[current_socket_location] = event;
+    event_location_to_fd[current_socket_location] = h->handle.fd;
 
-static EventHook  _free_hooks;
-
-static EventHook
-event_hook_alloc( FH  fh )
-{
-    EventHook  hook = _free_hooks;
-    if (hook != NULL)
-        _free_hooks = hook->next;
-    else {
-        hook = malloc( sizeof(*hook) );
-        if (hook == NULL) {
-            //_fatal( "could not allocate event hook\n" );
-            //TODO:
-        }
-    }
-    hook->next   = NULL;
-    hook->fh     = fh;
-    hook->wanted = 0;
-    hook->ready  = 0;
-    hook->h      = INVALID_HANDLE_VALUE;
-    hook->aux    = NULL;
-
-    hook->prepare = NULL;
-    hook->start   = NULL;
-    hook->stop    = NULL;
-    hook->check   = NULL;
-    hook->peek    = NULL;
-
-    return hook;
+    h->event_location = current_socket_location;
+    current_socket_location++;
 }
 
-static void
-event_hook_free( EventHook  hook )
-{
-    hook->fh     = NULL;
-    hook->wanted = 0;
-    hook->ready  = 0;
-    hook->next   = _free_hooks;
-    _free_hooks  = hook;
+static void free_event(SDB_SOCK_HANDLE* remove_h) {
+
+       LOG_INFO("FD(%d), LOCATION(%d), CUR_SOCKET(%d)\n", remove_h->handle.fd, remove_h->event_location, current_socket_location);
+
+       current_socket_location--;
+       int remove_location = remove_h->event_location;
+       remove_h->event_location = -1;
+       WSACloseEvent(socket_event_handle[remove_location]);
+       if(current_socket_location != remove_location) {
+               SDB_SOCK_HANDLE* replace_h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(event_location_to_fd[current_socket_location]);
+               replace_h->event_location = remove_location;
+               socket_event_handle[remove_location] = socket_event_handle[current_socket_location];
+               int replace_fd = event_location_to_fd[current_socket_location];
+               event_location_to_fd[remove_location] = replace_fd;
+       }
 }
 
-
-static void
-event_hook_signal( EventHook  hook )
-{
-    FH        f   = hook->fh;
-    int       fd  = _fh_to_int(f);
-    fdevent*  fde = fd_table[ fd - WIN32_FH_BASE ];
-
-    if (fde != NULL && fde->fd == fd) {
-        if ((fde->state & FDE_PENDING) == 0) {
-            fde->state |= FDE_PENDING;
-            fdevent_plist_enqueue( fde );
-        }
-        fde->events |= hook->wanted;
+static int _event_socket_verify(FD_EVENT* fde, WSANETWORKEVENTS* evts) {
+    if ((fde->events & FDE_READ) && (evts->lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))) {
+               return 1;
     }
-}
-
-static EventHook*
-event_looper_find_p( EventLooper  looper, FH  fh )
-{
-    EventHook  *pnode = &looper->hooks;
-    EventHook   node  = *pnode;
-    for (;;) {
-        if ( node == NULL || node->fh == fh )
-            break;
-        pnode = &node->next;
-        node  = *pnode;
+    if ((fde->events & FDE_WRITE) && (evts->lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE))) {
+               return 1;
     }
-    return  pnode;
+    return 0;
 }
 
-static void
-event_looper_hook( EventLooper  looper, int  fd, int  events )
-{
-    FH          f = _fh_from_int(fd);
-    EventHook  *pnode;
-    EventHook   node;
+static int _socket_wanted_to_flags(int wanted) {
+    int flags = 0;
+    if (wanted & FDE_READ)
+        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
 
-    if (f == NULL)  /* invalid arg */ {
-        D("event_looper_hook: invalid fd=%d\n", fd);
-        return;
-    }
+    if (wanted & FDE_WRITE)
+        flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
 
-    pnode = event_looper_find_p( looper, f );
-    node  = *pnode;
-    if ( node == NULL ) {
-        node       = event_hook_alloc( f );
-        node->next = *pnode;
-        *pnode     = node;
-    }
-
-    if ( (node->wanted & events) != events ) {
-        /* this should update start/stop/check/peek */
-        D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
-           fd, node->wanted, events);
-        f->clazz->_fh_hook( f, events & ~node->wanted, node );
-        node->wanted |= events;
-    } else {
-        D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
-           events, fd, node->wanted);
-    }
+    return flags;
 }
 
-static void
-event_looper_unhook( EventLooper  looper, int  fd, int  events )
-{
-    FH          fh    = _fh_from_int(fd);
-    EventHook  *pnode = event_looper_find_p( looper, fh );
-    EventHook   node  = *pnode;
-
-    if (node != NULL) {
-        int  events2 = events & node->wanted;
-        if ( events2 == 0 ) {
-            D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
-            return;
-        }
-        node->wanted &= ~events2;
-        if (!node->wanted) {
-            *pnode = node->next;
-            event_hook_free( node );
-        }
+static int _event_socket_start(FD_EVENT* fde) {
+    /* create an event which we're going to wait for */
+       int fd = fde->fd;
+    long flags = _socket_wanted_to_flags(fde->events);
+    SDB_SOCK_HANDLE* __h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fd);
+       LOG_INFO("FD(%d) LOCATION(%d)\n", fd, __h->event_location);
+    HANDLE event = socket_event_handle[__h->event_location];
+
+    if (event == INVALID_HANDLE_VALUE) {
+        LOG_ERROR( "no event for FD(%d)\n", fd);
+        return 0;
     }
+       D( "_event_socket_start: hooking FD(%d) for %x (flags %ld)\n", fd, fde->events, flags);
+       if (WSAEventSelect(__h->handle.u.socket, event, flags)) {
+               LOG_ERROR( "_event_socket_start: WSAEventSelect() for FD(%d) failed, error %d\n", fd, WSAGetLastError());
+               exit(1);
+               return 0;
+       }
+    return 1;
 }
 
-static EventLooperRec  win32_looper;
-
-static void _fdevent_init(void)
-{
-    win32_looper.htab_count = 0;
-    win32_looper.hooks      = NULL;
-}
-
-static void _fdevent_connect(fdevent *fde)
+static void _fdevent_disconnect(FD_EVENT *fde)
 {
-    EventLooper  looper = &win32_looper;
-    int          events = fde->state & FDE_EVENTMASK;
-
-    if (events != 0)
-        event_looper_hook( looper, fde->fd, events );
-}
-
-static void _fdevent_disconnect(fdevent *fde)
-{
-    EventLooper  looper = &win32_looper;
-    int          events = fde->state & FDE_EVENTMASK;
-
-    if (events != 0)
-        event_looper_unhook( looper, fde->fd, events );
+    int events = fde->events;
+
+    if (events) {
+       SDB_SOCK_HANDLE* h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd);
+       if(h == NULL) {
+               LOG_ERROR("FDE of FD(%d) has no socket event handle\n", fde->fd);
+               return;
+       }
+       free_event(h);
+    }
 }
 
-static void _fdevent_update(fdevent *fde, unsigned events)
+static void _fdevent_update(FD_EVENT *fde, unsigned events)
 {
-    EventLooper  looper  = &win32_looper;
-    unsigned     events0 = fde->state & FDE_EVENTMASK;
-
-    if (events != events0) {
-        int  removes = events0 & ~events;
-        int  adds    = events  & ~events0;
-        if (removes) {
-            D("fdevent_update: remove %x from %d\n", removes, fde->fd);
-            event_looper_unhook( looper, fde->fd, removes );
-        }
-        if (adds) {
-            D("fdevent_update: add %x to %d\n", adds, fde->fd);
-            event_looper_hook  ( looper, fde->fd, adds );
-        }
+    if(fde->events == events) {
+        return;
     }
+
+       fde->events = events;
+       SDB_SOCK_HANDLE* h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd);
+       if(h == NULL) {
+               LOG_ERROR("invalid FD(%d)\n", fde->fd);
+               return;
+       }
+
+       if(h->event_location == -1) {
+               alloc_event(h);
+       }
+       _event_socket_start(fde);
 }
 
-static void fdevent_process()
+void _fdevent_loop()
 {
-    EventLooper  looper = &win32_looper;
-    EventHook    hook;
-    int          gotone = 0;
-
-    /* if we have at least one ready hook, execute it/them */
-    for (hook = looper->hooks; hook; hook = hook->next) {
-        hook->ready = 0;
-        if (hook->prepare) {
-            hook->prepare(hook);
-            if (hook->ready != 0) {
-                event_hook_signal( hook );
-                gotone = 1;
-            }
-        }
-    }
-
-    /* nothing's ready yet, so wait for something to happen */
-    if (!gotone)
+    do
     {
-        looper->htab_count = 0;
-
-        for (hook = looper->hooks; hook; hook = hook->next)
-        {
-            if (hook->start && !hook->start(hook)) {
-                D( "fdevent_process: error when starting a hook\n" );
-                return;
-            }
-            if (hook->h != INVALID_HANDLE_VALUE) {
-                int  nn;
-
-                for (nn = 0; nn < looper->htab_count; nn++)
-                {
-                    if ( looper->htab[nn] == hook->h )
-                        goto DontAdd;
-                }
-                looper->htab[ looper->htab_count++ ] = hook->h;
-            DontAdd:
-                ;
-            }
+               if (current_socket_location == 0) {
+                       D( "fdevent_process: nothing to wait for !!\n" );
+                       continue;
+               }
+        LOG_INFO( "sdb_win32: fdevevnt loop for %d events start\n", current_socket_location );
+        if (current_socket_location > MAXIMUM_WAIT_OBJECTS) {
+            LOG_ERROR("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", current_socket_location);
+            abort();
         }
+        int wait_ret = WaitForMultipleObjects( current_socket_location, socket_event_handle, FALSE, INFINITE );
 
-        if (looper->htab_count == 0) {
-            D( "fdevent_process: nothing to wait for !!\n" );
-            return;
+        if(wait_ret == (int)WAIT_FAILED) {
+            LOG_ERROR( "sdb_win32: wait failed, error %ld\n", GetLastError() );
+            continue;
         }
+        else {
 
-        do
-        {
-            int   wait_ret;
+               int _fd = event_location_to_fd[wait_ret];
+               LOG_INFO("wait success. FD(%d), LOCATION(%d)\n", _fd, wait_ret);
+               SDB_HANDLE* _h = sdb_handle_map_get(_fd);
+                       WSANETWORKEVENTS evts;
 
-            D( "sdb_win32: waiting for %d events\n", looper->htab_count );
-            if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
-                D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", looper->htab_count);
-                abort();
-            }
-            wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
-            if (wait_ret == (int)WAIT_FAILED) {
-                D( "sdb_win32: wait failed, error %ld\n", GetLastError() );
-            } else {
-                D( "sdb_win32: got one (index %d)\n", wait_ret );
+                       HANDLE event = socket_event_handle[wait_ret];
+                       if(!WSAEnumNetworkEvents(_h->u.socket, event, &evts)) {
+                               FD_EVENT*  fde = fdevent_map_get(_fd);
+                               if(_event_socket_verify(fde, &evts)) {
 
-                /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
-                 * like mouse movements. we need to filter these with the "check" function
-                 */
-                if ((unsigned)wait_ret < (unsigned)looper->htab_count)
-                {
-                    for (hook = looper->hooks; hook; hook = hook->next)
-                    {
-                        if ( looper->htab[wait_ret] == hook->h       &&
-                         (!hook->check || hook->check(hook)) )
-                        {
-                            D( "sdb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
-                            event_hook_signal( hook );
-                            gotone = 1;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        while (!gotone);
 
-        for (hook = looper->hooks; hook; hook = hook->next) {
-            if (hook->stop)
-                hook->stop( hook );
-        }
-    }
-
-    for (hook = looper->hooks; hook; hook = hook->next) {
-        if (hook->peek && hook->peek(hook))
-                event_hook_signal( hook );
-    }
-}
-
-void _fdevent_loop()
-{
-    fdevent *fde;
+                                       if (fde != NULL && fde->fd == _fd) {
+                                               LOG_INFO("FD(%d) start\n", fde->fd);
+                                               fde->func(fde->fd, fde->events, fde->arg);
+                                               LOG_INFO("FD(%d) end\n", fde->fd);
+                                       }
+                               }
+                               else {
+                                       LOG_INFO("verify failed\n");
+                               }
 
-    for(;;) {
-#if DEBUG
-        fprintf(stderr,"--- ---- waiting for events\n");
-#endif
-        fdevent_process();
 
-        while((fde = fdevent_plist_dequeue())) {
-            unsigned events = fde->events;
-            fde->events = 0;
-            fde->state &= (~FDE_PENDING);
-            dump_fde(fde, "callback");
-            fde->func(fde->fd, events, fde->arg);
+                       }
         }
     }
+    while (1);
 }
 
 
 const struct fdevent_os_backend fdevent_windows_backend = {
-    .name = "windows fdevent",
-    .fdevent_init = _fdevent_init,
-    .fdevent_connect = _fdevent_connect,
     .fdevent_disconnect = _fdevent_disconnect,
     .fdevent_update = _fdevent_update,
     .fdevent_loop = _fdevent_loop
index e2c9d8f49aa5909fd78f13cdb924c5d25ca11882..dcd199a34d6a59989b20404f5702737b0d0a75ae 100644 (file)
@@ -34,7 +34,7 @@
 #include "utils.h"
 #include "strutils.h"
 #include "fdevent.h"
-#include "sdb.h"
+#include "log.h"
 
 static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC* dstF);
 
@@ -49,36 +49,35 @@ static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC
     dstF->finalize(dstfd);
 }
 
-static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes) {
+static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes, struct stat* src_stat, char* copy_flag) {
     D("file is copied from 'fd:%d' '%s' to 'fd:%d' '%s'\n", src_fd, srcp, dst_fd, dstp);
-    void* srcstat;
-    if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) {
-        return -1;
-    }
 
-    src_fd = srcF->readopen(src_fd, srcp, srcstat);
+    unsigned file_byte = src_stat->st_size;
+    unsigned written_byte = 0;
+
+    src_fd = srcF->readopen(src_fd, srcp, src_stat);
     if(src_fd < 0) {
         return -1;
     }
 
-    dst_fd = dstF->writeopen(dst_fd, dstp, srcstat);
+    dst_fd = dstF->writeopen(dst_fd, dstp, src_stat);
     if(dst_fd < 0) {
         return -1;
     }
 
     FILE_BUFFER srcbuf;
-    srcbuf.id = ID_DATA;
+    srcbuf.id = sync_data;
 
     while(1) {
-        int ret = srcF->readfile(src_fd, srcp, srcstat, &srcbuf);
+        int ret = srcF->readfile(src_fd, srcp, src_stat, &srcbuf);
         if(ret == 0) {
             break;
         }
         else if(ret == 1) {
-            ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes);
+            ret = dstF->writefile(dst_fd, dstp, &srcbuf, &written_byte);
             if(ret < 0) {
                 srcF->readclose(src_fd);
-                dstF->writeclose(dst_fd, dstp, srcstat);
+                dstF->writeclose(dst_fd, dstp, src_stat);
                 return -1;
             }
         }
@@ -86,27 +85,31 @@ static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC*
             continue;
         }
         else if(ret == 3) {
-            ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes);
+            ret = dstF->writefile(dst_fd, dstp, &srcbuf, &written_byte);
             if(ret < 0) {
                 srcF->readclose(src_fd);
-                dstF->writeclose(dst_fd, dstp, srcstat);
+                dstF->writeclose(dst_fd, dstp, src_stat);
                 return -1;
             }
             break;
         }
         else {
             srcF->readclose(src_fd);
-            dstF->writeclose(dst_fd, dstp, srcstat);
+            dstF->writeclose(dst_fd, dstp, src_stat);
             if(ret == 4) {
                 return 0;
             }
             return -1;
         }
+        //TODO pull / push progress bar
+        //fprintf(stderr,"%s [%u / %u]: %s -> %s \r", copy_flag, written_byte, file_byte, srcp, dstp);
     }
-    if(srcF->readclose(src_fd) < 0 || dstF->writeclose(dst_fd, dstp, srcstat) < 0) {
+    if(srcF->readclose(src_fd) < 0 || dstF->writeclose(dst_fd, dstp, src_stat) < 0) {
         return -1;
     }
-    free(srcstat);
+
+    fprintf(stderr,"%s: %s -> %s \n", copy_flag, srcp, dstp);
+    *total_bytes = *total_bytes + written_byte;
     return 1;
 }
 
@@ -115,16 +118,27 @@ static void free_copyinfo(void* data) {
     if(info != NULL) {
         if(info->src != NULL) {
             free(info->src);
+            info->src = NULL;
         }
         if(info->dst != NULL) {
             free(info->dst);
+            info->dst = NULL;
         }
         free(info);
+        info = NULL;
     }
 }
 
 int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int is_utf8, void** ext_argv) {
 
+    char copy_flag[7];
+    if(srcF->local) {
+        snprintf(copy_flag, sizeof(copy_flag), "%s", "pushed");
+    }
+    else {
+        snprintf(copy_flag, sizeof(copy_flag), "%s", "pulled");
+    }
+
     D("copy %s to the %s\n", srcp, dstp);
     unsigned total_bytes = 0;
     long long start_time = NOW();
@@ -132,8 +146,6 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
     int src_fd = 0;
     int dst_fd = 0;
 
-    void* srcstat = NULL;
-    void* dststat = NULL;
     int pushed = 0;
     int skiped = 0;
     src_fd = srcF->initialize(srcp, ext_argv);
@@ -141,15 +153,19 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
     if(src_fd < 0 || dst_fd < 0) {
         return 1;
     }
-    if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) {
+
+    struct stat src_stat;
+    struct stat dst_stat;
+
+    if(srcF->_stat(src_fd, srcp, &src_stat, 1) < 0) {
         finalize(src_fd, dst_fd, srcF, dstF);
         return 1;
     }
-    int src_dir = srcF->is_dir(srcp, srcstat, 1);
+    int src_dir = srcF->is_dir(srcp, &src_stat, 1);
     int dst_dir = 0;
 
-    if(dstF->_stat(dst_fd, dstp, &dststat, 0) >= 0) {
-        dst_dir = dstF->is_dir(dstp, dststat, 0);
+    if(dstF->_stat(dst_fd, dstp, &dst_stat, 0) >= 0) {
+        dst_dir = dstF->is_dir(dstp, &dst_stat, 0);
     }
     else {
         int dst_len = strlen(dstp);
@@ -157,9 +173,9 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
             dst_dir = 1;
         }
     }
-    free(dststat);
-    free(srcstat);
+
     if(src_dir == -1 || dst_dir == -1) {
+        LOG_ERROR("src_dir: %d, dst_dir %d\n", src_dir, dst_dir);
         finalize(src_fd, dst_fd, srcF, dstF);
         return 1;
     }
@@ -167,9 +183,9 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
         /* if we're copying a local file to a remote directory,
         ** we *really* want to copy to remotedir + "/" + localfilename
         */
+        char full_dstpath[PATH_MAX];
         if(dst_dir == 1) {
             char* src_filename = get_filename(srcp);
-            char full_dstpath[PATH_MAX];
             append_file(full_dstpath, dstp, src_filename);
 
             if(is_utf8 != 0) {
@@ -179,12 +195,13 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
                 dstp = full_dstpath;
             }
         }
-        int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes);
+        int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes, &src_stat, copy_flag);
 
         if(result == 1) {
             pushed++;
         }
         else {
+            fprintf(stderr,"skipped: %s -> %s\n", srcp, dstp);
             skiped++;
         }
     }
@@ -221,13 +238,12 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
                 char* src_p = (char*)info->src;
                 char* dst_p = (char*)info->dst;
 
-                if(srcF->_stat(src_fd, src_p, &srcstat, 1) < 0) {
+                if(srcF->_stat(src_fd, src_p, &src_stat, 1) < 0) {
                     finalize(src_fd, dst_fd, srcF, dstF);
                     return 1;
                 }
 
-                src_dir = srcF->is_dir(src_p, srcstat, 1);
-                free(srcstat);
+                src_dir = srcF->is_dir(src_p, &src_stat, 1);
                 if(src_dir < 0) {
                     finalize(src_fd, dst_fd, srcF, dstF);
                     return 1;
@@ -237,13 +253,13 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
                 }
                 else {
                     if(src_dir == 0) {
-                        fprintf(stderr,"push: %s -> %s\n", src_p, dst_p);
-                        int result = file_copy(src_fd, dst_fd, src_p, dst_p, srcF, dstF, &total_bytes);
+                        int result = file_copy(src_fd, dst_fd, src_p, dst_p, srcF, dstF, &total_bytes, &src_stat, copy_flag);
 
                         if(result == 1) {
                             pushed++;
                         }
                         else {
+                            fprintf(stderr,"skipped: %s -> %s\n", src_p, dst_p);
                             skiped++;
                         }
                     }
@@ -261,14 +277,8 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i
         }
     }
 
-    if(srcF == &REMOTE_FILE_FUNC) {
-        fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n",
-                pushed, "pulled", skiped);
-    }
-    else {
-        fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n",
-                pushed, "pushed", skiped);
-    }
+    fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n",
+            pushed, copy_flag, skiped);
 
     long long end_time = NOW() - start_time;
 
index baceb3b8b20ed7d70ee266cafd08d03686191367..d4013e665ef44342cd6708879c20d3eec6e5febb 100644 (file)
 #include "linkedlist.h"
 #include "strutils.h"
 #include "file_sync_client.h"
+#include "log.h"
+
+const unsigned sync_stat = MKSYNC('S','T','A','T');
+const unsigned sync_list = MKSYNC('L','I','S','T');
+const unsigned sync_send = MKSYNC('S','E','N','D');
+const unsigned sync_recv = MKSYNC('R','E','C','V');
+const unsigned sync_dent = MKSYNC('D','E','N','T');
+const unsigned sync_done = MKSYNC('D','O','N','E');
+const unsigned sync_data = MKSYNC('D','A','T','A');
+const unsigned sync_okay = MKSYNC('O','K','A','Y');
+const unsigned sync_fail = MKSYNC('F','A','I','L');
+const unsigned sync_quit = MKSYNC('Q','U','I','T');
 
 const FILE_FUNC LOCAL_FILE_FUNC = {
+        1,
         initialize_local,
         finalize_local,
         _stat_local,
-        is_directory_local,
+        is_directory_common,
         readopen_local,
         readclose_local,
         writeopen_local,
@@ -50,10 +63,11 @@ const FILE_FUNC LOCAL_FILE_FUNC = {
 };
 
 const FILE_FUNC REMOTE_FILE_FUNC = {
+        0,
         initialize_remote,
         finalize_remote,
         _stat_remote,
-        is_directory_remote,
+        is_directory_common,
         readopen_remote,
         readclose_remote,
         writeopen_remote,
@@ -63,18 +77,18 @@ const FILE_FUNC REMOTE_FILE_FUNC = {
         getdirlist_remote,
 };
 
-static int sync_readmode(int fd, const char *path, unsigned *mode);
+static int sync_readstat(int fd, const char *path, struct stat* st);
 
 //return > 0 fd, = 0 success, < 0 fail.
 int initialize_local(char* path, void** extargv) {
-    D("initialize local file '%s'", path);
+    D("initialize local file '%s'\n", path);
     return 0;
 }
 
 //return fd
 int initialize_remote(char* path, void** extargv) {
 
-    D("initialize remote file '%s'", path);
+    D("initialize remote file '%s'\n", path);
     int fd = sdb_connect("sync:", extargv);
 
     if(fd < 0) {
@@ -86,14 +100,14 @@ int initialize_remote(char* path, void** extargv) {
 }
 
 void finalize_local(int fd) {
-    D("finalize local fd '%d'", fd);
+    D("finalize local fd '%d'\n", fd);
 }
 
 void finalize_remote(int fd) {
-    D("finalize remote fd '%d'", fd);
-    syncmsg msg;
+    D("finalize remote fd '%d'\n", fd);
+    SYNC_MSG msg;
 
-    msg.req.id = ID_QUIT;
+    msg.req.id = sync_quit;
     msg.req.namelen = 0;
 
     writex(fd, &msg.req, sizeof(msg.req));
@@ -103,40 +117,36 @@ void finalize_remote(int fd) {
     }
 }
 
-//TODO stat should be freed.
-int _stat_local(int fd, char* path, void** _stat, int show_error) {
-    D("stat local file 'fd:%d' '%s'", fd, path);
-    struct stat* st = (struct stat*)malloc(sizeof(struct stat));
+int _stat_local(int fd, char* path, struct stat* st, int show_error) {
+
+    D("stat local file 'fd:%d' '%s'\n", fd, path);
     if(stat(path, st)) {
         if(show_error) {
             fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
         }
+        st->st_mode = 0;
         return -1;
     }
 
-    *_stat = st;
     return 1;
 }
 
-int _stat_remote(int fd, char* path, void** stat, int show_error) {
+int _stat_remote(int fd, char* path, struct stat* st, int show_error) {
 
-    D("stat remote file 'fd:%d' '%s'", fd, path);
-    unsigned* mode = (unsigned*)malloc(sizeof(unsigned));
-    if(sync_readmode(fd, path, mode)) {
+    D("stat remote file 'fd:%d' '%s'\n", fd, path);
+    if(sync_readstat(fd, path, st)) {
         if(show_error) {
             fprintf(stderr,"cannot read mode '%s': %s\n", path, strerror(errno));
         }
+        st->st_mode = 0;
         return -1;
     }
 
-    *stat = mode;
     return 1;
 }
 
-int is_directory_local(char* path, void* stat, int show_error) {
-    struct stat* st = (struct stat*)stat;
-
-    if(st == NULL) {
+int is_directory_common(char* path, struct stat* st, int show_error) {
+    if(st->st_mode == 0) {
         if(show_error) {
             fprintf(stderr,"'%s': No such file or directory\n", path);
         }
@@ -153,29 +163,10 @@ int is_directory_local(char* path, void* stat, int show_error) {
     return 2;
 }
 
-int is_directory_remote(char* path, void* stat, int show_error) {
-    int* mode = (int*)stat;
-
-    if(mode == NULL) {
-        if(show_error) {
-            fprintf(stderr,"'%s': No such file or directory\n", path);
-        }
-        return -1;
-    }
-    if(S_ISREG(*mode) || S_ISLNK(*mode)) {
-        return 0;
-    }
-    if(S_ISDIR(*mode)) {
-        return 1;
-    }
-    return 2;
-}
-
 //return fd.
-int readopen_local(int fd, char* srcp, void* srcstat) {
+int readopen_local(int fd, char* srcp, struct stat* st) {
 
-    D("read open local file 'fd:%d' '%s'", fd, srcp);
-    struct stat* st = srcstat;
+    D("read open local file 'fd:%d' '%s'\n", fd, srcp);
     if(S_ISREG(st->st_mode)) {
         fd = sdb_open(srcp, O_RDONLY);
 
@@ -190,9 +181,9 @@ int readopen_local(int fd, char* srcp, void* srcstat) {
     return fd;
 }
 
-int readopen_remote(int fd, char* srcp, void* srcstat) {
-    D("read open remote file 'fd:%d' '%s'", fd, srcp);
-    syncmsg msg;
+int readopen_remote(int fd, char* srcp, struct stat* st) {
+    D("read open remote file 'fd:%d' '%s'\n", fd, srcp);
+    SYNC_MSG msg;
     int len;
 
     len = strlen(srcp);
@@ -201,7 +192,7 @@ int readopen_remote(int fd, char* srcp, void* srcstat) {
         return -1;
     }
 
-    msg.req.id = ID_RECV;
+    msg.req.id = sync_recv;
     msg.req.namelen = htoll(len);
 
     if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, srcp, len)) {
@@ -212,7 +203,7 @@ int readopen_remote(int fd, char* srcp, void* srcstat) {
 }
 
 int readclose_local(int lfd) {
-    D("read close local file 'fd:%d'", lfd);
+    D("read close local file 'fd:%d'\n", lfd);
     if(lfd > 0) {
         sdb_close(lfd);
     }
@@ -220,13 +211,13 @@ int readclose_local(int lfd) {
 }
 
 int readclose_remote(int fd) {
-    D("read close remote file 'fd:%d'", fd);
+    D("read close remote file 'fd:%d'\n", fd);
     return fd;
 }
 
-int writeopen_local(int fd, char* dstp, void* stat) {
-    D("write open local file 'fd:%d' '%s'", fd, dstp);
-    sdb_unlink(dstp);
+int writeopen_local(int fd, char* dstp, struct stat* st) {
+    D("write open local file 'fd:%d' '%s'\n", fd, dstp);
+    unix_unlink(dstp);
     mkdirs(dstp);
     fd = sdb_creat(dstp, 0644);
 
@@ -239,10 +230,9 @@ int writeopen_local(int fd, char* dstp, void* stat) {
 }
 
 //return fd.
-int writeopen_remote(int fd, char* dstp, void* stat) {
-    D("write open remote file 'fd:%d' '%s'", fd, dstp);
-    syncmsg msg;
-    struct stat* st = (struct stat*)stat;
+int writeopen_remote(int fd, char* dstp, struct stat* st) {
+    D("write open remote file 'fd:%d' '%s'\n", fd, dstp);
+    SYNC_MSG msg;
 
     int len, r;
     int total_len;
@@ -258,7 +248,7 @@ int writeopen_remote(int fd, char* dstp, void* stat) {
         return -1;
     }
 
-    msg.req.id = ID_SEND;
+    msg.req.id = sync_send;
     msg.req.namelen = htoll(total_len);
 
     if(writex(fd, &msg.req, sizeof(msg.req)) ||
@@ -271,19 +261,18 @@ int writeopen_remote(int fd, char* dstp, void* stat) {
     return fd;
 }
 
-int writeclose_local(int fd, char*dstp, void* stat) {
-    D("write close local file 'fd:%d' '%s'", fd, dstp);
+int writeclose_local(int fd, char*dstp, struct stat* st) {
+    D("write close local file 'fd:%d' '%s'\n", fd, dstp);
     if(fd > 0) {
         sdb_close(fd);
     }
     return fd;
 }
 
-int writeclose_remote(int fd, char* dstp, void* stat) {
-    D("write close remote file 'fd:%d' '%s'", fd, dstp);
-    struct stat* st = (struct stat*)stat;
-    syncmsg msg;
-    msg.data.id = ID_DONE;
+int writeclose_remote(int fd, char* dstp, struct stat* st) {
+    D("write close remote file 'fd:%d' '%s'\n", fd, dstp);
+    SYNC_MSG msg;
+    msg.data.id = sync_done;
     msg.data.size = htoll(st->st_mtime);
 
     if(writex(fd, &msg.data, sizeof(msg.data))) {
@@ -296,9 +285,9 @@ int writeclose_remote(int fd, char* dstp, void* stat) {
         return -1;
     }
 
-    if(msg.status.id != ID_OKAY) {
+    if(msg.status.id != sync_okay) {
         char buf[256];
-        if(msg.status.id == ID_FAIL) {
+        if(msg.status.id == sync_fail) {
             int len = ltohl(msg.status.msglen);
             if(len > 256) {
                 len = 255;
@@ -325,9 +314,8 @@ int writeclose_remote(int fd, char* dstp, void* stat) {
 //-1:fail
 //1: write and continue load
 //3: write and stop
-int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) {
-    D("read local file 'fd:%d' '%s'", lfd, srcpath);
-    struct stat* st = (struct stat*)stat;
+int readfile_local(int lfd, char* srcpath, struct stat* st, FILE_BUFFER* sbuf) {
+    D("read local file 'fd:%d' '%s'\n", lfd, srcpath);
 
     if (S_ISREG(st->st_mode)) {
         int ret;
@@ -375,9 +363,9 @@ int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) {
     return -1;
 }
 
-int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) {
-    D("read remote file 'fd:%d' '%s'", fd, srcpath);
-    syncmsg msg;
+int readfile_remote(int fd, char* srcpath, struct stat* st, FILE_BUFFER* buffer) {
+    D("read remote file 'fd:%d' '%s'\n", fd, srcpath);
+    SYNC_MSG msg;
     unsigned id;
 
     if(readx(fd, &(msg.data), sizeof(msg.data))) {
@@ -387,14 +375,14 @@ int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) {
     id = msg.data.id;
     buffer->size = ltohl(msg.data.size);
 
-    if(id == ID_DONE) {
+    if(id == sync_done) {
         //Finish normally.
         return 0;
     }
     //fail
-    if(id != ID_DATA) {
-        int len;
-        if(id == ID_FAIL) {
+    if(id != sync_data) {
+        int len = 0;
+        if(id == sync_fail) {
             int len = buffer->size;
             if(len > 256) {
                 len = 255;
@@ -430,7 +418,7 @@ int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) {
 }
 
 int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) {
-    D("write local file 'fd:%d' '%s'", fd, dstp);
+    D("write local file 'fd:%d' '%s'\n", fd, dstp);
     char* data = sbuf->data;
     unsigned len = sbuf->size;
 
@@ -444,7 +432,7 @@ int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes
 }
 
 int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) {
-    D("write remote file 'fd:%d' '%s'", fd, dstp);
+    D("write remote file 'fd:%d' '%s'\n", fd, dstp);
     int size = ltohl(sbuf->size);
 
     if(writex(fd, sbuf, sizeof(unsigned)*2 + size)) {
@@ -457,7 +445,7 @@ int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_byte
 }
 
 int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) {
-    D("get list of local file 'fd:%d' '%s'", fd, src_dir);
+    D("get list of local file 'fd:%d' '%s'\n", fd, src_dir);
     DIR* d;
 
     d = opendir(src_dir);
@@ -488,7 +476,7 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist)
 
         COPY_INFO* info;
         create_copy_info(&info, src_full_path, dst_full_path);
-        append(dirlist, info);
+        prepend(dirlist, info);
     }
 
     closedir(d);
@@ -496,8 +484,8 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist)
 }
 
 int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) {
-    D("get list of remote file 'fd:%d' '%s'", fd, src_dir);
-    syncmsg msg;
+    D("get list of remote file 'fd:%d' '%s'\n", fd, src_dir);
+    SYNC_MSG msg;
     int len;
 
     len = strlen(src_dir);
@@ -507,36 +495,36 @@ int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist)
         return -1;
     }
 
-    msg.req.id = ID_LIST;
+    msg.req.id = sync_list;
     msg.req.namelen = htoll(len);
 
     if(writex(fd, &msg.req, sizeof(msg.req)) ||
        writex(fd, src_dir, len)) {
-        fprintf(stderr,"cannot request directory entry: '%s'", src_dir);
+        fprintf(stderr,"cannot request directory entry: '%s'\n", src_dir);
         return -1;
     }
 
     while(1) {
         if(readx(fd, &msg.dent, sizeof(msg.dent))) {
-            fprintf(stderr,"cannot read dirlist: '%s'", src_dir);
+            fprintf(stderr,"cannot read dirlist: '%s'\n", src_dir);
             return -1;
         }
-        if(msg.dent.id == ID_DONE) {
+        if(msg.dent.id == sync_done) {
             return fd;
         }
-        if(msg.dent.id != ID_DENT) {
-            fprintf(stderr,"received dent msg '%d' is not DENT", msg.dent.id);
+        if(msg.dent.id != sync_dent) {
+            fprintf(stderr,"received dent msg '%d' is not DENT\n", msg.dent.id);
             return -1;
         }
         len = ltohl(msg.dent.namelen);
         if(len > 256) {
-            fprintf(stderr,"some file in the remote '%s' exceeds 256", src_dir);
+            fprintf(stderr,"some file in the remote '%s' exceeds 256\n", src_dir);
             return -1;
         }
 
         char file_name[257];
         if(readx(fd, file_name, len)) {
-            fprintf(stderr,"cannot read file in the remote directory '%s'", src_dir);
+            fprintf(stderr,"cannot read file in the remote directory '%s'\n", src_dir);
             return -1;
         }
         file_name[len] = 0;
@@ -558,27 +546,39 @@ int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist)
 
         COPY_INFO* info;
         create_copy_info(&info, src_full_path, dst_full_path);
-        append(dirlist, info);
+        prepend(dirlist, info);
+        D("!!!!!!!!!!!!!!!!!!!\n");
     }
+    D("getting list of remote file 'fd:%d' '%s' is done\n", fd, src_dir);
     return fd;
 }
 
-static int sync_readmode(int fd, const char *path, unsigned *mode) {
-    syncmsg msg;
+static int sync_readstat(int fd, const char *path, struct stat* st) {
+    SYNC_MSG msg;
     int len = strlen(path);
-    msg.req.id = ID_STAT;
+    msg.req.id = sync_stat;
     msg.req.namelen = htoll(len);
 
     if(writex(fd, &msg.req, sizeof(msg.req)) ||
        writex(fd, path, len)) {
+        LOG_ERROR("fail to send request ID_STAT with name length %d\n", len);
         return -1;
     }
+
     if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+        LOG_ERROR("fail to read response of ID_STAT with name length %d\n", len);
         return -1;
     }
-    if(msg.stat.id != ID_STAT) {
+    if(msg.stat.id != sync_stat) {
+        return -1;
+    }
+    st->st_mode = ltohl(msg.stat.mode);
+
+    if(!st->st_mode) {
+        LOG_ERROR("fail to stat remote file: '%s'", path);
         return -1;
     }
-    *mode = ltohl(msg.stat.mode);
+    st->st_size = ltohl(msg.stat.size);
+    D("remote stat: mode %u, size %u\n", st->st_mode, st->st_size);
     return 0;
 }
index ddba671293562d0c5ddbe944b3db53cea1538fea..6897c90deefb11e6e4c903d2919ec94b7b31b32a 100644 (file)
@@ -29,6 +29,7 @@
 
 #define  TRACE_TAG  TRACE_SDB
 
+#include <sys/stat.h>
 #include "file_sync_service.h"
 #include "linkedlist.h"
 
@@ -51,26 +52,25 @@ int initialize_remote(char* path, void** extargv);
 void finalize_local(int fd);
 void finalize_remote(int fd);
 
-int _stat_local(int fd, char* path, void** _stat, int show_error);
-int _stat_remote(int fd, char* path, void** stat, int show_error);
+int _stat_local(int fd, char* path, struct stat* st, int show_error);
+int _stat_remote(int fd, char* path, struct stat* st, int show_error);
 
-int is_directory_local(char* path, void* stat, int show_error);
-int is_directory_remote(char* path, void* stat, int show_error);
+int is_directory_common(char* path, struct stat* st, int show_error);
 
-int readopen_local(int fd, char* srcp, void* srcstat);
-int readopen_remote(int fd, char* srcp, void* srcstat);
+int readopen_local(int fd, char* srcp, struct stat* st);
+int readopen_remote(int fd, char* srcp, struct stat* st);
 
 int readclose_local(int lfd);
 int readclose_remote(int fd);
 
-int writeopen_local(int fd, char* dstp, void* stat);
-int writeopen_remote(int fd, char* dstp, void* stat);
+int writeopen_local(int fd, char* dstp, struct stat* st);
+int writeopen_remote(int fd, char* dstp, struct stat* st);
 
-int writeclose_local(int fd, char*dstp, void* stat);
-int writeclose_remote(int fd, char* dstp, void* stat);
+int writeclose_local(int fd, char*dstp, struct stat* st);
+int writeclose_remote(int fd, char* dstp, struct stat* st);
 
-int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf);
-int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer);
+int readfile_local(int lfd, char* srcpath, struct stat* st, FILE_BUFFER* sbuf);
+int readfile_remote(int fd, char* srcpath, struct stat* st, FILE_BUFFER* buffer);
 
 int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes);
 int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes);
@@ -79,21 +79,22 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist);
 int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist);
 
 struct file_function {
+    int local;
     int(*initialize)(char* path, void** extargv);
     void(*finalize)(int fd);
-    int(*_stat)(int fd, char* path, void** stat, int show_error);
-    int(*is_dir)(char* path, void* stat, int show_error);
-    int(*readopen)(int fd, char* dstp, void* stat);
+    int(*_stat)(int fd, char* path, struct stat* st, int show_error);
+    int(*is_dir)(char* path, struct stat* st, int show_error);
+    int(*readopen)(int fd, char* dstp, struct stat* st);
     int(*readclose)(int fd);
-    int(*writeopen)(int fd, char* dstp, void* stat);
-    int(*writeclose)(int fd, char* dstp, void* stat);
-    int(*readfile)(int fd, char* path, void* stat, FILE_BUFFER* buf);
+    int(*writeopen)(int fd, char* dstp, struct stat* st);
+    int(*writeclose)(int fd, char* dstp, struct stat* st);
+    int(*readfile)(int fd, char* path, struct stat* st, FILE_BUFFER* buf);
     int(*writefile)(int fd, char* path, FILE_BUFFER* buf, unsigned* total_bytes);
     int(*get_dirlist)(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist);
 };
 typedef struct file_function FILE_FUNC;
 
-const FILE_FUNC LOCAL_FILE_FUNC;
-const FILE_FUNC REMOTE_FILE_FUNC;
+extern const FILE_FUNC LOCAL_FILE_FUNC;
+extern const FILE_FUNC REMOTE_FILE_FUNC;
 
 #endif /* FILE_SYNC_FUNCTIONS_H_ */
old mode 100644 (file)
new mode 100755 (executable)
index 6f01979..50de665
 #ifndef _FILE_SYNC_SERVICE_H_
 #define _FILE_SYNC_SERVICE_H_
 
-#ifdef HAVE_BIG_ENDIAN
-static inline unsigned __swap_uint32(unsigned x) 
-{
-    return (((x) & 0xFF000000) >> 24)
-        | (((x) & 0x00FF0000) >> 8)
-        | (((x) & 0x0000FF00) << 8)
-        | (((x) & 0x000000FF) << 24);
-}
-#define htoll(x) __swap_uint32(x)
-#define ltohl(x) __swap_uint32(x)
-#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24))
-#else
 #define htoll(x) (x)
 #define ltohl(x) (x)
-#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
-#endif
+#define MKSYNC(a,b,c,d) ( (d << 24) | (c << 16) | (b << 8) | a )
+
+extern const unsigned sync_stat;
+extern const unsigned sync_list;
+extern const unsigned sync_send;
+extern const unsigned sync_recv;
+extern const unsigned sync_dent;
+extern const unsigned sync_done;
+extern const unsigned sync_data;
+extern const unsigned sync_okay;
+extern const unsigned sync_fail;
+extern const unsigned sync_quit;
+
+typedef struct req REQ;
+struct req {
+    unsigned id;
+    unsigned namelen;
+};
 
-#define ID_STAT MKID('S','T','A','T')
-#define ID_LIST MKID('L','I','S','T')
-#define ID_ULNK MKID('U','L','N','K')
-#define ID_SEND MKID('S','E','N','D')
-#define ID_RECV MKID('R','E','C','V')
-#define ID_DENT MKID('D','E','N','T')
-#define ID_DONE MKID('D','O','N','E')
-#define ID_DATA MKID('D','A','T','A')
-#define ID_OKAY MKID('O','K','A','Y')
-#define ID_FAIL MKID('F','A','I','L')
-#define ID_QUIT MKID('Q','U','I','T')
+typedef struct sdb_stat SDB_STAT;
+struct sdb_stat {
+    unsigned id;
+    unsigned mode;
+    unsigned size;
+    unsigned time;
+};
+
+typedef struct dent DENT;
+struct dent {
+    unsigned id;
+    unsigned mode;
+    unsigned size;
+    unsigned time;
+    unsigned namelen;
+};
 
-typedef union {
+typedef struct data DATA;
+struct data {
     unsigned id;
-    struct {
-        unsigned id;
-        unsigned namelen;
-    } req;
-    struct {
-        unsigned id;
-        unsigned mode;
-        unsigned size;
-        unsigned time;
-    } stat;
-    struct {
-        unsigned id;
-        unsigned mode;
-        unsigned size;
-        unsigned time;
-        unsigned namelen;
-    } dent;
-    struct {
-        unsigned id;
-        unsigned size;
-    } data;
-    struct {
-        unsigned id;
-        unsigned msglen;
-    } status;    
-} syncmsg;
+    unsigned size;
+};
 
+typedef struct status STATUS;
+struct status {
+    unsigned id;
+    unsigned msglen;
+};
 
-void file_sync_service(int fd, void *cookie);
-int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, int isUtf8);
-int do_sync_sync(const char *lpath, const char *rpath, int listonly);
-int do_sync_pull(const char *rpath, const char *lpath);
+typedef union syncmsg SYNC_MSG;
+union syncmsg {
+    REQ req;
+    SDB_STAT stat;
+    DENT dent;
+    DATA data;
+    STATUS status;
+};
 
 #define SYNC_DATA_MAX (64*1024)
 #define SYNC_CHAR_MAX 1024
index 93aa7bbccf9fd0003ac523bb4b85c5782cf95924..4c6beb49abb2314b0f3284aae90d3b6d47a8210b 100644 (file)
@@ -31,7 +31,7 @@
 
 static void default_free(void* data);
 
-void append(LIST_NODE** listptr, void* value) {
+LIST_NODE* append(LIST_NODE** listptr, void* value) {
 
     LIST_NODE* prev_ptr = NULL;
     LIST_NODE* current_ptr = *listptr;
@@ -47,14 +47,34 @@ void append(LIST_NODE** listptr, void* value) {
 
     //listptr is empty.
     if(prev_ptr == NULL) {
+        new_ptr->prev_ptr = NULL;
         *listptr = new_ptr;
     }
     else {
         prev_ptr->next_ptr = new_ptr;
+        new_ptr->prev_ptr = prev_ptr;
     }
+
+    return new_ptr;
+}
+
+LIST_NODE* prepend(LIST_NODE** listptr, void* value) {
+
+    LIST_NODE* new_ptr = (LIST_NODE*)malloc(sizeof(LIST_NODE));
+    new_ptr->data = value;
+    new_ptr->next_ptr = *listptr;
+    new_ptr->prev_ptr = NULL;
+
+    if(*listptr != NULL) {
+        (*listptr)->prev_ptr = new_ptr;
+    }
+
+    *listptr = new_ptr;
+
+    return new_ptr;
 }
 
-void no_free() {
+void no_free(void* data) {
     //do nothing.
 }
 
@@ -64,17 +84,39 @@ void free_list(LIST_NODE* listptr, void(free_func)(void*)) {
         free_func = default_free;
     }
 
-    LIST_NODE* nextptr = NULL;
     LIST_NODE* currentptr = listptr;
 
     while(currentptr != NULL) {
-        nextptr = currentptr->next_ptr;
-        free_func(currentptr->data);
-        free(currentptr);
-        currentptr = nextptr;
+        LIST_NODE* prev = currentptr;
+        currentptr = currentptr->next_ptr;
+        free_func(prev->data);
+        free(prev);
     }
 }
 
+void remove_node(LIST_NODE** listptr, LIST_NODE* remove_node, void(free_func)(void*)) {
+
+    if(free_func == NULL) {
+        free_func = default_free;
+    }
+    LIST_NODE* next = remove_node->next_ptr;
+    LIST_NODE* prev = remove_node->prev_ptr;
+
+    if(*listptr == remove_node) {
+        *listptr = next;
+    }
+    else {
+        //if remove_node is not listptr, prev is always not NULL.
+        prev->next_ptr = next;
+    }
+    if (next != NULL) {
+        next->prev_ptr = prev;
+    }
+
+    free_func(remove_node->data);
+    free(remove_node);
+}
+
 static void default_free(void* data) {
     if(data != NULL) {
         free(data);
@@ -89,6 +131,9 @@ void remove_first(LIST_NODE** listptr, void(free_func)(void*)) {
 
     if(*listptr != NULL) {
         LIST_NODE* curptr = (*listptr)->next_ptr;
+        if(curptr != NULL) {
+            curptr->prev_ptr = NULL;
+        }
         LIST_NODE* removeptr = *listptr;
         *listptr = curptr;
         free_func(removeptr->data);
index b88a5de1015d23b1b252f93274bdd7b64f970ddb..11d7aed4b412ed28dde568ede047402cb81c86f3 100644 (file)
 struct list_node {
     void* data;
     struct list_node* next_ptr;
+    struct list_node* prev_ptr;
 };
 
 typedef struct list_node LIST_NODE;
 
-void no_free();
-void append( LIST_NODE** listptr, void* value);
-void free_list(LIST_NODE* listptr, void(free_func)(void*));
-void remove_first(LIST_NODE** listptr, void(free_func)(void*));
+void no_free(void* data);
+LIST_NODE* append( LIST_NODE** listptr, void* value);
+LIST_NODE* prepend(LIST_NODE** listptr, void* value);
+void free_list(LIST_NODE* listptr, void(free_func)(void* data));
+void remove_first(LIST_NODE** listptr, void(free_func)(void* data));
+void remove_node(LIST_NODE** listptr, LIST_NODE* remove_node, void(free_func)(void* data));
 
 #endif /* LINKEDLIST_H_ */
diff --git a/src/listener.c b/src/listener.c
new file mode 100644 (file)
index 0000000..c66ec70
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "listener.h"
+#include "fdevent.h"
+#include "utils.h"
+#include "sockets.h"
+
+LIST_NODE* listener_list = NULL;
+
+static void listener_event_func(int _fd, unsigned ev, void *_l);
+static LISTENER* find_listener(const char *local_name);
+
+void  free_listener(void* data)
+{
+    LISTENER* listener = data;
+    fdevent_remove(&(listener->fde));
+    free((void*)listener->local_name);
+    free((void*)listener->connect_to);
+    free(listener);
+}
+
+int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport)
+{
+    D("LN(%s)\n", local_name);
+
+    LISTENER* listener = find_listener(local_name);
+
+    if(listener != NULL) {
+        char *cto;
+
+            /* can't repurpose a smartsocket */
+        if(listener->connect_to[0] == '*') {
+            return -1;
+        }
+
+        cto = strdup(connect_to);
+        if(cto == 0) {
+            return -1;
+        }
+
+        //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
+        free((void*) listener->connect_to);
+        listener->connect_to = cto;
+        if (listener->transport != transport) {
+            listener->transport = transport;
+        }
+        return 0;
+    }
+
+    if(strncmp("tcp:", local_name, 4)){
+        LOG_FATAL("LN(%s) unknown local portname\n", local_name);
+        return -2;
+    }
+
+    int port = atoi(local_name + 4);
+
+    //TODO REMOTE_DEVICE_CONNECT block remote connect until security issue is cleard
+//    int fd = sdb_port_listen(INADDR_ANY, port, SOCK_STREAM);
+    int fd = sdb_port_listen(INADDR_LOOPBACK, port, SOCK_STREAM);
+
+    if(fd < 0) {
+        LOG_FATAL("LN(%s) cannot bind\n", local_name);
+        return -2;
+    }
+
+    listener = calloc(1, sizeof(LISTENER));
+    listener->local_name = strdup(local_name);
+    listener->connect_to = strdup(connect_to);
+    listener->fd = fd;
+    listener->node = prepend(&listener_list, listener);
+    listener->transport = transport;
+    close_on_exec(fd);
+    fdevent_install(&listener->fde, fd, listener_event_func, listener);
+    FDEVENT_SET(&listener->fde, FDE_READ);
+    return 0;
+}
+
+int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport)
+{
+    D("LN(%s)\n", local_name);
+    LISTENER* listener = find_listener(local_name);
+
+    if(listener != NULL &&
+            !strcmp(connect_to, listener->connect_to) &&
+            listener->transport != NULL &&
+            listener->transport == transport) {
+        remove_node(&listener_list, listener->node, free_listener);
+        D("LN(%s) removed\n", local_name);
+        return 0;
+    }
+
+    D("LN(%s) could not find\n", local_name);
+    return -1;
+}
+
+static void listener_event_func(int _fd, unsigned ev, void *_l)
+{
+    LISTENER *l = _l;
+    D("LN(%s)\n", l->local_name);
+
+    if(ev & FDE_READ) {
+        int fd = sdb_socket_accept(_fd);
+
+        if(fd < 0) {
+            D("LN(%s) fail to create\n", l->local_name);
+            return;
+        }
+
+        SDB_SOCKET *s = create_local_socket(fd);
+
+        int ss = 0;
+        if(!strcmp(l->connect_to, "*smartsocket*")) {
+            ss = 1;
+        }
+
+        if(ss) {
+            sdb_socket_setbufsize(fd, CHUNK_SIZE);
+        }
+        if(s) {
+
+            if(ss) {
+                local_socket_ready(s);
+            }
+            else {
+
+                if(l->transport->type == kTransportRemoteDevCon) {
+                    if(assign_remote_connect_socket_rid(s)) {
+                        local_socket_close(s);
+                        return;
+                    }
+                }
+
+                s->transport = l->transport;
+                connect_to_remote(s, l->connect_to);
+            }
+            return;
+        }
+
+        sdb_close(fd);
+    }
+}
+
+static LISTENER* find_listener(const char *local_name) {
+    LIST_NODE* currentptr = listener_list;
+    while(currentptr != NULL) {
+        LISTENER* l = currentptr->data;
+        currentptr = currentptr->next_ptr;
+        if(!strcmp(local_name, l->local_name)) {
+            return l;
+        }
+    }
+    return NULL;
+}
diff --git a/src/listener.h b/src/listener.h
new file mode 100644 (file)
index 0000000..b2850cc
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef LISTENER_H_
+#define LISTENER_H_
+
+#include "common_modules.h"
+extern LIST_NODE* listener_list;
+
+int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport);
+int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport);
+void  free_listener(void* data);
+
+#endif /* LISTENER_H_ */
diff --git a/src/log.c b/src/log.c
new file mode 100644 (file)
index 0000000..41477f3
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h> // for using va_list
+#include "log.h"
+#include "utils.h"
+
+int loglevel_mask;
+
+static struct {
+    char*  name;
+    LogLevel level;
+} log_levels[] = {
+    { "all", 0 },
+    { "fatal", SDBLOG_FATAL },
+    { "error", SDBLOG_ERROR },
+    { "debug", SDBLOG_DEBUG },
+    { "info", SDBLOG_INFO },
+    { "fixme", SDBLOG_FIXME },
+    { NULL, 0 }
+};
+
+void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...) {
+    char *name = NULL;
+    char mbuf[1024];
+    char fbuf[1024];
+    va_list args;
+
+    va_start(args, fmt);
+
+    switch (level) {
+        case SDBLOG_FATAL:
+            name = log_levels[SDBLOG_FATAL].name;
+            break;
+        case SDBLOG_ERROR:
+            name = log_levels[SDBLOG_ERROR].name;
+            break;
+        case SDBLOG_INFO:
+            name = log_levels[SDBLOG_INFO].name;
+            break;
+        case SDBLOG_DEBUG:
+            name = log_levels[SDBLOG_DEBUG].name;;
+            break;
+        case SDBLOG_FIXME:
+            name = log_levels[SDBLOG_FIXME].name;
+            break;
+        default:
+            name = log_levels[SDBLOG_INFO].name;
+            break;
+    }
+    snprintf(fbuf, sizeof(fbuf), "[%s][%s:%s():%d]%s", name, filename, funcname, line_number, fmt);
+    vsnprintf(mbuf, sizeof(mbuf), fbuf, args);
+    sdb_mutex_lock(&D_lock, NULL);
+    fprintf(stderr, "%s", mbuf);
+    sdb_mutex_unlock(&D_lock, NULL);
+    fflush(stderr);
+    va_end(args);
+}
+
+static void log_parse(char* args) {
+    char *level, *levels, *next;
+
+    levels = strdup(args);
+    if (levels == NULL) {
+        return;
+    }
+    int i=0;
+    for (level = levels; level; level = next) {
+        next = strchr(level, ',' );
+        if (next != NULL) {
+            *next++ = 0;
+        }
+
+        for (i = 0; log_levels[i].name != NULL; i++) {
+            if (!strcmp(level, log_levels[i].name))
+            {
+                if (!strcmp("all",log_levels[i].name)) {
+                    loglevel_mask = ~0;
+                    free(levels);
+                    return;
+                }
+                loglevel_mask |= 1 << log_levels[i].level;
+                break;
+            }
+        }
+    }
+    free(levels);
+}
+
+void  log_init(void)
+{
+    char*  sdb_debug = NULL;
+
+    if ((sdb_debug = getenv(DEBUG_ENV))) {
+        log_parse(sdb_debug);
+    }
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644 (file)
index 0000000..d6e85ac
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LOG_H
+#define __LOG_H
+
+#define  SDB_TRACE    1
+#define  DEBUG_ENV       "SDB_DEBUG"
+extern int loglevel_mask;
+
+typedef enum {
+    SDBLOG_FATAL = 1,
+    SDBLOG_ERROR,
+    SDBLOG_DEBUG,
+    SDBLOG_INFO,
+    SDBLOG_FIXME
+} LogLevel;
+
+#define LOG_FATAL(args...) \
+        do { \
+            logging(SDBLOG_FATAL, __FILE__, __FUNCTION__, __LINE__, args);\
+            exit(255);} while(0)
+
+#define LOG_ASSERT(cond)  do { if (!(cond)) LOG_FATAL( "assertion failed '%s'\n", #cond); } while (0)
+
+
+#define LOG_ERROR(args...) \
+        do { if ((loglevel_mask & (1 << SDBLOG_ERROR)) != 0) { \
+            logging(SDBLOG_ERROR, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+#define LOG_DEBUG(args...) \
+        do { if ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0) { \
+            logging(SDBLOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+#define LOG_INFO(args...) \
+        do { if ((loglevel_mask & (1 << SDBLOG_INFO)) != 0) { \
+            logging(SDBLOG_INFO, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+#define LOG_FIXME(args...) \
+        do { if ((loglevel_mask & (1 << SDBLOG_FIXME)) != 0) { \
+            logging(SDBLOG_FIXME, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+void log_init(void);
+void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...);
+
+// define for a while for testing
+#undef D
+#define D LOG_DEBUG
+#undef DR
+#define DR LOG_DEBUG
+#define SDB_TRACING  ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0)
+
+#endif
diff --git a/src/memutils.c b/src/memutils.c
new file mode 100644 (file)
index 0000000..4fdd686
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "log.h"
+#include "strutils.h"
+
+static size_t total_mem = 0;
+
+// added size of size_t to know how many bytes have been allocated.
+
+void *s_malloc(size_t size) {
+    void *ptr = malloc(size + sizeof(size_t));
+
+    if (ptr == NULL) {
+        LOG_FATAL("cannot allocate memory:%d bytes\n", (int ) size);
+    }
+    *(size_t*) ptr = size;
+
+    total_mem += size;
+
+    LOG_DEBUG("memory allocated:%u bytes / %u bytes\n", size, total_mem);
+
+    return ptr + sizeof(size_t);
+}
+
+void *s_realloc(void *ptr, size_t new_size) {
+    void *new_ptr;
+    size_t org_size;
+
+    if (ptr == NULL) {
+        LOG_FATAL("null argument in!!\n");
+    }
+
+    new_ptr = realloc(ptr - sizeof(size_t), new_size + sizeof(size_t));
+    if (new_ptr == NULL) {
+        LOG_FATAL("cannot allocate new memory:%d bytes\n", (int ) new_size);
+    }
+    org_size = *(size_t*) (ptr - sizeof(size_t));
+    *(size_t*) new_ptr = new_size;
+    total_mem += new_size - org_size;
+
+    LOG_DEBUG("memory allocated:%u bytes -> %u bytes / %u bytes\n", org_size, new_size, total_mem);
+
+    return new_ptr + sizeof(size_t);
+}
+
+void s_free(void *ptr) {
+    size_t size;
+
+    if (ptr == NULL) {
+        return;
+    }
+
+    size = *(size_t*) (ptr - sizeof(size_t));
+    total_mem -= size;
+
+    free(ptr - sizeof(size_t));
+
+    LOG_DEBUG("memory freed:%u bytes / %u\n", size, total_mem);
+
+}
+
+char *s_strdup(const char *str) {
+    if (str == NULL) {
+        return NULL;
+    }
+    int len = strlen(str) + 1;
+
+    char *ptr = s_malloc(len);
+
+    s_strncpy(ptr, str, len);
+    return ptr;
+}
diff --git a/src/memutils.h b/src/memutils.h
new file mode 100644 (file)
index 0000000..082bf59
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _MEMUTILS_H_
+#define _MEMUTILS_H_
+
+void *s_malloc(size_t size);
+void *s_realloc(void *ptr, size_t new_size);
+void s_free(void *ptr);
+char *s_strdup(const char *str);
+
+#endif
+
index d33b6b8552c2e8b78adc26911f2f9a1d6a4ad303..9471e56082dd967ec1d73fc60562d9fe3cf1926f 100755 (executable)
--- a/src/sdb.c
+++ b/src/sdb.c
 #include "fdevent.h"
 #include "sdb.h"
 #include "commandline.h"
+#include "sdb_constants.h"
+#include "listener.h"
 
 #if SDB_TRACE
 SDB_MUTEX_DEFINE( D_lock );
 #endif
 
-int HOST = 0;
+MAP hex_map;
 
-static const char *sdb_device_banner = "device";
-
-void fatal(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "error: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    va_end(ap);
-    exit(-1);
-}
-
-void fatal_errno(const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    fprintf(stderr, "error: %s: ", strerror(errno));
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n");
-    va_end(ap);
-    exit(-1);
-}
-
-int   sdb_trace_mask;
-
-/* read a comma/space/colum/semi-column separated list of tags
- * from the SDB_TRACE environment variable and build the trace
- * mask from it. note that '1' and 'all' are special cases to
- * enable all tracing
- */
-void  sdb_trace_init(void)
-{
-    const char*  p = getenv("SDB_TRACE");
-    const char*  q;
-
-    static const struct {
-        const char*  tag;
-        int           flag;
-    } tags[] = {
-        { "1", 0 },
-        { "all", 0 },
-        { "sdb", TRACE_SDB },
-        { "sockets", TRACE_SOCKETS },
-        { "packets", TRACE_PACKETS },
-        { "rwx", TRACE_RWX },
-        { "usb", TRACE_USB },
-        { "sync", TRACE_SYNC },
-        { "sysdeps", TRACE_SYSDEPS },
-        { "transport", TRACE_TRANSPORT },
-        { "jdwp", TRACE_JDWP },
-        { "services", TRACE_SERVICES },
-        { "properties", TRACE_PROPERTIES },
-        { NULL, 0 }
-    };
-
-    if (p == NULL)
-            return;
-
-    /* use a comma/column/semi-colum/space separated list */
-    while (*p) {
-        int  len, tagn;
-
-        q = strpbrk(p, " ,:;");
-        if (q == NULL) {
-            q = p + strlen(p);
-        }
-        len = q - p;
-
-        for (tagn = 0; tags[tagn].tag != NULL; tagn++)
-        {
-            int  taglen = strlen(tags[tagn].tag);
-
-            if (len == taglen && !memcmp(tags[tagn].tag, p, len) )
-            {
-                int  flag = tags[tagn].flag;
-                if (flag == 0) {
-                    sdb_trace_mask = ~0;
-                    return;
-                }
-                sdb_trace_mask |= (1 << flag);
-                break;
-            }
-        }
-        p = q;
-        if (*p)
-            p++;
-    }
-}
-
-apacket *get_apacket(void)
-{
-    apacket *p = malloc(sizeof(apacket));
-    if(p == 0) fatal("failed to allocate an apacket");
-    memset(p, 0, sizeof(apacket) - MAX_PAYLOAD);
-    return p;
-}
-
-void put_apacket(apacket *p)
-{
-    free(p);
-}
-
-void handle_online(void)
-{
-    D("sdb: online\n");
-}
-
-void handle_offline(atransport *t)
-{
-    D("sdb: offline\n");
-    //Close the associated usb
-    run_transport_disconnects(t);
-}
-
-#if TRACE_PACKETS
-#define DUMPMAX 32
-void print_packet(const char *label, apacket *p)
-{
-    char *tag;
-    char *x;
-    unsigned count;
-
-    switch(p->msg.command){
-    case A_SYNC: tag = "SYNC"; break;
-    case A_CNXN: tag = "CNXN" ; break;
-    case A_OPEN: tag = "OPEN"; break;
-    case A_OKAY: tag = "OKAY"; break;
-    case A_CLSE: tag = "CLSE"; break;
-    case A_WRTE: tag = "WRTE"; break;
-    default: tag = "????"; break;
-    }
-
-    fprintf(stderr, "%s: %s %08x %08x %04x \"",
-            label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length);
-    count = p->msg.data_length;
-    x = (char*) p->data;
-    if(count > DUMPMAX) {
-        count = DUMPMAX;
-        tag = "\n";
-    } else {
-        tag = "\"\n";
-    }
-    while(count-- > 0){
-        if((*x >= ' ') && (*x < 127)) {
-            fputc(*x, stderr);
-        } else {
-            fputc('.', stderr);
-        }
-        x++;
-    }
-    fprintf(stderr, tag);
-}
-#endif
-
-static void send_ready(unsigned local, unsigned remote, atransport *t)
-{
-    D("Calling send_ready \n");
-    apacket *p = get_apacket();
-    p->msg.command = A_OKAY;
-    p->msg.arg0 = local;
-    p->msg.arg1 = remote;
-    send_packet(p, t);
-}
-
-static void send_close(unsigned local, unsigned remote, atransport *t)
-{
-    D("Calling send_close \n");
-    apacket *p = get_apacket();
-    p->msg.command = A_CLSE;
-    p->msg.arg0 = local;
-    p->msg.arg1 = remote;
-    send_packet(p, t);
-}
-
-static void send_connect(atransport *t)
-{
-    D("Calling send_connect \n");
-    apacket *cp = get_apacket();
-    cp->msg.command = A_CNXN;
-    cp->msg.arg0 = A_VERSION;
-    cp->msg.arg1 = MAX_PAYLOAD;
-    snprintf((char*) cp->data, sizeof cp->data, "%s::",
-            HOST ? "host" : sdb_device_banner);
-    cp->msg.data_length = strlen((char*) cp->data) + 1;
-    send_packet(cp, t);
-
-    /* XXX why sleep here? */
-    // allow the device some time to respond to the connect message
-    sdb_sleep_ms(1000);
-
-}
-
-static char *connection_state_name(atransport *t)
-{
-    if (t == NULL) {
-        return "unknown";
-    }
-
-    switch(t->connection_state) {
-    case CS_BOOTLOADER:
-        return "bootloader";
-    case CS_DEVICE:
-        return "device";
-    case CS_OFFLINE:
-        return "offline";
-    default:
-        return "unknown";
-    }
-}
-
-void parse_banner(char *banner, atransport *t)
-{
-    char *type, *product, *end;
-
-    D("parse_banner: %s\n", banner);
-    type = banner;
-    product = strchr(type, ':');
-    if(product) {
-        *product++ = 0;
-    } else {
-        product = "";
-    }
-
-        /* remove trailing ':' */
-    end = strchr(product, ':');
-    if(end) *end = 0;
-
-        /* save product name in device structure */
-    if (t->product == NULL) {
-        t->product = strdup(product);
-    } else if (strcmp(product, t->product) != 0) {
-        free(t->product);
-        t->product = strdup(product);
-    }
-
-    if(!strcmp(type, "bootloader")){
-        D("setting connection_state to CS_BOOTLOADER\n");
-        t->connection_state = CS_BOOTLOADER;
-        update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "device")) {
-        D("setting connection_state to CS_DEVICE\n");
-        t->connection_state = CS_DEVICE;
-        update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "recovery")) {
-        D("setting connection_state to CS_RECOVERY\n");
-        t->connection_state = CS_RECOVERY;
-        update_transports();
-        return;
-    }
-
-    if(!strcmp(type, "sideload")) {
-        D("setting connection_state to CS_SIDELOAD\n");
-        t->connection_state = CS_SIDELOAD;
-        update_transports();
-        return;
-    }
-
-    t->connection_state = CS_HOST;
-}
-
-void handle_packet(apacket *p, atransport *t)
-{
-    asocket *s;
-
-    D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0],
-                ((char*) (&(p->msg.command)))[1],
-                ((char*) (&(p->msg.command)))[2],
-                ((char*) (&(p->msg.command)))[3]);
-
-    print_packet("recv", p);
-
-    switch(p->msg.command){
-    case A_SYNC:
-        if(p->msg.arg0){
-            send_packet(p, t);
-            if(HOST) send_connect(t);
-        } else {
-            t->connection_state = CS_OFFLINE;
-            handle_offline(t);
-            send_packet(p, t);
-        }
-        return;
-
-    case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
-            /* XXX verify version, etc */
-        if(t->connection_state != CS_OFFLINE) {
-            t->connection_state = CS_OFFLINE;
-            handle_offline(t);
-        }
-        parse_banner((char*) p->data, t);
-        handle_online();
-        if(!HOST) send_connect(t);
-        break;
-
-    case A_OPEN: /* OPEN(local-id, 0, "destination") */
-        if(t->connection_state != CS_OFFLINE) {
-            char *name = (char*) p->data;
-            name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
-            s = create_local_service_socket(name);
-            if(s == 0) {
-                send_close(0, p->msg.arg0, t);
-            } else {
-                s->peer = create_remote_socket(p->msg.arg0, t);
-                s->peer->peer = s;
-                send_ready(s->id, s->peer->id, t);
-                s->ready(s);
-            }
-        }
-        break;
-
-    case A_OKAY: /* READY(local-id, remote-id, "") */
-        if(t->connection_state != CS_OFFLINE) {
-            if((s = find_local_socket(p->msg.arg1))) {
-                if(s->peer == 0) {
-                    s->peer = create_remote_socket(p->msg.arg0, t);
-                    s->peer->peer = s;
-                }
-                s->ready(s);
-            }
-        }
-        break;
-
-    case A_CLSE: /* CLOSE(local-id, remote-id, "") */
-        if(t->connection_state != CS_OFFLINE) {
-            if((s = find_local_socket(p->msg.arg1))) {
-                s->close(s);
-            }
-        }
-        break;
-
-    case A_WRTE:
-        if(t->connection_state != CS_OFFLINE) {
-            if((s = find_local_socket(p->msg.arg1))) {
-                unsigned rid = p->msg.arg0;
-                p->len = p->msg.data_length;
-
-                if(s->enqueue(s, p) == 0) {
-                    D("Enqueue the socket\n");
-                    send_ready(s->id, rid, t);
-                }
-                return;
-            }
-        }
-        break;
-
-    default:
-        printf("handle_packet: what is %08x?!\n", p->msg.command);
-    }
-
-    put_apacket(p);
-}
-
-alistener listener_list = {
-    .next = &listener_list,
-    .prev = &listener_list,
-};
-
-static void ss_listener_event_func(int _fd, unsigned ev, void *_l)
-{
-    asocket *s;
-
-    if(ev & FDE_READ) {
-        struct sockaddr addr;
-        socklen_t alen;
-        int fd;
-
-        alen = sizeof(addr);
-        fd = sdb_socket_accept(_fd, &addr, &alen);
-        if(fd < 0) return;
-
-        sdb_socket_setbufsize(fd, CHUNK_SIZE);
-
-        s = create_local_socket(fd);
-        if(s) {
-            connect_to_smartsocket(s);
-            return;
-        }
-
-        sdb_close(fd);
-    }
-}
-
-static void listener_event_func(int _fd, unsigned ev, void *_l)
-{
-    alistener *l = _l;
-    asocket *s;
-
-    if(ev & FDE_READ) {
-        struct sockaddr addr;
-        socklen_t alen;
-        int fd;
-
-        alen = sizeof(addr);
-        fd = sdb_socket_accept(_fd, &addr, &alen);
-        if(fd < 0) return;
-
-        s = create_local_socket(fd);
-        if(s) {
-            s->transport = l->transport;
-            connect_to_remote(s, l->connect_to);
-            return;
-        }
-
-        sdb_close(fd);
-    }
-}
-
-static void  free_listener(alistener*  l)
-{
-    if (l->next) {
-        l->next->prev = l->prev;
-        l->prev->next = l->next;
-        l->next = l->prev = l;
-    }
-
-    // closes the corresponding fd
-    fdevent_remove(&l->fde);
-
-    if (l->local_name)
-        free((char*)l->local_name);
-
-    if (l->connect_to)
-        free((char*)l->connect_to);
-
-    if (l->transport) {
-        remove_transport_disconnect(l->transport, &l->disconnect);
-    }
-    free(l);
-}
-
-static void listener_disconnect(void*  _l, atransport*  t)
-{
-    alistener*  l = _l;
-
-    free_listener(l);
-}
-
-int local_name_to_fd(const char *name)
-{
-    int port;
-
-    if(!strncmp("tcp:", name, 4)){
-        int  ret;
-        port = atoi(name + 4);
-        ret = socket_loopback_server(port, SOCK_STREAM);
-        D("add loopback listen to %d", port);
-        return ret;
-    }
-
-    printf("unknown local portname '%s'\n", name);
-    return -1;
-}
-
-static int remove_listener(const char *local_name, const char *connect_to, atransport* transport)
-{
-    alistener *l;
-
-    for (l = listener_list.next; l != &listener_list; l = l->next) {
-        if (!strcmp(local_name, l->local_name) &&
-            !strcmp(connect_to, l->connect_to) &&
-            l->transport && l->transport == transport) {
-
-            listener_disconnect(l, transport);
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
-static int install_listener(const char *local_name, const char *connect_to, atransport* transport)
-{
-    alistener *l;
-
-    D("install_listener('%s','%s')\n", local_name, connect_to);
-
-    for(l = listener_list.next; l != &listener_list; l = l->next){
-        if(strcmp(local_name, l->local_name) == 0) {
-            char *cto;
-
-                /* can't repurpose a smartsocket */
-            if(l->connect_to[0] == '*') {
-                return -1;
-            }
-
-            cto = strdup(connect_to);
-            if(cto == 0) {
-                return -1;
-            }
-
-            //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
-            free((void*) l->connect_to);
-            l->connect_to = cto;
-            if (l->transport != transport) {
-                remove_transport_disconnect(l->transport, &l->disconnect);
-                l->transport = transport;
-                add_transport_disconnect(l->transport, &l->disconnect);
-            }
-            return 0;
-        }
-    }
-
-    if((l = calloc(1, sizeof(alistener))) == 0) goto nomem;
-    if((l->local_name = strdup(local_name)) == 0) goto nomem;
-    if((l->connect_to = strdup(connect_to)) == 0) goto nomem;
-
-
-    l->fd = local_name_to_fd(local_name);
-    if(l->fd < 0) {
-        free((void*) l->local_name);
-        free((void*) l->connect_to);
-        free(l);
-        printf("cannot bind '%s'\n", local_name);
-        return -2;
-    }
-
-    close_on_exec(l->fd);
-    if(!strcmp(l->connect_to, "*smartsocket*")) {
-        fdevent_install(&l->fde, l->fd, ss_listener_event_func, l);
-    } else {
-        fdevent_install(&l->fde, l->fd, listener_event_func, l);
-    }
-    fdevent_set(&l->fde, FDE_READ);
-
-    l->next = &listener_list;
-    l->prev = listener_list.prev;
-    l->next->prev = l;
-    l->prev->next = l;
-    l->transport = transport;
-
-    if (transport) {
-        l->disconnect.opaque = l;
-        l->disconnect.func   = listener_disconnect;
-        add_transport_disconnect(transport, &l->disconnect);
-    }
-    return 0;
-
-nomem:
-    fatal("cannot allocate listener");
-    return 0;
-}
+static void local_init(int port);
+static void init_wakeup_select_func();
 
 #ifdef OS_WINDOWS
 static BOOL WINAPI ctrlc_handler(DWORD type)
@@ -594,11 +50,65 @@ static BOOL WINAPI ctrlc_handler(DWORD type)
 }
 #endif
 
-static void sdb_cleanup(void)
+void sdb_cleanup(void)
 {
     sdb_usb_cleanup();
 }
 
+static void init_map() {
+    initialize_map(&event_map, EVENT_MAP_SIZE, NULL, NULL, no_free);
+    initialize_map(&hex_map, 16, NULL, NULL, no_free);
+    MAP_KEY key;
+    key.key_int = (int)'0';
+    map_put(&hex_map, key, 0);
+    key.key_int = (int)'1';
+    map_put(&hex_map, key, (void*)('1' - '0'));
+    key.key_int = (int)'2';
+    map_put(&hex_map, key, (void*)('2' - '0'));
+    key.key_int = (int)'3';
+    map_put(&hex_map, key, (void*)('3' - '0'));
+    key.key_int = (int)'4';
+    map_put(&hex_map, key, (void*)('4' - '0'));
+    key.key_int = (int)'5';
+    map_put(&hex_map, key, (void*)('5' - '0'));
+    key.key_int = (int)'6';
+    map_put(&hex_map, key, (void*)('6' - '0'));
+    key.key_int = (int)'7';
+    map_put(&hex_map, key, (void*)('7' - '0'));
+    key.key_int = (int)'8';
+    map_put(&hex_map, key, (void*)('8' - '0'));
+    key.key_int = (int)'9';
+    map_put(&hex_map, key, (void*)('9' - '0'));
+    key.key_int = (int)'a';
+    map_put(&hex_map, key, (void*)10);
+    key.key_int = (int)'b';
+    map_put(&hex_map, key, (void*)(10 + 'b' - 'a'));
+    key.key_int = (int)'c';
+    map_put(&hex_map, key, (void*)(10 + 'c' - 'a'));
+    key.key_int = (int)'d';
+    map_put(&hex_map, key, (void*)(10 + 'd' - 'a'));
+    key.key_int = (int)'e';
+    map_put(&hex_map, key, (void*)(10 + 'e' - 'a'));
+    key.key_int = (int)'f';
+    map_put(&hex_map, key, (void*)(10 + 'f' - 'a'));
+    key.key_int = (int)'A';
+    map_put(&hex_map, key, (void*)10);
+    key.key_int = (int)'B';
+    map_put(&hex_map, key, (void*)(10 + 'B' - 'A'));
+    key.key_int = (int)'C';
+    map_put(&hex_map, key, (void*)(10 + 'C' - 'A'));
+    key.key_int = (int)'D';
+    map_put(&hex_map, key, (void*)(10 + 'D' - 'A'));
+    key.key_int = (int)'E';
+    map_put(&hex_map, key, (void*)(10 + 'E' - 'A'));
+    key.key_int = (int)'F';
+    map_put(&hex_map, key, (void*)(10 + 'F' - 'A'));
+
+#if defined(OS_WINDOWS)
+    initialize_map(&sdb_handle_map, WIN32_MAX_FHS / 2, NULL, NULL, no_free);
+#endif
+}
+
 /* Constructs a local name of form tcp:port.
  * target_str points to the target string, it's content will be overwritten.
  * target_size is the capacity of the target string.
@@ -618,10 +128,8 @@ int sdb_main(int is_daemon, int server_port)
     signal(SIGPIPE, SIG_IGN);
 #endif
 
-    init_transport_registration();
+    init_wakeup_select_func();
 
-    HOST = 1;
-//    usb_vendors_init();
     sdb_usb_init();
     local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
 
@@ -641,337 +149,51 @@ int sdb_main(int is_daemon, int server_port)
 #endif
         start_logging();
     }
-    D("Event loop starting\n");
-
-    fdevent_loop();
+    LOG_INFO("Event loop starting\n");
+    FDEVENT_LOOP();
 
     atexit(sdb_cleanup);
-
     return 0;
 }
 
-void connect_device(char* host, char* buffer, int buffer_size)
+static void local_init(int port)
 {
-    int port, fd;
-    char* portstr = strchr(host, ':');
-    char hostbuf[100];
-    char serial[100];
-
-    strncpy(hostbuf, host, sizeof(hostbuf) - 1);
-    if (portstr) {
-        if (portstr - host >= sizeof(hostbuf)) {
-            snprintf(buffer, buffer_size, "bad host name %s", host);
-            return;
-        }
-        // zero terminate the host at the point we found the colon
-        hostbuf[portstr - host] = 0;
-        if (sscanf(portstr + 1, "%d", &port) == 0) {
-            snprintf(buffer, buffer_size, "bad port number %s", portstr);
-            return;
-        }
-    } else {
+    if(port < 1024) {
         port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
     }
+    int  count = SDB_LOCAL_TRANSPORT_MAX;
 
-    snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
-    if (find_transport(serial)) {
-        snprintf(buffer, buffer_size, "already connected to %s", serial);
-        return;
-    }
-
-    fd = socket_network_client(hostbuf, port, SOCK_STREAM);
-    if (fd < 0) {
-        snprintf(buffer, buffer_size, "unable to connect to %s", host);
-        return;
+    LOG_INFO("try to connect to emulator instances when booting sdb server up\n");
+    for ( ; count > 0; count--, port += 10 ) {
+        (void) local_connect(port, NULL);
     }
-
-    D("client: connected on remote on fd %d\n", fd);
-    close_on_exec(fd);
-    disable_tcp_nagle(fd);
-    register_socket_transport(fd, serial, port, 0, NULL);
-    snprintf(buffer, buffer_size, "connected to %s", serial);
 }
 
-void connect_emulator(char* port_spec, char* buffer, int buffer_size)
-{
-    char* port_separator = strchr(port_spec, ',');
-    if (!port_separator) {
-        snprintf(buffer, buffer_size,
-                "unable to parse '%s' as <console port>,<sdb port>",
-                port_spec);
-        return;
-    }
 
-    // Zero-terminate console port and make port_separator point to 2nd port.
-    *port_separator++ = 0;
-    int console_port = strtol(port_spec, NULL, 0);
-    int sdb_port = strtol(port_separator, NULL, 0);
-    if (!(console_port > 0 && sdb_port > 0)) {
-        *(port_separator - 1) = ',';
-        snprintf(buffer, buffer_size,
-                "Invalid port numbers: Expected positive numbers, got '%s'",
-                port_spec);
-        return;
-    }
+void init_wakeup_select_func() {
+    D("initialize select wakeup func\n");
+    int socket_pair[2];
 
-    /* Check if the emulator is already known.
-     * Note: There's a small but harmless race condition here: An emulator not
-     * present just yet could be registered by another invocation right
-     * after doing this check here. However, local_connect protects
-     * against double-registration too. From here, a better error message
-     * can be produced. In the case of the race condition, the very specific
-     * error message won't be shown, but the data doesn't get corrupted. */
-    atransport* known_emulator = find_emulator_transport_by_sdb_port(sdb_port);
-    if (known_emulator != NULL) {
-        snprintf(buffer, buffer_size,
-                "Emulator on port %d already registered.", sdb_port);
+    if(sdb_socketpair(socket_pair)){
+        D("cannot open select wakeup socketpair\n");
         return;
     }
+    fdevent_wakeup_send = socket_pair[0];
+    fdevent_wakeup_recv = socket_pair[1];
 
-    /* Check if more emulators can be registered. Similar unproblematic
-     * race condition as above. */
-    int candidate_slot = get_available_local_transport_index();
-    if (candidate_slot < 0) {
-        snprintf(buffer, buffer_size, "Cannot accept more emulators.");
-        return;
-    }
-
-    /* Preconditions met, try to connect to the emulator. */
-    if (!local_connect_arbitrary_ports(console_port, sdb_port, NULL)) {
-        snprintf(buffer, buffer_size,
-                "Connected to emulator on ports %d,%d", console_port, sdb_port);
-    } else {
-        snprintf(buffer, buffer_size,
-                "Could not connect to emulator on ports %d,%d",
-                console_port, sdb_port);
-    }
-}
-
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
-{
-    atransport *transport = NULL;
-    char buf[4096];
+    fdevent_install(&fdevent_wakeup_fde,
+                    fdevent_wakeup_recv,
+                    wakeup_select_func,
+                    0);
 
-    if(!strcmp(service, "kill")) {
-        fprintf(stderr,"sdb server killed by remote request\n");
-        fflush(stdout);
-        sdb_write(reply_fd, "OKAY", 4);
-        sdb_cleanup();
-        exit(0);
-    }
-
-    // "transport:" is used for switching transport with a specified serial number
-    // "transport-usb:" is used for switching transport to the only USB transport
-    // "transport-local:" is used for switching transport to the only local transport
-    // "transport-any:" is used for switching transport to the only transport
-    if (!strncmp(service, "transport", strlen("transport"))) {
-        char* error_string = "unknown failure";
-        transport_type type = kTransportAny;
-
-        if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
-            type = kTransportUsb;
-        } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
-            type = kTransportLocal;
-        } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
-            type = kTransportAny;
-        } else if (!strncmp(service, "transport:", strlen("transport:"))) {
-            service += strlen("transport:");
-            serial = service;
-        }
-
-        transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
-
-        if (transport) {
-            s->transport = transport;
-            sdb_write(reply_fd, "OKAY", 4);
-        } else {
-            sendfailmsg(reply_fd, error_string);
-        }
-        return 1;
-    }
-
-    // find a device which prefix match the partial serial num
-    // for example, there are two devices
-    // fjldsads9uq2oeu
-    // fjkuiaoejlfamck
-    // to make user's life more easier, it can specify a device with
-    // it's uniq prefix, in the above example, that means
-    // fjl <==> fjldsads9uq2oeu
-    // fjk <==> fjkuiaoejlfamck
-    if (!strncmp(service, "serial-match:", 13)) {
-        char *tmp = service + 13;
-        char *serial = NULL;
-        int ret = -1;
-        D("Try to find device for: %s\n", tmp);
-        ret = find_transports(&serial, tmp);
-        if (ret <= 0) {
-            D("No device found\n");
-            snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(serial), serial);
-        } else if (ret == 1) {
-            D("found device: %s\n", serial);
-            snprintf(buf, sizeof(buf), "OKAY%04x%s", (unsigned)strlen(serial), serial);
-        } else {
-            D("found more than one devices matched: %d\n", ret);
-            snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(serial), serial);
-        }
-
-        writex(reply_fd, buf, strlen(buf));
-        free(serial);
-        return 0;
-    }
-    // return a list of all connected devices
-    if (!strcmp(service, "devices")) {
-        char buffer[4096];
-        memset(buf, 0, sizeof(buf));
-        memset(buffer, 0, sizeof(buffer));
-        D("Getting device list \n");
-        list_transports(buffer, sizeof(buffer));
-        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
-        D("Wrote device list \n");
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-
-    // add a new TCP transport, device or emulator
-    if (!strncmp(service, "connect:", 8)) {
-        char buffer[4096];
-        char* host = service + 8;
-        if (!strncmp(host, "emu:", 4)) {
-            connect_emulator(host + 4, buffer, sizeof(buffer));
-        } else {
-            connect_device(host, buffer, sizeof(buffer));
-        }
-        // Send response for emulator and device
-        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-
-    // remove TCP transport
-    if (!strncmp(service, "disconnect:", 11)) {
-        char buffer[4096];
-        memset(buffer, 0, sizeof(buffer));
-        char* serial = service + 11;
-        if (serial[0] == 0) {
-            // disconnect from all TCP devices
-            unregister_all_tcp_transports();
-        } else {
-            char hostbuf[100];
-            // assume port 26101 if no port is specified
-            if (!strchr(serial, ':')) {
-                snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:26101", serial);
-                serial = hostbuf;
-            }
-            atransport *t = find_transport(serial);
-
-            if (t) {
-                unregister_transport(t);
-            } else {
-                snprintf(buffer, sizeof(buffer), "No such device %s", serial);
-            }
-        }
-
-        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-
-    // returns our value for SDB_SERVER_VERSION
-    if (!strcmp(service, "version")) {
-        char version[12];
-        snprintf(version, sizeof version, "%04x", SDB_SERVER_VERSION);
-        snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-
-    if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
-        char *out = "unknown";
-         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-       if (transport && transport->serial) {
-            out = transport->serial;
-        }
-        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-    // indicates a new emulator instance has started
-       if (!strncmp(service,"emulator:",9)) { /* tizen specific */
-           char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR);
-           int  port = 0;
-
-           if (tmp == NULL) {
-               port = atoi(service+9);
-           } else {
-               port = atoi(tmp);
-               tmp = strtok(NULL, DEVICEMAP_SEPARATOR);
-               if (tmp != NULL) {
-                   local_connect(port, tmp);
-               }
-           }
-           local_connect(port, NULL);
-        return 0;
-    }
-
-    if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
-        char *local, *remote, *err;
-        int r;
-        atransport *transport;
-
-        int createForward = strncmp(service,"kill",4);
-
-        local = service + (createForward ? 8 : 12);
-        remote = strchr(local,';');
-        if(remote == 0) {
-            sendfailmsg(reply_fd, "malformed forward spec");
-            return 0;
-        }
-
-        *remote++ = 0;
-        if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
-            sendfailmsg(reply_fd, "malformed forward spec");
-            return 0;
-        }
-
-        transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
-        if (!transport) {
-            sendfailmsg(reply_fd, err);
-            return 0;
-        }
-
-        if (createForward) {
-            r = install_listener(local, remote, transport);
-        } else {
-            r = remove_listener(local, remote, transport);
-        }
-        if(r == 0) {
-                /* 1st OKAY is connect, 2nd OKAY is status */
-            writex(reply_fd, "OKAYOKAY", 8);
-            return 0;
-        }
-
-        if (createForward) {
-            sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
-        } else {
-            sendfailmsg(reply_fd, "cannot remove listener");
-        }
-        return 0;
-    }
-
-    if(!strncmp(service,"get-state",strlen("get-state"))) {
-        transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
-        char *state = connection_state_name(transport);
-        snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
-        writex(reply_fd, buf, strlen(buf));
-        return 0;
-    }
-    return -1;
+    FDEVENT_SET(&fdevent_wakeup_fde, FDE_READ);
 }
 
 int main(int argc, char **argv)
 {
-    sdb_trace_init();
+    log_init();
     sdb_sysdeps_init();
+    init_map();
 
     return process_cmdline(argc - 1, argv + 1);
 }
index 16964b09e679772ebeebc469d7d518314a3fd689..70733dc73ceb1727363b74457320c7f2f2462133 100755 (executable)
--- a/src/sdb.h
+++ b/src/sdb.h
 
 #include <limits.h>
 
+#include "linkedlist.h"
 #include "transport.h"  /* readx(), writex() */
 #include "sdb_usb.h"
-
-#define MAX_PAYLOAD 4096
-
-#define A_SYNC 0x434e5953
-#define A_CNXN 0x4e584e43
-#define A_OPEN 0x4e45504f
-#define A_OKAY 0x59414b4f
-#define A_CLSE 0x45534c43
-#define A_WRTE 0x45545257
-
-#define A_VERSION 0x01000000        // SDB protocol version
-
-#define SDB_VERSION_MAJOR 2       // Used for help/version information
-#define SDB_VERSION_MINOR 2         // Used for help/version information
-
-#define SDB_SERVER_VERSION    5    // Increment this when we want to force users to start a new sdb server
-
-typedef struct amessage amessage;
-typedef struct apacket apacket;
-typedef struct asocket asocket;
-typedef struct alistener alistener;
-typedef struct aservice aservice;
-typedef struct atransport atransport;
-typedef struct adisconnect  adisconnect;
-
-struct amessage {
-    unsigned command;       /* command identifier constant      */
-    unsigned arg0;          /* first argument                   */
-    unsigned arg1;          /* second argument                  */
-    unsigned data_length;   /* length of payload (0 is allowed) */
-    unsigned data_check;    /* checksum of data payload         */
-    unsigned magic;         /* command ^ 0xffffffff             */
-};
-
-struct apacket
-{
-    apacket *next;
-
-    unsigned len;
-    unsigned char *ptr;
-
-    amessage msg;
-    unsigned char data[MAX_PAYLOAD];
-};
-
-/* An asocket represents one half of a connection between a local and
-** remote entity.  A local asocket is bound to a file descriptor.  A
-** remote asocket is bound to the protocol engine.
-*/
-struct asocket {
-        /* chain pointers for the local/remote list of
-        ** asockets that this asocket lives in
-        */
-    asocket *next;
-    asocket *prev;
-
-        /* the unique identifier for this asocket
-        */
-    unsigned id;
-
-        /* flag: set when the socket's peer has closed
-        ** but packets are still queued for delivery
-        */
-    int    closing;
-
-        /* flag: quit sdbd when both ends close the
-        ** local service socket
-        */
-    int    exit_on_close;
-
-        /* the asocket we are connected to
-        */
-
-    asocket *peer;
-
-        /* For local asockets, the fde is used to bind
-        ** us to our fd event system.  For remote asockets
-        ** these fields are not used.
-        */
-    fdevent fde;
-    int fd;
-
-        /* queue of apackets waiting to be written
-        */
-    apacket *pkt_first;
-    apacket *pkt_last;
-
-        /* enqueue is called by our peer when it has data
-        ** for us.  It should return 0 if we can accept more
-        ** data or 1 if not.  If we return 1, we must call
-        ** peer->ready() when we once again are ready to
-        ** receive data.
-        */
-    int (*enqueue)(asocket *s, apacket *pkt);
-
-        /* ready is called by the peer when it is ready for
-        ** us to send data via enqueue again
-        */
-    void (*ready)(asocket *s);
-
-        /* close is called by the peer when it has gone away.
-        ** we are not allowed to make any further calls on the
-        ** peer once our close method is called.
-        */
-    void (*close)(asocket *s);
-
-        /* socket-type-specific extradata */
-    void *extra;
-
-       /* A socket is bound to atransport */
-    atransport *transport;
-};
-
-
-/* the adisconnect structure is used to record a callback that
-** will be called whenever a transport is disconnected (e.g. by the user)
-** this should be used to cleanup objects that depend on the
-** transport (e.g. remote sockets, listeners, etc...)
-*/
-struct  adisconnect
-{
-    void        (*func)(void*  opaque, atransport*  t);
-    void*         opaque;
-    adisconnect*  next;
-    adisconnect*  prev;
-};
-
-
-/* a transport object models the connection to a remote device or emulator
-** there is one transport per connected device/emulator. a "local transport"
-** connects through TCP (for the emulator), while a "usb transport" through
-** USB (for real devices)
-**
-** note that kTransportHost doesn't really correspond to a real transport
-** object, it's a special value used to indicate that a client wants to
-** connect to a service implemented within the SDB server itself.
-*/
-typedef enum transport_type {
-        kTransportUsb,
-        kTransportLocal,
-        kTransportAny,
-        kTransportHost,
-} transport_type;
-
-struct atransport
-{
-    atransport *next;
-    atransport *prev;
-
-    int (*read_from_remote)(apacket *p, atransport *t);
-    int (*write_to_remote)(apacket *p, atransport *t);
-    void (*close)(atransport *t);
-    void (*kick)(atransport *t);
-
-    int fd;
-    int transport_socket;
-    fdevent transport_fde;
-    int ref_count;
-    unsigned sync_token;
-    int connection_state;
-    transport_type type;
-
-        /* usb handle or socket fd as needed */
-    usb_handle *usb;
-    int sfd;
-
-        /* used to identify transports for clients */
-    char *serial;
-    char *product;
-    int sdb_port; // Use for emulators (local transport)
-    char *device_name; // for connection explorer
-
-        /* a list of adisconnect callbacks called when the transport is kicked */
-    int          kicked;
-    adisconnect  disconnects;
-};
-
-
-/* A listener is an entity which binds to a local port
-** and, upon receiving a connection on that port, creates
-** an asocket to connect the new local connection to a
-** specific remote service.
-**
-** TODO: some listeners read from the new connection to
-** determine what exact service to connect to on the far
-** side.
-*/
-struct alistener
-{
-    alistener *next;
-    alistener *prev;
-
-    fdevent fde;
-    int fd;
-
-    const char *local_name;
-    const char *connect_to;
-    atransport *transport;
-    adisconnect  disconnect;
-};
-
-
-void print_packet(const char *label, apacket *p);
-
-asocket *find_local_socket(unsigned id);
-void install_local_socket(asocket *s);
-void remove_socket(asocket *s);
-void close_all_sockets(atransport *t);
-
-#define  LOCAL_CLIENT_PREFIX  "emulator-"
-
-asocket *create_local_socket(int fd);
-asocket *create_local_service_socket(const char *destination);
-
-asocket *create_remote_socket(unsigned id, atransport *t);
-void connect_to_remote(asocket *s, const char *destination);
-void connect_to_smartsocket(asocket *s);
-
-void fatal(const char *fmt, ...);
-void fatal_errno(const char *fmt, ...);
-
-void handle_packet(apacket *p, atransport *t);
-void send_packet(apacket *p, atransport *t);
+#include "log.h"
+#include "sdb_map.h"
 
 int sdb_main(int is_daemon, int server_port);
 
-
-/* transports are ref-counted
-** get_device_transport does an acquire on your behalf before returning
-*/
-void init_transport_registration(void);
-int find_transports(char **serial, const char *prefix);
-int  list_transports(char *buf, size_t  bufsize);
-void update_transports(void);
-
-asocket*  create_device_tracker(void);
-
-/* Obtain a transport from the available transports.
-** If state is != CS_ANY, only transports in that state are considered.
-** If serial is non-NULL then only the device with that serial will be chosen.
-** If no suitable transport is found, error is set.
-*/
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
-void   add_transport_disconnect( atransport*  t, adisconnect*  dis );
-void   remove_transport_disconnect( atransport*  t, adisconnect*  dis );
-void   run_transport_disconnects( atransport*  t );
-void   kick_transport( atransport*  t );
-
-/* initialize a transport object's func pointers and state */
-int get_available_local_transport_index();
-int  init_socket_transport(atransport *t, int s, int port, int local);
-void init_usb_transport(atransport *t, usb_handle *usb, int state);
-void close_usb_devices();
-
-
-/* cause new transports to be init'd and added to the list */
-void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name);
-
-/* these should only be used for the "sdb disconnect" command */
-void unregister_transport(atransport *t);
-void unregister_all_tcp_transports();
-
-void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
-
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb);
-
-atransport *find_transport(const char *serial);
-atransport* find_emulator_transport_by_sdb_port(int sdb_port);
-
-int service_to_fd(const char *name);
-asocket *host_service_to_socket(const char*  name, const char *serial);
-
-/* packet allocator */
-apacket *get_apacket(void);
-void put_apacket(apacket *p);
-
-int check_header(apacket *p);
-int check_data(apacket *p);
-
-/* define SDB_TRACE to 1 to enable tracing support, or 0 to disable it */
-
-#define  SDB_TRACE    1
-
-/* IMPORTANT: if you change the following list, don't
- * forget to update the corresponding 'tags' table in
- * the sdb_trace_init() function implemented in sdb.c
- */
-typedef enum {
-    TRACE_SDB = 0,
-    TRACE_SOCKETS,
-    TRACE_PACKETS,
-    TRACE_TRANSPORT,
-    TRACE_RWX,
-    TRACE_USB,
-    TRACE_SYNC,
-    TRACE_SYSDEPS,
-    TRACE_JDWP,
-    TRACE_SERVICES,
-    TRACE_PROPERTIES
-} SdbTrace;
-
-#if SDB_TRACE
-
-#define DQ(...) ((void)0)
-
-
-  extern int     sdb_trace_mask;
-  extern unsigned char    sdb_trace_output_count;
-  void    sdb_trace_init(void);
-
-#  define SDB_TRACING  ((sdb_trace_mask & (1 << TRACE_TAG)) != 0)
-
-  /* you must define TRACE_TAG before using this macro */
-#  define  D(...)                                      \
-        do {                                           \
-            if (SDB_TRACING) {                         \
-                int save_errno = errno;                \
-                sdb_mutex_lock(&D_lock);               \
-                fprintf(stderr, "%s::%s():",           \
-                        __FILE__, __FUNCTION__);       \
-                errno = save_errno;                    \
-                fprintf(stderr, __VA_ARGS__ );         \
-                fflush(stderr);                        \
-                sdb_mutex_unlock(&D_lock);             \
-                errno = save_errno;                    \
-           }                                           \
-        } while (0)
-#  define  DR(...)                                     \
-        do {                                           \
-            if (SDB_TRACING) {                         \
-                int save_errno = errno;                \
-                sdb_mutex_lock(&D_lock);               \
-                errno = save_errno;                    \
-                fprintf(stderr, __VA_ARGS__ );         \
-                fflush(stderr);                        \
-                sdb_mutex_unlock(&D_lock);             \
-                errno = save_errno;                    \
-           }                                           \
-        } while (0)
-#else
-#  define  D(...)          ((void)0)
-#  define  DR(...)         ((void)0)
-#  define  SDB_TRACING     0
-#endif
-
-
-#if !TRACE_PACKETS
-#define print_packet(tag,p) do {} while (0)
-#endif
-
-
-/* sdb and sdbd are coexisting on the target, so use 26099 for sdb
- * to avoid conflicting with sdbd's usage of 26098
- */
-#define DEFAULT_SDB_PORT 26099 /* tizen specific */
-#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 /* tizen specific */
-
-void local_init(int port);
-int  local_connect(int  port, const char *device_name);
-int  local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name);
-
-
 unsigned host_to_le32(unsigned n);
 int sdb_commandline(int argc, char **argv);
 
-int connection_state(atransport *t);
+int connection_state(TRANSPORT *t);
 
-#define CS_ANY       -1
-#define CS_OFFLINE    0
-#define CS_BOOTLOADER 1
-#define CS_DEVICE     2
-#define CS_HOST       3
-#define CS_RECOVERY   4
-#define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
-#define CS_SIDELOAD   6
-
-extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
-#define CHUNK_SIZE (64*1024)
-
-int sendfailmsg(int fd, const char *reason);
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
+void sdb_cleanup(void);
 
-void register_device_name(const char *device_type, const char *device_name, int port);
-int get_devicename_from_shdmem(int port, char *device_name);
 #endif
index 62dadc303eed9a904dff8247ad9bd636de039f7a..1aa4910f39440a6ddaa93fce3f8dbdcf94d5be16 100644 (file)
 
 #define  TRACE_TAG  TRACE_SDB
 #include "sdb_client.h"
+#include "log.h"
 
 static int switch_socket_transport(int fd, void** extra_args);
-static int send_service_with_length(int fd, const char* service);
-static int sdb_status(int fd);
+static int __inline__ write_msg_size(int fd, int size, int host_fd);
 
-static int send_service_with_length(int fd, const char* service) {
+void sendokmsg(int fd, const char *msg)
+{
+    char buf[1024];
+    snprintf(buf, sizeof(buf), "OKAY%04x%s", (unsigned)strlen(msg), msg);
+    writex(fd, buf, strlen(buf));
+}
+
+void sendfailmsg(int fd, const char *reason)
+{
+    char buf[1024];
+    snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(reason), reason);
+    writex(fd, buf, strlen(buf));
+}
+
+int send_service_with_length(int fd, const char* service, int host_fd) {
 
     int len;
     len = strlen(service);
 
     if(len < 1) {
-        fprintf(stderr,"error: service name is empty\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: service name is empty\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: service name is empty\n");
+        }
         return -1;
     }
     else if (len > 1024) {
-        fprintf(stderr,"error: service name too long\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: service name too long\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: service name too long\n");
+        }
         return -1;
     }
 
-    if(write_msg_size(fd, len) < 0) {
+    if(write_msg_size(fd, len, host_fd) < 0) {
+        D("fail to write msg size\n");
+        if(host_fd != 0) {
+            sendfailmsg(host_fd, "fail to write msg size\n");
+        }
         return -1;
     }
 
     if(writex(fd, service, len)) {
-        fprintf(stderr,"error: write failure during connection\n");
+        D("error: write failure during connection\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: write failure during connection\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: write failure during connection\n");
+        }
         return -1;
     }
 
@@ -68,19 +102,14 @@ static int switch_socket_transport(int fd, void** extra_args)
 
     get_host_prefix(service, sizeof service, ttype, serial, transport);
 
-    if(!strcmp(service, PREFIX_HOST)) {
-        // no switch necessary
-        return 0;
-    }
-
-    if(send_service_with_length(fd, service) < 0) {
+    if(send_service_with_length(fd, service, 0) < 0) {
         sdb_close(fd);
         return -1;
     }
 
     D("Switch transport in progress\n");
 
-    if(sdb_status(fd)) {
+    if(sdb_status(fd, 0)) {
         sdb_close(fd);
         D("Switch transport failed\n");
         return -1;
@@ -123,7 +152,7 @@ int sdk_launch_exist(void* extargv) {
 
     const char* expected_result = "/usr/sbin/sdk_launch";
 
-    if(!strncmp(expected_result, query_result, sizeof(expected_result))) {
+    if(!strncmp(expected_result, query_result, strlen(expected_result))) {
         return 1;
     }
     return 0;
@@ -172,14 +201,17 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) {
     null = strchr(ver_num, '-');
 
     if(null == NULL) {
-        fprintf(stderr, "error: cannot parse sdbd version\n");
-        return -1;
+        goto error;
     }
     *null = '\0';
 
     D("sdbd version: %s\n", ver_num);
 
     null = strchr(ver_num, '.');
+    if(null == NULL) {
+        goto error;
+    }
+
     *null = '\0';
     version = atoi(ver_num);
     if(version > first) {
@@ -191,6 +223,10 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) {
     ver_num = ++null;
 
     null = strchr(ver_num, '.');
+    if(null == NULL) {
+        goto error;
+    }
+
     version = atoi(ver_num);
     *null = '\0';
     if(version > middle) {
@@ -206,14 +242,23 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) {
         return 1;
     }
     return 0;
+
+error:
+    LOG_ERROR("wrong version format %s", ver);
+    return -1;
 }
 
-static int sdb_status(int fd)
+int sdb_status(int fd, int host_fd)
 {
     unsigned char buf[5];
 
     if(readx(fd, buf, 4)) {
-        fprintf(stderr,"error: protocol fault (no status)\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: protocol fault (no status)\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: protocol fault (no status)\n");
+        }
         return -1;
     }
 
@@ -222,29 +267,59 @@ static int sdb_status(int fd)
     }
 
     if(memcmp(buf, "FAIL", 4)) {
-        fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n",
-                buf[0], buf[1], buf[2], buf[3]);
+        if(host_fd == 0) {
+            fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n",
+                    buf[0], buf[1], buf[2], buf[3]);
+        }
+        else {
+            char err_msg[255];
+            snprintf(err_msg, sizeof(err_msg), "error: protocol fault (status %02x %02x %02x %02x?!)\n",
+                    buf[0], buf[1], buf[2], buf[3]);
+            sendfailmsg(host_fd, err_msg);
+        }
         return -1;
     }
 
     int len = read_msg_size(fd);
     if(len < 0) {
-        fprintf(stderr,"error: protocol fault (status len)\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: protocol fault (status len)\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: protocol fault (status len)\n");
+        }
         return -1;
     }
-    if(len > 255) len = 255;
+    if(len > 254) len = 254;
 
 
     char error[255];
     if(readx(fd, error, len)) {
-        fprintf(stderr,"error: protocol fault (status read)\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: protocol fault (status read)\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: protocol fault (status read)\n");
+        }
         return -1;
     }
     error[len] = '\0';
-    fprintf(stderr,"error: %s\n", error);
+    if(host_fd == 0) {
+        fprintf(stderr,"error msg: %s\n", error);
+    }
+    else {
+        char err_msg[255];
+        snprintf(err_msg, sizeof(err_msg), "error msg: %s\n", error);
+        sendfailmsg(host_fd, err_msg);
+    }
     return -1;
 }
 
+/**
+ * First check whether host service or transport service,
+ * If transport service, send transport prefix. Then, do the service.
+ * If host service, do the service. does not have to get transport.
+ */
 int _sdb_connect(const char *service, void** ext_args)
 {
     int fd;
@@ -253,22 +328,23 @@ int _sdb_connect(const char *service, void** ext_args)
 
     int server_port = *(int*)ext_args[2];
 
-    fd = socket_loopback_client(server_port, SOCK_STREAM);
+    fd = sdb_host_connect("127.0.0.1", server_port, SOCK_STREAM);
     if(fd < 0) {
         D("error: cannot connect to daemon\n");
         return -2;
     }
 
+    //If service is not host, send transport_prefix
     if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd, ext_args)) {
         return -1;
     }
 
-    if(send_service_with_length(fd, service) < 0) {
+    if(send_service_with_length(fd, service, 0) < 0) {
         sdb_close(fd);
         return -1;
     }
 
-    if(sdb_status(fd)) {
+    if(sdb_status(fd, 0)) {
         sdb_close(fd);
         return -1;
     }
@@ -277,7 +353,7 @@ int _sdb_connect(const char *service, void** ext_args)
     return fd;
 }
 
-int __inline__ read_msg_size(int fd) {
+int read_msg_size(int fd) {
     char buf[5];
 
     if(readx(fd, buf, 4)) {
@@ -288,17 +364,27 @@ int __inline__ read_msg_size(int fd) {
     return strtoul(buf, NULL, 16);
 }
 
-int __inline__ write_msg_size(int fd, int size) {
+static int __inline__ write_msg_size(int fd, int size, int host_fd) {
     char tmp[5];
     snprintf(tmp, sizeof tmp, "%04x", size);
 
     if(writex(fd, tmp, 4)) {
-        fprintf(stderr,"error: write msg size failure\n");
+        D("error: write msg size failure\n");
+        if(host_fd == 0) {
+            fprintf(stderr,"error: write msg size failure\n");
+        }
+        else {
+            sendfailmsg(host_fd, "error: write msg size failure\n");
+        }
         return -1;
     }
     return 1;
 }
 
+/**
+ * First, check the host version.
+ * Then, send the service using _sdb_connect
+ */
 int sdb_connect(const char *service, void** ext_args)
 {
     // first query the sdb server's version
@@ -336,7 +422,7 @@ int sdb_connect(const char *service, void** ext_args)
         }
 
         if(version != SDB_SERVER_VERSION) {
-            printf("sdb server is out of date.  killing...\n");
+            printf("client version: %d, server version: %d\nsdb server is out of date.  killing...\n", version, SDB_SERVER_VERSION);
             fd = _sdb_connect("host:kill", ext_args);
             sdb_close(fd);
 
@@ -370,7 +456,7 @@ int sdb_command(const char *service, void** extra_args)
         return -1;
     }
 
-    if(sdb_status(fd)) {
+    if(sdb_status(fd, 0)) {
         sdb_close(fd);
         return -1;
     }
@@ -418,7 +504,7 @@ void get_host_prefix(char* prefix, int size, transport_type ttype, const char* s
         }
     }
     else {
-        char* temp_prefix;
+        char* temp_prefix = NULL;
         if(ttype == kTransportUsb) {
             if(host_type == host) {
                 temp_prefix = (char*)PREFIX_HOST_USB;
@@ -435,12 +521,9 @@ void get_host_prefix(char* prefix, int size, transport_type ttype, const char* s
                 temp_prefix = (char*)PREFIX_TRANSPORT_LOCAL;
             }
         }
-        else if(ttype == kTransportHost) {
-            temp_prefix = (char*)PREFIX_HOST;
-        }
         else if(ttype == kTransportAny) {
             if(host_type == host) {
-                temp_prefix = (char*)PREFIX_HOST;
+                temp_prefix = (char*)PREFIX_HOST_ANY;
             }
             else if(host_type == transport) {
                 temp_prefix = (char*)PREFIX_TRANSPORT_ANY;
index 04d9da2038a925d3b05ce532b971656a8eb1b673..31be98e6315133ee51adbd8403a15e6e72dda958 100644 (file)
 #ifndef _SDB_CLIENT_H_
 #define _SDB_CLIENT_H_
 
-#include "sdb.h"
 #include "sdb_constants.h"
+#include "common_modules.h"
 
 // debug launch pad is applied after sdbd 2.2.3
 #define SDB_HIGHER_THAN_2_2_3(extargv) sdk_launch_exist(extargv)
 
+int send_service_with_length(int fd, const char* service, int host_fd);
+int sdb_status(int fd, int host_fd);
+
 /* connect to sdb, connect to the named service, and return
 ** a valid fd for interacting with that service upon success
 ** or a negative number on failure
@@ -64,8 +67,10 @@ int sdk_launch_exist(void* extargv);
 ** return 0 in the event of OKAY, -1 in the event of FAIL
 ** or protocol error
 */
-int __inline__ read_msg_size(int fd);
-int __inline__ write_msg_size(int fd, int size);
+int read_msg_size(int fd);
+
+void sendokmsg(int fd, const char *msg);
+void sendfailmsg(int fd, const char *reason);
 
 void get_host_prefix(char* prefix, int size, transport_type ttype, const char* serial, HOST_TYPE host_type);
 #endif
index 0c4acc9a39ba2da92bfd5c3b963dd28215ef0513..57a9e633ac0695b6d5c3369d71b6b2cdf83b66ae 100644 (file)
@@ -35,6 +35,7 @@
     const char* QUOTE_CHAR = " \"\\()";
 
     const char* PREFIX_HOST = "host:";
+    const char* PREFIX_HOST_ANY = "host-any:";
     const char* PREFIX_HOST_USB = "host-usb:";
     const char* PREFIX_HOST_LOCAL = "host-local:";
     const char* PREFIX_HOST_SERIAL = "host-serial:";
     const int COMMANDLINE_CONNECT_MAX_ARG = 1;
     const int COMMANDLINE_CONNECT_MIN_ARG = 1;
 
+    const char* COMMANDLINE_DEVICE_CON_NAME = "device_con";
+    const char* COMMANDLINE_DEVICE_CON_DESC[] = {
+            "connect to a remote device"
+    };
+    const int COMMANDLINE_DEVICE_CON_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DEVICE_CON_DESC, char*);
+    const char* COMMANDLINE_DEVICE_CON_ARG_DESC = "<host> <device serial-number>";
+    const int COMMANDLINE_DEVICE_CON_MAX_ARG = 2;
+    const int COMMANDLINE_DEVICE_CON_MIN_ARG = 2;
+
     const char* COMMANDLINE_GSERIAL_NAME = "get-serialno";
     const char* COMMANDLINE_GSERIAL_DESC[] = {
             "print: <serial-number>"
 
     const char* COMMANDLINE_GSTATE_NAME = "get-state";
     const char* COMMANDLINE_GSTATE_DESC[] = {
-            "print: offline | bootloader | device"
+            "print: offline | locked | device"
     };
     const int COMMANDLINE_GSTATE_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_GSTATE_DESC, char*);
     const int COMMANDLINE_GSTATE_MAX_ARG = 0;
     const int COMMANDLINE_EMULATOR_HAS_ARG = 0;
 
     const char* COMMANDLINE_ERROR_ARG_MISSING = "argument %s is missing for command %s";
+
+    const char* STATE_OFFLINE = "offline";
+    const char* STATE_BOOTLOADER = "bootloader";
+    const char* STATE_DEVICE = "device";
+    const char* STATE_HOST = "host";
+    const char* STATE_RECOVERY = "recovery";
+    const char* STATE_SIDELOAD = "sideload";
+    const char* STATE_NOPERM = "no permissions";
+    const char* STATE_LOCKED = "locked";
+    const char* STATE_UNKNOWN = "unknown";
+
+    const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET = "more than one target";
+    const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL = "more than one emulator";
+    const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV = "more than one device";
+    const char* TRANSPORT_ERR_TARGET_OFFLINE = "target offline";
+    const char* TRANSPORT_ERR_TARGET_NOT_FOUND = "target not found";
index caa88da69e71acb23a223c41b3e1584e47f7d49a..d0dda5536787e929b638d07b126c54e11ed5a1a1 100644 (file)
@@ -46,6 +46,7 @@ typedef enum host_type HOST_TYPE;
     extern const char* QUOTE_CHAR;
 
     extern const char* PREFIX_HOST;
+    extern const char* PREFIX_HOST_ANY;
     extern const char* PREFIX_HOST_USB;
     extern const char* PREFIX_HOST_LOCAL;
     extern const char* PREFIX_HOST_SERIAL;
@@ -89,6 +90,13 @@ typedef enum host_type HOST_TYPE;
     extern const int COMMANDLINE_CONNECT_MAX_ARG;
     extern const int COMMANDLINE_CONNECT_MIN_ARG;
 
+    extern const char* COMMANDLINE_DEVICE_CON_NAME;
+    extern const char* COMMANDLINE_DEVICE_CON_DESC[];
+    extern const int COMMANDLINE_DEVICE_CON_DESC_SIZE;
+    extern const char* COMMANDLINE_DEVICE_CON_ARG_DESC;
+    extern const int COMMANDLINE_DEVICE_CON_MAX_ARG;
+    extern const int COMMANDLINE_DEVICE_CON_MIN_ARG;
+
     extern const char* COMMANDLINE_GSERIAL_NAME;
     extern const char* COMMANDLINE_GSERIAL_DESC[];
     extern const int COMMANDLINE_GSERIAL_DESC_SIZE;
@@ -210,4 +218,20 @@ typedef enum host_type HOST_TYPE;
 
     extern const char* COMMANDLINE_ERROR_ARG_MISSING;
 
+    extern const char* STATE_OFFLINE;
+    extern const char* STATE_BOOTLOADER;
+    extern const char* STATE_DEVICE;
+    extern const char* STATE_HOST;
+    extern const char* STATE_RECOVERY;
+    extern const char* STATE_SIDELOAD;
+    extern const char* STATE_NOPERM;
+    extern const char* STATE_LOCKED;
+    extern const char* STATE_UNKNOWN;
+
+    extern const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET;
+    extern const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL;
+    extern const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV;
+    extern const char* TRANSPORT_ERR_TARGET_OFFLINE;
+    extern const char* TRANSPORT_ERR_TARGET_NOT_FOUND;
+
 #endif /* SDB_CONSTANTS_H_*/
diff --git a/src/sdb_map.c b/src/sdb_map.c
new file mode 100644 (file)
index 0000000..470429f
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#include <stdlib.h>
+#include "sdb_map.h"
+#include "linkedlist.h"
+
+static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key);
+static int default_hash(MAP* this, MAP_KEY key);
+static int default_equal(MAP_KEY key, MAP_KEY node_key);
+static void default_free(void* node);
+
+void initialize_map(MAP* this, int size, int(*hash)(struct map* this, MAP_KEY key),
+        int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data)) {
+
+    if(size < 1) {
+        this->size = DEFAULT_MAP_SIZE;
+    }
+    else {
+        this->size = size;
+    }
+
+    if(equal == NULL) {
+        this->equal = default_equal;
+    }
+    else {
+        this->equal = equal;
+    }
+
+    if(hash == NULL) {
+        this->hash = default_hash;
+    }
+    else {
+        this->hash = hash;
+    }
+
+    if(freedata == NULL) {
+        this->freedata = default_free;
+    }
+    else {
+        this->freedata = freedata;
+    }
+
+    this->map_node_list = (LIST_NODE**)calloc(this->size, sizeof(LIST_NODE*));
+}
+
+static void default_free(void* node) {
+    MAP_NODE* _node = node;
+    if(_node != NULL) {
+        if(_node->value != NULL ) {
+//            free(_node->value);
+        }
+        free(_node);
+    }
+}
+
+static int default_hash(MAP* this, MAP_KEY key) {
+    return key.key_int%(this->size);
+}
+
+static int default_equal(MAP_KEY key, MAP_KEY node_key) {
+    if(key.key_int != node_key.key_int) {
+        return 0;
+    }
+    return 1;
+}
+
+static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key) {
+
+    while(list != NULL) {
+        MAP_NODE* node = list->data;
+        if(this->equal(key, node->key)) {
+            return list;
+        }
+        list = list->next_ptr;
+    }
+
+    return NULL;
+}
+
+void map_put(MAP* this, MAP_KEY key, void* value) {
+
+    int hash_key = this->hash(this, key);
+    LIST_NODE** hash_list = &(this->map_node_list[hash_key]);
+
+    MAP_NODE* node = malloc(sizeof(MAP_NODE));
+    node->key = key;
+    node->value = value;
+
+    LIST_NODE* list_node = find_in_list(this, *hash_list, key);
+    if(list_node == NULL) {
+        prepend(hash_list, (void*)node);
+    }
+    else {
+        this->freedata(list_node->data);
+        list_node->data = node;
+    }
+}
+
+void* map_get(MAP* this, MAP_KEY key) {
+
+    int hash_key = this->hash(this, key);
+    LIST_NODE* hash_list = this->map_node_list[hash_key];
+    LIST_NODE* result_node = find_in_list(this, hash_list, key);
+    if(result_node == NULL) {
+        return NULL;
+    }
+
+    return ((MAP_NODE*)(result_node->data))->value;
+}
+
+void map_remove(MAP* this, MAP_KEY key) {
+
+    int hash_key = this->hash(this, key);
+    LIST_NODE** hash_list = &(this->map_node_list[hash_key]);
+
+    LIST_NODE* result_node = find_in_list(this, *hash_list, key);
+    if(result_node != NULL) {
+        this->freedata(result_node->data);
+        LIST_NODE* prev = result_node->prev_ptr;
+        LIST_NODE* next = result_node->next_ptr;
+
+        if(prev == NULL && next == NULL) {
+            *hash_list = NULL;
+        }
+        else {
+            if(prev != NULL) {
+                prev->next_ptr = next;
+            }
+
+            if(next != NULL) {
+                next->prev_ptr = prev;
+            }
+        }
+
+        free(result_node);
+    }
+}
+
+void map_clear(MAP* this) {
+
+    if(this != NULL) {
+        int i =0;
+        for(; i<this->size; i++) {
+            free_list(this->map_node_list[i], this->freedata);
+        }
+
+        free(this->map_node_list);
+    }
+}
diff --git a/src/sdb_map.h b/src/sdb_map.h
new file mode 100644 (file)
index 0000000..4af7bb9
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef SDB_MAP_H_
+#define SDB_MAP_H_
+
+#include "linkedlist.h"
+
+#define DEFAULT_MAP_SIZE 30
+
+union map_key {
+    int key_int;
+    void* key_void;
+};
+
+typedef union map_key MAP_KEY;
+
+struct map_node {
+    MAP_KEY key;
+    void* value;
+};
+typedef struct map_node MAP_NODE;
+
+struct map {
+    int size;
+    int(*hash)(struct map* this, MAP_KEY key);
+    int(*equal)(MAP_KEY key, MAP_KEY node_key);
+    void(*freedata)(void* data);
+    LIST_NODE** map_node_list;
+};
+typedef struct map MAP;
+
+void initialize_map(MAP* map, int size, int(*hash)(struct map* this, MAP_KEY key),
+        int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data));
+void map_put(MAP* map, MAP_KEY key, void* value);
+void* map_get(MAP* map, MAP_KEY key);
+void map_remove(MAP* this, MAP_KEY key);
+
+#endif /* SDB_MAP_H_ */
index 8b6162c95d6dc703981cc628198a3f4c45bad10f..203def1c4963a4f205a664a079fa3a333ba62f2e 100644 (file)
@@ -31,7 +31,7 @@
 #include "fdevent.h"
 #include "sdb_model.h"
 #include "linkedlist.h"
-#include "sdb.h"
+#include "log.h"
 
 const COMMAND NULL_COMMAND = {
         NULL,
@@ -157,7 +157,7 @@ int parse_opt(int argc, char** argv, LIST_NODE* opt_list, LIST_NODE** result_lis
             INPUT_OPTION* input = (INPUT_OPTION*)malloc(sizeof(INPUT_OPTION));
             input->option = option;
             input->value = value;
-            append(result_list, input);
+            prepend(result_list, input);
 
             argv = argv + local_pass_arg;
             argc = argc - local_pass_arg;
old mode 100644 (file)
new mode 100755 (executable)
index b4e27e8..4a02c6a
 #include "utils.h"
 #include "fdevent.h"
 #include "sdb_constants.h"
-
-#define  TRACE_TAG  TRACE_SOCKETS
+#include "sdb_map.h"
+#include "sdb_client.h"
+#include "sockets.h"
+#include "transport.h"
+#include "log.h"
+#include "listener.h"
 #include "sdb.h"
 
-SDB_MUTEX_DEFINE( socket_list_lock );
-
-static void local_socket_close_locked(asocket *s);
-
-int sendfailmsg(int fd, const char *reason)
-{
-    char buf[9];
-    int len;
-    len = strlen(reason);
-    if(len > 0xffff) len = 0xffff;
-    snprintf(buf, sizeof buf, "FAIL%04x", len);
-    if(writex(fd, buf, 8)) return -1;
-    return writex(fd, reason, len);
-}
+#define  TRACE_TAG  TRACE_SOCKETS
 
-//extern int online;
+static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p);
+static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func);
+static int peer_enqueue(SDB_SOCKET* socket, PACKET* p);
+static void local_socket_destroy(SDB_SOCKET  *s);
+static void remove_socket(void* s);
+static void destroy_socket(void* data);
+static void local_socket_event_func(int fd, unsigned ev, void *_s);
+static unsigned unhex(unsigned char*s, int len);
+static int find_transports(char **serial_out, const char *prefix);
+static void unregister_all_tcp_transports();
+static void connect_emulator(char* host, int port, char* buf, int buf_len);
+
+const unsigned int unsigned_int_bit = sizeof(unsigned int) * 8;
+const unsigned int remote_con_right_padding = ~(~0 << sizeof(unsigned int) * 4);
+const unsigned int remote_con_flag = 1 << (sizeof(unsigned int) * 8 - 1);
+unsigned int remote_con_cur_r_id = 1;
+unsigned int remote_con_cur_l_number = 0;
+const unsigned int remote_con_l_max = 16; // Ox1111
+const unsigned int remote_con_r_max = ~(~0 << (sizeof(unsigned int) * 8 - 5));
+unsigned int remote_con_l_table[16] = {0,};
 
 static unsigned local_socket_next_id = 1;
 
-static asocket local_socket_list = {
-    .next = &local_socket_list,
-    .prev = &local_socket_list,
-};
-
-/* the the list of currently closing local sockets.
-** these have no peer anymore, but still packets to
-** write to their fd.
-*/
-static asocket local_socket_closing_list = {
-    .next = &local_socket_closing_list,
-    .prev = &local_socket_closing_list,
-};
-
-asocket *find_local_socket(unsigned id)
+LIST_NODE* local_socket_list = NULL;
+
+SDB_SOCKET *find_local_socket(unsigned id)
 {
-    asocket *s;
-    asocket *result = NULL;
+    SDB_SOCKET *result = NULL;
 
-    sdb_mutex_lock(&socket_list_lock);
-    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
-        if (s->id == id) {
+
+    LIST_NODE* curptr = local_socket_list;
+    while(curptr != NULL) {
+        SDB_SOCKET* s = curptr->data;
+        curptr = curptr->next_ptr;
+        if(s->local_id == id) {
             result = s;
             break;
         }
     }
-    sdb_mutex_unlock(&socket_list_lock);
 
     return result;
 }
 
-static void
-insert_local_socket(asocket*  s, asocket*  list)
+static void remove_socket(void* s)
 {
-    s->next       = list;
-    s->prev       = s->next->prev;
-    s->prev->next = s;
-    s->next->prev = s;
+    SDB_SOCKET* socket = s;
+    socket->node = NULL;
 }
 
-
-void install_local_socket(asocket *s)
+int local_socket_enqueue(SDB_SOCKET *s, PACKET *p)
 {
-    sdb_mutex_lock(&socket_list_lock);
+    D("LS(%X) local enqueue\n", s->local_id);
 
-    s->id = local_socket_next_id++;
-    insert_local_socket(s, &local_socket_list);
+    if(s->pkt_list == NULL) {
+        int r = local_enqueue(s->fd, p, s, 0);
+        if( r == 0) {
+            //enqueue done normally
+            return 0;
+        }
+        if( r < 0) {
+            //error occurred
+            return 1;
+        }
+    }
+    //wait for next round
+    append(&(s->pkt_list), p);
+    FDEVENT_ADD(&s->fde, FDE_WRITE);
 
-    sdb_mutex_unlock(&socket_list_lock);
+    return 1;
 }
 
-void remove_socket(asocket *s)
+void local_socket_ready(SDB_SOCKET *s)
 {
-    // socket_list_lock should already be held
-    if (s->prev && s->next)
-    {
-        s->prev->next = s->next;
-        s->next->prev = s->prev;
-        s->next = 0;
-        s->prev = 0;
-        s->id = 0;
+    D("local socket ready. LS(%X)\n", s->local_id);
+    if(HAS_SOCKET_STATUS(s, NOTIFY)) {
+        D("local socket notify to the client FD(%d)\n", s->fd);
+        sdb_write(s->fd, "OKAY", 4);
+        REMOVE_SOCKET_STATUS(s, NOTIFY);
     }
+    FDEVENT_ADD(&s->fde, FDE_READ);
 }
 
-void close_all_sockets(atransport *t)
+void local_socket_close(SDB_SOCKET *s)
 {
-    asocket *s;
-
-        /* this is a little gross, but since s->close() *will* modify
-        ** the list out from under you, your options are limited.
-        */
-    sdb_mutex_lock(&socket_list_lock);
-restart:
-    for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
-        if(s->transport == t || (s->peer && s->peer->transport == t)) {
-            local_socket_close_locked(s);
-            goto restart;
-        }
+    D("LS(%X) FD(%d)\n", s->local_id, s->fd);
+    if(HAS_SOCKET_STATUS(s, NOTIFY)) {
+        D("LS(%X) fail to send notify\n", s->local_id);
+        sendfailmsg(s->fd, "closed");
+        REMOVE_SOCKET_STATUS(s, NOTIFY);
     }
-    sdb_mutex_unlock(&socket_list_lock);
-}
-
-static int local_socket_enqueue(asocket *s, apacket *p)
-{
-    D("LS(%d): enqueue %d\n", s->id, p->len);
-
-    p->ptr = p->data;
 
-        /* if there is already data queue'd, we will receive
-        ** events when it's time to write.  just add this to
-        ** the tail
-        */
-    if(s->pkt_first) {
-        goto enqueue;
-    }
 
-        /* write as much as we can, until we
-        ** would block or there is an error/eof
-        */
-    while(p->len > 0) {
-        int r = sdb_write(s->fd, p->ptr, p->len);
-        if(r > 0) {
-            p->len -= r;
-            p->ptr += r;
-            continue;
-        }
-        if((r == 0) || (errno != EAGAIN)) {
-            D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
-            s->close(s);
-            return 1; /* not ready (error) */
-        } else {
-            break;
-        }
+    if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) {
+        send_cmd(0, s->remote_id, A_CLSE, NULL, s->transport);
     }
+    int id = s->local_id;
 
-    if(p->len == 0) {
-        put_apacket(p);
-        return 0; /* ready for more data */
+    if(!s->closing && s->pkt_list != NULL) {
+        s->closing = 1;
+        FDEVENT_DEL(&s->fde, FDE_READ);
+        remove_node(&local_socket_list, s->node, remove_socket);
+        D("LS(%X) pending close\n", id);
     }
-
-enqueue:
-    p->next = 0;
-    if(s->pkt_first) {
-        s->pkt_last->next = p;
-    } else {
-        s->pkt_first = p;
+    else {
+        local_socket_destroy(s);
+        D("LS(%X) closed\n", id);
     }
-    s->pkt_last = p;
-
-        /* make sure we are notified when we can drain the queue */
-    fdevent_add(&s->fde, FDE_WRITE);
-
-    return 1; /* not ready (backlog) */
 }
 
-static void local_socket_ready(asocket *s)
-{
-        /* far side is ready for data, pay attention to
-           readable events */
-    fdevent_add(&s->fde, FDE_READ);
-//    D("LS(%d): ready()\n", s->id);
-}
-
-static void local_socket_close(asocket *s)
-{
-    sdb_mutex_lock(&socket_list_lock);
-    local_socket_close_locked(s);
-    sdb_mutex_unlock(&socket_list_lock);
+static void destroy_socket(void* data) {
+    SDB_SOCKET* socket = data;
+    socket->node = NULL;
+
+    if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) {
+        free(socket->read_packet);
+        unsigned int id = socket->local_id & ~remote_con_flag;
+
+        TRANSPORT* t = socket->transport;
+        if(t != NULL) {
+            LIST_NODE* node = t->remote_cnxn_socket;
+            while(node != NULL) {
+                SDB_SOCKET* s = node->data;
+                node = node->next_ptr;
+                if(s == socket) {
+                    remove_node(&(t->remote_cnxn_socket), s->node, no_free);
+                    break;
+                }
+            }
+        }
+        remote_con_l_table[id] = 0;
+    }
+    socket->local_id = 0;
+    free(socket);
 }
 
 // be sure to hold the socket list lock when calling this
-static void local_socket_destroy(asocket  *s)
+static void local_socket_destroy(SDB_SOCKET  *s)
 {
-    apacket *p, *n;
-    int exit_on_close = s->exit_on_close;
+    D("LS(%X) FD(%d)\n", s->local_id, s->fd);
 
-    D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
-
-        /* IMPORTANT: the remove closes the fd
+        /* IMPORTANT: fdevent_remove closes the fd
         ** that belongs to this socket
         */
     fdevent_remove(&s->fde);
 
         /* dispose of any unwritten data */
-    for(p = s->pkt_first; p; p = n) {
-        D("LS(%d): discarding %d bytes\n", s->id, p->len);
-        n = p->next;
-        put_apacket(p);
+    free_list(s->pkt_list, put_apacket);
+    s->pkt_list = NULL;
+
+    if(s->node != NULL) {
+        remove_node(&local_socket_list, s->node, destroy_socket);
+    }
+    else {
+        destroy_socket(s);
+    }
+}
+
+    //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared
+#if 0
+//remote_ls_id is a socket in the remote server.
+//local_ls_id is a socket of fowarding socket
+// left half is local_ls_id and right half is remote_ls_id.
+static unsigned int encoding_ls_id(unsigned int remote_ls_id, unsigned int local_ls_id) {
+    D("LS_R(%X), LS_L(%X)\n", remote_ls_id, local_ls_id);
+    return remote_ls_id | local_ls_id;
+}
+
+static void send_remote_con_packet(SDB_SOCKET* sock, PACKET* p) {
+
+    //message and data are filled send it to the target.
+    if(p->msg.command != A_CNXN) {
+        //A_CNXN does not have to encode local socket id.
+        p->msg.arg0 = encoding_ls_id(p->msg.arg0, sock->local_id);
+        LOG_INFO("LS_L(%X) LS_E(%X) encoding done\n", sock->local_id, p->msg.arg0);
+    }
+    else {
+        //for notifying transport that it has remaning socket which wait for CNXN
+        LOG_INFO("LS_L(%X) message was CNXN\n", sock->local_id);
+        append(&sock->transport->remote_cnxn_socket, sock);
     }
-    remove_socket(s);
-    free(s);
 
-    if (exit_on_close) {
-        D("local_socket_destroy: exiting\n");
-        exit(1);
+    encoding_packet(p);
+    //send packet to the target transport
+    if(sock->transport->write_to_remote(p, sock->transport)) {
+        LOG_ERROR("fail to write packet\n");
+        dump_packet("write error", "remote_con_enqueue", p);
     }
 }
 
+static int remote_con_enqueue(SDB_SOCKET* socket, PACKET* p) {
+    LOG_INFO("LS_L(%X)\n", socket->local_id);
 
-static void local_socket_close_locked(asocket *s)
-{
-    D("entered. LS(%d) fd=%d\n", s->id, s->fd);
-    if(s->peer) {
-        D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
-          s->id, s->peer->id, s->peer->fd);
-        s->peer->peer = 0;
-        // tweak to avoid deadlock
-        if (s->peer->close == local_socket_close) {
-            local_socket_close_locked(s->peer);
-        } else {
-            s->peer->close(s->peer);
+    PACKET* read_p = socket->read_packet;
+
+    if(read_p->len == 0 && p->len >= sizeof(MESSAGE)) {
+        if(p->len == sizeof(MESSAGE) + p->msg.data_length) {
+            //send packet directly without memcpy.
+            if(check_header(p) || check_data(read_p)) {
+                LOG_ERROR("bad packet: terminated (data)\n");
+                dump_packet("bad packet", "remote_con_enqueue", read_p);
+                put_apacket(p);
+                return 0;
+            }
+
+            LOG_INFO("packet is complete send directly\n");
+            send_remote_con_packet(socket, p);
+            put_apacket(p);
+            return 1;
         }
-        s->peer = 0;
     }
 
-        /* If we are already closing, or if there are no
-        ** pending packets, destroy immediately
-        */
-    if (s->closing || s->pkt_first == NULL) {
-        int   id = s->id;
-        local_socket_destroy(s);
-        D("LS(%d): closed\n", id);
-        return;
+    while(p != NULL) {
+        //read MESSAGE
+        if(read_p->len < sizeof(MESSAGE)) {
+            int read_length = 0;
+            int msg_done = 1;
+            if(read_p->len + p->len >= sizeof(MESSAGE)) {
+                read_length = sizeof(MESSAGE) - read_p->len;
+            }
+            else {
+                read_length = p->len;
+                msg_done = 0;
+            }
+            memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length);
+            p->ptr += read_length;
+            p->len -= read_length;
+            read_p->len += read_length;
+            if(msg_done) {
+                LOG_INFO("message reading done\n");
+
+                #if 0 && defined HAVE_BIG_ENDIAN
+                    D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
+                            socket_p->msg.command, socket_p->msg.arg0, socket_p->msg.arg1, socket_p->msg.data_length, socket_p->msg.data_check, socket_p->msg.magic);
+                #endif
+                if(check_header(read_p)) {
+                    LOG_ERROR("bad header: terminated (data)\n");
+                    dump_packet("bad header", "remote_con_enqueue", read_p);
+                    read_p->len = 0;
+                    put_apacket(p);
+                    return 0;
+                }
+            }
+            else {
+                //wait for next round
+                LOG_INFO("wait for next round while reading message\n");
+                put_apacket(p);
+                return 0;
+            }
+        }
+        //read data
+        unsigned data_length = read_p->msg.data_length + sizeof(MESSAGE);
+        int read_length = 0;
+        int data_done = 1;
+        if(read_p->len + p->len >= data_length) {
+            read_length = data_length - read_p->len;
+        }
+        else {
+            read_length = p->len;
+            data_done = 0;
+        }
+
+        memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length);
+        p->ptr += read_length;
+        p->len -= read_length;
+        read_p->len += read_length;
+
+        if(data_done) {
+            LOG_INFO("data reading done\n");
+            if(check_data(read_p)) {
+                LOG_ERROR("bad data: terminated (data)\n");
+                dump_packet("bad data", "remote_con_enqueue", read_p);
+                read_p->len = 0;
+                put_apacket(p);
+                return 0;
+            }
+
+            send_remote_con_packet(socket, read_p);
+            read_p->len = 0;
+        }
+
+        if(p->len == 0) {
+            LOG_INFO("reading all the packet is done\n");
+            put_apacket(p);
+            p = NULL;
+        }
     }
 
-        /* otherwise, put on the closing list
-        */
-    D("LS(%d): closing\n", s->id);
-    s->closing = 1;
-    fdevent_del(&s->fde, FDE_READ);
-    remove_socket(s);
-    D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
-    insert_local_socket(s, &local_socket_closing_list);
+    LOG_INFO("read_p->len: %d\n", read_p->len);
+    return 1;
+}
+#endif
+
+static int peer_enqueue(SDB_SOCKET* socket, PACKET* p) {
+    if(HAS_SOCKET_STATUS(socket, REMOTE_SOCKET)) {
+        D("entered remote_socket_enqueue RS(%d) WRTE fd=%d\n",
+                socket->remote_id, socket->fd);
+        p->msg.command = A_WRTE;
+        p->msg.arg0 = socket->local_id;
+        p->msg.arg1 = socket->remote_id;
+        p->msg.data_length = p->len;
+        send_packet(p, socket->transport);
+        put_apacket(p);
+        FDEVENT_DEL(&socket->fde, FDE_READ);
+        return 1;
+    }
+
+    //TODO REMOTE_DEVICE_CONNECT block this code until security issue is resolved
+#if 0
+    if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) {
+        return remote_con_enqueue(socket, p);
+    }
+#endif
+
+    if(HAS_SOCKET_STATUS(socket, DEVICE_TRACKER)) {
+        D("close device tracker.fd: '%d', LS(%X)", socket->fd, socket->local_id);
+        put_apacket(p);
+        local_socket_close(socket);
+        return -1;
+    }
+
+    //packet can be queued, so do not free it here.
+    return smart_socket_enqueue(socket, p);
+}
+
+/**
+ * If returns 0, appending is done. packet is freed.
+ * 1, EAGAIN happens packet is put in the queue. wait for next round.
+ * -1, error happens. socket is closed. return immediately.
+ */
+static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func) {
+    D("LS(%X) FD(%d)\n", s->local_id, fd);
+    while(p->len > 0) {
+        dump_packet("0", "local_enqueue", p);
+        int r = sdb_write(fd, p->ptr, p->len);
+        if(r < 0) {
+            if(errno == EAGAIN) {
+                //packet is used next round do not free.
+                D( "LS(%X) EAGAIN pending to next round\n", s->local_id);
+                return 1;
+            }
+            //TODO if we handle EINTR when local_socket_enqueue calls this, Windows debug fails.
+            if(errno == EINTR && event_func) {
+                D( "LS(%X) EINTR continue\n", s->local_id);
+                continue;
+            }
+        }
+        if(r > 0) {
+            p->len -= r;
+            p->ptr += r;
+            continue;
+        }
+        //error happens. close the socket.
+        D( "LS(%X) error ER(%d) %s\n", s->local_id, errno, strerror(errno) );
+        put_apacket(p);
+        local_socket_close(s);
+        return -1; /* not ready (error) */
+    }
+    //append done.
+    D("LS(%X) enqueue done\n", s->local_id);
+    put_apacket(p);
+    return 0;
 }
 
 static void local_socket_event_func(int fd, unsigned ev, void *_s)
 {
-    asocket *s = _s;
+    SDB_SOCKET *s = _s;
 
-    D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
+    D("LS(%X) FD(%d)\n", s->local_id, s->fd);
 
     /* put the FDE_WRITE processing before the FDE_READ
     ** in order to simplify the code.
     */
     if(ev & FDE_WRITE){
-        apacket *p;
-
-        while((p = s->pkt_first) != 0) {
-            while(p->len > 0) {
-                int r = sdb_write(fd, p->ptr, p->len);
-                if(r > 0) {
-                    p->ptr += r;
-                    p->len -= r;
-                    continue;
-                }
-                if(r < 0) {
-                    /* returning here is ok because FDE_READ will
-                    ** be processed in the next iteration loop
-                    */
-                    if(errno == EAGAIN) return;
-                    if(errno == EINTR) continue;
-                }
-                D(" closing after write because r=%d and errno is %d\n", r, errno);
-                s->close(s);
-                return;
+        D("LS(%X) gets a write event\n", s->local_id);
+        while(s->pkt_list != NULL) {
+            PACKET* p = s->pkt_list->data;
+            int r = local_enqueue(fd, p, s, 1);
+
+            if ( r == 0) {
+                //packet enqueue done
+                remove_first(&s->pkt_list, no_free);
             }
-
-            if(p->len == 0) {
-                s->pkt_first = p->next;
-                if(s->pkt_first == 0) s->pkt_last = 0;
-                put_apacket(p);
+            else {
+                //in both cases r = 1 and r = -1, return immediately.
+                return;
             }
         }
-
-            /* if we sent the last packet of a closing socket,
-            ** we can now destroy it.
-            */
         if (s->closing) {
-            D(" closing because 'closing' is set after write\n");
-            s->close(s);
+            D("LS(%X) closing because 'closing' is set after write\n", s->local_id);
+            local_socket_close(s);
             return;
         }
-
-            /* no more packets queued, so we can ignore
-            ** writable events again and tell our peer
-            ** to resume writing
-            */
-        fdevent_del(&s->fde, FDE_WRITE);
-        s->peer->ready(s->peer);
+        //all the packet in the pkt_list is enqueued. write event is done.
+        FDEVENT_DEL(&s->fde, FDE_WRITE);
+        if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) {
+            send_cmd(s->local_id, s->remote_id, A_OKAY, NULL, s->transport);
+        }
     }
 
 
     if(ev & FDE_READ){
-        apacket *p = get_apacket();
-        unsigned char *x = p->data;
+        D("LS(%X) gets a read event\n", s->local_id);
+        //packet should be freed in peer_enqueue
+        PACKET *p = get_apacket();
+
+        void *x;
+        if(HAS_SOCKET_STATUS(s, REMOTE_CON)) {
+            x = &p->msg;
+            p->ptr = &p->msg;
+        }
+        else {
+            x = p->data;
+        }
         size_t avail = MAX_PAYLOAD;
-        int r;
-        int is_eof = 0;
+        int r = 1;
 
         while(avail > 0) {
             r = sdb_read(fd, x, avail);
-            D("LS(%d): post sdb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
             if(r > 0) {
                 avail -= r;
                 x += r;
                 continue;
             }
             if(r < 0) {
-                if(errno == EAGAIN) break;
-                if(errno == EINTR) continue;
+                if(errno == EAGAIN) {
+                    D("LS(%X) EAGAIN while reading\n", s->local_id);
+                    break;
+                }
+                if(errno == EINTR) {
+                    continue;
+                }
+                LOG_ERROR("LS(%X) error while reading ER(%d), %s\n", s->local_id, errno, strerror(errno));
+                // r = 0 means EOF or unhandled error.
+                r = 0;
             }
-
-                /* r = 0 or unhandled error */
-            is_eof = 1;
+            D("LS(%X) reading done\n", s->local_id);
             break;
         }
-        D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
-          s->id, s->fd, r, is_eof, s->fde.force_eof);
-        if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
+
+        if(avail == MAX_PAYLOAD) {
             put_apacket(p);
         } else {
             p->len = MAX_PAYLOAD - avail;
-
-            r = s->peer->enqueue(s->peer, p);
-            D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
-
-            if(r < 0) {
-                    /* error return means they closed us as a side-effect
-                    ** and we must return immediately.
-                    **
-                    ** note that if we still have buffered packets, the
-                    ** socket will be placed on the closing socket list.
-                    ** this handler function will be called again
-                    ** to process FDE_WRITE events.
-                    */
+            if(peer_enqueue(s, p) < 0) {
+                //local socket is already closed by peer or should not close the socket.
                 return;
             }
-
-            if(r > 0) {
-                    /* if the remote cannot accept further events,
-                    ** we disable notification of READs.  They'll
-                    ** be enabled again when we get a call to ready()
-                    */
-                fdevent_del(&s->fde, FDE_READ);
-            }
         }
-        /* Don't allow a forced eof if data is still there */
-        if((s->fde.force_eof && !r) || is_eof) {
-            D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
-            s->close(s);
+        if(r == 0) {
+            D("LS(%X) EOF. closing\n", s->local_id);
+            local_socket_close(s);
         }
     }
-
-    if(ev & FDE_ERROR){
-            /* this should be caught be the next read or write
-            ** catching it here means we may skip the last few
-            ** bytes of readable data.
-            */
-//        s->close(s);
-        D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
-
-        return;
-    }
 }
 
-asocket *create_local_socket(int fd)
+SDB_SOCKET *create_local_socket(int fd)
 {
-    asocket *s = calloc(1, sizeof(asocket));
-    if (s == NULL) fatal("cannot allocate socket");
+    D("FD(%d)\n", fd);
+    SDB_SOCKET *s = calloc(1, sizeof(SDB_SOCKET));
+    if (s == NULL) {
+        LOG_FATAL("cannot allocate socket\n");
+    }
+    s->status = 0;
+    s->node = NULL;
+    s->pkt_list = NULL;
     s->fd = fd;
-    s->enqueue = local_socket_enqueue;
-    s->ready = local_socket_ready;
-    s->close = local_socket_close;
-    install_local_socket(s);
+
+    s->local_id = local_socket_next_id++;
+    s->node = prepend(&local_socket_list, s);
 
     fdevent_install(&s->fde, fd, local_socket_event_func, s);
-/*    fdevent_add(&s->fde, FDE_ERROR); */
-    //fprintf(stderr, "Created local socket in create_local_socket \n");
-    D("LS(%d): created (fd=%d)\n", s->id, s->fd);
+    D("LS(%X) FD(%d) created\n", s->local_id, s->fd);
     return s;
 }
 
-asocket *create_local_service_socket(const char *name)
-{
-    asocket *s;
-    int fd;
-
-    fd = service_to_fd(name);
-    if(fd < 0) return 0;
-
-    s = create_local_socket(fd);
-    D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
-
-    return s;
+void create_remote_connection_socket(SDB_SOCKET* socket) {
+    LOG_INFO("FD(%d)\n", socket->fd);
+    SET_SOCKET_STATUS(socket, REMOTE_CON);
+    socket->read_packet = malloc(sizeof(PACKET));
+    socket->read_packet->len = 0;
 }
 
-static asocket *create_host_service_socket(const char *name, const char* serial)
+void connect_to_remote(SDB_SOCKET *s, const char *destination)
 {
-    asocket *s;
-
-    s = host_service_to_socket(name, serial);
+    D("LS(%X)\n", s->local_id);
+    PACKET *p = get_apacket();
+    int len = strlen(destination) + 1;
 
-    if (s != NULL) {
-        D("LS(%d) bound to '%s'\n", s->id, name);
-        return s;
+    if(len > (MAX_PAYLOAD-1)) {
+        LOG_FATAL("destination oversized\n");
     }
 
-    return s;
+    D("LS(%X): connect('%s')\n", s->local_id, destination);
+    p->msg.command = A_OPEN;
+    p->msg.arg0 = s->local_id;
+    p->msg.data_length = len;
+    strcpy((char*) p->data, destination);
+    send_packet(p, s->transport);
+    put_apacket(p);
 }
 
-/* a Remote socket is used to send/receive data to/from a given transport object
-** it needs to be closed when the transport is forcibly destroyed by the user
-*/
-typedef struct aremotesocket {
-    asocket      socket;
-    adisconnect  disconnect;
-} aremotesocket;
+static unsigned unhex(unsigned char*s, int len) {
 
-static int remote_socket_enqueue(asocket *s, apacket *p)
-{
-    D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
-      s->id, s->fd, s->peer->fd);
-    p->msg.command = A_WRTE;
-    p->msg.arg0 = s->peer->id;
-    p->msg.arg1 = s->id;
-    p->msg.data_length = p->len;
-    send_packet(p, s->transport);
-    return 1;
+    unsigned n = 0;
+    while(len > 0) {
+        MAP_KEY key;
+        key.key_int = (int)(0 | *s++);
+        void* _c = map_get(&hex_map, key);
+        unsigned c = (unsigned)_c;
+        n = (n << 4) | c;
+        len--;
+    }
+    return n;
 }
 
-static void remote_socket_ready(asocket *s)
-{
-    D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
-      s->id, s->fd, s->peer->fd);
-    apacket *p = get_apacket();
-    p->msg.command = A_OKAY;
-    p->msg.arg0 = s->peer->id;
-    p->msg.arg1 = s->id;
-    send_packet(p, s->transport);
-}
+/**
+ * return 0 for host
+ * return 1 for transport
+ */
+static int parse_host_service(char* host_str, char** service_ptr, TRANSPORT** t, char** err_str) {
 
-static void remote_socket_close(asocket *s)
-{
-    D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
-      s->id, s->fd, s->peer?s->peer->fd:-1);
-    apacket *p = get_apacket();
-    p->msg.command = A_CLSE;
-    if(s->peer) {
-        p->msg.arg0 = s->peer->id;
-        s->peer->peer = 0;
-        D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
-          s->id, s->peer->id, s->peer->fd);
-        s->peer->close(s->peer);
-    }
-    p->msg.arg1 = s->id;
-    send_packet(p, s->transport);
-    D("RS(%d): closed\n", s->id);
-    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
-    free(s);
+    int prefix_len = strlen(PREFIX_HOST_USB);
+    if (!strncmp(host_str, PREFIX_HOST_USB, prefix_len)) {
+        *service_ptr = host_str + prefix_len;
+        *t = acquire_one_transport(kTransportUsb, NULL, err_str);
+        return 0;
+    }
+    prefix_len = strlen(PREFIX_HOST_LOCAL);
+    if (!strncmp(host_str, PREFIX_HOST_LOCAL, prefix_len)) {
+        *service_ptr = host_str + prefix_len;
+        *t = acquire_one_transport(kTransportLocal, NULL, err_str);
+        return 0;
+    }
+    prefix_len = strlen(PREFIX_HOST);
+    if (!strncmp(host_str, PREFIX_HOST, prefix_len)) {
+        if(!strncmp(host_str, PREFIX_TRANSPORT_ANY, strlen(PREFIX_TRANSPORT_ANY))) {
+            *t = acquire_one_transport(kTransportAny, NULL, err_str);
+            return 1;
+        }
+        if(!strncmp(host_str, PREFIX_TRANSPORT_LOCAL, strlen(PREFIX_TRANSPORT_LOCAL))) {
+            *t = acquire_one_transport(kTransportLocal, NULL, err_str);
+            return 1;
+        }
+        if(!strncmp(host_str, PREFIX_TRANSPORT_USB, strlen(PREFIX_TRANSPORT_USB))) {
+            *t = acquire_one_transport(kTransportUsb, NULL, err_str);
+            return 1;
+        }
+        if(!strncmp(host_str, PREFIX_TRANSPORT_SERIAL, strlen(PREFIX_TRANSPORT_SERIAL))) {
+            *t = acquire_one_transport(kTransportAny, host_str + strlen(PREFIX_TRANSPORT_SERIAL), err_str);
+            return 1;
+        }
+        *service_ptr = host_str + prefix_len;
+        //does not have to find transport.
+        *t = NULL;
+        *err_str = NULL;
+        return 0;
+    }
+    prefix_len = strlen(PREFIX_HOST_ANY);
+    if(!strncmp(host_str, PREFIX_HOST_ANY, prefix_len)) {
+        *service_ptr = host_str + prefix_len;
+        *t = acquire_one_transport(kTransportAny, NULL, err_str);
+        return 0;
+    }
+    prefix_len = strlen(PREFIX_HOST_SERIAL);
+    if(!strncmp(host_str, PREFIX_HOST_SERIAL, prefix_len)) {
+        char* serial = host_str + prefix_len;
+        char* end = strchr(serial, ':');
+        if(end == NULL) {
+            *err_str = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND;
+            return 0;
+        }
+        *end = '\0';
+        *service_ptr = end + 1;
+        *t = acquire_one_transport(kTransportAny, serial, err_str);
+        return 0;
+    }
+    *service_ptr = NULL;
+    return 0;
 }
 
-static void remote_socket_disconnect(void*  _s, atransport*  t)
-{
-    asocket*  s    = _s;
-    asocket*  peer = s->peer;
+static int handle_request_with_t(SDB_SOCKET* socket, char* service, TRANSPORT* t, char* err_str) {
+    int forward = 0;
+    if(!strncmp(service,"forward:",8)) {
+        forward = 8;
+    }
+    else if (!strncmp(service,"killforward:",12)) {
+        forward = 12;
+    }
+
+    if(forward) {
+        char* forward_err = NULL;
+
+        char *local, *remote = NULL;
+        local = service + forward;
+        remote = strchr(local,';');
+
+        if (t == NULL || t->connection_state == CS_OFFLINE) {
+            if(t != NULL) {
+                forward_err = (char*)TRANSPORT_ERR_TARGET_OFFLINE;
+            }
+            else {
+                forward_err = err_str;
+            }
+            goto sendfail;
+        }
+        if(remote == 0 || remote[1] == '\0') {
+            forward_err = "malformed forward spec";
+            goto sendfail;
+        }
+        *remote++ = 0;
 
-    D("remote_socket_disconnect RS(%d)\n", s->id);
-    if (peer) {
-        peer->peer = NULL;
-        peer->close(peer);
+        if (forward == 8) {
+            if(!install_listener(local, remote, t)) {
+                writex(socket->fd, "OKAYOKAY", 8);
+                return 0;
+            }
+            else {
+                LOG_INFO("LS(%X) T(%s) fail to install listener\n", socket->fd, t->device_name);
+                forward_err = "cannot install listener";
+            }
+        } else {
+            if(!remove_listener(local, remote, t)) {
+                writex(socket->fd, "OKAYOKAY", 8);
+                return 0;
+            } else {
+                LOG_INFO("LS(%X) T(%s) fail to remove listener\n", socket->fd, t->device_name);
+                forward_err = "cannot remove listener";
+            }
+        }
+sendfail:
+        sendfailmsg(socket->fd, forward_err);
+        return 0;
+    }
+    else if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
+       if (t) {
+           sendokmsg(socket->fd, t->serial);
+        }
+       else {
+           sendokmsg(socket->fd, "target not exist");
+       }
+        return 0;
+    }
+    else if(!strncmp(service,"get-state",strlen("get-state"))) {
+        const char *state = connection_state_name(t);
+        sendokmsg(socket->fd, state);
+        return 0;
     }
-    remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
-    free(s);
-}
 
-asocket *create_remote_socket(unsigned id, atransport *t)
-{
-    asocket *s = calloc(1, sizeof(aremotesocket));
-    adisconnect*  dis = &((aremotesocket*)s)->disconnect;
-
-    if (s == NULL) fatal("cannot allocate socket");
-    s->id = id;
-    s->enqueue = remote_socket_enqueue;
-    s->ready = remote_socket_ready;
-    s->close = remote_socket_close;
-    s->transport = t;
-
-    dis->func   = remote_socket_disconnect;
-    dis->opaque = s;
-    add_transport_disconnect( t, dis );
-    D("RS(%d): created\n", s->id);
-    return s;
+    //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared
+#if 0
+    else if(!strncmp(service,"_dev_con",strlen("_dev_con"))) {
+        if(t == NULL) {
+            sendfailmsg(socket->fd, err_str);
+            return 0;
+        }
+        if(assign_remote_connect_socket_lid(socket)) {
+            sendfailmsg(socket->fd, "remote connect socket exceeds limit. cannot create remote socket\n");
+            local_socket_close(socket);
+            return 0;
+        }
+        socket->transport = t;
+        create_remote_connection_socket(socket);
+
+        char* buf = "OKAY";
+        writex(socket->fd, buf, strlen(buf));
+        return 0;
+    }
+#endif
+
+    return -1;
 }
 
-void connect_to_remote(asocket *s, const char *destination)
+static int find_transports(char **serial_out, const char *prefix)
 {
-    D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
-    apacket *p = get_apacket();
-    int len = strlen(destination) + 1;
+    int nr = 0; // not found
+    char *match = NULL;
 
-    if(len > (MAX_PAYLOAD-1)) {
-        fatal("destination oversized");
-    }
+    if (!serial_out || !prefix)
+        return -1;
 
-    D("LS(%d): connect('%s')\n", s->id, destination);
-    p->msg.command = A_OPEN;
-    p->msg.arg0 = s->id;
-    p->msg.data_length = len;
-    strcpy((char*) p->data, destination);
-    send_packet(p, s->transport);
-}
+    sdb_mutex_lock(&transport_lock, "transport find_transports");
 
+    LIST_NODE* curptr = transport_list;
+    while(curptr != NULL) {
+        TRANSPORT* t = curptr->data;
+        curptr = curptr->next_ptr;
+        char* serial = t->serial;
+        if (!serial || !serial[0])
+            continue;
+        if (!strncmp(prefix, serial, strlen(prefix))) {
+            match = serial;
+            nr++;
+        }
 
-/* this is used by magic sockets to rig local sockets to
-   send the go-ahead message when they connect */
-static void local_socket_ready_notify(asocket *s)
-{
-    s->ready = local_socket_ready;
-    s->close = local_socket_close;
-    sdb_write(s->fd, "OKAY", 4);
-    s->ready(s);
+        if (nr > 1) {
+            match = NULL;
+            break;
+        }
+    }
+    sdb_mutex_unlock(&transport_lock, "transport find_transports");
+
+    if (nr == 1 && match) {
+        *serial_out = strdup(match);
+    } else if (nr == 0) {
+        asprintf(serial_out, "device not found");
+    } else if (nr > 1) {
+        asprintf(serial_out, "more than one device and emulator");
+    }
+
+    return nr;
 }
 
-/* this is used by magic sockets to rig local sockets to
-   send the failure message if they are closed before
-   connected (to avoid closing them without a status message) */
-static void local_socket_close_notify(asocket *s)
+static void unregister_all_tcp_transports()
 {
-    s->ready = local_socket_ready;
-    s->close = local_socket_close;
-    sendfailmsg(s->fd, "closed");
-    s->close(s);
+    sdb_mutex_lock(&transport_lock, "transport unregister_all_tcp_transports");
+
+    LIST_NODE* curptr = transport_list;
+    while(curptr != NULL) {
+        TRANSPORT* t = curptr->data;
+        curptr = curptr->next_ptr;
+        if (t->type == kTransportLocal && t->sdb_port == 0) {
+            //just kick the transport. transport is destroied by transport thread.
+            if(!t->kicked) {
+                t->kicked = 1;
+                t->kick(t);
+            }
+        }
+    }
+
+    sdb_mutex_unlock(&transport_lock, "transport unregister_all_tcp_transports");
 }
 
-unsigned unhex(unsigned char *s, int len)
+static int handle_host_request(char *service, SDB_SOCKET* socket)
 {
-    unsigned n = 0, c;
-
-    while(len-- > 0) {
-        switch((c = *s++)) {
-        case '0': case '1': case '2':
-        case '3': case '4': case '5':
-        case '6': case '7': case '8':
-        case '9':
-            c -= '0';
-            break;
-        case 'a': case 'b': case 'c':
-        case 'd': case 'e': case 'f':
-            c = c - 'a' + 10;
-            break;
-        case 'A': case 'B': case 'C':
-        case 'D': case 'E': case 'F':
-            c = c - 'A' + 10;
-            break;
-        default:
-            return 0xffffffff;
+    LOG_INFO("LS(%X)\n", socket->fd);
+    char cmd_buf[1024];
+    int cbuf_size = sizeof cmd_buf;
+
+    if (!strncmp(service, "serial-match:", 13)) {
+        char *tmp = service + 13;
+        char *serial = NULL;
+        int ret = -1;
+        D("Try to find device for: %s\n", tmp);
+        ret = find_transports(&serial, tmp);
+        if (ret <= 0) {
+            LOG_ERROR("No device found\n");
+            sendfailmsg(socket->fd, serial);
+        } else if (ret == 1) {
+            sendokmsg(socket->fd, serial);
+        } else {
+            LOG_ERROR("found more than one devices matched: %d\n", ret);
+            sendfailmsg(socket->fd, serial);
+        }
+        free(serial);
+        return 0;
+    }
+    // return a list of all connected devices
+    if (!strcmp(service, "devices")) {
+        list_transports(cmd_buf, cbuf_size);
+        sendokmsg(socket->fd, cmd_buf);
+        return 0;
+    }
+
+    // add a new TCP transport, device or emulator
+    if (!strncmp(service, "connect:", 8)) {
+        char* host = service + 8;
+        char* portstr = strchr(host, ':');
+        int port = -1;
+
+        if(portstr) {
+               *portstr++ = 0;
+               if(!sscanf(portstr, "%d", &port)) {
+                       snprintf(cmd_buf, cbuf_size, "bad port format '%s'", portstr);
+                       goto connect_done;
+               }
         }
+        connect_emulator(host, port, cmd_buf, cbuf_size);
 
-        n = (n << 4) | c;
+connect_done:
+        sendokmsg(socket->fd, cmd_buf);
+        return 0;
     }
 
-    return n;
-}
+    // remove TCP transport
+    if (!strncmp(service, "disconnect:", 11)) {
+        char* serial = service + 11;
+        if (serial[0]) {
+            if (!strchr(serial, ':')) {
+                snprintf(cmd_buf, cbuf_size, "%s:26101", serial);
+                serial = cmd_buf;
+            }
+            TRANSPORT *t = acquire_one_transport(kTransportAny, serial, NULL);
 
-/* skip_host_serial return the position in a string
-   skipping over the 'serial' parameter in the SDB protocol,
-   where parameter string may be a host:port string containing
-   the protocol delimiter (colon). */
-char *skip_host_serial(char *service) {
-    char *first_colon, *serial_end;
+            if (t) {
+                cmd_buf[0] = '\0';
+                kick_transport(t);
+            } else {
+                snprintf(cmd_buf, cbuf_size, "No such device %s", serial);
+            }
+        } else {
+            unregister_all_tcp_transports();
+            cmd_buf[0] = '\0';
+        }
 
-    first_colon = strchr(service, ':');
-    if (!first_colon) {
-        /* No colon in service string. */
-        return NULL;
+        sendokmsg(socket->fd, cmd_buf);
+        return 0;
     }
-    serial_end = first_colon;
-    if (isdigit(serial_end[1])) {
-        serial_end++;
-        while ((*serial_end) && isdigit(*serial_end)) {
-            serial_end++;
+
+    if (!strncmp(service, "device_con:", 11)) {
+        char* _host = service + 11;
+        char host_buf[4096];
+        char target_buf[4096];
+        char full_cmd[4096];
+        char full_serial[256];
+        strncpy(host_buf, _host, sizeof(host_buf) - 1);
+        _host = host_buf;
+        char* serial = strchr(host_buf, ':');
+        *(serial) = '\0';
+        serial++;
+
+        int fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM);
+        if (fd < 0) {
+            snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host);
+            LOG_ERROR(target_buf);
+            sendfailmsg(socket->fd, target_buf);
+            return 0;
+        }
+        D("FD(%d) remote connected with host: %s\n", fd, _host);
+
+        D("FULL_CMD %s\n", full_cmd);
+        snprintf(full_cmd, sizeof(full_cmd), "host:serial-match:%s", serial);
+        if(!send_service_with_length(fd, full_cmd, socket->fd)) {
+            if(!sdb_status(fd, socket->fd)) {
+                int n = read_msg_size(fd);
+                if(n > 0 && n < 256) {
+                    if(!readx(fd, full_serial, n)) {
+                        full_serial[n] = 0;
+                        serial = full_serial;
+                        goto success;
+                    }
+                }
+                snprintf(target_buf, sizeof(target_buf), "fail to read full serial of %s", serial);
+                sendfailmsg(socket->fd, target_buf);
+            }
+        }
+        sdb_close(fd);
+        return 0;
+
+success:
+        sdb_close(fd);
+        fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM);
+        if (fd < 0) {
+            snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host);
+            LOG_ERROR(target_buf);
+            sendfailmsg(socket->fd, target_buf);
+            return 0;
         }
-        if ((*serial_end) != ':') {
-            // Something other than numbers was found, reset the end.
-            serial_end = first_colon;
+        D("FD(%d) remote connected\n", fd);
+        get_host_prefix(target_buf, sizeof target_buf, kTransportAny, serial, host);
+        snprintf(full_cmd, sizeof full_cmd, "%s_dev_con",target_buf);
+
+        D("FULL_CMD: %s\n", full_cmd);
+        if(!send_service_with_length(fd, full_cmd, socket->fd)) {
+            if(!sdb_status(fd, socket->fd)) {
+                if(!register_device_con_transport(fd, serial)) {
+                    snprintf(target_buf, sizeof target_buf, "success to connect with remote target '%s'\n", serial);
+                    snprintf(full_cmd, sizeof(full_cmd), "OKAY%04x%s",(unsigned)strlen(target_buf), target_buf);
+                    if(!writex(socket->fd, full_cmd, strlen(full_cmd))) {
+                        return 0;
+                    }
+                    else {
+                        sendfailmsg(socket->fd, "fail to write OKAY message\n");
+                    }
+                }
+                else {
+                    sendfailmsg(socket->fd, "fail to connect with remote device\n");
+                }
+            }
         }
+        sdb_close(fd);
+        return 0;
     }
-    return serial_end;
+
+    // returns our value for SDB_SERVER_VERSION
+    if (!strcmp(service, "version")) {
+        snprintf(cmd_buf, cbuf_size, "%04x", SDB_SERVER_VERSION);
+        sendokmsg(socket->fd, cmd_buf);
+        return 0;
+    }
+
+    // indicates a new emulator instance has started
+       if (!strncmp(service,"emulator:",9)) { /* tizen specific */
+           D("new emulator is in\n");
+           char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR);
+           int  port = 0;
+
+           if (tmp == NULL) {
+               port = atoi(service+9);
+           } else {
+               port = atoi(tmp);
+               tmp = strtok(NULL, DEVICEMAP_SEPARATOR);
+           }
+           local_connect(port, tmp);
+        return 0;
+    }
+
+       if(!strcmp(service, "kill")) {
+          LOG_INFO("sdb is being killed\n");
+           sdb_cleanup();
+           sdb_write(socket->fd, "OKAY", 4);
+           exit(0);
+       }
+
+    return -1;
 }
 
-static int smart_socket_enqueue(asocket *s, apacket *p)
+static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p)
 {
     unsigned len;
-    char *service = NULL;
-    char* serial = NULL;
-    transport_type ttype = kTransportAny;
 
-    D("SS(%d): enqueue %d\n", s->id, p->len);
+    D("LS(%X)\n", s->local_id);
 
-    if(s->pkt_first == 0) {
-        s->pkt_first = p;
-        s->pkt_last = p;
-    } else {
-        if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
-            D("SS(%d): overflow\n", s->id);
+    if(s->pkt_list == NULL) {
+        prepend(&s->pkt_list, p);
+    }
+    else {
+        PACKET* socket_packet = s->pkt_list->data;
+        if((socket_packet->len + p->len) > MAX_PAYLOAD) {
+            D("SS(%d): overflow\n", s->local_id);
             put_apacket(p);
             goto fail;
         }
 
-        memcpy(s->pkt_first->data + s->pkt_first->len,
+        memcpy(socket_packet->data + socket_packet->len,
                p->data, p->len);
-        s->pkt_first->len += p->len;
+        socket_packet->len += p->len;
         put_apacket(p);
 
-        p = s->pkt_first;
+        p = socket_packet;
     }
 
         /* don't bother if we can't decode the length */
     if(p->len < 4) return 0;
 
     len = unhex(p->data, 4);
+
     if((len < 1) ||  (len > 1024)) {
-        D("SS(%d): bad size (%d)\n", s->id, len);
+        D("LS(%X): bad size (%d)\n", s->local_id, len);
         goto fail;
     }
 
-    D("SS(%d): len is %d\n", s->id, len );
         /* can't do anything until we have the full header */
     if((len + 4) > p->len) {
-        D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
+        D("LS(%X): waiting for %d more bytes in smart socket\n", s->local_id, len+4 - p->len);
         return 0;
     }
 
     p->data[len + 4] = 0;
+    D("LS(%X) %s\n", s->local_id, p->data + 4);
 
-    D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
-
-    service = (char *)p->data + 4;
-    if(!strncmp(service, PREFIX_HOST_SERIAL, strlen(PREFIX_HOST_SERIAL))) {
-        char* serial_end;
-        service += strlen(PREFIX_HOST_SERIAL);
-
-        // serial number should follow "host:" and could be a host:port string.
-        serial_end = skip_host_serial(service);
-        if (serial_end) {
-            *serial_end = 0; // terminate string
-            serial = service;
-            service = serial_end + 1;
-        }
-        ttype = kTransportUsb;
-    } else if (!strncmp(service, PREFIX_HOST_USB, strlen(PREFIX_HOST_USB))) {
-        service += strlen(PREFIX_HOST_USB);
-    } else if (!strncmp(service, PREFIX_HOST_LOCAL, strlen(PREFIX_HOST_LOCAL))) {
-        ttype = kTransportLocal;
-        service += strlen(PREFIX_HOST_LOCAL);
-    } else if (!strncmp(service, PREFIX_HOST, strlen(PREFIX_HOST))) {
-        ttype = kTransportAny;
-        service += strlen(PREFIX_HOST);
-    } else {
-        service = NULL;
+    char* host_str = (char *)p->data + 4;
+    char *service = NULL;
+    char* err_str = NULL;
+    TRANSPORT* t = NULL;
+
+    if(parse_host_service(host_str, &service, &t, &err_str) == 1) {
+        if (t && t->connection_state != CS_OFFLINE) {
+            s->transport = t;
+            sdb_write(s->fd, "OKAY", 4);
+            D("LS(%X) get transport T(%s)", s->local_id, t->device_name);
+        } else {
+            if(t != NULL) {
+                err_str = (char*)TRANSPORT_ERR_TARGET_OFFLINE;
+            }
+            LOG_ERROR("LS(%X) get no transport", s->local_id);
+            sendfailmsg(s->fd, err_str);
+        }
+        p->len = 0;
+        return 0;
     }
 
     if (service) {
-        asocket *s2;
-
-            /* some requests are handled immediately -- in that
-            ** case the handle_host_request() routine has sent
-            ** the OKAY or FAIL message and all we have to do
-            ** is clean up.
-            */
-        if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
+        if(handle_request_with_t(s, service, t, err_str) == 0) {
+            D( "LS(%X): handled host service with '%s'\n", s->local_id, service );
+            goto fail;
+        }
+
+        if(handle_host_request(service, s) == 0) {
                 /* XXX fail message? */
-            D( "SS(%d): handled host service '%s'\n", s->id, service );
+            D( "LS(%X): handled host service '%s'\n", s->local_id, service );
             goto fail;
         }
-        if (!strncmp(service, "transport", strlen("transport"))) {
-            D( "SS(%d): okay transport\n", s->id );
-            p->len = 0;
+
+        if (!strcmp(service,"track-devices")) {
+            free_list(s->pkt_list, put_apacket);
+            s->pkt_list = NULL;
+            D("LS(%X): OKAY\n", s->local_id);
+            SET_SOCKET_STATUS(s, DEVICE_TRACKER);
+            sdb_write(s->fd, "OKAY", 4);
+
+            D( "LS(%X) fd: '%d' for device tracking\n", s->local_id, s->fd );
+            char buffer[1024];
+            int len;
+            len = list_transports_msg(buffer, sizeof(buffer));
+            device_tracker_send(s, buffer, len);
             return 0;
         }
-
-            /* try to find a local service with this name.
-            ** if no such service exists, we'll fail out
-            ** and tear down here.
-            */
-        s2 = create_host_service_socket(service, serial);
-        if(s2 == 0) {
-            D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
-            sendfailmsg(s->peer->fd, "unknown host service");
+        else {
+            D( "LS(%X): couldn't create host service '%s'\n", s->local_id, service );
+            sendfailmsg(s->fd, "unknown host service");
             goto fail;
         }
-
-            /* we've connected to a local host service,
-            ** so we make our peer back into a regular
-            ** local socket and bind it to the new local
-            ** service socket, acknowledge the successful
-            ** connection, and close this smart socket now
-            ** that its work is done.
-            */
-        sdb_write(s->peer->fd, "OKAY", 4);
-
-        s->peer->ready = local_socket_ready;
-        s->peer->close = local_socket_close;
-        s->peer->peer = s2;
-        s2->peer = s->peer;
-        s->peer = 0;
-        D( "SS(%d): okay\n", s->id );
-        s->close(s);
-
-            /* initial state is "ready" */
-        s2->ready(s2);
-        return 0;
     }
 
     if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
-           /* if there's no remote we fail the connection
-            ** right here and terminate it
-            */
-        sendfailmsg(s->peer->fd, "device offline (x)");
+        sendfailmsg(s->fd, "device offline (x)");
         goto fail;
     }
 
+    if (!(s->transport) || (s->transport->connection_state == CS_PWLOCK)) {
+        sendfailmsg(s->fd, "device locked");
+        goto fail;
+    }
 
-        /* instrument our peer to pass the success or fail
-        ** message back once it connects or closes, then
-        ** detach from it, request the connection, and
-        ** tear down
-        */
-    s->peer->ready = local_socket_ready_notify;
-    s->peer->close = local_socket_close_notify;
-    s->peer->peer = 0;
-        /* give him our transport and upref it */
-    s->peer->transport = s->transport;
-
-    connect_to_remote(s->peer, (char*) (p->data + 4));
-    s->peer = 0;
-    s->close(s);
-    return 1;
+    if(s->transport->type == kTransportRemoteDevCon) {
+        if(assign_remote_connect_socket_rid(s)) {
+            sendfailmsg(s->fd, "remote connect socket exceeds limit. cannot create remote socket\n");
+            local_socket_close(s);
+            return -1;
+        }
+    }
+
+    SET_SOCKET_STATUS(s, NOTIFY);
+    connect_to_remote(s, (char*) (p->data + 4));
+    free_list(s->pkt_list, put_apacket);
+    s->pkt_list = NULL;
+    FDEVENT_DEL(&s->fde, FDE_READ);
+    return 0;
 
 fail:
-        /* we're going to close our peer as a side-effect, so
-        ** return -1 to signal that state to the local socket
-        ** who is enqueueing against us
-        */
-    s->close(s);
+
+    free_list(s->pkt_list, put_apacket);
+    s->pkt_list = NULL;
+    if(!HAS_SOCKET_STATUS(s, REMOTE_CON)) {
+        //do not close socket if it is remote connected socket
+        local_socket_close(s);
+    }
     return -1;
 }
 
-static void smart_socket_ready(asocket *s)
-{
-    D("SS(%d): ready\n", s->id);
+int assign_remote_connect_socket_rid (SDB_SOCKET* s) {
+    if(remote_con_cur_r_id > remote_con_r_max) {
+        LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd);
+        return -1;
+    }
+    int remote_id = (remote_con_cur_r_id << 4) | remote_con_flag;
+    LOG_INFO("LS(%X) -> LS_R(%X)\n", s->local_id, remote_id);
+    s->local_id = remote_id;
+    remote_con_cur_r_id++;
+    return 0;
 }
 
-static void smart_socket_close(asocket *s)
-{
-    D("SS(%d): closed\n", s->id);
-    if(s->pkt_first){
-        put_apacket(s->pkt_first);
+int assign_remote_connect_socket_lid (SDB_SOCKET* s) {
+    if(remote_con_cur_l_number >= remote_con_l_max) {
+        LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd);
+        return -1;
     }
-    if(s->peer) {
-        s->peer->peer = 0;
-        s->peer->close(s->peer);
-        s->peer = 0;
+    int i = 0;
+    for(i = 0; i< remote_con_l_max; i++) {
+        if(remote_con_l_table[i] == 0) {
+            unsigned int remote_id = i | remote_con_flag;
+            remote_con_cur_l_number++;
+            LOG_INFO("LS(%X) -> LS_L(%X)\n", s->local_id, remote_id);
+            s->local_id = remote_id;
+            remote_con_l_table[i] = 1;
+            return 0;
+        }
     }
-    free(s);
+    LOG_ERROR("not enough space in remote_con_l_table\n");
+    return -1;
 }
 
-asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
+int
+device_tracker_send( SDB_SOCKET* local_socket,
+                     const char*      buffer,
+                     int              len )
 {
-    D("Creating smart socket \n");
-    asocket *s = calloc(1, sizeof(asocket));
-    if (s == NULL) fatal("cannot allocate socket");
-    s->enqueue = smart_socket_enqueue;
-    s->ready = smart_socket_ready;
-    s->close = smart_socket_close;
-    s->extra = action_cb;
-
-    D("SS(%d): created %p\n", s->id, action_cb);
-    return s;
+    D("device tracker send to the socket. LS(%X), fd: '%d'\n", local_socket->local_id, local_socket->fd);
+    PACKET*  p = get_apacket();
+
+    memcpy(p->data, buffer, len);
+    p->len = len;
+    p->ptr = p->data;
+    //packet should not be freed after local_socket_enqueue because it can be still used in local socket packet queue.
+    return local_socket_enqueue( local_socket, p );
 }
 
-void smart_socket_action(asocket *s, const char *act)
-{
+static void connect_emulator(char* host, int port, char* buf, int buf_len) {
+    if(port < 0) {
+        port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
+    }
+    LOG_INFO("connecting ip: '%s', port: '%d'\n", host, port);
 
-}
+    int fd = sdb_host_connect(host, port, SOCK_STREAM);
+    if (fd < 0) {
+        snprintf(buf, buf_len, "fail to connect to %s", host);
+        return;
+    }
 
-void connect_to_smartsocket(asocket *s)
-{
-    D("Connecting to smart socket \n");
-    asocket *ss = create_smart_socket(smart_socket_action);
-    s->peer = ss;
-    ss->peer = s;
-    s->ready(s);
+    LOG_INFO("FD(%d) connected\n", fd);
+    close_on_exec(fd);
+    disable_tcp_nagle(fd);
+    char serial[100];
+    snprintf(serial, sizeof(serial), "%s:%d", host, port);
+    register_socket_transport(fd, serial, port, 0, NULL);
+    snprintf(buf, buf_len, "connected to %s", serial);
 }
diff --git a/src/sockets.h b/src/sockets.h
new file mode 100644 (file)
index 0000000..51fe875
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef SOCKETS_H_
+#define SOCKETS_H_
+
+#include "common_modules.h"
+
+#define SET_SOCKET_STATUS(asocket, _status) ((asocket)->status |= (1 << _status))
+#define REMOVE_SOCKET_STATUS(asocket, _status) ((asocket)->status &= ~(1 << _status))
+#define HAS_SOCKET_STATUS(asocket, _status) ((asocket)->status & (1 << _status))
+
+extern const unsigned int unsigned_int_bit;
+extern const unsigned int remote_con_right_padding;
+extern const unsigned int remote_con_flag;
+extern unsigned int remote_con_cur_r_id;
+extern unsigned int remote_con_cur_l_number;
+extern const unsigned int remote_con_l_max; // Ox1111
+extern const unsigned int remote_con_r_max;
+extern unsigned int remote_con_l_table[16];
+
+typedef enum {
+    NOTIFY = 0,
+    DEVICE_TRACKER,
+    REMOTE_SOCKET,
+    REMOTE_CON
+} SOCKET_STATUS;
+
+extern LIST_NODE* local_socket_list;
+
+SDB_SOCKET *find_local_socket(unsigned id);
+int local_socket_enqueue(SDB_SOCKET *s, PACKET *p);
+void local_socket_ready(SDB_SOCKET *s);
+void local_socket_close(SDB_SOCKET *s);
+SDB_SOCKET *create_local_socket(int fd);
+void connect_to_remote(SDB_SOCKET *s, const char *destination);
+int assign_remote_connect_socket_rid (SDB_SOCKET* s);
+int device_tracker_send( SDB_SOCKET* local_socket, const char* buffer, int len );
+#endif /* SOCKETS_H_ */
old mode 100644 (file)
new mode 100755 (executable)
index 33bff63..d4be7a3
@@ -12,7 +12,7 @@ size_t tokenize(const char *str, const char *delim, char *tokens[], size_t max_t
 
     char tmp[PATH_MAX];
 
-    strncpy(tmp, str, PATH_MAX);
+    strncpy(tmp, str, PATH_MAX - 1);
     char *p = strtok(tmp, delim);
     if (max_tokens < 1 || max_tokens > MAX_TOKENS) {
         max_tokens = 1;
@@ -79,8 +79,8 @@ char *s_strncpy(char *dest, const char *source, size_t n) {
           }
           *dest++ = *source++;
       }
+      *dest = '\0';
   }
 
-  *dest = '\0';
   return start;
 }
index 51a6abd39d5279623dfb921a632cb69b51f8e08f..a0c0cacac88a28fe0c728e4f8a973abfe69edaba 100755 (executable)
 #include <errno.h>
 #include "fdevent.h"
 #include "utils.h"
+#include "transport.h"
+#include "sockets.h"
+#include "sdb_constants.h"
+#include "strutils.h"
+#include "memutils.h"
+#include "listener.h"
+#include "log.h"
+
 #define   TRACE_TAG  TRACE_TRANSPORT
-#include "sdb.h"
 
-static void transport_unref(atransport *t);
+static void transport_unref(TRANSPORT *t);
+static void handle_packet(PACKET *p, TRANSPORT *t);
+static void parse_banner(char *banner, TRANSPORT *t);
+static void wakeup_select(T_PACKET* t_packet);
+static void  update_transports(void);
+static void run_transport_close(TRANSPORT* t);
+static void encoding_packet(PACKET* p);
+static int check_header(PACKET *p);
+static int check_data(PACKET *p);
+static void  dump_hex( const unsigned char*  ptr, size_t  len);
 
-static atransport transport_list = {
-    .next = &transport_list,
-    .prev = &transport_list,
-};
+LIST_NODE* transport_list = NULL;
 
 SDB_MUTEX_DEFINE( transport_lock );
+SDB_MUTEX_DEFINE( wakeup_select_lock );
 
 #ifdef _WIN32 /* FIXME : move to sysdeps.h later */
 int asprintf( char **, char *, ... );
@@ -60,183 +74,121 @@ int asprintf( char **sptr, char *fmt, ... )
 }
 #endif
 
-#if SDB_TRACE
-#define MAX_DUMP_HEX_LEN 16
-static void  dump_hex( const unsigned char*  ptr, size_t  len )
+#define MAX_DUMP_HEX_LEN 30
+static void  dump_hex( const unsigned char*  ptr, size_t  len)
 {
-    int  nn, len2 = len;
-    // Build a string instead of logging each character.
-    // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
-    char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
+    if(SDB_TRACING) {
+        char hex_str[]= "0123456789abcdef";
 
-    if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
+        if(len > MAX_DUMP_HEX_LEN) {
+            len = MAX_DUMP_HEX_LEN;
+        }
 
-    for (nn = 0; nn < len2; nn++) {
-        sprintf(pb, "%02x", ptr[nn]);
-        pb += 2;
-    }
-    sprintf(pb++, " ");
+        int  i;
+        char hex[len*2 + 1];
+        for (i = 0; i < len; i++) {
+            hex[i*2 + 0] = hex_str[ptr[i] >> 4];
+            hex[i*2 + 1] = hex_str[ptr[i] & 0x0F];
+        }
+        hex[len*2] = '\0';
 
-    for (nn = 0; nn < len2; nn++) {
-        int  c = ptr[nn];
-        if (c < 32 || c > 127)
-            c = '.';
-        *pb++ =  c;
+        char asci[len + 1];
+        for (i = 0; i < len; i++) {
+            if ((int)ptr[i] >= 32 && (int)ptr[i] <= 127) {
+                asci[i] = ptr[i];
+            }
+            else {
+                asci[i] = '.';
+            }
+        }
+        asci[len] = '\0';
+
+        DR("HEX:'%s', ASCI:'%s'\n", hex, asci);
     }
-    *pb++ = '\0';
-    DR("%s\n", buffer);
 }
-#endif
 
 void
-kick_transport(atransport*  t)
+kick_transport(TRANSPORT*  t)
 {
     if (t && !t->kicked)
     {
         int  kicked;
 
-        sdb_mutex_lock(&transport_lock);
+        sdb_mutex_lock(&transport_lock, "transport kick_transport");
         kicked = t->kicked;
         if (!kicked)
             t->kicked = 1;
-        sdb_mutex_unlock(&transport_lock);
+        sdb_mutex_unlock(&transport_lock, "transport kick_transport");
 
         if (!kicked)
             t->kick(t);
     }
 }
 
-void
-run_transport_disconnects(atransport*  t)
+static void run_transport_close(TRANSPORT* t)
 {
-    adisconnect*  dis = t->disconnects.next;
+    D("T(%s)\n", t->serial);
+    LIST_NODE* curptr = listener_list;
 
-    D("%s: run_transport_disconnects\n", t->serial);
-    while (dis != &t->disconnects) {
-        adisconnect*  next = dis->next;
-        dis->func( dis->opaque, t );
-        dis = next;
-    }
-}
+    while(curptr != NULL) {
+        LISTENER* l = curptr->data;
+        curptr = curptr->next_ptr;
 
-#if SDB_TRACE
-static void
-dump_packet(const char* name, const char* func, apacket* p)
-{
-    unsigned  command = p->msg.command;
-    int       len     = p->msg.data_length;
-    char      cmd[9];
-    char      arg0[12], arg1[12];
-    int       n;
-
-    for (n = 0; n < 4; n++) {
-        int  b = (command >> (n*8)) & 255;
-        if (b < 32 || b >= 127)
-            break;
-        cmd[n] = (char)b;
-    }
-    if (n == 4) {
-        cmd[4] = 0;
-    } else {
-        /* There is some non-ASCII name in the command, so dump
-            * the hexadecimal value instead */
-        snprintf(cmd, sizeof cmd, "%08x", command);
+        if(l->transport == t) {
+            D("LN(%s) being closed by T(%s)\n", l->local_name, t->serial);
+            remove_node(&listener_list, l->node, free_listener);
+        }
     }
 
-    if (p->msg.arg0 < 256U)
-        snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
-    else
-        snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
+    curptr = local_socket_list;
+    while(curptr != NULL) {
+        SDB_SOCKET* s = curptr->data;
+        curptr = curptr->next_ptr;
 
-    if (p->msg.arg1 < 256U)
-        snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
-    else
-        snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
-
-    D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
-        name, func, cmd, arg0, arg1, len);
-    dump_hex(p->data, len);
-}
-#endif /* SDB_TRACE */
-
-static int
-read_packet(int  fd, const char* name, apacket** ppacket)
-{
-    char *p = (char*)ppacket;  /* really read a packet address */
-    int   r;
-    int   len = sizeof(*ppacket);
-    char  buff[8];
-    if (!name) {
-        snprintf(buff, sizeof buff, "fd=%d", fd);
-        name = buff;
-    }
-    while(len > 0) {
-        r = sdb_read(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p   += r;
-        } else {
-            D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
-            return -1;
+        if(s->transport == t) {
+            D("LS(%X) FD(%d) being closed by T(%s)\n", s->local_id, s->fd, t->serial);
+            local_socket_close(s);
         }
     }
-
-#if SDB_TRACE
-    if (SDB_TRACING) {
-        dump_packet(name, "from remote", *ppacket);
-    }
-#endif
-    return 0;
 }
 
-static int
-write_packet(int  fd, const char* name, apacket** ppacket)
+
+void dump_packet(const char* name, const char* func, PACKET* p)
 {
-    char *p = (char*) ppacket;  /* we really write the packet address */
-    int r, len = sizeof(ppacket);
-    char buff[8];
-    if (!name) {
-        snprintf(buff, sizeof buff, "fd=%d", fd);
-        name = buff;
-    }
+    if(SDB_TRACING) {
+        unsigned  cmd = p->msg.command;
+        char command[9];
 
-#if SDB_TRACE
-    if (SDB_TRACING) {
-        dump_packet(name, "to remote", *ppacket);
-    }
-#endif
-    len = sizeof(ppacket);
-    while(len > 0) {
-        r = sdb_write(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
-            return -1;
+        if(cmd == A_CLSE) {
+            snprintf(command, sizeof command, "%s", "A_CLSE");
         }
-    }
-    return 0;
-}
-
-static void transport_socket_events(int fd, unsigned events, void *_t)
-{
-    atransport *t = _t;
-    D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
-    if(events & FDE_READ){
-        apacket *p = 0;
-        if(read_packet(fd, t->serial, &p)){
-            D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
-        } else {
-            handle_packet(p, (atransport *) _t);
+        else if(cmd == A_CNXN) {
+            snprintf(command, sizeof command, "%s", "A_CNXN");
+        }
+        else if(cmd == A_OPEN) {
+            snprintf(command, sizeof command, "%s", "A_OPEN");
         }
+        else if(cmd == A_OKAY) {
+            snprintf(command, sizeof command, "%s", "A_OKAY");
+        }
+        else if(cmd == A_WRTE) {
+            snprintf(command, sizeof command, "%s", "A_WRTE");
+        }
+        else if(cmd == A_TCLS) {
+            snprintf(command, sizeof command, "%s", "A_TCLS");
+        }
+        else {
+            //unrecongnized command dump the hexadecimal value.
+            snprintf(command, sizeof command, "%08x", cmd);
+        }
+
+        D("T(%s) %s: [%s] arg0=%X arg1=%X (len=%d) (total_msg_len=%d)\n",
+            name, func, command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->len);
+        dump_hex(p->data, p->msg.data_length);
     }
 }
 
-void send_packet(apacket *p, atransport *t)
-{
+static void encoding_packet(PACKET* p) {
     unsigned char *x;
     unsigned sum;
     unsigned count;
@@ -250,147 +202,116 @@ void send_packet(apacket *p, atransport *t)
         sum += *x++;
     }
     p->msg.data_check = sum;
+}
 
-    print_packet("send", p);
+void send_packet(PACKET *p, TRANSPORT *t)
+{
+    if(t != NULL && t->connection_state != CS_OFFLINE) {
+        encoding_packet(p);
 
-    if (t == NULL) {
-        D("Transport is null \n");
-        // Zap errno because print_packet() and other stuff have errno effect.
-        errno = 0;
-        fatal_errno("Transport is null");
+        D("%s: transport got packet, sending to remote\n", t->serial);
+        t->write_to_remote(p, t);
     }
-
-    if(write_packet(t->transport_socket, t->serial, &p)){
-        fatal_errno("cannot enqueue packet on transport socket");
+    else {
+        if (t == NULL) {
+            D("Transport is null \n");
+            errno = 0;
+            LOG_FATAL("Transport is null\n");
+        }
+        else {
+            D("%s: transport ignoring packet while offline\n", t->serial);
+        }
     }
 }
 
-/* The transport is opened by transport_register_func before
-** the input and output threads are started.
-**
-** The output thread issues a SYNC(1, token) message to let
-** the input thread know to start things up.  In the event
-** of transport IO failure, the output thread will post a
-** SYNC(0,0) message to ensure shutdown.
-**
-** The transport will not actually be closed until both
-** threads exit, but the input thread will kick the transport
-** on its way out to disconnect the underlying device.
-*/
-
-static void *output_thread(void *_t)
-{
-    atransport *t = _t;
-    apacket *p;
-
-    D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
-       t->serial, t->fd, t->sync_token + 1);
-    p = get_apacket();
-    p->msg.command = A_SYNC;
-    p->msg.arg0 = 1;
-    p->msg.arg1 = ++(t->sync_token);
-    p->msg.magic = A_SYNC ^ 0xffffffff;
-    if(write_packet(t->fd, t->serial, &p)) {
-        put_apacket(p);
-        D("%s: failed to write SYNC packet\n", t->serial);
-        goto oops;
-    }
+static __inline__ void wakeup_select(T_PACKET* t_packet) {
+    sdb_mutex_lock(&wakeup_select_lock, "wakeup_select");
+    writex(fdevent_wakeup_send, &t_packet, sizeof(t_packet));
+    sdb_mutex_unlock(&wakeup_select_lock, "wakeup_select");
+}
 
-    D("%s: data pump started\n", t->serial);
-    for(;;) {
-        p = get_apacket();
+static void handle_packet(PACKET *p, TRANSPORT *t)
+{
+    unsigned int cmd = p->msg.command;
+    T_PACKET* t_packet = malloc(sizeof(T_PACKET));
+    t_packet->t = t;
+    t_packet->p = NULL;
 
-        if(t->read_from_remote(p, t) == 0){
-            D("%s: received remote packet, sending to transport\n",
-              t->serial);
-            if(write_packet(t->fd, t->serial, &p)){
-                put_apacket(p);
-                D("%s: failed to write apacket to transport\n", t->serial);
-                goto oops;
-            }
-        } else {
-            D("%s: remote read failed for transport\n", t->serial);
-            put_apacket(p);
-            break;
-        }
+    //below commands should be done in main thread. packet is used in wakeup_select_func. Do not put a packet
+    if(cmd == A_WRTE || cmd == A_CLSE || cmd == A_CNXN || cmd == A_OKAY || cmd == A_STAT) {
+        ++(t->req);
+        t_packet->p = p;
+        wakeup_select(t_packet);
+        return;
     }
-
-    D("%s: SYNC offline for transport\n", t->serial);
-    p = get_apacket();
-    p->msg.command = A_SYNC;
-    p->msg.arg0 = 0;
-    p->msg.arg1 = 0;
-    p->msg.magic = A_SYNC ^ 0xffffffff;
-    if(write_packet(t->fd, t->serial, &p)) {
-        put_apacket(p);
-        D("%s: failed to write SYNC apacket to transport", t->serial);
+    else if(cmd == A_OPEN) {
+        LOG_FATAL("server does not handle A_OPEN\n");
+        exit(1);
     }
-
-oops:
-    D("%s: transport output thread is exiting\n", t->serial);
-    kick_transport(t);
-    transport_unref(t);
-    return 0;
+    D("Unknown packet command %08x\n", p->msg.command);
+    put_apacket(p);
+    free(t_packet);
 }
 
-static void *input_thread(void *_t)
+#define CNXN_DATA_MAX_TOKENS 3
+static void parse_banner(char *data, TRANSPORT *t)
 {
-    atransport *t = _t;
-    apacket *p;
-    int active = 0;
+    char *banner = s_strdup(data);
+    char *end = NULL;
 
-    D("%s: starting transport input thread, reading from fd %d\n",
-       t->serial, t->fd);
+    end = strchr(banner, ':');
+    if(end) {
+        *end = '\0';
+    }
+    const char* target_banner = STATE_HOST;
+    if(!strcmp(banner, STATE_DEVICE)) {
+        t->connection_state = CS_DEVICE;
+        target_banner = STATE_DEVICE;
+    }
+    else if(!strcmp(banner, STATE_BOOTLOADER)){
+        t->connection_state = CS_BOOTLOADER;
+        target_banner = STATE_BOOTLOADER;
+    }
+    else if(!strcmp(banner, STATE_RECOVERY)) {
+        t->connection_state = CS_RECOVERY;
+        target_banner = STATE_RECOVERY;
+    }
+    else if(!strcmp(banner, STATE_SIDELOAD)) {
+        t->connection_state = CS_SIDELOAD;
+        target_banner = STATE_SIDELOAD;
+    }
+    else {
+        t->connection_state = CS_HOST;
+    }
+    if (banner != NULL) {
+        s_free(banner);
+    }
+    // since version 2
+    char *tokens[CNXN_DATA_MAX_TOKENS];
+    size_t cnt = tokenize(data, "::", tokens, CNXN_DATA_MAX_TOKENS);
 
-    for(;;){
-        if(read_packet(t->fd, t->serial, &p)) {
-            D("%s: failed to read apacket from transport on fd %d\n",
-               t->serial, t->fd );
-            break;
-        }
-        if(p->msg.command == A_SYNC){
-            if(p->msg.arg0 == 0) {
-                D("%s: transport SYNC offline\n", t->serial);
-                put_apacket(p);
-                break;
-            } else {
-                if(p->msg.arg1 == t->sync_token) {
-                    D("%s: transport SYNC online\n", t->serial);
-                    active = 1;
-                } else {
-                    D("%s: transport ignoring SYNC %d != %d\n",
-                      t->serial, p->msg.arg1, t->sync_token);
-                }
-            }
-        } else {
-            if(active) {
-                D("%s: transport got packet, sending to remote\n", t->serial);
-                t->write_to_remote(p, t);
-            } else {
-                D("%s: transport ignoring packet while offline\n", t->serial);
-            }
+    if (cnt == 3) {
+        // update device_name except usb device but it should be changed soon.
+        if (strcmp(STATE_UNKNOWN, tokens[1])) {
+            t->device_name = strdup(tokens[1]);
         }
 
-        put_apacket(p);
+        if (!strcmp(tokens[2], "1")) {
+            t->connection_state = CS_PWLOCK;
+            target_banner = STATE_LOCKED;
+        }
     }
 
-    // this is necessary to avoid a race condition that occured when a transport closes
-    // while a client socket is still active.
-    close_all_sockets(t);
+    if (cnt) {
+        free_strings(tokens, cnt);
+    }
 
-    D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
-    kick_transport(t);
-    transport_unref(t);
-    return 0;
+    D("setting connection_state to '%s'\n", target_banner);
+    update_transports();
+    return;
 }
 
-
-static int transport_registration_send = -1;
-static int transport_registration_recv = -1;
-static fdevent transport_registration_fde;
-
-
-static int list_transports_msg(char*  buffer, size_t  bufferlen)
+int list_transports_msg(char*  buffer, size_t  bufferlen)
 {
     char  head[5];
     int   len;
@@ -402,519 +323,221 @@ static int list_transports_msg(char*  buffer, size_t  bufferlen)
     return len;
 }
 
-/* this adds support required by the 'track-devices' service.
- * this is used to send the content of "list_transport" to any
- * number of client connections that want it through a single
- * live TCP connection
- */
-typedef struct device_tracker  device_tracker;
-struct device_tracker {
-    asocket          socket;
-    int              update_needed;
-    device_tracker*  next;
-};
-
-/* linked list of all device trackers */
-static device_tracker*   device_tracker_list;
-
-static void
-device_tracker_remove( device_tracker*  tracker )
+static void  update_transports(void)
 {
-    device_tracker**  pnode = &device_tracker_list;
-    device_tracker*   node  = *pnode;
+    D("update transports\n");
+    char             buffer[1024];
+    int              len;
 
-    sdb_mutex_lock( &transport_lock );
-    while (node) {
-        if (node == tracker) {
-            *pnode = node->next;
-            break;
-        }
-        pnode = &node->next;
-        node  = *pnode;
-    }
-    sdb_mutex_unlock( &transport_lock );
-}
+    len = list_transports_msg(buffer, sizeof(buffer));
 
-static void
-device_tracker_close( asocket*  socket )
-{
-    device_tracker*  tracker = (device_tracker*) socket;
-    asocket*         peer    = socket->peer;
 
-    D( "device tracker %p removed\n", tracker);
-    if (peer) {
-        peer->peer = NULL;
-        peer->close(peer);
+    LIST_NODE* curptr = local_socket_list;
+    while(curptr != NULL) {
+        SDB_SOCKET *s = curptr->data;
+        curptr = curptr->next_ptr;
+        if (HAS_SOCKET_STATUS(s, DEVICE_TRACKER)) {
+            device_tracker_send(s, buffer, len);
+        }
     }
-    device_tracker_remove(tracker);
-    free(tracker);
 }
 
-static int
-device_tracker_enqueue( asocket*  socket, apacket*  p )
-{
-    /* you can't read from a device tracker, close immediately */
-    put_apacket(p);
-    device_tracker_close(socket);
-    return -1;
-}
-
-static int
-device_tracker_send( device_tracker*  tracker,
-                     const char*      buffer,
-                     int              len )
-{
-    apacket*  p = get_apacket();
-    asocket*  peer = tracker->socket.peer;
-
-    memcpy(p->data, buffer, len);
-    p->len = len;
-    return peer->enqueue( peer, p );
-}
+void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t) {
+    PACKET *p = get_apacket();
+    p->msg.arg0 = arg0;
+    p->msg.arg1 = arg1;
+    p->msg.command = cmd;
 
-
-static void
-device_tracker_ready( asocket*  socket )
-{
-    device_tracker*  tracker = (device_tracker*) socket;
-
-    /* we want to send the device list when the tracker connects
-    * for the first time, even if no update occured */
-    if (tracker->update_needed > 0) {
-        char  buffer[1024];
-        int   len;
-
-        tracker->update_needed = 0;
-
-        len = list_transports_msg(buffer, sizeof(buffer));
-        device_tracker_send(tracker, buffer, len);
+    if(data != NULL) {
+        snprintf((char*)p->data, sizeof(p->data), "%s", data);
+        p->msg.data_length = strlen((char*)p->data) + 1;
     }
-}
-
-
-asocket*
-create_device_tracker(void)
-{
-    device_tracker*  tracker = calloc(1,sizeof(*tracker));
-
-    if(tracker == 0) fatal("cannot allocate device tracker");
-
-    D( "device tracker %p created\n", tracker);
 
-    tracker->socket.enqueue = device_tracker_enqueue;
-    tracker->socket.ready   = device_tracker_ready;
-    tracker->socket.close   = device_tracker_close;
-    tracker->update_needed  = 1;
-
-    tracker->next       = device_tracker_list;
-    device_tracker_list = tracker;
-
-    return &tracker->socket;
+    send_packet(p, t);
+    put_apacket(p);
 }
 
-
-/* call this function each time the transport list has changed */
-void  update_transports(void)
+static void *transport_thread(void *_t)
 {
-    char             buffer[1024];
-    int              len;
-    device_tracker*  tracker;
-
-    len = list_transports_msg(buffer, sizeof(buffer));
-
-    tracker = device_tracker_list;
-    while (tracker != NULL) {
-        device_tracker*  next = tracker->next;
-        /* note: this may destroy the tracker if the connection is closed */
-        device_tracker_send(tracker, buffer, len);
-        tracker = next;
-    }
-}
+    TRANSPORT *t = _t;
+    PACKET *p;
 
-typedef struct tmsg tmsg;
-struct tmsg
-{
-    atransport *transport;
-    int         action;
-};
+    D("T(%s), FD(%d)\n", t->serial, t->sfd);
+    t->connection_state = CS_WAITCNXN;
+    send_cmd(A_VERSION, MAX_PAYLOAD, A_CNXN, "host::", t);
+    t->connection_state = CS_OFFLINE;
+    // allow the device some time to respond to the connect message
+    sdb_sleep_ms(1000);
 
-static int
-transport_read_action(int  fd, struct tmsg*  m)
-{
-    char *p   = (char*)m;
-    int   len = sizeof(*m);
-    int   r;
+    D("%s: data dump started\n", t->serial);
+    while(1) {
+        p = get_apacket();
+        LOG_INFO("T(%s) remote read start\n", t->serial);
 
-    while(len > 0) {
-        r = sdb_read(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p   += r;
-        } else {
-            if((r < 0) && (errno == EINTR)) continue;
-            D("transport_read_action: on fd %d, error %d: %s\n",
-              fd, errno, strerror(errno));
-            return -1;
+        if(t->read_from_remote(t, &p->msg, sizeof(MESSAGE))) {
+               break;
         }
-    }
-    return 0;
-}
-
-static int
-transport_write_action(int  fd, struct tmsg*  m)
-{
-    char *p   = (char*)m;
-    int   len = sizeof(*m);
-    int   r;
-
-    while(len > 0) {
-        r = sdb_write(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p   += r;
-        } else {
-            if((r < 0) && (errno == EINTR)) continue;
-            D("transport_write_action: on fd %d, error %d: %s\n",
-              fd, errno, strerror(errno));
-            return -1;
+               if(check_header(p)) {
+                       break;
+               }
+               if(p->msg.data_length) {
+                       if(t->read_from_remote(t, p->data, p->msg.data_length)){
+                               break;
+                       }
+               }
+               if(check_data(p)) {
+                       break;
+               }
+               dump_packet(t->serial, "remote_read", p);
+               D("%s: received remote packet, sending to transport\n",
+                 t->serial);
+               handle_packet(p, t);
+    }
+       LOG_INFO("T(%s) remote read fail. terminate transport\n", t->serial);
+       put_apacket(p);
+
+    t->connection_state = CS_OFFLINE;
+    do {
+        if(t->req == t->res) {
+            p = get_apacket();
+            p->msg.command = A_TCLS;
+            T_PACKET* t_packet = malloc(sizeof(T_PACKET));
+            t_packet->t = t;
+            t_packet->p = p;
+            wakeup_select(t_packet);
+            break;
+        }
+        else {
+            //TODO this should be changed to wait later.
+            sdb_sleep_ms(1000);
         }
     }
+    while(1);
     return 0;
 }
 
-static sdb_cond_t cond;// = PTHREAD_COND_INITIALIZER;
-
-static void transport_registration_func(int _fd, unsigned ev, void *data)
+void register_transport(TRANSPORT *t)
 {
-    tmsg m;
-    sdb_thread_t output_thread_ptr;
-    sdb_thread_t input_thread_ptr;
-    int s[2];
-    atransport *t;
-
-    if(!(ev & FDE_READ)) {
-        return;
-    }
-
-    if(transport_read_action(_fd, &m)) {
-        fatal_errno("cannot read transport registration socket");
-    }
-
-    t = m.transport;
-
-    if(m.action == 0){
-        D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
-
-            /* IMPORTANT: the remove closes one half of the
-            ** socket pair.  The close closes the other half.
-            */
-        fdevent_remove(&(t->transport_fde));
-        sdb_close(t->fd);
-
-        sdb_mutex_lock(&transport_lock);
-        t->next->prev = t->prev;
-        t->prev->next = t->next;
-
-        sdb_cond_broadcast(&cond);
-        sdb_mutex_unlock(&transport_lock);
-
-        run_transport_disconnects(t);
-
-        if (t->product)
-            free(t->product);
-        if (t->serial)
-            free(t->serial);
-        if (t->device_name)
-            free(t->device_name);
-
-        memset(t,0xee,sizeof(atransport));
-        free(t);
-
-        update_transports();
-        return;
-    }
-
-    /* don't create transport threads for inaccessible devices */
-    if (t->connection_state != CS_NOPERM) {
-        /* initial references are the two threads */
-        t->ref_count = 2;
-
-        if(sdb_socketpair(s)) {
-            fatal_errno("cannot open transport socketpair");
-        }
-
-        D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
-
-        t->transport_socket = s[0];
-        t->fd = s[1];
-
-        fdevent_install(&(t->transport_fde),
-                        t->transport_socket,
-                        transport_socket_events,
-                        t);
-
-        fdevent_set(&(t->transport_fde), FDE_READ);
+    D("T(%s), device name: '%s'\n", t->serial, t->device_name);
+    sdb_thread_t transport_thread_ptr;
 
-        if(sdb_thread_create(&input_thread_ptr, input_thread, t)){
-            fatal_errno("cannot create input thread");
-        }
-
-        if(sdb_thread_create(&output_thread_ptr, output_thread, t)){
-            fatal_errno("cannot create output thread");
-        }
+    //transport is updated by transport_thread, we do not have to update here.
+    if(sdb_thread_create(&transport_thread_ptr, transport_thread, t)){
+        LOG_FATAL("cannot create output thread\n");
     }
 
         /* put us on the master device list */
-    sdb_mutex_lock(&transport_lock);
-    t->next = &transport_list;
-    t->prev = transport_list.prev;
-    t->next->prev = t;
-    t->prev->next = t;
-
-    sdb_cond_broadcast(&cond);
-    sdb_mutex_unlock(&transport_lock);
-
-    t->disconnects.next = t->disconnects.prev = &t->disconnects;
-
-    update_transports();
+    sdb_mutex_lock(&transport_lock, "transport register_transport");
+    t->node = prepend(&transport_list, t);
+    sdb_mutex_unlock(&transport_lock, "transport register_transport");
 }
 
-void init_transport_registration(void)
+//lock is done by transport_unref
+static void remove_transport(TRANSPORT *t)
 {
-    int s[2];
+    D("transport removed. serial: %s, device name: %s\n", t->serial, t->device_name);
 
-    sdb_cond_init(&cond, NULL);
-    if(sdb_socketpair(s)){
-        fatal_errno("cannot open transport registration socketpair");
-    }
+    remove_node(&transport_list, t->node, no_free);
 
-    transport_registration_send = s[0];
-    transport_registration_recv = s[1];
+    run_transport_close(t);
 
-    fdevent_install(&transport_registration_fde,
-                    transport_registration_recv,
-                    transport_registration_func,
-                    0);
+    if (t->serial)
+        free(t->serial);
+    if (t->device_name)
+        free(t->device_name);
 
-    fdevent_set(&transport_registration_fde, FDE_READ);
+    free(t);
 }
 
-/* the fdevent select pump is single threaded */
-static void register_transport(atransport *transport)
+
+static void transport_unref(TRANSPORT *t)
 {
-    tmsg m;
-    m.transport = transport;
-    m.action = 1;
-    D("transport: %s registered\n", transport->serial);
-    if(transport_write_action(transport_registration_send, &m)) {
-        fatal_errno("cannot write transport registration socket\n");
+    if (t == NULL) {
+        return;
     }
-}
 
-static void remove_transport(atransport *transport)
-{
-    tmsg m;
-    m.transport = transport;
-    m.action = 0;
-    D("transport: %s removed\n", transport->serial);
-    if(transport_write_action(transport_registration_send, &m)) {
-        fatal_errno("cannot write transport registration socket\n");
+    sdb_mutex_lock(&transport_lock, "transport_unref transport");
+    int nr;
+
+    D("transport: %s unref (kicking and closing)\n", t->serial);
+    if (!t->kicked) {
+        t->kicked = 1;
+        t->kick(t);
     }
-}
+    t->close(t);
+    remove_transport(t);
 
+    LIST_NODE* curptr = transport_list;
 
-static void transport_unref_locked(atransport *t)
-{
-    atransport *tmp;
-    int nr;
-    t->ref_count--;
-    if (t->ref_count == 0) {
-        D("transport: %s unref (kicking and closing)\n", t->serial);
-        if (!t->kicked) {
-            t->kicked = 1;
-            t->kick(t);
-        }
-        t->close(t);
-        remove_transport(t);
-
-        /* update tizen specific device name */
-        for (tmp = t->next; tmp && tmp != &transport_list; tmp = tmp->next) {
-            if (tmp->type == kTransportUsb) {
-                D("update tizen specific device name: %s\n", tmp->device_name);
-                if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) {
-                    free(tmp->device_name);
-                    asprintf(&tmp->device_name, "device-%d", nr - 1);
-                }
+    while(curptr != NULL) {
+        TRANSPORT* tmp = curptr->data;
+        curptr = curptr->next_ptr;
+        if (tmp->type == kTransportUsb) {
+            if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) {
+                free(tmp->device_name);
+                asprintf(&tmp->device_name, "device-%d", nr - 1);
             }
         }
-    } else {
-        D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
     }
-}
 
-static void transport_unref(atransport *t)
-{
-    if (t) {
-        sdb_mutex_lock(&transport_lock);
-        transport_unref_locked(t);
-        sdb_mutex_unlock(&transport_lock);
-    }
+    sdb_mutex_unlock(&transport_lock, "transport_unref transport");
+    update_transports();
 }
 
-void add_transport_disconnect(atransport*  t, adisconnect*  dis)
+TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char** error_out)
 {
-    sdb_mutex_lock(&transport_lock);
-    dis->next       = &t->disconnects;
-    dis->prev       = dis->next->prev;
-    dis->prev->next = dis;
-    dis->next->prev = dis;
-    sdb_mutex_unlock(&transport_lock);
-}
+    TRANSPORT *result = NULL;
+    char* null_str = NULL;
 
-void remove_transport_disconnect(atransport*  t, adisconnect*  dis)
-{
-    dis->prev->next = dis->next;
-    dis->next->prev = dis->prev;
-    dis->next = dis->prev = dis;
-}
+    if(error_out == NULL) {
+        error_out = &null_str;
+    }
 
+    sdb_mutex_lock(&transport_lock, "transport acquire_one_transport");
 
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
-{
-    atransport *t;
-    atransport *result = NULL;
-    int ambiguous = 0;
-
-retry:
-    if (error_out)
-        *error_out = "device not found";
-
-    sdb_mutex_lock(&transport_lock);
-    for (t = transport_list.next; t != &transport_list; t = t->next) {
-        if (t->connection_state == CS_NOPERM) {
-        if (error_out)
-            *error_out = "insufficient permissions for device";
-            continue;
-        }
+    LIST_NODE* curptr = transport_list;
+    while(curptr != NULL) {
+        TRANSPORT* transport_ = curptr->data;
+        curptr = curptr->next_ptr;
 
         /* check for matching serial number */
         if (serial) {
-            if (t->serial && !strcmp(serial, t->serial)) {
-                result = t;
+            if (transport_->serial && !strcmp(serial, transport_->serial)) {
+                result = transport_;
                 break;
             }
         } else {
-            if (ttype == kTransportUsb && t->type == kTransportUsb) {
+            if(ttype == kTransportAny) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device";
-                    ambiguous = 1;
+                    *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_TARGET;
                     result = NULL;
                     break;
                 }
-                result = t;
-            } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
-                if (result) {
-                    if (error_out)
-                        *error_out = "more than one emulator";
-                    ambiguous = 1;
-                    result = NULL;
-                    break;
-                }
-                result = t;
-            } else if (ttype == kTransportAny) {
+                result = transport_;
+            }
+            if (ttype == transport_->type) {
                 if (result) {
-                    if (error_out)
-                        *error_out = "more than one device and emulator";
-                    ambiguous = 1;
+                    if(ttype == kTransportUsb) {
+                        *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_DEV;
+                    }
+                    else if(ttype == kTransportLocal) {
+                        *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_EMUL;
+                    }
                     result = NULL;
                     break;
                 }
-                result = t;
+                result = transport_;
             }
         }
     }
-    sdb_mutex_unlock(&transport_lock);
-
-    if (result) {
-         /* offline devices are ignored -- they are either being born or dying */
-        if (result && result->connection_state == CS_OFFLINE) {
-            if (error_out)
-                *error_out = "device offline";
-            result = NULL;
-        }
-         /* check for required connection state */
-        if (result && state != CS_ANY && result->connection_state != state) {
-            if (error_out)
-                *error_out = "invalid device state";
-            result = NULL;
-        }
-    }
-
-    if (result) {
-        /* found one that we can take */
-        if (error_out)
-            *error_out = NULL;
-    } else if (state != CS_ANY && (serial || !ambiguous)) {
-        sdb_sleep_ms(1000);
-        goto retry;
-    }
 
-    return result;
-}
-
-static const char *statename(atransport *t)
-{
-    switch(t->connection_state){
-    case CS_OFFLINE: return "offline";
-    case CS_BOOTLOADER: return "bootloader";
-    case CS_DEVICE: return "device";
-    case CS_HOST: return "host";
-    case CS_RECOVERY: return "recovery";
-    case CS_SIDELOAD: return "sideload";
-    case CS_NOPERM: return "no permissions";
-    default: return "unknown";
-    }
-}
-
-/*
- * find number of devices which serial match with the prefix
- */
-int find_transports(char **serial_out, const char *prefix)
-{
-    int nr = 0; // not found
-    char *match = NULL;
-    atransport *t;
-
-    if (!serial_out || !prefix)
-        return -1;
-
-    sdb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        char* serial = t->serial;
-        if (!serial || !serial[0])
-            continue;
-        if (!strncmp(prefix, serial, strlen(prefix))) {
-            match = serial;
-            nr++;
-        }
+    sdb_mutex_unlock(&transport_lock, "transport acquire_one_transport");
 
-        if (nr > 1) {
-            match = NULL;
-            break;
-        }
-    }
-    sdb_mutex_unlock(&transport_lock);
-
-    if (nr == 1 && match) {
-        *serial_out = strdup(match);
-    } else if (nr == 0) {
-        asprintf(serial_out, "device not found");
-    } else if (nr > 1) {
-        asprintf(serial_out, "more than one device and emulator");
+    if (result == NULL ) {
+        *error_out = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND;
     }
 
-    return nr;
+    return result;
 }
 
 int list_transports(char *buf, size_t  bufsize)
@@ -922,16 +545,20 @@ int list_transports(char *buf, size_t  bufsize)
     char*       p   = buf;
     char*       end = buf + bufsize;
     int         len;
-    atransport *t;
 
         /* XXX OVERRUN PROBLEMS XXX */
-    sdb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
+    sdb_mutex_lock(&transport_lock, "transport list_transports");
+
+    LIST_NODE* curptr = transport_list;
+    while(curptr != NULL) {
+        TRANSPORT* t = curptr->data;
+        curptr = curptr->next_ptr;
         const char* serial = t->serial;
         const char* devicename = (t->device_name == NULL) ? DEFAULT_DEVICENAME : t->device_name; /* tizen specific */
         if (!serial || !serial[0])
             serial = "????????????";
-        len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, statename(t), devicename);
+        // FIXME: what if each string length is longger than static length?
+        len = snprintf(p, end - p, "%-20s\t%-10s\t%s\n", serial, connection_state_name(t), devicename);
 
         if (p + len >= end) {
             /* discard last line if buffer is too short */
@@ -939,168 +566,48 @@ int list_transports(char *buf, size_t  bufsize)
         }
         p += len;
     }
+
     p[0] = 0;
-    sdb_mutex_unlock(&transport_lock);
+    sdb_mutex_unlock(&transport_lock, "transport list_transports");
     return p - buf;
 }
 
+int register_device_con_transport(int s, const char *serial) {
 
-/* hack for osx */
-void close_usb_devices()
-{
-    atransport *t;
-
-    sdb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        if ( !t->kicked ) {
-            t->kicked = 1;
-            t->kick(t);
-        }
+    //TODO REMOTE_DEVICE_CONNECT complete device connect after resolving security issue
+#if 0
+    if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) {
+        LOG_ERROR("Too many tcp connection\n");
+        return -1;
     }
-    sdb_mutex_unlock(&transport_lock);
-}
 
-void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name)
-{
-    atransport *t = calloc(1, sizeof(atransport));
+    TRANSPORT *t = calloc(1, sizeof(TRANSPORT));
     char buff[32];
 
     if (!serial) {
         snprintf(buff, sizeof buff, "T-%p", t);
-        serial = buff;
-    }
-    D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name);
-    if ( init_socket_transport(t, s, port, local) < 0 ) {
-        sdb_close(s);
-        free(t);
-        atransport *old_t = find_transport(serial);
-        if (old_t) {
-           unregister_transport(old_t);
-        } else {
-           D("No such device %s", serial);
-        }
-        return;
     }
-    if(serial) {
-        t->serial = strdup(serial);
+    else {
+        snprintf(buff, sizeof buff, "T-%s", serial);
     }
+    serial = buff;
 
-    if (device_name) {/* tizen specific */
-        t->device_name = strdup(device_name);
-    } else { // device_name could be null when sdb server was forked before qemu has sent the connect message.
-        char device_name[DEVICENAME_MAX];
-        if (get_devicename_from_shdmem(port, device_name) == 0) {
-            t->device_name = strdup(device_name);
-        }
+    init_socket_transport(t, s, 0);
+    t->remote_cnxn_socket = NULL;
+    t->serial = strdup(buff);
+    t->device_name = strdup("unknown");
+    t->type = kTransportRemoteDevCon;
+    TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL);
+    if(old_t != NULL) {
+        D("old transport '%s' is found. Unregister it\n", old_t->serial);
+        kick_transport(old_t);
     }
 
+    ++current_local_transports;
     register_transport(t);
-}
-
-atransport *find_transport(const char *serial)
-{
-    atransport *t;
-
-    sdb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        if (t->serial && !strcmp(serial, t->serial)) {
-            break;
-        }
-     }
-    sdb_mutex_unlock(&transport_lock);
-
-    if (t != &transport_list)
-        return t;
-    else
-        return 0;
-}
-
-void unregister_transport(atransport *t)
-{
-    sdb_mutex_lock(&transport_lock);
-    t->next->prev = t->prev;
-    t->prev->next = t->next;
-    sdb_mutex_unlock(&transport_lock);
-
-    kick_transport(t);
-    transport_unref(t);
-}
-
-// unregisters all non-emulator TCP transports
-void unregister_all_tcp_transports()
-{
-    atransport *t, *next;
-    sdb_mutex_lock(&transport_lock);
-    for (t = transport_list.next; t != &transport_list; t = next) {
-        next = t->next;
-        if (t->type == kTransportLocal && t->sdb_port == 0) {
-            t->next->prev = t->prev;
-            t->prev->next = next;
-            // we cannot call kick_transport when holding transport_lock
-            if (!t->kicked)
-            {
-                t->kicked = 1;
-                t->kick(t);
-            }
-            transport_unref_locked(t);
-        }
-     }
-
-    sdb_mutex_unlock(&transport_lock);
-}
-
-static int get_connected_device_count(transport_type type)
-{
-    int cnt = 0;
-    atransport *t;
-    sdb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        if (type == t->type)
-            cnt++;
-     }
-
-    sdb_mutex_unlock(&transport_lock);
-    D("connected device count:%d\n",cnt);
-    return cnt;
-}
-
-void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
-{
-    atransport *t = calloc(1, sizeof(atransport));
-    char device_name[256];
-
-    D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
-      serial ? serial : "");
-    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
-    if(serial) {
-        t->serial = strdup(serial);
-    }
-    /*
-     * send register request to server thread and wait it finished
-     */
-     sdb_mutex_lock(&transport_lock);
-     register_transport(t);
-
-     sdb_cond_wait(&cond, &transport_lock);
-     sdb_mutex_unlock(&transport_lock);
-    /* tizen specific */
-    sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb));
-    t->device_name = strdup(device_name);
-}
-
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb)
-{
-    atransport *t;
-    sdb_mutex_lock(&transport_lock);
-    for(t = transport_list.next; t != &transport_list; t = t->next) {
-        if (t->usb == usb && t->connection_state == CS_NOPERM) {
-            t->next->prev = t->prev;
-            t->prev->next = t->next;
-            break;
-        }
-     }
-    sdb_mutex_unlock(&transport_lock);
+    return 0;
+#endif
+    return -1;
 }
 
 #undef TRACE_TAG
@@ -1109,79 +616,67 @@ void unregister_usb_transport(usb_handle *usb)
 int readx(int fd, void *ptr, size_t len)
 {
     char *p = ptr;
-    int r;
-#if SDB_TRACE
-    int  len0 = len;
-#endif
-    D("readx: fd=%d wanted=%d\n", fd, (int)len);
+    D("FD(%d) wanted=%d\n", fd, (int)len);
     while(len > 0) {
-        r = sdb_read(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            if (r < 0) {
-                D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno));
-                if (errno == EINTR)
-                    continue;
-            } else {
-                D("readx: fd=%d disconnected\n", fd);
+        int r = sdb_read(fd, p, len);
+        if(r < 0) {
+            if(errno == EINTR) {
+                continue;
             }
+            LOG_ERROR("FD(%d) error %d: %s\n", fd, errno, strerror(errno));
+            return -1;
+        }
+        if( r == 0) {
+            D("FD(%d) disconnected\n", fd);
             return -1;
         }
+        len -= r;
+        p += r;
     }
-
-#if SDB_TRACE
-    D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len);
-    dump_hex( ptr, len0 );
-#endif
     return 0;
 }
 
 int writex(int fd, const void *ptr, size_t len)
 {
-    char *p = (char*) ptr;
-    int r;
+    char *p = (char *)ptr;
 
-#if SDB_TRACE
-    D("writex: fd=%d len=%d: ", fd, (int)len);
-    dump_hex( ptr, len );
-#endif
-    while(len > 0) {
-        r = sdb_write(fd, p, len);
-        if(r > 0) {
-            len -= r;
-            p += r;
-        } else {
-            if (r < 0) {
-                D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
-                if (errno == EINTR)
-                    continue;
-            } else {
-                D("writex: fd=%d disconnected\n", fd);
+    while( len > 0) {
+        int r = sdb_write(fd, p, len);
+        if(r < 0) {
+            if (errno == EINTR) {
+                continue;
             }
+            D("fd=%d error %d: %s\n", fd, errno, strerror(errno));
             return -1;
         }
+        if( r == 0) {
+            D("fd=%d disconnected\n", fd);
+            return -1;
+        }
+
+        len -= r;
+        p += r;
     }
     return 0;
 }
 
-int check_header(apacket *p)
+static int check_header(PACKET *p)
 {
     if(p->msg.magic != (p->msg.command ^ 0xffffffff)) {
-        D("check_header(): invalid magic\n");
+        LOG_ERROR("check_header(): invalid magic\n");
         return -1;
     }
 
     if(p->msg.data_length > MAX_PAYLOAD) {
-        D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
+       LOG_ERROR("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length);
         return -1;
     }
 
+    LOG_INFO("success to check header\n");
     return 0;
 }
 
-int check_data(apacket *p)
+static int check_data(PACKET *p)
 {
     unsigned count, sum;
     unsigned char *x;
@@ -1199,3 +694,165 @@ int check_data(apacket *p)
         return 0;
     }
 }
+
+static unsigned int decoding_to_remote_ls_id(unsigned int encoded_ls_id) {
+    unsigned int remote_ls_id = encoded_ls_id & ~15;
+    return remote_ls_id;
+}
+
+static unsigned int decoding_to_local_ls_id(unsigned encoded_ls_id) {
+    unsigned int local_ls_id = encoded_ls_id & 15;
+    local_ls_id |= remote_con_flag;
+    return local_ls_id;
+}
+
+void wakeup_select_func(int _fd, unsigned ev, void *data) {
+    T_PACKET* t_packet = NULL;
+
+    readx(_fd, &t_packet, sizeof(t_packet));
+
+    TRANSPORT* t= t_packet->t;
+    D("T(%s)\n", t->serial);
+    PACKET* p = t_packet->p;
+    free(t_packet);
+
+    if(p == NULL) {
+        D("T(%S) packet NULL\n", t->serial);
+        return;
+    }
+
+    int c_state = t->connection_state;
+    unsigned int cmd = p->msg.command;
+    unsigned int local_id = p->msg.arg1;
+    unsigned int remote_id = p->msg.arg0;
+    SDB_SOCKET* sock = NULL;
+    //CNXN cannot be distinguished using remote_con_flag
+    if(t->remote_cnxn_socket != NULL && cmd == A_CNXN) {
+        dump_packet("remote_con", "wakeup_select_func", p);
+        sock = t->remote_cnxn_socket->data;
+        if(sock != NULL) {
+            remove_first(&(t->remote_cnxn_socket), no_free);
+            LOG_INFO("LS_L(%X)\n", sock->local_id);
+            p->ptr = (void*)(&p->msg);
+            p->len = sizeof(MESSAGE) + p->msg.data_length;
+            local_socket_enqueue(sock, p);
+        }
+        goto endup;
+    }
+    //If transport is remote device, packet should not have to be decoded.
+    if((local_id & remote_con_flag) && t->type != kTransportRemoteDevCon) {
+        LOG_INFO("LS_L(%X), LS_R(%X), LS_E(%X)\n", decoding_to_local_ls_id(local_id),
+                decoding_to_remote_ls_id(local_id), local_id);
+        sock = find_local_socket(decoding_to_local_ls_id(local_id));
+        p->msg.arg1 = decoding_to_remote_ls_id(local_id);
+        p->ptr = (void*)(&p->msg);
+        p->len = sizeof(MESSAGE) + p->msg.data_length;
+        local_socket_enqueue(sock, p);
+        goto endup;
+    }
+    sock = find_local_socket(local_id);
+
+    if(c_state != CS_OFFLINE && sock != NULL) {
+        //packet is used by local_socket_enqueue do not put a packet.
+        if(cmd == A_WRTE) {
+            D("T(%s) write packet from RS(%d) to LS(%X)\n", t->serial, remote_id, local_id);
+            p->len = p->msg.data_length;
+            p->ptr = p->data;
+            if(local_socket_enqueue(sock, p) == 0) {
+                send_cmd(local_id, remote_id, A_OKAY, NULL, t);
+            }
+            goto endup;
+        }
+        else if(cmd == A_OKAY) {
+            if(!HAS_SOCKET_STATUS(sock, REMOTE_SOCKET)) {
+                SET_SOCKET_STATUS(sock, REMOTE_SOCKET);
+                D("remote socket attached LS(%X), RS(%d)\n", sock->local_id, sock->remote_id);
+                sock->remote_id = remote_id;
+                sock->transport = t;
+            }
+            local_socket_ready(sock);
+        }
+    }
+    if(cmd == A_CLSE) {
+        if(sock != NULL) {
+            D("T(%s) close LS(%X)\n", t->serial, local_id);
+            local_socket_close(sock);
+        }
+    }
+    else if(cmd == A_CNXN) {
+        D("T(%s) gets CNXN\n", t->serial);
+        if(t->connection_state != CS_OFFLINE) {
+            t->connection_state = CS_OFFLINE;
+            run_transport_close(t);
+        }
+        parse_banner((char*) p->data, t);
+    }
+    else if(cmd == A_STAT) {
+        D("T(%s) gets A_STAT:%d\n", t->serial, p->msg.arg0);
+        if (t->connection_state != CS_OFFLINE) {
+            t->connection_state = CS_OFFLINE;
+        }
+        if (p->msg.arg0 == 1) {
+            t->connection_state = CS_PWLOCK;
+        } else {
+            t->connection_state = CS_DEVICE;
+        }
+        update_transports();
+    }
+    else if(cmd == A_TCLS) {
+        //transport thread is finished
+        transport_unref(t);
+        return;
+    }
+    put_apacket(p);
+
+endup:
+    //request is done. res increases 1.
+    ++(t->res);
+}
+
+const char *connection_state_name(TRANSPORT *t)
+{
+    if(t != NULL) {
+        int state = t->connection_state;
+
+        if(state == CS_OFFLINE) {
+            return STATE_OFFLINE;
+        }
+        if(state == CS_BOOTLOADER) {
+            return STATE_BOOTLOADER;
+        }
+        if(state == CS_DEVICE) {
+            return STATE_DEVICE;
+        }
+        if(state == CS_HOST) {
+            return STATE_HOST;
+        }
+        if(state == CS_RECOVERY) {
+            return STATE_RECOVERY;
+        }
+        if(state == CS_SIDELOAD) {
+            return STATE_SIDELOAD;
+        }
+        if (state == CS_PWLOCK) {
+            return STATE_LOCKED;
+        }
+    }
+    return STATE_UNKNOWN;
+}
+
+PACKET *get_apacket(void)
+{
+    PACKET *p = malloc(sizeof(PACKET));
+    if(p == 0) {
+        LOG_FATAL("failed to allocate an apacket\n");
+    }
+    memset(p, 0, sizeof(PACKET) - MAX_PAYLOAD);
+    return p;
+}
+
+void put_apacket(void *p)
+{
+    PACKET* packet = p;
+    free(packet);
+}
old mode 100644 (file)
new mode 100755 (executable)
index 511b37e..d7c18af
 #ifndef __TRANSPORT_H
 #define __TRANSPORT_H
 
-/* convenience wrappers around read/write that will retry on
-** EINTR and/or short read/write.  Returns 0 on success, -1
-** on error or EOF.
-*/
-int readx(int fd, void *ptr, size_t len);
-int writex(int fd, const void *ptr, size_t len);
+#include "common_modules.h"
+
+#define  LOCAL_CLIENT_PREFIX  "emulator-"
+
+#define A_CNXN 0x4e584e43
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+#define A_TCLS 0x534C4354
+#define A_STAT 0x54415453
+
+#define CS_NONE      -10000
+#define CS_ANY       -1
+#define CS_OFFLINE    0
+#define CS_BOOTLOADER 1
+#define CS_DEVICE     2
+#define CS_HOST       3
+#define CS_RECOVERY   4
+#define CS_SIDELOAD   6
+#define CS_WAITCNXN   7
+#define CS_PWLOCK     10
+
+#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101
+#define  SDB_LOCAL_TRANSPORT_MAX  15
+
+extern LIST_NODE* transport_list;
+extern int current_local_transports;
+
+#ifdef _WIN32 /* FIXME : move to sysdeps.h later */
+int asprintf( char **, char *, ... );
+int vasprintf( char **, char *, va_list );
+#endif
+
+void wakeup_select_func(int _fd, unsigned ev, void *data);
+void dump_packet(const char* name, const char* func, PACKET* p);
+void send_packet(PACKET *p, TRANSPORT *t);
+const char *connection_state_name(TRANSPORT *t);
+PACKET *get_apacket(void);
+void put_apacket(void *p);
+void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name);
+void register_usb_transport(usb_handle *usb, const char *serial);
+int register_device_con_transport(int s, const char *serial);
+void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t);
+void close_usb_devices();
+int list_transports_msg(char*  buffer, size_t  bufferlen);
+int list_transports(char *buf, size_t  bufsize);
+int local_connect(int  port, const char *device_name);
+TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char **error_out);
+void kick_transport( TRANSPORT*  t );
+void register_transport(TRANSPORT *t);
 #endif   /* __TRANSPORT_H */
old mode 100644 (file)
new mode 100755 (executable)
index 8fca32d..80fc669
@@ -18,8 +18,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include "fdevent.h"
-#include "utils.h"
 #include <sys/types.h>
 
 #ifndef OS_WINDOWS
 #endif
 
 #define  TRACE_TAG  TRACE_TRANSPORT
-#include "sdb.h"
-
-#ifdef HAVE_BIG_ENDIAN
-#define H4(x)  (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
-static inline void fix_endians(apacket *p)
-{
-    p->msg.command     = H4(p->msg.command);
-    p->msg.arg0        = H4(p->msg.arg0);
-    p->msg.arg1        = H4(p->msg.arg1);
-    p->msg.data_length = H4(p->msg.data_length);
-    p->msg.data_check  = H4(p->msg.data_check);
-    p->msg.magic       = H4(p->msg.magic);
-}
-#else
-#define fix_endians(p) do {} while (0)
-#endif
+#include "strutils.h"
+#include "log.h"
+#include "common_modules.h"
+#include "fdevent.h"
+#include "utils.h"
+#include "transport.h"
 
 /* we keep a list of opened transports. The atransport struct knows to which
  * local transport it is connected. The list is used to detect when we're
  * trying to connect twice to a given local transport.
  */
-#define  SDB_LOCAL_TRANSPORT_MAX  16
 
-SDB_MUTEX_DEFINE( local_transports_lock );
+int current_local_transports = 0;
 
-static atransport*  local_transports[ SDB_LOCAL_TRANSPORT_MAX ];
+static int get_devicename_from_shdmem(int port, char *device_name);
 
-static int remote_read(apacket *p, atransport *t)
-{
-    if(readx(t->sfd, &p->msg, sizeof(amessage))){
-        D("remote local: read terminated (message)\n");
+static int remote_read(TRANSPORT* t, void* data, int len) {
+    return readx(t->sfd, data, len);
+}
+
+static int remote_write(PACKET *p, TRANSPORT *t) {
+    dump_packet(t->serial, "remote_write_local", p);
+    if(writex(t->sfd, &p->msg, sizeof(MESSAGE) + p->msg.data_length)) {
+        LOG_ERROR("remote local: write terminated\n");
         return -1;
     }
+    return 0;
+}
 
-    fix_endians(p);
+static int notify_sensord(int sdb_port) {
 
-#if 0 && defined HAVE_BIG_ENDIAN
-    D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
-      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
-#endif
-    if(check_header(p)) {
-        D("bad header: terminated (data)\n");
-        return -1;
-    }
+    int  fd = -1;
+    int  sensord_port = sdb_port + 2;
 
-    if(readx(t->sfd, p->data, p->msg.data_length)){
-        D("remote local: terminated (data)\n");
-        return -1;
-    }
+    fd = sdb_host_connect("127.0.0.1", sensord_port, SOCK_DGRAM);
 
-    if(check_data(p)) {
-        D("bad data: terminated (data)\n");
+    if (fd < 0) {
+        LOG_ERROR("failed to create socket to localhost(%d)\n", sensord_port);
         return -1;
     }
 
-    return 0;
-}
-
-static int remote_write(apacket *p, atransport *t)
-{
-    int   length = p->msg.data_length;
-
-    fix_endians(p);
+    char request[16];
+    snprintf(request, sizeof request, "2\n");
 
-#if 0 && defined HAVE_BIG_ENDIAN
-    D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
-      p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
-#endif
-    if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
-        D("remote local: write terminated\n");
-        return -1;
+    // send to sensord with udp
+    if (sdb_write(fd, request, strlen(request)) < 0) {
+        LOG_ERROR("could not send sensord request\n");
     }
 
+    sdb_close(fd);
     return 0;
 }
 
+int local_connect(int sdb_port, const char *device_name) {
 
-int local_connect(int port, const char *device_name) {
-    return local_connect_arbitrary_ports(port-1, port, device_name);
-}
-
-int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name)
-{
     char buf[64];
-    int  fd = -1;
 
-    fd = socket_loopback_client(sdb_port, SOCK_STREAM);
+    // in case of windows, it takes a long time to connect localhost compare to linux
+#if defined(OS_WINDOWS)
+    char devname[DEVICENAME_MAX]={0,};
+    if (get_devicename_from_shdmem(sdb_port, devname) == -1) {
+        return -1;
+    }
+#endif
+
+    int fd = sdb_host_connect("127.0.0.1", sdb_port, SOCK_STREAM);
 
     if (fd >= 0) {
-        D("client: connected on remote on fd %d\n", fd);
+        D("connected on remote on fd '%d', port '%d'\n", fd, sdb_port);
         close_on_exec(fd);
         disable_tcp_nagle(fd);
-        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
+
+
+        snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, sdb_port);
         register_socket_transport(fd, buf, sdb_port, 1, device_name);
+
+        // noti to sensord port to enable shell context menu on
+        notify_sensord(sdb_port);
         return 0;
     }
+    D("failed to connect on port '%d'\n", sdb_port);
     return -1;
 }
 
-int get_devicename_from_shdmem(int port, char *device_name)
+static int get_devicename_from_shdmem(int port, char *device_name)
 {
     char *vms = NULL;
 #ifndef OS_WINDOWS
@@ -136,8 +119,10 @@ int get_devicename_from_shdmem(int port, char *device_name)
     void *shared_memory = (void *)0;
 
     shm_id = shmget( (key_t)port-1, 0, 0);
-    if (shm_id == -1)
+    if (shm_id == -1) {
+        D("failed to get shm from key:(%d)\n", port-1);
         return -1;
+    }
 
     shared_memory = shmat(shm_id, (void *)0, SHM_RDONLY);
 
@@ -147,10 +132,12 @@ int get_devicename_from_shdmem(int port, char *device_name)
         return -1;
     }
     vms = strstr((char*)shared_memory, VMS_PATH);
-    if (vms != NULL)
-        strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
-    else
-        strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
+    if (vms != NULL) {
+        s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
+    } else {
+        D("failed to get vm name from(%s)\n", shared_memory);
+        return -1;
+    }
 
 #else /* _WIN32*/
     HANDLE hMapFile;
@@ -161,7 +148,7 @@ int get_devicename_from_shdmem(int port, char *device_name)
     hMapFile = OpenFileMapping(FILE_MAP_READ, TRUE, s_port);
 
     if(hMapFile == NULL) {
-        D("faild to get shdmem key (%ld) : %s\n", port, GetLastError() );
+        D("faild to get shdmem key from port (%d) : (%ld)\n", port, GetLastError() );
         return -1;
     }
     pBuf = (char*)MapViewOfFile(hMapFile,
@@ -176,158 +163,102 @@ int get_devicename_from_shdmem(int port, char *device_name)
     }
 
     vms = strstr((char*)pBuf, VMS_PATH);
-    if (vms != NULL)
-        strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
-    else
-        strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
+    if (vms != NULL) {
+        s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
+    } else {
+        D("failed to get vm name from(%s)\n", pBuf);
+        CloseHandle(hMapFile);
+        return -1;
+    }
     CloseHandle(hMapFile);
 #endif
-    // apply for new vms path policy from Jan 23 2013
     // vms path should be: ~/tizen-sdk-data/emulator-vms/vms/{name}/emulimg-em1.~~
     vms = strtok(device_name, OS_PATH_SEPARATOR_STR);
     if (vms != NULL) {
-        strncpy(device_name, vms, DEVICENAME_MAX);
+        s_strncpy(device_name, vms, DEVICENAME_MAX);
+    } else {
+        D("failed to get vm name from(%s)\n", device_name);
+        return -1;
     }
     D("init device name %s on port %d\n", device_name, port);
 
     return 0;
 }
 
-static void *register_local_connections(void *x)
-{
-    int  port  = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
-    int  count = SDB_LOCAL_TRANSPORT_MAX;
-
-    D("transport: client_socket_thread() starting\n");
-
-    /* try to connect to any number of running emulator instances     */
-    /* this is only done when SDB starts up. later, each new emulator */
-    /* will send a message to SDB to indicate that is is starting up  */
-    for ( ; count > 0; count--, port += 10 ) {
-        (void) local_connect(port, NULL);
-    }
-
-    return 0;
-}
-
-/**
- * register local connections
- */
-void local_init(int port)
-{
-    sdb_thread_t thr;
-    void* (*func)(void *);
-
-    func = register_local_connections;
-
-    if(sdb_thread_create(&thr, func, (void *)port)) {
-        fatal_errno("cannot create local socket %s thread",
-                    HOST ? "client" : "server");
-    }
-}
-
-static void remote_kick(atransport *t)
+static void remote_kick(TRANSPORT *t)
 {
     int fd = t->sfd;
-    int  nn;
 
     t->sfd = -1;
     sdb_shutdown(fd);
     sdb_close(fd);
 
-    sdb_mutex_lock( &local_transports_lock );
-    for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) {
-        if (local_transports[nn] == t) {
-            local_transports[nn] = NULL;
-            break;
-        }
-    }
-
-    sdb_mutex_unlock( &local_transports_lock );
-}
-
-static void remote_close(atransport *t)
-{
-    sdb_close(t->fd);
-}
-
-
-/* Only call this function if you already hold local_transports_lock. */
-atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port)
-{
-    int i;
-    for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
-        if (local_transports[i] && local_transports[i]->sdb_port == sdb_port) {
-            return local_transports[i];
-        }
-    }
-    return NULL;
-}
-
-atransport* find_emulator_transport_by_sdb_port(int sdb_port)
-{
-    sdb_mutex_lock( &local_transports_lock );
-    atransport* result = find_emulator_transport_by_sdb_port_locked(sdb_port);
-    sdb_mutex_unlock( &local_transports_lock );
-    return result;
-}
-
-/* Only call this function if you already hold local_transports_lock. */
-int get_available_local_transport_index_locked()
-{
-    int i;
-    for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
-        if (local_transports[i] == NULL) {
-            return i;
-        }
-    }
-    return -1;
+    --current_local_transports;
 }
 
-int get_available_local_transport_index()
+static void remote_close(TRANSPORT *t)
 {
-    sdb_mutex_lock( &local_transports_lock );
-    int result = get_available_local_transport_index_locked();
-    sdb_mutex_unlock( &local_transports_lock );
-    return result;
+    //nothing to close
+    D("close remote socket. serial: '%s', device name: '%s'\n", t->serial, t->device_name);
 }
 
-int init_socket_transport(atransport *t, int s, int sdb_port, int local)
+static void init_socket_transport(TRANSPORT *t, int s, int sdb_port)
 {
-    int  fail = 0;
-
     t->kick = remote_kick;
     t->close = remote_close;
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
     t->sfd = s;
-    t->sync_token = 1;
     t->connection_state = CS_OFFLINE;
     t->type = kTransportLocal;
-    t->sdb_port = 0;
-
-    if (HOST && local) {
-        sdb_mutex_lock( &local_transports_lock );
-        {
-            t->sdb_port = sdb_port;
-            atransport* existing_transport =
-                    find_emulator_transport_by_sdb_port_locked(sdb_port);
-            int index = get_available_local_transport_index_locked();
-            if (existing_transport != NULL) {
-                D("local transport for port %d already registered (%p)?\n",
-                sdb_port, existing_transport);
-                fail = -1;
-            } else if (index < 0) {
-                // Too many emulators.
-                D("cannot register more emulators. Maximum is %d\n",
-                        SDB_LOCAL_TRANSPORT_MAX);
-                fail = -1;
-            } else {
-                local_transports[index] = t;
-            }
-       }
-       sdb_mutex_unlock( &local_transports_lock );
+    t->node = NULL;
+    t->req = 0;
+    t->res = 0;
+    t->sdb_port = sdb_port;
+}
+
+void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name)
+{
+    if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) {
+        D("Too many emulators\n");
+        sdb_close(s);
+        return;
+    }
+
+    TRANSPORT *t = calloc(1, sizeof(TRANSPORT));
+    char buff[32];
+
+    if (!serial) {
+        snprintf(buff, sizeof buff, "T-%p", t);
+        serial = buff;
+    }
+    D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name);
+    int _port = port;
+    if(!local) {
+        _port = 0;
+    }
+    init_socket_transport(t, s, _port);
+    TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL);
+    if(old_t != NULL) {
+        D("old transport '%s' is found. Unregister it\n", old_t->serial);
+        kick_transport(old_t);
+    }
+
+    t->remote_cnxn_socket = NULL;
+    if(serial) {
+        t->serial = strdup(serial);
+    }
+
+    if (device_name) {
+        t->device_name = strdup(device_name);
+    } else {
+        // device_name could be null when sdb server was forked before qemu has sent the connect message.
+        t->device_name = (char*) malloc(DEVICENAME_MAX+1);
+        if (get_devicename_from_shdmem(port, t->device_name) == -1) {
+            s_strncpy(t->device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
+        }
     }
 
-    return fail;
+    ++current_local_transports;
+    register_transport(t);
 }
old mode 100644 (file)
new mode 100755 (executable)
index b0e557b..270bddd
 #include <stdlib.h>
 #include <string.h>
 
+#include "log.h"
 #include "fdevent.h"
 #include "utils.h"
 #define  TRACE_TAG  TRACE_TRANSPORT
-#include "sdb.h"
 #include "sdb_usb.h"
+#include "transport.h"
 
-#ifdef HAVE_BIG_ENDIAN
-#define H4(x)  (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
-static inline void fix_endians(apacket *p)
-{
-    p->msg.command     = H4(p->msg.command);
-    p->msg.arg0        = H4(p->msg.arg0);
-    p->msg.arg1        = H4(p->msg.arg1);
-    p->msg.data_length = H4(p->msg.data_length);
-    p->msg.data_check  = H4(p->msg.data_check);
-    p->msg.magic       = H4(p->msg.magic);
-}
-unsigned host_to_le32(unsigned n)
-{
-    return H4(n);
-}
-#else
-#define fix_endians(p) do {} while (0)
-unsigned host_to_le32(unsigned n)
-{
-    return n;
-}
-#endif
+static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state);
 
-static int remote_read(apacket *p, atransport *t)
+static int remote_read(TRANSPORT* t, void* data, int len)
 {
-    if(sdb_usb_read(t->usb, &p->msg, sizeof(amessage))){
-        D("remote usb: read terminated (message)\n");
-        return -1;
-    }
-
-    fix_endians(p);
-
-    if(check_header(p)) {
-        D("remote usb: check_header failed\n");
-        return -1;
-    }
-
-    if(p->msg.data_length) {
-        if(sdb_usb_read(t->usb, p->data, p->msg.data_length)){
-            D("remote usb: terminated (data)\n");
-            return -1;
-        }
-    }
-
-    if(check_data(p)) {
-        D("remote usb: check_data failed\n");
-        return -1;
-    }
-
-    return 0;
+       return sdb_usb_read(t->usb, data, len);
 }
 
-static int remote_write(apacket *p, atransport *t)
+static int remote_write(PACKET *p, TRANSPORT *t)
 {
-    unsigned size = p->msg.data_length;
-
-    fix_endians(p);
-
-    if(sdb_usb_write(t->usb, &p->msg, sizeof(amessage))) {
-        D("remote usb: 1 - write terminated\n");
+    dump_packet(t->serial, "remote_write_usb", p);
+    if(sdb_usb_write(t->usb, &p->msg, sizeof(MESSAGE))) {
+        LOG_ERROR("mesage write error\n");
         return -1;
     }
-    if(p->msg.data_length == 0) return 0;
-    if(sdb_usb_write(t->usb, &p->data, size)) {
-        D("remote usb: 2 - write terminated\n");
-        return -1;
+
+    if(p->msg.data_length != 0) {
+               if(sdb_usb_write(t->usb, &p->data, p->msg.data_length)) {
+                       D("remote usb: 2 - write terminated\n");
+                       return -1;
+               }
     }
 
     return 0;
 }
 
-static void remote_close(atransport *t)
+static void remote_close(TRANSPORT *t)
 {
     sdb_usb_close(t->usb);
     t->usb = 0;
 }
 
-static void remote_kick(atransport *t)
+static void remote_kick(TRANSPORT *t)
 {
     sdb_usb_kick(t->usb);
 }
 
-void init_usb_transport(atransport *t, usb_handle *h, int state)
+static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state)
 {
     D("transport: usb\n");
     t->close = remote_close;
     t->kick = remote_kick;
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
-    t->sync_token = 1;
     t->connection_state = state;
     t->type = kTransportUsb;
     t->usb = h;
+    t->sdb_port = -1;
+    t->req = 0;
+    t->res = 0;
+}
+
+static int get_connected_device_count(transport_type type)
+{
+    int cnt = 0;
+    sdb_mutex_lock(&transport_lock, "transport get_connected_device_count");
+
+    LIST_NODE* curptr = transport_list;
+    while(curptr != NULL) {
+        TRANSPORT *t = curptr->data;
+        curptr = curptr->next_ptr;
+        if (type == t->type) {
+            cnt++;
+        }
+    }
+
+    sdb_mutex_unlock(&transport_lock, "transport get_connected_device_count");
+    D("connected device count:%d\n",cnt);
+    return cnt;
+}
 
-    HOST = 1;
+void register_usb_transport(usb_handle *usb, const char *serial)
+{
+    TRANSPORT *t = calloc(1, sizeof(TRANSPORT));
+    char device_name[256];
+
+    D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
+      serial ? serial : "");
+    init_usb_transport(t, usb, CS_OFFLINE);
+    if(serial) {
+        t->serial = strdup(serial);
+    }
+    t->remote_cnxn_socket = NULL;
+    register_transport(t);
+
+    /* tizen specific */
+    sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb));
+    t->device_name = strdup(device_name);
 }
 
 int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_protocol)
@@ -133,3 +126,20 @@ int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_pro
 
     return 0;
 }
+
+void close_usb_devices()
+{
+    sdb_mutex_lock(&transport_lock, "transport close_usb_devices");
+
+    LIST_NODE* curptr = transport_list;
+    while(curptr != NULL) {
+        TRANSPORT* t = curptr->data;
+        curptr = curptr->next_ptr;
+        if ( !t->kicked ) {
+            t->kicked = 1;
+            t->kick(t);
+        }
+    }
+
+    sdb_mutex_unlock(&transport_lock, "transport close_usb_devices");
+}
diff --git a/src/usb_darwin.c b/src/usb_darwin.c
new file mode 100755 (executable)
index 0000000..7e9024d
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * documents from https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/USBBook/USBOverview/USBOverview.html
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <mach/mach.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+#include "fdevent.h"
+#include "strutils.h"
+#include "memutils.h"
+#include "sdb_usb.h"
+#include "device_vendors.h"
+#include "log.h"
+#include "utils.h"
+#include "linkedlist.h"
+#include "transport.h"
+
+#define MAX_C_STRLEN            128
+#define kUSBLanguageEnglish     0x409
+
+static IONotificationPortRef gNotifyPort;
+static io_iterator_t* gAddedIter;
+static CFRunLoopRef gRunLoop;
+
+static pthread_mutex_t usb_init_lock;
+static pthread_cond_t usb_init_cond;
+
+struct usb_handle {
+    UInt8 end_point[2]; // 0:in, 1:out
+    IOUSBInterfaceInterface **interface;
+    io_object_t usbNotification;
+    unsigned int zero_mask;
+};
+
+static void usb_unplugged(usb_handle *handle) {
+    LOG_INFO("clean interface resources\n");
+    if (!handle)
+        return;
+
+    if (handle->interface) {
+        (*handle->interface)->USBInterfaceClose(handle->interface);
+        (*handle->interface)->Release(handle->interface);
+        handle->interface = 0;
+    }
+}
+
+void DeviceNotification(void * refCon, io_service_t service, natural_t messageType,
+        void * messageArgument) {
+
+    kern_return_t kr;
+    usb_handle *handle = (usb_handle *) refCon;
+
+    if (messageType == kIOMessageServiceIsTerminated) {
+        LOG_DEBUG("Device 0x%08x removed.\n", service);
+
+        kr = IOObjectRelease(handle->usbNotification);
+        sdb_usb_kick(handle);
+    }
+
+}
+
+/**
+ * Authors: Vipul Gupta, Pete St. Pierre
+ **/
+static void UsbCharactersToHostCharacters(UniChar *p, UInt16 len) {
+    for (; len > 0; --len, ++p)
+        *p = USBToHostWord(*p);
+}
+
+kern_return_t getUSBSerial(IOUSBDeviceInterface182 **dev, UInt8 string_id, char *spotSerial) {
+    UInt8 buffer[256];
+    UInt16 result_length;
+    CFStringRef result;
+    kern_return_t kr = -1;
+    IOUSBDevRequest request;
+
+    memset(buffer, 0, sizeof(buffer));
+    if (string_id != 0) {
+        result_length = sizeof(buffer);
+        request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+        request.bRequest = kUSBRqGetDescriptor;
+        request.wValue = (kUSBStringDesc << 8) | string_id;
+        request.wIndex = kUSBLanguageEnglish;
+        request.wLength = result_length;
+        request.pData = buffer;
+        kr = (*dev)->DeviceRequest(dev, &request);
+
+        if ((kIOReturnSuccess == kr) && (request.wLength > 0)
+                && (request.wLength <= sizeof(buffer))) {
+            result_length = buffer[0];
+            if ((0 < result_length) && (result_length <= sizeof(buffer))) {
+                /*
+                 * Convert USB string (always little-endian) to host-endian but
+                 * leave the descriptor type byte and the length alone.
+                 */
+                UsbCharactersToHostCharacters(((UniChar *) buffer) + 1, ((result_length - 2) >> 1));
+
+                /* Recreate a string from the buffer of unicode characters */
+                result = CFStringCreateWithCharacters(kCFAllocatorDefault, ((UniChar *) buffer) + 1,
+                        ((result_length - 2) >> 1));
+
+                /* Copy the character contents to a local C string */
+                CFStringGetCString(result, spotSerial, MAX_C_STRLEN, kCFStringEncodingASCII);
+            }
+        }
+    }
+
+    return kr;
+}
+
+static IOReturn FindInterfaces(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product,
+        usb_handle *handle) {
+    IOReturn kr;
+    UInt8 intfClass;
+    UInt8 intfSubClass;
+    UInt8 intfProtocol;
+    UInt8 intfNumEndpoints;
+    int pipeRef;
+
+    // open the interface. This will cause the pipes to be instantiated that are
+    // associated with the endpoints defined in the interface descriptor.
+    kr = (*interface)->USBInterfaceOpen(interface);
+    if (kIOReturnSuccess != kr) {
+        LOG_DEBUG("unable to open interface (%08x)\n", kr);
+        return kr;
+    }
+
+    kr = (*interface)->GetNumEndpoints(interface, &intfNumEndpoints);
+    if (kIOReturnSuccess != kr) {
+        LOG_DEBUG("unable to get number of endpoints (%08x)\n", kr);
+        (void) (*interface)->USBInterfaceClose(interface);
+        return kr;
+    }
+
+    kr = (*interface)->GetInterfaceClass(interface, &intfClass);
+    kr = (*interface)->GetInterfaceSubClass(interface, &intfSubClass);
+    kr = (*interface)->GetInterfaceProtocol(interface, &intfProtocol);
+
+    LOG_DEBUG("interface class %0x, subclass %0x, protocol: %0x\n", intfClass, intfSubClass,
+            intfProtocol);
+
+    if (!is_sdb_interface(vendor, intfClass, intfSubClass, intfProtocol)) {
+        LOG_DEBUG("it is not sdb interface\n");
+        (void) (*interface)->USBInterfaceClose(interface);
+        return kIOReturnError;
+    }
+
+    for (pipeRef = 0; pipeRef <= intfNumEndpoints; pipeRef++) {
+        UInt8 direction;
+        UInt8 number;
+        UInt8 transferType;
+        UInt16 maxPacketSize;
+        UInt8 interval;
+        char *message;
+
+        kr = (*interface)->GetPipeProperties(interface, pipeRef, &direction, &number, &transferType,
+                &maxPacketSize, &interval);
+        if (kIOReturnSuccess != kr)
+            LOG_DEBUG("unable to get properties of pipe %d (%08x)\n", pipeRef, kr);
+        else {
+            LOG_DEBUG("++ pipeRef:%d: ++\n ", pipeRef);
+
+            switch (transferType) {
+            case kUSBControl:
+                message = "control";
+                break;
+            case kUSBIsoc:
+                message = "isoc";
+                break;
+            case kUSBBulk:
+                message = "bulk";
+                break;
+            case kUSBInterrupt:
+                message = "interrupt";
+                break;
+            case kUSBAnyType:
+                message = "any";
+                break;
+            default:
+                message = "???";
+            }
+            LOG_DEBUG("transfer type:%s, maxPacketSize:%d\n", message, maxPacketSize);
+            if (kUSBBulk != transferType) {
+                continue;
+            }
+            handle->zero_mask = maxPacketSize - 1;
+
+            switch (direction) {
+            case kUSBOut:
+                message = "out";
+                handle->end_point[1] = pipeRef;
+                break;
+            case kUSBIn:
+                message = "in";
+                handle->end_point[0] = pipeRef;
+                break;
+            case kUSBNone:
+                message = "none";
+                break;
+            case kUSBAnyDirn:
+                message = "any";
+                break;
+            default:
+                message = "???";
+            }
+            LOG_DEBUG("direction:%0x(%s)\n", pipeRef, message);
+            kr = kIOReturnSuccess;
+        }
+    }
+    handle->interface = interface;
+
+    return kr;
+}
+
+void DeviceAdded(void *refCon, io_iterator_t iterator) {
+    kern_return_t kr;
+    io_service_t usbDevice;
+    io_service_t usbInterface;
+    IOCFPlugInInterface **ioDev = NULL;
+    IOUSBDeviceInterface182 **intf = NULL;
+    IOUSBInterfaceInterface220 **interface = NULL;
+    SInt32 score;
+    HRESULT res;
+    UInt16 usbVendor;
+    UInt16 usbProduct;
+    UInt8 serialIndex;
+    char serial[256];
+
+    while ((usbInterface = IOIteratorNext(iterator))) {
+        // Create an intermediate plug-in
+        kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID,
+                kIOCFPlugInInterfaceID, &ioDev, &score);
+        IOObjectRelease(usbInterface);
+
+        if ((kIOReturnSuccess != kr) || !ioDev) {
+            LOG_DEBUG("couldn't create a device interface plugin, find next...\n");
+            continue;
+        }
+        res = (*ioDev)->QueryInterface(ioDev,
+                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) & interface);
+        (*ioDev)->Release(ioDev);
+
+        if (res || !interface) {
+            LOG_DEBUG("couldn't create an IOUSBInterfaceInterface, find next... \n");
+            continue;
+        }
+
+        kr = (*interface)->GetDevice(interface, &usbDevice);
+        if (kIOReturnSuccess != kr || !usbDevice) {
+            LOG_DEBUG("couldn't get device from interface, find next...\n");
+            continue;
+        }
+
+        kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+                kIOCFPlugInInterfaceID, &ioDev, &score);
+        // Release the usbDevice object after getting the plug-in
+        IOObjectRelease(usbDevice);
+
+        if ((kIOReturnSuccess != kr) || !ioDev) {
+            LOG_DEBUG("unable to create a device plugin, find next...\n");
+            continue;
+        }
+
+        // I have the device plugin, I need the device interface
+        //
+        res = (*ioDev)->QueryInterface(ioDev,
+                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&intf);
+        (*ioDev)->Release(ioDev);
+
+        if (res || !intf) {
+            LOG_DEBUG("couldn't create a usb interface, find next...\n");
+            continue;
+        }
+        // Get vendor, product and serial index
+        kr = (*intf)->GetDeviceVendor(intf, &usbVendor);
+        if (kIOReturnSuccess != kr) {
+            LOG_ERROR("couldn't get usb vendor name\n");
+        }
+        kr = (*intf)->GetDeviceProduct(intf, &usbProduct);
+        if (kIOReturnSuccess != kr) {
+            LOG_ERROR("couldn't get usb product name\n");
+        }
+        kr = (*intf)->USBGetSerialNumberStringIndex(intf, &serialIndex);
+        if (kIOReturnSuccess != kr) {
+            LOG_ERROR("couldn't get usb serial index\n");
+        }
+        kr = getUSBSerial(intf, serialIndex, serial);
+        (*intf)->Release(intf);
+
+        usb_handle* handle = calloc(1, sizeof(usb_handle));
+        if (handle == NULL) {
+            LOG_FATAL("could't alloc mememroy\n");
+        }
+
+        kr = FindInterfaces((IOUSBInterfaceInterface**) interface, usbVendor, usbProduct, handle);
+        if (kIOReturnSuccess != kr) {
+            free(handle);
+            handle = NULL;
+            (*interface)->Release(interface);
+            continue;
+        }
+
+        LOG_DEBUG("found tizen device and register usb transport.........\n");
+        register_usb_transport(handle, serial);
+
+        // Register for an interest notification for this device. Pass the reference to our
+        // private data as the refCon for the notification.
+        //
+        kr = IOServiceAddInterestNotification(gNotifyPort, // notifyPort
+                usbInterface, // service
+                kIOGeneralInterest, // interestType
+                DeviceNotification, // callback
+                handle, // refCon
+                &(handle->usbNotification) // notification
+                );
+
+        if (kIOReturnSuccess != kr) {
+            LOG_DEBUG("IOServiceAddInterestNotification returned 0x%08x\n", kr);
+        }
+
+    }
+    LOG_DEBUG("signal to wake up main thread\n");
+    sdb_mutex_lock(&usb_init_lock, "++usb locking++");
+    sdb_cond_signal(&usb_init_cond);
+    sdb_mutex_unlock(&usb_init_lock, "--usb unlocking--");
+}
+
+static int cleanup_flag = 0;
+static void sig_handler(int sigraised) {
+    int i = 0;
+
+    LOG_DEBUG("Interrupted!\n");
+
+    if (cleanup_flag == 1) {
+        return;
+    }
+
+    // Clean up
+    for (i = 0; i < vendor_total_cnt; i++) {
+        IOObjectRelease(gAddedIter[i]);
+    }
+    gAddedIter = NULL;
+
+    IONotificationPortDestroy(gNotifyPort);
+    gRunLoop = 0;
+
+    if (gAddedIter != NULL) {
+        s_free(gAddedIter);
+        gAddedIter = NULL;
+    }
+
+    LOG_DEBUG("RunLoopThread done\n");
+    if (gRunLoop) {
+        CFRunLoopStop(gRunLoop);
+    }
+    cleanup_flag = 1;
+}
+
+void do_lsusb(void) {
+    mach_port_t masterPort;
+    CFMutableDictionaryRef matchingDict;
+    CFRunLoopSourceRef runLoopSource;
+    CFNumberRef numberRef;
+    kern_return_t kr;
+    SInt32 usbVendor, subClass, protocol;
+    sig_t oldHandler;
+    int i = 0;
+
+    // Set up a signal handler so we can clean up when we're interrupted from the command line
+    // Otherwise we stay in our run loop forever.
+    //
+    oldHandler = signal(SIGINT, sig_handler);
+    if (oldHandler == SIG_ERR) {
+        LOG_DEBUG("Could not establish new signal handler\n");
+    }
+
+    // first create a master_port for my task
+    //
+    kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
+    if (kr || !masterPort) {
+        LOG_DEBUG("ERR: Couldn't create a master IOKit Port(%08x)\n", kr);
+        return;
+    }
+
+    // Create a notification port and add its run loop event source to our run loop
+    // This is how async notifications get set up.
+    //
+    gNotifyPort = IONotificationPortCreate(masterPort);
+    runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
+
+    gRunLoop = CFRunLoopGetCurrent();
+    CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode);
+
+    for (i = 0; tizen_device_vendors[i].vendor != NULL; i++) {
+        // Set up the matching criteria for the devices we're interested in.  The matching criteria needs to follow
+        // the same rules as kernel drivers:  mainly it needs to follow the USB Common Class Specification, pp. 6-7.
+        // See also http://developer.apple.com/qa/qa2001/qa1076.html
+        // One exception is that you can use the matching dictionary "as is", i.e. without adding any matching criteria
+        // to it and it will match every IOUSBDevice in the system.  IOServiceAddMatchingNotification will consume this
+        // dictionary reference, so there is no need to release it later on.
+        //
+        matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); // Interested in instances of class
+                                                                    // IOUSBInterface and its subclasses
+        if (!matchingDict) {
+            LOG_DEBUG("Can't create a USB matching dictionary\n");
+            mach_port_deallocate(mach_task_self(), masterPort);
+            return;
+        }
+        usbVendor = tizen_device_vendors[i].id;
+        subClass = SDB_INTERFACE_SUBCLASS;
+        protocol = SDB_INTERFACE_PROTOCOL;
+
+        LOG_DEBUG(
+                "Looking for devices matching vendor ID=%0x(%0x, %0x)\n", usbVendor, subClass, protocol);
+
+        // We are interested in all USB Devices (as opposed to USB interfaces).  The Common Class Specification
+        // tells us that we need to specify the idVendor, idProduct, and bcdDevice fields, or, if we're not interested
+        // in particular bcdDevices, just the idVendor and idProduct.  Note that if we were trying to match an IOUSBInterface,
+        // we would need to set more values in the matching dictionary (e.g. idVendor, idProduct, bInterfaceNumber and
+        // bConfigurationValue.
+        //
+
+        // Create a CFNumber for the idVendor, interface subclass and protocol and set the value in the dictionary
+        //
+        numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
+        CFRelease(numberRef);
+
+        numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &subClass);
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), numberRef);
+        CFRelease(numberRef);
+
+        numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &protocol);
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), numberRef);
+        CFRelease(numberRef);
+
+        numberRef = 0;
+
+        // Now set up a notification to be called when a device is first matched by I/O Kit.
+        // Note that this will not catch any devices that were already plugged in so we take
+        // care of those later.
+        //
+        kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
+                kIOFirstMatchNotification, // notificationType
+                matchingDict, // matching
+                DeviceAdded, // callback
+                NULL, // refCon
+                &gAddedIter[i] // notification
+                );
+
+        // Iterate once to get already-present devices and arm the notification
+        //
+        DeviceAdded(NULL, gAddedIter[i]);
+    }
+
+    // Now done with the master_port
+    mach_port_deallocate(mach_task_self(), masterPort);
+    masterPort = 0;
+
+    // Start the run loop. Now we'll receive notifications.
+    //
+    LOG_DEBUG("Starting run loop.\n");
+    CFRunLoopRun();
+
+    // We should never get here
+    //
+    LOG_DEBUG("Unexpectedly back from CFRunLoopRun()!\n");
+}
+
+void* usb_poll_thread(void* sleep_msec) {
+    LOG_DEBUG("created usb detecting thread\n");
+    do_lsusb();
+    return NULL;
+}
+
+void sdb_usb_init() {
+    sdb_thread_t tid;
+
+    init_device_vendors();
+    gAddedIter = (io_iterator_t*) s_malloc(vendor_total_cnt * sizeof(io_iterator_t));
+    if (gAddedIter == NULL) {
+        LOG_FATAL("Cound not alloc memory\n");
+        return;
+    }
+
+    sdb_mutex_init(&usb_init_lock, NULL);
+    sdb_cond_init(&usb_init_cond, NULL);
+
+    if (sdb_thread_create(&tid, usb_poll_thread, NULL)) {
+        LOG_FATAL("cannot create usb poll thread\n");
+    }
+    sdb_mutex_lock(&usb_init_lock, "++usb locking++");
+
+    LOG_DEBUG("waiting until to finish to initilize....\n");
+    // wait til finish to initialize some setting for usb detection
+    sdb_cond_wait(&usb_init_cond, &usb_init_lock);
+
+    LOG_DEBUG("woke up done....\n");
+    sdb_mutex_unlock(&usb_init_lock, "--usb unlocking--");
+    sdb_mutex_destroy(&usb_init_lock);
+    sdb_cond_destroy(&usb_init_cond);
+}
+
+void sdb_usb_cleanup() {
+    // called when server stop or interrupted
+    close_usb_devices();
+    sig_handler(0);
+}
+
+int sdb_usb_write(usb_handle *h, const void *data, int len) {
+    IOReturn kr;
+
+    kr = (*h->interface)->WritePipe(h->interface, h->end_point[1], (void *) data, len);
+    if (kr == kIOReturnSuccess) {
+        if (h->zero_mask && !(h->zero_mask & len)) {
+            (*h->interface)->WritePipe(h->interface, h->end_point[1], (void *) data, 0);
+        }
+        return 0;
+    }
+
+    LOG_DEBUG("Unable to perform bulk write (%08x)\n", kr);
+    return -1;
+}
+
+int sdb_usb_read(usb_handle *h, void *data, int len) {
+    IOReturn kr;
+    UInt32 size = len;
+
+    kr = (*h->interface)->ReadPipe(h->interface, h->end_point[0], data, &size);
+
+    if (kIOReturnSuccess != kr) {
+        LOG_DEBUG("Unable to perform bulk read (%08x)\n", kr);
+        return -1;
+    }
+
+    return 0;
+}
+
+int sdb_usb_close(usb_handle *h) {
+    return 0;
+}
+
+void sdb_usb_kick(usb_handle *h) {
+    usb_unplugged(h);
+}
old mode 100755 (executable)
new mode 100644 (file)
index 499b0c3..29aec30
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <fcntl.h>
 #include <errno.h>
-#include <ctype.h>
-
-#include <linux/usbdevice_fs.h>
-#include <linux/version.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <libudev.h>
+#include <locale.h>
 #include <linux/usb/ch9.h>
-#else
-#include <linux/usb_ch9.h>
-#endif
-#include <asm/byteorder.h>
-
+#include <linux/usbdevice_fs.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
 
-#include "fdevent.h"
 #include "utils.h"
-#define   TRACE_TAG  TRACE_USB
-#include "sdb.h"
-
+#include "fdevent.h"
+#include "strutils.h"
+#include "sdb_usb.h"
+#include "log.h"
+#include "transport.h"
 
-/* usb scan debugging is waaaay too verbose */
-#define DBGX(x...)
+#define   TRACE_TAG  TRACE_USB
 
 SDB_MUTEX_DEFINE( usb_lock );
 
+LIST_NODE* usb_list = NULL;
+
 struct usb_handle
 {
-    usb_handle *prev;
-    usb_handle *next;
+    LIST_NODE* node;
 
-    char fname[64];
-    int desc;
-    unsigned char ep_in;
-    unsigned char ep_out;
-
-    unsigned zero_mask;
-    unsigned writeable;
+    char unique_node_path[PATH_MAX+1];
+    int node_fd;
+    unsigned char end_point[2]; // 0:in, 1:out
+    int interface;
+};
 
-    struct usbdevfs_urb urb_in;
-    struct usbdevfs_urb urb_out;
+int register_device(const char* node, const char* serial) {
+    int             fd;
+    unsigned char device_desc[4096];
+    unsigned char* desc_current_ptr = NULL;
 
-    int urb_in_busy;
-    int urb_out_busy;
-    int dead;
+    if (node == NULL) {
+        return -1;
+    }
+    if (is_device_registered(node)) {
+        D("already registered device: %s\n", node);
+        return -1;
+    }
+    if ((fd = open(node, O_RDWR)) < 0) {
+        D ("failed to open usb node %s (%s)\n", node, strerror(errno));
+        return -1;
+    }
 
-    sdb_cond_t notify;
-    sdb_mutex_t lock;
+    if (read(fd, device_desc, sizeof(device_desc)) < 0) {
+        D ("failed to read usb node %s (%s)\n", node, strerror(errno));
+        close(fd);
+        return -1;
+    }
+    desc_current_ptr = device_desc;
 
-    // for garbage collecting disconnected devices
-    int mark;
+    // get device descriptor from head first
+    struct usb_device_descriptor* usb_dev = (struct usb_device_descriptor*)desc_current_ptr;
 
-    // ID of thread currently in REAPURB
-    pthread_t reaper_thread;
-};
+    if (USB_DT_DEVICE_SIZE != usb_dev->bLength) {
+        D("failed to get usb device descriptor\n");
+        return -1;
+    }
 
-static usb_handle handle_list = {
-    .prev = &handle_list,
-    .next = &handle_list,
-};
+    // move to get device config
+    desc_current_ptr += usb_dev->bLength;
 
-static int known_device(const char *dev_name)
-{
-    usb_handle *usb;
-
-    sdb_mutex_lock(&usb_lock);
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if(!strcmp(usb->fname, dev_name)) {
-            // set mark flag to indicate this device is still alive
-            usb->mark = 1;
-            sdb_mutex_unlock(&usb_lock);
-            return 1;
+    // enumerate all available configuration descriptors
+    int i = 0;
+    for (i = 0; i < usb_dev->bNumConfigurations; i++) {
+        struct usb_config_descriptor* usb_config = (struct usb_config_descriptor *) desc_current_ptr;
+        if (USB_DT_CONFIG_SIZE != usb_config->bLength) {
+            D("failed to get usb config descriptor\n");
+            break;
         }
-    }
-    sdb_mutex_unlock(&usb_lock);
-    return 0;
-}
+        desc_current_ptr += usb_config->bLength;
 
-static void linux_kick_disconnected_devices()
-{
-    usb_handle *usb;
-
-    sdb_mutex_lock(&usb_lock);
-    // kick any devices in the device list that were not found in the device scan
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if (usb->mark == 0) {
-            sdb_usb_kick(usb);
-        } else {
-            usb->mark = 0;
+        unsigned int wTotalLength = usb_config->wTotalLength;
+        unsigned int wSumLength = usb_config->bLength;
+
+        if (usb_config->bNumInterfaces < 1) {
+            D("there is no interfaces\n");
+            break;
         }
-    }
-    sdb_mutex_unlock(&usb_lock);
 
-}
+        while (wSumLength < wTotalLength)
+        {
+            int bLength = desc_current_ptr[0];
+            int bType = desc_current_ptr[1];
+
+            struct usb_interface_descriptor* usb_interface = (struct usb_interface_descriptor *)desc_current_ptr;
+
+            if (is_sdb_interface(usb_dev->idVendor, usb_interface->bInterfaceClass, usb_interface->bInterfaceSubClass,
+                    usb_interface->bInterfaceProtocol) &&
+                    (USB_DT_INTERFACE_SIZE == bLength && USB_DT_INTERFACE == bType && 2 == usb_interface->bNumEndpoints)) {
+                desc_current_ptr += usb_interface->bLength;
+                wSumLength += usb_interface->bLength;
+                struct usb_endpoint_descriptor *endpoint1 = (struct usb_endpoint_descriptor *) desc_current_ptr;
+                desc_current_ptr += endpoint1->bLength;
+                wSumLength += endpoint1->bLength;
+                struct usb_endpoint_descriptor *endpoint2 = (struct usb_endpoint_descriptor *) desc_current_ptr;
+                unsigned char endpoint_in;
+                unsigned char endpoint_out;
+                unsigned char interface = usb_interface->bInterfaceNumber;
+                // TODO: removed!
+                {
+                    int bConfigurationValue = 2;
+                    int n = ioctl(fd, USBDEVFS_RESET);
+                    if (n != 0) {
+                        D("usb reset failed\n");
+                    }
+                    n = ioctl(fd, USBDEVFS_SETCONFIGURATION, &bConfigurationValue);
+                    if (n != 0) {
+                        D("check kernel is supporting %dth configuration\n", bConfigurationValue);
+                    }
 
-static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
-                            int ifc, int serial_index, unsigned zero_mask);
+                    n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
+                    if (n != 0) {
+                        D("usb claim failed\n");
+                    }
+                }
 
-static inline int badname(const char *name)
-{
-    while(*name) {
-        if(!isdigit(*name++)) return 1;
-    }
-    return 0;
-}
+                // find in/out endpoint address
+                if ((endpoint1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+                    endpoint_in = endpoint1->bEndpointAddress;
+                    endpoint_out = endpoint2->bEndpointAddress;
+                } else {
+                    endpoint_out = endpoint1->bEndpointAddress;
+                    endpoint_in = endpoint2->bEndpointAddress;
+                }
+                // for now i can agree to register usb
+                {
+                    usb_handle* usb = NULL;
+                    usb = calloc(1, sizeof(usb_handle));
 
-static void find_usb_device(const char *base,
-        void (*register_device_callback)
-                (const char *, unsigned char, unsigned char, int, int, unsigned))
-{
-    char busname[32], devname[32];
-    unsigned char local_ep_in, local_ep_out;
-    DIR *busdir , *devdir ;
-    struct dirent *de;
-    int fd ;
-
-    busdir = opendir(base);
-    if(busdir == 0) return;
-
-    while((de = readdir(busdir)) != 0) {
-        if(badname(de->d_name)) continue;
-
-        snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
-        devdir = opendir(busname);
-        if(devdir == 0) continue;
-
-//        DBGX("[ scanning %s ]\n", busname);
-        while((de = readdir(devdir))) {
-            unsigned char devdesc[4096];
-            unsigned char* bufptr = devdesc;
-            unsigned char* bufend;
-            struct usb_device_descriptor* device;
-            struct usb_config_descriptor* config;
-            struct usb_interface_descriptor* interface;
-            struct usb_endpoint_descriptor *ep1, *ep2;
-            unsigned zero_mask = 0;
-            unsigned vid, pid;
-            unsigned int desclength;
-
-            if(badname(de->d_name)) continue;
-            snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
-
-            if(known_device(devname)) {
-                DBGX("skipping %s\n", devname);
-                continue;
-            }
+                    if (usb == NULL) {
+                        break;
+                    }
+                    usb->node_fd = fd;
+                    usb->interface = usb_interface->bInterfaceNumber;
+                    usb->end_point[0] = endpoint_in;
+                    usb->end_point[1] = endpoint_out;
 
-//            DBGX("[ scanning %s ]\n", devname);
-            if((fd = unix_open(devname, O_RDONLY)) < 0) {
-                continue;
-            }
+                    char usb_serial[256] = {0,};
 
-            desclength = sdb_read(fd, devdesc, sizeof(devdesc));
-            bufend = bufptr + desclength;
+                    if (serial != NULL) {
+                        s_strncpy(usb_serial, serial, sizeof(usb_serial));
+                    } else {
+                        strcpy(usb_serial, "unknown");
+                    }
+                    s_strncpy(usb->unique_node_path, node, sizeof(usb->unique_node_path));
 
-                // should have device and configuration descriptors, and atleast two endpoints
-            if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
-                D("desclength %d is too small\n", desclength);
-                sdb_close(fd);
-                continue;
-            }
+                    sdb_mutex_lock(&usb_lock, "usb register locked");
+                    usb->node = prepend(&usb_list, usb);
+                    D("-register new device (in: %04x, out: %04x) from %s\n", usb->end_point[0], usb->end_point[1], node);
 
-            device = (struct usb_device_descriptor*)bufptr;
-            bufptr += USB_DT_DEVICE_SIZE;
+                    register_usb_transport(usb, usb_serial);
+                    sdb_mutex_unlock(&usb_lock, "usb register unlocked");
+                }
+                desc_current_ptr += endpoint2->bLength;
+                wSumLength += endpoint2->bLength;
 
-            if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
-                sdb_close(fd);
-                continue;
+            } else {
+                wSumLength += usb_interface->bLength;
+                desc_current_ptr += usb_interface->bLength;
             }
+        }
+    }
+    return 0;
+}
+
+static void usb_plugged(struct udev_device *dev) {
+    if (udev_device_get_devnode(dev) != NULL) {
+        register_device(udev_device_get_devnode(dev), udev_device_get_sysattr_value(dev, "serial"));
+    }
+}
 
-            vid = device->idVendor;
-            pid = device->idProduct;
-            DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
+static void usb_unplugged(struct udev_device *dev) {
+    LOG_INFO("check device is removed from the list\n");
+}
 
-                // should have config descriptor next
-            config = (struct usb_config_descriptor *)bufptr;
+int usb_register_callback(int msec)
+{
+    struct udev *udev;
+    struct udev_enumerate *enumerate;
+    struct udev_list_entry *devices, *dev_list_entry;
+    struct udev_device *dev;
+
+    struct udev_monitor *mon;
+    int fd;
+
+    // Create the udev object
+    udev = udev_new();
+    if (!udev) {
+        D("Can't create udev\n");
+        exit(1);
+    }
 
-            /* tizen specific */
-            if (device->bNumConfigurations > 1) {
-                bufptr += config->wTotalLength;
-                config = (struct usb_config_descriptor *)bufptr;
-                bufend = bufptr + config->wTotalLength;
-            }
+    // Set up a monitor to monitor hidraw devices
+    mon = udev_monitor_new_from_netlink(udev, "udev");
+    udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device");
+    udev_monitor_enable_receiving(mon);
 
-            bufptr += USB_DT_CONFIG_SIZE;
-            if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
-                D("usb_config_descriptor not found\n");
-                sdb_close(fd);
-                continue;
-            }
+    // Get the file descriptor (fd) for the monitor. This fd will get passed to select()
+    fd = udev_monitor_get_fd(mon);
 
-                // loop through all the descriptors and look for the SDB interface
-            while (bufptr < bufend) {
-                unsigned char length = bufptr[0];
-                unsigned char type = bufptr[1];
+    // Create a list of the devices in the 'usb' subsystem.
+    enumerate = udev_enumerate_new(udev);
+    udev_enumerate_add_match_subsystem(enumerate, "usb");
+    udev_enumerate_scan_devices(enumerate);
 
-                if (type == USB_DT_INTERFACE) {
-                    interface = (struct usb_interface_descriptor *)bufptr;
-                    bufptr += length;
+    devices = udev_enumerate_get_list_entry(enumerate);
 
-                    if (length != USB_DT_INTERFACE_SIZE) {
-                        D("interface descriptor has wrong size\n");
-                        break;
-                    }
+    D("doing lsusb to find tizen devices\n");
+    udev_list_entry_foreach(dev_list_entry, devices) {
+        const char *path;
 
-                    DBGX("bInterfaceClass: %d,  bInterfaceSubClass: %d,"
-                         "bInterfaceProtocol: %d, bNumEndpoints: %d\n",
-                         interface->bInterfaceClass, interface->bInterfaceSubClass,
-                         interface->bInterfaceProtocol, interface->bNumEndpoints);
-
-                    if (interface->bNumEndpoints == 2 &&
-                            is_sdb_interface(vid, interface->bInterfaceClass,
-                            interface->bInterfaceSubClass, interface->bInterfaceProtocol))  {
-
-                        D("looking for bulk endpoints\n");
-                            // looks like SDB...
-                        ep1 = (struct usb_endpoint_descriptor *)bufptr;
-                        bufptr += USB_DT_ENDPOINT_SIZE;
-                        ep2 = (struct usb_endpoint_descriptor *)bufptr;
-                        bufptr += USB_DT_ENDPOINT_SIZE;
-
-                        if (bufptr > devdesc + desclength ||
-                            ep1->bLength != USB_DT_ENDPOINT_SIZE ||
-                            ep1->bDescriptorType != USB_DT_ENDPOINT ||
-                            ep2->bLength != USB_DT_ENDPOINT_SIZE ||
-                            ep2->bDescriptorType != USB_DT_ENDPOINT) {
-                            D("endpoints not found\n");
-                            break;
-                        }
-
-                            // both endpoints should be bulk
-                        if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
-                            ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
-                            D("bulk endpoints not found\n");
-                            continue;
-                        }
-                            /* aproto 01 needs 0 termination */
-                        if(interface->bInterfaceProtocol == 0x01) {
-                            zero_mask = ep1->wMaxPacketSize - 1;
-                        }
-
-                            // we have a match.  now we just need to figure out which is in and which is out.
-                        if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
-                            local_ep_in = ep1->bEndpointAddress;
-                            local_ep_out = ep2->bEndpointAddress;
-                        } else {
-                            local_ep_in = ep2->bEndpointAddress;
-                            local_ep_out = ep1->bEndpointAddress;
-                        }
-
-                        register_device_callback(devname, local_ep_in, local_ep_out,
-                                interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
-                        break;
-                    }
+        path = udev_list_entry_get_name(dev_list_entry);
+        dev = udev_device_new_from_syspath(udev, path);
+        usb_plugged(dev);
+        udev_device_unref(dev);
+
+    }
+    // Free the enumerator object
+    udev_enumerate_unref(enumerate);
+    D("done lsusb to find tizen devices\n");
+    while (1) {
+        fd_set fds;
+        struct timeval tv;
+        int ret;
+
+        FD_ZERO(&fds);
+        FD_SET(fd, &fds);
+        tv.tv_sec = 0;
+        tv.tv_usec = 0;
+
+        ret = select(fd+1, &fds, NULL, NULL, &tv);
+
+        if (ret > 0 && FD_ISSET(fd, &fds)) {
+            dev = udev_monitor_receive_device(mon);
+            if (dev) {
+                if (!strcmp("add", udev_device_get_action(dev))) {
+                    usb_plugged(dev);
                 } else {
-                    bufptr += length;
+                    usb_unplugged(dev);
                 }
-            } // end of while
+                udev_device_unref(dev);
+            } else {
+                D("failed to get noti from udev monitor\n");
+            }
+        }
+        usleep(msec);
+    }
+    udev_unref(udev);
 
-            sdb_close(fd);
-        } // end of devdir while
-        closedir(devdir);
-    } //end of busdir while
-    closedir(busdir);
+    return 0;
 }
 
-void sdb_usb_cleanup()
+int is_device_registered(const char *unique_node_path)
 {
+    int r = 0;
+    sdb_mutex_lock(&usb_lock, "usb registering locked");
+
+    LIST_NODE* curptr = usb_list;
+    while(curptr != NULL) {
+        usb_handle *usb = curptr->data;
+        if (!strcmp(usb->unique_node_path, unique_node_path)) {
+            r = 1;
+            break;
+        }
+        curptr = curptr->next_ptr;
+    }
+
+    sdb_mutex_unlock(&usb_lock, "usb registering unlocked");
+    return r;
 }
 
-static int usb_bulk_write(usb_handle *h, const void *data, int len)
+void* usb_callback_thread(void* sleep_msec)
 {
-    struct usbdevfs_urb *urb = &h->urb_out;
-    int res;
-    struct timeval tv;
-    struct timespec ts;
-
-    memset(urb, 0, sizeof(*urb));
-    urb->type = USBDEVFS_URB_TYPE_BULK;
-    urb->endpoint = h->ep_out;
-    urb->status = -1;
-    urb->buffer = (void*) data;
-    urb->buffer_length = len;
-
-    D("++ write ++\n");
-
-    sdb_mutex_lock(&h->lock);
-    if(h->dead) {
-        res = -1;
-        goto fail;
-    }
-    do {
-        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
-    } while((res < 0) && (errno == EINTR));
+    D("created usb callback thread\n");
+    int  mseconds = (int) sleep_msec;
 
-    if(res < 0) {
-        goto fail;
-    }
+    usb_register_callback(mseconds);
 
-    res = -1;
-    h->urb_out_busy = 1;
-    for(;;) {
-        /* time out after five seconds */
-        gettimeofday(&tv, NULL);
-        ts.tv_sec = tv.tv_sec + 5;
-        ts.tv_nsec = tv.tv_usec * 1000L;
-        res = pthread_cond_timedwait(&h->notify, &h->lock, &ts);
-        if(res < 0 || h->dead) {
-            break;
-        }
-        if(h->urb_out_busy == 0) {
-            if(urb->status == 0) {
-                res = urb->actual_length;
-            }
-            break;
-        }
+    return NULL;
+}
+
+void sdb_usb_init(void)
+{
+    sdb_thread_t tid;
+
+    if(sdb_thread_create(&tid, usb_callback_thread, (void*)(250*1000))){
+        LOG_FATAL("cannot create input thread\n");
     }
-fail:
-    sdb_mutex_unlock(&h->lock);
-    D("-- write --\n");
-    return res;
 }
 
-static int usb_bulk_read(usb_handle *h, void *data, int len)
+void sdb_usb_cleanup()
 {
-    struct usbdevfs_urb *urb = &h->urb_in;
-    struct usbdevfs_urb *out = NULL;
-    int res;
-
-    memset(urb, 0, sizeof(*urb));
-    urb->type = USBDEVFS_URB_TYPE_BULK;
-    urb->endpoint = h->ep_in;
-    urb->status = -1;
-    urb->buffer = data;
-    urb->buffer_length = len;
-
-
-    sdb_mutex_lock(&h->lock);
-    if(h->dead) {
-        res = -1;
-        goto fail;
+    close_usb_devices();
+}
+
+#define URB_USERCONTEXT_COOKIE      ((void *)0x1)
+
+static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size, int timeout) {
+    struct usbdevfs_urb urb;
+    int bytesdone = 0, requested;
+    struct timeval tv, tv_ref, tv_now;
+    struct usbdevfs_urb *context;
+    int ret, waiting;
+
+    struct timeval tv_cur;
+    /*
+     * HACK: The use of urb.usercontext is a hack to get threaded applications
+     * sort of working again. Threaded support is still not recommended, but
+     * this should allow applications to work in the common cases. Basically,
+     * if we get the completion for an URB we're not waiting for, then we update
+     * the usercontext pointer to 1 for the other threads URB and it will see
+     * the change after it wakes up from the the timeout. Ugly, but it works.
+     */
+
+    /*
+     * Get actual time, and add the timeout value. The result is the absolute
+     * time where we have to quit waiting for an message.
+     */
+    if (gettimeofday(&tv_cur, NULL) != 0) {
+        D("failed to read clock\n");
+        return -1;
     }
-    do {
-        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
-    } while((res < 0) && (errno == EINTR));
+    tv_cur.tv_sec = tv_cur.tv_sec + timeout / 1000;
+    tv_cur.tv_usec = tv_cur.tv_usec + (timeout % 1000) * 1000;
 
-    if(res < 0) {
-        goto fail;
+    if (tv_cur.tv_usec > 1000000) {
+        tv_cur.tv_usec -= 1000000;
+        tv_cur.tv_sec++;
     }
 
-    h->urb_in_busy = 1;
-    for(;;) {
-        D("[ reap urb - wait ]\n");
-        h->reaper_thread = pthread_self();
-        sdb_mutex_unlock(&h->lock);
-        res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
-        int saved_errno = errno;
-        sdb_mutex_lock(&h->lock);
-        h->reaper_thread = 0;
-        if(h->dead) {
-            res = -1;
-            break;
-        }
-        if(res < 0) {
-            if(saved_errno == EINTR) {
-                continue;
-            }
-            D("[ reap urb - error ]\n");
-            break;
+    do {
+        fd_set writefds;
+
+        requested = size - bytesdone;
+        if (requested > MAX_READ_WRITE)
+            requested = MAX_READ_WRITE;
+
+        urb.type = USBDEVFS_URB_TYPE_BULK;
+        urb.endpoint = ep;
+        urb.flags = 0;
+        urb.buffer = bytes + bytesdone;
+        urb.buffer_length = requested;
+        urb.signr = 0;
+        urb.actual_length = 0;
+        urb.number_of_packets = 0; /* don't do isochronous yet */
+        urb.usercontext = NULL;
+
+        ret = ioctl(h->node_fd, USBDEVFS_SUBMITURB, &urb);
+        if (ret < 0) {
+            D("failed to submit urb: %s\n", strerror(errno));
+            return -1;
         }
-        D("[ urb @%p status = %d, actual = %d ]\n",
-            out, out->status, out->actual_length);
-
-        if(out == &h->urb_in) {
-            D("[ reap urb - IN complete ]\n");
-            h->urb_in_busy = 0;
-            if(urb->status == 0) {
-                res = urb->actual_length;
-            } else {
-                res = -1;
+
+        FD_ZERO(&writefds);
+        FD_SET(h->node_fd, &writefds);
+
+restart: waiting = 1;
+        context = NULL;
+        while (!urb.usercontext && ((ret = ioctl(h->node_fd, USBDEVFS_REAPURBNDELAY, &context)) == -1) && waiting) {
+            tv.tv_sec = 0;
+            tv.tv_usec = 1000; // 1 msec
+
+            select(h->node_fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
+
+            if (timeout) {
+                /* compare with actual time, as the select timeout is not that precise */
+                gettimeofday(&tv_now, NULL);
+
+                if ((tv_now.tv_sec > tv_cur.tv_sec)
+                        || ((tv_now.tv_sec == tv_cur.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
+                    waiting = 0;
             }
-            break;
         }
-        if(out == &h->urb_out) {
-            D("[ reap urb - OUT compelete ]\n");
-            h->urb_out_busy = 0;
-            sdb_cond_broadcast(&h->notify);
+
+        if (context && context != &urb) {
+            context->usercontext = URB_USERCONTEXT_COOKIE;
+            /* We need to restart since we got a successful URB, but not ours */
+            goto restart;
         }
+
+        /*
+         * If there was an error, that wasn't EAGAIN (no completion), then
+         * something happened during the reaping and we should return that
+         * error now
+         */
+        if (ret < 0 && !urb.usercontext && errno != EAGAIN)
+            D("error reaping URB: %s\n", strerror(errno));
+
+        bytesdone += urb.actual_length;
+    } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
+
+    /* If the URB didn't complete in success or error, then let's unlink it */
+    if (ret < 0 && !urb.usercontext) {
+        int rc;
+        if (!waiting)
+            rc = -ETIMEDOUT;
+        else
+            rc = urb.status;
+
+        ret = ioctl(h->node_fd, USBDEVFS_DISCARDURB, &urb);
+        if (ret < 0 && errno != EINVAL)
+            D("error discarding URB: %s\n", strerror(errno));
+
+        /*
+         * When the URB is unlinked, it gets moved to the completed list and
+         * then we need to reap it or else the next time we call this function,
+         * we'll get the previous completion and exit early
+         */
+        ioctl(h->node_fd, USBDEVFS_REAPURB, &context);
+
+        return rc;
     }
-fail:
-    sdb_mutex_unlock(&h->lock);
-    return res;
-}
 
+    return bytesdone;
+}
 
 int sdb_usb_write(usb_handle *h, const void *_data, int len)
 {
-    unsigned char *data = (unsigned char*) _data;
-    int n;
-    int need_zero = 0;
-
-    if(h->zero_mask) {
-            /* if we need 0-markers and our transfer
-            ** is an even multiple of the packet size,
-            ** we make note of it
-            */
-        if(!(len & h->zero_mask)) {
-            need_zero = 1;
-        }
-    }
+    char *data = (char*) _data;
+    int n = 0;
+
+    D("+sdb_usb_write\n");
 
     while(len > 0) {
-        int xfer = (len > 4096) ? 4096 : len;
+        int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
 
-        n = usb_bulk_write(h, data, xfer);
+        n = usb_urb_transfer(h, h->end_point[1], data, xfer, 0);
         if(n != xfer) {
-            D("ERROR: n = %d, errno = %d (%s)\n",
-                n, errno, strerror(errno));
+            D("fail to usb write: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
             return -1;
         }
 
@@ -447,37 +458,32 @@ int sdb_usb_write(usb_handle *h, const void *_data, int len)
         data += xfer;
     }
 
-    if(need_zero){
-        n = usb_bulk_write(h, _data, 0);
-        return n;
-    }
+    D("-usb_write\n");
 
     return 0;
 }
 
 int sdb_usb_read(usb_handle *h, void *_data, int len)
 {
-    unsigned char *data = (unsigned char*) _data;
+    char *data = (char*) _data;
     int n;
 
-    D("++ usb_read ++\n");
+    D("+sdb_usb_read\n");
+
     while(len > 0) {
-        int xfer = (len > 4096) ? 4096 : len;
+        int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
 
-        D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
-        n = usb_bulk_read(h, data, xfer);
-        D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
+        n = usb_urb_transfer(h, h->end_point[0], data, xfer, 0);
         if(n != xfer) {
-            if((errno == ETIMEDOUT) && (h->desc != -1)) {
-                D("[ timeout ]\n");
+            if((errno == ETIMEDOUT)) {
+                D("usb bulk read timeout\n");
                 if(n > 0){
                     data += n;
                     len -= n;
                 }
                 continue;
             }
-            D("ERROR: n = %d, errno = %d (%s)\n",
-                n, errno, strerror(errno));
+            D("fail to usb read: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
             return -1;
         }
 
@@ -485,230 +491,28 @@ int sdb_usb_read(usb_handle *h, void *_data, int len)
         data += xfer;
     }
 
-    D("-- usb_read --\n");
+    D("-sdb_usb_read\n");
+
     return 0;
 }
 
 void sdb_usb_kick(usb_handle *h)
 {
-    D("[ kicking %p (fd = %d) ]\n", h, h->desc);
-    sdb_mutex_lock(&h->lock);
-    if(h->dead == 0) {
-        h->dead = 1;
-
-        if (h->writeable) {
-            /* HACK ALERT!
-            ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
-            ** This is a workaround for that problem.
-            */
-            if (h->reaper_thread) {
-                pthread_kill(h->reaper_thread, SIGALRM);
-            }
-
-            /* cancel any pending transactions
-            ** these will quietly fail if the txns are not active,
-            ** but this ensures that a reader blocked on REAPURB
-            ** will get unblocked
-            */
-            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
-            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
-            h->urb_in.status = -ENODEV;
-            h->urb_out.status = -ENODEV;
-            h->urb_in_busy = 0;
-            h->urb_out_busy = 0;
-            sdb_cond_broadcast(&h->notify);
-        } else {
-            unregister_usb_transport(h);
-        }
-    }
-    sdb_mutex_unlock(&h->lock);
+    D("+kicking\n");
+    D("-kicking\n");
 }
 
 int sdb_usb_close(usb_handle *h)
 {
-    D("[ usb close ... ]\n");
-    sdb_mutex_lock(&usb_lock);
-    h->next->prev = h->prev;
-    h->prev->next = h->next;
-    h->prev = 0;
-    h->next = 0;
-
-    sdb_close(h->desc);
-    D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
-    sdb_mutex_unlock(&usb_lock);
-
-    free(h);
-    return 0;
-}
+    D("+usb close\n");
 
-static void register_device(const char *dev_name,
-                            unsigned char ep_in, unsigned char ep_out,
-                            int interface, int serial_index, unsigned zero_mask)
-{
-    usb_handle* usb = 0;
-    int n = 0;
-    char serial[256];
-    int bConfigurationValue = 2; /* tizen specific : sdb needs 2nd configruation */
-
-        /* Since Linux will not reassign the device ID (and dev_name)
-        ** as long as the device is open, we can add to the list here
-        ** once we open it and remove from the list when we're finally
-        ** closed and everything will work out fine.
-        **
-        ** If we have a usb_handle on the list 'o handles with a matching
-        ** name, we have no further work to do.
-        */
-    sdb_mutex_lock(&usb_lock);
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if(!strcmp(usb->fname, dev_name)) {
-            sdb_mutex_unlock(&usb_lock);
-            return;
-        }
-    }
-    sdb_mutex_unlock(&usb_lock);
-
-    D("[ usb located new device %s (%d/%d/%d) ]\n",
-        dev_name, ep_in, ep_out, interface);
-    usb = calloc(1, sizeof(usb_handle));
-    strcpy(usb->fname, dev_name);
-    usb->ep_in = ep_in;
-    usb->ep_out = ep_out;
-    usb->zero_mask = zero_mask;
-    usb->writeable = 1;
-
-    sdb_cond_init(&usb->notify, 0);
-    sdb_mutex_init(&usb->lock, 0);
-    /* initialize mark to 1 so we don't get garbage collected after the device scan */
-    usb->mark = 1;
-    usb->reaper_thread = 0;
-
-    usb->desc = unix_open(usb->fname, O_RDWR);
-    if(usb->desc < 0) {
-        /* if we fail, see if have read-only access */
-        usb->desc = unix_open(usb->fname, O_RDONLY);
-        if(usb->desc < 0) goto fail;
-        usb->writeable = 0;
-        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
-    } else {
-        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
-        // TODO: verify reset is really needed!
-        n = ioctl(usb->desc, USBDEVFS_RESET);
-        if(n != 0) {
-            D("[ usb reset failed %s fd = %d]\n", usb->fname, usb->desc);
-        }
-        n = ioctl(usb->desc, USBDEVFS_SETCONFIGURATION, &bConfigurationValue);
-        if (n != 0) {
-            D("[ usb set %d configuration failed %s fd = %d]\n", bConfigurationValue, usb->fname, usb->desc);
-            D("check kernel is supporting %dth configuration\n", bConfigurationValue);
-        }
-
-        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
-        if(n != 0) {
-            D("[ usb claim failed %s fd = %d]\n", usb->fname, usb->desc);
-        }
+    if (h != NULL) {
+        remove_node(&usb_list, h->node, no_free);
+        sdb_close(h->node_fd);
+        free(h);
+        h = NULL;
     }
-
-        /* read the device's serial number */
-    serial[0] = 0;
-    memset(serial, 0, sizeof(serial));
-    if (serial_index) {
-        struct usbdevfs_ctrltransfer  ctrl;
-        __u16 buffer[128];
-        __u16 languages[128];
-        int i, result;
-        int languageCount = 0;
-
-        memset(languages, 0, sizeof(languages));
-        memset(&ctrl, 0, sizeof(ctrl));
-
-            // read list of supported languages
-        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-        ctrl.wValue = (USB_DT_STRING << 8) | 0;
-        ctrl.wIndex = 0;
-        ctrl.wLength = sizeof(languages);
-        ctrl.data = languages;
-        ctrl.timeout = 1000;
-
-        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
-        if (result > 0)
-            languageCount = (result - 2) / 2;
-
-        for (i = 1; i <= languageCount; i++) {
-            memset(buffer, 0, sizeof(buffer));
-            memset(&ctrl, 0, sizeof(ctrl));
-
-            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
-            ctrl.wIndex = __le16_to_cpu(languages[i]);
-            ctrl.wLength = sizeof(buffer);
-            ctrl.data = buffer;
-            ctrl.timeout = 1000;
-
-            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
-            if (result > 0) {
-                int j;
-                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-                result /= 2;
-                for (j = 1; j < result; j++) {
-                    serial[j - 1] = __le16_to_cpu(buffer[j]);
-                }
-                serial[j - 1] = 0;
-                break;
-            }
-        }
-    }
-
-        /* add to the end of the active handles */
-    sdb_mutex_lock(&usb_lock);
-    usb->next = &handle_list;
-    usb->prev = handle_list.prev;
-    usb->prev->next = usb;
-    usb->next->prev = usb;
-    sdb_mutex_unlock(&usb_lock);
-
-    register_usb_transport(usb, serial, usb->writeable);
-    return;
-
-fail:
-    D("[ usb open %s error=%d, err_str = %s]\n",
-        usb->fname,  errno, strerror(errno));
-    if(usb->desc >= 0) {
-        sdb_close(usb->desc);
-    }
-    free(usb);
-}
-
-void* device_poll_thread(void* unused)
-{
-    D("Created device thread\n");
-    for(;;) {
-            /* XXX use inotify */
-        find_usb_device("/dev/bus/usb", register_device);
-        linux_kick_disconnected_devices();
-        sleep(1);
-    }
-    return NULL;
-}
-
-static void sigalrm_handler(int signo)
-{
-    // don't need to do anything here
+    D("-usb close\n");
+    return 0;
 }
 
-void sdb_usb_init()
-{
-    sdb_thread_t tid;
-    struct sigaction    actions;
-
-    memset(&actions, 0, sizeof(actions));
-    sigemptyset(&actions.sa_mask);
-    actions.sa_flags = 0;
-    actions.sa_handler = sigalrm_handler;
-    sigaction(SIGALRM,& actions, NULL);
-
-    if(sdb_thread_create(&tid, device_poll_thread, NULL)){
-        fatal_errno("cannot create input thread");
-    }
-}
old mode 100644 (file)
new mode 100755 (executable)
index aab3afb..16e1fec
 
 #include "utils.h"
 #include "utils_backend.h"
+#include "log.h"
 
 #include "fdevent.h"
 #include "sdb_constants.h"
-#include "sdb.h"
+
+#define   TRACE_TAG  TRACE_SDB
 
 #if defined(OS_WINDOWS)
 const struct utils_os_backend* utils_backend = &utils_windows_backend;
@@ -187,18 +189,23 @@ char* ansi_to_utf8(const char *str) {
 }
 
 int sdb_open(const char* path, int options) {
+       LOG_INFO("path %s, options %d\n", path, options);
     return utils_backend->sdb_open(path, options);
 }
 
-int sdb_open_mode(const char* pathname, int options, int mode) {
-    return utils_backend->sdb_open_mode(pathname, options, mode);
-}
-
 int unix_open(const char* path, int options, ...) {
-    return utils_backend->unix_open(path, options);
+    int mode;
+    va_list args;
+
+    va_start( args, options);
+    mode = va_arg( args, int );
+    va_end( args);
+
+    return open(path, options, mode);
 }
 
 int sdb_creat(const char* path, int mode) {
+       LOG_INFO("path %s mode %d\n", path, mode);
     return utils_backend->sdb_creat(path, mode);
 }
 
@@ -210,10 +217,6 @@ int sdb_write(int fd, const void* buf, size_t len) {
     return utils_backend->sdb_write(fd, buf, len);
 }
 
-int sdb_lseek(int fd, int pos, int where) {
-    return utils_backend->sdb_lseek(fd, pos, where);
-}
-
 int sdb_shutdown(int fd) {
     return utils_backend->sdb_shutdown(fd);
 }
@@ -222,8 +225,16 @@ int sdb_close(int fd) {
     return utils_backend->sdb_close(fd);
 }
 
-int sdb_unlink(const char* path) {
-    return utils_backend->sdb_unlink(path);
+int unix_unlink(const char* path) {
+    int rc = unlink(path);
+
+    if (rc == -1 && errno == EACCES) {
+        rc = chmod(path, S_IREAD | S_IWRITE);
+        if (rc == 0) {
+            rc = unlink(path);
+        }
+    }
+    return rc;
 }
 
 int sdb_mkdir(const char* path, int mode) {
@@ -234,11 +245,13 @@ void close_on_exec(int fd) {
     return utils_backend->close_on_exec(fd);
 }
 
-int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) {
-    return utils_backend->sdb_socket_accept(serverfd, addr, addrlen);
+int sdb_socket_accept(int serverfd) {
+       LOG_INFO("FD(%d)\n");
+    return utils_backend->sdb_socket_accept(serverfd);
 }
 
 int sdb_socketpair(int sv[2]) {
+       LOG_INFO("\n");
     return utils_backend->sdb_socketpair(sv);
 }
 
@@ -266,11 +279,17 @@ int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg)
     return utils_backend->sdb_thread_create(pthread, start, arg);
 }
 
-int sdb_mutex_lock(sdb_mutex_t *mutex) {
+int sdb_mutex_lock(sdb_mutex_t *mutex, char* name) {
+    if(name != NULL) {
+        D("lock %s\n", name);
+    }
     return utils_backend->sdb_mutex_lock(mutex);
 }
 
-int sdb_mutex_unlock(sdb_mutex_t *mutex) {
+int sdb_mutex_unlock(sdb_mutex_t *mutex, char *name) {
+    if(name != NULL) {
+        D("unlock %s\n", name);
+    }
     return utils_backend->sdb_mutex_unlock(mutex);
 }
 
@@ -290,18 +309,13 @@ void sdb_sysdeps_init(void) {
     return utils_backend->sdb_sysdeps_init();
 }
 
-int socket_loopback_client(int port, int type) {
-    return utils_backend->socket_loopback_client(port, type);
+int sdb_host_connect(const char *host, int port, int type) {
+       LOG_INFO("host %s, port %d\n", host, port);
+    return utils_backend->sdb_host_connect(host, port, type);
 }
 
-int socket_network_client(const char *host, int port, int type) {
-    return utils_backend->socket_network_client(host, port, type);
+int sdb_port_listen(uint32_t inet, int port, int type) {
+       LOG_INFO("port %d, type %d\n", port, type);
+    return utils_backend->sdb_port_listen(inet, port, type);
 }
 
-int socket_loopback_server(int port, int type) {
-    return utils_backend->socket_loopback_server(port, type);
-}
-
-int socket_inaddr_any_server(int port, int type) {
-    return utils_backend->socket_inaddr_any_server(port, type);
-}
index 1d87666dce46e5c07c9a1a9d73860aacbaf97ae1..a31af3411405aa556aea682aab84e44acb495978 100644 (file)
@@ -83,14 +83,17 @@ extern int unix_read(int fd, void* buf, size_t len);
 typedef  pthread_t                sdb_thread_t;
 typedef  pthread_mutex_t          sdb_mutex_t;
 #define  sdb_cond_t               pthread_cond_t
-#define sdb_mutex_init           pthread_mutex_init
+#define  sdb_mutex_init           pthread_mutex_init
+#define  sdb_cond_signal          pthread_cond_signal
+#define  sdb_cond_destroy         pthread_cond_destroy
+#define  sdb_mutex_destroy        pthread_mutex_destroy
 
 typedef void*  (*sdb_thread_func_t)( void*  arg );
 
 void sdb_sysdeps_init(void);
 int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg);
-int sdb_mutex_lock(sdb_mutex_t *mutex);
-int sdb_mutex_unlock(sdb_mutex_t *mutex);
+int sdb_mutex_lock(sdb_mutex_t *mutex, char* lock_name);
+int sdb_mutex_unlock(sdb_mutex_t *mutex, char* lock_name);
 int sdb_cond_init(sdb_cond_t *cond, const void *unused);
 int sdb_cond_wait(sdb_cond_t *cond, sdb_mutex_t *mutex);
 int sdb_cond_broadcast(sdb_cond_t *cond);
@@ -98,9 +101,8 @@ int sdb_cond_broadcast(sdb_cond_t *cond);
 #define  SDB_MUTEX(x)   sdb_mutex_t  x;
 
 SDB_MUTEX(dns_lock)
-SDB_MUTEX(socket_list_lock)
 SDB_MUTEX(transport_lock)
-SDB_MUTEX(local_transports_lock)
+SDB_MUTEX(wakeup_select_lock)
 SDB_MUTEX(usb_lock)
 SDB_MUTEX(D_lock)
 
@@ -113,13 +115,12 @@ int unix_open(const char* path, int options, ...);
 int sdb_creat(const char* path, int mode);
 int sdb_read(int fd, void* buf, size_t len);
 int sdb_write(int fd, const void* buf, size_t len);
-int sdb_lseek(int fd, int pos, int where);
 int sdb_shutdown(int fd);
 int sdb_close(int fd);
-int sdb_unlink(const char* path);
+int unix_unlink(const char* path);
 int sdb_mkdir(const char* path, int mode);
 void close_on_exec(int fd);
-int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
+int sdb_socket_accept(int serverfd);
 int sdb_socketpair(int sv[2]);
 void sdb_sleep_ms(int mseconds);
 char* sdb_dirstart(const char* path);
@@ -128,10 +129,10 @@ int sdb_socket_setbufsize(int fd, int bufsize);
 void disable_tcp_nagle(int fd);
 
 // sockets
-int socket_loopback_client(int port, int type);
-int socket_network_client(const char *host, int port, int type);
-int socket_loopback_server(int port, int type);
-int socket_inaddr_any_server(int port, int type);
+#define LISTEN_BACKLOG 4
+
+int sdb_host_connect(const char *host, int port, int type);
+int sdb_port_listen(uint32_t inet, int port, int type);
 
 #define DEVICEMAP_SEPARATOR ":"
 #define DEVICENAME_MAX 256
old mode 100644 (file)
new mode 100755 (executable)
index 39d0295..f8feb7a
 #ifndef _SDB_BACKEND_UTILS_H
 #define _SDB_BACKEND_UTILS_H
 
-#if defined(OS_WINDOWS)
-
-typedef const struct FHClassRec_*   FHClass;
-
-typedef struct FHRec_*          FH;
-
-typedef struct EventHookRec_*  EventHook;
-
-typedef struct FHClassRec_
-{
-    void (*_fh_init) ( FH  f );
-    int  (*_fh_close)( FH  f );
-    int  (*_fh_lseek)( FH  f, int  pos, int  origin );
-    int  (*_fh_read) ( FH  f, void*  buf, int  len );
-    int  (*_fh_write)( FH  f, const void*  buf, int  len );
-    void (*_fh_hook) ( FH  f, int  events, EventHook  hook );
-
-} FHClassRec;
+#include "linkedlist.h"
+#include "sdb_map.h"
 
-/* used to emulate unix-domain socket pairs */
-typedef struct SocketPairRec_*  SocketPair;
 
-typedef struct FHRec_
-{
-    FHClass    clazz;
-    int        used;
-    int        eof;
-    union {
-        HANDLE      handle;
-        SOCKET      socket;
-        SocketPair  pair;
-    } u;
+#if defined(OS_WINDOWS)
 
-    HANDLE    event;
-    int       mask;
+struct sdb_handle {
+       union {
+               HANDLE      file_handle;
+               SOCKET      socket;
+       } u;
+       int fd;
+};
 
-    char  name[32];
+typedef struct sdb_handle SDB_HANDLE;
 
-} FHRec;
+struct sdb_socket_handle {
+       SDB_HANDLE handle;
+       int event_location;
+};
 
-#define  fh_handle  u.handle
-#define  fh_socket  u.socket
-#define  fh_pair    u.pair
+typedef struct sdb_socket_handle SDB_SOCK_HANDLE;
 
 #define  BIP_BUFFER_SIZE   4096
-#define  WIN32_FH_BASE    100
-#define  WIN32_MAX_FHS    128
-
-typedef struct BipBufferRec_
-{
-    int                a_start;
-    int                a_end;
-    int                b_end;
-    int                fdin;
-    int                fdout;
-    int                closed;
-    int                can_write;  /* boolean */
-    HANDLE             evt_write;  /* event signaled when one can write to a buffer  */
-    int                can_read;   /* boolean */
-    HANDLE             evt_read;   /* event signaled when one can read from a buffer */
-    CRITICAL_SECTION  lock;
-    unsigned char      buff[ BIP_BUFFER_SIZE ];
-
-} BipBufferRec, *BipBuffer;
-
-typedef struct EventLooperRec_*  EventLooper;
-
-typedef struct EventHookRec_
-{
-    EventHook    next;
-    FH           fh;
-    HANDLE       h;
-    int          wanted;   /* wanted event flags */
-    int          ready;    /* ready event flags  */
-    void*        aux;
-    void        (*prepare)( EventHook  hook );
-    int         (*start)  ( EventHook  hook );
-    void        (*stop)   ( EventHook  hook );
-    int         (*check)  ( EventHook  hook );
-    int         (*peek)   ( EventHook  hook );
-} EventHookRec;
-
 #define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
+#define IS_SOCKET_HANDLE(handle) (handle->fd < WIN32_MAX_FHS)
+#define IS_SOCKET_FD(fd) (fd < WIN32_MAX_FHS)
 
-typedef struct EventLooperRec_
-{
-    EventHook    hooks;
-    HANDLE       htab[ MAX_LOOPER_HANDLES ];
-    int          htab_count;
-
-} EventLooperRec;
-
-int _fh_to_int( FH  f );
-FH _fh_from_int( int   fd );
+SDB_HANDLE* sdb_handle_map_get(int _key);
+void sdb_handle_map_put(int _key, SDB_HANDLE* value);
+void sdb_handle_map_remove(int _key);
 
 #else
 #endif // end of unix
@@ -123,18 +60,14 @@ struct utils_os_backend {
     void (*start_logging)(void);
     char* (*ansi_to_utf8)(const char *str);
     int (*sdb_open)(const char* path, int options);
-    int (*sdb_open_mode)(const char* path, int options, int mode);
-    int (*unix_open)(const char* path, int options, ...);
     int (*sdb_creat)(const char* path, int mode);
     int (*sdb_read)(int fd, void* buf, size_t len);
     int (*sdb_write)(int fd, const void* buf, size_t len);
-    int (*sdb_lseek)(int fd, int pos, int where);
     int (*sdb_shutdown)(int fd);
     int (*sdb_close)(int fd);
-    int (*sdb_unlink)(const char* path);
     int (*sdb_mkdir)(const char* path, int mode);
     void (*close_on_exec)(int fd);
-    int (*sdb_socket_accept)(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
+    int (*sdb_socket_accept)(int serverfd);
     int (*sdb_socketpair)(int sv[2]);
     void (*sdb_sleep_ms)(int mseconds);
     char* (*sdb_dirstart)(const char* path);
@@ -156,10 +89,8 @@ struct utils_os_backend {
     int (*sdb_cond_broadcast)(sdb_cond_t *cond);
     void (*sdb_sysdeps_init)(void);
     // helpers for sockets
-    int (*socket_loopback_client)(int port, int type);
-    int (*socket_network_client)(const char *host, int port, int type);
-    int (*socket_loopback_server)(int port, int type);
-    int (*socket_inaddr_any_server)(int port, int type);
+    int (*sdb_host_connect)(const char *host, int port, int type);
+    int (*sdb_port_listen)(uint32_t inet, int port, int type);
 
 };
 
old mode 100644 (file)
new mode 100755 (executable)
index c9227a1..5f29b68
 #include "fdevent.h"
 
 #define  TRACE_TAG  TRACE_SYSDEPS
-#include "sdb.h"
 #include "utils_backend.h"
-
-#define LISTEN_BACKLOG 4
-
-static void  _close_on_exec(int  fd);
+#include "log.h"
 
 #if defined(OS_DARWIN)
 
@@ -104,6 +100,8 @@ static int _launch_server(int server_port)
         dup2(fd[1], STDERR_FILENO);
         sdb_close(fd[1]);
 
+        sdb_close(STDOUT_FILENO);
+
         // child process
         int result = execl(path, "sdb", "fork-server", "server", NULL);
         // this should not return
@@ -119,6 +117,7 @@ static int _launch_server(int server_port)
         int ret = sdb_read(fd[0], temp, 3);
         int saved_errno = errno;
         sdb_close(fd[0]);
+
         if (ret < 0) {
             fprintf(stderr, "could not read ok from SDB Server, errno = %d\n", saved_errno);
             return -1;
@@ -136,23 +135,36 @@ static int _launch_server(int server_port)
 
 static void _start_logging(void)
 {
-    const char*  p = getenv("SDB_TRACE");
+    const char*  p = getenv(DEBUG_ENV);
     if (p == NULL) {
         return;
     }
     int fd;
 
     fd = unix_open("/dev/null", O_RDONLY);
-    dup2(fd, 0);
-    sdb_close(fd);
+    if (fd >= 0) {
+        dup2(fd, 0);
+        sdb_close(fd);
+    }
+    else {
+        sdb_close(0);
+    }
 
     fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
     if(fd < 0) {
+        fprintf(stderr, "fail to open '/tmp/sdb.log' logging fails\n");
         fd = unix_open("/dev/null", O_WRONLY);
+        if( fd < 0 ) {
+            fprintf(stderr, "fail to open /dev/null\n");
+            fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
+            return;
+        }
     }
+
     dup2(fd, 1);
     dup2(fd, 2);
     sdb_close(fd);
+
     fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
 }
 
@@ -169,21 +181,9 @@ static char* _ansi_to_utf8(const char *str)
     return utf8;
 }
 
-static int  _unix_open(const char*  path, int options,...)
+static void  _close_on_exec(int  fd)
 {
-    if ((options & O_CREAT) == 0)
-    {
-        return  open(path, options);
-    }
-    else
-    {
-        int      mode;
-        va_list  args;
-        va_start( args, options );
-        mode = va_arg( args, int );
-        va_end( args );
-        return open(path, options, mode);
-    }
+    fcntl( fd, F_SETFD, FD_CLOEXEC );
 }
 
 static int _sdb_open( const char*  pathname, int  options )
@@ -195,15 +195,9 @@ static int _sdb_open( const char*  pathname, int  options )
     return fd;
 }
 
-static int _sdb_open_mode( const char*  pathname, int  options, int  mode )
-{
-    return open( pathname, options, mode );
-}
-
-
 static int  _sdb_creat(const char*  path, int  mode)
 {
-    int  fd = creat(path, mode);
+    int  fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
 
     if ( fd < 0 )
         return -1;
@@ -222,11 +216,6 @@ static int  _sdb_write(int  fd, const void*  buf, size_t  len)
     return write(fd, buf, len);
 }
 
-static int  _sdb_lseek(int  fd, int  pos, int  where)
-{
-    return lseek(fd, pos, where);
-}
-
 static int  _sdb_shutdown(int fd)
 {
     return shutdown(fd, SHUT_RDWR);
@@ -237,26 +226,19 @@ static int  _sdb_close(int fd)
     return close(fd);
 }
 
-static void  _close_on_exec(int  fd)
-{
-    fcntl( fd, F_SETFD, FD_CLOEXEC );
-}
-
-static int _sdb_unlink(const char*  path)
-{
-    return  unlink(path);
-}
-
 static int  _sdb_mkdir(const char*  path, int mode)
 {
     return mkdir(path, mode);
 }
 
-static int _sdb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
+static int _sdb_socket_accept(int  serverfd)
 {
     int fd;
+    struct sockaddr addr;
+    socklen_t alen = sizeof(addr);
+
+    fd = accept(serverfd, &addr, &alen);
 
-    fd = accept(serverfd, addr, addrlen);
     if (fd >= 0) {
         _close_on_exec(fd);
     }
@@ -343,44 +325,32 @@ static void  _sdb_sysdeps_init(void)
 {
 }
 
-static int _socket_loopback_client(int port, int type)
+static int _sdb_host_connect(const char *host, int port, int type)
 {
+    struct hostent *hp;
     struct sockaddr_in addr;
     int s;
 
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
-
-    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        sdb_close(s);
+    // FIXME: might take a long time to get information
+    if ((hp = gethostbyname(host)) == NULL) {
+        LOG_ERROR("failed to get hostname:%s(%d)\n", host, port);
         return -1;
     }
 
-    return s;
-
-}
-
-static int _socket_network_client(const char *host, int port, int type)
-{
-    struct hostent *hp;
-    struct sockaddr_in addr;
-    int s;
-
-    hp = gethostbyname(host);
-    if(hp == 0) return -1;
-
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = hp->h_addrtype;
     addr.sin_port = htons(port);
     memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
 
-    s = socket(hp->h_addrtype, type, 0);
-    if(s < 0) return -1;
+    if (type == SOCK_STREAM) {
+        s = socket(AF_INET, type, 0);
+    } else {
+        s = socket(AF_INET, type, IPPROTO_UDP);
+    }
+    if (s < 0) {
+        LOG_ERROR("failed to create socket to %s(%d)\n", host, port);
+        return -1;
+    }
 
     if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         sdb_close(s);
@@ -391,61 +361,21 @@ static int _socket_network_client(const char *host, int port, int type)
 
 }
 
-static int _socket_loopback_server(int port, int type)
+static int _sdb_port_listen(uint32_t inet, int port, int type)
 {
     struct sockaddr_in addr;
     int s, n;
-    int cnt_max = 30;
 
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(inet);
     addr.sin_port = htons(port);
 
-    if(cnt_max ==0)
-        addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    else
-        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
-
-    n = 1;
-    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
-
-
-
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        sdb_close(s);
+    if ((s = socket(AF_INET, type, 0)) < 0) {
+        LOG_ERROR("failed to create socket to %u(%d)\n", inet, port);
         return -1;
     }
 
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-
-        if (ret < 0) {
-            sdb_close(s);
-            return -1;
-        }
-    }
-
-    return s;
-}
-
-static int _socket_inaddr_any_server(int port, int type)
-{
-    struct sockaddr_in addr;
-    int s, n;
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
-
     n = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
 
@@ -454,12 +384,9 @@ static int _socket_inaddr_any_server(int port, int type)
         return -1;
     }
 
+    // only listen if tcp mode
     if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-
-        if (ret < 0) {
+        if (listen(s, LISTEN_BACKLOG) < 0) {
             sdb_close(s);
             return -1;
         }
@@ -468,22 +395,19 @@ static int _socket_inaddr_any_server(int port, int type)
     return s;
 }
 
+
 const struct utils_os_backend utils_unix_backend = {
     .name = "unix utils",
     .launch_server = _launch_server,
     .start_logging = _start_logging,
     .ansi_to_utf8 = _ansi_to_utf8,
     .sdb_open = _sdb_open,
-    .sdb_open_mode = _sdb_open_mode,
-    .unix_open = _unix_open,
     .sdb_creat = _sdb_creat,
     .sdb_read = _sdb_read,
     .sdb_write = _sdb_write,
-    .sdb_lseek = _sdb_lseek,
     .sdb_shutdown = _sdb_shutdown,
     .sdb_close = _sdb_close,
     .close_on_exec = _close_on_exec,
-    .sdb_unlink = _sdb_unlink,
     .sdb_mkdir = _sdb_mkdir,
     .sdb_socket_accept = _sdb_socket_accept,
     .sdb_socketpair = _sdb_socketpair,
@@ -500,8 +424,6 @@ const struct utils_os_backend utils_unix_backend = {
     .sdb_cond_wait = _sdb_cond_wait,
     .sdb_cond_broadcast = _sdb_cond_broadcast,
     .sdb_sysdeps_init = _sdb_sysdeps_init,
-    .socket_loopback_client = _socket_loopback_client,
-    .socket_network_client = _socket_network_client,
-    .socket_loopback_server = _socket_loopback_server,
-    .socket_inaddr_any_server = _socket_inaddr_any_server
+    .sdb_host_connect = _sdb_host_connect,
+    .sdb_port_listen = _sdb_port_listen
 };
old mode 100644 (file)
new mode 100755 (executable)
index 3f1b5eb..33edf5a
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <windows.h>
 #include <winsock2.h>
 #include <stdio.h>
 #include <errno.h>
+#include <limits.h>
 #include "utils.h"
 #include "fdevent.h"
 #include "fdevent_backend.h"
+#include "sdb_map.h"
 
 #define  TRACE_TAG  TRACE_SYSDEPS
-#include "sdb.h"
 #include "utils_backend.h"
+#include "log.h"
+
+// error mapping table between windoes & unix
+// error codes are described: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx
+void setBaseErrno(DWORD dwLastErrorCode);
+int getBaseErrno(DWORD dwLastErrorCode);
+
+static int total_handle_number = 0;
+static LIST_NODE* free_socket_handle_list = NULL;
+//this increases 1 when one file fd is created.
+static int file_handle_count = WIN32_MAX_FHS;
+//this indicates total number of socket fds.
+static int socket_handle_number = 0;
+
+struct errno_lists {
+        unsigned long wincode;
+        int posixcode;
+};
+
+static struct errno_lists errno_list[] = {
+        { 0, 0 },                               /* 0 return 0 as normal operation */
+        { ERROR_INVALID_FUNCTION, EINVAL },     /* 1 Incorrect function. */
+        { ERROR_FILE_NOT_FOUND, ENOENT },       /* 2 The system cannot find the file specified. */
+        { ERROR_PATH_NOT_FOUND, ENOENT },       /* 3 The system cannot find the path specified. */
+        { ERROR_TOO_MANY_OPEN_FILES, EMFILE },  /* 4 The system cannot open the file. */
+        { ERROR_ACCESS_DENIED, EACCES },        /* 5 Access is denied. */
+        { ERROR_INVALID_HANDLE, EBADF },        /* 6 The handle is invalid. */
+        { ERROR_ARENA_TRASHED, ENOMEM },        /* 7 The storage control blocks were destroyed.*/
+        { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },    /* 8 Not enough storage is available to process this command. */
+        { ERROR_INVALID_BLOCK, ENOMEM },        /* 9 he storage control block address is invalid. */
+        { ERROR_BAD_ENVIRONMENT, E2BIG },       /* 10 The environment is incorrect. */
+        { ERROR_BAD_FORMAT, ENOEXEC },          /* 11 An attempt was made to load a program with an incorrect format. */
+        { ERROR_INVALID_ACCESS, EINVAL },       /* 12 The access code is invalid. */
+        { ERROR_INVALID_DATA, EINVAL },         /* 13 The data is invalid. */
+        { ERROR_OUTOFMEMORY, ENOMEM },          /* 14 Not enough storage is available to complete this operation. */
+        { ERROR_INVALID_DRIVE, ENOENT },        /* 15 The system cannot find the drive specified.*/
+        { ERROR_CURRENT_DIRECTORY, EACCES },    /* 16 */
+        { ERROR_NOT_SAME_DEVICE, EXDEV },       /* 17 */
+        { ERROR_NO_MORE_FILES, ENOENT },        /* 18 */
+        { ERROR_LOCK_VIOLATION, EACCES },       /* 33 */
+        { ERROR_BAD_NETPATH, ENOENT },          /* 53 */
+        { ERROR_NETWORK_ACCESS_DENIED, EACCES },/* 65 */
+        { ERROR_BAD_NET_NAME, ENOENT },         /* 67 */
+        { ERROR_FILE_EXISTS, EEXIST },          /* 80 */
+        { ERROR_CANNOT_MAKE, EACCES },          /* 82 */
+        { ERROR_FAIL_I24, EACCES },             /* 83 */
+        { ERROR_INVALID_PARAMETER, EINVAL },    /* 87 */
+        { ERROR_NO_PROC_SLOTS, EAGAIN },        /* 89 */
+        { ERROR_DRIVE_LOCKED, EACCES },         /* 108 */
+        { ERROR_BROKEN_PIPE, EPIPE },           /* 109 */
+        { ERROR_DISK_FULL, ENOSPC },            /* 112 */
+        { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
+        { ERROR_INVALID_HANDLE, EINVAL },       /* 124 */
+        { ERROR_WAIT_NO_CHILDREN, ECHILD },     /* 128 */
+        { ERROR_CHILD_NOT_COMPLETE, ECHILD },   /* 129 */
+        { ERROR_DIRECT_ACCESS_HANDLE, EBADF },  /* 130 */
+        { ERROR_NEGATIVE_SEEK, EINVAL },        /* 131 */
+        { ERROR_SEEK_ON_DEVICE, EACCES },       /* 132 */
+        { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },     /* 145 */
+        { ERROR_NOT_LOCKED, EACCES },           /* 158 */
+        { ERROR_BAD_PATHNAME, ENOENT },         /* 161 */
+        { ERROR_MAX_THRDS_REACHED, EAGAIN },    /* 164 */
+        { ERROR_LOCK_FAILED, EACCES },          /* 167 */
+        { ERROR_ALREADY_EXISTS, EEXIST },       /* 183 */
+        { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
+        { ERROR_NESTING_NOT_ALLOWED, EAGAIN },  /* 215 */
+        { ERROR_NO_DATA, EPIPE },               /* 232 */
+        { ERROR_NOT_ENOUGH_QUOTA, ENOMEM },     /* 1816 */
+        { WSAEINTR, EINTR }, /* 10004 Interrupted function call. */
+        { WSAEWOULDBLOCK, EAGAIN } /* 10035 This error is returned from operations on nonblocking sockets that cannot be completed immediately */
+};
+
+void setBaseErrno(DWORD dwLastErrorCode)
+{
+    errno = getBaseErrno(dwLastErrorCode);
+}
+
+int getBaseErrno(DWORD dwLastErrorCode)
+{
+    int i;
+
+    for (i = 0; i < sizeof(errno_list)/sizeof(errno_list[0]); ++i) {
+        if (dwLastErrorCode == errno_list[i].posixcode) {
+            return errno_list[i].posixcode;
+        }
+    }
+    LOG_FIXME("unsupport error code: %ld\n", dwLastErrorCode);
+    return EINVAL;
+}
 
 /*
  * from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
@@ -122,7 +213,7 @@ static int _launch_server(int server_port) {
 
 static void _start_logging(void)
 {
-    const char*  p = getenv("SDB_TRACE");
+    const char*  p = getenv(DEBUG_ENV);
     if (p == NULL) {
         return;
     }
@@ -150,11 +241,6 @@ static void _start_logging(void)
     fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
 }
 
-
-extern void fatal(const char *fmt, ...);
-
-#define assert(cond)  do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -164,344 +250,275 @@ extern void fatal(const char *fmt, ...);
 /**************************************************************************/
 
 static sdb_mutex_t _win32_lock;
-static FHRec _win32_fhs[WIN32_MAX_FHS];
-static int _win32_fh_count;
-
-FH _fh_from_int(int fd) {
-    FH f;
-
-    fd -= WIN32_FH_BASE;
-
-    if (fd < 0 || fd >= _win32_fh_count) {
-        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE);
-        errno = EBADF;
-        return NULL;
+static sdb_mutex_t sdb_handle_map_lock;
+static sdb_mutex_t free_socket_handle_list_lock;
+
+static SDB_HANDLE* alloc_handle(int socket) {
+
+       SDB_HANDLE* _h = NULL;
+    sdb_mutex_lock(&_win32_lock, "_fh_alloc");
+
+    if(total_handle_number < WIN32_MAX_FHS) {
+       total_handle_number++;
+       if(socket) {
+               if(free_socket_handle_list == NULL) {
+                       SDB_SOCK_HANDLE* __h = malloc(sizeof(SDB_SOCK_HANDLE));
+                       __h->event_location = -1;
+                       _h = (SDB_HANDLE*)__h;
+                       _h->fd = socket_handle_number++;
+                       LOG_INFO("no free socket. assign socket fd FD(%d)\n", _h->fd);
+               }
+               else {
+                       sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_alloc");
+                       _h = free_socket_handle_list->data;
+                       remove_first(&free_socket_handle_list, no_free);
+                       sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_alloc");
+                       LOG_INFO("reuse socket fd FD(%d)\n", _h->fd);
+               }
+               _h->u.socket = INVALID_SOCKET;
+       }
+       else {
+               _h = malloc(sizeof(SDB_HANDLE));
+               _h->fd = file_handle_count++;
+               _h->u.file_handle = INVALID_HANDLE_VALUE;
+       }
+
+       sdb_handle_map_put(_h->fd, _h);
     }
-
-    f = &_win32_fhs[fd];
-
-    if (f->used == 0) {
-        D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE);
-        errno = EBADF;
-        return NULL;
-    }
-
-    return f;
-}
-
-int _fh_to_int(FH f) {
-    if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
-        return (int) (f - _win32_fhs) + WIN32_FH_BASE;
-
-    return -1;
+    else {
+       errno = ENOMEM;
+       LOG_ERROR("no more space for file descriptor. max file descriptor is %d\n", WIN32_MAX_FHS);
+    }
+
+    sdb_mutex_unlock(&_win32_lock, "_fh_alloc");
+    return _h;
+}
+
+SDB_HANDLE* sdb_handle_map_get(int _key) {
+       MAP_KEY key;
+       key.key_int = _key;
+       sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_get");
+       SDB_HANDLE* result = map_get(&sdb_handle_map, key);
+       sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_get");
+       return result;
+}
+
+void sdb_handle_map_put(int _key, SDB_HANDLE* value) {
+       MAP_KEY key;
+       key.key_int = _key;
+       sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_put");
+       map_put(&sdb_handle_map, key, value);
+       sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_put");
+}
+
+void sdb_handle_map_remove(int _key) {
+       MAP_KEY key;
+       key.key_int = _key;
+       sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_remove");
+       map_remove(&sdb_handle_map, key);
+       sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_remove");
+}
+
+static int _fh_close(SDB_HANDLE* _h) {
+       if(IS_SOCKET_HANDLE(_h)) {
+           shutdown(_h->u.socket, SD_BOTH);
+           closesocket(_h->u.socket);
+           _h->u.socket = INVALID_SOCKET;
+               sdb_handle_map_remove(_h->fd);
+               sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_close");
+               prepend(&free_socket_handle_list, _h);
+               sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_close");
+       }
+       else {
+           CloseHandle(_h->u.file_handle);
+           _h->u.file_handle = INVALID_HANDLE_VALUE;
+           free(_h);
+       }
+       total_handle_number--;
+    return 0;
 }
 
-static FH _fh_alloc(FHClass clazz) {
-    int nn;
-    FH f = NULL;
+static int check_socket_err(int result) {
 
-    sdb_mutex_lock(&_win32_lock);
+       if(result != SOCKET_ERROR) {
+               return result;
+       }
 
-    if (_win32_fh_count < WIN32_MAX_FHS) {
-        f = &_win32_fhs[_win32_fh_count++];
-        goto Exit;
-    }
+       DWORD err = WSAGetLastError();
 
-    for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
-        if (_win32_fhs[nn].clazz == NULL) {
-            f = &_win32_fhs[nn];
-            goto Exit;
-        }
-    }
-    D( "_fh_alloc: no more free file descriptors\n");
-    Exit: if (f) {
-        f->clazz = clazz;
-        f->used = 1;
-        f->eof = 0;
-        clazz->_fh_init(f);
-    }
-    sdb_mutex_unlock(&_win32_lock);
-    return f;
-}
-
-static int _fh_close(FH f) {
-    if (f->used) {
-        f->clazz->_fh_close(f);
-        f->used = 0;
-        f->eof = 0;
-        f->clazz = NULL;
-    }
-    return 0;
+       if(err == WSAEWOULDBLOCK) {
+               errno = EAGAIN;
+               LOG_ERROR("socket error EAGAIN\n");
+       }
+       else if(err == WSAEINTR) {
+               errno = EINTR;
+               LOG_ERROR("socket error EINTR\n");
+       }
+       else if(err == 0) {
+               errno = 0;
+               LOG_ERROR("socket error 0\n");
+       }
+       else {
+               errno = EINVAL;
+               LOG_ERROR("unknown error %d\n", err);
+       }
+       return -1;
 }
 
-/* forward definitions */
-static const FHClassRec _fh_file_class;
-static const FHClassRec _fh_socket_class;
+static int check_file_err(HANDLE h) {
 
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    file-based descriptor handling                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
+    if (h != INVALID_HANDLE_VALUE) {
+       return 1;
+    }
 
-static void _fh_file_init(FH f) {
-    f->fh_handle = INVALID_HANDLE_VALUE;
-}
+       _fh_close(h);
+       DWORD err = GetLastError();
 
-static int _fh_file_close(FH f) {
-    CloseHandle(f->fh_handle);
-    f->fh_handle = INVALID_HANDLE_VALUE;
-    return 0;
+       if(err == ERROR_PATH_NOT_FOUND) {
+               LOG_ERROR("path not found\n");
+               errno = ENOTDIR;
+       }
+       else if (err == ERROR_FILE_NOT_FOUND) {
+               LOG_ERROR("file not found\n");
+               errno = ENOENT;
+       }
+       else {
+               LOG_ERROR("unknown erro %d\n", err);
+               errno = ENOENT;
+       }
+       return -1;
 }
 
-static int _fh_file_read(FH f, void* buf, int len) {
-    DWORD read_bytes;
-
-    if (!ReadFile(f->fh_handle, buf, (DWORD) len, &read_bytes, NULL)) {
-        D( "sdb_read: could not read %d bytes from %s\n", len, f->name);
-        errno = EIO;
-        return -1;
-    } else if (read_bytes < (DWORD) len) {
-        f->eof = 1;
-    }
-    return (int) read_bytes;
-}
+static int _sdb_open(const char* path, int file_options) {
 
-static int _fh_file_write(FH f, const void* buf, int len) {
-    DWORD wrote_bytes;
+    DWORD access_mode = 0;
+    DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
 
-    if (!WriteFile(f->fh_handle, buf, (DWORD) len, &wrote_bytes, NULL)) {
-        D( "sdb_file_write: could not write %d bytes from %s\n", len, f->name);
-        errno = EIO;
-        return -1;
-    } else if (wrote_bytes < (DWORD) len) {
-        f->eof = 1;
+    if(file_options == O_RDONLY) {
+        access_mode = GENERIC_READ;
     }
-    return (int) wrote_bytes;
-}
-
-static int _fh_file_lseek(FH f, int pos, int origin) {
-    DWORD method;
-    DWORD result;
-
-    switch (origin) {
-    case SEEK_SET:
-        method = FILE_BEGIN;
-        break;
-    case SEEK_CUR:
-        method = FILE_CURRENT;
-        break;
-    case SEEK_END:
-        method = FILE_END;
-        break;
-    default:
-        errno = EINVAL;
-        return -1;
+    else if(file_options == O_WRONLY) {
+       access_mode = GENERIC_WRITE;
     }
-
-    result = SetFilePointer(f->fh_handle, pos, NULL, method);
-    if (result == INVALID_SET_FILE_POINTER) {
-        errno = EIO;
-        return -1;
-    } else {
-        f->eof = 0;
+    else if(file_options == O_RDWR) {
+       access_mode = GENERIC_READ | GENERIC_WRITE;
     }
-    return (int) result;
-}
-
-static void _fh_file_hook(FH f, int event, EventHook eventhook); /* forward */
-
-static const FHClassRec _fh_file_class = { _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read, _fh_file_write,
-        _fh_file_hook };
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    file-based descriptor handling                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static int _sdb_open(const char* path, int options) {
-    FH f;
-
-    DWORD desiredAccess = 0;
-    DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
-    switch (options) {
-    case O_RDONLY:
-        desiredAccess = GENERIC_READ;
-        break;
-    case O_WRONLY:
-        desiredAccess = GENERIC_WRITE;
-        break;
-    case O_RDWR:
-        desiredAccess = GENERIC_READ | GENERIC_WRITE;
-        break;
-    default:
-        D("sdb_open: invalid options (0x%0x)\n", options);
+    else {
+        LOG_ERROR("invalid options (0x%0x)\n", file_options);
         errno = EINVAL;
         return -1;
     }
 
-    f = _fh_alloc(&_fh_file_class);
-    if (!f) {
+    SDB_HANDLE* _h;
+    _h = alloc_handle(0);
+    if (!_h) {
         errno = ENOMEM;
         return -1;
     }
 
-    f->fh_handle = CreateFile(path, desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
-
-    if (f->fh_handle == INVALID_HANDLE_VALUE) {
-        _fh_close(f);
-        D( "sdb_open: could not open '%s':", path);
-        switch (GetLastError()) {
-        case ERROR_FILE_NOT_FOUND:
-            D( "file not found\n");
-            errno = ENOENT;
-            return -1;
-
-        case ERROR_PATH_NOT_FOUND:
-            D( "path not found\n");
-            errno = ENOTDIR;
-            return -1;
-
-        default:
-            D( "unknown error\n");
-            errno = ENOENT;
-            return -1;
-        }
-    }
-
-    snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
-    D( "sdb_open: '%s' => fd %d\n", path, _fh_to_int(f));
-    return _fh_to_int(f);
-}
-
-static int _sdb_open_mode(const char* path, int options, int mode) {
-    return sdb_open(path, options);
-}
+    _h->u.file_handle = CreateFile(path, access_mode, share_mode, NULL, OPEN_EXISTING, 0, NULL);
 
-static int _unix_open(const char* path, int options, ...) {
-    if ((options & O_CREAT) == 0) {
-        return open(path, options);
-    } else {
-        int mode;
-        va_list args;
-        va_start( args, options);
-        mode = va_arg( args, int );
-        va_end( args);
-        return open(path, options, mode);
+    if(check_file_err(_h->u.file_handle) == -1) {
+       return -1;
     }
+    return _h->fd;
 }
 
-/* ignore mode on Win32 */
 static int _sdb_creat(const char* path, int mode) {
-    FH f;
+    SDB_HANDLE* _h = alloc_handle(0);
 
-    f = _fh_alloc(&_fh_file_class);
-    if (!f) {
-        errno = ENOMEM;
+    if (!_h) {
+       errno = ENOMEM;
         return -1;
     }
-
-    f->fh_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
+    _h->u.file_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
             FILE_ATTRIBUTE_NORMAL, NULL);
 
-    if (f->fh_handle == INVALID_HANDLE_VALUE) {
-        _fh_close(f);
-        D( "sdb_creat: could not open '%s':", path);
-        switch (GetLastError()) {
-        case ERROR_FILE_NOT_FOUND:
-            D( "file not found\n");
-            errno = ENOENT;
-            return -1;
-
-        case ERROR_PATH_NOT_FOUND:
-            D( "path not found\n");
-            errno = ENOTDIR;
-            return -1;
-
-        default:
-            D( "unknown error\n");
-            errno = ENOENT;
-            return -1;
-        }
+    if(check_file_err(_h->u.file_handle) == -1) {
+       return -1;
     }
-    snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
-    D( "sdb_creat: '%s' => fd %d\n", path, _fh_to_int(f));
-    return _fh_to_int(f);
+    return _h->fd;
 }
 
-static int _sdb_read(int fd, void* buf, size_t len) {
-    FH f = _fh_from_int(fd);
+static int _sdb_read(int fd, void* buffer, size_t r_length) {
+    SDB_HANDLE* _h = sdb_handle_map_get(fd);
 
-    if (f == NULL) {
-        return -1;
+    if (_h == NULL) {
+       LOG_ERROR("FD(%d) disconnected\n", fd);
+        return 0;
     }
 
-    return f->clazz->_fh_read(f, buf, len);
-}
-
-static int _sdb_write(int fd, const void* buf, size_t len) {
-    FH f = _fh_from_int(fd);
-
-    if (f == NULL) {
-        return -1;
+    if(IS_SOCKET_HANDLE(_h)) {
+       return check_socket_err(recv(_h->u.socket, buffer, r_length, 0));
     }
+    else {
+        DWORD r_bytes;
 
-    return f->clazz->_fh_write(f, buf, len);
+        if (!ReadFile(_h->u.file_handle, buffer, (DWORD) r_length, &r_bytes, NULL)) {
+            D( "sdb_read: could not read %d bytes from FD(%d)\n", r_length, _h->fd);
+            errno = EIO;
+            return -1;
+        }
+        return (int) r_bytes;
+    }
 }
 
-static int _sdb_lseek(int fd, int pos, int where) {
-    FH f = _fh_from_int(fd);
+static int _sdb_write(int fd, const void* buffer, size_t w_length) {
+    SDB_HANDLE* _h = sdb_handle_map_get(fd);
 
-    if (!f) {
-        return -1;
+    if (_h == NULL) {
+       LOG_ERROR("FD(%d) not exists. disconnected\n", fd);
+        return 0;
     }
 
-    return f->clazz->_fh_lseek(f, pos, where);
+    if(IS_SOCKET_HANDLE(_h)) {
+       return check_socket_err(send(_h->u.socket, buffer, w_length, 0));
+    }
+    else {
+        DWORD w_bytes;
+
+        if (!WriteFile(_h->u.file_handle, buffer, (DWORD) w_length, &w_bytes, NULL)) {
+            D( "sdb_file_write: could not write %d bytes from FD(%d)\n", w_length, _h->fd);
+            errno = EIO;
+            return -1;
+        }
+        return (int) w_bytes;
+    }
 }
 
 static int _sdb_shutdown(int fd) {
-    FH f = _fh_from_int(fd);
 
-    if (!f) {
+       if(!IS_SOCKET_FD(fd)) {
+               LOG_ERROR("FD(%d) is file fd\n", fd);
+               return -1;
+       }
+
+       SDB_HANDLE* _h = sdb_handle_map_get(fd);
+
+    if (_h == NULL) {
+       LOG_ERROR("FD(%d) not exists\n", fd);
         return -1;
     }
 
-    D( "sdb_shutdown: %s\n", f->name);
-    shutdown(f->fh_socket, SD_BOTH);
+    D( "sdb_shutdown: FD(%d)\n", fd);
+    shutdown(_h->u.socket, SD_BOTH);
     return 0;
 }
 
 static int _sdb_close(int fd) {
-    FH f = _fh_from_int(fd);
 
-    if (!f) {
+       SDB_HANDLE* _h = sdb_handle_map_get(fd);
+
+    if (_h == NULL) {
+       LOG_ERROR("FD(%d) not exists\n", fd);
         return -1;
     }
 
-    D( "sdb_close: %s\n", f->name);
-    _fh_close(f);
+    D( "sdb_close: FD(%d)\n", fd);
+    _fh_close(_h);
     return 0;
 }
 
-static int _sdb_unlink(const char* path) {
-    int rc = unlink(path);
-
-    if (rc == -1 && errno == EACCES) {
-        /* unlink returns EACCES when the file is read-only, so we first */
-        /* try to make it writable, then unlink again...                  */
-        rc = chmod(path, _S_IREAD | _S_IWRITE);
-        if (rc == 0)
-            rc = unlink(path);
-    }
-    return rc;
-}
-
 static int _sdb_mkdir(const char* path, int mode) {
     return _mkdir(path);
 }
@@ -555,146 +572,30 @@ static char* _sdb_dirstop(const char* path) {
     return p;
 }
 
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    socket-based file descriptors                               *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static void _socket_set_errno(void) {
-    switch (WSAGetLastError()) {
-    case 0:
-        errno = 0;
-        break;
-    case WSAEWOULDBLOCK:
-        errno = EAGAIN;
-        break;
-    case WSAEINTR:
-        errno = EINTR;
-        break;
-    default:
-        D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError());
-        errno = EINVAL;
-    }
-}
-
-static void _fh_socket_init(FH f) {
-    f->fh_socket = INVALID_SOCKET;
-    f->event = WSACreateEvent();
-    f->mask = 0;
-}
-
-static int _fh_socket_close(FH f) {
-    /* gently tell any peer that we're closing the socket */
-    shutdown(f->fh_socket, SD_BOTH);
-    closesocket(f->fh_socket);
-    f->fh_socket = INVALID_SOCKET;
-    CloseHandle(f->event);
-    f->mask = 0;
-    return 0;
-}
-
-static int _fh_socket_lseek(FH f, int pos, int origin) {
-    errno = EPIPE;
-    return -1;
-}
-
-static int _fh_socket_read(FH f, void* buf, int len) {
-    int result = recv(f->fh_socket, buf, len, 0);
-    if (result == SOCKET_ERROR) {
-        _socket_set_errno();
-        result = -1;
-    }
-    return result;
-}
-
-static int _fh_socket_write(FH f, const void* buf, int len) {
-    int result = send(f->fh_socket, buf, len, 0);
-    if (result == SOCKET_ERROR) {
-        _socket_set_errno();
-        result = -1;
-    }
-    return result;
-}
-
-static void _fh_socket_hook(FH f, int event, EventHook hook); /* forward */
-
-static const FHClassRec _fh_socket_class = { _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read,
-        _fh_socket_write, _fh_socket_hook };
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    replacement for libs/cutils/socket_xxxx.c                   *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-#include <winsock2.h>
-
 static int _winsock_init;
 
-static void _cleanup_winsock(void) {
+static void _cleanup_winsock() {
     WSACleanup();
 }
 
 static void _init_winsock(void) {
     if (!_winsock_init) {
         WSADATA wsaData;
-        int rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
-        if (rc != 0) {
-            fatal("sdb: could not initialize Winsock\n");
+        if(WSAStartup(MAKEWORD(2, 2), &wsaData)) {
+            LOG_FATAL("sdb: could not initialize Winsock\n");
         }
-        atexit(_cleanup_winsock);
         _winsock_init = 1;
+        atexit(_cleanup_winsock);
     }
 }
 
-static int _socket_loopback_client(int port, int type) {
-    FH f = _fh_alloc(&_fh_socket_class);
-    struct sockaddr_in addr;
-    SOCKET s;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-    s = socket(AF_INET, type, 0);
-    if (s == INVALID_SOCKET) {
-        D("socket_loopback_client: could not create socket\n");
-        _fh_close(f);
-        return -1;
-    }
-
-    f->fh_socket = s;
-    if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port);
-        _fh_close(f);
-        return -1;
-    }
-    snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
-    D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
-    return _fh_to_int(f);
-}
-
-#define LISTEN_BACKLOG 4
-
-static int _socket_loopback_server(int port, int type) {
-    FH f = _fh_alloc(&_fh_socket_class);
+static int _sdb_port_listen(uint32_t inet, int port, int type) {
+    SDB_HANDLE* _h = alloc_handle(1);
     struct sockaddr_in addr;
     SOCKET s;
     int n;
 
-    if (!f) {
+    if (_h == NULL) {
         return -1;
     }
 
@@ -703,51 +604,51 @@ static int _socket_loopback_server(int port, int type) {
 
     memset(&addr, 0, sizeof(addr));
     addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(inet);
     addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
-    s = socket(AF_INET, type, 0);
-    if (s == INVALID_SOCKET)
+    if ((s = socket(AF_INET, type, 0)) == INVALID_SOCKET) {
+        LOG_ERROR("failed to create socket to %u(%d)\n", inet, port);
         return -1;
+    }
 
-    f->fh_socket = s;
+    _h->u.socket = s;
 
     n = 1;
     setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n));
 
     if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+        _fh_close(_h);
         return -1;
     }
+    // only listen if tcp mode
     if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
+        if (listen(s, LISTEN_BACKLOG) < 0) {
+            _fh_close(_h);
             return -1;
         }
     }
-    snprintf(f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
-    D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
-    return _fh_to_int(f);
+
+    D( "sdb_port_listen: port %d type %s => FD(%d)\n", port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd);
+    return _h->fd;
 }
 
-static int _socket_network_client(const char *host, int port, int type) {
-    FH f = _fh_alloc(&_fh_socket_class);
+static int _sdb_host_connect(const char *host, int port, int type) {
+    SDB_HANDLE* _h = alloc_handle(1);
     struct hostent *hp;
     struct sockaddr_in addr;
     SOCKET s;
 
-    if (!f)
+    if (!_h)
         return -1;
 
     if (!_winsock_init)
         _init_winsock();
 
-    hp = gethostbyname(host);
-    if (hp == 0) {
-        _fh_close(f);
+    // FIXME: might take a long time to get information
+    if ((hp = gethostbyname(host)) == NULL) {
+        LOG_ERROR("failed to get hostname:%s(%d)\n", host, port);
+        _fh_close(_h);
         return -1;
     }
 
@@ -756,503 +657,167 @@ static int _socket_network_client(const char *host, int port, int type) {
     addr.sin_port = htons(port);
     memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
 
-    s = socket(hp->h_addrtype, type, 0);
-    if (s == INVALID_SOCKET) {
-        _fh_close(f);
+    if ((s = socket(hp->h_addrtype, type, 0)) == INVALID_SOCKET) {
+        LOG_ERROR("failed to create socket to %s(%d)\n", host, port);
+        _fh_close(_h);
         return -1;
     }
-    f->fh_socket = s;
+
+    _h->u.socket = s;
 
     if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+        _fh_close(_h);
         return -1;
     }
 
-    snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
-    D(
-            "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
-    return _fh_to_int(f);
+    D("sdb_host_connect: host '%s' port %d type %s => FD(%d)\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd);
+    return _h->fd;
 }
 
-static int _socket_inaddr_any_server(int port, int type) {
-    FH f = _fh_alloc(&_fh_socket_class);
-    struct sockaddr_in addr;
-    SOCKET s;
-    int n;
+static int _sdb_socket_accept(int serverfd) {
 
-    if (!f)
-        return -1;
+       if(!IS_SOCKET_FD(serverfd)) {
+               LOG_ERROR("FD(%d) is file fd\n", serverfd);
+               return -1;
+       }
 
-    if (!_winsock_init)
-        _init_winsock();
+    SDB_HANDLE* server_h = sdb_handle_map_get(serverfd);
+    struct sockaddr addr;
+    socklen_t alen = sizeof(addr);
 
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    s = socket(AF_INET, type, 0);
-    if (s == INVALID_SOCKET) {
-        _fh_close(f);
+    if (!server_h) {
+        LOG_ERROR( "FD(%d) Invalid server fd\n", serverfd);
         return -1;
     }
 
-    f->fh_socket = s;
-    n = 1;
-    setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n));
-
-    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
+    SDB_HANDLE* _h = alloc_handle(1);
+    if (!_h) {
         return -1;
     }
 
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-        if (ret < 0) {
-            _fh_close(f);
-            return -1;
-        }
-    }
-    snprintf(f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
-    D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
-    return _fh_to_int(f);
-}
-
-static int _sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) {
-    FH serverfh = _fh_from_int(serverfd);
-    FH fh;
-
-    if (!serverfh || serverfh->clazz != &_fh_socket_class) {
-        D( "sdb_socket_accept: invalid fd %d\n", serverfd);
-        return -1;
-    }
-
-    fh = _fh_alloc(&_fh_socket_class);
-    if (!fh) {
-        D( "sdb_socket_accept: not enough memory to allocate accepted socket descriptor\n");
-        return -1;
-    }
-
-    fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
-    if (fh->fh_socket == INVALID_SOCKET) {
-        _fh_close(fh);
-        D( "sdb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError());
+    _h->u.socket = accept(server_h->u.socket, &addr, &alen);
+    if (_h->u.socket == INVALID_SOCKET) {
+        _fh_close(_h);
+        LOG_ERROR( "sdb_socket_accept: accept on FD(%d) return error %ld\n", serverfd, GetLastError());
         return -1;
     }
 
-    snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name);
-    D( "sdb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh));
-    return _fh_to_int(fh);
+    LOG_INFO( "sdb_socket_accept on FD(%d) returns FD(%d)\n", serverfd, _h->fd);
+    return _h->fd;
 }
 
 static void _disable_tcp_nagle(int fd) {
-    FH fh = _fh_from_int(fd);
-    int on;
-
-    if (!fh || fh->clazz != &_fh_socket_class)
-        return;
-
-    setsockopt(fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on));
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    emulated socketpairs                                       *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-/* we implement socketpairs directly in use space for the following reasons:
- *   - it avoids copying data from/to the Nt kernel
- *   - it allows us to implement fdevent hooks easily and cheaply, something
- *     that is not possible with standard Win32 pipes !!
- *
- * basically, we use two circular buffers, each one corresponding to a given
- * direction.
- *
- * each buffer is implemented as two regions:
- *
- *   region A which is (a_start,a_end)
- *   region B which is (0, b_end)  with b_end <= a_start
- *
- * an empty buffer has:  a_start = a_end = b_end = 0
- *
- * a_start is the pointer where we start reading data
- * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
- * then you start writing at b_end
- *
- * the buffer is full when  b_end == a_start && a_end == BUFFER_SIZE
- *
- * there is room when b_end < a_start || a_end < BUFER_SIZE
- *
- * when reading, a_start is incremented, it a_start meets a_end, then
- * we do:  a_start = 0, a_end = b_end, b_end = 0, and keep going on..
- */
-
-#define  BIP_BUFFER_SIZE   4096
-
-#if 0
-#include <stdio.h>
-#  define  BIPD(x)      D x
-#  define  BIPDUMP   bip_dump_hex
 
-static void bip_dump_hex( const unsigned char* ptr, size_t len )
-{
-    int nn, len2 = len;
-
-    if (len2 > 8) len2 = 8;
-
-    for (nn = 0; nn < len2; nn++)
-    printf("%02x", ptr[nn]);
-    printf("  ");
-
-    for (nn = 0; nn < len2; nn++) {
-        int c = ptr[nn];
-        if (c < 32 || c > 127)
-        c = '.';
-        printf("%c", c);
-    }
-    printf("\n");
-    fflush(stdout);
-}
+       if(!IS_SOCKET_FD(fd)) {
+               LOG_ERROR("FD(%d) is file fd\n", fd);
+               return;
+       }
 
-#else
-#  define  BIPD(x)        do {} while (0)
-#  define  BIPDUMP(p,l)   BIPD(p)
-#endif
-
-
-static void bip_buffer_init(BipBuffer buffer) {
-    D( "bit_buffer_init %p\n", buffer);
-    buffer->a_start = 0;
-    buffer->a_end = 0;
-    buffer->b_end = 0;
-    buffer->can_write = 1;
-    buffer->can_read = 0;
-    buffer->fdin = 0;
-    buffer->fdout = 0;
-    buffer->closed = 0;
-    buffer->evt_write = CreateEvent(NULL, TRUE, TRUE, NULL);
-    buffer->evt_read = CreateEvent(NULL, TRUE, FALSE, NULL);
-    InitializeCriticalSection(&buffer->lock);
-}
-
-static void bip_buffer_close(BipBuffer bip) {
-    bip->closed = 1;
-
-    if (!bip->can_read) {
-        SetEvent(bip->evt_read);
-    }
-    if (!bip->can_write) {
-        SetEvent(bip->evt_write);
+    SDB_HANDLE* _h = sdb_handle_map_get(fd);
+    if (!_h) {
+        return;
     }
-}
 
-static void bip_buffer_done(BipBuffer bip) {
-    BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
-    CloseHandle(bip->evt_read);
-    CloseHandle(bip->evt_write);
-    DeleteCriticalSection(&bip->lock);
+    int on;
+    setsockopt(_h->u.socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on));
 }
 
-static int bip_buffer_write(BipBuffer bip, const void* src, int len) {
-    int avail, count = 0;
-
-    if (len <= 0)
-        return 0;
-
-    BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-    BIPDUMP( src, len);
-
-    EnterCriticalSection(&bip->lock);
-
-    while (!bip->can_write) {
-        int ret;
-        LeaveCriticalSection(&bip->lock);
-
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-        /* spinlocking here is probably unfair, but let's live with it */
-        ret = WaitForSingleObject(bip->evt_write, INFINITE);
-        if (ret != WAIT_OBJECT_0) { /* buffer probably closed */
-            D(
-                    "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
-            return 0;
-        }
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-        EnterCriticalSection(&bip->lock);
-    }
-
-    BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
-    avail = BIP_BUFFER_SIZE - bip->a_end;
-    if (avail > 0) {
-        /* we can append to region A */
-        if (avail > len)
-            avail = len;
+static int socketpair_impl(int af, int type, int protocol, SOCKET socks[2])
+{
+    struct sockaddr_in addr;
+    SOCKET s;
 
-        memcpy(bip->buff + bip->a_end, src, avail);
-        src += avail;
-        count += avail;
-        len -= avail;
+    LOG_INFO("+socketpair impl in\n");
 
-        bip->a_end += avail;
-        if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
-            bip->can_write = 0;
-            ResetEvent(bip->evt_write);
-            goto Exit;
-        }
+    if (!_winsock_init) {
+        _init_winsock();
     }
+    // Create a socket, bind it to 127.0.0.1 and a random port, and listen.
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(0x7f000001);
+    addr.sin_port = 0;
 
-    if (len == 0)
-        goto Exit;
-
-    avail = bip->a_start - bip->b_end;
-    assert( avail > 0);
-    /* since can_write is TRUE */
-
-    if (avail > len)
-        avail = len;
-
-    memcpy(bip->buff + bip->b_end, src, avail);
-    count += avail;
-    bip->b_end += avail;
+    socks[0] = socks[1] = INVALID_SOCKET;
 
-    if (bip->b_end == bip->a_start) {
-        bip->can_write = 0;
-        ResetEvent(bip->evt_write);
+    if ((s = socket(af, type, 0)) == INVALID_SOCKET) {
+        return -1;
     }
 
-    Exit:
-    assert( count > 0);
-
-    if (!bip->can_read) {
-        bip->can_read = 1;
-        SetEvent(bip->evt_read);
+    if (bind(s, (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) {
+        closesocket(s);
+        return -1;
     }
 
-    BIPD(
-            ( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
-    LeaveCriticalSection(&bip->lock);
-
-    return count;
-}
-
-static int bip_buffer_read(BipBuffer bip, void* dst, int len) {
-    int avail, count = 0;
-
-    if (len <= 0)
-        return 0;
-
-    BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
-    EnterCriticalSection(&bip->lock);
-    while (!bip->can_read) {
-#if 0
-        LeaveCriticalSection( &bip->lock );
-        errno = EAGAIN;
+    int addr_len = sizeof(addr);
+    if (getsockname(s, (struct sockaddr*) &addr, &addr_len) == SOCKET_ERROR) {
+        closesocket(s);
         return -1;
-#else
-        int ret;
-        LeaveCriticalSection(&bip->lock);
+    }
 
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
+    do
+    {
+        if (listen(s, 1) == SOCKET_ERROR) {
+            break;
         }
-
-        ret = WaitForSingleObject(bip->evt_read, INFINITE);
-        if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
-            D(
-                    "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
-            return 0;
+        // Creates the second socket and connects it to the same address and port.
+        if ((socks[0] = socket(af, type, 0)) == INVALID_SOCKET) {
+            break;
         }
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
+        if (connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) {
+            break;
         }
-        EnterCriticalSection(&bip->lock);
-#endif
-    }
-
-    BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
-    avail = bip->a_end - bip->a_start;
-    assert( avail > 0);
-    /* since can_read is TRUE */
-
-    if (avail > len)
-        avail = len;
-
-    memcpy(dst, bip->buff + bip->a_start, avail);
-    dst += avail;
-    count += avail;
-    len -= avail;
-
-    bip->a_start += avail;
-    if (bip->a_start < bip->a_end)
-        goto Exit;
-
-    bip->a_start = 0;
-    bip->a_end = bip->b_end;
-    bip->b_end = 0;
-
-    avail = bip->a_end;
-    if (avail > 0) {
-        if (avail > len)
-            avail = len;
-        memcpy(dst, bip->buff, avail);
-        count += avail;
-        bip->a_start += avail;
-
-        if (bip->a_start < bip->a_end)
-            goto Exit;
-
-        bip->a_start = bip->a_end = 0;
-    }
-
-    bip->can_read = 0;
-    ResetEvent(bip->evt_read);
-
-    Exit:
-    assert( count > 0);
-
-    if (!bip->can_write) {
-        bip->can_write = 1;
-        SetEvent(bip->evt_write);
-    }
-
-    BIPDUMP( (const unsigned char*)dst - count, count);
-    BIPD(
-            ( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
-    LeaveCriticalSection(&bip->lock);
-
-    return count;
-}
-
-typedef struct SocketPairRec_ {
-    BipBufferRec a2b_bip;
-    BipBufferRec b2a_bip;
-    FH a_fd;
-    int used;
-
-} SocketPairRec;
-
-void _fh_socketpair_init(FH f) {
-    f->fh_pair = NULL;
-}
-
-static int _fh_socketpair_close(FH f) {
-    if (f->fh_pair) {
-        SocketPair pair = f->fh_pair;
-
-        if (f == pair->a_fd) {
-            pair->a_fd = NULL;
+        if ((socks[1] = accept(s, NULL, NULL)) == INVALID_SOCKET) {
+            break;
         }
+        closesocket(s);
+        LOG_INFO("-socketpair impl out\n");
+        return 0;
 
-        bip_buffer_close(&pair->b2a_bip);
-        bip_buffer_close(&pair->a2b_bip);
+    } while (0);
 
-        if (--pair->used == 0) {
-            bip_buffer_done(&pair->b2a_bip);
-            bip_buffer_done(&pair->a2b_bip);
-            free(pair);
-        }
-        f->fh_pair = NULL;
-    }
-    return 0;
-}
+    closesocket(socks[0]);
+    closesocket(socks[1]);
+    closesocket(s);
 
-static int _fh_socketpair_lseek(FH f, int pos, int origin) {
-    errno = ESPIPE;
+    LOG_ERROR("socketpair error: %ld\n", WSAGetLastError());
     return -1;
 }
 
-static int _fh_socketpair_read(FH f, void* buf, int len) {
-    SocketPair pair = f->fh_pair;
-    BipBuffer bip;
+static int _sdb_socketpair(int sv[2]) {
+    SOCKET socks[2];
+    int r = 0;
 
-    if (!pair)
+    r = socketpair_impl( AF_INET, SOCK_STREAM, IPPROTO_TCP, socks);
+    if (r < 0) {
+        LOG_ERROR("failed to create socket pair:(%ld)\n", GetLastError());
         return -1;
+    }
 
-    if (f == pair->a_fd)
-        bip = &pair->b2a_bip;
-    else
-        bip = &pair->a2b_bip;
-
-    return bip_buffer_read(bip, buf, len);
-}
-
-static int _fh_socketpair_write(FH f, const void* buf, int len) {
-    SocketPair pair = f->fh_pair;
-    BipBuffer bip;
+    SDB_HANDLE* _ha = alloc_handle(1);
+    SDB_HANDLE* _hb = alloc_handle(1);
 
-    if (!pair)
+    if (!_ha || !_hb) {
         return -1;
-
-    if (f == pair->a_fd)
-        bip = &pair->a2b_bip;
-    else
-        bip = &pair->b2a_bip;
-
-    return bip_buffer_write(bip, buf, len);
-}
-
-static void _fh_socketpair_hook(FH f, int event, EventHook hook); /* forward */
-
-static const FHClassRec _fh_socketpair_class = { _fh_socketpair_init, _fh_socketpair_close, _fh_socketpair_lseek,
-        _fh_socketpair_read, _fh_socketpair_write, _fh_socketpair_hook };
-
-static int _sdb_socketpair(int sv[2]) {
-    FH fa, fb;
-    SocketPair pair;
-
-    fa = _fh_alloc(&_fh_socketpair_class);
-    fb = _fh_alloc(&_fh_socketpair_class);
-
-    if (!fa || !fb)
-        goto Fail;
-
-    pair = malloc(sizeof(*pair));
-    if (pair == NULL) {
-        D("sdb_socketpair: not enough memory to allocate pipes\n");
-        goto Fail;
     }
 
-    bip_buffer_init(&pair->a2b_bip);
-    bip_buffer_init(&pair->b2a_bip);
+    _ha->u.socket = socks[0];
+    _hb->u.socket = socks[1];
 
-    fa->fh_pair = pair;
-    fb->fh_pair = pair;
-    pair->used = 2;
-    pair->a_fd = fa;
-
-    sv[0] = _fh_to_int(fa);
-    sv[1] = _fh_to_int(fb);
-
-    pair->a2b_bip.fdin = sv[0];
-    pair->a2b_bip.fdout = sv[1];
-    pair->b2a_bip.fdin = sv[1];
-    pair->b2a_bip.fdout = sv[0];
+    if (_ha->u.socket == INVALID_SOCKET || _hb->u.socket == INVALID_SOCKET) {
+        _fh_close(_ha);
+        _fh_close(_hb);
+        LOG_ERROR( "failed to get socket:(%ld)\n", GetLastError());
+        return -1;
+    }
+    sv[0] = _ha->fd;
+    sv[1] = _hb->fd;
 
-    snprintf(fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1]);
-    snprintf(fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0]);
-    D( "sdb_socketpair: returns (%d, %d)\n", sv[0], sv[1]);
+    D( "sdb_socketpair: returns (FD(%d), FD(%d))\n", sv[0], sv[1] );
     return 0;
-
-    Fail: _fh_close(fb);
-    _fh_close(fa);
-    return -1;
 }
 
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -1264,199 +829,18 @@ static int _sdb_socketpair(int sv[2]) {
 /**************************************************************************/
 /**************************************************************************/
 
-
-/**  FILE EVENT HOOKS
- **/
-
-static void _event_file_prepare(EventHook hook) {
-    if (hook->wanted & (FDE_READ | FDE_WRITE)) {
-        /* we can always read/write */
-        hook->ready |= hook->wanted & (FDE_READ | FDE_WRITE);
-    }
-}
-
-static int _event_file_peek(EventHook hook) {
-    return (hook->wanted & (FDE_READ | FDE_WRITE));
-}
-
-static void _fh_file_hook(FH f, int events, EventHook hook) {
-    hook->h = f->fh_handle;
-    hook->prepare = _event_file_prepare;
-    hook->peek = _event_file_peek;
-}
-
-/** SOCKET EVENT HOOKS
- **/
-
-static void _event_socket_verify(EventHook hook, WSANETWORKEVENTS* evts) {
-    if (evts->lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) {
-        if (hook->wanted & FDE_READ)
-            hook->ready |= FDE_READ;
-        if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
-            hook->ready |= FDE_ERROR;
-    }
-    if (evts->lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE)) {
-        if (hook->wanted & FDE_WRITE)
-            hook->ready |= FDE_WRITE;
-        if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
-            hook->ready |= FDE_ERROR;
-    }
-    if (evts->lNetworkEvents & FD_OOB) {
-        if (hook->wanted & FDE_ERROR)
-            hook->ready |= FDE_ERROR;
-    }
-}
-
-static void _event_socket_prepare(EventHook hook) {
-    WSANETWORKEVENTS evts;
-
-    /* look if some of the events we want already happened ? */
-    if (!WSAEnumNetworkEvents(hook->fh->fh_socket, NULL, &evts))
-        _event_socket_verify(hook, &evts);
-}
-
-static int _socket_wanted_to_flags(int wanted) {
-    int flags = 0;
-    if (wanted & FDE_READ)
-        flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
-
-    if (wanted & FDE_WRITE)
-        flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
-
-    if (wanted & FDE_ERROR)
-        flags |= FD_OOB;
-
-    return flags;
-}
-
-static int _event_socket_start(EventHook hook) {
-    /* create an event which we're going to wait for */
-    FH fh = hook->fh;
-    long flags = _socket_wanted_to_flags(hook->wanted);
-
-    hook->h = fh->event;
-    if (hook->h == INVALID_HANDLE_VALUE) {
-        D( "_event_socket_start: no event for %s\n", fh->name);
-        return 0;
-    }
-
-    if (flags != fh->mask) {
-        D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags);
-        if (WSAEventSelect(fh->fh_socket, hook->h, flags)) {
-            D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError());
-            CloseHandle(hook->h);
-            hook->h = INVALID_HANDLE_VALUE;
-            exit(1);
-            return 0;
-        }
-        fh->mask = flags;
-    }
-    return 1;
-}
-
-static void _event_socket_stop(EventHook hook) {
-    hook->h = INVALID_HANDLE_VALUE;
-}
-
-static int _event_socket_check(EventHook hook) {
-    int result = 0;
-    FH fh = hook->fh;
-    WSANETWORKEVENTS evts;
-
-    if (!WSAEnumNetworkEvents(fh->fh_socket, hook->h, &evts)) {
-        _event_socket_verify(hook, &evts);
-        result = (hook->ready != 0);
-        if (result) {
-            ResetEvent(hook->h);
-        }
-    }
-    D( "_event_socket_check %s returns %d\n", fh->name, result);
-    return result;
-}
-
-static int _event_socket_peek(EventHook hook) {
-    WSANETWORKEVENTS evts;
-    FH fh = hook->fh;
-
-    /* look if some of the events we want already happened ? */
-    if (!WSAEnumNetworkEvents(fh->fh_socket, NULL, &evts)) {
-        _event_socket_verify(hook, &evts);
-        if (hook->ready)
-            ResetEvent(hook->h);
-    }
-
-    return hook->ready != 0;
-}
-
-static void _fh_socket_hook(FH f, int events, EventHook hook) {
-    hook->prepare = _event_socket_prepare;
-    hook->start = _event_socket_start;
-    hook->stop = _event_socket_stop;
-    hook->check = _event_socket_check;
-    hook->peek = _event_socket_peek;
-
-    _event_socket_start(hook);
-}
-
-/** SOCKETPAIR EVENT HOOKS
- **/
-
-static void _event_socketpair_prepare(EventHook hook) {
-    FH fh = hook->fh;
-    SocketPair pair = fh->fh_pair;
-    BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
-    BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
-    if (hook->wanted & FDE_READ && rbip->can_read)
-        hook->ready |= FDE_READ;
-
-    if (hook->wanted & FDE_WRITE && wbip->can_write)
-        hook->ready |= FDE_WRITE;
-}
-
-static int _event_socketpair_start(EventHook hook) {
-    FH fh = hook->fh;
-    SocketPair pair = fh->fh_pair;
-    BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
-    BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
-    if (hook->wanted == FDE_READ)
-        hook->h = rbip->evt_read;
-
-    else if (hook->wanted == FDE_WRITE)
-        hook->h = wbip->evt_write;
-
-    else {
-        D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n");
-        return 0;
-    }
-    D( "_event_socketpair_start: hook %s for %x wanted=%x\n", hook->fh->name, _fh_to_int(fh), hook->wanted);
-    return 1;
-}
-
-static int _event_socketpair_peek(EventHook hook) {
-    _event_socketpair_prepare(hook);
-    return hook->ready != 0;
-}
-
-static void _fh_socketpair_hook(FH fh, int events, EventHook hook) {
-    hook->prepare = _event_socketpair_prepare;
-    hook->start = _event_socketpair_start;
-    hook->peek = _event_socketpair_peek;
-}
-
 static void _sdb_sysdeps_init(void) {
     //re define mutex variable & initialized
 #undef SDB_MUTEX
 #define  SDB_MUTEX(x)  InitializeCriticalSection( & x );
     SDB_MUTEX(dns_lock)
-    SDB_MUTEX(socket_list_lock)
     SDB_MUTEX(transport_lock)
-    SDB_MUTEX(local_transports_lock)
     SDB_MUTEX(usb_lock)
     SDB_MUTEX(wakeup_select_lock)
     SDB_MUTEX(D_lock)
     SDB_MUTEX(_win32_lock);
+    SDB_MUTEX(sdb_handle_map_lock);
+    SDB_MUTEX(free_socket_handle_list_lock);
 }
 
 typedef  void (*win_thread_func_t)(void*  arg);
@@ -1610,16 +994,12 @@ const struct utils_os_backend utils_windows_backend = {
     .start_logging = _start_logging,
     .ansi_to_utf8 = _ansi_to_utf8,
     .sdb_open = _sdb_open,
-    .sdb_open_mode = _sdb_open_mode,
-    .unix_open = _unix_open,
     .sdb_creat = _sdb_creat,
     .sdb_read = _sdb_read,
     .sdb_write = _sdb_write,
-    .sdb_lseek = _sdb_lseek,
     .sdb_shutdown = _sdb_shutdown,
     .sdb_close = _sdb_close,
     .close_on_exec = _close_on_exec,
-    .sdb_unlink = _sdb_unlink,
     .sdb_mkdir = _sdb_mkdir,
     .sdb_socket_accept = _sdb_socket_accept,
     .sdb_socketpair = _sdb_socketpair,
@@ -1636,8 +1016,6 @@ const struct utils_os_backend utils_windows_backend = {
     .sdb_cond_init = _pthread_cond_init,
     .sdb_cond_broadcast = _pthread_cond_broadcast,
     .sdb_sysdeps_init = _sdb_sysdeps_init,
-    .socket_loopback_client = _socket_loopback_client,
-    .socket_network_client = _socket_network_client,
-    .socket_loopback_server = _socket_loopback_server,
-    .socket_inaddr_any_server = _socket_inaddr_any_server
+    .sdb_host_connect = _sdb_host_connect,
+    .sdb_port_listen = _sdb_port_listen
 };