Upload tizen_2.2 source
authorkh5325.kim <kh5325.kim@samsung.com>
Tue, 18 Jun 2013 01:27:25 +0000 (10:27 +0900)
committerkh5325.kim <kh5325.kim@samsung.com>
Tue, 18 Jun 2013 01:27:25 +0000 (10:27 +0900)
Change-Id: I5f479b03ba18b94fa97910427b1407b59bf40be2

153 files changed:
Makefile
Makefile.win [new file with mode: 0644]
SdbWinApi.bat [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/sdbd.install [new file with mode: 0644]
package/changelog
package/pkginfo.manifest
script/S06sdbd [new file with mode: 0755]
script/sdbd [new file with mode: 0755]
src/Android.mk [new file with mode: 0644]
src/MODULE_LICENSE_APACHE2 [new file with mode: 0644]
src/NOTICE [new file with mode: 0644]
src/OVERVIEW.TXT [new file with mode: 0644]
src/SERVICES.TXT [new file with mode: 0644]
src/TizenConfig.h [new file with mode: 0644]
src/android_reboot.c [new file with mode: 0644]
src/android_reboot.h [new file with mode: 0644]
src/clear_vars.mk [new file with mode: 0644]
src/command_function.c [deleted file]
src/command_function.h [deleted file]
src/commandline.c
src/commandline.h [deleted file]
src/console.c [new file with mode: 0644]
src/fdevent.c
src/fdevent.h
src/fdevent_backend.h [deleted file]
src/fdevent_unix.c [deleted file]
src/fdevent_windows.c [deleted file]
src/file_sync_client.c [changed mode: 0644->0755]
src/file_sync_client.h [deleted file]
src/file_sync_functions.c [deleted file]
src/file_sync_functions.h [deleted file]
src/file_sync_service.c [new file with mode: 0644]
src/file_sync_service.h
src/framebuffer_service.c [new file with mode: 0644]
src/get_my_path_darwin.c [new file with mode: 0644]
src/get_my_path_freebsd.c [new file with mode: 0644]
src/get_my_path_linux.c [new file with mode: 0644]
src/get_my_path_windows.c [new file with mode: 0644]
src/jdwp_service.c [new file with mode: 0644]
src/libusb/darwin.c [deleted file]
src/libusb/descriptors.c [deleted file]
src/libusb/error.c [deleted file]
src/libusb/error.h [deleted file]
src/libusb/linux.c [deleted file]
src/libusb/linux.h [deleted file]
src/libusb/usb.c [deleted file]
src/libusb/usb.h [deleted file]
src/libusb/usbi.h [deleted file]
src/libusb/windows.c [deleted file]
src/libusb/winusb.h [deleted file]
src/linkedlist.c [deleted file]
src/linkedlist.h [deleted file]
src/mutex_list.h [new file with mode: 0644]
src/properties.c [new file with mode: 0644]
src/properties.h [new file with mode: 0644]
src/protocol.txt [new file with mode: 0644]
src/pthread_win32.h [deleted file]
src/qemu_pipe.h [new file with mode: 0644]
src/remount_service.c [new file with mode: 0644]
src/sdb.c
src/sdb.h
src/sdb_client.c
src/sdb_client.h
src/sdb_constants.c [deleted file]
src/sdb_constants.h [deleted file]
src/sdb_model.c [deleted file]
src/sdb_model.h [deleted file]
src/sdb_usb.c [deleted file]
src/sdb_usb.h [deleted file]
src/sdbwinapi/BUILDME.TXT [new file with mode: 0644]
src/sdbwinapi/MAKEFILE [new file with mode: 0644]
src/sdbwinapi/MAKEFILE.org [new file with mode: 0644]
src/sdbwinapi/Resource.h [new file with mode: 0644]
src/sdbwinapi/SOURCES [new file with mode: 0644]
src/sdbwinapi/SdbWinApi.cpp [new file with mode: 0644]
src/sdbwinapi/SdbWinApi.def [new file with mode: 0644]
src/sdbwinapi/SdbWinApi.rc [new file with mode: 0644]
src/sdbwinapi/sdb_api.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_api.h [new file with mode: 0644]
src/sdbwinapi/sdb_api_instance.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_api_instance.h [new file with mode: 0644]
src/sdbwinapi/sdb_api_legacy.h [new file with mode: 0644]
src/sdbwinapi/sdb_api_private_defines.h [new file with mode: 0644]
src/sdbwinapi/sdb_endpoint_object.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_endpoint_object.h [new file with mode: 0644]
src/sdbwinapi/sdb_helper_routines.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_helper_routines.h [new file with mode: 0644]
src/sdbwinapi/sdb_interface.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_interface.h [new file with mode: 0644]
src/sdbwinapi/sdb_interface_enum.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_interface_enum.h [new file with mode: 0644]
src/sdbwinapi/sdb_io_completion.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_io_completion.h [new file with mode: 0644]
src/sdbwinapi/sdb_legacy_endpoint_object.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_legacy_endpoint_object.h [new file with mode: 0644]
src/sdbwinapi/sdb_legacy_interface.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_legacy_interface.h [new file with mode: 0644]
src/sdbwinapi/sdb_legacy_io_completion.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_legacy_io_completion.h [new file with mode: 0644]
src/sdbwinapi/sdb_object_handle.cpp [new file with mode: 0644]
src/sdbwinapi/sdb_object_handle.h [new file with mode: 0644]
src/sdbwinapi/sdb_winusb_api.h [new file with mode: 0644]
src/sdbwinapi/stdafx.cpp [new file with mode: 0644]
src/sdbwinapi/stdafx.h [new file with mode: 0644]
src/sdbwinusbapi/BUILDME.TXT [new file with mode: 0644]
src/sdbwinusbapi/MAKEFILE [new file with mode: 0644]
src/sdbwinusbapi/Resource.h [new file with mode: 0644]
src/sdbwinusbapi/SOURCES [new file with mode: 0644]
src/sdbwinusbapi/SdbWinUsbApi.cpp [new file with mode: 0644]
src/sdbwinusbapi/SdbWinUsbApi.def [new file with mode: 0644]
src/sdbwinusbapi/SdbWinUsbApi.rc [new file with mode: 0644]
src/sdbwinusbapi/sdb_winusb_endpoint_object.cpp [new file with mode: 0644]
src/sdbwinusbapi/sdb_winusb_endpoint_object.h [new file with mode: 0644]
src/sdbwinusbapi/sdb_winusb_interface.cpp [new file with mode: 0644]
src/sdbwinusbapi/sdb_winusb_interface.h [new file with mode: 0644]
src/sdbwinusbapi/sdb_winusb_io_completion.cpp [new file with mode: 0644]
src/sdbwinusbapi/sdb_winusb_io_completion.h [new file with mode: 0644]
src/sdbwinusbapi/stdafx.cpp [new file with mode: 0644]
src/sdbwinusbapi/stdafx.h [new file with mode: 0644]
src/services.c
src/socket_inaddr_any_server.c [new file with mode: 0644]
src/socket_local.h [new file with mode: 0644]
src/socket_local_client.c [new file with mode: 0644]
src/socket_local_server.c [new file with mode: 0644]
src/socket_loopback_client.c [new file with mode: 0644]
src/socket_loopback_server.c [new file with mode: 0644]
src/socket_network_client.c [new file with mode: 0644]
src/sockets.c
src/sockets.dia [new file with mode: 0644]
src/sockets.h [new file with mode: 0644]
src/strutils.c
src/sysdeps.h [new file with mode: 0644]
src/sysdeps_win32.c [new file with mode: 0644]
src/threads.h [new file with mode: 0644]
src/transport.c
src/transport_local.c
src/transport_usb.c
src/usb_libusb.c [new file with mode: 0644]
src/usb_linux.c [new file with mode: 0755]
src/usb_linux_client.c [new file with mode: 0644]
src/usb_osx.c [new file with mode: 0644]
src/usb_vendors.c [new file with mode: 0644]
src/usb_vendors.h [new file with mode: 0644]
src/usb_windows.c [new file with mode: 0644]
src/utils.c
src/utils.h
src/utils_backend.h [deleted file]
src/utils_unix.c [deleted file]
src/utils_windows.c [deleted file]

index 5cc84f3903fcba5bea4c008d77f4a50a9568dd92..2127c92b7c9a634a79378f5530990f2a1689dc9d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,47 +4,39 @@
 #
 
 #
-HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1)
+HOST_OS := $(shell uname -s | tr A-Z a-z)
 
 # sdb host tool
 # =========================================================
 
-ifeq ($(HOST_OS),darwin)
-       CC := /Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/bin/llvm-gcc-4.2
-else
-       CC := gcc
-endif
+# Default to a virtual (sockets) usb interface
+USB_SRCS :=
+EXTRA_SRCS :=
 
-#
 ifeq ($(HOST_OS),linux)
-       LOCAL_USB_SRC :=  src/libusb/linux.c src/sdb_usb.c src/libusb/error.c src/libusb/usb.c src/libusb/descriptors.c
-       LOCAL_UTIL_SRC := src/utils_unix.c
-       LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c
-       LOCAL_LFLAGS := -lrt -lncurses -lpthread
-       LOCAL_CFLAGS := -DOS_LINUX -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1
+       USB_SRCS := usb_linux.c
+       EXTRA_SRCS := get_my_path_linux.c
+       LOCAL_LDLIBS += -lrt -lncurses -lpthread
 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_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
+       USB_SRCS := usb_osx.c
+       EXTRA_SRCS := get_my_path_darwin.c
+       LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+       SDB_EXTRA_CFLAGS := -mmacosx-version-min=10.4
 endif
 
-ifeq ($(HOST_OS),mingw32)
-       LOCAL_USB_SRC := src/libusb/windows.c
-       LOCAL_UTIL_SRC := src/utils_windows.c
-       LOCAL_OTHER_SRC := src/fdevent.c  src/fdevent_windows.c
-       LOCAL_CFLAGS := -DOS_WINDOWS
-       LOCAL_IFLAGS := -I/mingw/include/ddk
-       LOCAL_LFLAGS := -lws2_32
-       LOCAL_STATIC_LFLAGS := /mingw/lib/libsetupapi.a
+ifeq ($(HOST_OS),freebsd)
+       USB_SRCS := usb_libusb.c
+       EXTRA_SRCS := get_my_path_freebsd.c
+       LOCAL_LDLIBS += -lpthread -lusb
 endif
 
 
+
 SDB_SRC_FILES := \
        src/sdb.c \
+       src/console.c \
        src/transport.c \
        src/transport_local.c \
        src/transport_usb.c \
@@ -53,34 +45,97 @@ SDB_SRC_FILES := \
        src/sockets.c \
        src/services.c \
        src/file_sync_client.c \
-       $(LOCAL_USB_SRC) \
-       $(LOCAL_UTIL_SRC) \
-       $(LOCAL_OTHER_SRC) \
+       src/$(EXTRA_SRCS) \
+       src/$(USB_SRCS) \
        src/utils.c \
-       src/strutils.c \
-       src/linkedlist.c \
-       src/sdb_model.c \
-       src/sdb_constants.c \
-       src/file_sync_functions.c \
-       src/command_function.c
-
-SDB_CFLAGS := -O2 -g -Wall -Wno-unused-parameter
+       src/usb_vendors.c \
+       src/fdevent.c \
+       src/socket_inaddr_any_server.c \
+       src/socket_local_client.c \
+       src/socket_local_server.c \
+       src/socket_loopback_client.c \
+       src/socket_loopback_server.c \
+       src/socket_network_client.c \
+       src/strutils.c
+
+SDB_CFLAGS := -O2 -g -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1 -Wall -Wno-unused-parameter
 SDB_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
-SDB_CFLAGS += -Iinclude -Isrc
-SDB_CFLAGS += $(LOCAL_CFLAGS)
-SDB_LFLAGS := $(LOCAL_LFLAGS)
-STATIC_LFLAGS := $(LOCAL_STATIC_LFLAGS)
+SDB_CFLAGS += -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS
+SDB_LFLAGS := $(LOCAL_LDLIBS)
+
+SDBD_SRC_FILES := \
+       src/sdb.c \
+       src/fdevent.c \
+       src/transport.c \
+       src/transport_local.c \
+       src/transport_usb.c \
+       src/sockets.c \
+       src/services.c \
+       src/file_sync_service.c \
+       src/framebuffer_service.c \
+       src/remount_service.c \
+       src/usb_linux_client.c \
+       src/utils.c \
+       src/socket_inaddr_any_server.c \
+       src/socket_local_client.c \
+       src/socket_local_server.c \
+       src/socket_loopback_client.c \
+       src/socket_loopback_server.c \
+       src/socket_network_client.c \
+       src/properties.c \
+       src/android_reboot.c \
+       src/strutils.c
 
+SDBD_CFLAGS := -O2 -g -DSDB_HOST=0 -Wall -Wno-unused-parameter
+SDBD_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+SDBD_CFLAGS += -DHAVE_FORKEXEC -fPIE
+
+IFLAGS := -Iinclude -Isrc
 OBJDIR := bin
+INSTALLDIR := usr/sbin
+INITSCRIPTDIR := etc/init.d
+RCSCRIPTDIR := etc/rc.d/rc3.d
+
+UNAME := $(shell uname -sm)
+ifneq (,$(findstring 86,$(UNAME)))
+       HOST_ARCH := x86
+endif
 
-MODULE := sdb
+TARGET_ARCH = $(HOST_ARCH)
+ifeq ($(TARGET_ARCH),)
+       TARGET_ARCH := arm
+endif
+
+ifeq ($(TARGET_ARCH),arm)
+       MODULE := sdbd
+       SDBD_CFLAGS += -DANDROID_GADGET=1
+else
+ifeq ($(TARGET_HOST),true)
+       MODULE := sdb
+else
+       MODULE := sdbd
+endif
+endif
 
 all : $(MODULE)
 
 sdb : $(SDB_SRC_FILES)
-       rm -rf $(OBJDIR)
        mkdir -p $(OBJDIR)
-       $(CC) $(SDB_CFLAGS) -o $(OBJDIR)/$(MODULE) $(SDB_SRC_FILES) $(LOCAL_IFLAGS) $(SDB_LFLAGS) $(STATIC_LFLAGS)
+       $(CC) -pthread -o $(OBJDIR)/$(MODULE) $(SDB_CFLAGS) $(SDB_EXTRA_CFLAGS) $(SDB_LFLAGS) $(IFLAGS) $(SDB_SRC_FILES)
+
+sdbd : $(SDBD_SRC_FILES)
+       mkdir -p $(OBJDIR)
+       $(CC) -pthread -o $(OBJDIR)/$(MODULE) $(SDBD_CFLAGS) $(IFLAGS) $(SDBD_SRC_FILES)
+
+install :
+       mkdir -p $(DESTDIR)/$(INSTALLDIR)
+       install $(OBJDIR)/$(MODULE) $(DESTDIR)/$(INSTALLDIR)/$(MODULE)
+ifeq ($(MODULE),sdbd)
+       mkdir -p $(DESTDIR)/$(INITSCRIPTDIR)
+       install script/sdbd $(DESTDIR)/$(INITSCRIPTDIR)/sdbd
+endif
+       mkdir -p $(DESTDIR)/$(RCSCRIPTDIR)
+       install script/S06sdbd $(DESTDIR)/$(RCSCRIPTDIR)/S06sdbd
 
 clean :
        rm -rf $(OBJDIR)/*
diff --git a/Makefile.win b/Makefile.win
new file mode 100644 (file)
index 0000000..d9c8974
--- /dev/null
@@ -0,0 +1,50 @@
+CC := gcc
+SRC_FILES := \
+       src/sdb.c \
+       src/console.c \
+       src/transport.c \
+       src/transport_local.c \
+       src/transport_usb.c \
+       src/commandline.c \
+       src/sdb_client.c \
+       src/sockets.c \
+       src/services.c \
+       src/file_sync_client.c \
+       src/get_my_path_windows.c \
+       src/usb_windows.c \
+       src/utils.c \
+       src/usb_vendors.c \
+       src/socket_local_client.c \
+       src/sysdeps_win32.c \
+       src/strutils.c
+
+INCS := \
+       -I/mingw/include/ddk \
+       -Isrc/sdbwinapi \
+       -Isrc
+
+DIRECT_INCS := \
+       -include src/TizenConfig.h
+
+LIB_PATH := \
+       -Lprebuilt
+
+LIBS := -lws2_32 \
+       prebuilt/SdbWinApi.a
+
+CFLAGS := \
+       -O2 -DSDB_HOST=1 -Wall -Wno-unused-parameter \
+       -D_XOPEN_SOURCE -D_GNU_SOURCE
+
+OBJDIR := bin
+PREBUILTDIR := prebuilt
+
+all : sdb
+
+sdb : $(SRC_FILES)
+       rm -rf $(OBJDIR)
+       mkdir $(OBJDIR)
+       $(CC) $(CFLAGS) $(INCS) -o $(OBJDIR)/$@ $(SRC_FILES) $(DIRECT_INCS) $(LIB_PATH) $(LIBS)
+       cp $(PREBUILTDIR)/SdbWinApi.dll $(OBJDIR)
+       cp $(PREBUILTDIR)/SdbWinUsbApi.dll $(OBJDIR)
+
diff --git a/SdbWinApi.bat b/SdbWinApi.bat
new file mode 100644 (file)
index 0000000..3bc86c2
--- /dev/null
@@ -0,0 +1,10 @@
+md prebuilt\r
+cd src\sdbwinapi\r
+build -cbeEIFZ\r
+copy objfre_win7_x86\i386\SdbWinApi.dll ..\..\prebuilt\\r
+copy SdbWinApi.def ..\..\prebuilt\\r
+cd ..\..\prebuilt\r
+dlltool --def SdbWInApi.def --dllname SdbWinApi.dll --output-lib SdbWinApi.a\r
+cd ..\src\sdbwinusbapi\r
+build -cbeEIFZ\r
+copy objfre_win7_x86\i386\SdbWinUsbApi.dll ..\..\prebuilt\\r
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..5d47358
--- /dev/null
@@ -0,0 +1,7 @@
+sdbd (0.0.1-1) unstable; urgency=low
+
+  * Initial upload
+  * Git: 165.213.180.234:slp/pkgs/s/sdbd
+  * Tag: sdbd_0.0.1-1
+
+ -- Joogwan Kim <joogwan.kim@samsung.com>  Sat, 26 Sep 2011 15:00:56 +0900
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7813681
--- /dev/null
@@ -0,0 +1 @@
+5
\ No newline at end of file
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..aa3ba16
--- /dev/null
@@ -0,0 +1,10 @@
+Source: sdbd
+Section: net
+Priority: extra
+Maintainer: Kangho Kim <kh5325.kim@samsung.com>, Yoonki Park <yoonki.park@samsung.com>, Ho Namkoong <ho.namkoong@samsung.com> 
+Build-Depends: debhelper (>= 5), libc6-dev
+Standards-Version: 0.0.1
+
+Package: sdbd
+Architecture: any 
+Description: SDB daemon
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..6ebe31f
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/make -f
+
+UNAME := $(shell uname -sm)
+ifneq (,$(findstring 86,$(UNAME)))
+       HOST_ARCH := x86
+endif
+
+configure: configure-stamp
+
+configure-stamp:
+       dh_testdir
+       touch configure-stamp
+
+build: build-stamp
+
+build-stamp: configure-stamp
+       dh_testdir
+       $(MAKE)
+       touch build-stamp
+
+install: build
+       dh_testdir
+       dh_testroot
+       $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
+
+binary: build install
+       dh_testdir
+       dh_testroot
+ifeq ($(HOST_ARCH),x86)
+       dh_install --sourcedir=debian/tmp
+else
+       dh_install --sourcedir=debian/tmp -XS06sdbd
+endif
+       dh_strip
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+clean:
+       dh_testdir
+       rm -f build-stamp configure-stamp
+       $(MAKE) clean
+       dh_clean
+
diff --git a/debian/sdbd.install b/debian/sdbd.install
new file mode 100644 (file)
index 0000000..5ac7294
--- /dev/null
@@ -0,0 +1,3 @@
+usr/sbin/sdbd
+etc/init.d/sdbd
+etc/rc.d/rc3.d/S06sdbd
index 6010e7aeffec99a89f9d7c93b0f4207c06dc78a0..15f50794b62fe56f80b9b88b67263f50358fa9af 100644 (file)
@@ -1,3 +1,9 @@
+* 2.1.28
+- revert: change app path
+== ho.namkoong <ho.namkoong@samsung.com> 2013-05-31
+* 2.1.27
+- change app path
+== ho.namkoong <ho.namkoong@samsung.com> 2013-05-31
 * 2.1.26
 - support debug command
 == yoonki.park <yoonki.park@samsung.com> 2013-04-22
index cf3affb74eed76b2cdc5983f562737d41d312893..bfa41c4403baae1a421b8a9d32d0b952b564cfd0 100644 (file)
@@ -1,4 +1,4 @@
-Version:2.1.26
+Version:2.1.28
 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>
 
diff --git a/script/S06sdbd b/script/S06sdbd
new file mode 100755 (executable)
index 0000000..6a05d55
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+/etc/init.d/sdbd start
diff --git a/script/sdbd b/script/sdbd
new file mode 100755 (executable)
index 0000000..85a868c
--- /dev/null
@@ -0,0 +1,39 @@
+#! /bin/sh
+
+. /lib/lsb/init-functions
+
+export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
+
+case "$1" in
+  start)
+        log_daemon_msg "Starting SDB Daemon..." "sdbd"
+        if start-stop-daemon --start --quiet --background --make-pidfile --pidfile /var/run/sdbd.pid --exec /usr/sbin/sdbd; then
+            log_end_msg 0
+        else
+            log_end_msg 1
+        fi
+        ;;
+  stop)
+        log_daemon_msg "Stopping SDB Daemon..." "sdbd"
+        if start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/sdbd.pid; then
+            log_end_msg 0
+        else
+            log_end_msg 1
+        fi
+        ;;
+  restart)
+        log_daemon_msg "Restarting SDB Daemon..." "sdbd"
+        start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /var/run/sdbd.pid
+       sleep 1        
+        if start-stop-daemon --start --quiet --background --make-pidfile --pidfile /var/run/sdbd.pid --exec /usr/sbin/sdbd; then
+            log_end_msg 0
+        else
+            log_end_msg 1
+        fi
+        ;;
+  *)
+       log_action_msg "Usage: /etc/init.d/sdbd {start|stop|restart}"
+       exit 1
+esac
+
+exit 0
diff --git a/src/Android.mk b/src/Android.mk
new file mode 100644 (file)
index 0000000..7faca9b
--- /dev/null
@@ -0,0 +1,154 @@
+# Copyright 2005 The Android Open Source Project
+#
+# Android.mk for adb
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# adb host tool
+# =========================================================
+include $(CLEAR_VARS)
+
+# Default to a virtual (sockets) usb interface
+USB_SRCS :=
+EXTRA_SRCS :=
+
+ifeq ($(HOST_OS),linux)
+  USB_SRCS := usb_linux.c
+  EXTRA_SRCS := get_my_path_linux.c
+  LOCAL_LDLIBS += -lrt -lncurses -lpthread
+endif
+
+ifeq ($(HOST_OS),darwin)
+  USB_SRCS := usb_osx.c
+  EXTRA_SRCS := get_my_path_darwin.c
+  LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+endif
+
+ifeq ($(HOST_OS),freebsd)
+  USB_SRCS := usb_libusb.c
+  EXTRA_SRCS := get_my_path_freebsd.c
+  LOCAL_LDLIBS += -lpthread -lusb
+endif
+
+ifeq ($(HOST_OS),windows)
+  USB_SRCS := usb_windows.c
+  EXTRA_SRCS := get_my_path_windows.c
+  EXTRA_STATIC_LIBS := AdbWinApi
+  ifneq ($(strip $(USE_CYGWIN)),)
+    # Pure cygwin case
+    LOCAL_LDLIBS += -lpthread
+    LOCAL_C_INCLUDES += /usr/include/w32api/ddk
+  endif
+  ifneq ($(strip $(USE_MINGW)),)
+    # MinGW under Linux case
+    LOCAL_LDLIBS += -lws2_32
+    USE_SYSDEPS_WIN32 := 1
+    LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
+  endif
+  LOCAL_C_INCLUDES += development/host/windows/usb/api/
+endif
+
+LOCAL_SRC_FILES := \
+       adb.c \
+       console.c \
+       transport.c \
+       transport_local.c \
+       transport_usb.c \
+       commandline.c \
+       adb_client.c \
+       sockets.c \
+       services.c \
+       file_sync_client.c \
+       $(EXTRA_SRCS) \
+       $(USB_SRCS) \
+       utils.c \
+       usb_vendors.c
+
+
+ifneq ($(USE_SYSDEPS_WIN32),)
+  LOCAL_SRC_FILES += sysdeps_win32.c
+else
+  LOCAL_SRC_FILES += fdevent.c
+endif
+
+LOCAL_CFLAGS += -O2 -g -DADB_HOST=1  -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+LOCAL_MODULE := adb
+
+LOCAL_STATIC_LIBRARIES := libzipfile libunz $(EXTRA_STATIC_LIBS)
+ifeq ($(USE_SYSDEPS_WIN32),)
+       LOCAL_STATIC_LIBRARIES += libcutils
+endif
+
+include $(BUILD_HOST_EXECUTABLE)
+
+$(call dist-for-goals,droid,$(LOCAL_BUILT_MODULE))
+
+ifeq ($(HOST_OS),windows)
+$(LOCAL_INSTALLED_MODULE): \
+    $(HOST_OUT_EXECUTABLES)/AdbWinApi.dll \
+    $(HOST_OUT_EXECUTABLES)/AdbWinUsbApi.dll
+endif
+
+
+# adbd device daemon
+# =========================================================
+
+# build adbd in all non-simulator builds
+BUILD_ADBD := false
+ifneq ($(TARGET_SIMULATOR),true)
+    BUILD_ADBD := true
+endif
+
+# build adbd for the Linux simulator build
+# so we can use it to test the adb USB gadget driver on x86
+#ifeq ($(HOST_OS),linux)
+#    BUILD_ADBD := true
+#endif
+
+
+ifeq ($(BUILD_ADBD),true)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       adb.c \
+       fdevent.c \
+       transport.c \
+       transport_local.c \
+       transport_usb.c \
+       sockets.c \
+       services.c \
+       file_sync_service.c \
+       jdwp_service.c \
+       framebuffer_service.c \
+       remount_service.c \
+       usb_linux_client.c \
+       log_service.c \
+       utils.c
+
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
+
+# TODO: This should probably be board specific, whether or not the kernel has
+# the gadget driver; rather than relying on the architecture type.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_CFLAGS += -DANDROID_GADGET=1
+endif
+
+LOCAL_MODULE := adbd
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+
+ifeq ($(TARGET_SIMULATOR),true)
+  LOCAL_STATIC_LIBRARIES := libcutils
+  LOCAL_LDLIBS += -lpthread
+  include $(BUILD_HOST_EXECUTABLE)
+else
+  LOCAL_STATIC_LIBRARIES := libcutils libc
+  include $(BUILD_EXECUTABLE)
+endif
+
+endif
diff --git a/src/MODULE_LICENSE_APACHE2 b/src/MODULE_LICENSE_APACHE2
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/NOTICE b/src/NOTICE
new file mode 100644 (file)
index 0000000..9ffcc08
--- /dev/null
@@ -0,0 +1,191 @@
+
+   Copyright (c) 2006-2009, The Android Open Source Project
+   Copyright 2006, Brian Swetland <swetland@frotz.net>
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/src/OVERVIEW.TXT b/src/OVERVIEW.TXT
new file mode 100644 (file)
index 0000000..0d9784a
--- /dev/null
@@ -0,0 +1,139 @@
+Implementation notes regarding SDB.
+
+I. General Overview:
+
+The Android Debug Bridge (SDB) is used to:
+
+- keep track of all Android devices and emulators instances
+  connected to or running on a given host developer machine
+
+- implement various control commands (e.g. "sdb shell", "sdb pull", etc..)
+  for the benefit of clients (command-line users, or helper programs like
+  DDMS). These commands are what is called a 'service' in SDB.
+
+As a whole, everything works through the following components:
+
+  1. The SDB server
+
+    This is a background process that runs on the host machine. Its purpose
+    if to sense the USB ports to know when devices are attached/removed,
+    as well as when emulator instances start/stop.
+
+    It thus maintains a list of "connected devices" and assigns a 'state'
+    to each one of them: OFFLINE, BOOTLOADER, RECOVERY or ONLINE (more on
+    this below).
+
+    The SDB server is really one giant multiplexing loop whose purpose is
+    to orchestrate the exchange of data (packets, really) between clients,
+    services and devices.
+
+
+  2. The SDB daemon (sdbd)
+
+    The 'sdbd' program runs as a background process within an Android device
+    or emulated system. Its purpose is to connect to the SDB server
+    (through USB for devices, through TCP for emulators) and provide a
+    few services for clients that run on the host.
+
+    The SDB server considers that a device is ONLINE when it has successfully
+    connected to the sdbd program within it. Otherwise, the device is OFFLINE,
+    meaning that the SDB server detected a new device/emulator, but could not
+    connect to the sdbd daemon.
+
+    the BOOTLOADER and RECOVERY states correspond to alternate states of
+    devices when they are in the bootloader or recovery mode.
+
+  3. The SDB command-line client
+
+    The 'sdb' command-line program is used to run sdb commands from a shell
+    or a script. It first tries to locate the SDB server on the host machine,
+    and will start one automatically if none is found.
+
+    then, the client sends its service requests to the SDB server. It doesn't
+    need to know.
+
+    Currently, a single 'sdb' binary is used for both the server and client.
+    this makes distribution and starting the server easier.
+
+
+  4. Services
+
+    There are essentially two kinds of services that a client can talk to.
+
+    Host Services:
+      these services run within the SDB Server and thus do not need to
+      communicate with a device at all. A typical example is "sdb devices"
+      which is used to return the list of currently known devices and their
+      state. They are a few couple other services though.
+
+    Local Services:
+      these services either run within the sdbd daemon, or are started by
+      it on the device. The SDB server is used to multiplex streams
+      between the client and the service running in sdbd. In this case
+      its role is to initiate the connection, then of being a pass-through
+      for the data.
+
+
+II. Protocol details:
+
+  1. Client <-> Server protocol:
+
+    This details the protocol used between SDB clients and the SDB
+    server itself. The SDB server listens on TCP:localhost:5037.
+
+    A client sends a request using the following format:
+
+        1. A 4-byte hexadecimal string giving the length of the payload
+        2. Followed by the payload itself.
+
+    For example, to query the SDB server for its internal version number,
+    the client will do the following:
+
+        1. Connect to tcp:localhost:5037
+        2. Send the string "000Chost:version" to the corresponding socket
+
+    The 'host:' prefix is used to indicate that the request is addressed
+    to the server itself (we will talk about other kinds of requests later).
+    The content length is encoded in ASCII for easier debugging.
+
+    The server should answer a request with one of the following:
+
+        1. For success, the 4-byte "OKAY" string
+
+        2. For failure, the 4-byte "FAIL" string, followed by a
+           4-byte hex length, followed by a string giving the reason
+           for failure.
+
+        3. As a special exception, for 'host:version', a 4-byte
+           hex string corresponding to the server's internal version number
+
+    Note that the connection is still alive after an OKAY, which allows the
+    client to make other requests. But in certain cases, an OKAY will even
+    change the state of the connection. 
+
+    For example, the case of the 'host:transport:<serialnumber>' request,
+    where '<serialnumber>' is used to identify a given device/emulator; after
+    the "OKAY" answer, all further requests made by the client will go
+    directly to the corresponding sdbd daemon.
+
+    The file SERVICES.TXT lists all services currently implemented by SDB.
+
+
+  2. Transports:
+
+    An SDB transport models a connection between the SDB server and one device
+    or emulator. There are currently two kinds of transports:
+
+       - USB transports, for physical devices through USB
+
+       - Local transports, for emulators running on the host, connected to
+         the server through TCP
+
+    In theory, it should be possible to write a local transport that proxies
+    a connection between an SDB server and a device/emulator connected to/
+    running on another machine. This hasn't been done yet though.
+
+    Each transport can carry one or more multiplexed streams between clients
+    and the device/emulator they point to. The SDB server must handle
+    unexpected transport disconnections (e.g. when a device is physically
+    unplugged) properly.
diff --git a/src/SERVICES.TXT b/src/SERVICES.TXT
new file mode 100644 (file)
index 0000000..3bfbe37
--- /dev/null
@@ -0,0 +1,236 @@
+This file tries to document all requests a client can make
+to the SDB server of an sdbd daemon. See the OVERVIEW.TXT document
+to understand what's going on here.
+
+HOST SERVICES:
+
+host:version
+    Ask the SDB server for its internal version number.
+
+    As a special exception, the server will respond with a 4-byte
+    hex string corresponding to its internal version number, without
+    any OKAY or FAIL.
+
+host:kill
+    Ask the SDB server to quit immediately. This is used when the
+    SDB client detects that an obsolete server is running after an
+    upgrade.
+
+host:devices
+    Ask to return the list of available Android devices and their
+    state. After the OKAY, this is followed by a 4-byte hex len,
+    and a string that will be dumped as-is by the client, then
+    the connection is closed
+
+host:track-devices
+    This is a variant of host:devices which doesn't close the
+    connection. Instead, a new device list description is sent
+    each time a device is added/removed or the state of a given
+    device changes (hex4 + content). This allows tools like DDMS
+    to track the state of connected devices in real-time without
+    polling the server repeatedly.
+
+host:emulator:<port>
+    This is a special query that is sent to the SDB server when a
+    new emulator starts up. <port> is a decimal number corresponding
+    to the emulator's SDB control port, i.e. the TCP port that the
+    emulator will forward automatically to the sdbd daemon running
+    in the emulator system.
+
+    This mechanism allows the SDB server to know when new emulator
+    instances start.
+
+host:transport:<serial-number>
+    Ask to switch the connection to the device/emulator identified by
+    <serial-number>. After the OKAY response, every client request will
+    be sent directly to the sdbd daemon running on the device.
+    (Used to implement the -s option)
+
+host:transport-usb
+    Ask to switch the connection to one device connected through USB
+    to the host machine. This will fail if there are more than one such
+    devices. (Used to implement the -d convenience option)
+
+host:transport-local
+    Ask to switch the connection to one emulator connected through TCP.
+    This will fail if there is more than one such emulator instance
+    running. (Used to implement the -e convenience option)
+
+host:transport-any
+    Another host:transport variant. Ask to switch the connection to
+    either the device or emulator connect to/running on the host.
+    Will fail if there is more than one such device/emulator available.
+    (Used when neither -s, -d or -e are provided)
+
+host-serial:<serial-number>:<request>
+    This is a special form of query, where the 'host-serial:<serial-number>:'
+    prefix can be used to indicate that the client is asking the SDB server
+    for information related to a specific device. <request> can be in one
+    of the format described below.
+
+host-usb:<request>
+    A variant of host-serial used to target the single USB device connected
+    to the host. This will fail if there is none or more than one.
+
+host-local:<request>
+    A variant of host-serial used to target the single emulator instance
+    running on the host. This will fail if there is none or more than one.
+
+host:<request>
+    When asking for information related to a device, 'host:' can also be
+    interpreted as 'any single device or emulator connected to/running on
+    the host'.
+
+<host-prefix>:get-product
+    XXX
+
+<host-prefix>:get-serialno
+    Returns the serial number of the corresponding device/emulator.
+    Note that emulator serial numbers are of the form "emulator-5554"
+
+<host-prefix>:get-state
+    Returns the state of a given device as a string.
+
+<host-prefix>:forward:<local>;<remote>
+    Asks the SDB server to forward local connections from <local>
+    to the <remote> address on a given device.
+
+    There, <host-prefix> can be one of the
+    host-serial/host-usb/host-local/host prefixes as described previously
+    and indicates which device/emulator to target.
+
+    the format of <local> is one of:
+
+        tcp:<port>      -> TCP connection on localhost:<port>
+        local:<path>    -> Unix local domain socket on <path>
+
+    the format of <remote> is one of:
+
+        tcp:<port>      -> TCP localhost:<port> on device
+        local:<path>    -> Unix local domain socket on device
+        jdwp:<pid>      -> JDWP thread on VM process <pid>
+
+    or even any one of the local services described below.
+
+
+
+LOCAL SERVICES:
+
+All the queries below assumed that you already switched the transport
+to a real device, or that you have used a query prefix as described
+above.
+
+shell:command arg1 arg2 ...
+    Run 'command arg1 arg2 ...' in a shell on the device, and return
+    its output and error streams. Note that arguments must be separated
+    by spaces. If an argument contains a space, it must be quoted with
+    double-quotes. Arguments cannot contain double quotes or things
+    will go very wrong.
+
+    Note that this is the non-interactive version of "sdb shell"
+
+shell:
+    Start an interactive shell session on the device. Redirect
+    stdin/stdout/stderr as appropriate. Note that the SDB server uses
+    this to implement "sdb shell", but will also cook the input before
+    sending it to the device (see interactive_shell() in commandline.c)
+
+remount:
+    Ask sdbd to remount the device's filesystem in read-write mode,
+    instead of read-only. This is usually necessary before performing
+    an "sdb sync" or "sdb push" request.
+
+    This request may not succeed on certain builds which do not allow
+    that.
+
+dev:<path>
+    Opens a device file and connects the client directly to it for
+    read/write purposes. Useful for debugging, but may require special
+    privileges and thus may not run on all devices. <path> is a full
+    path from the root of the filesystem.
+
+tcp:<port>
+    Tries to connect to tcp port <port> on localhost.
+
+tcp:<port>:<server-name>
+    Tries to connect to tcp port <port> on machine <server-name> from
+    the device. This can be useful to debug some networking/proxy
+    issues that can only be revealed on the device itself.
+
+local:<path>
+    Tries to connect to a Unix domain socket <path> on the device
+
+localreserved:<path>
+localabstract:<path>
+localfilesystem:<path>
+    Variants of local:<path> that are used to access other Android
+    socket namespaces.
+
+log:<name>
+    Opens one of the system logs (/dev/log/<name>) and allows the client
+    to read them directly. Used to implement 'sdb logcat'. The stream
+    will be read-only for the client.
+
+framebuffer:
+    This service is used to send snapshots of the framebuffer to a client.
+    It requires sufficient privileges but works as follow:
+
+      After the OKAY, the service sends 16-byte binary structure
+      containing the following fields (little-endian format):
+
+            depth:   uint32_t:    framebuffer depth
+            size:    uint32_t:    framebuffer size in bytes
+            width:   uint32_t:    framebuffer width in pixels
+            height:  uint32_t:    framebuffer height in pixels
+
+      With the current implementation, depth is always 16, and
+      size is always width*height*2
+
+      Then, each time the client wants a snapshot, it should send
+      one byte through the channel, which will trigger the service
+      to send it 'size' bytes of framebuffer data.
+
+      If the sdbd daemon doesn't have sufficient privileges to open
+      the framebuffer device, the connection is simply closed immediately.
+
+dns:<server-name>
+    This service is an exception because it only runs within the SDB server.
+    It is used to implement USB networking, i.e. to provide a network connection
+    to the device through the host machine (note: this is the exact opposite of
+    network tethering).
+
+    It is used to perform a gethostbyname(<address>) on the host and return
+    the corresponding IP address as a 4-byte string.
+
+recover:<size>
+    This service is used to upload a recovery image to the device. <size>
+    must be a number corresponding to the size of the file. The service works
+    by:
+
+       - creating a file named /tmp/update
+       - reading 'size' bytes from the client and writing them to /tmp/update
+       - when everything is read successfully, create a file named /tmp/update.start
+
+    This service can only work when the device is in recovery mode. Otherwise,
+    the /tmp directory doesn't exist and the connection will be closed immediately.
+
+jdwp:<pid>
+    Connects to the JDWP thread running in the VM of process <pid>.
+
+track-jdwp
+    This is used to send the list of JDWP pids periodically to the client.
+    The format of the returned data is the following:
+
+        <hex4>:    the length of all content as a 4-char hexadecimal string
+        <content>: a series of ASCII lines of the following format:
+                        <pid> "\n"
+
+    This service is used by DDMS to know which debuggable processes are running
+    on the device/emulator.
+
+    Note that there is no single-shot service to retrieve the list only once.
+
+sync:
+    This starts the file synchronisation service, used to implement "sdb push"
+    and "sdb pull". Since this service is pretty complex, it will be detailed
+    in a companion document named SYNC.TXT
diff --git a/src/TizenConfig.h b/src/TizenConfig.h
new file mode 100644 (file)
index 0000000..81d36f3
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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.
+ */
+
+/*
+ * Android config -- "CYGWIN_NT-5.1".  
+ *
+ * Cygwin has pthreads, but GDB seems to get confused if you use it to
+ * create threads.  By "confused", I mean it freezes up the first time the
+ * debugged process creates a thread, even if you use CreateThread.  The
+ * mere presence of pthreads linkage seems to cause problems.
+ */
+#ifndef _ANDROID_CONFIG_H
+#define _ANDROID_CONFIG_H
+
+/*
+ * ===========================================================================
+ *                              !!! IMPORTANT !!!
+ * ===========================================================================
+ *
+ * This file is included by ALL C/C++ source files.  Don't put anything in
+ * here unless you are absolutely certain it can't go anywhere else.
+ *
+ * Any C++ stuff must be wrapped with "#ifdef __cplusplus".  Do not use "//"
+ * comments.
+ */
+
+/*
+ * Threading model.  Choose one:
+ *
+ * HAVE_PTHREADS - use the pthreads library.
+ * HAVE_WIN32_THREADS - use Win32 thread primitives.
+ */
+#define HAVE_WIN32_THREADS
+
+/*
+ * Do we have the futex syscall?
+ */
+
+/* #define HAVE_FUTEX */
+
+
+/*
+ * Process creation model.  Choose one:
+ *
+ * HAVE_FORKEXEC - use fork() and exec()
+ * HAVE_WIN32_PROC - use CreateProcess()
+ */
+#ifdef __CYGWIN__
+#  define HAVE_FORKEXEC
+#else
+#  define HAVE_WIN32_PROC
+#endif
+
+/*
+ * Process out-of-memory adjustment.  Set if running on Linux,
+ * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
+ * badness adjustment.
+ */
+/* #define HAVE_OOM_ADJ */
+
+/*
+ * IPC model.  Choose one:
+ *
+ * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
+ * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
+ * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
+ * HAVE_ANDROID_IPC - use Android versions (?, mmap).
+ */
+#define HAVE_WIN32_IPC
+
+/*
+ * Memory-mapping model. Choose one:
+ *
+ * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
+ * HAVE_WIN32_FILEMAP - use Win32 filemaps
+ */
+#ifdef __CYGWIN__
+#define  HAVE_POSIX_FILEMAP
+#else
+#define  HAVE_WIN32_FILEMAP
+#endif
+
+/*
+ * Define this if you have <termio.h>
+ */
+#ifdef __CYGWIN__
+#  define  HAVE_TERMIO_H
+#endif
+
+/*
+ * Define this if you have <sys/sendfile.h>
+ */
+#ifdef __CYGWIN__
+#  define  HAVE_SYS_SENDFILE_H 1
+#endif
+
+/*
+ * Define this if you build against MSVCRT.DLL
+ */
+#ifndef __CYGWIN__
+#  define HAVE_MS_C_RUNTIME
+#endif
+
+/*
+ * Define this if you have sys/uio.h
+ */
+#ifdef __CYGWIN__
+#define  HAVE_SYS_UIO_H
+#endif
+
+
+/*
+ * Define this if we have localtime_r().
+ */
+/* #define HAVE_LOCALTIME_R */
+
+/*
+ * Define this if we have gethostbyname_r().
+ */
+/* #define HAVE_GETHOSTBYNAME_R */
+
+/*
+ * Define this if we have ioctl().
+ */
+/* #define HAVE_IOCTL */
+
+/*
+ * Define this if we want to use WinSock.
+ */
+#ifndef __CYGWIN__
+#define HAVE_WINSOCK
+#endif
+
+/*
+ * Define this if your platforms implements symbolic links
+ * in its filesystems
+ */
+/* #define HAVE_SYMLINKS */
+
+/*
+ * Define this if have clock_gettime() and friends
+ */
+/* #define HAVE_POSIX_CLOCKS */
+
+/*
+ * Endianness of the target machine.  Choose one:
+ *
+ * HAVE_ENDIAN_H -- have endian.h header we can include.
+ * HAVE_LITTLE_ENDIAN -- we are little endian.
+ * HAVE_BIG_ENDIAN -- we are big endian.
+ */
+#ifdef __CYGWIN__
+#define HAVE_ENDIAN_H
+#endif
+
+#define HAVE_LITTLE_ENDIAN
+
+/*
+ * We need to choose between 32-bit and 64-bit off_t.  All of our code should
+ * agree on the same size.  For desktop systems, use 64-bit values,
+ * because some of our libraries (e.g. wxWidgets) expect to be built that way.
+ */
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE 1
+
+/*
+ * Defined if we have the backtrace() call for retrieving a stack trace.
+ * Needed for CallStack to operate; if not defined, CallStack is
+ * non-functional.
+ */
+#define HAVE_BACKTRACE 0
+
+/*
+ * Defined if we have the dladdr() call for retrieving the symbol associated
+ * with a memory address.  If not defined, stack crawls will not have symbolic
+ * information.
+ */
+#define HAVE_DLADDR 0
+
+/*
+ * Defined if we have the cxxabi.h header for demangling C++ symbols.  If
+ * not defined, stack crawls will be displayed with raw mangled symbols
+ */
+#define HAVE_CXXABI 0
+
+/*
+ * Define if tm struct has tm_gmtoff field
+ */
+/* #define HAVE_TM_GMTOFF 1 */
+
+/*
+ * Define if dirent struct has d_type field
+ */
+/* #define HAVE_DIRENT_D_TYPE 1 */
+
+/*
+ * Define if libc includes Android system properties implementation.
+ */
+/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
+
+/*
+ * Define if system provides a system property server (should be
+ * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
+ */
+/* #define HAVE_SYSTEM_PROPERTY_SERVER */
+
+/*
+ * Define if we have madvise() in <sys/mman.h>
+ */
+/*#define HAVE_MADVISE 1*/
+
+/*
+ * Add any extra platform-specific defines here.
+ */
+#define WIN32 1                 /* stock Cygwin doesn't define these */
+#define _WIN32 1
+#define _WIN32_WINNT 0x0500     /* admit to using >= Win2K */
+
+#define HAVE_WINDOWS_PATHS      /* needed by simulator */
+
+/*
+ * What CPU architecture does this platform use?
+ */
+#define ARCH_X86
+
+/*
+ * sprintf() format string for shared library naming.
+ */
+#define OS_SHARED_LIB_FORMAT_STR    "lib%s.dll"
+
+/*
+ * type for the third argument to mincore().
+ */
+#define MINCORE_POINTER_TYPE unsigned char *
+
+/*
+ * The default path separator for the platform
+ */
+#define OS_PATH_SEPARATOR '\\'
+
+/*
+ * Is the filesystem case sensitive?
+ */
+/* #define OS_CASE_SENSITIVE */
+
+/*
+ * Define if <sys/socket.h> exists.
+ * Cygwin has it, but not MinGW.
+ */
+#ifdef USE_MINGW
+/* #define HAVE_SYS_SOCKET_H */
+#else
+#define HAVE_SYS_SOCKET_H 1
+#endif
+
+/*
+ * Define if the strlcpy() function exists on the system.
+ */
+/* #define HAVE_STRLCPY 1 */
+
+/*
+ * Define if the open_memstream() function exists on the system.
+ */
+/* #define HAVE_OPEN_MEMSTREAM 1 */
+
+/*
+ * Define if the BSD funopen() function exists on the system.
+ */
+/* #define HAVE_FUNOPEN 1 */
+
+/*
+ * Define if <winsock2.h> exists.
+ * Only MinGW has it.
+ */
+#ifdef USE_MINGW
+#define HAVE_WINSOCK2_H 1
+#else
+/* #define HAVE_WINSOCK2_H */
+#endif
+
+/*
+ * Various definitions missing in MinGW
+ */
+#ifdef USE_MINGW
+#define S_IRGRP 0
+#endif
+
+/*
+ * Define if writev() exists.
+ */
+/* #define HAVE_WRITEV */
+
+/*
+ * Define if <stdint.h> exists.
+ */
+/* #define HAVE_STDINT_H */
+
+/*
+ * Define if <stdbool.h> exists.
+ */
+#define HAVE_STDBOOL_H
+
+/*
+ * Define if <sched.h> exists.
+ */
+/* #define HAVE_SCHED_H */
+
+/*
+ * Define if pread() exists
+ */
+/* #define HAVE_PREAD 1 */
+
+/*
+ * Define if we have st_mtim in struct stat
+ */
+/* #define HAVE_STAT_ST_MTIM 1 */
+
+/*
+ * Define if printf() supports %zd for size_t arguments
+ */
+/* #define HAVE_PRINTF_ZD 1 */
+
+#endif /*_ANDROID_CONFIG_H*/
diff --git a/src/android_reboot.c b/src/android_reboot.c
new file mode 100644 (file)
index 0000000..db8a4a9
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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 <unistd.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "android_reboot.h"
+
+/* Check to see if /proc/mounts contains any writeable filesystems
+ * backed by a block device.
+ * Return true if none found, else return false.
+ */
+static int remount_ro_done(void)
+{
+    FILE *f;
+    char mount_dev[256];
+    char mount_dir[256];
+    char mount_type[256];
+    char mount_opts[256];
+    int mount_freq;
+    int mount_passno;
+    int match;
+    int found_rw_fs = 0;
+
+    f = fopen("/proc/mounts", "r");
+    if (! f) {
+        /* If we can't read /proc/mounts, just give up */
+        return 1;
+    }
+
+    do {
+        match = fscanf(f, "%255s %255s %255s %255s %d %d\n",
+                       mount_dev, mount_dir, mount_type,
+                       mount_opts, &mount_freq, &mount_passno);
+        mount_dev[255] = 0;
+        //mount_dir[255] = 0;
+        //mount_type[255] = 0;
+        mount_opts[255] = 0;
+        if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw")) {
+            found_rw_fs = 1;
+            break;
+        }
+    } while (match != EOF);
+
+    fclose(f);
+
+    return !found_rw_fs;
+}
+
+/* Remounting filesystems read-only is difficult when there are files
+ * opened for writing or pending deletes on the filesystem.  There is
+ * no way to force the remount with the mount(2) syscall.  The magic sysrq
+ * 'u' command does an emergency remount read-only on all writable filesystems
+ * that have a block device (i.e. not tmpfs filesystems) by calling
+ * emergency_remount(), which knows how to force the remount to read-only.
+ * Unfortunately, that is asynchronous, and just schedules the work and
+ * returns.  The best way to determine if it is done is to read /proc/mounts
+ * repeatedly until there are no more writable filesystems mounted on
+ * block devices.
+ */
+static void remount_ro(void)
+{
+    int fd, cnt = 0;
+    /* Trigger the remount of the filesystems as read-only,
+     * which also marks them clean.
+     */
+    fd = open("/proc/sysrq-trigger", O_WRONLY);
+    if (fd < 0) {
+        return;
+    }
+    write(fd, "u", 1);
+    close(fd);
+
+    /* Now poll /proc/mounts till it's done */
+    while (!remount_ro_done() && (cnt < 50)) {
+        usleep(100000);
+        cnt++;
+    }
+
+    return;
+}
+
+
+int android_reboot(int cmd, int flags, char *arg)
+{
+    int ret;
+
+    if (!(flags & ANDROID_RB_FLAG_NO_SYNC))
+        sync();
+
+    if (!(flags & ANDROID_RB_FLAG_NO_REMOUNT_RO))
+        remount_ro();
+
+    switch (cmd) {
+        case ANDROID_RB_RESTART:
+            ret = reboot(RB_AUTOBOOT);
+            break;
+
+        case ANDROID_RB_POWEROFF:
+            ret = reboot(RB_POWER_OFF);
+            break;
+#if 0 /* tizen specific */
+        case ANDROID_RB_RESTART2:
+            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                           LINUX_REBOOT_CMD_RESTART2, arg);
+            break;
+#endif
+        default:
+            ret = -1;
+    }
+
+    return ret;
+}
+
diff --git a/src/android_reboot.h b/src/android_reboot.h
new file mode 100644 (file)
index 0000000..5fcb61c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 __CUTILS_ANDROID_REBOOT_H__
+#define __CUTILS_ANDROID_REBOOT_H__
+
+__BEGIN_DECLS
+
+/* Commands */
+#define ANDROID_RB_RESTART  0xDEAD0001
+#define ANDROID_RB_POWEROFF 0xDEAD0002
+#define ANDROID_RB_RESTART2 0xDEAD0003
+
+/* Flags */
+#define ANDROID_RB_FLAG_NO_SYNC       0x1
+#define ANDROID_RB_FLAG_NO_REMOUNT_RO 0x2
+
+int android_reboot(int cmd, int flags, char *arg);
+
+__END_DECLS
+
+#endif /* __CUTILS_ANDROID_REBOOT_H__ */
diff --git a/src/clear_vars.mk b/src/clear_vars.mk
new file mode 100644 (file)
index 0000000..ee28f21
--- /dev/null
@@ -0,0 +1,107 @@
+###########################################################
+## Clear out values of all variables used by rule templates.
+###########################################################
+
+LOCAL_MODULE:=
+LOCAL_MODULE_PATH:=
+LOCAL_MODULE_STEM:=
+LOCAL_DONT_CHECK_MODULE:=
+LOCAL_CHECKED_MODULE:=
+LOCAL_BUILT_MODULE:=
+LOCAL_BUILT_MODULE_STEM:=
+OVERRIDE_BUILT_MODULE_PATH:=
+LOCAL_INSTALLED_MODULE:=
+LOCAL_UNINSTALLABLE_MODULE:=
+LOCAL_INTERMEDIATE_TARGETS:=
+LOCAL_UNSTRIPPED_PATH:=
+LOCAL_MODULE_CLASS:=
+LOCAL_MODULE_SUFFIX:=
+LOCAL_PACKAGE_NAME:=
+LOCAL_OVERRIDES_PACKAGES:=
+LOCAL_EXPORT_PACKAGE_RESOURCES:=
+LOCAL_MANIFEST_PACKAGE_NAME:=
+LOCAL_REQUIRED_MODULES:=
+LOCAL_ACP_UNAVAILABLE:=
+LOCAL_MODULE_TAGS:=
+LOCAL_SRC_FILES:=
+LOCAL_PREBUILT_OBJ_FILES:=
+LOCAL_STATIC_JAVA_LIBRARIES:=
+LOCAL_STATIC_LIBRARIES:=
+LOCAL_WHOLE_STATIC_LIBRARIES:=
+LOCAL_SHARED_LIBRARIES:=
+LOCAL_IS_HOST_MODULE:=
+LOCAL_CC:=
+LOCAL_CXX:=
+LOCAL_CPP_EXTENSION:=
+LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
+LOCAL_NO_FDO_SUPPORT :=
+LOCAL_ARM_MODE:=
+LOCAL_YACCFLAGS:=
+LOCAL_ASFLAGS:=
+LOCAL_CFLAGS:=
+LOCAL_CPPFLAGS:=
+LOCAL_C_INCLUDES:=
+LOCAL_LDFLAGS:=
+LOCAL_LDLIBS:=
+LOCAL_AAPT_FLAGS:=
+LOCAL_SYSTEM_SHARED_LIBRARIES:=none
+LOCAL_PREBUILT_LIBS:=
+LOCAL_PREBUILT_EXECUTABLES:=
+LOCAL_PREBUILT_JAVA_LIBRARIES:=
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=
+LOCAL_PREBUILT_STRIP_COMMENTS:=
+LOCAL_INTERMEDIATE_SOURCES:=
+LOCAL_INTERMEDIATE_SOURCE_DIR:=
+LOCAL_JAVACFLAGS:=
+LOCAL_JAVA_LIBRARIES:=
+LOCAL_NO_STANDARD_LIBRARIES:=
+LOCAL_CLASSPATH:=
+LOCAL_DROIDDOC_USE_STANDARD_DOCLET:=
+LOCAL_DROIDDOC_SOURCE_PATH:=
+LOCAL_DROIDDOC_TEMPLATE_DIR:=
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=
+LOCAL_DROIDDOC_ASSET_DIR:=
+LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=
+LOCAL_DROIDDOC_OPTIONS:=
+LOCAL_DROIDDOC_HTML_DIR:=
+LOCAL_ASSET_FILES:=
+LOCAL_ASSET_DIR:=
+LOCAL_RESOURCE_DIR:=
+LOCAL_JAVA_RESOURCE_DIRS:=
+LOCAL_JAVA_RESOURCE_FILES:=
+LOCAL_GENERATED_SOURCES:=
+LOCAL_COPY_HEADERS_TO:=
+LOCAL_COPY_HEADERS:=
+LOCAL_FORCE_STATIC_EXECUTABLE:=
+LOCAL_ADDITIONAL_DEPENDENCIES:=
+LOCAL_PRELINK_MODULE:=
+LOCAL_COMPRESS_MODULE_SYMBOLS:=
+LOCAL_STRIP_MODULE:=
+LOCAL_POST_PROCESS_COMMAND:=true
+LOCAL_JNI_SHARED_LIBRARIES:=
+LOCAL_JAR_MANIFEST:=
+LOCAL_INSTRUMENTATION_FOR:=
+LOCAL_MANIFEST_INSTRUMENTATION_FOR:=
+LOCAL_AIDL_INCLUDES:=
+LOCAL_JARJAR_RULES:=
+LOCAL_ADDITIONAL_JAVA_DIR:=
+LOCAL_ALLOW_UNDEFINED_SYMBOLS:=
+LOCAL_DX_FLAGS:=
+LOCAL_CERTIFICATE:=
+LOCAL_SDK_VERSION:=
+LOCAL_NDK_VERSION:=
+LOCAL_NO_EMMA_INSTRUMENT:=
+LOCAL_NO_EMMA_COMPILE:=
+LOCAL_PROGUARD_ENABLED:= # '',optonly,full,custom
+LOCAL_PROGUARD_FLAGS:=
+LOCAL_PROGUARD_FLAG_FILES:=
+LOCAL_EMMA_COVERAGE_FILTER:=
+LOCAL_MANIFEST_FILE:=
+LOCAL_BUILD_HOST_DEX:=
+LOCAL_DEX_PREOPT:=
+
+# Trim MAKEFILE_LIST so that $(call my-dir) doesn't need to
+# iterate over thousands of entries every time.
+# Leave the current makefile to make sure we don't break anything
+# that expects to be able to find the name of the current makefile.
+MAKEFILE_LIST := $(lastword $(MAKEFILE_LIST))
diff --git a/src/command_function.c b/src/command_function.c
deleted file mode 100644 (file)
index 240833f..0000000
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
-* 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 <stdio.h>
-#include <limits.h>
-#include "utils.h"
-#include "fdevent.h"
-#include "sdb.h"
-
-#include "commandline.h"
-#include "command_function.h"
-#include "sdb_client.h"
-#include "sdb_constants.h"
-#include "file_sync_service.h"
-
-#include "strutils.h"
-#include "file_sync_client.h"
-#include "file_sync_functions.h"
-
-static const char *SDK_TOOL_PATH="/home/developer/sdk_tools";
-static const char *APP_PATH_PREFIX="/opt/apps";
-
-static void __inline__ format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial);
-static int get_pkgtype_file_name(const char* file_name);
-static int get_pkgtype_from_app_id(const char* app_id, void** extargv);
-static int kill_gdbserver_if_running(const char* process_cmd, void** extargv);
-static int verify_gdbserver_exist(void** extargv);
-
-int da(int argc, char ** argv, void** extargv) {
-    char full_cmd[PATH_MAX] = "shell:/usr/bin/da_command";
-
-    append_args(full_cmd, --argc, (const char**)++argv, PATH_MAX-1);
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    int result = __sdb_command(full_cmd, extargv);
-
-    if(result < 0) {
-        return 1;
-    }
-    return 0;
-}
-
-int oprofile(int argc, char ** argv, void** extargv) {
-    char full_cmd[PATH_MAX] = "shell:/usr/bin/oprofile_command";
-
-    append_args(full_cmd, --argc, (const char**)++argv, PATH_MAX- 1);
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    int result = __sdb_command(full_cmd, extargv);
-
-    if(result < 0) {
-        return 1;
-    }
-    return 0;
-}
-
-int launch(int argc, char ** argv, void** extargv) {
-    int i;
-    int result = 0;
-    char pkgid[11] = {0,};
-    char exe[512] = {0,};
-    char args[512] = {0,};
-    int mode = 0;
-    int port = 0;
-    int pid = 0;
-    int type = 0;
-    char fullcommand[PATH_MAX] = {'s','h','e','l','l',':',};
-    char buf[128] = {0,};
-    char flag = 0;
-
-    if (argc < 7 || argc > 15 ) {
-        fprintf(stderr,"usage: sdb launch -p <pkgid> -e <executable> -m <run|debug> [-P <port>] [-attach <pid>] [-t <gtest,gcov>]  [<args...>]\n");
-        return -1;
-    }
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-p")) {
-            flag = 'p';
-            continue;
-        }
-        if (!strcmp(argv[i], "-e")) {
-            flag = 'e';
-            continue;
-        }
-        if (!strcmp(argv[i], "-m")) {
-            flag = 'm';
-            continue;
-        }
-        if (!strcmp(argv[i], "-P")) {
-            flag = 'P';
-            continue;
-        }
-        if (!strcmp(argv[i], "-t")) {
-            flag = 't';
-            continue;
-        }
-        if (!strcmp(argv[i], "-attach")) {
-            flag = 'a';
-            continue;
-        }
-        D("launch cmd args: %c : %s\n", flag, argv[i]);
-
-        switch (flag) {
-        case 'p' :
-            s_strncpy(pkgid, argv[i], sizeof(pkgid));
-            flag = 0;
-            break;
-        case 'e':
-            s_strncpy(exe, argv[i], sizeof(exe));
-            flag = 0;
-            break;
-        case 'm': {
-            if (!strcmp(argv[i], "run")) {
-                mode = 0;
-            } else if (!strcmp(argv[i], "debug")) {
-                mode = 1;
-            } else {
-                fprintf(stderr,"The -m option accepts arguments only run or debug options\n");
-                return -1;
-            }
-            flag = 0;
-            break;
-        }
-        case 'P': {
-            if (mode != 1) {
-                fprintf(stderr,"The -P option should be used in debug mode\n");
-                return -1;
-            }
-            port = atoi(argv[i]);
-            flag = 0;
-            break;
-        }
-        case 'a': {
-            if (mode != 1) {
-                fprintf(stderr, "The -attach option should be used in debug mode\n");
-                return -1;
-            }
-            pid = atoi(argv[i]);
-            flag = 0;
-            break;
-        }
-        case 't': {
-            char *str = argv[i];
-            for (; *str; str++) {
-                if (!memcmp(str, "gtest", 5)) {
-                    snprintf(buf, sizeof(buf), "export LD_LIBRARY_PATH=%s/gtest/usr/lib && ", SDK_TOOL_PATH);
-                    strncat(fullcommand, buf, sizeof(fullcommand) - 1);
-                    type = 1;
-                }
-                if (!memcmp(str, "gcov", 4)) {
-                    snprintf(buf, sizeof(buf), "export GCOV_PREFIX=/tmp/%s/data && export GCOV_PREFIX_STRIP=0 && ", pkgid);
-                    strncat(fullcommand, buf, sizeof(fullcommand) - 1);
-                    type = 2;
-                }
-                char *ptr = strstr(str, ",");
-                if (ptr) {
-                    str = ptr;
-                }
-            }
-            flag = 0;
-        }
-            break;
-        default : {
-            while (i < argc) {
-                strncat(args, " ", sizeof(args)-1);
-                strncat(args, argv[i], sizeof(args)-1);
-                i++;
-            }
-            break;
-        }
-        }
-    }
-
-    if (mode == 0) {
-        if (type == 0) {
-            snprintf(buf, sizeof(buf), "/usr/bin/launch_app %s.%s", pkgid, exe);
-            strncat(fullcommand, buf, sizeof(fullcommand)-1);
-        } else {
-            snprintf(buf, sizeof(buf), "%s/%s/bin/%s", APP_PATH_PREFIX, pkgid, exe);
-            strncat(fullcommand, buf, sizeof(fullcommand)-1);
-        }
-    } else if (mode == 1) {
-        if (verify_gdbserver_exist(extargv) < 0) {
-            return -1;
-        }
-        if (!port) {
-            fprintf(stderr,"The port number is not valid\n");
-            return -1;
-        }
-        if (pid) {
-            snprintf(buf, sizeof(buf), "%s/gdbserver/gdbserver :%d --attach %d", SDK_TOOL_PATH, port, pid);
-        } else {
-            snprintf(buf, sizeof(buf), "%s/gdbserver/gdbserver :%d %s/%s/bin/%s", SDK_TOOL_PATH, port, APP_PATH_PREFIX, pkgid, exe);
-        }
-        if (kill_gdbserver_if_running(buf, extargv) < 0) {
-            fprintf(stderr, "Gdbserver is already running on your target.\nAn gdb is going to connect the previous gdbserver process.\n");
-            return -1;
-        }
-        strncat(fullcommand, buf, sizeof(fullcommand)-1);
-    }
-    if (strlen(args) > 1) {
-        strncat(fullcommand, " ", sizeof(fullcommand)-1);
-        strncat(fullcommand, args, sizeof(fullcommand)-1);
-    }
-
-    D("launch command: [%s]\n", fullcommand);
-    result = __sdb_command(fullcommand, extargv);
-    sdb_close(result);
-
-    return result;
-}
-
-int devices(int argc, char ** argv, void** extargv) {
-    char *tmp;
-    char full_cmd[PATH_MAX];
-
-    snprintf(full_cmd, sizeof full_cmd, "host:%s", argv[0]);
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    tmp = sdb_query(full_cmd, extargv);
-    if(tmp) {
-        printf("List of devices attached \n");
-        printf("%s", tmp);
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-int __disconnect(int argc, char ** argv, void** extargv) {
-    char full_cmd[PATH_MAX];
-    char* tmp;
-
-    if (argc == 2) {
-        snprintf(full_cmd, sizeof full_cmd, "host:disconnect:%s", argv[1]);
-    } else {
-        snprintf(full_cmd, sizeof full_cmd, "host:disconnect:");
-    }
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    tmp = sdb_query(full_cmd, extargv);
-    if(tmp) {
-        printf("%s\n", tmp);
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-int __connect(int argc, char ** argv, void** extargv) {
-    char full_cmd[PATH_MAX];
-    char * tmp;
-    snprintf(full_cmd, sizeof full_cmd, "host:connect:%s", argv[1]);
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    tmp = sdb_query(full_cmd, extargv);
-    if(tmp) {
-        printf("%s\n", tmp);
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-int get_state_serialno(int argc, char ** argv, void** extargv) {
-    char* serial = (char *)extargv[0];
-    transport_type* ttype = (transport_type*)extargv[1];
-    char *tmp;
-    char full_cmd[PATH_MAX];
-
-    format_host_command(full_cmd, sizeof full_cmd, argv[0], *ttype, serial);
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    tmp = sdb_query(full_cmd, extargv);
-    if(tmp) {
-        printf("%s\n", tmp);
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-int root(int argc, char ** argv, void** extargv) {
-    char full_cmd[20];
-    snprintf(full_cmd, sizeof(full_cmd), "root:%s", argv[1]);
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    int fd = sdb_connect(full_cmd, extargv);
-
-    if(fd >= 0) {
-        read_and_dump(fd);
-        sdb_close(fd);
-        return 0;
-    }
-    return 1;
-}
-
-int status_window(int argc, char ** argv, void** extargv) {
-    char* serial = (char *)extargv[0];
-    transport_type* ttype = (transport_type*)extargv[1];
-
-    char full_cmd[PATH_MAX];
-    char *state = 0;
-    char *laststate = 0;
-
-        /* silence stderr (It means 2>/dev/null) */
-#ifdef _WIN32
-    /* XXX: TODO */
-#else
-    int  fd;
-    fd = unix_open("/dev/null", O_WRONLY);
-    dup2(fd, 2);
-    sdb_close(fd);
-#endif
-
-    format_host_command(full_cmd, sizeof full_cmd, "get-state", *ttype, serial);
-
-    for(;;) {
-        sdb_sleep_ms(250);
-
-        if(state) {
-            free(state);
-            state = 0;
-        }
-
-        D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-        state = sdb_query(full_cmd, extargv);
-
-        if(state) {
-            if(laststate && !strcmp(state,laststate)){
-                continue;
-            } else {
-                if(laststate) free(laststate);
-                laststate = strdup(state);
-            }
-        }
-
-        printf("%c[2J%c[2H", 27, 27);
-        printf("Samsung Development Bridge\n");
-        printf("State: %s\n", state ? state : "offline");
-        fflush(stdout);
-    }
-
-    return 0;
-}
-
-int kill_server(int argc, char ** argv, void** extargv) {
-    int fd;
-    fd = _sdb_connect("host:kill", extargv);
-    if(fd == -1) {
-        fprintf(stderr,"* server not running *\n");
-        return 1;
-    }
-    return 0;
-}
-
-int start_server(int argc, char ** argv, void** extargv) {
-    return sdb_connect("host:start-server", extargv);
-}
-
-int version(int argc, char ** argv, void** extargv) {
-    transport_type ttype = *(transport_type*)extargv[1];
-
-    if (ttype == kTransportUsb || ttype == kTransportLocal) {
-        char* VERSION_QUERY ="shell:rpm -qa | grep sdbd";
-        send_shellcommand(VERSION_QUERY, extargv);
-    } else {
-        fprintf(stdout, "Smart Development Bridge version %d.%d.%d\n",
-             SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_SERVER_VERSION);
-    }
-    return 0;
-}
-
-int forward(int argc, char ** argv, void** extargv) {
-    char* serial = (char *)extargv[0];
-    transport_type ttype = *(transport_type*)extargv[1];
-
-    char full_cmd[PATH_MAX];
-    char prefix[NAME_MAX];
-
-    get_host_prefix(prefix, NAME_MAX, ttype, serial, host);
-    snprintf(full_cmd, sizeof full_cmd, "%sforward:%s;%s",prefix, argv[1], argv[2]);
-
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    if(sdb_command(full_cmd, extargv) < 0) {
-        return 1;
-    }
-    return 0;
-}
-
-int dlog(int argc, char ** argv, void** extargv) {
-    D("dlog with serial: %s\n", (char*)extargv[0]);
-
-    char full_cmd[PATH_MAX] = "shell:/usr/bin/dlogutil";
-
-    int i;
-    for(i = 1; i<argc; i++) {
-        char quoted_string[MAX_INPUT];
-        dup_quote(quoted_string, argv[i], MAX_INPUT);
-
-        strncat(full_cmd, " ", sizeof(full_cmd)-1);
-        strncat(full_cmd, quoted_string, sizeof(full_cmd)-1);
-    }
-
-    send_shellcommand(full_cmd, extargv);
-    return 0;
-}
-
-int push(int argc, char ** argv, void** extargv) {
-    int i=0;
-    int utf8 = 0;
-
-    if(argc > 3 && !strcmp(argv[argc-1], "--with-utf8")) {
-        D("push with utf8");
-        utf8 = 1;
-        --argc;
-    }
-
-    for (i=1; i<argc-1; i++) {
-        do_sync_copy(argv[i], argv[argc-1], (FILE_FUNC*)&LOCAL_FILE_FUNC, (FILE_FUNC*)&REMOTE_FILE_FUNC, utf8, extargv);
-    }
-    return 0;
-}
-
-int pull(int argc, char ** argv, void** extargv) {
-    if (argc == 2) {
-        return do_sync_copy(argv[1], ".", (FILE_FUNC*)&REMOTE_FILE_FUNC, (FILE_FUNC*)&LOCAL_FILE_FUNC, 0, extargv);
-    }
-    return do_sync_copy(argv[1], argv[2], (FILE_FUNC*)&REMOTE_FILE_FUNC, (FILE_FUNC*)&LOCAL_FILE_FUNC, 0, extargv);
-}
-
-int shell(int argc, char ** argv, void** extargv) {
-    char buf[4096];
-
-        int r;
-        int fd;
-
-        if(argc < 2) {
-            D("starting interactive shell\n");
-            r = interactive_shell(extargv);
-            return r;
-        }
-
-        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
-        argc -= 2;
-        argv += 2;
-        while(argc-- > 0) {
-            strcat(buf, " ");
-
-            /* quote empty strings and strings with spaces */
-            int quote = (**argv == 0 || strchr(*argv, ' '));
-            if (quote)
-                strcat(buf, "\"");
-            strcat(buf, *argv++);
-            if (quote)
-                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;
-        }
-        return 1;
-}
-
-int forkserver(int argc, char** argv, void** extargv) {
-    if(!strcmp(argv[1], "server")) {
-        int r = sdb_main(1, get_server_port());
-        return r;
-    }
-    else {
-        fprintf(stderr,COMMANDLINE_ERROR_ARG_MISSING, "server", "forkserver");
-        return 1;
-    }
-}
-
-int install(int argc, char **argv, void** extargv) {
-
-    char* srcpath = argv[1];
-    const char* filename = sdb_dirstop(srcpath);
-
-    const char* args[2];
-    args[0] = DIR_APP_TMP;
-    char destination[PATH_MAX];
-    if (filename) {
-        filename++;
-        args[1] = filename;
-    } else {
-        args[1] = srcpath;
-    }
-    append_args(destination, 2, args, sizeof destination);
-
-    D("Install path%s\n", destination);
-    int tpk = get_pkgtype_file_name(srcpath);
-    if (tpk == -1) {
-        fprintf(stderr, "error: unknown package type\n");
-        return 1;
-    }
-
-    D("Push file: %s to %s\n", srcpath, destination);
-    int result = do_sync_copy(srcpath, destination, (FILE_FUNC*)&LOCAL_FILE_FUNC, (FILE_FUNC*)&REMOTE_FILE_FUNC, 0, extargv);
-
-    if(result < 0) {
-        return 1;
-    }
-
-    const char* SHELL_INSTALL_CMD ="shell:/usr/bin/pkgcmd -i -t %s -p %s -q";
-    char full_cmd[PATH_MAX];
-
-    if(tpk == 1) {
-        snprintf(full_cmd, sizeof full_cmd, SHELL_INSTALL_CMD, "tpk", destination);
-    }
-    else if(tpk == 0){
-        snprintf(full_cmd, sizeof full_cmd, SHELL_INSTALL_CMD, "wgt", destination);
-    }
-
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    result = __sdb_command(full_cmd, extargv);
-
-    if(result < 0) {
-        return 1;
-    }
-
-    const char* SHELL_REMOVE_CMD = "shell:rm %s";
-    snprintf(full_cmd, sizeof full_cmd, SHELL_REMOVE_CMD, destination);
-    D(COMMANDLINE_MSG_FULL_CMD, "remove", full_cmd);
-    result = __sdb_command(full_cmd, extargv);
-
-    if(result < 0) {
-        return 1;
-    }
-
-    return 0;
-}
-
-int uninstall(int argc, char **argv, void** extargv) {
-    char* appid = argv[1];
-    const char* SHELL_UNINSTALL_CMD ="shell:/usr/bin/pkgcmd -u -t %s -n %s -q";
-    char full_cmd[PATH_MAX];
-    int result = 0;
-    int tpk = get_pkgtype_from_app_id(appid, extargv);
-    if(tpk == 1) {
-        snprintf(full_cmd, sizeof full_cmd, SHELL_UNINSTALL_CMD, "tpk", appid);
-    }
-    else if(tpk == 0){
-        snprintf(full_cmd, sizeof full_cmd, SHELL_UNINSTALL_CMD, "wgt", appid);
-    }
-    else {
-        return 1;
-    }
-    D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd);
-    result = __sdb_command(full_cmd, extargv);
-
-    if(result < 0) {
-        return 1;
-    }
-
-    return 0;
-}
-
-// Returns 0 if pkg type is wgt. Returns 1 if pkg type is tpk. Returns minus if exception happens.
-static int get_pkgtype_file_name(const char* file_name) {
-
-    char* pkg_type;
-
-    int result = -1;
-
-    pkg_type = strrchr(file_name, '.')+1;
-    if (pkg_type != NULL) {
-        if(!strcmp(pkg_type, "wgt")) {
-            result = 0;
-        }
-        else if(!strcmp(pkg_type, "tpk")) {
-            result = 1;
-        }
-    }
-
-    return result;
-}
-
-// Returns 0 if pkg type is wgt. Returns 1 if pkg type is tpk. Returns minus if exception happens.
-static int get_pkgtype_from_app_id(const char* app_id, void** extargv) {
-
-    char* GET_PKG_TYPE_CMD = "shell:/usr/bin/pkgcmd -l | grep %s | awk '{print $2}'";
-    char full_cmd[PATH_MAX];
-    snprintf(full_cmd, sizeof full_cmd, GET_PKG_TYPE_CMD, app_id);
-
-    int result = sdb_connect(full_cmd, extargv);
-    if(result < 0) {
-        return result;
-    }
-    char buf[100] = "";
-
-    int rl_result = read_line(result, buf, 100);
-    if(rl_result < 0) {
-        D("Error to read buffer (fd=%d)\n", rl_result);
-        return rl_result;
-    }
-
-    sdb_close(result);
-    result = -1;
-
-    if(strstr(buf, "[tpk]") != NULL) {
-        result = 1;
-    } else if(strstr(buf, "[wgt]") != NULL) {
-        result = 0;
-    }
-    return result;
-}
-
-
-/*
- * kill gdbserver if running
- */
-
-static int kill_gdbserver_if_running(const char* process_cmd, void** extargv) {
-    char cmd[512] = {};
-    char buf[512] = {};
-
-    // hopefully, it is not going to happen, but check executable gdbserver is existed
-    snprintf(cmd, sizeof(cmd), "shell:/usr/bin/da_command process | grep '%s' | grep -v grep | wc -l", process_cmd);
-    int result = sdb_connect(cmd, extargv);
-
-    if(result < 0) {
-        return -1;
-    }
-    if (read_line(result, buf, sizeof(buf)) < 0) {
-        sdb_close(result);
-        return -1;
-    }
-    if(memcmp(buf, "0", 1)) {
-/*
-        // TODO: check cmd return code
-        snprintf(cmd, sizeof(cmd), "shell:/usr/bin/da_command killapp '%s'", process_cmd);
-        result = sdb_connect(cmd);
-        if (read_line(result, buf, sizeof(buf)) < 0) {
-            sdb_close(result);
-            return -1;
-        }
-*/
-    }
-    sdb_close(result);
-    return 1;
-}
-
-static void __inline__ format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
-{
-    char prefix[NAME_MAX];
-    get_host_prefix(prefix, NAME_MAX, ttype, serial, host);
-    snprintf(buffer, buflen, "%s%s", prefix, command);
-}
-
-
-/*
- * returns -1 if gdbserver exists
- */
-static int verify_gdbserver_exist(void** extargv) {
-    char cmd[512] = {};
-    char buf[512] = {};
-
-    snprintf(cmd, sizeof(cmd), "shell:%s/gdbserver/gdbserver --version 1>/dev/null", SDK_TOOL_PATH);
-    int result = sdb_connect(cmd, extargv);
-
-    if(result < 0) {
-        sdb_close(result);
-        return -1;
-    }
-    if (read_line(result, buf, sizeof(buf)) > 0) {
-        fprintf(stderr, "error: %s\n", buf);
-        sdb_close(result);
-        return -1;
-    }
-    sdb_close(result);
-    return result;
-}
diff --git a/src/command_function.h b/src/command_function.h
deleted file mode 100644 (file)
index 92e71ae..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* 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 COMMAND_FUNCTION_H_
-#define COMMAND_FUNCTION_H_
-
-#define  TRACE_TAG  TRACE_SDB
-
-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 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);
-int start_server(int argc, char ** argv, void** extargv);
-int kill_server(int argc, char ** argv, void** extargv);
-int version(int argc, char ** argv, void** extargv);
-int forward(int argc, char ** argv, void** extargv);
-int push(int argc, char ** argv, void** extargv);
-int pull(int argc, char ** argv, void** extargv);
-int dlog(int argc, char ** argv, void** extargv);
-int install(int argc, char **argv, void** extargv);
-int uninstall(int argc, char **argv, void** extargv);
-int forkserver(int argc, char** argv, void** extargv);
-int shell(int argc, char ** argv, void** extargv);
-
-#endif /* COMMAND_FUNCTION_H_ */
index fafae79e23329020b78d788f6200a7b2ae33d60f..400525b8561cb070c7ed0375c8b31bfd6bf0142c 100755 (executable)
 #include <ctype.h>
 #include <assert.h>
 
-#define  TRACE_TAG  TRACE_SDB
-
-#include "fdevent.h"
+#include "sysdeps.h"
 #include "strutils.h"
 
 #ifdef HAVE_TERMIO_H
 #include <termios.h>
 #endif
-#include "utils.h"
+
+#define  TRACE_TAG  TRACE_SDB
 #include "sdb.h"
 #include "sdb_client.h"
 #include "file_sync_service.h"
+#include "utils.h"
+
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
 
+void get_my_path(char *s, size_t maxLen);
+int find_sync_dirs(const char *srcarg,
+        char **android_srcdir_out, char **data_srcdir_out);
+int install_app(transport_type transport, char* serial, int argc, char** argv);
+int uninstall_app_sdb(const char *app_id);
+int install_app_sdb(const char *srcpath);
+int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
+int get_pkgtype_file_name(const char* file_name);
+int get_pkgtype_from_app_id(const char* app_id);
+int sdb_command2(const char* cmd);
+int launch_app(transport_type transport, char* serial, int argc, char** argv);
+void version_sdbd(transport_type ttype, char* serial);
+int verify_gdbserver_exist();
+int kill_gdbserver_if_running();
+
+static const char *gProductOutPath = NULL;
+static const char *APP_PATH_PREFIX="/opt/apps";
+static const char *SDK_TOOL_PATH="/home/developer/sdk_tools";
+
+static char *product_file(const char *extra)
+{
+    int n;
+    char *x;
 
-#include "linkedlist.h"
-#include "sdb_constants.h"
-#include "sdb_model.h"
-#include "commandline.h"
-#include "command_function.h"
+    if (gProductOutPath == NULL) {
+        fprintf(stderr, "sdb: Product directory not specified; "
+                "use -p or define ANDROID_PRODUCT_OUT\n");
+        exit(1);
+    }
 
-static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist);
-static void create_opt_list(LIST_NODE** opt_list);
-static void create_cmd_list(LIST_NODE** cmd_list);
-static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
+    n = strlen(gProductOutPath) + strlen(extra) + 2;
+    x = malloc(n);
+    if (x == 0) {
+        fprintf(stderr, "sdb: Out of memory (product_file())\n");
+        exit(1);
+    }
 
-#ifdef HAVE_TERMIO_H
+    snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
+    return x;
+}
+
+void version(FILE * out) {
+    fprintf(out, "Smart Development Bridge version %d.%d.%d\n",
+         SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_SERVER_VERSION);
+}
+
+void help()
+{
+    version(stderr);
+
+    fprintf(stderr,
+    "\n"
+    " Usage : sdb [option] <command> [parameters]\n"
+        "\n"
+    " options:\n"
+    " -d                            - direct command to the only connected USB device\n"
+    "                                 return an error if more than one USB device is present.\n"
+    " -e                            - direct command to the only running emulator.\n"
+    "                                 return an error if more than one emulator is running.\n"
+    " -s <serial number>            - direct command to the USB device or emulator with\n"
+    "                                 the given serial number.\n"
+    " devices                       - list all connected devices\n"
+    " connect <host>[:<port>]       - connect to a device via TCP/IP\n"
+    "                                 Port 26101 is used by default if no port number is specified.\n"
+    " disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.\n"
+    "                                 Port 26101 is used by default if no port number is specified.\n"
+    "                                 Using this command with no additional arguments\n"
+    "                                 will disconnect from all connected TCP/IP devices.\n"
+    "\n"
+    " commands:\n"
+    "  sdb push <local> <remote> [--with-utf8]\n"
+    "                               - copy file/dir to device\n"
+    "                                 (--with-utf8 means to create the remote file with utf-8 character encoding)\n"
+    "  sdb pull <remote> [<local>]  - copy file/dir from device\n"
+    "  sdb shell                    - run remote shell interactively\n"
+    "  sdb shell <command>          - run remote shell \n"
+    "  sdb dlog [<filter-spec>]     - view device log\n"
+    "  sdb install <pkg_path>       - push package file and install it\n"
+    "  sdb uninstall <appid>        - uninstall this app from the device\n"
+    "  sdb forward <local> <remote> - forward socket connections\n"
+
+    "                                 forward spec is : \n"
+    "                                   tcp:<port>\n"
+    "  sdb help                     - show this help message\n"
+    "  sdb version                  - show version num\n"
+    "\n"
+    "  sdb start-server             - ensure that there is a server running\n"
+    "  sdb kill-server              - kill the server if it is running\n"
+    "  sdb get-state                - print: offline | bootloader | device\n"
+    "  sdb get-serialno             - print: <serial-number>\n"
+    "  sdb status-window            - continuously print device status for a specified device\n"
+//    "  sdb usb                      - restarts the sdbd daemon listing on USB\n"
+//    "  sdb tcpip                    - restarts the sdbd daemon listing on TCP\n"
+    "  sdb root <on|off>            - switch to root or developer account mode\n"
+    "                                 'on' means to root mode, and vice versa"
+    "\n"
+        );
+}
+
+int usage()
+{
+    help();
+    return 1;
+}
 
-static __inline__ void stdin_raw_init(int fd, struct termios* tio_save);
-static __inline__ void stdin_raw_restore(int fd, struct termios* tio_save);
+#ifdef HAVE_TERMIO_H
+static struct termios tio_save;
 
-static __inline__ void stdin_raw_init(int fd, struct termios* tio_save)
+static void stdin_raw_init(int fd)
 {
     struct termios tio;
 
     if(tcgetattr(fd, &tio)) return;
-    memcpy(tio_save, &tio, sizeof(struct termios));
+    if(tcgetattr(fd, &tio_save)) return;
 
     tio.c_lflag = 0; /* disable CANON, ECHO*, etc */
 
@@ -73,21 +166,21 @@ static __inline__ void stdin_raw_init(int fd, struct termios* tio_save)
     tcflush(fd, TCIFLUSH);
 }
 
-static __inline__ void stdin_raw_restore(int fd, struct termios* tio_save)
+static void stdin_raw_restore(int fd)
 {
-    tcsetattr(fd, TCSANOW, tio_save);
+    tcsetattr(fd, TCSANOW, &tio_save);
     tcflush(fd, TCIFLUSH);
 }
 #endif
 
-void read_and_dump(int fd)
+static void read_and_dump(int fd)
 {
-    char buf[PATH_MAX];
+    char buf[4096];
     int len;
 
     while(fd >= 0) {
         D("read_and_dump(): pre sdb_read(fd=%d)\n", fd);
-        len = sdb_read(fd, buf, PATH_MAX);
+        len = sdb_read(fd, buf, 4096);
         D("read_and_dump(): post sdb_read(fd=%d): len=%d\n", fd, len);
         if(len == 0) {
             break;
@@ -102,43 +195,77 @@ void read_and_dump(int fd)
     }
 }
 
+static void copy_to_file(int inFd, int outFd) {
+    const size_t BUFSIZE = 32 * 1024;
+    char* buf = (char*) malloc(BUFSIZE);
+    int len;
+    long total = 0;
+
+    D("copy_to_file(%d -> %d)\n", inFd, outFd);
+    for (;;) {
+        len = sdb_read(inFd, buf, BUFSIZE);
+        if (len == 0) {
+            D("copy_to_file() : read 0 bytes; exiting\n");
+            break;
+        }
+        if (len < 0) {
+            if (errno == EINTR) {
+                D("copy_to_file() : EINTR, retrying\n");
+                continue;
+            }
+            D("copy_to_file() : error %d\n", errno);
+            break;
+        }
+        sdb_write(outFd, buf, len);
+        total += len;
+    }
+    D("copy_to_file() finished after %lu bytes\n", total);
+    free(buf);
+}
+
 static void *stdin_read_thread(void *x)
 {
+    int fd, fdi;
     unsigned char buf[1024];
     int r, n;
+    int state = 0;
+
+    int *fds = (int*) x;
+    fd = fds[0];
+    fdi = fds[1];
+    free(fds);
 
-    void** args = (void**) x;
-    int fd = *(int*)args[0];
-#ifdef HAVE_TERMIO_H
-    struct termios* tio_save = args[1];
-#endif
-    free(args[0]);
-    free(args);
     for(;;) {
         /* fdi is really the client's stdin, so use read, not sdb_read here */
-        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", INPUT_FD);
-        r = unix_read(INPUT_FD, buf, 1024);
-        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", INPUT_FD);
+        D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
+        r = unix_read(fdi, buf, 1024);
+        D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
         if(r == 0) break;
         if(r < 0) {
             if(errno == EINTR) continue;
             break;
         }
         for(n = 0; n < r; n++){
-            if(buf[n] == '\n' || buf[n] == '\r') {
-                n++;
-                if(buf[n] == '~') {
-                    n++;
-                    if(buf[n] == '.') {
-                        fprintf(stderr,"\n* disconnect *\n");
+            switch(buf[n]) {
+            case '\n':
+                state = 1;
+                break;
+            case '\r':
+                state = 1;
+                break;
+            case '~':
+                if(state == 1) state++;
+                break;
+            case '.':
+                if(state == 2) {
+                    fprintf(stderr,"\n* disconnect *\n");
 #ifdef HAVE_TERMIO_H
-                    stdin_raw_restore(INPUT_FD, tio_save);
-                    free(tio_save);
+                    stdin_raw_restore(fdi);
 #endif
-                    free(args);
                     exit(0);
-                    }
                 }
+            default:
+                state = 0;
             }
         }
         r = sdb_write(fd, buf, r);
@@ -149,406 +276,1715 @@ static void *stdin_read_thread(void *x)
     return 0;
 }
 
-int interactive_shell(void** extargv)
+int interactive_shell(void)
 {
     sdb_thread_t thr;
+    int fdi, fd;
+    int *fds;
 
-    int fd = sdb_connect("shell:", extargv);
+    fd = sdb_connect("shell:");
     if(fd < 0) {
+        fprintf(stderr,"error: %s\n", sdb_error());
         return 1;
     }
-    int* fd_p = malloc(sizeof(int));
-    *fd_p = fd;
+    fdi = 0; //dup(0);
+
+    fds = malloc(sizeof(int) * 2);
+    fds[0] = fd;
+    fds[1] = fdi;
 
 #ifdef HAVE_TERMIO_H
-    void** args = (void**)malloc(sizeof(void*)*2);
-    struct termios tio_save;
-    stdin_raw_init(INPUT_FD, &tio_save);
-    struct termios* tio_save_p = (struct termios*)malloc(sizeof(struct termios));
-    memcpy(tio_save_p, &tio_save, sizeof(struct termios));
-    args[1] = tio_save_p;
-#else
-    void** args = (void**)malloc(sizeof(void*));
+    stdin_raw_init(fdi);
 #endif
-    args[0] = fd_p;
-    sdb_thread_create(&thr, stdin_read_thread, args);
+    sdb_thread_create(&thr, stdin_read_thread, fds);
     read_and_dump(fd);
 #ifdef HAVE_TERMIO_H
-    stdin_raw_restore(INPUT_FD, &tio_save);
+    stdin_raw_restore(fdi);
 #endif
     return 0;
 }
 
-int send_shellcommand(char* buf, void** extargv)
+
+static void format_host_command(char* buffer, size_t  buflen, const char* command, transport_type ttype, const char* serial)
 {
-    int fd, ret;
-    char* serial = (char *)extargv[0];
-    transport_type ttype = *(transport_type*)extargv[1];
+    if (serial) {
+        snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
+    } else {
+        const char* prefix = "host";
+        if (ttype == kTransportUsb)
+            prefix = "host-usb";
+        else if (ttype == kTransportLocal)
+            prefix = "host-local";
 
-    for(;;) {
-        fd = sdb_connect(buf, extargv);
-        if(fd >= 0)
-            break;
-        fprintf(stderr,"- waiting for device -\n");
-        sdb_sleep_ms(1000);
-        do_cmd(ttype, serial, "wait-for-device", 0);
+        snprintf(buffer, buflen, "%s:%s", prefix, command);
     }
+}
+#if 0 /* tizen specific */
+int sdb_download_buffer(const char *service, const void* data, int sz,
+                        unsigned progress)
+{
+    char buf[4096];
+    unsigned total;
+    int fd;
+    const unsigned char *ptr;
 
-    read_and_dump(fd);
-    ret = sdb_close(fd);
-    if (ret)
-        perror("close");
+    sprintf(buf,"%s:%d", service, sz);
+    fd = sdb_connect(buf);
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", sdb_error());
+        return -1;
+    }
 
-    return ret;
-}
+    int opt = CHUNK_SIZE;
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
 
-static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
-{
-    char *argv[16];
-    int argc;
-    va_list ap;
+    total = sz;
+    ptr = data;
 
-    va_start(ap, cmd);
-    argc = 0;
+    if(progress) {
+        char *x = strrchr(service, ':');
+        if(x) service = x + 1;
+    }
 
-    if (serial) {
-        argv[argc++] = "-s";
-        argv[argc++] = serial;
-    } else if (ttype == kTransportUsb) {
-        argv[argc++] = "-d";
-    } else if (ttype == kTransportLocal) {
-        argv[argc++] = "-e";
+    while(sz > 0) {
+        unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
+        if(writex(fd, ptr, xfer)) {
+            sdb_status(fd);
+            fprintf(stderr,"* failed to write data '%s' *\n", sdb_error());
+            return -1;
+        }
+        sz -= xfer;
+        ptr += xfer;
+        if(progress) {
+            printf("sending: '%s' %4d%%    \r", service, (int)(100LL - ((100LL * sz) / (total))));
+            fflush(stdout);
+        }
+    }
+    if(progress) {
+        printf("\n");
     }
 
-    argv[argc++] = cmd;
-    while((argv[argc] = va_arg(ap, char*)) != 0) {
-        argc++;
+    if(readx(fd, buf, 4)){
+        fprintf(stderr,"* error reading response *\n");
+        sdb_close(fd);
+        return -1;
+    }
+    if(memcmp(buf, "OKAY", 4)) {
+        buf[4] = 0;
+        fprintf(stderr,"* error response '%s' *\n", buf);
+        sdb_close(fd);
+        return -1;
     }
-    va_end(ap);
 
-#if 0
-    int n;
-    fprintf(stderr,"argc = %d\n",argc);
-    for(n = 0; n < argc; n++) {
-        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
+    sdb_close(fd);
+    return 0;
+}
+
+int sdb_download(const char *service, const char *fn, unsigned progress)
+{
+    void *data;
+    unsigned sz;
+
+    data = load_file(fn, &sz);
+    if(data == 0) {
+        fprintf(stderr,"* cannot read '%s' *\n", service);
+        return -1;
     }
+
+    int status = sdb_download_buffer(service, data, sz, progress);
+    free(data);
+    return status;
+}
+#endif
+static void status_window(transport_type ttype, const char* serial)
+{
+    char command[4096];
+    char *state = 0;
+    char *laststate = 0;
+
+        /* silence stderr */
+#ifdef _WIN32
+    /* XXX: TODO */
+#else
+    int  fd;
+    fd = unix_open("/dev/null", O_WRONLY);
+    dup2(fd, 2);
+    sdb_close(fd);
 #endif
 
-    return process_cmdline(argc, argv);
+    format_host_command(command, sizeof command, "get-state", ttype, serial);
+
+    for(;;) {
+        sdb_sleep_ms(250);
+
+        if(state) {
+            free(state);
+            state = 0;
+        }
+
+        state = sdb_query(command);
+
+        if(state) {
+            if(laststate && !strcmp(state,laststate)){
+                continue;
+            } else {
+                if(laststate) free(laststate);
+                laststate = strdup(state);
+            }
+        }
+
+        printf("%c[2J%c[2H", 27, 27);
+        printf("Samsung Development Bridge\n");
+        printf("State: %s\n", state ? state : "offline");
+        fflush(stdout);
+    }
 }
 
-int __sdb_command(const char* cmd, void** extargv) {
-    int result = sdb_connect(cmd, extargv);
+/** duplicate string and quote all \ " ( ) chars + space character. */
+static char *
+dupAndQuote(const char *s)
+{
+    const char *ts;
+    size_t alloc_len;
+    char *ret;
+    char *dest;
 
-    if(result < 0) {
-        return result;
+    ts = s;
+
+    alloc_len = 0;
+
+    for( ;*ts != '\0'; ts++) {
+        alloc_len++;
+        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+            alloc_len++;
+        }
     }
 
-    D("about to read_and_dump(fd=%d)\n", result);
-    read_and_dump(result);
-    D("read_and_dump() done.\n");
-    sdb_close(result);
+    ret = (char *)malloc(alloc_len + 1);
 
-    return 0;
+    ts = s;
+    dest = ret;
+
+    for ( ;*ts != '\0'; ts++) {
+        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+            *dest++ = '\\';
+        }
+
+        *dest++ = *ts;
+    }
+
+    *dest++ = '\0';
+
+    return ret;
 }
 
-const char* get_basename(const char* filename)
+/**
+ * Run ppp in "notty" mode against a resource listed as the first parameter
+ * eg:
+ *
+ * ppp dev:/dev/omap_csmi_tty0 <ppp options>
+ *
+ */
+int ppp(int argc, char **argv)
 {
-    const char* basename = sdb_dirstop(filename);
-    if (basename) {
-        basename++;
-        return basename;
-    } else {
-        return filename;
+#ifdef HAVE_WIN32_PROC
+    fprintf(stderr, "error: sdb %s not implemented on Win32\n", argv[0]);
+    return -1;
+#else
+    char *sdb_service_name;
+    pid_t pid;
+    int fd;
+
+    if (argc < 2) {
+        fprintf(stderr, "usage: sdb %s <sdb service name> [ppp opts]\n",
+                argv[0]);
+
+        return 1;
     }
-}
 
-int __inline__ get_server_port() {
-    return DEFAULT_SDB_PORT;
-}
+    sdb_service_name = argv[1];
+
+    fd = sdb_connect(sdb_service_name);
+
+    if(fd < 0) {
+        fprintf(stderr,"Error: Could not open sdb service: %s. Error: %s\n",
+                sdb_service_name, sdb_error());
+        return 1;
+    }
+
+    pid = fork();
 
-static void create_opt_list(LIST_NODE** opt_list) {
+    if (pid < 0) {
+        perror("from fork()");
+        return 1;
+    } else if (pid == 0) {
+        int err;
+        int i;
+        const char **ppp_args;
+
+        // copy args
+        ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
+        ppp_args[0] = "pppd";
+        for (i = 2 ; i < argc ; i++) {
+            //argv[2] and beyond become ppp_args[1] and beyond
+            ppp_args[i - 1] = argv[i];
+        }
+        ppp_args[i-1] = NULL;
 
-    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);
+        // child side
 
-    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);
+        dup2(fd, STDIN_FILENO);
+        dup2(fd, STDOUT_FILENO);
+        sdb_close(STDERR_FILENO);
+        sdb_close(fd);
 
-    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);
-}
-
-static void create_cmd_list(LIST_NODE** cmd_list) {
+        err = execvp("pppd", (char * const *)ppp_args);
 
-    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);
-
-    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);
-
-    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);
+        if (err < 0) {
+            perror("execing pppd");
+        }
+        exit(-1);
+    } else {
+        // parent side
 
-    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);
+        sdb_close(fd);
+        return 0;
+    }
+#endif /* !HAVE_WIN32_PROC */
+}
 
-    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);
+static int send_shellcommand(transport_type transport, char* serial, char* buf)
+{
+    int fd, ret;
 
-    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);
+    for(;;) {
+        fd = sdb_connect(buf);
+        if(fd >= 0)
+            break;
+        fprintf(stderr,"- waiting for device -\n");
+        sdb_sleep_ms(1000);
+        do_cmd(transport, serial, "wait-for-device", 0);
+    }
 
-    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);
+    read_and_dump(fd);
+    ret = sdb_close(fd);
+    if (ret)
+        perror("close");
 
-    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);
+    return ret;
+}
 
-    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);
+static int logcat(transport_type transport, char* serial, int argc, char **argv)
+{
+    char buf[4096];
 
-    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);
+    snprintf(buf, sizeof(buf),
+        "shell:/usr/bin/dlogutil");
 
-    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);
+/*
+    if (!strcmp(argv[0],"longcat")) {
+        strncat(buf, " -v long", sizeof(buf)-1);
+    }
+*/
 
-    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);
+    argc -= 1;
+    argv += 1;
+    while(argc-- > 0) {
+        char *quoted;
 
-    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);
+        quoted = dupAndQuote (*argv++);
 
-    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);
+        strncat(buf, " ", sizeof(buf)-1);
+        strncat(buf, quoted, sizeof(buf)-1);
+        free(quoted);
+    }
 
-    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);
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
 
-    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);
-
-    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);
-
-    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);
-
-    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);
-
-    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);
-
-    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);
-
-    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 );
-}
-
-int process_cmdline(int argc, char** argv) {
+static int mkdirs(char *path)
+{
+    int ret;
+    char *x = path + 1;
 
-    transport_type ttype = kTransportAny;
-    char* serial = NULL;
+    for(;;) {
+        x = sdb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        ret = sdb_mkdir(path, 0775);
+        *x = OS_PATH_SEPARATOR;
+        if((ret < 0) && (errno != EEXIST)) {
+            return ret;
+        }
+        x++;
+    }
+    return 0;
+}
 
-    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
+static int backup(int argc, char** argv) {
+    char buf[4096];
+    char default_name[32];
+    const char* filename = strcpy(default_name, "./backup.ab");
+    int fd, outFd;
+    int i, j;
+
+    /* find, extract, and use any -f argument */
+    for (i = 1; i < argc; i++) {
+        if (!strcmp("-f", argv[i])) {
+            if (i == argc-1) {
+                fprintf(stderr, "sdb: -f passed with no filename\n");
+                return usage();
+            }
+            filename = argv[i+1];
+            for (j = i+2; j <= argc; ) {
+                argv[i++] = argv[j++];
+            }
+            argc -= 2;
+            argv[argc] = NULL;
+        }
+    }
+
+    /* bare "sdb backup" or "sdb backup -f filename" are not valid invocations */
+    if (argc < 2) return usage();
 
-    LIST_NODE* cmd_list = NULL;
-    LIST_NODE* opt_list = NULL;
-    LIST_NODE* input_opt_list = NULL;
+    sdb_unlink(filename);
+    mkdirs((char *)filename);
+    outFd = sdb_creat(filename, 0640);
+    if (outFd < 0) {
+        fprintf(stderr, "sdb: unable to open file %s\n", filename);
+        return -1;
+    }
 
-    create_cmd_list(&cmd_list);
-    create_opt_list(&opt_list);
-    int parsed_argc = parse_opt(argc, argv, opt_list, &input_opt_list);
+    snprintf(buf, sizeof(buf), "backup");
+    for (argc--, argv++; argc; argc--, argv++) {
+        strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
+        strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
+    }
 
-    if(parsed_argc < 0) {
+    D("backup. filename=%s buf=%s\n", filename, buf);
+    fd = sdb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "sdb: unable to connect for backup\n");
+        sdb_close(outFd);
         return -1;
     }
 
-    D("Parsed %d arguments\n", parsed_argc);
+    printf("Now unlock your device and confirm the backup operation.\n");
+    copy_to_file(fd, outFd);
 
-    argc = argc - parsed_argc;
-    argv = argv + parsed_argc;
+    sdb_close(fd);
+    sdb_close(outFd);
+    return 0;
+}
 
-    int server_port = get_server_port();
-    void* extraarg[3];
-    extraarg[2] = &server_port;
+static int restore(int argc, char** argv) {
+    const char* filename;
+    int fd, tarFd;
 
-    INPUT_OPTION* opt_s = get_inputopt(input_opt_list, (char*)COMMANDLINE_SERIAL_SHORT_OPT);
-    if(opt_s != NULL) {
-        serial = opt_s->value;
+    if (argc != 2) return usage();
 
-        char buf[PATH_MAX];
-        char *tmp;
-        snprintf(buf, sizeof(buf), "host:serial-match:%s", serial);
+    filename = argv[1];
+    tarFd = sdb_open(filename, O_RDONLY);
+    if (tarFd < 0) {
+        fprintf(stderr, "sdb: unable to open file %s\n", filename);
+        return -1;
+    }
+
+    fd = sdb_connect("restore:");
+    if (fd < 0) {
+        fprintf(stderr, "sdb: unable to connect for backup\n");
+        sdb_close(tarFd);
+        return -1;
+    }
 
+    printf("Now unlock your device and confirm the restore operation.\n");
+    copy_to_file(tarFd, fd);
 
-        tmp = sdb_query(buf, extraarg);
-        if (tmp) {
-            serial = strdup(tmp);
+    sdb_close(fd);
+    sdb_close(tarFd);
+    return 0;
+}
+
+#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
+static int top_works(const char *top)
+{
+    if (top != NULL && sdb_is_absolute_host_path(top)) {
+        char path_buf[PATH_MAX];
+        snprintf(path_buf, sizeof(path_buf),
+                "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
+        return access(path_buf, F_OK) == 0;
+    }
+    return 0;
+}
+
+static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
+{
+    strcpy(path_buf, indir);
+    while (1) {
+        if (top_works(path_buf)) {
+            return path_buf;
+        }
+        char *s = sdb_dirstop(path_buf);
+        if (s != NULL) {
+            *s = '\0';
         } else {
-            fprintf(stderr, "wrong serial number '%s'\n", serial);
-            return 1;
+            path_buf[0] = '\0';
+            return NULL;
         }
     }
-    else {
-        INPUT_OPTION* opt_d = get_inputopt(input_opt_list, (char*)COMMANDLINE_DEVICE_SHORT_OPT);
-        if(opt_d != NULL) {
-            ttype = kTransportUsb;
+}
+
+static char *find_top(char path_buf[PATH_MAX])
+{
+    char *top = getenv("ANDROID_BUILD_TOP");
+    if (top != NULL && top[0] != '\0') {
+        if (!top_works(top)) {
+            fprintf(stderr, "sdb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
+            return NULL;
         }
-        else {
-            INPUT_OPTION* opt_e = get_inputopt(input_opt_list, (char*)COMMANDLINE_EMULATOR_SHORT_OPT);
-            if(opt_e != NULL) {
-                ttype = kTransportLocal;
+    } else {
+        top = getenv("TOP");
+        if (top != NULL && top[0] != '\0') {
+            if (!top_works(top)) {
+                fprintf(stderr, "sdb: bad TOP value \"%s\"\n", top);
+                return NULL;
             }
+        } else {
+            top = NULL;
         }
     }
 
-    if(argc > 0) {
-        if(!strcmp(argv[0], COMMANDLINE_HELP_NAME)) {
-            print_help(opt_list, cmd_list);
-            return 1;
-        }
-        COMMAND* command = get_command(cmd_list, argv[0]);
+    if (top != NULL) {
+        /* The environment pointed to a top directory that works.
+         */
+        strcpy(path_buf, top);
+        return path_buf;
+    }
 
-        D("process command: %s\n", command->name);
-        int minargs = command->minargs;
-        int maxargs = command->maxargs;
+    /* The environment didn't help.  Walk up the tree from the CWD
+     * to see if we can find the top.
+     */
+    char dir[PATH_MAX];
+    top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
+    if (top == NULL) {
+        /* If the CWD isn't under a good-looking top, see if the
+         * executable is.
+         */
+        get_my_path(dir, PATH_MAX);
+        top = find_top_from(dir, path_buf);
+    }
+    return top;
+}
 
-        if(argc < minargs + 1) {
-            fprintf(stderr, "%s command has following args: %s, and it require at least %d arguments\n", argv[0],  command->argdesc, minargs);
-            return 1;
+/* <hint> may be:
+ * - A simple product name
+ *   e.g., "sooner"
+TODO: debug?  sooner-debug, sooner:debug?
+ * - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
+ *   e.g., "out/target/product/sooner"
+ * - An absolute path to the PRODUCT_OUT dir
+ *   e.g., "/src/device/out/target/product/sooner"
+ *
+ * Given <hint>, try to construct an absolute path to the
+ * ANDROID_PRODUCT_OUT dir.
+ */
+static const char *find_product_out_path(const char *hint)
+{
+    static char path_buf[PATH_MAX];
+
+    if (hint == NULL || hint[0] == '\0') {
+        return NULL;
+    }
+
+    /* If it's already absolute, don't bother doing any work.
+     */
+    if (sdb_is_absolute_host_path(hint)) {
+        strcpy(path_buf, hint);
+        return path_buf;
+    }
+
+    /* If there are any slashes in it, assume it's a relative path;
+     * make it absolute.
+     */
+    if (sdb_dirstart(hint) != NULL) {
+        if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
+            fprintf(stderr, "sdb: Couldn't get CWD: %s\n", strerror(errno));
+            return NULL;
         }
-        if(argc > maxargs + 1 && maxargs > -1) {
-            fprintf(stderr, "command %s require at most %d arguments\n", argv[0], maxargs);
-            return 1;
+        if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
+            fprintf(stderr, "sdb: Couldn't assemble path\n");
+            return NULL;
         }
-        extraarg[0] = serial;
-        extraarg[1] = &ttype;
-        int (*Func)(int, char**, void**) = command->Func;
-        free_list(cmd_list, NULL);
-        free_list(input_opt_list, NULL);
-        free_list(opt_list, NULL);
-        return Func(argc, argv, extraarg);
+        strcat(path_buf, OS_PATH_SEPARATOR_STR);
+        strcat(path_buf, hint);
+        return path_buf;
     }
 
-    print_help(opt_list, cmd_list);
-    return 1;
+    /* It's a string without any slashes.  Try to do something with it.
+     *
+     * Try to find the root of the build tree, and build a PRODUCT_OUT
+     * path from there.
+     */
+    char top_buf[PATH_MAX];
+    const char *top = find_top(top_buf);
+    if (top == NULL) {
+        fprintf(stderr, "sdb: Couldn't find top of build tree\n");
+        return NULL;
+    }
+//TODO: if we have a way to indicate debug, look in out/debug/target/...
+    snprintf(path_buf, sizeof(path_buf),
+            "%s" OS_PATH_SEPARATOR_STR
+            "out" OS_PATH_SEPARATOR_STR
+            "target" OS_PATH_SEPARATOR_STR
+            "product" OS_PATH_SEPARATOR_STR
+            "%s", top_buf, hint);
+    if (access(path_buf, F_OK) < 0) {
+        fprintf(stderr, "sdb: Couldn't find a product dir "
+                "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
+        return NULL;
+    }
+    return path_buf;
 }
 
-static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) {
-
-    fprintf(stderr, "Smart Development Bridge version %d.%d.%d\n",
-         SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_SERVER_VERSION);
-    fprintf(stderr, "\n Usage : sdb [option] <command> [parameters]\n\n");
-    fprintf(stderr, " options:\n");
-
-    LIST_NODE* curptr = optlist;
-    int append_len = strlen(HELP_APPEND_STR);
-    char* append_str = (char*)malloc(sizeof(char)*append_len);
-    char* help_str = (char*)malloc(sizeof(char)*append_len*3);
-    while(curptr != NULL) {
-        OPTION* opt = (OPTION*)curptr->data;
-        const char** des = opt->desc;
-        if(des != NULL) {
-            snprintf(help_str, append_len*3, "  -%s, --%s %s", opt->shortopt, opt->longopt, opt->argdesc);
-            int opt_len = strlen(help_str);
-            if(opt_len >= append_len) {
-                fprintf(stderr, "%s\n%s", help_str, HELP_APPEND_STR);
-            }
-            else {
-                snprintf(append_str, append_len - opt_len + 1, "%s", HELP_APPEND_STR);
-                fprintf(stderr, "%s%s", help_str, append_str);
-            }
-        }
+int sdb_commandline(int argc, char **argv)
+{
+    char buf[4096];
+    int no_daemon = 0;
+    int is_daemon = 0;
+    int is_server = 0;
+    int persist = 0;
+    int r;
+    int quote;
+    transport_type ttype = kTransportAny;
+    char* serial = NULL;
+    char* server_port_str = NULL;
+
+        /* If defined, this should be an absolute path to
+         * the directory containing all of the various system images
+         * for a particular product.  If not defined, and the sdb
+         * command requires this information, then the user must
+         * specify the path using "-p".
+         */
+    gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
+    if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
+        gProductOutPath = NULL;
+    }
+    // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
-        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]);
+    serial = getenv("ANDROID_SERIAL");
+
+    /* Validate and assign the server port */
+    server_port_str = getenv("ANDROID_SDB_SERVER_PORT");
+    int server_port = DEFAULT_SDB_PORT;
+    if (server_port_str && strlen(server_port_str) > 0) {
+        server_port = (int) strtol(server_port_str, NULL, 0);
+        if (server_port <= 0) {
+            fprintf(stderr,
+                    "sdb: Env var ANDROID_SDB_SERVER_PORT must be a positive number. Got \"%s\"\n",
+                    server_port_str);
+            return usage();
         }
-        curptr = curptr->next_ptr;
     }
-    fprintf(stderr, "\n commands:\n");
 
-    curptr = cmdlist;
-    while(curptr != NULL) {
-        COMMAND* cmd = (COMMAND*)curptr ->data;
-        const char** des = cmd->desc;
-        if(des != NULL) {
-            snprintf(help_str, append_len*3, "  sdb %s %s", cmd->name, cmd->argdesc);
-            int cmd_len = strlen(help_str);
-            if(cmd_len >= append_len) {
-                fprintf(stderr, "%s\n%s", help_str, HELP_APPEND_STR);
+    /* modifiers and flags */
+    while(argc > 0) {
+        if(!strcmp(argv[0],"server")) {
+            is_server = 1;
+        } else if(!strcmp(argv[0],"nodaemon")) {
+            no_daemon = 1;
+        } else if (!strcmp(argv[0], "fork-server")) {
+            /* this is a special flag used only when the SDB client launches the SDB Server */
+            is_daemon = 1;
+        } else if(!strcmp(argv[0],"persist")) {
+            persist = 1;
+        } else if(!strncmp(argv[0], "-p", 2)) {
+            const char *product = NULL;
+            if (argv[0][2] == '\0') {
+                if (argc < 2) return usage();
+                product = argv[1];
+                argc--;
+                argv++;
+            } else {
+                product = argv[1] + 2;
             }
-            else {
-                snprintf(append_str, append_len - cmd_len + 1, "%s", HELP_APPEND_STR);
-                fprintf(stderr, "%s%s", help_str, append_str);
+            gProductOutPath = find_product_out_path(product);
+            if (gProductOutPath == NULL) {
+                fprintf(stderr, "sdb: could not resolve \"-p %s\"\n",
+                        product);
+                return usage();
             }
-            int array_len = cmd->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]);
+        } else if (argv[0][0]=='-' && argv[0][1]=='s') {
+            if (isdigit(argv[0][2])) {
+                serial = argv[0] + 2;
+            } else {
+                if(argc < 2 || argv[0][2] != '\0') return usage();
+                serial = argv[1];
+                argc--;
+                argv++;
             }
-        }
-        curptr = curptr->next_ptr;
-    }
+        } else if (!strcmp(argv[0],"-d")) {
+            ttype = kTransportUsb;
+        } else if (!strcmp(argv[0],"-e")) {
+            ttype = kTransportLocal;
+        } else {
+                /* out of recognized modifiers and flags */
+            break;
+        }
+        argc--;
+        argv++;
+    }
+
+
+//    sdb_set_transport(ttype, serial);
+//    sdb_set_tcp_specifics(server_port);
+
+    if (is_server) {
+        if (no_daemon || is_daemon) {
+            r = sdb_main(is_daemon, server_port);
+        } else {
+            r = launch_server(server_port);
+        }
+        if(r) {
+            fprintf(stderr,"* could not start server *\n");
+        }
+        return r;
+    }
+
+top:
+    if(argc == 0) {
+        return usage();
+    }
+
+    // first, get the uniq device from the partial serial with prefix matching
+    if (serial) {
+        char *tmp;
+        snprintf(buf, sizeof(buf), "host:serial-match:%s", serial);
+        tmp = sdb_query(buf);
+        if (tmp) {
+            //printf("connect to device: %s\n", tmp);
+            serial = strdup(tmp);
+            sdb_set_transport(ttype, serial);
+            sdb_set_tcp_specifics(server_port);
+        } else {
+            return 1;
+        }
+    } else {
+        sdb_set_transport(ttype, serial);
+        sdb_set_tcp_specifics(server_port);
+    }
+    /* sdb_connect() commands */
+
+    if(!strcmp(argv[0], "devices")) {
+        char *tmp;
+        snprintf(buf, sizeof buf, "host:%s", argv[0]);
+        tmp = sdb_query(buf);
+        if(tmp) {
+            printf("List of devices attached \n");
+            printf("%s", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if(!strcmp(argv[0], "connect")) {
+        char *tmp;
+        if (argc != 2) {
+            fprintf(stderr, "Usage: sdb connect <host>[:<port>]\n");
+            return 1;
+        }
+        snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
+        tmp = sdb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if(!strcmp(argv[0], "disconnect")) {
+        char *tmp;
+        if (argc > 2) {
+            fprintf(stderr, "Usage: sdb disconnect [<host>[:<port>]]\n");
+            return 1;
+        }
+        if (argc == 2) {
+            snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
+        } else {
+            snprintf(buf, sizeof buf, "host:disconnect:");
+        }
+        tmp = sdb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if (!strcmp(argv[0], "emu")) {
+        return sdb_send_emulator_command(argc, argv);
+    }
+
+    if(!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
+        int r;
+        int fd;
+
+        char h = (argv[0][0] == 'h');
+
+        if (h) {
+            printf("\x1b[41;33m");
+            fflush(stdout);
+        }
+
+        if(argc < 2) {
+            D("starting interactive shell\n");
+            r = interactive_shell();
+            if (h) {
+                printf("\x1b[0m");
+                fflush(stdout);
+            }
+            return r;
+        }
+
+        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while(argc-- > 0) {
+            strcat(buf, " ");
+
+            /* quote empty strings and strings with spaces */
+            quote = (**argv == 0 || strchr(*argv, ' '));
+            if (quote)
+                strcat(buf, "\"");
+            strcat(buf, *argv++);
+            if (quote)
+                strcat(buf, "\"");
+        }
+
+        for(;;) {
+            D("interactive shell loop. buff=%s\n", buf);
+            fd = sdb_connect(buf);
+            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 {
+                fprintf(stderr,"error: %s\n", sdb_error());
+                r = -1;
+            }
+
+            if(persist) {
+                fprintf(stderr,"\n- waiting for device -\n");
+                sdb_sleep_ms(1000);
+                do_cmd(ttype, serial, "wait-for-device", 0);
+            } else {
+                if (h) {
+                    printf("\x1b[0m");
+                    fflush(stdout);
+                }
+                D("interactive shell loop. return r=%d\n", r);
+                return r;
+            }
+        }
+    }
+
+    if(!strcmp(argv[0], "kill-server")) {
+        int fd;
+        fd = _sdb_connect("host:kill");
+        if(fd == -1) {
+            fprintf(stderr,"* server not running *\n");
+            return 1;
+        }
+        return 0;
+    }
+#if 0 /* tizen specific */
+    if(!strcmp(argv[0], "sideload")) {
+        if(argc != 2) return usage();
+        if(sdb_download("sideload", argv[1], 1)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+#endif
+    if(!strcmp(argv[0], "root")) {
+        char command[100];
+
+        if (argc != 2) {
+            return usage();
+        }
+        if (strcmp(argv[1], "on") != 0 && strcmp(argv[1], "off") != 0) {
+            return usage();
+        }
+        snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
+        int fd = sdb_connect(command);
+        if(fd >= 0) {
+            read_and_dump(fd);
+            sdb_close(fd);
+            return 0;
+        }
+        //TODO: it may be here due to version mis-match
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return 1;
+    }
+
+    if(!strcmp(argv[0], "bugreport")) {
+        if (argc != 1) return usage();
+        do_cmd(ttype, serial, "shell", "bugreport", 0);
+        return 0;
+    }
+
+    /* sdb_command() wrapper commands */
+
+    if(!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
+        char* service = argv[0];
+        if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
+            if (ttype == kTransportUsb) {
+                service = "wait-for-usb";
+            } else if (ttype == kTransportLocal) {
+                service = "wait-for-local";
+            } else {
+                service = "wait-for-any";
+            }
+        }
+
+        format_host_command(buf, sizeof buf, service, ttype, serial);
+
+        if (sdb_command(buf)) {
+            D("failure: %s *\n",sdb_error());
+            fprintf(stderr,"error: %s\n", sdb_error());
+            return 1;
+        }
+
+        /* Allow a command to be run after wait-for-device,
+            * e.g. 'sdb wait-for-device shell'.
+            */
+        if(argc > 1) {
+            argc--;
+            argv++;
+            goto top;
+        }
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "forward")) {
+        if(argc != 3) return usage();
+        if (serial) {
+            snprintf(buf, sizeof buf, "host-serial:%s:forward:%s;%s",serial, argv[1], argv[2]);
+        } else if (ttype == kTransportUsb) {
+            snprintf(buf, sizeof buf, "host-usb:forward:%s;%s", argv[1], argv[2]);
+        } else if (ttype == kTransportLocal) {
+            snprintf(buf, sizeof buf, "host-local:forward:%s;%s", argv[1], argv[2]);
+        } else {
+            snprintf(buf, sizeof buf, "host:forward:%s;%s", argv[1], argv[2]);
+        }
+        if(sdb_command(buf)) {
+            fprintf(stderr,"error: %s\n", sdb_error());
+            return 1;
+        }
+        return 0;
+    }
+
+    /* do_sync_*() commands */
+
+    if(!strcmp(argv[0], "ls")) {
+        if(argc != 2) return usage();
+        return do_sync_ls(argv[1]);
+    }
+
+    if(!strcmp(argv[0], "push")) {
+        int i=0;
+        int utf8=0;
+
+        if(argc < 3) return usage();
+        if (argv[argc-1][0] == '-') {
+            if (!strcmp(argv[argc-1], "--with-utf8")) {
+                utf8 = 1;
+                argc = argc - 1;
+            } else {
+                return usage();
+            }
+        }
+        for (i=1; i<argc-1; i++) {
+            do_sync_push(argv[i], argv[argc-1], 0 /* no verify APK */, utf8);
+        }
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "install")) {
+        if(argc == 2) {
+            return install_app_sdb(argv[1]);
+        }
+
+        return usage();
+    }
+
+    if(!strcmp(argv[0], "uninstall")) {
+        if(argc == 2) {
+            return uninstall_app_sdb(argv[1]);
+        }
+
+        return usage();
+    }
+
+    if(!strcmp(argv[0], "launch")) {
+        //if (argc < 2) return usage();
+        //TODO : check argument validations
+        return launch_app(ttype, serial, argc, argv);
+    }
+
+    if(!strcmp(argv[0], "pull")) {
+        if (argc == 2) {
+            return do_sync_pull(argv[1], ".");
+        } else if (argc == 3) {
+            return do_sync_pull(argv[1], argv[2]);
+        } else {
+            return usage();
+        }
+    }
+
+    if(!strcmp(argv[0], "install")) {
+        if (argc < 2) return usage();
+        return install_app(ttype, serial, argc, argv);
+    }
+
+    if(!strcmp(argv[0], "uninstall")) {
+        if (argc < 2) return usage();
+        return uninstall_app(ttype, serial, argc, argv);
+    }
+
+    if(!strcmp(argv[0], "sync")) {
+        char *srcarg, *android_srcpath, *data_srcpath;
+        int listonly = 0;
+
+        int ret;
+        if(argc < 2) {
+            /* No local path was specified. */
+            srcarg = NULL;
+        } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
+            listonly = 1;
+            if (argc == 3) {
+                srcarg = argv[2];
+            } else {
+                srcarg = NULL;
+            }
+        } else if(argc == 2) {
+            /* A local path or "android"/"data" arg was specified. */
+            srcarg = argv[1];
+        } else {
+            return usage();
+        }
+        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
+        if(ret != 0) return usage();
+
+        if(android_srcpath != NULL)
+            ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if(ret == 0 && data_srcpath != NULL)
+            ret = do_sync_sync(data_srcpath, "/data", listonly);
+
+        free(android_srcpath);
+        free(data_srcpath);
+        return ret;
+    }
+
+    /* passthrough commands */
+
+    if(!strcmp(argv[0],"get-state") ||
+        !strcmp(argv[0],"get-serialno"))
+    {
+        char *tmp;
+
+        format_host_command(buf, sizeof buf, argv[0], ttype, serial);
+        tmp = sdb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    /* other commands */
+
+    if(!strcmp(argv[0],"status-window")) {
+        status_window(ttype, serial);
+        return 0;
+    }
+
+    if(!strcmp(argv[0],"dlog")) {
+        return logcat(ttype, serial, argc, argv);
+    }
+
+    if(!strcmp(argv[0],"ppp")) {
+        return ppp(argc, argv);
+    }
+
+    if (!strcmp(argv[0], "start-server")) {
+        return sdb_connect("host:start-server");
+    }
+
+    if (!strcmp(argv[0], "backup")) {
+        return backup(argc, argv);
+    }
+
+    if (!strcmp(argv[0], "restore")) {
+        return restore(argc, argv);
+    }
+
+    if (!strcmp(argv[0], "jdwp")) {
+        int  fd = sdb_connect("jdwp");
+        if (fd >= 0) {
+            read_and_dump(fd);
+            sdb_close(fd);
+            return 0;
+        } else {
+            fprintf(stderr, "error: %s\n", sdb_error());
+            return -1;
+        }
+    }
+
+    /* "sdb /?" is a common idiom under Windows */
+    if(!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
+        help();
+        return 0;
+    }
+
+    if(!strcmp(argv[0], "version")) {
+        if (ttype == kTransportUsb || ttype == kTransportLocal) {
+            version_sdbd(ttype, serial);
+        } else {
+            version(stdout);
+        }
+        return 0;
+    }
+
+    usage();
+    return 1;
+}
+
+static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
+{
+    char *argv[16];
+    int argc;
+    va_list ap;
+
+    va_start(ap, cmd);
+    argc = 0;
+
+    if (serial) {
+        argv[argc++] = "-s";
+        argv[argc++] = serial;
+    } else if (ttype == kTransportUsb) {
+        argv[argc++] = "-d";
+    } else if (ttype == kTransportLocal) {
+        argv[argc++] = "-e";
+    }
+
+    argv[argc++] = cmd;
+    while((argv[argc] = va_arg(ap, char*)) != 0) {
+        argc++;
+    }
+    va_end(ap);
+
+#if 0
+    int n;
+    fprintf(stderr,"argc = %d\n",argc);
+    for(n = 0; n < argc; n++) {
+        fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
+    }
+#endif
+
+    return sdb_commandline(argc, argv);
+}
+
+int find_sync_dirs(const char *srcarg,
+        char **android_srcdir_out, char **data_srcdir_out)
+{
+    char *android_srcdir, *data_srcdir;
+
+    if(srcarg == NULL) {
+        android_srcdir = product_file("system");
+        data_srcdir = product_file("data");
+    } else {
+        /* srcarg may be "data", "system" or NULL.
+         * if srcarg is NULL, then both data and system are synced
+         */
+        if(strcmp(srcarg, "system") == 0) {
+            android_srcdir = product_file("system");
+            data_srcdir = NULL;
+        } else if(strcmp(srcarg, "data") == 0) {
+            android_srcdir = NULL;
+            data_srcdir = product_file("data");
+        } else {
+            /* It's not "system" or "data".
+             */
+            return 1;
+        }
+    }
+
+    if(android_srcdir_out != NULL)
+        *android_srcdir_out = android_srcdir;
+    else
+        free(android_srcdir);
+
+    if(data_srcdir_out != NULL)
+        *data_srcdir_out = data_srcdir;
+    else
+        free(data_srcdir);
+
+    return 0;
+}
+
+static int pm_command(transport_type transport, char* serial,
+                      int argc, char** argv)
+{
+    char buf[4096];
+
+    snprintf(buf, sizeof(buf), "shell:pm");
+
+    while(argc-- > 0) {
+        char *quoted;
+
+        quoted = dupAndQuote(*argv++);
+
+        strncat(buf, " ", sizeof(buf)-1);
+        strncat(buf, quoted, sizeof(buf)-1);
+        free(quoted);
+    }
+
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
+
+int sdb_command2(const char* cmd) {
+    int result = sdb_connect(cmd);
+
+    if(result < 0) {
+        return result;
+    }
+
+    D("about to read_and_dump(fd=%d)\n", result);
+    read_and_dump(result);
+    D("read_and_dump() done.\n");
+    sdb_close(result);
+
+    return 0;
+}
+
+int install_app_sdb(const char *srcpath) {
+    D("Install start\n");
+    const char * APP_DEST = "/opt/usr/apps/tmp/%s";
+    const char* filename = sdb_dirstop(srcpath);
+    char destination[PATH_MAX];
+
+    if (filename) {
+        filename++;
+        snprintf(destination, sizeof destination, APP_DEST, filename);
+    } else {
+        snprintf(destination, sizeof destination, APP_DEST, srcpath);
+    }
+
+    int tpk = get_pkgtype_file_name(srcpath);
+    if (tpk == -1) {
+        fprintf(stderr, "error: unknown package type\n");
+        return -1;
+    }
+    D("Push file: %s to %s\n", srcpath, destination);
+    int result = do_sync_push(srcpath, destination, 0, 0);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return -1;
+    }
+
+    const char* SHELL_INSTALL_CMD ="shell:/usr/bin/pkgcmd -i -t %s -p %s -q";
+    char full_cmd[PATH_MAX];
+
+    if(tpk == 1) {
+        snprintf(full_cmd, sizeof full_cmd, SHELL_INSTALL_CMD, "tpk", destination);
+    }
+    else if(tpk == 0){
+        snprintf(full_cmd, sizeof full_cmd, SHELL_INSTALL_CMD, "wgt", destination);
+    }
+    else {
+        return tpk;
+    }
+    D("Install command: %s\n", full_cmd);
+    result = sdb_command2(full_cmd);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return result;
+    }
+
+    const char* SHELL_REMOVE_CMD = "shell:rm %s";
+    snprintf(full_cmd, sizeof full_cmd, SHELL_REMOVE_CMD, destination);
+    D("Remove file command: %s\n", full_cmd);
+    result = sdb_command2(full_cmd);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return result;
+    }
+
+    return 0;
+}
+
+int uninstall_app_sdb(const char *appid) {
+    const char* SHELL_UNINSTALL_CMD ="shell:/usr/bin/pkgcmd -u -t %s -n %s -q";
+    char full_cmd[PATH_MAX];
+    int result = 0;
+    int tpk = get_pkgtype_from_app_id(appid);
+    if(tpk == 1) {
+        snprintf(full_cmd, sizeof full_cmd, SHELL_UNINSTALL_CMD, "tpk", appid);
+    }
+    else if(tpk == 0){
+        snprintf(full_cmd, sizeof full_cmd, SHELL_UNINSTALL_CMD, "wgt", appid);
+    }
+    else {
+        return tpk;
+    }
+    result = sdb_command2(full_cmd);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return result;
+    }
+
+    return 0;
+}
+
+int uninstall_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    /* if the user choose the -k option, we refuse to do it until devices are
+       out with the option to uninstall the remaining data somehow (sdb/ui) */
+    if (argc == 3 && strcmp(argv[1], "-k") == 0)
+    {
+        printf(
+            "The -k option uninstalls the application while retaining the data/cache.\n"
+            "At the moment, there is no way to remove the remaining data.\n"
+            "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+            "If you truly wish to continue, execute 'sdb shell pm uninstall -k %s'\n", argv[2]);
+        return -1;
+    }
+
+    /* 'sdb uninstall' takes the same arguments as 'pm uninstall' on device */
+    return pm_command(transport, serial, argc, argv);
+}
+
+// Returns 0 if pkg type is wgt. Returns 1 if pkg type is tpk. Returns minus if exception happens.
+int get_pkgtype_file_name(const char* file_name) {
+
+    char* pkg_type;
+
+    int result = -1;
+
+    pkg_type = strrchr(file_name, '.')+1;
+    if (pkg_type != NULL) {
+        if(!strcmp(pkg_type, "wgt")) {
+            result = 0;
+        }
+        else if(!strcmp(pkg_type, "tpk")) {
+            result = 1;
+        }
+    }
+
+    return result;
+}
+
+// Returns 0 if pkg type is wgt. Returns 1 if pkg type is tpk. Returns minus if exception happens.
+int get_pkgtype_from_app_id(const char* app_id) {
+
+    char* GET_PKG_TYPE_CMD = "shell:/usr/bin/pkgcmd -l | grep %s | awk '{print $2}'";
+    char full_cmd[PATH_MAX];
+    snprintf(full_cmd, sizeof full_cmd, GET_PKG_TYPE_CMD, app_id);
+
+    int result = sdb_connect(full_cmd);
+    if(result < 0) {
+        return result;
+    }
+    char buf[100] = "";
+
+    int rl_result = read_line(result, buf, 100);
+    if(rl_result < 0) {
+        D("Error to read buffer (fd=%d)\n", rl_result);
+        return rl_result;
+    }
+
+    sdb_close(result);
+    result = -1;
+
+    if(strstr(buf, "[tpk]") != NULL) {
+        result = 1;
+    } else if(strstr(buf, "[wgt]") != NULL) {
+        result = 0;
+    }
+    return result;
+}
+
+static int delete_file(transport_type transport, char* serial, char* filename)
+{
+    char buf[4096];
+    char* quoted;
+
+    snprintf(buf, sizeof(buf), "shell:rm ");
+    quoted = dupAndQuote(filename);
+    strncat(buf, quoted, sizeof(buf)-1);
+    free(quoted);
 
+    send_shellcommand(transport, serial, buf);
+    return 0;
+}
 
+const char* get_basename(const char* filename)
+{
+    const char* basename = sdb_dirstop(filename);
+    if (basename) {
+        basename++;
+        return basename;
+    } else {
+        return filename;
+    }
 }
 
+static int check_file(const char* filename)
+{
+    struct stat st;
+
+    if (filename == NULL) {
+        return 0;
+    }
+
+    if (stat(filename, &st) != 0) {
+        fprintf(stderr, "can't find '%s' to install\n", filename);
+        return 1;
+    }
+
+    if (!S_ISREG(st.st_mode)) {
+        fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
+        return 1;
+    }
+
+    return 0;
+}
 
+int install_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    static const char *const DATA_DEST = "/data/local/tmp/%s";
+    static const char *const SD_DEST = "/sdcard/tmp/%s";
+    const char* where = DATA_DEST;
+    char apk_dest[PATH_MAX];
+    char verification_dest[PATH_MAX];
+    char* apk_file;
+    char* verification_file = NULL;
+    int file_arg = -1;
+    int err;
+    int i;
+    int verify_apk = 1;
+
+    for (i = 1; i < argc; i++) {
+        if (*argv[i] != '-') {
+            file_arg = i;
+            break;
+        } else if (!strcmp(argv[i], "-i")) {
+            // Skip the installer package name.
+            i++;
+        } else if (!strcmp(argv[i], "-s")) {
+            where = SD_DEST;
+        } else if (!strcmp(argv[i], "--algo")) {
+            verify_apk = 0;
+            i++;
+        } else if (!strcmp(argv[i], "--iv")) {
+            verify_apk = 0;
+            i++;
+        } else if (!strcmp(argv[i], "--key")) {
+            verify_apk = 0;
+            i++;
+        }
+    }
+
+    if (file_arg < 0) {
+        fprintf(stderr, "can't find filename in arguments\n");
+        return 1;
+    } else if (file_arg + 2 < argc) {
+        fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
+        return 1;
+    }
+
+    apk_file = argv[file_arg];
+
+    if (file_arg != argc - 1) {
+        verification_file = argv[file_arg + 1];
+    }
+
+    if (check_file(apk_file) || check_file(verification_file)) {
+        return 1;
+    }
+
+    snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
+    if (verification_file != NULL) {
+        snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
+
+        if (!strcmp(apk_dest, verification_dest)) {
+            fprintf(stderr, "APK and verification file can't have the same name\n");
+            return 1;
+        }
+    }
+
+    err = do_sync_push(apk_file, apk_dest, verify_apk, 0);
+    if (err) {
+        goto cleanup_apk;
+    } else {
+        argv[file_arg] = apk_dest; /* destination name, not source location */
+    }
+
+    if (verification_file != NULL) {
+        err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */, 0);
+        if (err) {
+            goto cleanup_apk;
+        } else {
+            argv[file_arg + 1] = verification_dest; /* destination name, not source location */
+        }
+    }
+
+    pm_command(transport, serial, argc, argv);
+
+cleanup_apk:
+    if (verification_file != NULL) {
+        delete_file(transport, serial, verification_dest);
+    }
+
+    delete_file(transport, serial, apk_dest);
+
+    return err;
+}
+
+int launch_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    int i;
+    int result = 0;
+    char pkgid[11] = {0,};
+    char exe[512] = {0,};
+    char args[512] = {0,};
+    int mode = 0;
+    int port = 0;
+    int pid = 0;
+    int type = 0;
+    char fullcommand[4096] = {'s','h','e','l','l',':',};
+    char buf[128] = {0,};
+    char flag = 0;
+
+    if (argc < 7 || argc > 15 ) {
+        fprintf(stderr,"usage: sdb launch -p <pkgid> -e <executable> -m <run|debug> [-P <port>] [-attach <pid>] [-t <gtest,gcov>]  [<args...>]\n");
+        return -1;
+    }
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-p")) {
+            flag = 'p';
+            continue;
+        }
+        if (!strcmp(argv[i], "-e")) {
+            flag = 'e';
+            continue;
+        }
+        if (!strcmp(argv[i], "-m")) {
+            flag = 'm';
+            continue;
+        }
+        if (!strcmp(argv[i], "-P")) {
+            flag = 'P';
+            continue;
+        }
+        if (!strcmp(argv[i], "-t")) {
+            flag = 't';
+            continue;
+        }
+        if (!strcmp(argv[i], "-attach")) {
+            flag = 'a';
+            continue;
+        }
+        D("launch cmd args: %c : %s\n", flag, argv[i]);
+
+        switch (flag) {
+        case 'p' :
+            s_strncpy(pkgid, argv[i], sizeof(pkgid));
+            flag = 0;
+            break;
+        case 'e':
+            s_strncpy(exe, argv[i], sizeof(exe));
+            flag = 0;
+            break;
+        case 'm': {
+            if (!strcmp(argv[i], "run")) {
+                mode = 0;
+            } else if (!strcmp(argv[i], "debug")) {
+                mode = 1;
+            } else {
+                fprintf(stderr,"The -m option accepts arguments only run or debug options\n");
+                return -1;
+            }
+            flag = 0;
+            break;
+        }
+        case 'P': {
+            if (mode != 1) {
+                fprintf(stderr,"The -P option should be used in debug mode\n");
+                return -1;
+            }
+            port = atoi(argv[i]);
+            flag = 0;
+            break;
+        }
+        case 'a': {
+            if (mode != 1) {
+                fprintf(stderr, "The -attach option should be used in debug mode\n");
+                return -1;
+            }
+            pid = atoi(argv[i]);
+            flag = 0;
+            break;
+        }
+        case 't': {
+            char *str = argv[i];
+            for (; *str; str++) {
+                if (!memcmp(str, "gtest", 5)) {
+                    snprintf(buf, sizeof(buf), "export LD_LIBRARY_PATH=%s/gtest/usr/lib && ", SDK_TOOL_PATH);
+                    strncat(fullcommand, buf, sizeof(fullcommand) - 1);
+                    type = 1;
+                }
+                if (!memcmp(str, "gcov", 4)) {
+                    snprintf(buf, sizeof(buf), "export GCOV_PREFIX=/tmp/%s/data && export GCOV_PREFIX_STRIP=0 && ", pkgid);
+                    strncat(fullcommand, buf, sizeof(fullcommand) - 1);
+                    type = 2;
+                }
+                char *ptr = strstr(str, ",");
+                if (ptr) {
+                    str = ptr;
+                }
+            }
+            flag = 0;
+        }
+            break;
+        default : {
+            while (i < argc) {
+                strncat(args, " ", sizeof(args)-1);
+                strncat(args, argv[i], sizeof(args)-1);
+                i++;
+            }
+            break;
+        }
+        }
+    }
+
+    if (mode == 0) {
+        if (type == 0) {
+            snprintf(buf, sizeof(buf), "/usr/bin/launch_app %s.%s", pkgid, exe);
+            strncat(fullcommand, buf, sizeof(fullcommand)-1);
+        } else {
+            snprintf(buf, sizeof(buf), "%s/%s/bin/%s", APP_PATH_PREFIX, pkgid, exe);
+            strncat(fullcommand, buf, sizeof(fullcommand)-1);
+        }
+    } else if (mode == 1) {
+        if (verify_gdbserver_exist() < 0) {
+            return -1;
+        }
+        if (!port) {
+            fprintf(stderr,"The port number is not valid\n");
+            return -1;
+        }
+        if (pid) {
+            snprintf(buf, sizeof(buf), "%s/gdbserver/gdbserver :%d --attach %d", SDK_TOOL_PATH, port, pid);
+        } else {
+            snprintf(buf, sizeof(buf), "%s/gdbserver/gdbserver :%d %s/%s/bin/%s", SDK_TOOL_PATH, port, APP_PATH_PREFIX, pkgid, exe);
+        }
+        if (kill_gdbserver_if_running(buf) < 0) {
+            fprintf(stderr, "Gdbserver is already running on your target.\nAn gdb is going to connect the previous gdbserver process.\n");
+            return -1;
+        }
+        strncat(fullcommand, buf, sizeof(fullcommand)-1);
+    }
+    if (strlen(args) > 1) {
+        strncat(fullcommand, " ", sizeof(fullcommand)-1);
+        strncat(fullcommand, args, sizeof(fullcommand)-1);
+    }
+
+    D("launch command: [%s]\n", fullcommand);
+    result = sdb_command2(fullcommand);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+    }
+    sdb_close(result);
+
+    return result;
+
+}
+
+/*
+ * kill gdbserver if running
+ */
+
+int kill_gdbserver_if_running(const char* process_cmd) {
+    char cmd[512] = {};
+    char buf[512] = {};
+
+    // hopefully, it is not going to happen, but check executable gdbserver is existed
+    snprintf(cmd, sizeof(cmd), "shell:/usr/bin/da_command process | grep '%s' | grep -v grep | wc -l", process_cmd);
+    int result = sdb_connect(cmd);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        return -1;
+    }
+    if (read_line(result, buf, sizeof(buf)) < 0) {
+        sdb_close(result);
+        return -1;
+    }
+    if(memcmp(buf, "0", 1)) {
+/*
+        // TODO: check cmd return code
+        snprintf(cmd, sizeof(cmd), "shell:/usr/bin/da_command killapp '%s'", process_cmd);
+        result = sdb_connect(cmd);
+        if (read_line(result, buf, sizeof(buf)) < 0) {
+            sdb_close(result);
+            return -1;
+        }
+*/
+    }
+    sdb_close(result);
+    return 1;
+}
+
+/*
+ * returns -1 if gdbserver exists
+ */
+int verify_gdbserver_exist() {
+    char cmd[512] = {};
+    char buf[512] = {};
+
+    snprintf(cmd, sizeof(cmd), "shell:%s/gdbserver/gdbserver --version 1>/dev/null", SDK_TOOL_PATH);
+    int result = sdb_connect(cmd);
+
+    if(result < 0) {
+        fprintf(stderr, "error: %s\n", sdb_error());
+        sdb_close(result);
+        return -1;
+    }
+    if (read_line(result, buf, sizeof(buf)) > 0) {
+        fprintf(stderr, "error: %s\n", buf);
+        sdb_close(result);
+        return -1;
+    }
+    sdb_close(result);
+    return result;
+}
+
+void version_sdbd(transport_type ttype, char* serial) {
+    char* VERSION_QUERY ="shell:rpm -qa | grep sdbd";
+    send_shellcommand(ttype, serial, VERSION_QUERY);
+}
diff --git a/src/commandline.h b/src/commandline.h
deleted file mode 100644 (file)
index ea018a9..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* 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 COMMANDLINE_H_
-#define COMMANDLINE_H_
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-#ifndef NAME_MAX
-#define NAME_MAX 255
-#endif
-
-#ifndef MAX_INPUT
-#define MAX_INPUT 255
-#endif
-
-#ifndef INPUT_FD
-#define INPUT_FD 0
-#endif
-
-int send_shellcommand(char* buf, void** extargv);
-int process_cmdline(int argc, char** argv);
-void read_and_dump(int fd);
-int interactive_shell(void** extargv);
-int __inline__ get_server_port();
-int __sdb_command(const char* cmd, void** extargv);
-
-#endif /* COMMANDLINE_H_ */
diff --git a/src/console.c b/src/console.c
new file mode 100644 (file)
index 0000000..2926b5c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 "sysdeps.h"
+#include "sdb.h"
+#include "sdb_client.h"
+#include <stdio.h>
+
+static int  connect_to_console(void)
+{
+    int  fd, port;
+
+    port = sdb_get_emulator_console_port();
+    if (port < 0) {
+        if (port == -2)
+            fprintf(stderr, "error: more than one emulator detected. use -s option\n");
+        else
+            fprintf(stderr, "error: no emulator detected\n");
+        return -1;
+    }
+    fd = socket_loopback_client( port, SOCK_STREAM );
+    if (fd < 0) {
+        fprintf(stderr, "error: could not connect to TCP port %d\n", port);
+        return -1;
+    }
+    return  fd;
+}
+
+
+int  sdb_send_emulator_command(int  argc, char**  argv)
+{
+    int   fd, nn;
+
+    fd = connect_to_console();
+    if (fd < 0)
+        return 1;
+
+#define  QUIT  "quit\n"
+
+    for (nn = 1; nn < argc; nn++) {
+        sdb_write( fd, argv[nn], strlen(argv[nn]) );
+        sdb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
+    }
+    sdb_write( fd, QUIT, sizeof(QUIT)-1 );
+    sdb_close(fd);
+
+    return 0;
+}
index 32dd05f3379da09eb98cc6dac5b5046deb18aec6..4171acb21e8bb3200ae0862c137b3234345e7393 100644 (file)
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <sys/ioctl.h>
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stddef.h>
 
-#include "fdevent_backend.h"
+#include "fdevent.h"
 #include "transport.h"
-#include "utils.h"
-
-#if defined(OS_LINUX)
-const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend;
-#elif defined(OS_DARWIN)
-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"
-#endif
+#include "sysdeps.h"
 
-fdevent list_pending = {
-    .next = &list_pending,
-    .prev = &list_pending,
-};
 
-fdevent **fd_table = 0;
-int fd_table_max = 0;
+/* !!! Do not enable DEBUG for the sdb that will run as the server:
+** both stdout and stderr are used to communicate between the client
+** and server. Any extra output will cause failures.
+*/
+#define DEBUG 0   /* non-0 will break sdb server */
+
+// 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.
+int SHELL_EXIT_NOTIFY_FD = -1;
 
-void _fatal(const char *fn, const char *fmt, ...)
+static void fatal(const char *fn, const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
@@ -58,28 +53,395 @@ void _fatal(const char *fn, const char *fmt, ...)
     abort();
 }
 
-void fdevent_register(fdevent *fde)
+#define FATAL(x...) fatal(__FUNCTION__, x)
+
+#if DEBUG
+#define D(...) \
+    do { \
+        sdb_mutex_lock(&D_lock);               \
+        int save_errno = errno;                \
+        fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__);  \
+        errno = save_errno;                    \
+        fprintf(stderr, __VA_ARGS__);          \
+        sdb_mutex_unlock(&D_lock);             \
+        errno = save_errno;                    \
+    } while(0)
+static void dump_fde(fdevent *fde, const char *info)
+{
+    sdb_mutex_lock(&D_lock);
+    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);
+    sdb_mutex_unlock(&D_lock);
+}
+#else
+#define D(...) ((void)0)
+#define dump_fde(fde, info) do { } while(0)
+#endif
+
+#define FDE_EVENTMASK  0x00ff
+#define FDE_STATEMASK  0xff00
+
+#define FDE_ACTIVE     0x0100
+#define FDE_PENDING    0x0200
+#define FDE_CREATED    0x0400
+
+static void fdevent_plist_enqueue(fdevent *node);
+static void fdevent_plist_remove(fdevent *node);
+static fdevent *fdevent_plist_dequeue(void);
+static void fdevent_subproc_event_func(int fd, unsigned events, void *userdata);
+
+static fdevent list_pending = {
+    .next = &list_pending,
+    .prev = &list_pending,
+};
+
+static fdevent **fd_table = 0;
+static int fd_table_max = 0;
+
+#ifdef CRAPTASTIC
+//HAVE_EPOLL
+
+#include <sys/epoll.h>
+
+static int epoll_fd = -1;
+
+static void fdevent_init()
+{
+        /* XXX: what's a good size for the passed in hint? */
+    epoll_fd = epoll_create(256);
+
+    if(epoll_fd < 0) {
+        perror("epoll_create() failed");
+        exit(1);
+    }
+
+        /* mark for close-on-exec */
+    fcntl(epoll_fd, F_SETFD, FD_CLOEXEC);
+}
+
+static void fdevent_connect(fdevent *fde)
+{
+    struct epoll_event ev;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.events = 0;
+    ev.data.ptr = fde;
+
+#if 0
+    if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
+        perror("epoll_ctl() failed\n");
+        exit(1);
+    }
+#endif
+}
+
+static void fdevent_disconnect(fdevent *fde)
+{
+    struct epoll_event ev;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.events = 0;
+    ev.data.ptr = fde;
+
+        /* technically we only need to delete if we
+        ** were actively monitoring events, but let's
+        ** be aggressive and do it anyway, just in case
+        ** something's out of sync
+        */
+    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev);
+}
+
+static void fdevent_update(fdevent *fde, unsigned events)
+{
+    struct epoll_event ev;
+    int active;
+
+    active = (fde->state & FDE_EVENTMASK) != 0;
+
+    memset(&ev, 0, sizeof(ev));
+    ev.events = 0;
+    ev.data.ptr = fde;
+
+    if(events & FDE_READ) ev.events |= EPOLLIN;
+    if(events & FDE_WRITE) ev.events |= EPOLLOUT;
+    if(events & FDE_ERROR) ev.events |= (EPOLLERR | EPOLLHUP);
+
+    fde->state = (fde->state & FDE_STATEMASK) | events;
+
+    if(active) {
+            /* we're already active. if we're changing to *no*
+            ** events being monitored, we need to delete, otherwise
+            ** we need to just modify
+            */
+        if(ev.events) {
+            if(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fde->fd, &ev)) {
+                perror("epoll_ctl() failed\n");
+                exit(1);
+            }
+        } else {
+            if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fde->fd, &ev)) {
+                perror("epoll_ctl() failed\n");
+                exit(1);
+            }
+        }
+    } else {
+            /* we're not active.  if we're watching events, we need
+            ** to add, otherwise we can just do nothing
+            */
+        if(ev.events) {
+            if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fde->fd, &ev)) {
+                perror("epoll_ctl() failed\n");
+                exit(1);
+            }
+        }
+    }
+}
+
+static void fdevent_process()
+{
+    struct epoll_event events[256];
+    fdevent *fde;
+    int i, n;
+
+    n = epoll_wait(epoll_fd, events, 256, -1);
+
+    if(n < 0) {
+        if(errno == EINTR) return;
+        perror("epoll_wait");
+        exit(1);
+    }
+
+    for(i = 0; i < n; i++) {
+        struct epoll_event *ev = events + i;
+        fde = ev->data.ptr;
+
+        if(ev->events & EPOLLIN) {
+            fde->events |= FDE_READ;
+        }
+        if(ev->events & EPOLLOUT) {
+            fde->events |= FDE_WRITE;
+        }
+        if(ev->events & (EPOLLERR | EPOLLHUP)) {
+            fde->events |= FDE_ERROR;
+        }
+        if(fde->events) {
+            if(fde->state & FDE_PENDING) continue;
+            fde->state |= FDE_PENDING;
+            fdevent_plist_enqueue(fde);
+        }
+    }
+}
+
+#else /* USE_SELECT */
+
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+#else
+#include <sys/select.h>
+#endif
+
+static fd_set read_fds;
+static fd_set write_fds;
+static fd_set error_fds;
+
+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)
+{
+    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)
 {
-#if defined(OS_WINDOWS)
-    int  fd = fde->fd - WIN32_FH_BASE;
+    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;
+
+        }
+    }
+    return n;
+}
+
+#if !DEBUG
+static inline void dump_all_fds(const char *extra_msg) {}
 #else
-    int  fd = fde->fd;
+static void dump_all_fds(const char *extra_msg)
+{
+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(" ");
+    }
+    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;
+
+    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);
+            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;
+}
+
 #endif
 
-    if(fd < 0) {
+static void fdevent_register(fdevent *fde)
+{
+    if(fde->fd < 0) {
         FATAL("bogus negative fd (%d)\n", fde->fd);
     }
 
-    if(fd >= fd_table_max) {
+    if(fde->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();
+            fdevent_init();
             fd_table_max = 256;
         }
-        while(fd_table_max <= fd) {
+        while(fd_table_max <= fde->fd) {
             fd_table_max *= 2;
         }
         fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
@@ -89,25 +451,20 @@ void fdevent_register(fdevent *fde)
         memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
     }
 
-    fd_table[fd] = fde;
+    fd_table[fde->fd] = fde;
 }
 
-void fdevent_unregister(fdevent *fde)
+static void fdevent_unregister(fdevent *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)) {
+    if((fde->fd < 0) || (fde->fd >= fd_table_max)) {
         FATAL("fd out of range (%d)\n", fde->fd);
     }
 
-    if(fd_table[fd] != fde) {
-        FATAL("fd_table out of sync");
+    if(fd_table[fde->fd] != fde) {
+        FATAL("fd_table out of sync [%d]\n", fde->fd);
     }
 
-    fd_table[fd] = 0;
+    fd_table[fde->fd] = 0;
 
     if(!(fde->state & FDE_DONT_CLOSE)) {
         dump_fde(fde, "close");
@@ -115,7 +472,7 @@ void fdevent_unregister(fdevent *fde)
     }
 }
 
-void fdevent_plist_enqueue(fdevent *node)
+static void fdevent_plist_enqueue(fdevent *node)
 {
     fdevent *list = &list_pending;
 
@@ -125,7 +482,7 @@ void fdevent_plist_enqueue(fdevent *node)
     list->prev = node;
 }
 
-void fdevent_plist_remove(fdevent *node)
+static void fdevent_plist_remove(fdevent *node)
 {
     node->prev->next = node->next;
     node->next->prev = node->prev;
@@ -133,7 +490,7 @@ void fdevent_plist_remove(fdevent *node)
     node->prev = 0;
 }
 
-fdevent *fdevent_plist_dequeue(void)
+static fdevent *fdevent_plist_dequeue(void)
 {
     fdevent *list = &list_pending;
     fdevent *node = list->next;
@@ -148,6 +505,74 @@ fdevent *fdevent_plist_dequeue(void)
     return node;
 }
 
+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);
+    }
+}
+
 fdevent *fdevent_create(int fd, fd_func func, void *arg)
 {
     fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
@@ -175,12 +600,12 @@ void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
     fde->func = func;
     fde->arg = arg;
 
-#ifndef OS_WINDOWS
+#ifndef HAVE_WINSOCK
     fcntl(fd, F_SETFL, O_NONBLOCK);
 #endif
     fdevent_register(fde);
     dump_fde(fde, "connect");
-    fdevent_backend->fdevent_connect(fde);
+    fdevent_connect(fde);
     fde->state |= FDE_ACTIVE;
 }
 
@@ -191,7 +616,7 @@ void fdevent_remove(fdevent *fde)
     }
 
     if(fde->state & FDE_ACTIVE) {
-        fdevent_backend->fdevent_disconnect(fde);
+        fdevent_disconnect(fde);
         dump_fde(fde, "disconnect");
         fdevent_unregister(fde);
     }
@@ -208,7 +633,7 @@ void fdevent_set(fdevent *fde, unsigned events)
     if((fde->state & FDE_EVENTMASK) == events) return;
 
     if(fde->state & FDE_ACTIVE) {
-        fdevent_backend->fdevent_update(fde, events);
+        fdevent_update(fde, events);
         dump_fde(fde, "update");
     }
 
@@ -227,15 +652,47 @@ void fdevent_set(fdevent *fde, unsigned events)
     }
 }
 
-void fdevent_add(fdevent *fde, unsigned events) {
-    fdevent_set(fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
+void fdevent_add(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
+}
+
+void fdevent_del(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
 }
 
-void fdevent_del(fdevent *fde, unsigned events) {
-    fdevent_set(fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
+void fdevent_subproc_setup()
+{
+    int s[2];
+
+    if(sdb_socketpair(s)) {
+        FATAL("cannot create shell-exit socket-pair\n");
+    }
+    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);
 }
 
 void fdevent_loop()
 {
-    fdevent_backend->fdevent_loop();
+    fdevent *fde;
+    fdevent_subproc_setup();
+
+    for(;;) {
+        D("--- ---- waiting for events\n");
+
+        if (fdevent_process() < 0) {
+            return;
+        }
+
+        while((fde = fdevent_plist_dequeue())) {
+            fdevent_call_fdfunc(fde);
+        }
+    }
 }
index 6bb2d4bfb0ffe451f792cf5ce50ef3dd923dbf33..a6db9eab87c29ef5f46c7a4e989fe69c47698229 100644 (file)
 #define FDE_ERROR             0x0004
 #define FDE_TIMEOUT           0x0008
 
-
-#define FDE_EVENTMASK  0x00ff
-#define FDE_STATEMASK  0xff00
-
-#define FDE_ACTIVE     0x0100
-#define FDE_PENDING    0x0200
-#define FDE_CREATED    0x0400
-
 /* features that may be set (via the events set/add/del interface) */
 #define FDE_DONT_CLOSE        0x0080
 
diff --git a/src/fdevent_backend.h b/src/fdevent_backend.h
deleted file mode 100644 (file)
index 3213f58..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 __FDEVENT_I_H
-#define __FDEVENT_I_H
-
-#include "fdevent.h"
-
-extern fdevent list_pending;
-extern fdevent **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;
-
-#endif
diff --git a/src/fdevent_unix.c b/src/fdevent_unix.c
deleted file mode 100644 (file)
index d5b6807..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * 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 <sys/ioctl.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <fcntl.h>
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#include "fdevent_backend.h"
-#include "transport.h"
-#include "utils.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.
-int SHELL_EXIT_NOTIFY_FD = -1;
-
-#include <sys/select.h>
-
-
-static fd_set read_fds;
-static fd_set write_fds;
-static fd_set error_fds;
-
-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)
-{
-    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;
-
-        }
-    }
-    return n;
-}
-
-#if !DEBUG
-static inline void dump_all_fds(const char *extra_msg) {}
-#else
-static void dump_all_fds(const char *extra_msg)
-{
-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(" ");
-    }
-    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;
-
-    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);
-            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");
-    }
-    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();
-
-    for(;;) {
-        D("--- ---- waiting for events\n");
-
-        if (_fdevent_process() < 0) {
-            return;
-        }
-
-        while((fde = fdevent_plist_dequeue())) {
-            fdevent_call_fdfunc(fde);
-        }
-    }
-}
-
-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
-};
diff --git a/src/fdevent_windows.c b/src/fdevent_windows.c
deleted file mode 100644 (file)
index 5f750a4..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * 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 <winsock2.h>
-#include <ws2tcpip.h>
-#include <process.h>
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#include "utils.h"
-#include "utils_backend.h"
-#include "fdevent_backend.h"
-#include "transport.h"
-
-#define D(...) ((void)0)
-
-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;
-}
-
-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
-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 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;
-    }
-    return  pnode;
-}
-
-static void
-event_looper_hook( EventLooper  looper, int  fd, int  events )
-{
-    FH          f = _fh_from_int(fd);
-    EventHook  *pnode;
-    EventHook   node;
-
-    if (f == NULL)  /* invalid arg */ {
-        D("event_looper_hook: invalid fd=%d\n", fd);
-        return;
-    }
-
-    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);
-    }
-}
-
-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 EventLooperRec  win32_looper;
-
-static void _fdevent_init(void)
-{
-    win32_looper.htab_count = 0;
-    win32_looper.hooks      = NULL;
-}
-
-static void _fdevent_connect(fdevent *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 );
-}
-
-static void _fdevent_update(fdevent *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 );
-        }
-    }
-}
-
-static void fdevent_process()
-{
-    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)
-    {
-        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 (looper->htab_count == 0) {
-            D( "fdevent_process: nothing to wait for !!\n" );
-            return;
-        }
-
-        do
-        {
-            int   wait_ret;
-
-            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 );
-
-                /* 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;
-
-    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);
-        }
-    }
-}
-
-
-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
-};
-
-
old mode 100644 (file)
new mode 100755 (executable)
index b5c3e54..0a1c4ab
 /*
-* 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
-*
-*/
+ * 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 <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <dirent.h>
 #include <limits.h>
-#include <stdio.h>
+#include <sys/types.h>
+// tizen specific #include <zipfile/zipfile.h>
+
+#include "sysdeps.h"
+#include "sdb.h"
+#include "sdb_client.h"
+#include "file_sync_service.h"
+
+
+static unsigned total_bytes;
+static long long start_time;
+extern const char* get_basename(const char* filename);
 
-#include "file_sync_client.h"
-#include "file_sync_functions.h"
-#include "utils.h"
-#include "strutils.h"
+static long long NOW()
+{
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    return ((long long) tv.tv_usec) +
+        1000000LL * ((long long) tv.tv_sec);
+}
+
+static void BEGIN()
+{
+    total_bytes = 0;
+    start_time = NOW();
+}
 
-static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC* dstF);
+static void END(const char* filename)
+{
+    long long t = NOW() - start_time;
+    if(total_bytes == 0) return;
 
-__inline__ void create_copy_info(COPY_INFO** info, char* srcp, char* dstp) {
-    *info = (COPY_INFO*)malloc(sizeof(COPY_INFO));
-    (*info)->src = srcp;
-    (*info)->dst = dstp;
+    if (t == 0)  /* prevent division by 0 :-) */
+        t = 1000000;
+
+    fprintf(stderr,"%-30s   %lld KB/s (%lld bytes in %lld.%03llds)\n",
+            filename,
+            ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
+            (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
 }
 
-static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC* dstF) {
-    srcF->finalize(srcfd);
-    dstF->finalize(dstfd);
+
+void sync_quit(int fd)
+{
+    syncmsg msg;
+
+    msg.req.id = ID_QUIT;
+    msg.req.namelen = 0;
+
+    writex(fd, &msg.req, sizeof(msg.req));
 }
 
-static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes) {
-    void* srcstat;
-    if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) {
+typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
+
+int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
+{
+    syncmsg msg;
+    char buf[257];
+    int len;
+
+    len = strlen(path);
+    if(len > 1024) goto fail;
+
+    msg.req.id = ID_LIST;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        goto fail;
+    }
+
+    for(;;) {
+        if(readx(fd, &msg.dent, sizeof(msg.dent))) break;
+        if(msg.dent.id == ID_DONE) return 0;
+        if(msg.dent.id != ID_DENT) break;
+
+        len = ltohl(msg.dent.namelen);
+        if(len > 256) break;
+
+        if(readx(fd, buf, len)) break;
+        buf[len] = 0;
+
+        func(ltohl(msg.dent.mode),
+             ltohl(msg.dent.size),
+             ltohl(msg.dent.time),
+             buf, cookie);
+    }
+
+fail:
+    sdb_close(fd);
+    return -1;
+}
+
+typedef struct syncsendbuf syncsendbuf;
+
+struct syncsendbuf {
+    unsigned id;
+    unsigned size;
+    char data[SYNC_DATA_MAX];
+};
+
+static syncsendbuf send_buffer;
+
+int sync_readtime(int fd, const char *path, unsigned *timestamp)
+{
+    syncmsg msg;
+    int len = strlen(path);
+
+    msg.req.id = ID_STAT;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
         return -1;
     }
 
-    src_fd = srcF->readopen(src_fd, srcp, srcstat);
-    if(src_fd < 0) {
+    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
         return -1;
     }
 
-    dst_fd = dstF->writeopen(dst_fd, dstp, srcstat);
-    if(dst_fd < 0) {
+    if(msg.stat.id != ID_STAT) {
         return -1;
     }
 
-    FILE_BUFFER srcbuf;
-    srcbuf.id = ID_DATA;
+    *timestamp = ltohl(msg.stat.time);
+    return 0;
+}
+
+static int sync_start_readtime(int fd, const char *path)
+{
+    syncmsg msg;
+    int len = strlen(path);
 
-    while(1) {
-        int ret = srcF->readfile(src_fd, srcp, srcstat, &srcbuf);
-        if(ret == 0) {
+    msg.req.id = ID_STAT;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int sync_finish_readtime(int fd, unsigned int *timestamp,
+                                unsigned int *mode, unsigned int *size)
+{
+    syncmsg msg;
+
+    if(readx(fd, &msg.stat, sizeof(msg.stat)))
+        return -1;
+
+    if(msg.stat.id != ID_STAT)
+        return -1;
+
+    *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
+    *size = ltohl(msg.stat.size);
+
+    return 0;
+}
+
+int sync_readmode(int fd, const char *path, unsigned *mode)
+{
+    syncmsg msg;
+    int len = strlen(path);
+
+    msg.req.id = ID_STAT;
+    msg.req.namelen = htoll(len);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, path, len)) {
+        return -1;
+    }
+
+    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
+        return -1;
+    }
+
+    if(msg.stat.id != ID_STAT) {
+        return -1;
+    }
+
+    *mode = ltohl(msg.stat.mode);
+    return 0;
+}
+
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
+{
+    int lfd, err = 0;
+
+    lfd = sdb_open(path, O_RDONLY);
+    if(lfd < 0) {
+        fprintf(stderr,"cannot open '%s': %s\n", path, strerror(errno));
+        return -1;
+    }
+
+    sbuf->id = ID_DATA;
+    for(;;) {
+        int ret;
+
+        ret = sdb_read(lfd, sbuf->data, SYNC_DATA_MAX);
+        if(!ret)
+            break;
+
+        if(ret < 0) {
+            if(errno == EINTR)
+                continue;
+            fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
             break;
         }
-        else if(ret == 1) {
-            ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes);
-            if(ret < 0) {
-                srcF->readclose(src_fd);
-                dstF->writeclose(dst_fd, dstp, srcstat);
-                return -1;
-            }
+
+        sbuf->size = htoll(ret);
+        if(writex(fd, sbuf, sizeof(unsigned) * 2 + ret)){
+            err = -1;
+            break;
         }
-        else if(ret == 2) {
-            continue;
+        total_bytes += ret;
+    }
+
+    sdb_close(lfd);
+    return err;
+}
+
+static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
+{
+    int err = 0;
+    int total = 0;
+
+    sbuf->id = ID_DATA;
+    while (total < size) {
+        int count = size - total;
+        if (count > SYNC_DATA_MAX) {
+            count = SYNC_DATA_MAX;
         }
-        else if(ret == 3) {
-            ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes);
-            if(ret < 0) {
-                srcF->readclose(src_fd);
-                dstF->writeclose(dst_fd, dstp, srcstat);
-                return -1;
-            }
+
+        memcpy(sbuf->data, &file_buffer[total], count);
+        sbuf->size = htoll(count);
+        if(writex(fd, sbuf, sizeof(unsigned) * 2 + count)){
+            err = -1;
             break;
         }
-        else {
-            srcF->readclose(src_fd);
-            dstF->writeclose(dst_fd, dstp, srcstat);
-            if(ret == 4) {
-                return 0;
-            }
+        total += count;
+        total_bytes += count;
+    }
+
+    return err;
+}
+
+#ifdef HAVE_SYMLINKS
+static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
+{
+    int len, ret;
+
+    len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+    if(len < 0) {
+        fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
+        return -1;
+    }
+    sbuf->data[len] = '\0';
+
+    sbuf->size = htoll(len + 1);
+    sbuf->id = ID_DATA;
+
+    ret = writex(fd, sbuf, sizeof(unsigned) * 2 + len + 1);
+    if(ret)
+        return -1;
+
+    total_bytes += len + 1;
+
+    return 0;
+}
+#endif
+
+static int sync_send(int fd, const char *lpath, const char *rpath,
+                     unsigned mtime, mode_t mode, int verifyApk)
+{
+    syncmsg msg;
+    int len, r;
+    syncsendbuf *sbuf = &send_buffer;
+    char* file_buffer = NULL;
+    int size = 0;
+    char tmp[64];
+
+    len = strlen(rpath);
+    if(len > 1024) goto fail;
+
+    snprintf(tmp, sizeof(tmp), ",%d", mode);
+    r = strlen(tmp);
+#if 0 /* tizen specific */
+    if (verifyApk) {
+        int lfd;
+        zipfile_t zip;
+        zipentry_t entry;
+        int amt;
+
+        // if we are transferring an APK file, then sanity check to make sure
+        // we have a real zip file that contains an AndroidManifest.xml
+        // this requires that we read the entire file into memory.
+        lfd = sdb_open(lpath, O_RDONLY);
+        if(lfd < 0) {
+            fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
             return -1;
         }
+
+        size = sdb_lseek(lfd, 0, SEEK_END);
+        if (size == -1 || -1 == sdb_lseek(lfd, 0, SEEK_SET)) {
+            fprintf(stderr, "error seeking in file '%s'\n", lpath);
+            sdb_close(lfd);
+            return 1;
+        }
+
+        file_buffer = (char *)malloc(size);
+        if (file_buffer == NULL) {
+            fprintf(stderr, "could not allocate buffer for '%s'\n",
+                    lpath);
+            sdb_close(lfd);
+            return 1;
+        }
+        amt = sdb_read(lfd, file_buffer, size);
+        if (amt != size) {
+            fprintf(stderr, "error reading from file: '%s'\n", lpath);
+            sdb_close(lfd);
+            free(file_buffer);
+            return 1;
+        }
+
+        sdb_close(lfd);
+
+        zip = init_zipfile(file_buffer, size);
+        if (zip == NULL) {
+            fprintf(stderr, "file '%s' is not a valid zip file\n",
+                    lpath);
+            free(file_buffer);
+            return 1;
+        }
+
+        entry = lookup_zipentry(zip, "AndroidManifest.xml");
+        release_zipfile(zip);
+        if (entry == NULL) {
+            fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
+                    lpath);
+            free(file_buffer);
+            return 1;
+        }
+    }
+#endif
+    msg.req.id = ID_SEND;
+    msg.req.namelen = htoll(len + r);
+
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, rpath, len) || writex(fd, tmp, r)) {
+        free(file_buffer);
+        goto fail;
+    }
+
+    if (file_buffer) {
+        write_data_buffer(fd, file_buffer, size, sbuf);
+        free(file_buffer);
+    } else if (S_ISREG(mode))
+        write_data_file(fd, lpath, sbuf);
+#ifdef HAVE_SYMLINKS
+    else if (S_ISLNK(mode))
+        write_data_link(fd, lpath, sbuf);
+#endif
+    else
+        goto fail;
+
+    msg.data.id = ID_DONE;
+    msg.data.size = htoll(mtime);
+    if(writex(fd, &msg.data, sizeof(msg.data)))
+        goto fail;
+
+    if(readx(fd, &msg.status, sizeof(msg.status)))
+        return -1;
+
+    if(msg.status.id != ID_OKAY) {
+        if(msg.status.id == ID_FAIL) {
+            len = ltohl(msg.status.msglen);
+            if(len > 256) len = 256;
+            if(readx(fd, sbuf->data, len)) {
+                return -1;
+            }
+            sbuf->data[len] = 0;
+        } else
+            strcpy(sbuf->data, "unknown reason");
+
+        fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
+        return -1;
+    }
+
+    return 0;
+
+fail:
+    fprintf(stderr,"protocol failure\n");
+    sdb_close(fd);
+    return -1;
+}
+
+static int mkdirs(char *name)
+{
+    int ret;
+    char *x = name + 1;
+
+    for(;;) {
+        x = sdb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        ret = sdb_mkdir(name, 0775);
+        *x = OS_PATH_SEPARATOR;
+        if((ret < 0) && (errno != EEXIST)) {
+            return ret;
+        }
+        x++;
     }
-    srcF->readclose(src_fd);
-    dstF->writeclose(dst_fd, dstp, srcstat);
-    free(srcstat);
-    return 1;
+    return 0;
 }
 
-static void free_copyinfo(void* data) {
-    COPY_INFO* info = (COPY_INFO*)data;
-    if(info != NULL) {
-        if(info->src != NULL) {
-            free(info->src);
+int sync_recv(int fd, const char *rpath, const char *lpath)
+{
+    syncmsg msg;
+    int len;
+    int lfd = -1;
+    char *buffer = send_buffer.data;
+    unsigned id;
+
+    len = strlen(rpath);
+    if(len > 1024) return -1;
+
+    msg.req.id = ID_RECV;
+    msg.req.namelen = htoll(len);
+    if(writex(fd, &msg.req, sizeof(msg.req)) ||
+       writex(fd, rpath, len)) {
+        return -1;
+    }
+
+    if(readx(fd, &msg.data, sizeof(msg.data))) {
+        return -1;
+    }
+    id = msg.data.id;
+
+    if((id == ID_DATA) || (id == ID_DONE)) {
+        sdb_unlink(lpath);
+        mkdirs((char *)lpath);
+        lfd = sdb_creat(lpath, 0644);
+        if(lfd < 0) {
+            fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
+            return -1;
+        }
+        goto handle_data;
+    } else {
+        goto remote_error;
+    }
+
+    for(;;) {
+        if(readx(fd, &msg.data, sizeof(msg.data))) {
+            return -1;
+        }
+        id = msg.data.id;
+
+    handle_data:
+        len = ltohl(msg.data.size);
+        if(id == ID_DONE) break;
+        if(id != ID_DATA) goto remote_error;
+        if(len > SYNC_DATA_MAX) {
+            fprintf(stderr,"data overrun\n");
+            sdb_close(lfd);
+            return -1;
+        }
+
+        if(readx(fd, buffer, len)) {
+            sdb_close(lfd);
+            return -1;
+        }
+
+        if(writex(lfd, buffer, len)) {
+            fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
+            sdb_close(lfd);
+            return -1;
         }
-        if(info->dst != NULL) {
-            free(info->dst);
+
+        total_bytes += len;
+    }
+
+    sdb_close(lfd);
+    return 0;
+
+remote_error:
+    sdb_close(lfd);
+    sdb_unlink(lpath);
+
+    if(id == ID_FAIL) {
+        len = ltohl(msg.data.size);
+        if(len > 256) len = 256;
+        if(readx(fd, buffer, len)) {
+            return -1;
         }
-        free(info);
+        buffer[len] = 0;
+    } else {
+        memcpy(buffer, &id, 4);
+        buffer[4] = 0;
+//        strcpy(buffer,"unknown reason");
     }
+    fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
+    return 0;
 }
 
-int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int is_utf8, void** ext_argv) {
 
-    unsigned total_bytes = 0;
-    long long start_time = NOW();
 
-    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);
-    dst_fd = dstF->initialize(dstp, ext_argv);
-    if(src_fd < 0 || dst_fd < 0) {
+
+static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
+                          const char *name, void *cookie)
+{
+    printf("%08x %08x %08x %s\n", mode, size, time, name);
+}
+
+int do_sync_ls(const char *path)
+{
+    int fd = sdb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", sdb_error());
         return 1;
     }
-    if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) {
-        finalize(src_fd, dst_fd, srcF, dstF);
+
+    if(sync_ls(fd, path, do_sync_ls_cb, 0)) {
         return 1;
+    } else {
+        sync_quit(fd);
+        return 0;
     }
-    int src_dir = srcF->is_dir(srcp, srcstat, 1);
-    int dst_dir = 1;
+}
 
-    if(dstF->_stat(dst_fd, dstp, &dststat, 0) >= 0) {
-        dst_dir = dstF->is_dir(dstp, dststat, 0);
+typedef struct copyinfo copyinfo;
+
+struct copyinfo
+{
+    copyinfo *next;
+    const char *src;
+    const char *dst;
+    unsigned int time;
+    unsigned int mode;
+    unsigned int size;
+    int flag;
+    //char data[0];
+};
+
+copyinfo *mkcopyinfo(const char *spath, const char *dpath,
+                     const char *name, int isdir)
+{
+    int slen = strlen(spath);
+    int dlen = strlen(dpath);
+    int nlen = strlen(name);
+    int ssize = slen + nlen + 2;
+    int dsize = dlen + nlen + 2;
+
+    copyinfo *ci = malloc(sizeof(copyinfo) + ssize + dsize);
+    if(ci == 0) {
+        fprintf(stderr,"out of memory\n");
+        abort();
     }
-    free(dststat);
-    free(srcstat);
-    if(src_dir == -1 || dst_dir == -1) {
-        finalize(src_fd, dst_fd, srcF, dstF);
-        return 1;
+
+    ci->next = 0;
+    ci->time = 0;
+    ci->mode = 0;
+    ci->size = 0;
+    ci->flag = 0;
+    ci->src = (const char*)(ci + 1);
+    ci->dst = ci->src + ssize;
+    snprintf((char*) ci->src, ssize, isdir ? "%s%s/" : "%s%s", spath, name);
+    snprintf((char*) ci->dst, dsize, isdir ? "%s%s/" : "%s%s", dpath, name);
+
+//    fprintf(stderr,"mkcopyinfo('%s','%s')\n", ci->src, ci->dst);
+    return ci;
+}
+
+
+static int local_build_list(copyinfo **filelist,
+                            const char *lpath, const char *rpath)
+{
+    DIR *d;
+    struct dirent *de;
+    struct stat st;
+    copyinfo *dirlist = 0;
+    copyinfo *ci, *next;
+
+//    fprintf(stderr,"local_build_list('%s','%s')\n", lpath, rpath);
+
+    d = opendir(lpath);
+    if(d == 0) {
+        fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
+        return -1;
     }
-    //copy file
-    else if(src_dir == 0) {
-        /* if we're copying a local file to a remote directory,
-        ** we *really* want to copy to remotedir + "/" + localfilename
-        */
-        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) {
-                dstp = ansi_to_utf8(full_dstpath);
+
+    while((de = readdir(d))) {
+        char stat_path[PATH_MAX];
+        char *name = de->d_name;
+
+        if(name[0] == '.') {
+            if(name[1] == 0) continue;
+            if((name[1] == '.') && (name[2] == 0)) continue;
+        }
+
+        /*
+         * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
+         * always returns DT_UNKNOWN, so we just use stat() for all cases.
+         */
+        if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
+            continue;
+        strcpy(stat_path, lpath);
+        strcat(stat_path, de->d_name);
+        stat(stat_path, &st);
+
+        if (S_ISDIR(st.st_mode)) {
+            ci = mkcopyinfo(lpath, rpath, name, 1);
+            ci->next = dirlist;
+            dirlist = ci;
+        } else {
+            ci = mkcopyinfo(lpath, rpath, name, 0);
+            if(lstat(ci->src, &st)) {
+                fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                closedir(d);
+                if (ci != NULL) {
+                    free(ci);
+                }
+                return -1;
             }
-            else {
-                dstp = full_dstpath;
+            if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                fprintf(stderr, "skipping special file '%s'\n", ci->src);
+                free(ci);
+            } else {
+                ci->time = st.st_mtime;
+                ci->mode = st.st_mode;
+                ci->size = st.st_size;
+                ci->next = *filelist;
+                *filelist = ci;
             }
         }
-        int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes);
-        if(result < 0) {
-            finalize(src_fd, dst_fd, srcF, dstF);
-            return 1;
+    }
+
+    closedir(d);
+
+    for(ci = dirlist; ci != 0; ci = next) {
+        next = ci->next;
+        local_build_list(filelist, ci->src, ci->dst);
+        free(ci);
+    }
+
+    return 0;
+}
+
+
+static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
+{
+    copyinfo *filelist = 0;
+    copyinfo *ci, *next;
+    int pushed = 0;
+    int skipped = 0;
+
+    if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
+    if(lpath[strlen(lpath) - 1] != '/') {
+        int  tmplen = strlen(lpath)+2;
+        char *tmp = malloc(tmplen);
+        if(tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/",lpath);
+        lpath = tmp;
+    }
+    if(rpath[strlen(rpath) - 1] != '/') {
+        int tmplen = strlen(rpath)+2;
+        char *tmp = malloc(tmplen);
+        if(tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/",rpath);
+        rpath = tmp;
+    }
+
+    if(local_build_list(&filelist, lpath, rpath)) {
+        return -1;
+    }
+
+    if(checktimestamps){
+        for(ci = filelist; ci != 0; ci = ci->next) {
+            if(sync_start_readtime(fd, ci->dst)) {
+                return 1;
+            }
+        }
+        for(ci = filelist; ci != 0; ci = ci->next) {
+            unsigned int timestamp, mode, size;
+            if(sync_finish_readtime(fd, &timestamp, &mode, &size))
+                return 1;
+            if(size == ci->size) {
+                /* for links, we cannot update the atime/mtime */
+                if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                    ci->flag = 1;
+            }
         }
-        if(result == 1) {
+    }
+    for(ci = filelist; ci != 0; ci = next) {
+        next = ci->next;
+        if(ci->flag == 0) {
+            fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
+            if(!listonly &&
+               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
+                return 1;
+            }
             pushed++;
+        } else {
+            skipped++;
+        }
+        free(ci);
+    }
+
+    fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
+            pushed, (pushed == 1) ? "" : "s",
+            skipped, (skipped == 1) ? "" : "s");
+
+    return 0;
+}
+
+
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int isUtf8)
+{
+    struct stat st;
+    unsigned mode;
+    int fd;
+    char *tmp = NULL;
+    char *utf8 = NULL;
+    int ret = 0;
+
+    fd = sdb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", sdb_error());
+        return 1;
+    }
+
+    if(stat(lpath, &st)) {
+        fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
+        sync_quit(fd);
+        return 1;
+    }
+
+    if(S_ISDIR(st.st_mode)) {
+        BEGIN();
+        if(copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
+            return 1;
+        } else {
+            END(get_basename(lpath));
+            sync_quit(fd);
         }
-        else {
-            skiped++;
+    } else {
+        if(sync_readmode(fd, rpath, &mode)) {
+            return 1;
+        }
+
+        if((mode != 0) && S_ISDIR(mode)) {
+                /* if we're copying a local file to a remote directory,
+                ** we *really* want to copy to remotedir + "/" + localfilename
+                */
+            const char *name = sdb_dirstop(lpath);
+            if(name == 0) {
+                name = lpath;
+            } else {
+                name++;
+            }
+            int  tmplen = strlen(name) + strlen(rpath) + 2;
+            tmp = malloc(strlen(name) + strlen(rpath) + 2);
+            if(tmp == 0) return 1;
+            snprintf(tmp, tmplen, "%s/%s", rpath, name);
+            if (isUtf8 != 0) { //ansi to utf8
+                utf8 = ansi_to_utf8(tmp);
+                rpath = utf8;
+            } else {
+                rpath = tmp;
+            }
+        }// FIXME
+        /* else {
+            fprintf(stderr, "error: file exists : %s\n", rpath);
+            return 1;
+        }*/
+
+        BEGIN();
+        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
+            ret = 1;
+            goto cleanup;
+        } else {
+            END(get_basename(lpath));
+            sync_quit(fd);
+            ret = 0;
+            goto cleanup;
         }
     }
-    else if(src_dir == 2) {
-        skiped++;
+    return 0;
+cleanup:
+    if (tmp != NULL) {
+        free(tmp);
     }
-    //copy directory
-    else {
-        LIST_NODE* dir_list = NULL;
-        //for free later, do strncpy
-        int len = strlen(srcp);
-        char* _srcp = (char*)malloc(sizeof(char)*len + 1);
-        s_strncpy(_srcp, srcp, len+1);
+    if (utf8 != NULL) {
+        free(utf8);
+    }
+    return ret;
+}
 
-        len = strlen(dstp);
-        char* _dstp = (char*)malloc(sizeof(char)*len + 1);
-        s_strncpy(_dstp, dstp, len+1);
 
-        COPY_INFO* __info;
-        create_copy_info(&__info, _srcp, _dstp);
-        append(&dir_list, __info);
+typedef struct {
+    copyinfo **filelist;
+    copyinfo **dirlist;
+    const char *rpath;
+    const char *lpath;
+} sync_ls_build_list_cb_args;
+
+void
+sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
+                      const char *name, void *cookie)
+{
+    sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
+    copyinfo *ci;
+
+    if (S_ISDIR(mode)) {
+        copyinfo **dirlist = args->dirlist;
+
+        /* Don't try recursing down "." or ".." */
+        if (name[0] == '.') {
+            if (name[1] == '\0') return;
+            if ((name[1] == '.') && (name[2] == '\0')) return;
+        }
+
+        ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
+        ci->next = *dirlist;
+        *dirlist = ci;
+    } else if (S_ISREG(mode) || S_ISLNK(mode)) {
+        copyinfo **filelist = args->filelist;
+
+        ci = mkcopyinfo(args->rpath, args->lpath, name, 0);
+        ci->time = time;
+        ci->mode = mode;
+        ci->size = size;
+        ci->next = *filelist;
+        *filelist = ci;
+    } else {
+        fprintf(stderr, "skipping special file '%s'\n", name);
+    }
+}
+
+static int remote_build_list(int syncfd, copyinfo **filelist,
+                             const char *rpath, const char *lpath)
+{
+    copyinfo *dirlist = NULL;
+    sync_ls_build_list_cb_args args;
+
+    args.filelist = filelist;
+    args.dirlist = &dirlist;
+    args.rpath = rpath;
+    args.lpath = lpath;
+
+    /* Put the files/dirs in rpath on the lists. */
+    if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
+        return 1;
+    }
+
+    /* Recurse into each directory we found. */
+    while (dirlist != NULL) {
+        copyinfo *next = dirlist->next;
+        if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
+            return 1;
+        }
+        free(dirlist);
+        dirlist = next;
+    }
+
+    return 0;
+}
+
+static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
+                                 int checktimestamps)
+{
+    copyinfo *filelist = 0;
+    copyinfo *ci, *next;
+    int pulled = 0;
+    int skipped = 0;
+
+    /* Make sure that both directory paths end in a slash. */
+    if (rpath[0] == 0 || lpath[0] == 0) return -1;
+    if (rpath[strlen(rpath) - 1] != '/') {
+        int  tmplen = strlen(rpath) + 2;
+        char *tmp = malloc(tmplen);
+        if (tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/", rpath);
+        rpath = tmp;
+    }
+    if (lpath[strlen(lpath) - 1] != '/') {
+        int  tmplen = strlen(lpath) + 2;
+        char *tmp = malloc(tmplen);
+        if (tmp == 0) return -1;
+        snprintf(tmp, tmplen, "%s/", lpath);
+        lpath = tmp;
+    }
 
-        while(dir_list != NULL) {
-            LIST_NODE* entry_list = NULL;
-            COPY_INFO* _info = (COPY_INFO*)dir_list->data;
-            if(srcF->get_dirlist(src_fd, _info->src, _info->dst, &entry_list) < 0) {
-                finalize(src_fd, dst_fd, srcF, dstF);
+    fprintf(stderr, "pull: building file list...\n");
+    /* Recursively build the list of files to copy. */
+    if (remote_build_list(fd, &filelist, rpath, lpath)) {
+        return -1;
+    }
+
+#if 0
+    if (checktimestamps) {
+        for (ci = filelist; ci != 0; ci = ci->next) {
+            if (sync_start_readtime(fd, ci->dst)) {
+                return 1;
+            }
+        }
+        for (ci = filelist; ci != 0; ci = ci->next) {
+            unsigned int timestamp, mode, size;
+            if (sync_finish_readtime(fd, &timestamp, &mode, &size))
+                return 1;
+            if (size == ci->size) {
+                /* for links, we cannot update the atime/mtime */
+                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+                    ci->flag = 1;
+            }
+        }
+    }
+#endif
+    for (ci = filelist; ci != 0; ci = next) {
+        next = ci->next;
+        if (ci->flag == 0) {
+            fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
+            if (sync_recv(fd, ci->src, ci->dst)) {
                 return 1;
             }
-            LIST_NODE* curptr = entry_list;
+            pulled++;
+        } else {
+            skipped++;
+        }
+        free(ci);
+    }
 
-            while(curptr != NULL) {
-                COPY_INFO* info = (COPY_INFO*)curptr->data;
-                char* src_p = (char*)info->src;
-                char* dst_p = (char*)info->dst;
+    fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
+            pulled, (pulled == 1) ? "" : "s",
+            skipped, (skipped == 1) ? "" : "s");
 
-                if(srcF->_stat(src_fd, src_p, &srcstat, 1) < 0) {
-                    finalize(src_fd, dst_fd, srcF, dstF);
-                    return 1;
-                }
+    return 0;
+}
 
-                src_dir = srcF->is_dir(src_p, srcstat, 1);
-                free(srcstat);
-                if(src_dir < 0) {
-                    finalize(src_fd, dst_fd, srcF, dstF);
-                    return 1;
-                }
-                if(src_dir == 1) {
-                    append(&dir_list, info);
-                }
-                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);
-                        if(result < 0) {
-                            finalize(src_fd, dst_fd, srcF, dstF);
-                            return 1;
-                        }
-                        if(result == 1) {
-                            pushed++;
-                        }
-                        else {
-                            skiped++;
-                        }
-                    }
-                    else if(src_dir == 2) {
-                        skiped++;
-                    }
-                    free(src_p);
-                    free(dst_p);
-                    free(info);
+int do_sync_pull(const char *rpath, const char *lpath)
+{
+    unsigned mode;
+    struct stat st;
+
+    int fd;
+
+    fd = sdb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", sdb_error());
+        return 1;
+    }
+
+    if(sync_readmode(fd, rpath, &mode)) {
+        return 1;
+    }
+    if(mode == 0) {
+        fprintf(stderr,"'%s': No such file or directory\n", rpath);
+        sync_quit(fd);
+        return 1;
+    }
+
+    if(S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
+        if(stat(lpath, &st) == 0) {
+            if(S_ISDIR(st.st_mode)) {
+                    /* if we're copying a remote file to a local directory,
+                    ** we *really* want to copy to localdir + "/" + remotefilename
+                    */
+                const char *name = sdb_dirstop(rpath);
+                if(name == 0) {
+                    name = rpath;
+                } else {
+                    name++;
                 }
-                curptr = curptr->next_ptr;
+                int  tmplen = strlen(name) + strlen(lpath) + 2;
+                char *tmp = malloc(tmplen);
+                if(tmp == 0) return 1;
+                snprintf(tmp, tmplen, "%s/%s", lpath, name);
+                lpath = tmp;
             }
-            free_list(entry_list, no_free);
-            remove_first(&dir_list, free_copyinfo);
         }
+        BEGIN();
+        if(sync_recv(fd, rpath, lpath)) {
+            return 1;
+        } else {
+            END(get_basename(rpath));
+            sync_quit(fd);
+            return 0;
+        }
+    } else if(S_ISDIR(mode)) {
+        BEGIN();
+        if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
+            return 1;
+        } else {
+            END(get_basename(rpath));
+            sync_quit(fd);
+            return 0;
+        }
+    } else {
+        fprintf(stderr,"'%s': No such file or directory\n", rpath);
+        return 1;
     }
+}
 
-    fprintf(stderr,"%d file(s) pushed. %d file(s) skipped.\n",
-            pushed, skiped);
-
-    long long end_time = NOW() - start_time;
+int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+{
+    fprintf(stderr,"syncing %s...\n",rpath);
 
-    if(end_time != 0) {
-        fprintf(stderr,"%-30s   %lld KB/s (%lld bytes in %lld.%03llds)\n",
-                srcp,
-                ((((long long) total_bytes) * 1000000LL) / end_time) / 1024LL,
-                (long long) total_bytes, (end_time / 1000000LL), (end_time % 1000000LL) / 1000LL);
+    int fd = sdb_connect("sync:");
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", sdb_error());
+        return 1;
     }
 
-    finalize(src_fd, dst_fd, srcF, dstF);
-    return 0;
+    BEGIN();
+    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+        return 1;
+    } else {
+        END(get_basename(lpath));
+        sync_quit(fd);
+        return 0;
+    }
 }
diff --git a/src/file_sync_client.h b/src/file_sync_client.h
deleted file mode 100644 (file)
index 7bb53bb..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-* 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 FILE_SYNC_CLIENT_H_
-#define FILE_SYNC_CLIENT_H_
-
-#include "file_sync_functions.h"
-
-__inline__ void create_copy_info(COPY_INFO** info, char* srcp, char* dstp);
-int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int is_utf8, void** ext_argv);
-
-#endif /* FILE_SYNC_CLIENT_H_ */
diff --git a/src/file_sync_functions.c b/src/file_sync_functions.c
deleted file mode 100644 (file)
index 7d2ae12..0000000
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
-* 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 <stdio.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include "fdevent.h"
-#include "utils.h"
-#include "sdb_client.h"
-#include "file_sync_functions.h"
-#include "linkedlist.h"
-
-#include "strutils.h"
-#include "file_sync_client.h"
-
-const FILE_FUNC LOCAL_FILE_FUNC = {
-        initialize_local,
-        finalize_local,
-        _stat_local,
-        is_directory_local,
-        readopen_local,
-        readclose_local,
-        writeopen_local,
-        writeclose_local,
-        readfile_local,
-        writefile_local,
-        getdirlist_local,
-};
-
-const FILE_FUNC REMOTE_FILE_FUNC = {
-        initialize_remote,
-        finalize_remote,
-        _stat_remote,
-        is_directory_remote,
-        readopen_remote,
-        readclose_remote,
-        writeopen_remote,
-        writeclose_remote,
-        readfile_remote,
-        writefile_remote,
-        getdirlist_remote,
-};
-
-static int sync_readmode(int fd, const char *path, unsigned *mode);
-
-//return > 0 fd, = 0 success, < 0 fail.
-int initialize_local(char* path, void** extargv) {
-    return 0;
-}
-
-//return fd
-int initialize_remote(char* path, void** extargv) {
-
-    int fd = sdb_connect("sync:", extargv);
-
-    if(fd < 0) {
-        fprintf(stderr,"cannot sync remote: %s\n", strerror(errno));
-        return -1;
-    }
-
-    return fd;
-}
-
-void finalize_local(int fd) {
-
-}
-
-void finalize_remote(int fd) {
-    syncmsg msg;
-
-    msg.req.id = ID_QUIT;
-    msg.req.namelen = 0;
-
-    writex(fd, &msg.req, sizeof(msg.req));
-
-    if(fd > 0) {
-        sdb_close(fd);
-    }
-}
-
-//TODO stat should be freed.
-int _stat_local(int fd, char* path, void** _stat, int show_error) {
-    struct stat* st = (struct stat*)malloc(sizeof(struct stat));
-    if(lstat(path, st)) {
-        if(show_error) {
-            fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
-        }
-        return -1;
-    }
-
-    *_stat = st;
-    return 1;
-}
-
-int _stat_remote(int fd, char* path, void** stat, int show_error) {
-
-    unsigned* mode = (unsigned*)malloc(sizeof(unsigned));
-    if(sync_readmode(fd, path, mode)) {
-        if(show_error) {
-            fprintf(stderr,"cannot read mode '%s': %s\n", path, strerror(errno));
-        }
-        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) {
-        if(show_error) {
-            fprintf(stderr,"'%s': No such file or directory\n", path);
-        }
-        return -1;
-    }
-
-    if(S_ISDIR(st->st_mode)) {
-        return 1;
-    }
-    if(S_ISREG(st->st_mode) || S_ISLNK(st->st_mode)) {
-        return 0;
-    }
-
-    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) {
-
-    struct stat* st = srcstat;
-    if(S_ISREG(st->st_mode)) {
-        fd = sdb_open(srcp, O_RDONLY);
-
-        if(fd < 0) {
-            fprintf(stderr,"cannot open local file '%s': %s\n", srcp, strerror(errno));
-            return -1;
-        }
-
-        return fd;
-    }
-
-    return fd;
-}
-
-int readopen_remote(int fd, char* srcp, void* srcstat) {
-    syncmsg msg;
-    int len;
-
-    len = strlen(srcp);
-    if(len > SYNC_CHAR_MAX) {
-        fprintf(stderr,"protocol failure while opening remote file '%s' for reading. request should not exceeds %d\n", srcp, SYNC_CHAR_MAX);
-        return -1;
-    }
-
-    msg.req.id = ID_RECV;
-    msg.req.namelen = htoll(len);
-
-    if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, srcp, len)) {
-        fprintf(stderr,"exception occurred while sending read request to remote file'%s': %s\n", srcp, strerror(errno));
-        return -1;
-    }
-    return fd;
-}
-
-int readclose_local(int lfd) {
-    if(lfd > 0) {
-        sdb_close(lfd);
-    }
-    return lfd;
-}
-
-int readclose_remote(int fd) {
-    return fd;
-}
-
-int writeopen_local(int fd, char* dstp, void* stat) {
-    sdb_unlink(dstp);
-    mkdirs(dstp);
-    fd = sdb_creat(dstp, 0644);
-
-    if(fd < 0) {
-        fprintf(stderr,"cannot create '%s': %s\n", dstp, strerror(errno));
-        return -1;
-    }
-
-    return fd;
-}
-
-//return fd.
-int writeopen_remote(int fd, char* dstp, void* stat) {
-    syncmsg msg;
-    struct stat* st = (struct stat*)stat;
-
-    int len, r;
-    int total_len;
-    char tmp[64];
-
-    snprintf(tmp, sizeof(tmp), ",%d", st->st_mode);
-    len = strlen(dstp);
-    r = strlen(tmp);
-    total_len = len + r;
-
-    if(total_len > PATH_MAX) {
-        fprintf(stderr,"protocol failure. buffer [%s%s] exceeds limits: %d\n", dstp, tmp, PATH_MAX);
-        return -1;
-    }
-
-    msg.req.id = ID_SEND;
-    msg.req.namelen = htoll(total_len);
-
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-            writex(fd, dstp, len) ||
-            writex(fd, tmp, r)) {
-        fprintf(stderr,"exception occurred while sending read msg: %s\n", dstp);
-        return -1;
-    }
-
-    return fd;
-}
-
-int writeclose_local(int fd, char*dstp, void* stat) {
-    if(fd > 0) {
-        sdb_close(fd);
-    }
-    return fd;
-}
-
-int writeclose_remote(int fd, char* dstp, void* stat) {
-    struct stat* st = (struct stat*)stat;
-    syncmsg msg;
-    msg.data.id = ID_DONE;
-    msg.data.size = htoll(st->st_mtime);
-
-    if(writex(fd, &msg.data, sizeof(msg.data))) {
-        fprintf(stderr,"exception occurred while sending close msg: %s\n", dstp);
-        return -1;
-    }
-
-    if(readx(fd, &msg.status, sizeof(msg.status))) {
-        fprintf(stderr,"exception occurred while receiving close msg: %s\n", dstp);
-        return -1;
-    }
-
-    if(msg.status.id != ID_OKAY) {
-        char buf[256];
-        if(msg.status.id == ID_FAIL) {
-            int len = ltohl(msg.status.msglen);
-            if(len > 256) {
-                len = 255;
-            }
-            if(readx(fd, buf, len)) {
-                fprintf(stderr, "cannot close remote file '%s' and its failed msg. %s\n", dstp, strerror(errno));
-                return -1;
-            }
-            buf[len] = 0;
-        } else {
-            strcpy(buf, "unknown reason");
-        }
-
-        fprintf(stderr,"cannot close remote file '%s' with failed msg '%s'. %s\n", dstp, buf, strerror(errno));
-        return -1;
-    }
-
-    return fd;
-}
-
-//4: finish skipped
-//0: finish normally.
-//2: continue load but don't write.
-//-1:fail
-//1: write and continue load
-//3: write and stop
-int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) {
-    struct stat* st = (struct stat*)stat;
-
-    if (S_ISREG(st->st_mode)) {
-        int ret;
-
-        ret = sdb_read(lfd, sbuf->data, SYNC_DATA_MAX);
-        if (!ret) {
-            //Finish normally.
-            return 0;
-        }
-        if (ret < 0) {
-            //continue load but don't write
-            if (errno == EINTR) {
-                return 2;
-            }
-            //fail.
-            fprintf(stderr, "cannot read local file '%s': %s\n", srcpath, strerror(errno));
-            return -1;
-        }
-
-         sbuf->size = htoll(ret);
-        //write and continue load.
-        return 1;
-    }
-#ifdef HAVE_SYMLINKS
-    else if (S_ISLNK(st->st_mode)) {
-        int len;
-
-        len = readlink(srcpath, sbuf->data, SYNC_DATA_MAX-1);
-        //fail
-        if(len < 0) {
-            fprintf(stderr, "cannot read local link '%s': %s\n", srcpath, strerror(errno));
-            return -1;
-        }
-        sbuf->data[len] = '\0';
-        sbuf->size = htoll(len + 1);
-
-        //write and stop.
-        return 3;
-    }
-#endif
-
-    fprintf(stderr,"protocol failure\n");
-
-    //fail
-    return -1;
-}
-
-int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) {
-    syncmsg msg;
-    unsigned id;
-
-    if(readx(fd, &(msg.data), sizeof(msg.data))) {
-        fprintf(stderr, "cannot read remote file status '%s': %s\n", srcpath, strerror(errno));
-        return -1;
-    }
-    id = msg.data.id;
-    buffer->size = ltohl(msg.data.size);
-
-    if(id == ID_DONE) {
-        //Finish normally.
-        return 0;
-    }
-    //fail
-    if(id != ID_DATA) {
-        int len;
-        if(id == ID_FAIL) {
-            int len = buffer->size;
-            if(len > 256) {
-                len = 255;
-            }
-            if(readx(fd, buffer->data, len)) {
-                fprintf(stderr, "cannot read remote file '%s' and its failed msg. %s\n", srcpath, strerror(errno));
-                return -1;
-            }
-        }
-        else {
-            len = 4;
-            memcpy(buffer->data, &id, len);
-        }
-        buffer->data[len] = 0;
-
-        fprintf(stderr, "cannot read remote file '%s' with its failed msg '%s'. %s\n", srcpath, buffer->data, strerror(errno));
-        return 4;
-    }
-    //fail
-    if(buffer->size > SYNC_DATA_MAX) {
-        fprintf(stderr,"data overrun\n");
-        return -1;
-    }
-
-    //fail
-    if(readx(fd, buffer->data, buffer->size)) {
-        fprintf(stderr, "cannot read remote file '%s': %s\n", srcpath, strerror(errno));
-        return -1;
-    }
-
-    //write and continue load
-    return 1;
-}
-
-int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) {
-    char* data = sbuf->data;
-    unsigned len = sbuf->size;
-
-    if(writex(fd, data, len)) {
-        fprintf(stderr,"cannot write '%s': %s\n", dstp, strerror(errno));
-        return -1;
-    }
-
-    *total_bytes += len;
-    return 0;
-}
-
-int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) {
-    int size = ltohl(sbuf->size);
-
-    if(writex(fd, sbuf, sizeof(unsigned)*2 + size)) {
-        fprintf(stderr, "cannot write remote file '%s': %s\n", dstp, strerror(errno));
-        return -1;
-    }
-
-    *total_bytes += size;
-    return 0;
-}
-
-int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) {
-    DIR* d;
-
-    d = opendir(src_dir);
-    if(d == 0) {
-        fprintf(stderr,"cannot open '%s': %s\n", src_dir, strerror(errno));
-        readclose_local(fd);
-        return -1;
-    }
-    struct dirent* de;
-
-    while((de = readdir(d))) {
-        char* file_name = de->d_name;
-
-        if(file_name[0] == '.') {
-            if(file_name[1] == 0) {
-                continue;
-            }
-            if((file_name[1] == '.') && (file_name[2] == 0)) {
-                continue;
-            }
-        }
-
-        char* src_full_path = (char*)malloc(sizeof(char)*PATH_MAX);
-        append_file(src_full_path, src_dir, file_name);
-
-        char* dst_full_path = (char*)malloc(sizeof(char)*PATH_MAX);
-        append_file(dst_full_path, dst_dir, file_name);
-
-        COPY_INFO* info;
-        create_copy_info(&info, src_full_path, dst_full_path);
-        append(dirlist, info);
-    }
-
-    closedir(d);
-    return fd;
-}
-
-int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) {
-    syncmsg msg;
-    int len;
-
-    len = strlen(src_dir);
-
-    if(len > SYNC_CHAR_MAX) {
-        fprintf(stderr,"protocol failure while getting dirlist of remote file '%s'. request should not exceeds %d\n", src_dir, SYNC_CHAR_MAX);
-        return -1;
-    }
-
-    msg.req.id = ID_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);
-        return -1;
-    }
-
-    while(1) {
-        if(readx(fd, &msg.dent, sizeof(msg.dent))) {
-            fprintf(stderr,"cannot read dirlist: '%s'", src_dir);
-            return -1;
-        }
-        if(msg.dent.id == ID_DONE) {
-            return fd;
-        }
-        if(msg.dent.id != ID_DENT) {
-            fprintf(stderr,"received dent msg '%d' is not DENT", 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);
-            return -1;
-        }
-
-        char file_name[257];
-        if(readx(fd, file_name, len)) {
-            fprintf(stderr,"cannot read file in the remote directory '%s'", src_dir);
-            return -1;
-        }
-        file_name[len] = 0;
-
-        if(file_name[0] == '.') {
-            if(file_name[1] == 0) {
-                continue;
-            }
-            if((file_name[1] == '.') && (file_name[2] == 0)) {
-                continue;
-            }
-        }
-
-        char* src_full_path = (char*)malloc(sizeof(char)*PATH_MAX);
-        append_file(src_full_path, src_dir, file_name);
-
-        char* dst_full_path = (char*)malloc(sizeof(char)*PATH_MAX);
-        append_file(dst_full_path, dst_dir, file_name);
-
-        COPY_INFO* info;
-        create_copy_info(&info, src_full_path, dst_full_path);
-        append(dirlist, info);
-    }
-    return fd;
-}
-
-static int sync_readmode(int fd, const char *path, unsigned *mode) {
-    syncmsg msg;
-    int len = strlen(path);
-    msg.req.id = ID_STAT;
-    msg.req.namelen = htoll(len);
-
-    if(writex(fd, &msg.req, sizeof(msg.req)) ||
-       writex(fd, path, len)) {
-        return -1;
-    }
-    if(readx(fd, &msg.stat, sizeof(msg.stat))) {
-        return -1;
-    }
-    if(msg.stat.id != ID_STAT) {
-        return -1;
-    }
-    *mode = ltohl(msg.stat.mode);
-    return 0;
-}
diff --git a/src/file_sync_functions.h b/src/file_sync_functions.h
deleted file mode 100644 (file)
index 34be58e..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-* 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 FILE_SYNC_FUNCTIONS_H_
-#define FILE_SYNC_FUNCTIONS_H_
-
-#include "file_sync_service.h"
-#include "linkedlist.h"
-
-struct copy_info {
-    char* src;
-    char* dst;
-};
-typedef struct copy_info COPY_INFO;
-
-struct _file_buf {
-    unsigned id;
-    unsigned size;
-    char data[SYNC_DATA_MAX];
-};
-typedef struct _file_buf FILE_BUFFER;
-
-int initialize_local(char* path, void** extargv);
-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 is_directory_local(char* path, void* stat, int show_error);
-int is_directory_remote(char* path, void* stat, int show_error);
-
-int readopen_local(int fd, char* srcp, void* srcstat);
-int readopen_remote(int fd, char* srcp, void* srcstat);
-
-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 writeclose_local(int fd, char*dstp, void* stat);
-int writeclose_remote(int fd, char* dstp, void* stat);
-
-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 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);
-
-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(*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(*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(*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;
-
-#endif /* FILE_SYNC_FUNCTIONS_H_ */
diff --git a/src/file_sync_service.c b/src/file_sync_service.c
new file mode 100644 (file)
index 0000000..5871a8c
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <utime.h>
+
+#include <errno.h>
+
+#include "sysdeps.h"
+
+#define TRACE_TAG  TRACE_SYNC
+#include "sdb.h"
+#include "file_sync_service.h"
+
+/* The typical default value for the umask is S_IWGRP | S_IWOTH (octal 022).
+ * Before use the DIR_PERMISSION, the process umask value should be set 0 using umask().
+ */
+#define DIR_PERMISSION 0777
+
+static int mkdirs(char *name)
+{
+    int ret;
+    char *x = name + 1;
+
+    if(name[0] != '/') return -1;
+
+    for(;;) {
+        x = sdb_dirstart(x);
+        if(x == 0) return 0;
+        *x = 0;
+        /* tizen specific */
+        ret = sdb_mkdir(name, DIR_PERMISSION);
+
+        if((ret < 0) && (errno != EEXIST)) {
+            D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
+            *x = '/';
+            return ret;
+        }
+        *x++ = '/';
+    }
+    return 0;
+}
+
+static int do_stat(int s, const char *path)
+{
+    syncmsg msg;
+    struct stat st;
+
+    msg.stat.id = ID_STAT;
+
+    /* follw link */
+    if(stat(path, &st)) {
+        msg.stat.mode = 0;
+        msg.stat.size = 0;
+        msg.stat.time = 0;
+    } else {
+        msg.stat.mode = htoll(st.st_mode);
+        msg.stat.size = htoll(st.st_size);
+        msg.stat.time = htoll(st.st_mtime);
+    }
+
+    return writex(s, &msg.stat, sizeof(msg.stat));
+}
+
+static int do_list(int s, const char *path)
+{
+    DIR *d;
+    struct dirent *de;
+    struct stat st;
+    syncmsg msg;
+    int len;
+
+    char tmp[1024 + 256 + 1];
+    char *fname;
+
+    len = strlen(path);
+    memcpy(tmp, path, len);
+    tmp[len] = '/';
+    fname = tmp + len + 1;
+
+    msg.dent.id = ID_DENT;
+
+    d = opendir(path);
+    if(d == 0) goto done;
+
+    while((de = readdir(d))) {
+        int len = strlen(de->d_name);
+
+            /* not supposed to be possible, but
+               if it does happen, let's not buffer overrun */
+        if(len > 256) continue;
+
+        strcpy(fname, de->d_name);
+        if(lstat(tmp, &st) == 0) {
+            msg.dent.mode = htoll(st.st_mode);
+            msg.dent.size = htoll(st.st_size);
+            msg.dent.time = htoll(st.st_mtime);
+            msg.dent.namelen = htoll(len);
+
+            if(writex(s, &msg.dent, sizeof(msg.dent)) ||
+               writex(s, de->d_name, len)) {
+                return -1;
+            }
+        }
+    }
+
+    closedir(d);
+
+done:
+    msg.dent.id = ID_DONE;
+    msg.dent.mode = 0;
+    msg.dent.size = 0;
+    msg.dent.time = 0;
+    msg.dent.namelen = 0;
+    return writex(s, &msg.dent, sizeof(msg.dent));
+}
+
+static int fail_message(int s, const char *reason)
+{
+    syncmsg msg;
+    int len = strlen(reason);
+
+    D("sync: failure: %s\n", reason);
+
+    msg.data.id = ID_FAIL;
+    msg.data.size = htoll(len);
+    if(writex(s, &msg.data, sizeof(msg.data)) ||
+       writex(s, reason, len)) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+static int fail_errno(int s)
+{
+    return fail_message(s, strerror(errno));
+}
+
+static int handle_send_file(int s, char *path, mode_t mode, char *buffer)
+{
+    syncmsg msg;
+    unsigned int timestamp = 0;
+    int fd;
+
+    fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+    if(fd < 0 && errno == ENOENT) {
+        mkdirs(path);
+        fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+    }
+    if(fd < 0 && errno == EEXIST) {
+        fd = sdb_open_mode(path, O_WRONLY, mode);
+    }
+    if(fd < 0) {
+        if(fail_errno(s))
+            return -1;
+        fd = -1;
+    }
+
+    for(;;) {
+        unsigned int len;
+
+        if(readx(s, &msg.data, sizeof(msg.data)))
+            goto fail;
+
+        if(msg.data.id != ID_DATA) {
+            if(msg.data.id == ID_DONE) {
+                timestamp = ltohl(msg.data.size);
+                break;
+            }
+            fail_message(s, "invalid data message");
+            goto fail;
+        }
+        len = ltohl(msg.data.size);
+        if(len > SYNC_DATA_MAX) {
+            fail_message(s, "oversize data message");
+            goto fail;
+        }
+        if(readx(s, buffer, len))
+            goto fail;
+
+        if(fd < 0)
+            continue;
+        if(writex(fd, buffer, len)) {
+            int saved_errno = errno;
+            sdb_close(fd);
+            sdb_unlink(path);
+            fd = -1;
+            errno = saved_errno;
+            if(fail_errno(s)) return -1;
+        }
+    }
+
+    if(fd >= 0) {
+        struct utimbuf u;
+        sdb_close(fd);
+        u.actime = timestamp;
+        u.modtime = timestamp;
+        utime(path, &u);
+
+        msg.status.id = ID_OKAY;
+        msg.status.msglen = 0;
+        if(writex(s, &msg.status, sizeof(msg.status)))
+            return -1;
+    }
+    return 0;
+
+fail:
+    if(fd >= 0)
+        sdb_close(fd);
+    sdb_unlink(path);
+    return -1;
+}
+
+#ifdef HAVE_SYMLINKS
+static int handle_send_link(int s, char *path, char *buffer)
+{
+    syncmsg msg;
+    unsigned int len;
+    int ret;
+
+    if(readx(s, &msg.data, sizeof(msg.data)))
+        return -1;
+
+    if(msg.data.id != ID_DATA) {
+        fail_message(s, "invalid data message: expected ID_DATA");
+        return -1;
+    }
+
+    len = ltohl(msg.data.size);
+    if(len > SYNC_DATA_MAX) {
+        fail_message(s, "oversize data message");
+        return -1;
+    }
+    if(readx(s, buffer, len))
+        return -1;
+
+    ret = symlink(buffer, path);
+    if(ret && errno == ENOENT) {
+        mkdirs(path);
+        ret = symlink(buffer, path);
+    }
+    if(ret) {
+        fail_errno(s);
+        return -1;
+    }
+
+    if(readx(s, &msg.data, sizeof(msg.data)))
+        return -1;
+
+    if(msg.data.id == ID_DONE) {
+        msg.status.id = ID_OKAY;
+        msg.status.msglen = 0;
+        if(writex(s, &msg.status, sizeof(msg.status)))
+            return -1;
+    } else {
+        fail_message(s, "invalid data message: expected ID_DONE");
+        return -1;
+    }
+
+    return 0;
+}
+#endif /* HAVE_SYMLINKS */
+
+static int do_send(int s, char *path, char *buffer)
+{
+    char *tmp;
+    mode_t mode;
+    int is_link, ret;
+
+    tmp = strrchr(path,',');
+    if(tmp) {
+        *tmp = 0;
+        errno = 0;
+        mode = strtoul(tmp + 1, NULL, 0);
+#ifndef HAVE_SYMLINKS
+        is_link = 0;
+#else
+        is_link = S_ISLNK(mode);
+#endif
+        // extracts file permission from stat.mode. (ex 100644 & 0777 = 644);
+        mode &= 0777; // combination of (S_IRWXU | S_IRWXG | S_IRWXO)
+    }
+    if(!tmp || errno) {
+        mode = 0644; // set default permission value in most of unix system.
+        is_link = 0;
+    }
+
+    // sdb does not allow to check that file exists or not. After deleting old file and creating new file again unconditionally.
+    sdb_unlink(path);
+
+
+#ifdef HAVE_SYMLINKS
+    if(is_link)
+        ret = handle_send_link(s, path, buffer);
+    else {
+#else
+    {
+#endif
+        /* copy user permission bits to "group" and "other" permissions.
+         * ex) 0644 file will be created copied 0666 file.
+         * the following 2 lines should be commented if sdb process has been set to umask 0.
+         */
+
+        //mode |= ((mode >> 3) & 0070);
+        //mode |= ((mode >> 3) & 0007);
+
+        ret = handle_send_file(s, path, mode, buffer);
+    }
+    D("link? %s\n", (is_link==0) ? "no" : "yes");
+    return ret;
+}
+
+static int do_recv(int s, const char *path, char *buffer)
+{
+    syncmsg msg;
+    int fd, r;
+
+    fd = sdb_open(path, O_RDONLY);
+    if(fd < 0) {
+        if(fail_errno(s)) return -1;
+        return 0;
+    }
+
+    msg.data.id = ID_DATA;
+    for(;;) {
+        r = sdb_read(fd, buffer, SYNC_DATA_MAX);
+        if(r <= 0) {
+            if(r == 0) break;
+            if(errno == EINTR) continue;
+            r = fail_errno(s);
+            sdb_close(fd);
+            return r;
+        }
+        msg.data.size = htoll(r);
+        if(writex(s, &msg.data, sizeof(msg.data)) ||
+           writex(s, buffer, r)) {
+            sdb_close(fd);
+            return -1;
+        }
+    }
+
+    sdb_close(fd);
+
+    msg.data.id = ID_DONE;
+    msg.data.size = 0;
+    if(writex(s, &msg.data, sizeof(msg.data))) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void file_sync_service(int fd, void *cookie)
+{
+    syncmsg msg;
+    char name[1025];
+    unsigned namelen;
+
+    char *buffer = malloc(SYNC_DATA_MAX);
+    if(buffer == 0) goto fail;
+
+    for(;;) {
+        D("sync: waiting for command\n");
+
+        if(readx(fd, &msg.req, sizeof(msg.req))) {
+            fail_message(fd, "command read failure");
+            break;
+        }
+        namelen = ltohl(msg.req.namelen);
+        if(namelen > 1024) {
+            fail_message(fd, "invalid namelen");
+            break;
+        }
+        if(readx(fd, name, namelen)) {
+            fail_message(fd, "filename read failure");
+            break;
+        }
+        name[namelen] = 0;
+
+        msg.req.namelen = 0;
+        D("sync: '%s' '%s'\n", (char*) &msg.req, name);
+
+        switch(msg.req.id) {
+        case ID_STAT:
+            if(do_stat(fd, name)) goto fail;
+            break;
+        case ID_LIST:
+            if(do_list(fd, name)) goto fail;
+            break;
+        case ID_SEND:
+            if(do_send(fd, name, buffer)) goto fail;
+            break;
+        case ID_RECV:
+            if(do_recv(fd, name, buffer)) goto fail;
+            break;
+        case ID_QUIT:
+            goto fail;
+        default:
+            fail_message(fd, "unknown command");
+            goto fail;
+        }
+    }
+
+fail:
+    if(buffer != 0) free(buffer);
+    D("sync: done\n");
+    sdb_close(fd);
+}
index 6f019796eab3fdce609da1d96e3761dc890e5e5f..84f06bb4f86bd1d650fb65bd5d01b69319bd44e5 100644 (file)
@@ -78,11 +78,10 @@ typedef union {
 
 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_push(const char *lpath, const char *rpath, int verifyApk, int isUtf8);
 int do_sync_sync(const char *lpath, const char *rpath, int listonly);
 int do_sync_pull(const char *rpath, const char *lpath);
 
 #define SYNC_DATA_MAX (64*1024)
-#define SYNC_CHAR_MAX 1024
 
 #endif
diff --git a/src/framebuffer_service.c b/src/framebuffer_service.c
new file mode 100644 (file)
index 0000000..0aac145
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "fdevent.h"
+#include "sdb.h"
+
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+/* TODO:
+** - sync with vsync to avoid tearing
+*/
+/* This version number defines the format of the fbinfo struct.
+   It must match versioning in ddms where this data is consumed. */
+#define DDMS_RAWIMAGE_VERSION 1
+struct fbinfo {
+    unsigned int version;
+    unsigned int bpp;
+    unsigned int size;
+    unsigned int width;
+    unsigned int height;
+    unsigned int red_offset;
+    unsigned int red_length;
+    unsigned int blue_offset;
+    unsigned int blue_length;
+    unsigned int green_offset;
+    unsigned int green_length;
+    unsigned int alpha_offset;
+    unsigned int alpha_length;
+} __attribute__((packed));
+
+void framebuffer_service(int fd, void *cookie)
+{
+    struct fbinfo fbinfo;
+    unsigned int i;
+    char buf[640];
+    int fd_screencap;
+    int w, h, f;
+    int fds[2];
+    pid_t pid = 0;
+
+    if (pipe(fds) < 0) goto done;
+
+    pid = fork();
+    if (pid < 0) goto done;
+
+    if (pid == 0) {
+        dup2(fds[1], STDOUT_FILENO);
+        close(fds[0]);
+        close(fds[1]);
+        const char* command = "screencap";
+        const char *args[2] = {command, NULL};
+        execvp(command, (char**)args);
+        exit(1);
+    }
+
+    fd_screencap = fds[0];
+
+    /* read w, h & format */
+    if(readx(fd_screencap, &w, 4)) goto done;
+    if(readx(fd_screencap, &h, 4)) goto done;
+    if(readx(fd_screencap, &f, 4)) goto done;
+
+    fbinfo.version = DDMS_RAWIMAGE_VERSION;
+    /* see hardware/hardware.h */
+    switch (f) {
+        case 1: /* RGBA_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 8;
+            break;
+        case 2: /* RGBX_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 0;
+            break;
+        case 3: /* RGB_888 */
+            fbinfo.bpp = 24;
+            fbinfo.size = w * h * 3;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 0;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 16;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 0;
+            break;
+        case 4: /* RGB_565 */
+            fbinfo.bpp = 16;
+            fbinfo.size = w * h * 2;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 11;
+            fbinfo.red_length = 5;
+            fbinfo.green_offset = 5;
+            fbinfo.green_length = 6;
+            fbinfo.blue_offset = 0;
+            fbinfo.blue_length = 5;
+            fbinfo.alpha_offset = 0;
+            fbinfo.alpha_length = 0;
+            break;
+        case 5: /* BGRA_8888 */
+            fbinfo.bpp = 32;
+            fbinfo.size = w * h * 4;
+            fbinfo.width = w;
+            fbinfo.height = h;
+            fbinfo.red_offset = 16;
+            fbinfo.red_length = 8;
+            fbinfo.green_offset = 8;
+            fbinfo.green_length = 8;
+            fbinfo.blue_offset = 0;
+            fbinfo.blue_length = 8;
+            fbinfo.alpha_offset = 24;
+            fbinfo.alpha_length = 8;
+           break;
+        default:
+            goto done;
+    }
+
+    /* write header */
+    if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
+
+    /* write data */
+    for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
+      if(readx(fd_screencap, buf, sizeof(buf))) goto done;
+      if(writex(fd, buf, sizeof(buf))) goto done;
+    }
+    if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
+    if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;
+
+done:
+    TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
+
+    close(fds[0]);
+    close(fds[1]);
+    close(fd);
+}
diff --git a/src/get_my_path_darwin.c b/src/get_my_path_darwin.c
new file mode 100644 (file)
index 0000000..880ccfd
--- /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.
+ */
+
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+void get_my_path(char *s, size_t maxLen)
+{
+    ProcessSerialNumber psn;
+    GetCurrentProcess(&psn);
+    CFDictionaryRef dict;
+    dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
+    CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
+                CFSTR("CFBundleExecutable"));
+    CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8);
+}
+
diff --git a/src/get_my_path_freebsd.c b/src/get_my_path_freebsd.c
new file mode 100644 (file)
index 0000000..628a2b0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+
+void
+get_my_path(char *exe, size_t maxLen)
+{
+    char proc[64];
+
+    snprintf(proc, sizeof(proc), "/proc/%d/file", getpid());
+
+    int err = readlink(proc, exe, maxLen - 1);
+
+    exe[err > 0 ? err : 0] = '\0';
+}
+
diff --git a/src/get_my_path_linux.c b/src/get_my_path_linux.c
new file mode 100644 (file)
index 0000000..08ba668
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+
+void get_my_path(char *exe, size_t maxLen)
+{
+    char proc[64];
+    snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
+    int err = readlink(proc, exe, maxLen - 1);
+    if(err > 0) {
+        exe[err] = '\0';
+    } else {
+        exe[0] = '\0';
+    }
+}
+
diff --git a/src/get_my_path_windows.c b/src/get_my_path_windows.c
new file mode 100644 (file)
index 0000000..630e4d1
--- /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.
+ */
+
+#include <limits.h>
+#include <assert.h>
+#include <windows.h>
+
+void get_my_path(char *exe, size_t maxLen)
+{
+    char  *r;
+
+    /* XXX: should be GetModuleFileNameA */
+    if (GetModuleFileName(NULL, exe, maxLen) > 0) {
+        r = strrchr(exe, '\\');
+        if (r != NULL)
+            *r = '\0';
+    } else {
+        exe[0] = '\0';
+    }
+}
+
diff --git a/src/jdwp_service.c b/src/jdwp_service.c
new file mode 100644 (file)
index 0000000..ab6f11b
--- /dev/null
@@ -0,0 +1,751 @@
+/*
+ * 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.
+ */
+/* implement the "debug-ports" and "track-debug-ports" device services */
+#include "sysdeps.h"
+#define  TRACE_TAG   TRACE_JDWP
+#include "sdb.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* here's how these things work.
+
+   when sdbd starts, it creates a unix server socket
+   named @vm-debug-control (@ is a shortcut for "first byte is zero"
+   to use the private namespace instead of the file system)
+
+   when a new JDWP daemon thread starts in a new VM process, it creates
+   a connection to @vm-debug-control to announce its availability.
+
+
+     JDWP thread                             @vm-debug-control
+         |                                         |
+         |------------------------------->         |
+         | hello I'm in process <pid>              |
+         |                                         |
+         |                                         |
+
+    the connection is kept alive. it will be closed automatically if
+    the JDWP process terminates (this allows sdbd to detect dead
+    processes).
+
+    sdbd thus maintains a list of "active" JDWP processes. it can send
+    its content to clients through the "device:debug-ports" service,
+    or even updates through the "device:track-debug-ports" service.
+
+    when a debugger wants to connect, it simply runs the command
+    equivalent to  "sdb forward tcp:<hostport> jdwp:<pid>"
+
+    "jdwp:<pid>" is a new forward destination format used to target
+    a given JDWP process on the device. when sutch a request arrives,
+    sdbd does the following:
+
+      - first, it calls socketpair() to create a pair of equivalent
+        sockets.
+
+      - it attaches the first socket in the pair to a local socket
+        which is itself attached to the transport's remote socket:
+
+
+      - it sends the file descriptor of the second socket directly
+        to the JDWP process with the help of sendmsg()
+
+
+     JDWP thread                             @vm-debug-control
+         |                                         |
+         |                  <----------------------|
+         |           OK, try this file descriptor  |
+         |                                         |
+         |                                         |
+
+   then, the JDWP thread uses this new socket descriptor as its
+   pass-through connection to the debugger (and receives the
+   JDWP-Handshake message, answers to it, etc...)
+
+   this gives the following graphics:
+                    ____________________________________
+                   |                                    |
+                   |          SDB Server (host)         |
+                   |                                    |
+        Debugger <---> LocalSocket <----> RemoteSocket  |
+                   |                           ^^       |
+                   |___________________________||_______|
+                                               ||
+                                     Transport ||
+           (TCP for emulator - USB for device) ||
+                                               ||
+                    ___________________________||_______
+                   |                           ||       |
+                   |          SDBD  (device)   ||       |
+                   |                           VV       |
+         JDWP <======> LocalSocket <----> RemoteSocket  |
+                   |                                    |
+                   |____________________________________|
+
+    due to the way sdb works, this doesn't need a special socket
+    type or fancy handling of socket termination if either the debugger
+    or the JDWP process closes the connection.
+
+    THIS IS THE SIMPLEST IMPLEMENTATION I COULD FIND, IF YOU HAPPEN
+    TO HAVE A BETTER IDEA, LET ME KNOW - Digit
+
+**********************************************************************/
+
+/** JDWP PID List Support Code
+ ** for each JDWP process, we record its pid and its connected socket
+ **/
+
+#define  MAX_OUT_FDS   4
+
+#if !SDB_HOST
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+typedef struct JdwpProcess  JdwpProcess;
+struct JdwpProcess {
+    JdwpProcess*  next;
+    JdwpProcess*  prev;
+    int           pid;
+    int           socket;
+    fdevent*      fde;
+
+    char          in_buff[4];  /* input character to read PID */
+    int           in_len;      /* number from JDWP process    */
+
+    int           out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
+    int           out_count;            /* to send to the JDWP process      */
+};
+
+static JdwpProcess  _jdwp_list;
+
+static int
+jdwp_process_list( char*  buffer, int  bufferlen )
+{
+    char*         end  = buffer + bufferlen;
+    char*         p    = buffer;
+    JdwpProcess*  proc = _jdwp_list.next;
+
+    for ( ; proc != &_jdwp_list; proc = proc->next ) {
+        int  len;
+
+        /* skip transient connections */
+        if (proc->pid < 0)
+            continue;
+
+        len = snprintf(p, end-p, "%d\n", proc->pid);
+        if (p + len >= end)
+            break;
+        p += len;
+    }
+    p[0] = 0;
+    return (p - buffer);
+}
+
+
+static int
+jdwp_process_list_msg( char*  buffer, int  bufferlen )
+{
+    char  head[5];
+    int   len = jdwp_process_list( buffer+4, bufferlen-4 );
+    snprintf(head, sizeof head, "%04x", len);
+    memcpy(buffer, head, 4);
+    return len + 4;
+}
+
+
+static void  jdwp_process_list_updated(void);
+
+static void
+jdwp_process_free( JdwpProcess*  proc )
+{
+    if (proc) {
+        int  n;
+
+        proc->prev->next = proc->next;
+        proc->next->prev = proc->prev;
+
+        if (proc->socket >= 0) {
+            sdb_shutdown(proc->socket);
+            sdb_close(proc->socket);
+            proc->socket = -1;
+        }
+
+        if (proc->fde != NULL) {
+            fdevent_destroy(proc->fde);
+            proc->fde = NULL;
+        }
+        proc->pid = -1;
+
+        for (n = 0; n < proc->out_count; n++) {
+            sdb_close(proc->out_fds[n]);
+        }
+        proc->out_count = 0;
+
+        free(proc);
+
+        jdwp_process_list_updated();
+    }
+}
+
+
+static void  jdwp_process_event(int, unsigned, void*);  /* forward */
+
+
+static JdwpProcess*
+jdwp_process_alloc( int  socket )
+{
+    JdwpProcess*  proc = calloc(1,sizeof(*proc));
+
+    if (proc == NULL) {
+        D("not enough memory to create new JDWP process\n");
+        return NULL;
+    }
+
+    proc->socket = socket;
+    proc->pid    = -1;
+    proc->next   = proc;
+    proc->prev   = proc;
+
+    proc->fde = fdevent_create( socket, jdwp_process_event, proc );
+    if (proc->fde == NULL) {
+        D("could not create fdevent for new JDWP process\n" );
+        free(proc);
+        return NULL;
+    }
+
+    proc->fde->state |= FDE_DONT_CLOSE;
+    proc->in_len      = 0;
+    proc->out_count   = 0;
+
+    /* append to list */
+    proc->next = &_jdwp_list;
+    proc->prev = proc->next->prev;
+
+    proc->prev->next = proc;
+    proc->next->prev = proc;
+
+    /* start by waiting for the PID */
+    fdevent_add(proc->fde, FDE_READ);
+
+    return proc;
+}
+
+
+static void
+jdwp_process_event( int  socket, unsigned  events, void*  _proc )
+{
+    JdwpProcess*  proc = _proc;
+
+    if (events & FDE_READ) {
+        if (proc->pid < 0) {
+            /* read the PID as a 4-hexchar string */
+            char*  p    = proc->in_buff + proc->in_len;
+            int    size = 4 - proc->in_len;
+            char   temp[5];
+            while (size > 0) {
+                int  len = recv( socket, p, size, 0 );
+                if (len < 0) {
+                    if (errno == EINTR)
+                        continue;
+                    if (errno == EAGAIN)
+                        return;
+                    /* this can fail here if the JDWP process crashes very fast */
+                    D("weird unknown JDWP process failure: %s\n",
+                      strerror(errno));
+
+                    goto CloseProcess;
+                }
+                if (len == 0) {  /* end of stream ? */
+                    D("weird end-of-stream from unknown JDWP process\n");
+                    goto CloseProcess;
+                }
+                p            += len;
+                proc->in_len += len;
+                size         -= len;
+            }
+            /* we have read 4 characters, now decode the pid */
+            memcpy(temp, proc->in_buff, 4);
+            temp[4] = 0;
+
+            if (sscanf( temp, "%04x", &proc->pid ) != 1) {
+                D("could not decode JDWP %p PID number: '%s'\n", proc, temp);
+                goto CloseProcess;
+            }
+
+            /* all is well, keep reading to detect connection closure */
+            D("Adding pid %d to jdwp process list\n", proc->pid);
+            jdwp_process_list_updated();
+        }
+        else
+        {
+            /* the pid was read, if we get there it's probably because the connection
+             * was closed (e.g. the JDWP process exited or crashed) */
+            char  buf[32];
+
+            for (;;) {
+                int  len = recv(socket, buf, sizeof(buf), 0);
+
+                if (len <= 0) {
+                    if (len < 0 && errno == EINTR)
+                        continue;
+                    if (len < 0 && errno == EAGAIN)
+                        return;
+                    else {
+                        D("terminating JDWP %d connection: %s\n", proc->pid,
+                          strerror(errno));
+                        break;
+                    }
+                }
+                else {
+                    D( "ignoring unexpected JDWP %d control socket activity (%d bytes)\n",
+                       proc->pid, len );
+                }
+            }
+
+        CloseProcess:
+            if (proc->pid >= 0)
+                D( "remove pid %d to jdwp process list\n", proc->pid );
+            jdwp_process_free(proc);
+            return;
+        }
+    }
+
+    if (events & FDE_WRITE) {
+        D("trying to write to JDWP pid controli (count=%d first=%d) %d\n",
+          proc->pid, proc->out_count, proc->out_fds[0]);
+        if (proc->out_count > 0) {
+            int  fd = proc->out_fds[0];
+            int  n, ret;
+            struct cmsghdr*  cmsg;
+            struct msghdr    msg;
+            struct iovec     iov;
+            char             dummy = '!';
+            char             buffer[sizeof(struct cmsghdr) + sizeof(int)];
+            int flags;
+
+            iov.iov_base       = &dummy;
+            iov.iov_len        = 1;
+            msg.msg_name       = NULL;
+            msg.msg_namelen    = 0;
+            msg.msg_iov        = &iov;
+            msg.msg_iovlen     = 1;
+            msg.msg_flags      = 0;
+            msg.msg_control    = buffer;
+            msg.msg_controllen = sizeof(buffer);
+
+            cmsg = CMSG_FIRSTHDR(&msg);
+            cmsg->cmsg_len   = msg.msg_controllen;
+            cmsg->cmsg_level = SOL_SOCKET;
+            cmsg->cmsg_type  = SCM_RIGHTS;
+            ((int*)CMSG_DATA(cmsg))[0] = fd;
+
+            flags = fcntl(proc->socket,F_GETFL,0);
+
+            if (flags == -1) {
+                D("failed to get cntl flags for socket %d: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+
+            }
+
+            if (fcntl(proc->socket, F_SETFL, flags & ~O_NONBLOCK) == -1) {
+                D("failed to remove O_NONBLOCK flag for socket %d: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+            }
+
+            for (;;) {
+                ret = sendmsg(proc->socket, &msg, 0);
+                if (ret >= 0) {
+                    sdb_close(fd);
+                    break;
+                }
+                if (errno == EINTR)
+                    continue;
+                D("sending new file descriptor to JDWP %d failed: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+            }
+
+            D("sent file descriptor %d to JDWP process %d\n",
+              fd, proc->pid);
+
+            for (n = 1; n < proc->out_count; n++) {
+                proc->out_fds[n-1] = proc->out_fds[n];
+            }
+
+            if (fcntl(proc->socket, F_SETFL, flags) == -1) {
+                D("failed to set O_NONBLOCK flag for socket %d: %s\n",
+                  proc->pid, strerror(errno));
+                goto CloseProcess;
+            }
+
+            if (--proc->out_count == 0)
+                fdevent_del( proc->fde, FDE_WRITE );
+        }
+    }
+}
+
+
+int
+create_jdwp_connection_fd(int  pid)
+{
+    JdwpProcess*  proc = _jdwp_list.next;
+
+    D("looking for pid %d in JDWP process list\n", pid);
+    for ( ; proc != &_jdwp_list; proc = proc->next ) {
+        if (proc->pid == pid) {
+            goto FoundIt;
+        }
+    }
+    D("search failed !!\n");
+    return -1;
+
+FoundIt:
+    {
+        int  fds[2];
+
+        if (proc->out_count >= MAX_OUT_FDS) {
+            D("%s: too many pending JDWP connection for pid %d\n",
+              __FUNCTION__, pid);
+            return -1;
+        }
+
+        if (sdb_socketpair(fds) < 0) {
+            D("%s: socket pair creation failed: %s\n",
+              __FUNCTION__, strerror(errno));
+            return -1;
+        }
+
+        proc->out_fds[ proc->out_count ] = fds[1];
+        if (++proc->out_count == 1)
+            fdevent_add( proc->fde, FDE_WRITE );
+
+        return fds[0];
+    }
+}
+
+/**  VM DEBUG CONTROL SOCKET
+ **
+ **  we do implement a custom asocket to receive the data
+ **/
+
+/* name of the debug control Unix socket */
+#define  JDWP_CONTROL_NAME      "\0jdwp-control"
+#define  JDWP_CONTROL_NAME_LEN  (sizeof(JDWP_CONTROL_NAME)-1)
+
+typedef struct {
+    int       listen_socket;
+    fdevent*  fde;
+
+} JdwpControl;
+
+
+static void
+jdwp_control_event(int  s, unsigned events, void*  user);
+
+
+static int
+jdwp_control_init( JdwpControl*  control,
+                   const char*   sockname,
+                   int           socknamelen )
+{
+    struct sockaddr_un   addr;
+    socklen_t            addrlen;
+    int                  s;
+    int                  maxpath = sizeof(addr.sun_path);
+    int                  pathlen = socknamelen;
+
+    if (pathlen >= maxpath) {
+        D( "vm debug control socket name too long (%d extra chars)\n",
+           pathlen+1-maxpath );
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    memcpy(addr.sun_path, sockname, socknamelen);
+
+    s = socket( AF_UNIX, SOCK_STREAM, 0 );
+    if (s < 0) {
+        D( "could not create vm debug control socket. %d: %s\n",
+           errno, strerror(errno));
+        return -1;
+    }
+
+    addrlen = (pathlen + sizeof(addr.sun_family));
+
+    if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
+        D( "could not bind vm debug control socket: %d: %s\n",
+           errno, strerror(errno) );
+        sdb_close(s);
+        return -1;
+    }
+
+    if ( listen(s, 4) < 0 ) {
+        D("listen failed in jdwp control socket: %d: %s\n",
+          errno, strerror(errno));
+        sdb_close(s);
+        return -1;
+    }
+
+    control->listen_socket = s;
+
+    control->fde = fdevent_create(s, jdwp_control_event, control);
+    if (control->fde == NULL) {
+        D( "could not create fdevent for jdwp control socket\n" );
+        sdb_close(s);
+        return -1;
+    }
+
+    /* only wait for incoming connections */
+    fdevent_add(control->fde, FDE_READ);
+    close_on_exec(s);
+
+    D("jdwp control socket started (%d)\n", control->listen_socket);
+    return 0;
+}
+
+
+static void
+jdwp_control_event( int  s, unsigned  events, void*  _control )
+{
+    JdwpControl*  control = (JdwpControl*) _control;
+
+    if (events & FDE_READ) {
+        struct sockaddr   addr;
+        socklen_t         addrlen = sizeof(addr);
+        int               s = -1;
+        JdwpProcess*      proc;
+
+        do {
+            s = sdb_socket_accept( control->listen_socket, &addr, &addrlen );
+            if (s < 0) {
+                if (errno == EINTR)
+                    continue;
+                if (errno == ECONNABORTED) {
+                    /* oops, the JDWP process died really quick */
+                    D("oops, the JDWP process died really quick\n");
+                    return;
+                }
+                /* the socket is probably closed ? */
+                D( "weird accept() failed on jdwp control socket: %s\n",
+                   strerror(errno) );
+                return;
+            }
+        }
+        while (s < 0);
+
+        proc = jdwp_process_alloc( s );
+        if (proc == NULL) {
+            return;
+        }
+    }
+}
+
+
+static JdwpControl   _jdwp_control;
+
+/** "jdwp" local service implementation
+ ** this simply returns the list of known JDWP process pids
+ **/
+
+typedef struct {
+    asocket  socket;
+    int      pass;
+} JdwpSocket;
+
+static void
+jdwp_socket_close( asocket*  s )
+{
+    asocket*  peer = s->peer;
+
+    remove_socket(s);
+
+    if (peer) {
+        peer->peer = NULL;
+        peer->close(peer);
+    }
+    free(s);
+}
+
+static int
+jdwp_socket_enqueue( asocket*  s, apacket*  p )
+{
+    /* you can't write to this asocket */
+    put_apacket(p);
+    s->peer->close(s->peer);
+    return -1;
+}
+
+
+static void
+jdwp_socket_ready( asocket*  s )
+{
+    JdwpSocket*  jdwp = (JdwpSocket*)s;
+    asocket*     peer = jdwp->socket.peer;
+
+   /* on the first call, send the list of pids,
+    * on the second one, close the connection
+    */
+    if (jdwp->pass == 0) {
+        apacket*  p = get_apacket();
+        p->len = jdwp_process_list((char*)p->data, MAX_PAYLOAD);
+        peer->enqueue(peer, p);
+        jdwp->pass = 1;
+    }
+    else {
+        peer->close(peer);
+    }
+}
+
+asocket*
+create_jdwp_service_socket( void )
+{
+    JdwpSocket*  s = calloc(sizeof(*s),1);
+
+    if (s == NULL)
+        return NULL;
+
+    install_local_socket(&s->socket);
+
+    s->socket.ready   = jdwp_socket_ready;
+    s->socket.enqueue = jdwp_socket_enqueue;
+    s->socket.close   = jdwp_socket_close;
+    s->pass           = 0;
+
+    return &s->socket;
+}
+
+/** "track-jdwp" local service implementation
+ ** this periodically sends the list of known JDWP process pids
+ ** to the client...
+ **/
+
+typedef struct JdwpTracker  JdwpTracker;
+
+struct JdwpTracker {
+    asocket       socket;
+    JdwpTracker*  next;
+    JdwpTracker*  prev;
+    int           need_update;
+};
+
+static JdwpTracker   _jdwp_trackers_list;
+
+
+static void
+jdwp_process_list_updated(void)
+{
+    char             buffer[1024];
+    int              len;
+    JdwpTracker*  t = _jdwp_trackers_list.next;
+
+    len = jdwp_process_list_msg(buffer, sizeof(buffer));
+
+    for ( ; t != &_jdwp_trackers_list; t = t->next ) {
+        apacket*  p    = get_apacket();
+        asocket*  peer = t->socket.peer;
+        memcpy(p->data, buffer, len);
+        p->len = len;
+        peer->enqueue( peer, p );
+    }
+}
+
+static void
+jdwp_tracker_close( asocket*  s )
+{
+    JdwpTracker*  tracker = (JdwpTracker*) s;
+    asocket*      peer    = s->peer;
+
+    if (peer) {
+        peer->peer = NULL;
+        peer->close(peer);
+    }
+
+    remove_socket(s);
+
+    tracker->prev->next = tracker->next;
+    tracker->next->prev = tracker->prev;
+
+    free(s);
+}
+
+static void
+jdwp_tracker_ready( asocket*  s )
+{
+    JdwpTracker*  t = (JdwpTracker*) s;
+
+    if (t->need_update) {
+        apacket*  p = get_apacket();
+        t->need_update = 0;
+        p->len = jdwp_process_list_msg((char*)p->data, sizeof(p->data));
+        s->peer->enqueue(s->peer, p);
+    }
+}
+
+static int
+jdwp_tracker_enqueue( asocket*  s, apacket*  p )
+{
+    /* you can't write to this socket */
+    put_apacket(p);
+    s->peer->close(s->peer);
+    return -1;
+}
+
+
+asocket*
+create_jdwp_tracker_service_socket( void )
+{
+    JdwpTracker*  t = calloc(sizeof(*t),1);
+
+    if (t == NULL)
+        return NULL;
+
+    t->next = &_jdwp_trackers_list;
+    t->prev = t->next->prev;
+
+    t->next->prev = t;
+    t->prev->next = t;
+
+    install_local_socket(&t->socket);
+
+    t->socket.ready   = jdwp_tracker_ready;
+    t->socket.enqueue = jdwp_tracker_enqueue;
+    t->socket.close   = jdwp_tracker_close;
+    t->need_update    = 1;
+
+    return &t->socket;
+}
+
+
+int
+init_jdwp(void)
+{
+    _jdwp_list.next = &_jdwp_list;
+    _jdwp_list.prev = &_jdwp_list;
+
+    _jdwp_trackers_list.next = &_jdwp_trackers_list;
+    _jdwp_trackers_list.prev = &_jdwp_trackers_list;
+
+    return jdwp_control_init( &_jdwp_control,
+                              JDWP_CONTROL_NAME,
+                              JDWP_CONTROL_NAME_LEN );
+}
+
+#endif /* !SDB_HOST */
diff --git a/src/libusb/darwin.c b/src/libusb/darwin.c
deleted file mode 100644 (file)
index c330eb0..0000000
+++ /dev/null
@@ -1,1329 +0,0 @@
-/*
- * 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/src/libusb/descriptors.c b/src/libusb/descriptors.c
deleted file mode 100644 (file)
index f7fc784..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * 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/src/libusb/error.c b/src/libusb/error.c
deleted file mode 100644 (file)
index 9212e86..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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/src/libusb/error.h b/src/libusb/error.h
deleted file mode 100644 (file)
index c980e22..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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/src/libusb/linux.c b/src/libusb/linux.c
deleted file mode 100644 (file)
index 6b13afb..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * 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/src/libusb/linux.h b/src/libusb/linux.h
deleted file mode 100644 (file)
index e544c09..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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/src/libusb/usb.c b/src/libusb/usb.c
deleted file mode 100644 (file)
index ea4b375..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * 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/src/libusb/usb.h b/src/libusb/usb.h
deleted file mode 100644 (file)
index 35955b7..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * 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/src/libusb/usbi.h b/src/libusb/usbi.h
deleted file mode 100644 (file)
index d71b5c4..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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/src/libusb/windows.c b/src/libusb/windows.c
deleted file mode 100644 (file)
index 9c79b24..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * 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"
-
-#define   TRACE_TAG  TRACE_USB
-#include "sdb.h"
-#include "sdb_usb.h"
-
-struct usb_handle {
-    usb_handle *prev;
-    usb_handle *next;
-
-    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 usb_handle handle_list = {
-  .prev = &handle_list,
-  .next = &handle_list,
-};
-
-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)
-{
-    usb_handle *usb;
-    int r = 0;
-    sdb_mutex_lock(&usb_lock);
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if(!strcmp(usb->unique_node_path, node_path)) {
-            r = 1;
-            break;
-        }
-    }
-    sdb_mutex_unlock(&usb_lock);
-    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) {
-        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;
-    }
-
-    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) {
-        return NULL;
-    }
-
-    if (!is_sdb_interface(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);
-
-    hnd->next = &handle_list;
-    hnd->prev = handle_list.prev;
-    hnd->prev->next = hnd;
-    hnd->next->prev = hnd;
-
-    sdb_mutex_unlock(&usb_lock);
-
-    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);
-}
-
-int is_sdb_interface(int usb_class, int usb_subclass, int usb_protocol)
-{
-    if (usb_class == SDB_INTERFACE_CLASS && usb_subclass == SDB_INTERFACE_SUBCLASS
-            && usb_protocol == SDB_INTERFACE_PROTOCOL) {
-        return 1;
-    }
-
-    return 0;
-}
-
-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) {
-                if (register_device(hnd)) {
-                    char serial[256];
-                    if (get_serial_number(hnd, serial, sizeof(serial)) > 0) {
-                        D("register usb for: %s\n", serial);
-                        register_usb_transport(hnd, serial, 1);
-                    } else {
-                        D("fail to get usb serial name%s\n");
-                        win_usb_close(hnd);
-                    }
-                } else {
-                    D("fail to register_new_device for %s\n", devicePath);
-                    win_usb_close(hnd);
-                }
-            } else {
-                win_usb_close(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*)1000)) {
-        fatal_errno("cannot create input thread");
-    }
-}
-
-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;
-}
-
-void usb_cleanup_handle(usb_handle* handle) {
-    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;
-    }
-}
-
-int win_usb_close(usb_handle *handle) {
-    D("+usb win_usb_close\n");
-    if (NULL != handle) {
-        usb_cleanup_handle(handle);
-        free(handle);
-        handle = NULL;
-    }
-    D("-usb win_usb_close\n");
-    return 0;
-}
-
-void sdb_usb_kick(usb_handle* handle) {
-    D("+sdb_usb_kick: %p\n", handle);
-    if (NULL != handle) {
-        sdb_mutex_lock(&usb_lock);
-
-        usb_cleanup_handle(handle);
-
-        sdb_mutex_unlock(&usb_lock);
-      } else {
-        SetLastError(ERROR_INVALID_HANDLE);
-        errno = ERROR_INVALID_HANDLE;
-      }
-    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);
-        handle->next->prev = handle->prev;
-        handle->prev->next = handle->next;
-        handle->prev = 0;
-        handle->next = 0;
-        sdb_mutex_unlock(&usb_lock);
-        win_usb_close(handle);
-    }
-    D("-sdb_usb_close: %p\n", handle);
-    return 0;
-}
-
-void do_lsusb() {
-    usb_find_devices(TIZEN_CLASSID);
-}
diff --git a/src/libusb/winusb.h b/src/libusb/winusb.h
deleted file mode 100755 (executable)
index 8e5cf8a..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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
diff --git a/src/linkedlist.c b/src/linkedlist.c
deleted file mode 100644 (file)
index 93aa7bb..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-* 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 <stdio.h>
-#include <stdlib.h>
-#include "linkedlist.h"
-#include "file_sync_functions.h"
-
-static void default_free(void* data);
-
-void append(LIST_NODE** listptr, void* value) {
-
-    LIST_NODE* prev_ptr = NULL;
-    LIST_NODE* current_ptr = *listptr;
-
-    LIST_NODE* new_ptr = (LIST_NODE*)malloc(sizeof(LIST_NODE));
-    new_ptr->data = value;
-    new_ptr->next_ptr = NULL;
-
-    while(current_ptr != NULL) {
-        prev_ptr = current_ptr;
-        current_ptr = prev_ptr->next_ptr;
-    }
-
-    //listptr is empty.
-    if(prev_ptr == NULL) {
-        *listptr = new_ptr;
-    }
-    else {
-        prev_ptr->next_ptr = new_ptr;
-    }
-}
-
-void no_free() {
-    //do nothing.
-}
-
-void free_list(LIST_NODE* listptr, void(free_func)(void*)) {
-
-    if(free_func == NULL) {
-        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;
-    }
-}
-
-static void default_free(void* data) {
-    if(data != NULL) {
-        free(data);
-    }
-}
-
-void remove_first(LIST_NODE** listptr, void(free_func)(void*)) {
-
-    if(free_func == NULL) {
-        free_func = default_free;
-    }
-
-    if(*listptr != NULL) {
-        LIST_NODE* curptr = (*listptr)->next_ptr;
-        LIST_NODE* removeptr = *listptr;
-        *listptr = curptr;
-        free_func(removeptr->data);
-        free(removeptr);
-    }
-}
diff --git a/src/linkedlist.h b/src/linkedlist.h
deleted file mode 100644 (file)
index b88a5de..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-* 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 LINKEDLIST_H_
-#define LINKEDLIST_H_
-
-struct list_node {
-    void* data;
-    struct list_node* next_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*));
-
-#endif /* LINKEDLIST_H_ */
diff --git a/src/mutex_list.h b/src/mutex_list.h
new file mode 100644 (file)
index 0000000..3e55e9f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+/* the list of mutexes used by sdb */
+/* #ifndef __MUTEX_LIST_H
+ * Do not use an include-guard. This file is included once to declare the locks
+ * and once in win32 to actually do the runtime initialization.
+ */
+#ifndef SDB_MUTEX
+#error SDB_MUTEX not defined when including this file
+#endif
+SDB_MUTEX(dns_lock)
+SDB_MUTEX(socket_list_lock)
+SDB_MUTEX(transport_lock)
+#if SDB_HOST
+SDB_MUTEX(local_transports_lock)
+#endif
+SDB_MUTEX(usb_lock)
+
+// Sadly logging to /data/sdb/sdb-... is not thread safe.
+//  After modifying sdb.h::D() to count invocations:
+//   DEBUG(jpa):0:Handling main()
+//   DEBUG(jpa):1:[ usb_init - starting thread ]
+// (Oopsies, no :2:, and matching message is also gone.)
+//   DEBUG(jpa):3:[ usb_thread - opening device ]
+//   DEBUG(jpa):4:jdwp control socket started (10)
+SDB_MUTEX(D_lock)
+
+#undef SDB_MUTEX
diff --git a/src/properties.c b/src/properties.c
new file mode 100644 (file)
index 0000000..2c36dde
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "sockets.h"
+#include <errno.h>
+#include <assert.h>
+
+#include "properties.h"
+//#include "loghack.h"
+#include "sysdeps.h"
+#define  TRACE_TAG   TRACE_PROPERTIES
+#include "sdb.h"
+#include "strutils.h"
+
+#define HAVE_TIZEN_PROPERTY
+
+#ifdef HAVE_TIZEN_PROPERTY
+
+#define HAVE_PTHREADS
+#include <stdio.h>
+#include "threads.h"
+
+static mutex_t  env_lock = MUTEX_INITIALIZER;
+
+#define TIZEN_PROPERTY_FILE       "/tmp/.sdb.conf" /* tizen specific*/
+#define PROPERTY_SEPARATOR "="
+
+struct config_node {
+    char *key;
+    char value[PROPERTY_VALUE_MAX];
+} sdbd_config[] = {
+    { "service.sdb.tcp.port", "0" },
+    { NULL, "" }
+};
+
+void property_save();
+int read_line(const int fd, char* ptr, const unsigned int maxlen);
+
+static void property_init(void)
+{
+    int fd;
+    int i = 0;
+    char buffer[PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX+1];
+    char *tok = NULL;
+
+    fd = unix_open(TIZEN_PROPERTY_FILE, O_RDONLY);
+    if (fd < 0)
+        return;
+    for(;;) {
+        if(read_line(fd, buffer, PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX+1) < 0)
+            break;
+        tok = strtok(buffer, PROPERTY_SEPARATOR);
+        for (i = 0; sdbd_config[i].key; i++) {
+            if (!strcmp(tok, sdbd_config[i].key)) {
+                tok = strtok(NULL, PROPERTY_SEPARATOR);
+                strncpy(sdbd_config[i].value, tok, PROPERTY_VALUE_MAX);
+                D("property init key=%s, value=%s\n", sdbd_config[i].key, tok);
+            }
+        }
+
+    }
+    sdb_close(fd);
+    D("called property_init\n");
+}
+
+void property_save()
+{
+    int fd;
+    int i = 0;
+    char buffer[PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX+1];
+
+    mutex_lock(&env_lock);
+    if (access(TIZEN_PROPERTY_FILE, F_OK) == 0) // if exist
+        sdb_unlink(TIZEN_PROPERTY_FILE);
+
+    fd = unix_open(TIZEN_PROPERTY_FILE, O_WRONLY | O_CREAT | O_APPEND, 0640);
+    if (fd <0 )
+        return;
+
+    for (i = 0; sdbd_config[i].key; i++) {
+        sprintf(buffer,"%s%s%s\n", sdbd_config[i].key, PROPERTY_SEPARATOR, sdbd_config[i].value);
+        sdb_write(fd, buffer, strlen(buffer));
+    }
+    sdb_close(fd);
+    mutex_unlock(&env_lock);
+}
+
+int property_set(const char *key, const char *value)
+{
+    int i = 0;
+
+    mutex_lock(&env_lock);
+    for (i = 0; sdbd_config[i].key; i++) {
+        if (!strcmp(key,sdbd_config[i].key)) {
+            strncpy(sdbd_config[i].value, value, PROPERTY_VALUE_MAX);
+            D("property set key=%s, value=%s\n", key, value);
+            break;
+        }
+    }
+    mutex_unlock(&env_lock);
+    property_save();
+    return -1;
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    int len = 0;
+    int i = 0;
+
+    property_init();
+    mutex_lock(&env_lock);
+    for (i = 0; sdbd_config[i].key; i++) {
+        if (!strcmp(key,sdbd_config[i].key)) {
+            len = strlen(sdbd_config[i].value);
+            memcpy(value, sdbd_config[i].value, len + 1);
+            D("property get key=%s, value=%s\n", key, value);
+            mutex_unlock(&env_lock);
+            return len;
+        }
+    }
+
+    if(default_value) {
+        len = strlen(default_value);
+        memcpy(value, default_value, len + 1);
+        D("by default, property get key=%s, value=%s\n", key, value);
+    }
+    mutex_unlock(&env_lock);
+    return len;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    return 0;
+}
+
+#elif defined(HAVE_LIBC_SYSTEM_PROPERTIES)
+
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+//#include <sys/_system_properties.h>
+
+int property_set(const char *key, const char *value)
+{
+    return __system_property_set(key, value);
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    int len;
+
+    len = __system_property_get(key, value);
+    if(len > 0) {
+        return len;
+    }
+
+    if(default_value) {
+        len = strlen(default_value);
+        memcpy(value, default_value, len + 1);
+    }
+    return len;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    char name[PROP_NAME_MAX];
+    char value[PROP_VALUE_MAX];
+    const prop_info *pi;
+    unsigned n;
+
+    for(n = 0; (pi = __system_property_find_nth(n)); n++) {
+        __system_property_read(pi, name, value);
+        propfn(name, value, cookie);
+    }
+    return 0;
+}
+
+#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
+
+/*
+ * The Linux simulator provides a "system property server" that uses IPC
+ * to set/get/list properties.  The file descriptor is shared by all
+ * threads in the process, so we use a mutex to ensure that requests
+ * from multiple threads don't get interleaved.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
+
+static pthread_once_t gInitOnce = PTHREAD_ONCE_INIT;
+static pthread_mutex_t gPropertyFdLock = PTHREAD_MUTEX_INITIALIZER;
+static int gPropFd = -1;
+
+/*
+ * Connect to the properties server.
+ *
+ * Returns the socket descriptor on success.
+ */
+static int connectToServer(const char* fileName)
+{
+    int sock = -1;
+    int cc;
+
+    struct sockaddr_un addr;
+
+    sock = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (sock < 0) {
+        D("UNIX domain socket create failed (errno=%d)\n", errno);
+        return -1;
+    }
+
+    /* connect to socket; fails if file doesn't exist */
+    strcpy(addr.sun_path, fileName);    // max 108 bytes
+    addr.sun_family = AF_UNIX;
+    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
+    if (cc < 0) {
+        // ENOENT means socket file doesn't exist
+        // ECONNREFUSED means socket exists but nobody is listening
+        D("AF_UNIX connect failed for '%s': %s\n",
+            fileName, strerror(errno));
+        sdb_close(sock);
+        return -1;
+    }
+
+    return sock;
+}
+
+/*
+ * Perform one-time initialization.
+ */
+static void init(void)
+{
+    assert(gPropFd == -1);
+
+    gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);
+    if (gPropFd < 0) {
+        D("not connected to system property server\n");
+    } else {
+        D("Connected to system property server\n");
+    }
+}
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    char sendBuf[1+PROPERTY_KEY_MAX];
+    char recvBuf[1+PROPERTY_VALUE_MAX];
+    int len = -1;
+
+    D("PROPERTY GET [%s]\n", key);
+
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0) {
+        /* this mimics the behavior of the device implementation */
+        if (default_value != NULL) {
+            strcpy(value, default_value);
+            len = strlen(value);
+        }
+        return len;
+    }
+
+    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
+
+    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
+
+    sendBuf[0] = (char) kSystemPropertyGet;
+    strcpy(sendBuf+1, key);
+
+    pthread_mutex_lock(&gPropertyFdLock);
+    if (sdb_write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    if (sdb_read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    pthread_mutex_unlock(&gPropertyFdLock);
+
+    /* first byte is 0 if value not defined, 1 if found */
+    if (recvBuf[0] == 0) {
+        if (default_value != NULL) {
+            strcpy(value, default_value);
+            len = strlen(value);
+        } else {
+            /*
+             * If the value isn't defined, hand back an empty string and
+             * a zero length, rather than a failure.  This seems wrong,
+             * since you can't tell the difference between "undefined" and
+             * "defined but empty", but it's what the device does.
+             */
+            value[0] = '\0';
+            len = 0;
+        }
+    } else if (recvBuf[0] == 1) {
+        strcpy(value, recvBuf+1);
+        len = strlen(value);
+    } else {
+        D("Got strange response to property_get request (%d)\n",
+            recvBuf[0]);
+        assert(0);
+        return -1;
+    }
+    D("PROP [found=%d def='%s'] (%d) [%s]: [%s]\n",
+        recvBuf[0], default_value, len, key, value);
+
+    return len;
+}
+
+
+int property_set(const char *key, const char *value)
+{
+    char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
+    char recvBuf[1];
+    int result = -1;
+
+    D("PROPERTY SET [%s]: [%s]\n", key, value);
+
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0)
+        return -1;
+
+    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
+    if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;
+
+    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind
+
+    sendBuf[0] = (char) kSystemPropertySet;
+    strcpy(sendBuf+1, key);
+    strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);
+
+    pthread_mutex_lock(&gPropertyFdLock);
+    if (sdb_write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    if (sdb_read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
+        pthread_mutex_unlock(&gPropertyFdLock);
+        return -1;
+    }
+    pthread_mutex_unlock(&gPropertyFdLock);
+
+    if (recvBuf[0] != 1)
+        return -1;
+    return 0;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    D("PROPERTY LIST\n");
+    pthread_once(&gInitOnce, init);
+    if (gPropFd < 0)
+        return -1;
+
+    return 0;
+}
+
+#else
+
+/* SUPER-cheesy place-holder implementation for Win32 */
+#define HAVE_PTHREADS /*tizen specific */
+#include <stdio.h>
+#include "threads.h"
+
+static mutex_t  env_lock = MUTEX_INITIALIZER;
+
+int property_get(const char *key, char *value, const char *default_value)
+{
+    char ename[PROPERTY_KEY_MAX + 6];
+    char *p;
+    int len;
+
+    len = strlen(key);
+    if(len >= PROPERTY_KEY_MAX) return -1;
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+
+    mutex_lock(&env_lock);
+
+    p = getenv(ename);
+    if(p == 0) p = "";
+    len = strlen(p);
+    if(len >= PROPERTY_VALUE_MAX) {
+        len = PROPERTY_VALUE_MAX - 1;
+    }
+
+    if((len == 0) && default_value) {
+        len = strlen(default_value);
+        memcpy(value, default_value, len + 1);
+    } else {
+        memcpy(value, p, len);
+        value[len] = 0;
+    }
+
+    mutex_unlock(&env_lock);
+    D("get [key=%s value='%s:%s']\n", key, ename, value);
+    return len;
+}
+
+
+int property_set(const char *key, const char *value)
+{
+    char ename[PROPERTY_KEY_MAX + 6];
+    char *p;
+    int len;
+    int r;
+
+    if(strlen(value) >= PROPERTY_VALUE_MAX) return -1;
+
+    len = strlen(key);
+    if(len >= PROPERTY_KEY_MAX) return -1;
+    memcpy(ename, "PROP_", 5);
+    memcpy(ename + 5, key, len + 1);
+
+    mutex_lock(&env_lock);
+#ifdef HAVE_MS_C_RUNTIME
+    {
+        char  temp[256];
+        snprintf( temp, sizeof(temp), "%s=%s", ename, value);
+        putenv(temp);
+        r = 0;
+    }
+#else
+    r = setenv(ename, value, 1);
+#endif
+    mutex_unlock(&env_lock);
+    D("set [key=%s value='%s%s']\n", key, ename, value);
+    return r;
+}
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
+                  void *cookie)
+{
+    return 0;
+}
+
+#endif
diff --git a/src/properties.h b/src/properties.h
new file mode 100644 (file)
index 0000000..08f9d18
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 __CUTILS_PROPERTIES_H
+#define __CUTILS_PROPERTIES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* System properties are *small* name value pairs managed by the
+** property service.  If your data doesn't fit in the provided
+** space it is not appropriate for a system property.
+**
+** WARNING: system/bionic/include/sys/system_properties.h also defines
+**          these, but with different names.  (TODO: fix that)
+*/
+#define PROPERTY_KEY_MAX   32
+#define PROPERTY_VALUE_MAX  92
+
+/* property_get: returns the length of the value which will never be
+** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated.
+** (the length does not include the terminating zero).
+**
+** If the property read fails or returns an empty value, the default
+** value is used (if nonnull).
+*/
+int property_get(const char *key, char *value, const char *default_value);
+
+/* property_set: returns 0 on success, < 0 on failure
+*/
+int property_set(const char *key, const char *value);
+
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
+
+#ifdef HAVE_SYSTEM_PROPERTY_SERVER
+/*
+ * We have an external property server instead of built-in libc support.
+ * Used by the simulator.
+ */
+#define SYSTEM_PROPERTY_PIPE_NAME       "/tmp/sdb-sysporp"
+
+enum {
+    kSystemPropertyUnknown = 0,
+    kSystemPropertyGet,
+    kSystemPropertySet,
+    kSystemPropertyList
+};
+#endif /*HAVE_SYSTEM_PROPERTY_SERVER*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/protocol.txt b/src/protocol.txt
new file mode 100644 (file)
index 0000000..e1e84d0
--- /dev/null
@@ -0,0 +1,252 @@
+
+--- a replacement for aproto -------------------------------------------
+
+When it comes down to it, aproto's primary purpose is to forward
+various streams between the host computer and client device (in either
+direction).
+
+This replacement further simplifies the concept, reducing the protocol
+to an extremely straightforward model optimized to accomplish the
+forwarding of these streams and removing additional state or
+complexity.
+
+The host side becomes a simple comms bridge with no "UI", which will 
+be used by either commandline or interactive tools to communicate with 
+a device or emulator that is connected to the bridge.
+
+The protocol is designed to be straightforward and well-defined enough 
+that if it needs to be reimplemented in another environment (Java 
+perhaps), there should not problems ensuring perfect interoperability.
+
+The protocol discards the layering aproto has and should allow the 
+implementation to be much more robust.
+
+
+--- protocol overview and basics ---------------------------------------
+
+The transport layer deals in "messages", which consist of a 24 byte
+header followed (optionally) by a payload.  The header consists of 6
+32 bit words which are sent across the wire in little endian format.
+
+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_crc32;    /* crc32 of data payload            */
+    unsigned magic;         /* command ^ 0xffffffff             */
+};
+
+Receipt of an invalid message header, corrupt message payload, or an
+unrecognized command MUST result in the closing of the remote
+connection.  The protocol depends on shared state and any break in the
+message stream will result in state getting out of sync.
+
+The following sections describe the six defined message types in
+detail.  Their format is COMMAND(arg0, arg1, payload) where the payload
+is represented by a quoted string or an empty string if none should be
+sent.
+
+The identifiers "local-id" and "remote-id" are always relative to the
+*sender* of the message, so for a receiver, the meanings are effectively
+reversed.
+
+
+
+--- CONNECT(version, maxdata, "system-identity-string") ----------------
+
+The CONNECT message establishes the presence of a remote system.
+The version is used to ensure protocol compatibility and maxdata
+declares the maximum message body size that the remote system
+is willing to accept.
+
+Currently, version=0x01000000 and maxdata=4096
+
+Both sides send a CONNECT message when the connection between them is
+established.  Until a CONNECT message is received no other messages may
+be sent.  Any messages received before a CONNECT message MUST be ignored.
+
+If a CONNECT message is received with an unknown version or insufficiently
+large maxdata value, the connection with the other side must be closed.
+
+The system identity string should be "<systemtype>:<serialno>:<banner>"
+where systemtype is "bootloader", "device", or "host", serialno is some
+kind of unique ID (or empty), and banner is a human-readable version
+or identifier string (informational only).
+
+
+--- OPEN(local-id, 0, "destination") -----------------------------------
+
+The OPEN message informs the recipient that the sender has a stream
+identified by local-id that it wishes to connect to the named
+destination in the message payload.  The local-id may not be zero.
+
+The OPEN message MUST result in either a READY message indicating that
+the connection has been established (and identifying the other end) or
+a CLOSE message, indicating failure.  An OPEN message also implies
+a READY message sent at the same time.
+
+Common destination naming conventions include:
+
+* "tcp:<host>:<port>" - host may be omitted to indicate localhost
+* "udp:<host>:<port>" - host may be omitted to indicate localhost
+* "local-dgram:<identifier>"
+* "local-stream:<identifier>"
+* "shell" - local shell service
+* "upload" - service for pushing files across (like aproto's /sync)
+* "fs-bridge" - FUSE protocol filesystem bridge
+
+
+--- READY(local-id, remote-id, "") -------------------------------------
+
+The READY message informs the recipient that the sender's stream
+identified by local-id is ready for write messages and that it is
+connected to the recipient's stream identified by remote-id.
+
+Neither the local-id nor the remote-id may be zero. 
+
+A READY message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have been
+closed while this message was in-flight.
+
+The local-id is ignored on all but the first READY message (where it
+is used to establish the connection).  Nonetheless, the local-id MUST
+not change on later READY messages sent to the same stream.
+
+
+
+--- WRITE(0, remote-id, "data") ----------------------------------------
+
+The WRITE message sends data to the recipient's stream identified by
+remote-id.  The payload MUST be <= maxdata in length.
+
+A WRITE message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have been
+closed while this message was in-flight.
+
+A WRITE message may not be sent until a READY message is received.
+Once a WRITE message is sent, an additional WRITE message may not be
+sent until another READY message has been received.  Recipients of
+a WRITE message that is in violation of this requirement will CLOSE
+the connection.
+
+
+--- CLOSE(local-id, remote-id, "") -------------------------------------
+
+The CLOSE message informs recipient that the connection between the
+sender's stream (local-id) and the recipient's stream (remote-id) is
+broken.  The remote-id MUST not be zero, but the local-id MAY be zero
+if this CLOSE indicates a failed OPEN.
+
+A CLOSE message containing a remote-id which does not map to an open
+stream on the recipient's side is ignored.  The stream may have
+already been closed by the recipient while this message was in-flight.
+
+The recipient should not respond to a CLOSE message in any way.  The
+recipient should cancel pending WRITEs or CLOSEs, but this is not a
+requirement, since they will be ignored.
+
+
+--- SYNC(online, sequence, "") -----------------------------------------
+
+The SYNC message is used by the io pump to make sure that stale
+outbound messages are discarded when the connection to the remote side
+is broken.  It is only used internally to the bridge and never valid
+to send across the wire.  
+
+* when the connection to the remote side goes offline, the io pump 
+  sends a SYNC(0, 0) and starts discarding all messages
+* when the connection to the remote side is established, the io pump
+  sends a SYNC(1, token) and continues to discard messages
+* when the io pump receives a matching SYNC(1, token), it once again
+  starts accepting messages to forward to the remote side
+
+
+--- message command constants ------------------------------------------
+
+#define A_SYNC 0x434e5953
+#define A_CNXN 0x4e584e43
+#define A_OPEN 0x4e45504f
+#define A_OKAY 0x59414b4f
+#define A_CLSE 0x45534c43
+#define A_WRTE 0x45545257
+
+
+
+--- implementation details ---------------------------------------------
+
+The core of the bridge program will use three threads.  One thread
+will be a select/epoll loop to handle io between various inbound and
+outbound connections and the connection to the remote side.
+
+The remote side connection will be implemented as two threads (one for
+reading, one for writing) and a datagram socketpair to provide the
+channel between the main select/epoll thread and the remote connection
+threadpair.  The reason for this is that for usb connections, the
+kernel interface on linux and osx does not allow you to do meaningful
+nonblocking IO.
+
+The endian swapping for the message headers will happen (as needed) in
+the remote connection threadpair and that the rest of the program will
+always treat message header values as native-endian.
+
+The bridge program will be able to have a number of mini-servers
+compiled in.  They will be published under known names (examples
+"shell", "fs-bridge", etc) and upon receiving an OPEN() to such a
+service, the bridge program will create a stream socketpair and spawn
+a thread or subprocess to handle the io.
+
+
+--- simplified / embedded implementation -------------------------------
+
+For limited environments, like the bootloader, it is allowable to
+support a smaller, fixed number of channels using pre-assigned channel
+ID numbers such that only one stream may be connected to a bootloader
+endpoint at any given time.  The protocol remains unchanged, but the
+"embedded" version of it is less dynamic.
+
+The bootloader will support two streams.  A "bootloader:debug" stream,
+which may be opened to get debug messages from the bootloader and a 
+"bootloader:control", stream which will support the set of basic 
+bootloader commands.
+
+Example command stream dialogues:  
+  "flash_kernel,2515049,........\n" "okay\n" 
+  "flash_ramdisk,5038,........\n" "fail,flash write error\n" 
+  "bogus_command......" <CLOSE>
+
+
+--- future expansion ---------------------------------------------------
+
+I plan on providing either a message or a special control stream so that
+the client device could ask the host computer to setup inbound socket
+translations on the fly on behalf of the client device.
+
+
+The initial design does handshaking to provide flow control, with a
+message flow that looks like:
+
+  >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE
+
+The far side may choose to issue the READY message as soon as it receives
+a WRITE or it may defer the READY until the write to the local stream
+succeeds.  A future version may want to do some level of windowing where
+multiple WRITEs may be sent without requiring individual READY acks.
+
+------------------------------------------------------------------------
+
+--- smartsockets -------------------------------------------------------
+
+Port 5037 is used for smart sockets which allow a client on the host
+side to request access to a service in the host sdb daemon or in the
+remote (device) daemon.  The service is requested by ascii name,
+preceeded by a 4 digit hex length.  Upon successful connection an
+"OKAY" response is sent, otherwise a "FAIL" message is returned.  Once
+connected the client is talking to that (remote or local) service.
+
+client: <hex4> <service-name>
+server: "OKAY"
+
+client: <hex4> <service-name>
+server: "FAIL" <hex4> <reason>
+
diff --git a/src/pthread_win32.h b/src/pthread_win32.h
deleted file mode 100644 (file)
index cf1ae9e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 _PTHREAD_WIN32_H
-#define _PTHREAD_WIN32_H
-
-//#include <windows.h>
-
-// implementing posix thread on win32
-
-typedef struct {
-    HANDLE handle;
-    void *(*start_routine)(void*);
-    void *arg;
-    DWORD tid;
-} pthread_t;
-
-typedef struct {
-    LONG waiters;
-    int was_broadcast;
-    CRITICAL_SECTION waiters_lock;
-    HANDLE sema;
-    HANDLE continue_broadcast;
-} pthread_cond_t;
-
-
-typedef CRITICAL_SECTION        pthread_mutex_t;
-typedef  pthread_mutex_t        CRITICAL_SECTION;
-
-#define  SDB_MUTEX_DEFINE(x)    sdb_mutex_t   x
-
-#endif /* _PTHREAD_WIN32_H */
diff --git a/src/qemu_pipe.h b/src/qemu_pipe.h
new file mode 100644 (file)
index 0000000..5d6e87e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
+#define ANDROID_INCLUDE_HARDWARE_QEMU_PIPE_H
+
+#include <sys/cdefs.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <pthread.h>  /* for pthread_once() */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef D
+#  define  D(...)   do{}while(0)
+#endif
+
+/* Try to open a new Qemu fast-pipe. This function returns a file descriptor
+ * that can be used to communicate with a named service managed by the
+ * emulator.
+ *
+ * This file descriptor can be used as a standard pipe/socket descriptor.
+ *
+ * 'pipeName' is the name of the emulator service you want to connect to.
+ * E.g. 'opengles' or 'camera'.
+ *
+ * On success, return a valid file descriptor
+ * Returns -1 on error, and errno gives the error code, e.g.:
+ *
+ *    EINVAL  -> unknown/unsupported pipeName
+ *    ENOSYS  -> fast pipes not available in this system.
+ *
+ * ENOSYS should never happen, except if you're trying to run within a
+ * misconfigured emulator.
+ *
+ * You should be able to open several pipes to the same pipe service,
+ * except for a few special cases (e.g. GSM modem), where EBUSY will be
+ * returned if more than one client tries to connect to it.
+ */
+static __inline__ int
+qemu_pipe_open(const char*  pipeName)
+{
+    char  buff[256];
+    int   buffLen;
+    int   fd, ret;
+
+    if (pipeName == NULL || pipeName[0] == '\0') {
+        errno = EINVAL;
+        return -1;
+    }
+
+    snprintf(buff, sizeof buff, "pipe:%s", pipeName);
+
+    fd = open("/dev/qemu_pipe", O_RDWR);
+    if (fd < 0) {
+        D("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__, strerror(errno));
+        //errno = ENOSYS;
+        return -1;
+    }
+
+    buffLen = strlen(buff);
+
+    ret = TEMP_FAILURE_RETRY(write(fd, buff, buffLen+1));
+    if (ret != buffLen+1) {
+        D("%s: Could not connect to %s pipe service: %s", __FUNCTION__, pipeName, strerror(errno));
+        if (ret == 0) {
+            errno = ECONNRESET;
+        } else if (ret > 0) {
+            errno = EINVAL;
+        }
+        return -1;
+    }
+
+    return fd;
+}
+
+#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/src/remount_service.c b/src/remount_service.c
new file mode 100644 (file)
index 0000000..21ed259
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <errno.h>
+
+#include "sysdeps.h"
+
+#define  TRACE_TAG  TRACE_SDB
+#include "sdb.h"
+
+
+static int system_ro = 1;
+
+/* Returns the device used to mount a directory in /proc/mounts */
+static char *find_mount(const char *dir)
+{
+    int fd;
+    int res;
+    char *token = NULL;
+    const char delims[] = "\n";
+    char buf[4096];
+
+    fd = unix_open("/proc/mounts", O_RDONLY);
+    if (fd < 0)
+        return NULL;
+
+    buf[sizeof(buf) - 1] = '\0';
+    sdb_read(fd, buf, sizeof(buf) - 1);
+    sdb_close(fd);
+
+    token = strtok(buf, delims);
+
+    while (token) {
+        char mount_dev[256];
+        char mount_dir[256];
+        int mount_freq;
+        int mount_passno;
+
+        res = sscanf(token, "%255s %255s %*s %*s %d %d\n",
+                     mount_dev, mount_dir, &mount_freq, &mount_passno);
+        mount_dev[255] = 0;
+        mount_dir[255] = 0;
+        if (res == 4 && (strcmp(dir, mount_dir) == 0))
+            return strdup(mount_dev);
+
+        token = strtok(NULL, delims);
+    }
+    return NULL;
+}
+
+/* Init mounts /system as read only, remount to enable writes. */
+static int remount_system()
+{
+    char *dev;
+
+    if (system_ro == 0) {
+        return 0;
+    }
+
+    dev = find_mount("/system");
+
+    if (!dev)
+        return -1;
+
+    system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
+
+    free(dev);
+
+    return system_ro;
+}
+
+static void write_string(int fd, const char* str)
+{
+    writex(fd, str, strlen(str));
+}
+
+void remount_service(int fd, void *cookie)
+{
+    int ret = remount_system();
+
+    if (!ret)
+       write_string(fd, "remount succeeded\n");
+    else {
+        char    buffer[200];
+        snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
+        write_string(fd, buffer);
+    }
+
+    sdb_close(fd);
+}
+
index d33b6b8552c2e8b78adc26911f2f9a1d6a4ad303..a92ab5b51a61220b54693469f08f049d7f83c892 100755 (executable)
--- a/src/sdb.c
+++ b/src/sdb.c
 #include <sys/time.h>
 #include <signal.h>
 
-#include "utils.h"
-#include "fdevent.h"
+#include "sysdeps.h"
 #include "sdb.h"
-#include "commandline.h"
+
+#if !SDB_HOST
+//#include <private/android_filesystem_config.h> eric
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#define SDB_PIDPATH "/var/run/sdbd.pid"
+#else
+#include "usb_vendors.h"
+#endif
 
 #if SDB_TRACE
 SDB_MUTEX_DEFINE( D_lock );
@@ -37,6 +44,19 @@ SDB_MUTEX_DEFINE( D_lock );
 
 int HOST = 0;
 
+/*
+void handle_sig_term(int sig) {
+#ifdef SDB_PIDPATH
+    if (access(SDB_PIDPATH, F_OK) == 0)
+        sdb_unlink(SDB_PIDPATH);
+#endif
+    if (access("/dev/samsung_sdb", F_OK) == 0) {
+        exit(0);
+    } else {
+       // do nothing on a emulator
+    }
+}*/
+
 static const char *sdb_device_banner = "device";
 
 void fatal(const char *fmt, ...)
@@ -127,6 +147,61 @@ void  sdb_trace_init(void)
     }
 }
 
+#if !SDB_HOST
+/*
+ * Implements SDB tracing inside the emulator.
+ */
+
+#include <stdarg.h>
+
+/*
+ * Redefine open and write for qemu_pipe.h that contains inlined references
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ */
+
+#undef open
+#undef write
+#define open    sdb_open
+#define write   sdb_write
+#include "qemu_pipe.h"
+#undef open
+#undef write
+#define open    ___xxx_open
+#define write   ___xxx_write
+
+/* A handle to sdb-debug qemud service in the emulator. */
+int   sdb_debug_qemu = -1;
+
+/* Initializes connection with the sdb-debug qemud service in the emulator. */
+#if 0 /* doen't support in Tizen */
+static int sdb_qemu_trace_init(void)
+{
+    char con_name[32];
+
+    if (sdb_debug_qemu >= 0) {
+        return 0;
+    }
+
+    /* sdb debugging QEMUD service connection request. */
+    snprintf(con_name, sizeof(con_name), "qemud:sdb-debug");
+    sdb_debug_qemu = qemu_pipe_open(con_name);
+    return (sdb_debug_qemu >= 0) ? 0 : -1;
+}
+
+void sdb_qemu_trace(const char* fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    char msg[1024];
+
+    if (sdb_debug_qemu >= 0) {
+        vsnprintf(msg, sizeof(msg), fmt, args);
+        sdb_write(sdb_debug_qemu, msg, strlen(msg));
+    }
+}
+#endif
+#endif  /* !SDB_HOST */
+
 apacket *get_apacket(void)
 {
     apacket *p = malloc(sizeof(apacket));
@@ -223,11 +298,11 @@ static void send_connect(atransport *t)
             HOST ? "host" : sdb_device_banner);
     cp->msg.data_length = strlen((char*) cp->data) + 1;
     send_packet(cp, t);
-
-    /* XXX why sleep here? */
+#if SDB_HOST
+        /* XXX why sleep here? */
     // allow the device some time to respond to the connect message
     sdb_sleep_ms(1000);
-
+#endif
 }
 
 static char *connection_state_name(atransport *t)
@@ -489,10 +564,22 @@ int local_name_to_fd(const char *name)
         int  ret;
         port = atoi(name + 4);
         ret = socket_loopback_server(port, SOCK_STREAM);
-        D("add loopback listen to %d", port);
         return ret;
     }
+#ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
+    // It's non-sensical to support the "reserved" space on the sdb host side
+    if(!strncmp(name, "local:", 6)) {
+        return socket_local_server(name + 6,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localabstract:", 14)) {
+        return socket_local_server(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localfilesystem:", 16)) {
+        return socket_local_server(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+    }
 
+#endif
     printf("unknown local portname '%s'\n", name);
     return -1;
 }
@@ -518,7 +605,7 @@ static int install_listener(const char *local_name, const char *connect_to, atra
 {
     alistener *l;
 
-    D("install_listener('%s','%s')\n", local_name, connect_to);
+    //printf("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) {
@@ -586,7 +673,7 @@ nomem:
     return 0;
 }
 
-#ifdef OS_WINDOWS
+#ifdef HAVE_WIN32_PROC
 static BOOL WINAPI ctrlc_handler(DWORD type)
 {
     exit(STATUS_CONTROL_C_EXIT);
@@ -596,8 +683,259 @@ static BOOL WINAPI ctrlc_handler(DWORD type)
 
 static void sdb_cleanup(void)
 {
-    sdb_usb_cleanup();
+    usb_cleanup();
+}
+
+void start_logging(void)
+{
+#ifdef HAVE_WIN32_PROC
+    char    temp[ MAX_PATH ];
+    FILE*   fnul;
+    FILE*   flog;
+
+    GetTempPath( sizeof(temp) - 8, temp );
+    strcat( temp, "sdb.log" );
+
+    /* Win32 specific redirections */
+    fnul = fopen( "NUL", "rt" );
+    if (fnul != NULL)
+        stdin[0] = fnul[0];
+
+    flog = fopen( temp, "at" );
+    if (flog == NULL)
+        flog = fnul;
+
+    setvbuf( flog, NULL, _IONBF, 0 );
+
+    stdout[0] = flog[0];
+    stderr[0] = flog[0];
+    fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
+#else
+    int fd;
+
+    fd = unix_open("/dev/null", O_RDONLY);
+    dup2(fd, 0);
+    sdb_close(fd);
+
+    fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
+    if(fd < 0) {
+        fd = unix_open("/dev/null", O_WRONLY);
+    }
+    dup2(fd, 1);
+    dup2(fd, 2);
+    sdb_close(fd);
+    fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
+#endif
+}
+
+#if !SDB_HOST
+void start_device_log(void)
+{
+    int fd;
+    char    path[PATH_MAX];
+    struct tm now;
+    time_t t;
+//    char value[PROPERTY_VALUE_MAX];
+    const char* p = getenv("SDB_TRACE");
+    // read the trace mask from persistent property persist.sdb.trace_mask
+    // give up if the property is not set or cannot be parsed
+#if 0 /* tizen specific */
+    property_get("persist.sdb.trace_mask", value, "");
+    if (sscanf(value, "%x", &sdb_trace_mask) != 1)
+        return;
+#endif
+
+    if (p == NULL) {
+        return;
+    }
+    tzset();
+    time(&t);
+    localtime_r(&t, &now);
+    strftime(path, sizeof(path),
+                "/tmp/sdbd-%Y-%m-%d-%H-%M-%S.txt",
+                &now);
+    fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+    if (fd < 0)
+        return;
+
+    // redirect stdout and stderr to the log file
+    dup2(fd, 1);
+    dup2(fd, 2);
+    fprintf(stderr,"--- sdbd starting (pid %d) ---\n", getpid());
+    sdb_close(fd);
+
+    fd = unix_open("/dev/null", O_RDONLY);
+    dup2(fd, 0);
+    sdb_close(fd);
+}
+
+int daemonize(void) {
+
+    // set file creation mask to 0
+    umask(0);
+
+    switch (fork()) {
+    case -1:
+        return -1;
+    case 0:
+        break;
+    default:
+        _exit(0);
+    }
+#ifdef SDB_PIDPATH
+    FILE *f = fopen(SDB_PIDPATH, "w");
+
+    if (f != NULL) {
+        fprintf(f, "%d\n", getpid());
+        fclose(f);
+    }
+#endif
+    if (setsid() == -1)
+        return -1;
+
+    if (chdir("/") < 0)
+        D("sdbd: unable to change working directory to /\n");
+
+    return 0;
+}
+#endif
+
+#if SDB_HOST
+int launch_server(int server_port)
+{
+#ifdef HAVE_WIN32_PROC
+    /* we need to start the server in the background                    */
+    /* we create a PIPE that will be used to wait for the server's "OK" */
+    /* message since the pipe handles must be inheritable, we use a     */
+    /* security attribute                                               */
+    HANDLE                pipe_read, pipe_write;
+    SECURITY_ATTRIBUTES   sa;
+    STARTUPINFO           startup;
+    PROCESS_INFORMATION   pinfo;
+    char                  program_path[ MAX_PATH ];
+    int                   ret;
+
+    sa.nLength = sizeof(sa);
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = TRUE;
+
+    /* create pipe, and ensure its read handle isn't inheritable */
+    ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
+    if (!ret) {
+        fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
+        return -1;
+    }
+
+    SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+
+    ZeroMemory( &startup, sizeof(startup) );
+    startup.cb = sizeof(startup);
+    startup.hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
+    startup.hStdOutput = pipe_write;
+    startup.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
+    startup.dwFlags    = STARTF_USESTDHANDLES;
+
+    ZeroMemory( &pinfo, sizeof(pinfo) );
+
+    /* get path of current program */
+    GetModuleFileName( NULL, program_path, sizeof(program_path) );
+
+    ret = CreateProcess(
+            program_path,                              /* program path  */
+            "sdb fork-server server",
+                                    /* the fork-server argument will set the
+                                       debug = 2 in the child           */
+            NULL,                   /* process handle is not inheritable */
+            NULL,                    /* thread handle is not inheritable */
+            TRUE,                          /* yes, inherit some handles */
+            DETACHED_PROCESS, /* the new process doesn't have a console */
+            NULL,                     /* use parent's environment block */
+            NULL,                    /* use parent's starting directory */
+            &startup,                 /* startup info, i.e. std handles */
+            &pinfo );
+
+    CloseHandle( pipe_write );
+
+    if (!ret) {
+        fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
+        CloseHandle( pipe_read );
+        return -1;
+    }
+
+    CloseHandle( pinfo.hProcess );
+    CloseHandle( pinfo.hThread );
+
+    /* wait for the "OK\n" message */
+    {
+        char  temp[3];
+        DWORD  count;
+
+        ret = ReadFile( pipe_read, temp, 3, &count, NULL );
+        CloseHandle( pipe_read );
+        if ( !ret ) {
+            fprintf(stderr, "could not read ok from SDB Server, error = %ld\n", GetLastError() );
+            return -1;
+        }
+        if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+            fprintf(stderr, "SDB server didn't ACK\n" );
+            return -1;
+        }
+    }
+#elif defined(HAVE_FORKEXEC)
+    char    path[PATH_MAX];
+    int     fd[2];
+
+    // set up a pipe so the child can tell us when it is ready.
+    // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
+    if (pipe(fd)) {
+        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
+        return -1;
+    }
+    get_my_path(path, PATH_MAX);
+    pid_t pid = fork();
+    if(pid < 0) return -1;
+
+    if (pid == 0) {
+        // child side of the fork
+
+        // redirect stderr to the pipe
+        // we use stderr instead of stdout due to stdout's buffering behavior.
+        sdb_close(fd[0]);
+        dup2(fd[1], STDERR_FILENO);
+        sdb_close(fd[1]);
+
+        // child process
+        int result = execl(path, "sdb", "fork-server", "server", NULL);
+        // this should not return
+        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+    } else  {
+        // parent side of the fork
+
+        char  temp[3];
+
+        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
+        // wait for the "OK\n" message
+        sdb_close(fd[1]);
+        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;
+        }
+        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
+            fprintf(stderr, "SDB server didn't ACK\n" );
+            return -1;
+        }
+
+        setsid();
+    }
+#else
+#error "cannot implement background server start on this platform"
+#endif
+    return 0;
 }
+#endif
 
 /* Constructs a local name of form tcp:port.
  * target_str points to the target string, it's content will be overwritten.
@@ -609,20 +947,66 @@ void build_local_name(char* target_str, size_t target_size, int server_port)
   snprintf(target_str, target_size, "tcp:%d", server_port);
 }
 
+#if 0
+#if !SDB_HOST
+static int should_drop_privileges() {
+#ifndef ALLOW_SDBD_ROOT
+    return 1;
+#else /* ALLOW_SDBD_ROOT */
+    int secure = 0;
+    char value[PROPERTY_VALUE_MAX];
+
+   /* run sdbd in secure mode if ro.secure is set and
+    ** we are not in the emulator
+    */
+    property_get("ro.kernel.qemu", value, "");
+    if (strcmp(value, "1") != 0) {
+        property_get("ro.secure", value, "1");
+        if (strcmp(value, "1") == 0) {
+            // don't run as root if ro.secure is set...
+            secure = 1;
+
+            // ... except we allow running as root in userdebug builds if the
+            // service.sdb.root property has been set by the "sdb root" command
+            property_get("ro.debuggable", value, "");
+            if (strcmp(value, "1") == 0) {
+                property_get("service.sdb.root", value, "");
+                if (strcmp(value, "1") == 0) {
+                    secure = 0;
+                }
+            }
+        }
+    }
+    return secure;
+#endif /* ALLOW_SDBD_ROOT */
+}
+#endif /* !SDB_HOST */
+#endif
+
 int sdb_main(int is_daemon, int server_port)
 {
-#ifdef OS_WINDOWS
+#if !SDB_HOST
+    int port;
+    char value[PROPERTY_VALUE_MAX];
+
+    umask(000);
+#endif
+
+    atexit(sdb_cleanup);
+#ifdef HAVE_WIN32_PROC
     SetConsoleCtrlHandler( ctrlc_handler, TRUE );
-#else
+#elif defined(HAVE_FORKEXEC)
     // No SIGCHLD. Let the service subproc handle its children.
     signal(SIGPIPE, SIG_IGN);
 #endif
 
     init_transport_registration();
 
+
+#if SDB_HOST
     HOST = 1;
-//    usb_vendors_init();
-    sdb_usb_init();
+    usb_vendors_init();
+    usb_init();
     local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
 
     char local_name[30];
@@ -630,13 +1014,98 @@ int sdb_main(int is_daemon, int server_port)
     if(install_listener(local_name, "*smartsocket*", NULL)) {
         exit(1);
     }
+#else
+#if 0 /* tizen specific */
+    /* don't listen on a port (default 5037) if running in secure mode */
+    /* don't run as root if we are running in secure mode */
+    if (should_drop_privileges()) {
+        struct __user_cap_header_struct header;
+        struct __user_cap_data_struct cap;
+
+        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
+            exit(1);
+        }
+
+        /* add extra groups:
+        ** AID_SDB to access the USB driver
+        ** AID_LOG to read system logs (sdb logcat)
+        ** AID_INPUT to diagnose input issues (getevent)
+        ** AID_INET to diagnose network issues (netcfg, ping)
+        ** AID_GRAPHICS to access the frame buffer
+        ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+        ** AID_SDCARD_R to allow reading from the SD card
+        ** AID_SDCARD_RW to allow writing to the SD card
+        ** AID_MOUNT to allow unmounting the SD card before rebooting
+        ** AID_NET_BW_STATS to read out qtaguid statistics
+        */
+        gid_t groups[] = { AID_SDB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
+                           AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+                           AID_MOUNT, AID_NET_BW_STATS };
+        if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+            exit(1);
+        }
+
+        /* then switch user and group to "shell" */
+        if (setgid(AID_SHELL) != 0) {
+            exit(1);
+        }
+        if (setuid(AID_SHELL) != 0) {
+            exit(1);
+        }
+
+        /* set CAP_SYS_BOOT capability, so "sdb reboot" will succeed */
+        header.version = _LINUX_CAPABILITY_VERSION;
+        header.pid = 0;
+        cap.effective = cap.permitted = (1 << CAP_SYS_BOOT);
+        cap.inheritable = 0;
+        capset(&header, &cap);
+
+        D("Local port disabled\n");
+    } else {
+#endif
+        char local_name[30];
+        build_local_name(local_name, sizeof(local_name), server_port);
+        if(install_listener(local_name, "*smartsocket*", NULL)) {
+            exit(1);
+        }
+#if 0 /* tizen specific */
+    }
+#endif
+        /* for the device, start the usb transport if the
+        ** android usb device exists and the "service.sdb.tcp.port" and
+        ** "persist.sdb.tcp.port" properties are not set.
+        ** Otherwise start the network transport.
+        */
+    property_get("service.sdb.tcp.port", value, "");
+#if 0 /* tizen specific */
+    if (!value[0])
+        property_get("persist.sdb.tcp.port", value, "");
+#endif
+    if (sscanf(value, "%d", &port) == 1 && port > 0) {
+        // listen on TCP port specified by service.sdb.tcp.port property
+        local_init(port);
+    } else if (access("/dev/samsung_sdb", F_OK) == 0) {
+        // listen on USB
+        usb_init();
+    } else {
+        // listen on default port
+        local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT);
+    }
+
+#if 0 /* tizen specific */
+    D("sdb_main(): pre init_jdwp()\n");
+    init_jdwp();
+    D("sdb_main(): post init_jdwp()\n");
+#endif
+#endif
+
     if (is_daemon)
     {
         // inform our parent that we are up and running.
-#ifdef OS_WINDOWS
+#ifdef HAVE_WIN32_PROC
         DWORD  count;
         WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
-#else
+#elif defined(HAVE_FORKEXEC)
         fprintf(stderr, "OK\n");
 #endif
         start_logging();
@@ -645,11 +1114,12 @@ int sdb_main(int is_daemon, int server_port)
 
     fdevent_loop();
 
-    atexit(sdb_cleanup);
+    usb_cleanup();
 
     return 0;
 }
 
+#if SDB_HOST
 void connect_device(char* host, char* buffer, int buffer_size)
 {
     int port, fd;
@@ -746,6 +1216,7 @@ void connect_emulator(char* port_spec, char* buffer, int buffer_size)
                 console_port, sdb_port);
     }
 }
+#endif
 
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
 {
@@ -756,10 +1227,11 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
         fprintf(stderr,"sdb server killed by remote request\n");
         fflush(stdout);
         sdb_write(reply_fd, "OKAY", 4);
-        sdb_cleanup();
+        usb_cleanup();
         exit(0);
     }
 
+#if SDB_HOST
     // "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
@@ -912,6 +1384,7 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
            local_connect(port, NULL);
         return 0;
     }
+#endif // SDB_HOST
 
     if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
         char *local, *remote, *err;
@@ -968,10 +1441,37 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r
     return -1;
 }
 
+#if !SDB_HOST
+int recovery_mode = 0;
+#endif
+
 int main(int argc, char **argv)
 {
-    sdb_trace_init();
+    sdb_trace_init(); /* tizen specific */
+#if SDB_HOST
     sdb_sysdeps_init();
+    sdb_trace_init();
+    return sdb_commandline(argc - 1, argv + 1);
+#else
+    /* If sdbd runs inside the emulator this will enable sdb tracing via
+     * sdb-debug qemud service in the emulator. */
+#if 0 /* tizen specific */
+    sdb_qemu_trace_init();
+    if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
+        sdb_device_banner = "recovery";
+        recovery_mode = 1;
+    }
+#endif
+#if !SDB_HOST
+    if (daemonize() < 0)
+        fatal("daemonize() failed: %.200s", strerror(errno));
+#endif
 
-    return process_cmdline(argc - 1, argv + 1);
+    start_device_log();
+    D("Handling main()\n");
+
+    //sdbd will never die on emulator!
+    //signal(SIGTERM, handle_sig_term); /* tizen specific */
+    return sdb_main(0, DEFAULT_SDB_PORT);
+#endif
 }
index b45134a4b53e948ea7647b3cae2d0cd94a0b199d..f7cf3c1fb195f9f29b4cceba95f940da7dc47172 100755 (executable)
--- a/src/sdb.h
+++ b/src/sdb.h
@@ -20,7 +20,6 @@
 #include <limits.h>
 
 #include "transport.h"  /* readx(), writex() */
-#include "sdb_usb.h"
 
 #define MAX_PAYLOAD 4096
 
@@ -34,7 +33,7 @@
 #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_VERSION_MINOR 1         // Used for help/version information
 
 #define SDB_SERVER_VERSION    0    // Increment this when we want to force users to start a new sdb server
 
@@ -45,6 +44,7 @@ typedef struct alistener alistener;
 typedef struct aservice aservice;
 typedef struct atransport atransport;
 typedef struct adisconnect  adisconnect;
+typedef struct usb_handle usb_handle;
 
 struct amessage {
     unsigned command;       /* command identifier constant      */
@@ -86,7 +86,7 @@ struct asocket {
         */
     int    closing;
 
-        /* flag: quit sdbd when both ends close the
+        /* flag: quit adbd when both ends close the
         ** local service socket
         */
     int    exit_on_close;
@@ -245,6 +245,8 @@ void fatal_errno(const char *fmt, ...);
 void handle_packet(apacket *p, atransport *t);
 void send_packet(apacket *p, atransport *t);
 
+void get_my_path(char *s, size_t maxLen);
+int launch_server(int server_port);
 int sdb_main(int is_daemon, int server_port);
 
 
@@ -270,11 +272,14 @@ void   run_transport_disconnects( atransport*  t );
 void   kick_transport( atransport*  t );
 
 /* initialize a transport object's func pointers and state */
+#if SDB_HOST
 int get_available_local_transport_index();
+#endif
 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();
 
+/* for MacOS X cleanup */
+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);
@@ -289,10 +294,33 @@ void register_usb_transport(usb_handle *h, const char *serial, unsigned writeabl
 void unregister_usb_transport(usb_handle *usb);
 
 atransport *find_transport(const char *serial);
+#if SDB_HOST
 atransport* find_emulator_transport_by_sdb_port(int sdb_port);
+#endif
 
 int service_to_fd(const char *name);
+#if SDB_HOST
 asocket *host_service_to_socket(const char*  name, const char *serial);
+#endif
+
+#if !SDB_HOST
+int       init_jdwp(void);
+asocket*  create_jdwp_service_socket();
+asocket*  create_jdwp_tracker_service_socket();
+int       create_jdwp_connection_fd(int  jdwp_pid);
+#endif
+
+#if !SDB_HOST
+typedef enum {
+    BACKUP,
+    RESTORE
+} BackupOperation;
+int backup_service(BackupOperation operation, char* args);
+void framebuffer_service(int fd, void *cookie);
+void log_service(int fd, void *cookie);
+void remount_service(int fd, void *cookie);
+char * get_log_file_path(const char * log_name);
+#endif
 
 /* packet allocator */
 apacket *get_apacket(void);
@@ -325,8 +353,20 @@ typedef enum {
 
 #if SDB_TRACE
 
-#define DQ(...) ((void)0)
+#if !SDB_HOST
+/*
+ * When running inside the emulator, guest's sdbd can connect to 'sdb-debug'
+ * qemud service that can display sdb trace messages (on condition that emulator
+ * has been started with '-debug sdb' option).
+ */
 
+/* Delivers a trace message to the emulator via QEMU pipe. */
+void sdb_qemu_trace(const char* fmt, ...);
+/* Macro to use to send SDB trace messages to the emulator. */
+#define DQ(...)    sdb_qemu_trace(__VA_ARGS__)
+#else
+#define DQ(...) ((void)0)
+#endif  /* !SDB_HOST */
 
   extern int     sdb_trace_mask;
   extern unsigned char    sdb_trace_output_count;
@@ -372,17 +412,38 @@ typedef enum {
 #define print_packet(tag,p) do {} while (0)
 #endif
 
-
+#if SDB_HOST_ON_TARGET
 /* 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_PORT 26099 /* tizen specific */
+#else
+#  define DEFAULT_SDB_PORT 26099 /* tizen specific */
+#endif
+
 #define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 /* tizen specific */
 
+#define SDB_CLASS              0xff
+#define SDB_SUBCLASS           0x20 //0x42 /* tizen specific */
+#define SDB_PROTOCOL           0x02 //0x01 /* 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);
 
+/* usb host/client interface */
+void usb_init();
+void usb_cleanup();
+int usb_write(usb_handle *h, const void *data, int len);
+int usb_read(usb_handle *h, void *data, int len);
+int usb_close(usb_handle *h);
+void usb_kick(usb_handle *h);
+
+/* used for USB device detection */
+#if SDB_HOST
+int is_sdb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
+#endif
 
 unsigned host_to_le32(unsigned n);
 int sdb_commandline(int argc, char **argv);
@@ -406,6 +467,12 @@ extern int SHELL_EXIT_NOTIFY_FD;
 int sendfailmsg(int fd, const char *reason);
 int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
 
+#if SDB_HOST /* tizen-specific */
+#define DEVICEMAP_SEPARATOR ":"
+#define DEVICENAME_MAX 256
+#define VMS_PATH OS_PATH_SEPARATOR_STR "vms" OS_PATH_SEPARATOR_STR // should include sysdeps.h above
+#define DEFAULT_DEVICENAME "<unknown>"
 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
+#endif
index dd26d29ba7abebc5f8ad2846beefc3769d76fc42..18fd20bee31890888211d3e42cf9527232f5c324 100644 (file)
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+// tizen specific #include <zipfile/zipfile.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "fdevent.h"
-#include "sdb_constants.h"
-#include "utils.h"
+
+#include "sysdeps.h"
 
 #define  TRACE_TAG  TRACE_SDB
 #include "sdb_client.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 transport_type __sdb_transport = kTransportAny;
+static const char* __sdb_serial = NULL;
 
-static int send_service_with_length(int fd, const char* service) {
-    char tmp[5];
-    int len;
-    len = strlen(service);
+static int __sdb_server_port = DEFAULT_SDB_PORT;
 
-    if(len < 1) {
-        fprintf(stderr,"error: service name is empty\n");
-        return -1;
-    }
-    else if (len > 1024) {
-        fprintf(stderr,"error: service name too long\n");
-        return -1;
-    }
+void sdb_set_transport(transport_type type, const char* serial)
+{
+    __sdb_transport = type;
+    __sdb_serial = serial;
+}
 
-    if(write_msg_size(fd, len) < 0) {
-        return -1;
-    }
+void sdb_set_tcp_specifics(int server_port)
+{
+    __sdb_server_port = server_port;
+}
 
-    if(writex(fd, service, len)) {
-        fprintf(stderr,"error: write failure during connection\n");
-        return -1;
+int  sdb_get_emulator_console_port(void)
+{
+    const char*   serial = __sdb_serial;
+    int           port;
+
+    if (serial == NULL) {
+        /* if no specific device was specified, we need to look at */
+        /* the list of connected devices, and extract an emulator  */
+        /* name from it. two emulators is an error                 */
+        char*  tmp = sdb_query("host:devices");
+        char*  p   = tmp;
+        if(!tmp) {
+            printf("no emulator connected\n");
+            return -1;
+        }
+        while (*p) {
+            char*  q = strchr(p, '\n');
+            if (q != NULL)
+                *q++ = 0;
+            else
+                q = p + strlen(p);
+
+            if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
+                if (serial != NULL) {  /* more than one emulator listed */
+                    free(tmp);
+                    return -2;
+                }
+                serial = p;
+            }
+
+            p = q;
+        }
+        free(tmp);
+
+        if (serial == NULL)
+            return -1;  /* no emulator found */
+    }
+    else {
+        if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
+            return -1;  /* not an emulator */
     }
 
-    return 0;
+    serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
+    port    = strtol(serial, NULL, 10);
+    return port;
 }
 
-static int switch_socket_transport(int fd, void** extra_args)
+static char __sdb_error[256] = { 0 };
+
+const char *sdb_error(void)
 {
-    char* serial = (char *)extra_args[0];
-    transport_type ttype = *(transport_type*)extra_args[1];
+    return __sdb_error;
+}
 
+static int switch_socket_transport(int fd)
+{
     char service[64];
+    char tmp[5];
+    int len;
 
-    get_host_prefix(service, sizeof service, ttype, serial, transport);
+    if (__sdb_serial)
+        snprintf(service, sizeof service, "host:transport:%s", __sdb_serial);
+    else {
+        char* transport_type = "???";
+
+         switch (__sdb_transport) {
+            case kTransportUsb:
+                transport_type = "transport-usb";
+                break;
+            case kTransportLocal:
+                transport_type = "transport-local";
+                break;
+            case kTransportAny:
+                transport_type = "transport-any";
+                break;
+            case kTransportHost:
+                // no switch necessary
+                return 0;
+                break;
+            default:
+                D("unknown transport type\n");
+                break;
+        }
 
-    if(!strcmp(service, PREFIX_HOST)) {
-        // no switch necessary
-        return 0;
+        snprintf(service, sizeof service, "host:%s", transport_type);
     }
+    len = strlen(service);
+    snprintf(tmp, sizeof tmp, "%04x", len);
 
-    if(send_service_with_length(fd, service) < 0) {
+    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
+        strcpy(__sdb_error, "write failure during connection");
         sdb_close(fd);
         return -1;
     }
-
     D("Switch transport in progress\n");
 
     if(sdb_status(fd)) {
@@ -89,12 +150,13 @@ static int switch_socket_transport(int fd, void** extra_args)
     return 0;
 }
 
-static int sdb_status(int fd)
+int sdb_status(int fd)
 {
     unsigned char buf[5];
+    unsigned len;
 
     if(readx(fd, buf, 4)) {
-        fprintf(stderr,"error: protocol fault (no status)\n");
+        strcpy(__sdb_error, "protocol fault (no status)");
         return -1;
     }
 
@@ -103,48 +165,53 @@ static int sdb_status(int fd)
     }
 
     if(memcmp(buf, "FAIL", 4)) {
-        fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n",
+        sprintf(__sdb_error,
+                "protocol fault (status %02x %02x %02x %02x?!)",
                 buf[0], buf[1], buf[2], buf[3]);
         return -1;
     }
 
-    int len = read_msg_size(fd);
-    if(len < 0) {
-        fprintf(stderr,"error: protocol fault (status len)\n");
+    if(readx(fd, buf, 4)) {
+        strcpy(__sdb_error, "protocol fault (status len)");
         return -1;
     }
+    buf[4] = 0;
+    len = strtoul((char*)buf, 0, 16);
     if(len > 255) len = 255;
-
-
-    char error[255];
-    if(readx(fd, error, len)) {
-        fprintf(stderr,"error: protocol fault (status read)\n");
+    if(readx(fd, __sdb_error, len)) {
+        strcpy(__sdb_error, "protocol fault (status read)");
         return -1;
     }
-    error[len] = '\0';
-    fprintf(stderr,"error: %s\n", error);
+    __sdb_error[len] = 0;
     return -1;
 }
 
-int _sdb_connect(const char *service, void** ext_args)
+int _sdb_connect(const char *service)
 {
+    char tmp[5];
+    int len;
     int fd;
 
     D("_sdb_connect: %s\n", service);
+    len = strlen(service);
+    if((len < 1) || (len > 1024)) {
+        strcpy(__sdb_error, "service name too long");
+        return -1;
+    }
+    snprintf(tmp, sizeof tmp, "%04x", len);
 
-    int server_port = *(int*)ext_args[2];
-
-    fd = socket_loopback_client(server_port, SOCK_STREAM);
+    fd = socket_loopback_client(__sdb_server_port, SOCK_STREAM);
     if(fd < 0) {
-        D("error: cannot connect to daemon\n");
+        strcpy(__sdb_error, "cannot connect to daemon");
         return -2;
     }
 
-    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd, ext_args)) {
+    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
         return -1;
     }
 
-    if(send_service_with_length(fd, service) < 0) {
+    if(writex(fd, tmp, 4) || writex(fd, service, len)) {
+        strcpy(__sdb_error, "write failure during connection");
         sdb_close(fd);
         return -1;
     }
@@ -158,40 +225,17 @@ int _sdb_connect(const char *service, void** ext_args)
     return fd;
 }
 
-int __inline__ read_msg_size(int fd) {
-    char buf[5];
-
-    if(readx(fd, buf, 4)) {
-        return -1;
-    }
-
-    buf[4] = 0;
-    return strtoul(buf, NULL, 16);
-}
-
-int __inline__ write_msg_size(int fd, int size) {
-    char tmp[5];
-    snprintf(tmp, sizeof tmp, "%04x", size);
-
-    if(writex(fd, tmp, 4)) {
-        fprintf(stderr,"error: write msg size failure\n");
-        return -1;
-    }
-    return 1;
-}
-
-int sdb_connect(const char *service, void** ext_args)
+int sdb_connect(const char *service)
 {
     // first query the sdb server's version
-    int fd = _sdb_connect("host:version", ext_args);
-    int server_port = *(int*)ext_args[2];
+    int fd = _sdb_connect("host:version");
 
     D("sdb_connect: service %s\n", service);
     if(fd == -2) {
         fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
-                server_port);
+                __sdb_server_port);
     start_server:
-        if(launch_server(server_port)) {
+        if(launch_server(__sdb_server_port)) {
             fprintf(stderr,"* failed to start daemon *\n");
             return -1;
         } else {
@@ -202,23 +246,31 @@ int sdb_connect(const char *service, void** ext_args)
         // fall through to _sdb_connect
     } else {
         // if server was running, check its version to make sure it is not out of date
+        char buf[100];
+        int n;
         int version = SDB_SERVER_VERSION - 1;
 
         // if we have a file descriptor, then parse version result
         if(fd >= 0) {
-            int n = read_msg_size(fd);
-            char buf[100];
-            if(n < 0 || readx(fd, buf, n) || sscanf(buf, "%04x", &version) != 1) {
-                goto error;
-            }
+            if(readx(fd, buf, 4)) goto error;
+
+            buf[4] = 0;
+            n = strtoul(buf, 0, 16);
+            if(n > (int)sizeof(buf)) goto error;
+            if(readx(fd, buf, n)) goto error;
             sdb_close(fd);
+
+            if (sscanf(buf, "%04x", &version) != 1) goto error;
         } else {
+            // if fd is -1, then check for "unknown host service",
+            // which would indicate a version of sdb that does not support the version command
+            if (strcmp(__sdb_error, "unknown host service") != 0)
                 return fd;
         }
 
         if(version != SDB_SERVER_VERSION) {
             printf("sdb server is out of date.  killing...\n");
-            fd = _sdb_connect("host:kill", ext_args);
+            fd = _sdb_connect("host:kill");
             sdb_close(fd);
 
             /* XXX can we better detect its death? */
@@ -231,7 +283,7 @@ int sdb_connect(const char *service, void** ext_args)
     if (!strcmp(service, "host:start-server"))
         return 0;
 
-    fd = _sdb_connect(service, ext_args);
+    fd = _sdb_connect(service);
     if(fd == -2) {
         fprintf(stderr,"** daemon still not running");
     }
@@ -244,9 +296,9 @@ error:
 }
 
 
-int sdb_command(const char *service, void** extra_args)
+int sdb_command(const char *service)
 {
-    int fd = sdb_connect(service, extra_args);
+    int fd = sdb_connect(service);
     if(fd < 0) {
         return -1;
     }
@@ -259,20 +311,24 @@ int sdb_command(const char *service, void** extra_args)
     return 0;
 }
 
-char *sdb_query(const char *service, void** extra_args)
+char *sdb_query(const char *service)
 {
+    char buf[5];
+    unsigned n;
     char *tmp;
 
     D("sdb_query: %s\n", service);
-    int fd = sdb_connect(service, extra_args);
+    int fd = sdb_connect(service);
     if(fd < 0) {
+        fprintf(stderr,"error: %s\n", __sdb_error);
         return 0;
     }
 
-    int n = read_msg_size(fd);
-    if(n < 0 || n > 1024) {
-        goto oops;
-    }
+    if(readx(fd, buf, 4)) goto oops;
+
+    buf[4] = 0;
+    n = strtoul(buf, 0, 16);
+    if(n > 1024) goto oops;
 
     tmp = malloc(n + 1);
     if(tmp == 0) goto oops;
@@ -288,45 +344,3 @@ oops:
     sdb_close(fd);
     return 0;
 }
-
-void get_host_prefix(char* prefix, int size, transport_type ttype, const char* serial, HOST_TYPE host_type) {
-    if(serial) {
-        if(host_type == host) {
-            snprintf(prefix, size, "%s%s:", PREFIX_HOST_SERIAL, serial);
-        }
-        else if(host_type == transport) {
-            snprintf(prefix, size, "%s%s", PREFIX_TRANSPORT_SERIAL, serial);
-        }
-    }
-    else {
-        char* temp_prefix;
-        if(ttype == kTransportUsb) {
-            if(host_type == host) {
-                temp_prefix = (char*)PREFIX_HOST_USB;
-            }
-            else if(host_type == transport) {
-                temp_prefix = (char*)PREFIX_TRANSPORT_USB;
-            }
-        }
-        else if(ttype == kTransportLocal) {
-            if(host_type == host) {
-                temp_prefix = (char*)PREFIX_HOST_LOCAL;
-            }
-            else if(host_type == transport) {
-                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;
-            }
-            else if(host_type == transport) {
-                temp_prefix = (char*)PREFIX_TRANSPORT_ANY;
-            }
-        }
-        snprintf(prefix, size, "%s", temp_prefix);
-    }
-}
index f20b672e677c2cc71e0df7c97e2b045834742950..86e9ef165026d8672bc875fa1c5fb29f97c16fbb 100644 (file)
 #define _SDB_CLIENT_H_
 
 #include "sdb.h"
-#include "sdb_constants.h"
 
 /* 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
 */
-int sdb_connect(const char *service, void** ext_args);
-int _sdb_connect(const char *service, void** ext_args);
+int sdb_connect(const char *service);
+int _sdb_connect(const char *service);
 
 /* connect to sdb, connect to the named service, return 0 if
 ** the connection succeeded AND the service returned OKAY
 */
-int sdb_command(const char *service, void** ext_args);
+int sdb_command(const char *service);
 
 /* connect to sdb, connect to the named service, return
 ** a malloc'd string of its response upon success or NULL
 ** on failure.
 */
 
-char *sdb_query(const char *service, void** ext_args);
+char *sdb_query(const char *service);
+
+/* Set the preferred transport to connect to.
+*/
+void sdb_set_transport(transport_type type, const char* serial);
+
+/* Set TCP specifics of the transport to use
+*/
+void sdb_set_tcp_specifics(int server_port);
+
+/* Return the console port of the currently connected emulator (if any)
+ * of -1 if there is no emulator, and -2 if there is more than one.
+ * assumes sdb_set_transport() was alled previously...
+ */
+int  sdb_get_emulator_console_port(void);
+
+/* send commands to the current emulator instance. will fail if there
+ * is zero, or more than one emulator connected (or if you use -s <serial>
+ * with a <serial> that does not designate an emulator)
+ */
+int  sdb_send_emulator_command(int  argc, char**  argv);
 
 /* return verbose error string from last operation */
 const char *sdb_error(void);
@@ -46,8 +65,6 @@ const char *sdb_error(void);
 ** 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 sdb_status(int fd);
 
-void get_host_prefix(char* prefix, int size, transport_type ttype, const char* serial, HOST_TYPE host_type);
 #endif
diff --git a/src/sdb_constants.c b/src/sdb_constants.c
deleted file mode 100644 (file)
index aeac8e2..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-* 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 "sdb_constants.h"
-
-    const char* HELP_APPEND_STR = "                                ";
-
-    const char* EMPTY_STRING = "";
-    const char* DIR_APP_TMP = "/opt/usr/apps/tmp/";
-    const char* QUOTE_CHAR = " \"\\()";
-
-    const char* PREFIX_HOST = "host:";
-    const char* PREFIX_HOST_USB = "host-usb:";
-    const char* PREFIX_HOST_LOCAL = "host-local:";
-    const char* PREFIX_HOST_SERIAL = "host-serial:";
-
-    const char* PREFIX_TRANSPORT_ANY = "host:transport-any";
-    const char* PREFIX_TRANSPORT_USB = "host:transport-usb";
-    const char* PREFIX_TRANSPORT_LOCAL = "host:transport-local";
-    const char* PREFIX_TRANSPORT_SERIAL = "host:transport:";
-
-    const char* COMMANDLINE_MSG_FULL_CMD = "full command of %s: %s\n";
-    const char* COMMANDLINE_OPROFILE_NAME = "oprofile";
-    const int COMMANDLINE_OPROFILE_MAX_ARG = -1;
-    const int COMMANDLINE_OPROFILE_MIN_ARG = 0;
-
-    const char* COMMANDLINE_DA_NAME = "da";
-    const int COMMANDLINE_DA_MAX_ARG = -1;
-    const int COMMANDLINE_DA_MIN_ARG = 0;
-
-    const char* COMMANDLINE_LAUNCH_NAME = "launch";
-    const int COMMANDLINE_LAUNCH_MAX_ARG = -1;
-    const int COMMANDLINE_LAUNCH_MIN_ARG = 0;
-
-    const char* COMMANDLINE_DEVICES_NAME = "devices";
-    const char* COMMANDLINE_DEVICES_DESC[] = {
-            "list all connected devices"
-    };
-    const int COMMANDLINE_DEVICES_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DEVICES_DESC, char*);
-    const int COMMANDLINE_DEVICES_MAX_ARG = 0;
-    const int COMMANDLINE_DEVICES_MIN_ARG = 0;
-
-    const char* COMMANDLINE_DISCONNECT_NAME = "disconnect";
-    const char* COMMANDLINE_DISCONNECT_DESC[] = {
-            "disconnect from a TCP/IP device.",
-            "Port 26101 is used by default if no port number is specified",
-            "Using this command with no additional arguments",
-            "will disconnect from all connected TCP/IP devices",
-    };
-    const int COMMANDLINE_DISCONNECT_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DISCONNECT_DESC, char*);
-    const char* COMMANDLINE_DISCONNECT_ARG_DESC = "[<host>[:<port>]]";
-    const int COMMANDLINE_DISCONNECT_MAX_ARG = 1;
-    const int COMMANDLINE_DISCONNECT_MIN_ARG = 0;
-
-    const char* COMMANDLINE_CONNECT_NAME = "connect";
-    const char* COMMANDLINE_CONNECT_DESC[] = {
-            "connect to a device via TCP/IP",
-            "Port 26101 is used by default if no port number is specified"
-    };
-    const int COMMANDLINE_CONNECT_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_CONNECT_DESC, char*);
-    const char* COMMANDLINE_CONNECT_ARG_DESC = "<host>[:<port>]";
-    const int COMMANDLINE_CONNECT_MAX_ARG = 1;
-    const int COMMANDLINE_CONNECT_MIN_ARG = 1;
-
-    const char* COMMANDLINE_GSERIAL_NAME = "get-serialno";
-    const char* COMMANDLINE_GSERIAL_DESC[] = {
-            "print: <serial-number>"
-    };
-    const int COMMANDLINE_GSERIAL_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_GSERIAL_DESC, char*);
-    const int COMMANDLINE_GSERIAL_MAX_ARG = 0;
-    const int COMMANDLINE_GSERIAL_MIN_ARG = 0;
-
-    const char* COMMANDLINE_GSTATE_NAME = "get-state";
-    const char* COMMANDLINE_GSTATE_DESC[] = {
-            "print: offline | bootloader | device"
-    };
-    const int COMMANDLINE_GSTATE_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_GSTATE_DESC, char*);
-    const int COMMANDLINE_GSTATE_MAX_ARG = 0;
-    const int COMMANDLINE_GSTATE_MIN_ARG = 0;
-
-    const char* COMMANDLINE_ROOT_NAME = "root";
-    const char* COMMANDLINE_ROOT_DESC[] = {
-            "switch to root or developer account mode",
-            "'on' means to root mode, and vice versa"
-    };
-    const int COMMANDLINE_ROOT_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_ROOT_DESC, char*);
-    const char* COMMANDLINE_ROOT_ARG_DESC = "<on|off>";
-    const int COMMANDLINE_ROOT_MAX_ARG = 1;
-    const int COMMANDLINE_ROOT_MIN_ARG = 1;
-
-    const char* COMMANDLINE_SWINDOW_NAME = "status-window";
-    const char* COMMANDLINE_SWINDOW_DESC[] = {
-            "continuously print device status for a specified device"
-    };
-    const int COMMANDLINE_SWINDOW_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_SWINDOW_DESC, char*);
-    const int COMMANDLINE_SWINDOW_MAX_ARG = 0;
-    const int COMMANDLINE_SWINDOW_MIN_ARG = 0;
-
-    const char* COMMANDLINE_SSERVER_NAME = "start-server";
-    const char* COMMANDLINE_SSERVER_DESC[] = {
-            "ensure that there is a server running"
-    };
-    const int COMMANDLINE_SSERVER_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_SSERVER_DESC, char*);
-    const int COMMANDLINE_SSERVER_MAX_ARG = 0;
-    const int COMMANDLINE_SSERVER_MIN_ARG = 0;
-
-    const char* COMMANDLINE_KSERVER_NAME = "kill-server";
-    const char* COMMANDLINE_KSERVER_DESC[] = {
-            "kill the server if it is running"
-    };
-    const int COMMANDLINE_KSERVER_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_KSERVER_DESC, char*);
-    const int COMMANDLINE_KSERVER_MAX_ARG = 0;
-    const int COMMANDLINE_KSERVER_MIN_ARG = 0;
-
-    const char* COMMANDLINE_HELP_NAME = "help";
-    const char* COMMANDLINE_HELP_DESC[] = {
-            "show this help message"
-    };
-    const int COMMANDLINE_HELP_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_HELP_DESC, char*);
-
-    const char* COMMANDLINE_VERSION_NAME = "version";
-    const char* COMMANDLINE_VERSION_DESC[] = {
-            "show version num"
-    };
-    const int COMMANDLINE_VERSION_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_VERSION_DESC, char*);
-    const int COMMANDLINE_VERSION_MAX_ARG = 0;
-    const int COMMANDLINE_VERSION_MIN_ARG = 0;
-
-    const char* COMMANDLINE_DLOG_NAME = "dlog";
-    const char* COMMANDLINE_DLOG_DESC[] = {
-            "view device log"
-    };
-    const int COMMANDLINE_DLOG_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DLOG_DESC, char*);
-    const char* COMMANDLINE_DLOG_ARG_DESC = "[<filter-spec>]";
-    const int COMMANDLINE_DLOG_MAX_ARG = -1;
-    const int COMMANDLINE_DLOG_MIN_ARG = 0;
-
-    const char* COMMANDLINE_FORWARD_NAME = "forward";
-    const char* COMMANDLINE_FORWARD_DESC[] = {
-            "forward socket connections",
-            "forward spec is : tcp:<port>"
-    };
-    const int COMMANDLINE_FORWARD_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_FORWARD_DESC, char*);
-    const char* COMMANDLINE_FORWARD_ARG_DESC = "<local> <remote>";
-    const int COMMANDLINE_FORWARD_MAX_ARG = 2;
-    const int COMMANDLINE_FORWARD_MIN_ARG = 2;
-
-    const char* COMMANDLINE_PUSH_NAME = "push";
-    const char* COMMANDLINE_PUSH_DESC[] = {
-            "copy file/dir to device",
-            "(--with-utf8 means to create the remote file with utf-8 character encoding)"
-    };
-    const int COMMANDLINE_PUSH_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_PUSH_DESC, char*);
-    const char* COMMANDLINE_PUSH_ARG_DESC = "<local> <remote> [--with-utf8]";
-    const int COMMANDLINE_PUSH_MAX_ARG = -1;
-    const int COMMANDLINE_PUSH_MIN_ARG = 2;
-
-    const char* COMMANDLINE_PULL_NAME = "pull";
-    const char* COMMANDLINE_PULL_DESC[] = {
-            "copy file/dir from device"
-    };
-    const int COMMANDLINE_PULL_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_PULL_DESC, char*);
-    const char* COMMANDLINE_PULL_ARG_DESC = "<remote> [<local>]";
-    const int COMMANDLINE_PULL_MAX_ARG = -2;
-    const int COMMANDLINE_PULL_MIN_ARG = 1;
-
-    const char* COMMANDLINE_SHELL_NAME = "shell";
-    const char* COMMANDLINE_SHELL_DESC[] = {
-            "run remote shell interactively"
-    };
-    const int COMMANDLINE_SHELL_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_SHELL_DESC, char*);
-    const char* COMMANDLINE_SHELL_ARG_DESC = "[command]";
-    const int COMMANDLINE_SHELL_MAX_ARG = -1;
-    const int COMMANDLINE_SHELL_MIN_ARG = 0;
-
-    const char* COMMANDLINE_INSTALL_NAME = "install";
-    const char* COMMANDLINE_INSTALL_DESC[] = {
-            "push package file and install it"
-    };
-    const int COMMANDLINE_INSTALL_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_INSTALL_DESC, char*);
-    const char* COMMANDLINE_INSTALL_ARG_DESC = "<pkg_path>";
-    const int COMMANDLINE_INSTALL_MAX_ARG = 1;
-    const int COMMANDLINE_INSTALL_MIN_ARG = 1;
-
-    const char* COMMANDLINE_UNINSTALL_NAME = "uninstall";
-    const char* COMMANDLINE_UNINSTALL_DESC[] = {
-            "uninstall an app from the device"
-    };
-    const int COMMANDLINE_UNINSTALL_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_UNINSTALL_DESC, char*);
-    const char* COMMANDLINE_UNINSTALL_ARG_DESC = "<app_id>";
-    const int COMMANDLINE_UNINSTALL_MAX_ARG = 1;
-    const int COMMANDLINE_UNINSTALL_MIN_ARG = 1;
-
-    const char* COMMANDLINE_FORKSERVER_NAME = "fork-server";
-    const int COMMANDLINE_FORKSERVER_MAX_ARG = 1;
-    const int COMMANDLINE_FORKSERVER_MIN_ARG = 1;
-
-    const char* COMMANDLINE_SERIAL_SHORT_OPT = "s";
-    const char* COMMANDLINE_SERIAL_LONG_OPT = "serial";
-    const char* COMMANDLINE_SERIAL_DESC[] = {
-            "direct command to the USB device or emulator with the given serial number."
-    };
-    const int COMMANDLINE_SERIAL_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_SERIAL_DESC, char*);
-    const char* COMMANDLINE_SERIAL_ARG_DESC = "<serial number>";
-    const int COMMANDLINE_SERIAL_HAS_ARG = 1;
-
-    const char* COMMANDLINE_DEVICE_SHORT_OPT = "d";
-    const char* COMMANDLINE_DEVICE_LONG_OPT = "device";
-    const char* COMMANDLINE_DEVICE_DESC[] = {
-            "direct command to the only connected USB device.",
-            "return an error if more than one USB device is present."
-    };
-    const int COMMANDLINE_DEVICE_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DEVICE_DESC, char*);
-    const int COMMANDLINE_DEVICE_HAS_ARG = 0;
-
-    const char* COMMANDLINE_EMULATOR_SHORT_OPT = "e";
-    const char* COMMANDLINE_EMULATOR_LONG_OPT = "emulator";
-    const char* COMMANDLINE_EMULATOR_DESC[] = {
-            "direct command to the only running emulator.",
-            "return an error if more than one emulator is running."
-    };
-    const int COMMANDLINE_EMULATOR_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_EMULATOR_DESC, char*);
-    const int COMMANDLINE_EMULATOR_HAS_ARG = 0;
-
-    const char* COMMANDLINE_ERROR_ARG_MISSING = "argument %s is missing for command %s";
diff --git a/src/sdb_constants.h b/src/sdb_constants.h
deleted file mode 100644 (file)
index 110a138..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
-* 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_CONSTANTS_H_
-#define SDB_CONSTANTS_H_
-
-#define GET_ARRAY_SIZE(parameter, type) sizeof(parameter)/sizeof(type)
-
-enum host_type {
-    host,
-    transport
-};
-
-typedef enum host_type HOST_TYPE;
-
-    const char* HELP_APPEND_STR;
-
-    const char* EMPTY_STRING;
-    const char* DIR_APP_TMP;
-    const char *DIR_APP;
-    const char* QUOTE_CHAR;
-
-    const char* PREFIX_HOST;
-    const char* PREFIX_HOST_USB;
-    const char* PREFIX_HOST_LOCAL;
-    const char* PREFIX_HOST_SERIAL;
-
-    const char* PREFIX_TRANSPORT_ANY;
-    const char* PREFIX_TRANSPORT_USB;
-    const char* PREFIX_TRANSPORT_LOCAL;
-    const char* PREFIX_TRANSPORT_SERIAL;
-
-    const char* COMMANDLINE_MSG_FULL_CMD;
-
-    const char* COMMANDLINE_OPROFILE_NAME;
-    const int COMMANDLINE_OPROFILE_MAX_ARG;
-    const int COMMANDLINE_OPROFILE_MIN_ARG;
-
-    const char* COMMANDLINE_DA_NAME;
-    const int COMMANDLINE_DA_MAX_ARG;
-    const int COMMANDLINE_DA_MIN_ARG;
-
-    const char* COMMANDLINE_LAUNCH_NAME;
-    const int COMMANDLINE_LAUNCH_MAX_ARG;
-    const int COMMANDLINE_LAUNCH_MIN_ARG;
-
-    const char* COMMANDLINE_DEVICES_NAME;
-    extern const char* COMMANDLINE_DEVICES_DESC[];
-    const int COMMANDLINE_DEVICES_DESC_SIZE;
-    const int COMMANDLINE_DEVICES_MAX_ARG;
-    const int COMMANDLINE_DEVICES_MIN_ARG;
-
-    const char* COMMANDLINE_DISCONNECT_NAME;
-    extern const char* COMMANDLINE_DISCONNECT_DESC[];
-    const int COMMANDLINE_DISCONNECT_DESC_SIZE;
-    const char* COMMANDLINE_DISCONNECT_ARG_DESC;
-    const int COMMANDLINE_DISCONNECT_MAX_ARG;
-    const int COMMANDLINE_DISCONNECT_MIN_ARG;
-
-    const char* COMMANDLINE_CONNECT_NAME;
-    extern const char* COMMANDLINE_CONNECT_DESC[];
-    const int COMMANDLINE_CONNECT_DESC_SIZE;
-    const char* COMMANDLINE_CONNECT_ARG_DESC;
-    const int COMMANDLINE_CONNECT_MAX_ARG;
-    const int COMMANDLINE_CONNECT_MIN_ARG;
-
-    const char* COMMANDLINE_GSERIAL_NAME;
-    extern const char* COMMANDLINE_GSERIAL_DESC[];
-    const int COMMANDLINE_GSERIAL_DESC_SIZE;
-    const int COMMANDLINE_GSERIAL_MAX_ARG;
-    const int COMMANDLINE_GSERIAL_MIN_ARG;
-
-    const char* COMMANDLINE_GSTATE_NAME;
-    extern const char* COMMANDLINE_GSTATE_DESC[];
-    const int COMMANDLINE_GSTATE_DESC_SIZE;
-    const int COMMANDLINE_GSTATE_MAX_ARG;
-    const int COMMANDLINE_GSTATE_MIN_ARG;
-
-    const char* COMMANDLINE_ROOT_NAME;
-    extern const char* COMMANDLINE_ROOT_DESC[];
-    const int COMMANDLINE_ROOT_DESC_SIZE;
-    const char* COMMANDLINE_ROOT_ARG_DESC;
-    const int COMMANDLINE_ROOT_MAX_ARG;
-    const int COMMANDLINE_ROOT_MIN_ARG;
-
-    const char* COMMANDLINE_SWINDOW_NAME;
-    extern const char* COMMANDLINE_SWINDOW_DESC[];
-    const int COMMANDLINE_SWINDOW_DESC_SIZE;
-    const int COMMANDLINE_SWINDOW_MAX_ARG;
-    const int COMMANDLINE_SWINDOW_MIN_ARG;
-
-    const char* COMMANDLINE_SSERVER_NAME;
-    extern const char* COMMANDLINE_SSERVER_DESC[];
-    const int COMMANDLINE_SSERVER_DESC_SIZE;
-    const int COMMANDLINE_SSERVER_MAX_ARG;
-    const int COMMANDLINE_SSERVER_MIN_ARG;
-
-    const char* COMMANDLINE_KSERVER_NAME;
-    extern const char* COMMANDLINE_KSERVER_DESC[];
-    const int COMMANDLINE_KSERVER_DESC_SIZE;
-    const int COMMANDLINE_KSERVER_MAX_ARG;
-    const int COMMANDLINE_KSERVER_MIN_ARG;
-
-    const char* COMMANDLINE_HELP_NAME;
-    extern const char* COMMANDLINE_HELP_DESC[];
-    const int COMMANDLINE_HELP_DESC_SIZE;
-
-    const char* COMMANDLINE_VERSION_NAME;
-    extern const char* COMMANDLINE_VERSION_DESC[];
-    const int COMMANDLINE_VERSION_DESC_SIZE;
-    const int COMMANDLINE_VERSION_MAX_ARG;
-    const int COMMANDLINE_VERSION_MIN_ARG;
-
-    const char* COMMANDLINE_FORWARD_NAME;
-    extern const char* COMMANDLINE_FORWARD_DESC[];
-    const int COMMANDLINE_FORWARD_DESC_SIZE;
-    const char* COMMANDLINE_FORWARD_ARG_DESC;
-    const int COMMANDLINE_FORWARD_MAX_ARG;
-    const int COMMANDLINE_FORWARD_MIN_ARG;
-
-    const char* COMMANDLINE_DLOG_NAME;
-    extern const char* COMMANDLINE_DLOG_DESC[];
-    const int COMMANDLINE_DLOG_DESC_SIZE;
-    const char* COMMANDLINE_DLOG_ARG_DESC;
-    const int COMMANDLINE_DLOG_MAX_ARG;
-    const int COMMANDLINE_DLOG_MIN_ARG;
-
-    const char* COMMANDLINE_PUSH_NAME;
-    extern const char* COMMANDLINE_PUSH_DESC[];
-    const int COMMANDLINE_PUSH_DESC_SIZE;
-    const char* COMMANDLINE_PUSH_ARG_DESC;
-    const int COMMANDLINE_PUSH_MAX_ARG;
-    const int COMMANDLINE_PUSH_MIN_ARG;
-
-    const char* COMMANDLINE_PULL_NAME;
-    extern const char* COMMANDLINE_PULL_DESC[];
-    const int COMMANDLINE_PULL_DESC_SIZE;
-    const char* COMMANDLINE_PULL_ARG_DESC;
-    const int COMMANDLINE_PULL_MAX_ARG;
-    const int COMMANDLINE_PULL_MIN_ARG;
-
-    const char* COMMANDLINE_SHELL_NAME;
-    extern const char* COMMANDLINE_SHELL_DESC[];
-    const int COMMANDLINE_SHELL_DESC_SIZE;
-    const char* COMMANDLINE_SHELL_ARG_DESC;
-    const int COMMANDLINE_SHELL_MAX_ARG;
-    const int COMMANDLINE_SHELL_MIN_ARG;
-
-    const char* COMMANDLINE_INSTALL_NAME;
-    extern const char* COMMANDLINE_INSTALL_DESC[];
-    const int COMMANDLINE_INSTALL_DESC_SIZE;
-    const char* COMMANDLINE_INSTALL_ARG_DESC;
-    const int COMMANDLINE_INSTALL_MAX_ARG;
-    const int COMMANDLINE_INSTALL_MIN_ARG;
-
-    const char* COMMANDLINE_UNINSTALL_NAME;
-    extern const char* COMMANDLINE_UNINSTALL_DESC[];
-    const int COMMANDLINE_UNINSTALL_DESC_SIZE;
-    const char* COMMANDLINE_UNINSTALL_ARG_DESC;
-    const int COMMANDLINE_UNINSTALL_MAX_ARG;
-    const int COMMANDLINE_UNINSTALL_MIN_ARG;
-
-    const char* COMMANDLINE_FORKSERVER_NAME;
-    const int COMMANDLINE_FORKSERVER_MAX_ARG;
-    const int COMMANDLINE_FORKSERVER_MIN_ARG;
-
-    const char* COMMANDLINE_SERIAL_SHORT_OPT;
-    const char* COMMANDLINE_SERIAL_LONG_OPT;
-    extern const char* COMMANDLINE_SERIAL_DESC[];
-    const int COMMANDLINE_SERIAL_DESC_SIZE;
-    const char* COMMANDLINE_SERIAL_ARG_DESC;
-    const int COMMANDLINE_SERIAL_HAS_ARG;
-
-    const char* COMMANDLINE_DEVICE_SHORT_OPT;
-    const char* COMMANDLINE_DEVICE_LONG_OPT;
-    extern const char* COMMANDLINE_DEVICE_DESC[];
-    const int COMMANDLINE_DEVICE_DESC_SIZE;
-    const int COMMANDLINE_DEVICE_HAS_ARG;
-
-    const char* COMMANDLINE_EMULATOR_SHORT_OPT;
-    const char* COMMANDLINE_EMULATOR_LONG_OPT;
-    extern const char* COMMANDLINE_EMULATOR_DESC[];
-    const int COMMANDLINE_EMULATOR_DESC_SIZE;
-    const int COMMANDLINE_EMULATOR_HAS_ARG;
-
-    const char* COMMANDLINE_ERROR_ARG_MISSING;
-
-#endif /* SDB_CONSTANTS_H_*/
diff --git a/src/sdb_model.c b/src/sdb_model.c
deleted file mode 100644 (file)
index 8b6162c..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
-* 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 <string.h>
-#include <stdio.h>
-#include "utils.h"
-#include "fdevent.h"
-#include "sdb_model.h"
-#include "linkedlist.h"
-#include "sdb.h"
-
-const COMMAND NULL_COMMAND = {
-        NULL,
-        0,
-        NULL,
-        NULL,
-        null_function,
-        -1,
-        0
-};
-
-//Create a command. A user should free cmdptr manually.
-void create_command(COMMAND** cmdptr, const char* name, const char** desc, int desc_size, const char* argdesc,
-        int (*Func)(int, char**, void**), int maxargs, int minargs) {
-    *cmdptr = (COMMAND*)malloc(sizeof(COMMAND));
-    (*cmdptr)->name = name;
-    (*cmdptr)->desc = desc;
-    (*cmdptr)->desc_size = desc_size;
-    (*cmdptr)->argdesc = argdesc;
-    (*cmdptr)->Func = Func;
-    (*cmdptr)->maxargs = maxargs;
-    (*cmdptr)->minargs = minargs;
-}
-
-//Create a command. A user should free optptr manually.
-void create_option(OPTION** optptr, const char* longopt, const char* shortopt, const char** desc,
-        int desc_size, const char* argdesc, int hasarg) {
-    *optptr = (OPTION*)malloc(sizeof(OPTION));
-    (*optptr)->longopt = longopt;
-    (*optptr)->shortopt = shortopt;
-    (*optptr)->desc = desc;
-    (*optptr)->desc_size = desc_size;
-    (*optptr)->argdesc = argdesc;
-    (*optptr)->hasarg = hasarg;
-}
-
-COMMAND* get_command(LIST_NODE* cmd_list, char* name) {
-
-    LIST_NODE* curptr = cmd_list;
-
-    while(curptr != NULL) {
-        COMMAND* curcmd = (COMMAND*)(curptr->data);
-
-        if(!strcmp(curcmd->name, name)) {
-            return curcmd;
-        }
-        curptr = curptr->next_ptr;
-    }
-    return (COMMAND*)&NULL_COMMAND;
-}
-
-OPTION* get_option(LIST_NODE* opt_list, char* name, int longname) {
-
-    LIST_NODE* curptr = opt_list;
-
-    while(curptr != NULL) {
-        OPTION* curopt = (OPTION*)(curptr->data);
-        if(longname) {
-            if(!strcmp(curopt->longopt, name)) {
-                return curopt;
-            }
-        }
-        else if(!strcmp(curopt->shortopt, name)) {
-            return curopt;
-        }
-        curptr = curptr->next_ptr;
-    }
-    return NULL;
-}
-
-INPUT_OPTION* get_inputopt(LIST_NODE* inputopt_list, char* shortname) {
-    LIST_NODE* curptr = inputopt_list;
-
-    while(curptr != NULL) {
-        INPUT_OPTION* cur_inputopt = (INPUT_OPTION*)(curptr->data);
-
-        if(!strcmp(cur_inputopt->option->shortopt, shortname)) {
-                return cur_inputopt;
-        }
-
-        curptr = curptr->next_ptr;
-    }
-
-    return NULL;
-}
-
-int parse_opt(int argc, char** argv, LIST_NODE* opt_list, LIST_NODE** result_list) {
-
-    D("Parsing options.\n");
-    int pass_arg = 0;
-    while(argc > 0) {
-        if(argv[0][0] == '-') {
-            int local_pass_arg = 1;
-            int longname = 0;
-            char* name = NULL;
-            //long name
-            if(strlen(argv[0]) > 1 && argv[0][1] == '-') {
-                    longname = 1;
-                    name = argv[0] + 2;
-            }
-            else {
-                name = argv[0] + 1;
-            }
-            D("Parse option: %s with longname %d\n", name, longname);
-            OPTION* option = get_option(opt_list, name, longname);
-            if(option == NULL) {
-                fprintf(stderr, "unrecognized option: %s\n", name);
-                return -1;
-            }
-
-            char* value = NULL;
-            if(option->hasarg) {
-                if(argc > 1 && argv[1][0] != '-') {
-                    value = argv[1];
-                    local_pass_arg++;
-                }
-                else {
-                    fprintf(stderr, "option: %s should have a argument\n", name);
-                    return -1;
-                }
-            }
-            D("Option %s with value %s", name, value);
-            INPUT_OPTION* input = (INPUT_OPTION*)malloc(sizeof(INPUT_OPTION));
-            input->option = option;
-            input->value = value;
-            append(result_list, input);
-
-            argv = argv + local_pass_arg;
-            argc = argc - local_pass_arg;
-            pass_arg = pass_arg + local_pass_arg;
-        }
-        else {
-            return pass_arg;
-        }
-    }
-    return pass_arg;
-}
-
-int null_function (int argc, char** argv, void** extraarg) {
-    fprintf(stderr, "unsupported command: %s\n", argv[0]);
-    return -1;
-}
diff --git a/src/sdb_model.h b/src/sdb_model.h
deleted file mode 100644 (file)
index 60c889a..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* 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_MODEL_H_
-#define SDB_MODEL_H_
-
-#include "linkedlist.h"
-#include "sdb_constants.h"
-
-#define TRACE_TAG TRACE_SDB
-
-struct command {
-    const char* name;
-    //hidden command does not have a description.
-    int desc_size;
-    const char** desc;
-    const char* argdesc;
-    int (*Func)(int, char**, void**);
-    // -1 means no max limit.
-    int maxargs;
-    int minargs;
-};
-typedef struct command COMMAND;
-
-struct option {
-    const char* longopt;
-    const char* shortopt;
-    //hidden option does not have a description.
-    const char** desc;
-    int desc_size;
-    const char* argdesc;
-    int hasarg;
-};
-typedef struct option OPTION;
-
-struct input_option {
-    char* value;
-    OPTION* option;
-};
-typedef struct input_option INPUT_OPTION;
-
-const COMMAND NULL_COMMAND;
-
-int null_function (int argc, char** argv, void** extraarg);
-void create_command(COMMAND** cmdptr, const char* name, const char** desc, int desc_size, const char* argdesc,
-        int (*Func)(int, char**, void**), int maxargs, int minargs);
-
-void create_option(OPTION** optptr, const char* longopt, const char* shortopt, const char** desc, int desc_size, const char* argdesc, int hasarg);
-COMMAND* get_command(LIST_NODE* cmd_list, char* name);
-OPTION* get_option(LIST_NODE* opt_list, char* name, int longname);
-INPUT_OPTION* get_inputopt(LIST_NODE* inputopt_list, char* shortname);
-int parse_opt(int argc, char** argv, LIST_NODE* opt_list, LIST_NODE** result_list);
-
-#endif /* SDB_MODEL_H_ */
diff --git a/src/sdb_usb.c b/src/sdb_usb.c
deleted file mode 100755 (executable)
index 0d63c9f..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * 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 <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include "utils.h"
-#include "fdevent.h"
-#include "libusb/usb.h"
-
-#define   TRACE_TAG  TRACE_USB
-#include "sdb.h"
-#include "strutils.h"
-#include "sdb_usb.h"
-
-SDB_MUTEX_DEFINE( usb_lock );
-
-struct usb_handle
-{
-    usb_handle *prev;
-    usb_handle *next;
-
-    usb_dev_handle *usb_handle;
-    char unique_node_path[PATH_MAX+1];
-    unsigned char end_point[2]; // 0:in, 1:out
-    int interface;
-    unsigned zero_mask;
-
-};
-
-static usb_handle handle_list = {
-    .prev = &handle_list,
-    .next = &handle_list,
-};
-
-int is_device_registered(const char *unique_node_path)
-{
-    usb_handle *usb;
-    int r = 0;
-    sdb_mutex_lock(&usb_lock);
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
-        if(!strcmp(usb->unique_node_path, unique_node_path)) {
-            // set mark flag to indicate this device is still alive
-            usb->zero_mask = 1;
-            r = 1;
-            break;
-        }
-    }
-    sdb_mutex_unlock(&usb_lock);
-    return r;
-}
-
-void register_device(struct usb_device *dev)
-{
-    usb_dev_handle *udev;
-    int ret, i;
-
-    char usb_path[PATH_MAX+1];
-
-    snprintf(usb_path, sizeof(usb_path), "/dev/bus/usb/%s/%s", dev->bus->dirname, dev->filename);
-
-    if (is_device_registered(usb_path)) {
-        //D("skip to register device: %s\n", usb_path);
-        return;
-    }
-
-    if (!dev->config) {
-        D("couldn't retrieve descriptors\n");
-        return;
-    }
-
-    struct usb_interface_descriptor *altsetting = NULL;
-    ret = 0;
-    for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-        struct usb_config_descriptor *config = &dev->config[i];
-        int interface_index = 0;
-        for (interface_index = 0; interface_index < config->bNumInterfaces; interface_index++) {
-            struct usb_interface *interface = &config->interface[interface_index];
-            int altsetting_index = 0;
-            for (altsetting_index = 0; altsetting_index < interface->num_altsetting; altsetting_index++) {
-                altsetting = &interface->altsetting[altsetting_index];
-
-                if (is_sdb_interface(altsetting->bInterfaceClass, altsetting->bInterfaceSubClass, altsetting->bInterfaceProtocol)) {
-                    ret = 1;
-                    break;
-                }
-
-            }
-        }
-    }
-    if (ret == 0) {
-        //D("fail to get sdb interface descriptor\n");
-        return;
-    }
-    if (altsetting->bNumEndpoints !=2) {
-        D("the number of endpoint should be two\n");
-        return;
-    }
-
-    usb_handle* usb = NULL;
-    usb = calloc(1, sizeof(usb_handle));
-
-    if (usb == NULL) {
-        return;
-    }
-
-    int sdb_configuration = 2;
-    const struct usb_endpoint_descriptor *ep1 = &altsetting->endpoint[0];
-    const struct usb_endpoint_descriptor *ep2 = &altsetting->endpoint[1];
-
-    usb->interface = altsetting->bInterfaceNumber;
-    // find out which  endpoint is in or out
-    if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
-
-        usb->end_point[0] = ep1->bEndpointAddress;
-        usb->end_point[1] = ep2->bEndpointAddress;
-    } else {
-        usb->end_point[0] = ep2->bEndpointAddress;
-        usb->end_point[1] = ep1->bEndpointAddress;
-    }
-
-    if (altsetting->bInterfaceProtocol == 0x01) {
-        usb->zero_mask = ep1->wMaxPacketSize - 1;
-    }
-
-    udev = usb_open(dev);
-    if (udev == NULL) {
-        D("unable to open %s\n", usb_path);
-        free(usb);
-        return;
-    }
-    usb->usb_handle = udev;
-    char serial[256];
-
-    if (dev->descriptor.iSerialNumber) {
-        ret = usb_get_string_simple(udev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
-        if (ret < 1) {
-            D("error to get serial name: %d(%s)\n", ret, strerror(errno));
-            strcpy(serial, "unknown");
-        }
-    }
-
-    s_strncpy(usb->unique_node_path, usb_path, sizeof(usb->unique_node_path));
-
-    /*
-    // detach any kernel driver
-    if ((ret = libusb_kernel_driver_active(dev_handle, 0))) {
-        if ((ret = libusb_detach_kernel_driver(dev_handle, 0))) {
-            D ("detach!\n");
-        }
-    }*/
-
-    ret = usb_reset(udev);
-    ret = usb_set_configuration(udev, sdb_configuration);
-    // claim the device
-    ret = usb_claim_interface(udev, usb->interface);
-    D("claim %d: %d(%s)\n", ret, errno, strerror(errno));
-
-    sdb_mutex_lock(&usb_lock);
-    usb->next = &handle_list;
-    usb->prev = handle_list.prev;
-    usb->prev->next = usb;
-    usb->next->prev = usb;
-
-    D("-register new device (in: %04x, out: %04x) from %s\n",usb->end_point[0], usb->end_point[1], usb_path);
-
-    register_usb_transport(usb, serial, 1);
-    sdb_mutex_unlock(&usb_lock);
-}
-
-
-void do_lsusb()
-{
-    struct usb_bus *bus;
-
-    usb_init();
-
-    usb_find_busses();
-    usb_find_devices();
-
-    for (bus = usb_busses; bus; bus = bus->next) {
-        struct usb_device *dev;
-
-        for (dev = bus->devices; dev; dev = dev->next) {
-            register_device(dev);
-        }
-
-    }
-    //D("finished loop\n");
-}
-
-
-void* usb_poll_thread(void* sleep_msec)
-{
-    D("created usb detecting thread\n");
-    int  mseconds = (int) sleep_msec;
-
-    while (1) {
-        do_lsusb();
-        //kick_disconnected_devices();
-        sdb_sleep_ms(mseconds);
-    }
-    return NULL;
-}
-
-
-void sdb_usb_init(void)
-{
-    sdb_thread_t tid;
-
-    if(sdb_thread_create(&tid, usb_poll_thread, (void*)1000)){
-        fatal_errno("cannot create input thread");
-    }
-}
-
-void sdb_usb_cleanup()
-{
-    close_usb_devices();
-}
-
-int sdb_usb_write(usb_handle *h, const void *_data, int len)
-{
-    char *data = (char*) _data;
-    int n = 0;
-    int need_zero = 0;
-
-    D("+sdb_usb_write\n");
-
-    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;
-        }
-    }
-
-    while(len > 0) {
-        int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
-
-        n = usb_bulk_write(h->usb_handle,  h->end_point[1], data, xfer, 0);
-        if(n != xfer) {
-            D("fail to usb write: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
-            return -1;
-        }
-
-        len -= xfer;
-        data += xfer;
-    }
-
-    if(need_zero){
-        n = usb_bulk_write(h->usb_handle,  h->end_point[1], (char *)_data, 0, 0);
-        if (n < 0) {
-            D("fail to to usb write for 0 len from %p\n", h->usb_handle);
-        }
-        return n;
-    }
-    D("-usb_write\n");
-    return 0;
-}
-
-int sdb_usb_read(usb_handle *h, void *_data, int len)
-{
-    char *data = (char*) _data;
-    int n;
-
-    D("+sdb_usb_read\n");
-    while(len > 0) {
-        int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
-
-        n = usb_bulk_read(h->usb_handle, h->end_point[0], data, xfer, 0);
-
-        if(n != xfer) {
-            if((errno == ETIMEDOUT)) {
-                D("usb bulk read timeout\n");
-                if(n > 0){
-                    data += n;
-                    len -= n;
-                }
-                continue;
-            }
-            D("fail to usb read: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
-            return -1;
-        }
-
-        len -= xfer;
-        data += xfer;
-    }
-
-    D("-sdb_usb_read\n");
-    return 0;
-}
-
-void sdb_usb_kick(usb_handle *h)
-{
-    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;
-
-    usb_release_interface(h->usb_handle, h->interface);
-    usb_close(h->usb_handle);
-    sdb_mutex_unlock(&usb_lock);
-
-    if (h != NULL) {
-        free(h);
-        h = NULL;
-    }
-    D("-usb close\n");
-    return 0;
-}
-
-int is_sdb_interface(int usb_class, int usb_subclass, int usb_protocol)
-{
-    if (usb_class == SDB_INTERFACE_CLASS && usb_subclass == SDB_INTERFACE_SUBCLASS
-            && usb_protocol == SDB_INTERFACE_PROTOCOL) {
-        return 1;
-    }
-
-    return 0;
-}
-
-#ifdef _USE_UDEV_
-
-#include <libudev.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <locale.h>
-#include <unistd.h>
-
-int udev_notify(void)
-{
-    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) {
-        printf("Can't create udev\n");
-        exit(1);
-    }
-
-    /* This section sets up a monitor which will report events when
-       devices attached to the system change.  Events include "add",
-       "remove", "change", "online", and "offline".
-
-       This section sets up and starts the monitoring. Events are
-       polled for (and delivered) later in the file.
-
-       It is important that the monitor be set up before the call to
-       udev_enumerate_scan_devices() so that events (and devices) are
-       not missed.  For example, if enumeration happened first, there
-       would be no event generated for a device which was attached after
-       enumeration but before monitoring began.
-
-       Note that a filter is added so that we only get events for
-       "hidraw" devices. */
-
-    /* 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);
-    /* Get the file descriptor (fd) for the monitor.
-       This fd will get passed to select() */
-    fd = udev_monitor_get_fd(mon);
-
-
-    /* Create a list of the devices in the 'hidraw' subsystem. */
-    enumerate = udev_enumerate_new(udev);
-    udev_enumerate_add_match_subsystem(enumerate, "usb");
-    udev_enumerate_scan_devices(enumerate);
-
-
-    devices = udev_enumerate_get_list_entry(enumerate);
-    /* For each item enumerated, print out its information.
-       udev_list_entry_foreach is a macro which expands to
-       a loop. The loop will be executed for each member in
-       devices, setting dev_list_entry to a list entry
-       which contains the device's path in /sys. */
-    udev_list_entry_foreach(dev_list_entry, devices) {
-        const char *path;
-
-        /* Get the filename of the /sys entry for the device
-           and create a udev_device object (dev) representing it */
-        path = udev_list_entry_get_name(dev_list_entry);
-        dev = udev_device_new_from_syspath(udev, path);
-
-        /* usb_device_get_devnode() returns the path to the device node
-           itself in /dev. */
-        printf("Device Node Path: %s\n", udev_device_get_devnode(dev));
-
-        /* The device pointed to by dev contains information about
-           the hidraw device. In order to get information about the
-           USB device, get the parent device with the
-           subsystem/devtype pair of "usb"/"usb_device". This will
-           be several levels up the tree, but the function will find
-           it.*/
-        /*dev = udev_device_get_parent_with_subsystem_devtype(
-               dev,
-               "usb",
-               "usb_device");
-        if (!dev) {
-            printf("Unable to find parent usb device.");
-            exit(1);
-        }*/
-
-        /* From here, we can call get_sysattr_value() for each file
-           in the device's /sys entry. The strings passed into these
-           functions (idProduct, idVendor, serial, etc.) correspond
-           directly to the files in the /sys directory which
-           represents the USB device. Note that USB strings are
-           Unicode, UCS2 encoded, but the strings returned from
-           udev_device_get_sysattr_value() are UTF-8 encoded. */
-        printf("  VID/PID: %s %s\n",
-                udev_device_get_sysattr_value(dev,"idVendor"),
-                udev_device_get_sysattr_value(dev, "idProduct"));
-        printf("  %s\n  %s\n",
-                udev_device_get_sysattr_value(dev,"manufacturer"),
-                udev_device_get_sysattr_value(dev,"product"));
-        printf("  serial: %s\n",
-                 udev_device_get_sysattr_value(dev, "serial"));
-        udev_device_unref(dev);
-    }
-    /* Free the enumerator object */
-    udev_enumerate_unref(enumerate);
-
-    /* Begin polling for udev events. Events occur when devices
-       attached to the system are added, removed, or change state.
-       udev_monitor_receive_device() will return a device
-       object representing the device which changed and what type of
-       change occured.
-
-       The select() system call is used to ensure that the call to
-       udev_monitor_receive_device() will not block.
-
-       The monitor was set up earler in this file, and monitoring is
-       already underway.
-
-       This section will run continuously, calling usleep() at the end
-       of each pass. This is to demonstrate how to use a udev_monitor
-       in a non-blocking way. */
-    while (1) {
-        /* Set up the call to select(). In this case, select() will
-           only operate on a single file descriptor, the one
-           associated with our udev_monitor. Note that the timeval
-           object is set to 0, which will cause select() to not
-           block. */
-        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);
-
-        /* Check if our file descriptor has received data. */
-        if (ret > 0 && FD_ISSET(fd, &fds)) {
-            printf("\nselect() says there should be data\n");
-
-            /* Make the call to receive the device.
-               select() ensured that this will not block. */
-            dev = udev_monitor_receive_device(mon);
-            if (dev) {
-                printf("Got Device\n");
-                printf("   Node: %s\n", udev_device_get_devnode(dev));
-                printf("   Subsystem: %s\n", udev_device_get_subsystem(dev));
-                printf("   Devtype: %s\n", udev_device_get_devtype(dev));
-
-                printf("   Action: %s\n", udev_device_get_action(dev));
-                udev_device_unref(dev);
-            }
-            else {
-                printf("No Device from receive_device(). An error occured.\n");
-            }
-        }
-        usleep(250*1000);
-        printf(".");
-        fflush(stdout);
-    }
-
-
-    udev_unref(udev);
-
-    return 0;
-}
-
-#endif
diff --git a/src/sdb_usb.h b/src/sdb_usb.h
deleted file mode 100755 (executable)
index 045926d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-
-#ifndef __USB_H
-#define __USB_H
-
-
-#include <limits.h>
-
-// should bo implements for each os type
-typedef struct usb_handle usb_handle;
-typedef struct sdb_usb_dev_handle sdb_usb_dev_handle;
-
-void    do_lsusb(void);
-
-void    sdb_usb_init();
-void    sdb_usb_cleanup();
-int     sdb_usb_write(usb_handle *h, const void *data, int len);
-int     sdb_usb_read(usb_handle *h, void *data, int len);
-int     sdb_usb_close(usb_handle *h);
-void    sdb_usb_kick(usb_handle *h);
-
-int     is_sdb_interface(int usb_class, int usb_subclass, int usb_protocol);
-int     is_device_registered(const char *node_path);
-void*   usb_poll_thread(void* sleep_msec);
-void    kick_disconnected_devices();
-
-#define SDB_INTERFACE_CLASS              0xff
-#define SDB_INTERFACE_SUBCLASS           0x20
-#define SDB_INTERFACE_PROTOCOL           0x02
-
-/*
- * 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)
-
-#endif  // __USB_H
diff --git a/src/sdbwinapi/BUILDME.TXT b/src/sdbwinapi/BUILDME.TXT
new file mode 100644 (file)
index 0000000..a8a2ca2
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (C) 2006 The Android Open Source Project\r
+\r
+Licensed under the Apache License, Version 2.0 (the "License");\r
+you may not use this file except in compliance with the License.\r
+You may obtain a copy of the License at\r
+\r
+  http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+Unless required by applicable law or agreed to in writing, software\r
+distributed under the License is distributed on an "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+See the License for the specific language governing permissions and\r
+limitations under the License.\r
+\r
+In order to build SdbWinApi.dll you will need to install Windows Driver Kit,\r
+which can be obtained from Microsoft. Assuming that WDK is installed, you\r
+need to set one of the WDK's build environments, "cd" back into this directory,\r
+and execute "build -cbeEIFZ" to clean and rebuild this project, or you can\r
+execute "build -befEIF" to do a minimal build.\r
diff --git a/src/sdbwinapi/MAKEFILE b/src/sdbwinapi/MAKEFILE
new file mode 100644 (file)
index 0000000..c38c73f
--- /dev/null
@@ -0,0 +1,22 @@
+#\r
+#  Copyright (C) 2006 The Android Open Source Project\r
+# \r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+# \r
+#       http://www.apache.org/licenses/LICENSE-2.0\r
+# \r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+#\r
+\r
+#\r
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source\r
+# file to this component.  This file merely indirects to the real make file\r
+# that is shared by all the components of NT OS/2\r
+#\r
+!INCLUDE $(NTMAKEENV)\makefile.def\r
diff --git a/src/sdbwinapi/MAKEFILE.org b/src/sdbwinapi/MAKEFILE.org
new file mode 100644 (file)
index 0000000..c38c73f
--- /dev/null
@@ -0,0 +1,22 @@
+#\r
+#  Copyright (C) 2006 The Android Open Source Project\r
+# \r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+# \r
+#       http://www.apache.org/licenses/LICENSE-2.0\r
+# \r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+#\r
+\r
+#\r
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source\r
+# file to this component.  This file merely indirects to the real make file\r
+# that is shared by all the components of NT OS/2\r
+#\r
+!INCLUDE $(NTMAKEENV)\makefile.def\r
diff --git a/src/sdbwinapi/Resource.h b/src/sdbwinapi/Resource.h
new file mode 100644 (file)
index 0000000..4a394fd
--- /dev/null
@@ -0,0 +1,34 @@
+/*\r
+ * Copyright (C) 2008 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by SdbWinApi.rc\r
+//\r
+\r
+#define IDS_PROJNAME                    100\r
+#define IDR_SDBWINAPI  101\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        201\r
+#define _APS_NEXT_COMMAND_VALUE         32768\r
+#define _APS_NEXT_CONTROL_VALUE         201\r
+#define _APS_NEXT_SYMED_VALUE           102\r
+#endif\r
+#endif\r
diff --git a/src/sdbwinapi/SOURCES b/src/sdbwinapi/SOURCES
new file mode 100644 (file)
index 0000000..6b3e319
--- /dev/null
@@ -0,0 +1,96 @@
+#\r
+#  Copyright (C) 2006 The Android Open Source Project\r
+# \r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+# \r
+#       http://www.apache.org/licenses/LICENSE-2.0\r
+# \r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+#\r
+\r
+TARGETNAME = SdbWinApi\r
+TARGETPATH = obj\r
+TARGETTYPE = DYNLINK\r
+\r
+UMTYPE = windows\r
+DLLDEF = SdbWinApi.def\r
+\r
+# Use statically linked atl libraries:\r
+# - atls.lib for free build\r
+# - atlsd.lib for checked build\r
+USE_STATIC_ATL  = 1\r
+# Use ATL v. 7.1\r
+ATL_VER         = 71\r
+# Use STL v. 6.0\r
+USE_STL         = 1\r
+STL_VER         = 60\r
+# Use multithreaded libraries\r
+USE_LIBCMT      = 1\r
+\r
+# Include directories\r
+INCLUDES = $(DDK_INC_PATH);           \\r
+           $(SDK_INC_PATH);           \\r
+           $(CRT_INC_PATH);           \\r
+           $(SDK_INC_PATH)\crt;       \\r
+           $(CRT_INC_PATH)\atl71;     \\r
+           $(SDK_INC_PATH)\crt\stl60\r
+\r
+# Common target libraries\r
+TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib    \\r
+             $(SDK_LIB_PATH)\Advapi32.lib \\r
+             $(SDK_LIB_PATH)\Kernel32.lib \\r
+             $(SDK_LIB_PATH)\User32.lib   \\r
+             $(SDK_LIB_PATH)\oleaut32.lib \\r
+             $(SDK_LIB_PATH)\wbemuuid.lib \\r
+             $(SDK_LIB_PATH)\uuid.lib     \\r
+             $(SDK_LIB_PATH)\setupapi.lib \\r
+             $(SDK_LIB_PATH)\usbd.lib\r
+           \r
+!IF "$(DDKBUILDENV)" == "fre"\r
+# Libraries for release (free) builds\r
+TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib\r
+!ELSE\r
+# Libraries for debug (checked) builds\r
+TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib\r
+!ENDIF\r
+           \r
+# Common C defines           \r
+C_DEFINES= $(C_DEFINES) -DSDBWIN_EXPORTS -D_UNICODE \\r
+           -DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL\r
+\r
+!IF "$(DDKBUILDENV)" == "fre"\r
+# C defines for release (free) builds\r
+C_DEFINES = $(C_DEFINES) -DNDEBUG\r
+!ELSE\r
+# C defines for debug (checked) builds\r
+C_DEFINES = $(C_DEFINES) -D_DEBUG\r
+!ENDIF\r
+\r
+# Turn on all warnings, and treat warnings as errors\r
+MSC_WARNING_LEVEL = /W4 /Wp64 /WX\r
+# Common C defines           \r
+USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo\r
+# Set precompiled header information\r
+PRECOMPILED_CXX = 1\r
+PRECOMPILED_INCLUDE = stdafx.h\r
+PRECOMPILED_SOURCEFILE = stdafx.cpp\r
+\r
+# Define source files for SdbWinApi.dll\r
+SOURCES = sdb_api.cpp                     \\r
+          sdb_endpoint_object.cpp         \\r
+          sdb_legacy_endpoint_object.cpp  \\r
+          sdb_helper_routines.cpp         \\r
+          sdb_interface.cpp               \\r
+          sdb_legacy_interface.cpp        \\r
+          sdb_interface_enum.cpp          \\r
+          sdb_io_completion.cpp           \\r
+          sdb_legacy_io_completion.cpp    \\r
+          sdb_object_handle.cpp           \\r
+          SdbWinApi.cpp                   \\r
+                     SdbWinApi.rc\r
diff --git a/src/sdbwinapi/SdbWinApi.cpp b/src/sdbwinapi/SdbWinApi.cpp
new file mode 100644 (file)
index 0000000..6892496
--- /dev/null
@@ -0,0 +1,112 @@
+/*\r
+ * Copyright (C) 2008 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+// SdbWinApi.cpp : Implementation of DLL Exports.\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api.h"\r
+#include "sdb_winusb_api.h"\r
+\r
+extern "C" {\r
+int _forceCRTManifest;\r
+int _forceMFCManifest;\r
+int _forceAtlDllManifest;\r
+};\r
+\r
+/// References InstantiateWinUsbInterface declared in sdb_api.cpp\r
+extern PFN_INSTSDBWINUSBINTERFACE InstantiateSdbWinUsbInterface;\r
+\r
+class CSdbWinApiModule : public CAtlDllModuleT< CSdbWinApiModule > {\r
+ public:\r
+  CSdbWinApiModule()\r
+      : CAtlDllModuleT< CSdbWinApiModule >(),\r
+        sdbwinusbapi_handle_(NULL),\r
+        is_initialized_(false) {\r
+  }\r
+\r
+  ~CSdbWinApiModule() {\r
+    // Unload SdbWinUsbApi.dll before we exit\r
+    if (NULL != sdbwinusbapi_handle_) {\r
+      FreeLibrary(sdbwinusbapi_handle_);\r
+    }\r
+  }\r
+\r
+  /** \brief Loads SdbWinUsbApi.dll and caches its InstantiateWinUsbInterface\r
+    export.\r
+\r
+    This method is called from DllMain on DLL_PROCESS_ATTACH event. In this\r
+    method we will check if WINUSB.DLL required by SdbWinUsbApi.dll is\r
+    installed, and if it is we will load SdbWinUsbApi.dll and cache address of\r
+    InstantiateWinUsbInterface routine exported from SdbWinUsbApi.dll\r
+  */\r
+  void AttachToSdbWinUsbApi() {\r
+    // We only need to run this only once.\r
+    if (is_initialized_) {\r
+      return;\r
+    }\r
+\r
+    // Just mark that we have ran initialization.\r
+    is_initialized_ = true;\r
+\r
+    // Before we can load SdbWinUsbApi.dll we must make sure that WINUSB.DLL\r
+    // has been installed. Build path to the file.\r
+    wchar_t path_to_winusb_dll[MAX_PATH+1];\r
+    if (!GetSystemDirectory(path_to_winusb_dll, MAX_PATH)) {\r
+      return;\r
+    }\r
+    wcscat(path_to_winusb_dll, L"\\WINUSB.DLL");\r
+\r
+    if (0xFFFFFFFF == GetFileAttributes(path_to_winusb_dll)) {\r
+      // WINUSB.DLL is not installed. We don't (in fact, can't) load\r
+      // SdbWinUsbApi.dll\r
+      return;\r
+    }\r
+\r
+    // WINUSB.DLL is installed. Lets load SdbWinUsbApi.dll and cache its\r
+    // InstantiateWinUsbInterface export.\r
+    // We require that SdbWinUsbApi.dll is located in the same folder\r
+    // where SdbWinApi.dll and sdb.exe are located, so by Windows\r
+    // conventions we can pass just module name, and not the full path.\r
+    sdbwinusbapi_handle_ = LoadLibrary(L"SdbWinUsbApi.dll");\r
+    if (NULL != sdbwinusbapi_handle_) {\r
+      InstantiateSdbWinUsbInterface = reinterpret_cast<PFN_INSTSDBWINUSBINTERFACE>\r
+          (GetProcAddress(sdbwinusbapi_handle_, "InstantiateSdbWinUsbInterface"));\r
+    }\r
+  }\r
+\r
+ protected:\r
+  /// Handle to the loaded SdbWinUsbApi.dll\r
+  HINSTANCE sdbwinusbapi_handle_;\r
+\r
+  /// Flags whether or not this module has been initialized.\r
+  bool      is_initialized_;\r
+};\r
+\r
+CSdbWinApiModule _AtlModule;\r
+\r
+// DLL Entry Point\r
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance,\r
+                               DWORD reason,\r
+                               LPVOID reserved) {\r
+  // Lets see if we need to initialize InstantiateWinUsbInterface\r
+  // variable. We do that only once, on condition that this DLL is\r
+  // being attached to the process and InstantiateWinUsbInterface\r
+  // address has not been calculated yet.\r
+  if (DLL_PROCESS_ATTACH == reason) {\r
+    _AtlModule.AttachToSdbWinUsbApi();\r
+  }\r
+  return _AtlModule.DllMain(reason, reserved);\r
+}\r
diff --git a/src/sdbwinapi/SdbWinApi.def b/src/sdbwinapi/SdbWinApi.def
new file mode 100644 (file)
index 0000000..e2dbec2
--- /dev/null
@@ -0,0 +1,18 @@
+; SdbWinApi.def : Declares the module parameters.\r
+\r
+LIBRARY      "SdbWinApi.DLL"\r
+\r
+EXPORTS\r
+SdbEnumInterfaces\r
+SdbNextInterface\r
+SdbCreateInterfaceByName\r
+SdbOpenDefaultBulkReadEndpoint\r
+SdbOpenDefaultBulkWriteEndpoint\r
+SdbCloseHandle\r
+SdbGetInterfaceName\r
+SdbWriteEndpointSync\r
+SdbReadEndpointSync\r
+SdbGetSerialNumber\r
+SdbGetUsbInterfaceDescriptor\r
+SdbGetUsbDeviceDescriptor\r
+SdbGetEndpointInformation\r
diff --git a/src/sdbwinapi/SdbWinApi.rc b/src/sdbwinapi/SdbWinApi.rc
new file mode 100644 (file)
index 0000000..c5b19a4
--- /dev/null
@@ -0,0 +1,111 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+//Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "winres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE  \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE  \r
+BEGIN\r
+    "#include ""winres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#ifndef _MAC\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION 2,0,0,0\r
+ PRODUCTVERSION 2,0,0,0\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904e4"\r
+        BEGIN\r
+            VALUE "CompanyName", "Google, inc"\r
+            VALUE "FileDescription", "Android SDB API"\r
+            VALUE "FileVersion", "2.0.0.0"\r
+            VALUE "LegalCopyright", "Copyright (C) 2006 The Android Open Source Project"\r
+            VALUE "InternalName", "SdbWinApi.dll"\r
+            VALUE "OriginalFilename", "SdbWinApi.dll"\r
+            VALUE "ProductName", "Android SDK"\r
+            VALUE "ProductVersion", "2.0.0.0"\r
+            VALUE "OLESelfRegister", ""\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+               VALUE "Translation", 0x0409, 1252\r
+    END\r
+END\r
+\r
+#endif    // !_MAC\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE  \r
+BEGIN\r
+       IDS_PROJNAME                                    "SdbWinApi"\r
+END\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+#endif\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+#endif    // not APSTUDIO_INVOKED\r
diff --git a/src/sdbwinapi/sdb_api.cpp b/src/sdbwinapi/sdb_api.cpp
new file mode 100644 (file)
index 0000000..f2c80c5
--- /dev/null
@@ -0,0 +1,537 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of rotines that are exported\r
+  from this DLL.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api.h"\r
+#include "sdb_object_handle.h"\r
+#include "sdb_interface_enum.h"\r
+#include "sdb_interface.h"\r
+#include "sdb_legacy_interface.h"\r
+#include "sdb_endpoint_object.h"\r
+#include "sdb_io_completion.h"\r
+#include "sdb_helper_routines.h"\r
+#include "sdb_winusb_api.h"\r
+\r
+/** \brief Points to InstantiateWinUsbInterface exported from SdbWinUsbApi.dll.\r
+\r
+  This variable is initialized with the actual address in DllMain routine for\r
+  this DLL on DLL_PROCESS_ATTACH event.\r
+  @see PFN_INSTWINUSBINTERFACE for more information.\r
+*/\r
+PFN_INSTSDBWINUSBINTERFACE InstantiateSdbWinUsbInterface = NULL;\r
+\r
+SDBAPIHANDLE __cdecl SdbEnumInterfaces(GUID class_id,\r
+                               bool exclude_not_present,\r
+                               bool exclude_removed,\r
+                               bool active_only) {\r
+  SdbInterfaceEnumObject* enum_obj = NULL;\r
+  SDBAPIHANDLE ret = NULL;\r
+\r
+  try {\r
+    // Instantiate and initialize enum object\r
+    enum_obj = new SdbInterfaceEnumObject();\r
+\r
+    if (enum_obj->InitializeEnum(class_id,\r
+                                 exclude_not_present,\r
+                                 exclude_removed,\r
+                                 active_only)) {\r
+      // After successful initialization we can create handle.\r
+      ret = enum_obj->CreateHandle();\r
+    }\r
+  } catch (...) {\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+  }\r
+\r
+  if (NULL != enum_obj)\r
+    enum_obj->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool __cdecl SdbNextInterface(SDBAPIHANDLE sdb_handle,\r
+                      SdbInterfaceInfo* info,\r
+                      unsigned long* size) {\r
+  if (NULL == size) {\r
+    SetLastError(ERROR_INVALID_PARAMETER);\r
+    return false;\r
+  }\r
+\r
+  // Lookup SdbInterfaceEnumObject object for the handle\r
+  SdbInterfaceEnumObject* sdb_ienum_object =\r
+    LookupObject<SdbInterfaceEnumObject>(sdb_handle);\r
+  if (NULL == sdb_ienum_object)\r
+    return false;\r
+\r
+  // Everything is verified. Pass it down to the object\r
+  bool ret = sdb_ienum_object->Next(info, size);\r
+\r
+  sdb_ienum_object->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool __cdecl SdbResetInterfaceEnum(SDBAPIHANDLE sdb_handle) {\r
+  // Lookup SdbInterfaceEnumObject object for the handle\r
+  SdbInterfaceEnumObject* sdb_ienum_object =\r
+    LookupObject<SdbInterfaceEnumObject>(sdb_handle);\r
+  if (NULL == sdb_ienum_object)\r
+    return false;\r
+\r
+  // Everything is verified. Pass it down to the object\r
+  bool ret = sdb_ienum_object->Reset();\r
+\r
+  sdb_ienum_object->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbCreateInterfaceByName(\r
+    const wchar_t* interface_name) {\r
+  SdbInterfaceObject* obj = NULL;\r
+  SDBAPIHANDLE ret = NULL;\r
+\r
+  try {\r
+    // Instantiate interface object, depending on the USB driver type.\r
+    if (IsLegacyInterface(interface_name)) {\r
+      // We have legacy USB driver underneath us.\r
+      obj = new SdbLegacyInterfaceObject(interface_name);\r
+    } else {\r
+    printf("IsLegacyInterface failed\n");\r
+      // We have WinUsb driver underneath us. Make sure that SdbWinUsbApi.dll\r
+      // is loaded and its InstantiateWinUsbInterface routine address has\r
+      // been cached.\r
+      if (NULL != InstantiateSdbWinUsbInterface) {\r
+               printf("NULL != InstantiateSdbWinUsbInterface\n");\r
+        obj = InstantiateSdbWinUsbInterface(interface_name);\r
+        if (NULL == obj) {\r
+               printf("NULL == obj\n");\r
+          return NULL;\r
+        }\r
+      } else {\r
+      printf("NULL != InstantiateWinUsbInterface\n");\r
+        return NULL;\r
+      }\r
+    }\r
+\r
+    // Create handle for it\r
+    ret = obj->CreateHandle();\r
+  } catch (...) {\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+  }\r
+\r
+  if (NULL != obj)\r
+    obj->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbCreateInterface(GUID class_id,\r
+                                unsigned short vendor_id,\r
+                                unsigned short product_id,\r
+                                unsigned char interface_id) {\r
+  // Enumerate all active interfaces for the given class\r
+  SdbEnumInterfaceArray interfaces;\r
+\r
+  if (!EnumerateDeviceInterfaces(class_id,\r
+                                 DIGCF_DEVICEINTERFACE | DIGCF_PRESENT,\r
+                                 true,\r
+                                 true,\r
+                                 &interfaces)) {\r
+    return NULL;\r
+  }\r
+\r
+  if (interfaces.empty()) {\r
+    SetLastError(ERROR_DEVICE_NOT_AVAILABLE);\r
+    return NULL;\r
+  }\r
+\r
+  // Now iterate over active interfaces looking for the name match.\r
+  // The name is formatted as such:\r
+  // "\\\\?\\usb#vid_xxxx&pid_xxxx&mi_xx#123456789abcdef#{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"\r
+  // where\r
+  //    vid_xxxx is for the vendor id (xxxx are hex for the given vendor id),\r
+  //    pid_xxxx is for the product id (xxxx are hex for the given product id)\r
+  //    mi_xx is for the interface id  (xx are hex for the given interface id)\r
+  // EnumerateDeviceInterfaces will guarantee that returned interface names\r
+  // will have our class id at the end of the name (those last XXXes in the\r
+  // format). So, we only need to match the beginning of the name\r
+  wchar_t match_name[64];\r
+  if (0xFF == interface_id) {\r
+    // No interface id for the name.\r
+    swprintf(match_name, L"\\\\?\\usb#vid_%04x&pid_%04x#",\r
+             vendor_id, product_id);\r
+  } else {\r
+    // With interface id for the name.\r
+    swprintf(match_name, L"\\\\?\\usb#vid_%04x&pid_%04x&mi_%02x#",\r
+             vendor_id, product_id, interface_id);\r
+  }\r
+  size_t match_len = wcslen(match_name);\r
+\r
+  for (SdbEnumInterfaceArray::iterator it = interfaces.begin();\r
+       it != interfaces.end(); it++) {\r
+    const SdbInstanceEnumEntry& next_interface = *it;\r
+    if (0 == _wcsnicmp(match_name,\r
+                      next_interface.device_name().c_str(),\r
+                      match_len)) {\r
+      // Found requested interface among active interfaces.\r
+      return SdbCreateInterfaceByName(next_interface.device_name().c_str());\r
+    }\r
+  }\r
+\r
+  SetLastError(ERROR_DEVICE_NOT_AVAILABLE);\r
+  return NULL;\r
+}\r
+\r
+bool __cdecl SdbGetInterfaceName(SDBAPIHANDLE sdb_interface,\r
+                         void* buffer,\r
+                         unsigned long* buffer_char_size,\r
+                         bool ansi) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch call to the found object\r
+    bool ret = sdb_object->GetInterfaceName(buffer, buffer_char_size, ansi);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetSerialNumber(SDBAPIHANDLE sdb_interface,\r
+                        void* buffer,\r
+                        unsigned long* buffer_char_size,\r
+                        bool ansi) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch call to the found object\r
+    bool ret = sdb_object->GetSerialNumber(buffer, buffer_char_size, ansi);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetUsbDeviceDescriptor(SDBAPIHANDLE sdb_interface,\r
+                               USB_DEVICE_DESCRIPTOR* desc) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch close to the found object\r
+    bool ret = sdb_object->GetUsbDeviceDescriptor(desc);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetUsbConfigurationDescriptor(SDBAPIHANDLE sdb_interface,\r
+                                      USB_CONFIGURATION_DESCRIPTOR* desc) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch close to the found object\r
+    bool ret = sdb_object->GetUsbConfigurationDescriptor(desc);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetUsbInterfaceDescriptor(SDBAPIHANDLE sdb_interface,\r
+                                  USB_INTERFACE_DESCRIPTOR* desc) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch close to the found object\r
+    bool ret = sdb_object->GetUsbInterfaceDescriptor(desc);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetEndpointInformation(SDBAPIHANDLE sdb_interface,\r
+                               UCHAR endpoint_index,\r
+                               SdbEndpointInformation* info) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch close to the found object\r
+    bool ret = sdb_object->GetEndpointInformation(endpoint_index, info);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetDefaultBulkReadEndpointInformation(SDBAPIHANDLE sdb_interface,\r
+                                              SdbEndpointInformation* info) {\r
+  return SdbGetEndpointInformation(sdb_interface,\r
+                                   SDB_QUERY_BULK_READ_ENDPOINT_INDEX,\r
+                                   info);\r
+}\r
+\r
+bool __cdecl SdbGetDefaultBulkWriteEndpointInformation(SDBAPIHANDLE sdb_interface,\r
+                                               SdbEndpointInformation* info) {\r
+  return SdbGetEndpointInformation(sdb_interface,\r
+                                   SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX,\r
+                                   info);\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbOpenEndpoint(SDBAPIHANDLE sdb_interface,\r
+                             unsigned char endpoint_index,\r
+                             SdbOpenAccessType access_type,\r
+                             SdbOpenSharingMode sharing_mode) {\r
+  // Lookup interface object for the handle\r
+  SdbInterfaceObject* sdb_object =\r
+    LookupObject<SdbInterfaceObject>(sdb_interface);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch close to the found object\r
+    SDBAPIHANDLE ret =\r
+      sdb_object->OpenEndpoint(endpoint_index, access_type, sharing_mode);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return NULL;\r
+  }\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbOpenDefaultBulkReadEndpoint(SDBAPIHANDLE sdb_interface,\r
+                                            SdbOpenAccessType access_type,\r
+                                            SdbOpenSharingMode sharing_mode) {\r
+  return SdbOpenEndpoint(sdb_interface,\r
+                         SDB_QUERY_BULK_READ_ENDPOINT_INDEX,\r
+                         access_type,\r
+                         sharing_mode);\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbOpenDefaultBulkWriteEndpoint(SDBAPIHANDLE sdb_interface,\r
+                                             SdbOpenAccessType access_type,\r
+                                             SdbOpenSharingMode sharing_mode) {\r
+  return SdbOpenEndpoint(sdb_interface,\r
+                         SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX,\r
+                         access_type,\r
+                         sharing_mode);\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbGetEndpointInterface(SDBAPIHANDLE sdb_endpoint) {\r
+  // Lookup endpoint object for the handle\r
+  SdbEndpointObject* sdb_object =\r
+    LookupObject<SdbEndpointObject>(sdb_endpoint);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    SDBAPIHANDLE ret = sdb_object->GetParentInterfaceHandle();\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return NULL;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbQueryInformationEndpoint(SDBAPIHANDLE sdb_endpoint,\r
+                                 SdbEndpointInformation* info) {\r
+  // Lookup endpoint object for the handle\r
+  SdbEndpointObject* sdb_object =\r
+    LookupObject<SdbEndpointObject>(sdb_endpoint);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    bool ret = sdb_object->GetEndpointInformation(info);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbReadEndpointAsync(SDBAPIHANDLE sdb_endpoint,\r
+                                  void* buffer,\r
+                                  unsigned long bytes_to_read,\r
+                                  unsigned long* bytes_read,\r
+                                  unsigned long time_out,\r
+                                  HANDLE event_handle) {\r
+  // Lookup endpoint object for the handle\r
+  SdbEndpointObject* sdb_object =\r
+    LookupObject<SdbEndpointObject>(sdb_endpoint);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    SDBAPIHANDLE ret = sdb_object->AsyncRead(buffer,\r
+                                             bytes_to_read,\r
+                                             bytes_read,\r
+                                             event_handle,\r
+                                             time_out);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return NULL;\r
+  }\r
+}\r
+\r
+SDBAPIHANDLE __cdecl SdbWriteEndpointAsync(SDBAPIHANDLE sdb_endpoint,\r
+                                   void* buffer,\r
+                                   unsigned long bytes_to_write,\r
+                                   unsigned long* bytes_written,\r
+                                   unsigned long time_out,\r
+                                   HANDLE event_handle) {\r
+  // Lookup endpoint object for the handle\r
+  SdbEndpointObject* sdb_object =\r
+    LookupObject<SdbEndpointObject>(sdb_endpoint);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    SDBAPIHANDLE ret = sdb_object->AsyncWrite(buffer,\r
+                                              bytes_to_write,\r
+                                              bytes_written,\r
+                                              event_handle,\r
+                                              time_out);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbReadEndpointSync(SDBAPIHANDLE sdb_endpoint,\r
+                         void* buffer,\r
+                         unsigned long bytes_to_read,\r
+                         unsigned long* bytes_read,\r
+                         unsigned long time_out) {\r
+  // Lookup endpoint object for the handle\r
+  SdbEndpointObject* sdb_object =\r
+    LookupObject<SdbEndpointObject>(sdb_endpoint);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    bool ret =\r
+      sdb_object->SyncRead(buffer, bytes_to_read, bytes_read, time_out);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return NULL;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbWriteEndpointSync(SDBAPIHANDLE sdb_endpoint,\r
+                          void* buffer,\r
+                          unsigned long bytes_to_write,\r
+                          unsigned long* bytes_written,\r
+                          unsigned long time_out) {\r
+  // Lookup endpoint object for the handle\r
+  SdbEndpointObject* sdb_object =\r
+    LookupObject<SdbEndpointObject>(sdb_endpoint);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    bool ret =\r
+      sdb_object->SyncWrite(buffer, bytes_to_write, bytes_written, time_out);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbGetOvelappedIoResult(SDBAPIHANDLE sdb_io_completion,\r
+                             LPOVERLAPPED overlapped,\r
+                             unsigned long* bytes_transferred,\r
+                             bool wait) {\r
+  // Lookup endpoint object for the handle\r
+  SdbIOCompletion* sdb_object =\r
+    LookupObject<SdbIOCompletion>(sdb_io_completion);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    bool ret =\r
+      sdb_object->GetOvelappedIoResult(overlapped, bytes_transferred, wait);\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbHasOvelappedIoComplated(SDBAPIHANDLE sdb_io_completion) {\r
+  // Lookup endpoint object for the handle\r
+  SdbIOCompletion* sdb_object =\r
+    LookupObject<SdbIOCompletion>(sdb_io_completion);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch the call to the found object\r
+    bool ret =\r
+      sdb_object->IsCompleted();\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return true;\r
+  }\r
+}\r
+\r
+bool __cdecl SdbCloseHandle(SDBAPIHANDLE sdb_handle) {\r
+  // Lookup object for the handle\r
+  SdbObjectHandle* sdb_object = SdbObjectHandle::Lookup(sdb_handle);\r
+\r
+  if (NULL != sdb_object) {\r
+    // Dispatch close to the found object\r
+    bool ret = sdb_object->CloseHandle();\r
+    sdb_object->Release();\r
+    return ret;\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+}\r
diff --git a/src/sdbwinapi/sdb_api.h b/src/sdbwinapi/sdb_api.h
new file mode 100644 (file)
index 0000000..2ae7aa6
--- /dev/null
@@ -0,0 +1,622 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDBWINAPI_H__\r
+#define ANDROID_USB_API_SDBWINAPI_H__\r
+\r
+/** \file\r
+  This file consists of declarations of routines exported by the API as well\r
+  as types, structures, and constants definitions used in the API.\r
+*/\r
+\r
+// Enables compillation for "straight" C\r
+#ifdef __cplusplus\r
+  #define EXTERN_C    extern "C"\r
+#else\r
+  #define EXTERN_C    extern\r
+  typedef int bool;\r
+  #define true  1\r
+  #define false 0\r
+#endif\r
+\r
+/** \brief Enumerates SDB endpoint types.\r
+\r
+  This enum is taken from WDF_USB_PIPE_TYPE enum found in WDK.\r
+*/\r
+typedef enum _SdbEndpointType {\r
+  /// Unknown (invalid, or not initialized) endpoint type.\r
+  SdbEndpointTypeInvalid = 0,\r
+\r
+  /// Endpoint is device control pipe.\r
+  SdbEndpointTypeControl,\r
+\r
+  /// Endpoint is isochronous r/w pipe.\r
+  SdbEndpointTypeIsochronous,\r
+\r
+  /// Endpoint is a bulk r/w pipe.\r
+  SdbEndpointTypeBulk,\r
+\r
+  /// Endpoint is an interrupt r/w pipe.\r
+  SdbEndpointTypeInterrupt,\r
+} SdbEndpointType;\r
+\r
+/** \brief Endpoint desriptor.\r
+\r
+  This structure is based on WDF_USB_PIPE_INFORMATION structure found in WDK.\r
+*/\r
+typedef struct _SdbEndpointInformation {\r
+  /// Maximum packet size this endpoint is capable of.\r
+  unsigned long max_packet_size;\r
+\r
+  /// Maximum size of one transfer which should be sent to the host controller.\r
+  unsigned long max_transfer_size;\r
+\r
+  /// SDB endpoint type.\r
+  SdbEndpointType endpoint_type;\r
+\r
+  /// Raw endpoint address on the device as described by its descriptor.\r
+  unsigned char endpoint_address;\r
+\r
+  /// Polling interval.\r
+  unsigned char polling_interval;\r
+\r
+  /// Which alternate setting this structure is relevant for.\r
+  unsigned char setting_index;\r
+} SdbEndpointInformation;\r
+\r
+/// Shortcut to default write bulk endpoint in zero-based endpoint index API.\r
+#define SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX  0xFC\r
+\r
+/// Shortcut to default read bulk endpoint in zero-based endpoint index API.\r
+#define SDB_QUERY_BULK_READ_ENDPOINT_INDEX  0xFE\r
+\r
+// {F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}\r
+/// Our USB class id that driver uses to register our device.\r
+#define ANDROID_USB_CLASS_ID  {0x9ca29f37, 0xdd62, 0x4aad, {0x82, 0x65, 0xcf, 0xf7, 0x88, 0xc8, 0xba, 0x89}};\r
+//{0xf72fe0d4, 0xcbcb, 0x407d, {0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b}};\r
+\r
+/// Defines vendor ID for HCT devices.\r
+#define DEVICE_VENDOR_ID                  0x0BB4\r
+\r
+/// Defines product ID for the device with single interface.\r
+#define DEVICE_SINGLE_PRODUCT_ID          0x0C01\r
+\r
+/// Defines product ID for the Dream composite device.\r
+#define DEVICE_COMPOSITE_PRODUCT_ID       0x0C02\r
+\r
+/// Defines product ID for the Magic composite device.\r
+#define DEVICE_MAGIC_COMPOSITE_PRODUCT_ID 0x0C03\r
+\r
+/// Defines interface ID for the device.\r
+#define DEVICE_INTERFACE_ID               0x01\r
+\r
+/// Defines vendor ID for the device\r
+#define DEVICE_EMULATOR_VENDOR_ID         0x18D1\r
+\r
+/// Defines product ID for a SoftUSB device simulator that is used to test\r
+/// the driver in isolation from hardware.\r
+#define DEVICE_EMULATOR_PROD_ID           0xDDDD\r
+\r
+// The following ifdef block is the standard way of creating macros which make\r
+// exporting  from a DLL simpler. All files within this DLL are compiled with\r
+// the SDBWIN_EXPORTS symbol defined on the command line. this symbol should\r
+// not be defined on any project that uses this DLL. This way any other project\r
+// whose source files include this file see SDBWIN_API functions as being\r
+// imported from a DLL, whereas this DLL sees symbols defined with this macro\r
+// as being exported.\r
+#ifdef SDBWIN_EXPORTS\r
+#define SDBWIN_API EXTERN_C __declspec(dllexport)\r
+#define SDBWIN_API_CLASS     __declspec(dllexport)\r
+#else\r
+#define SDBWIN_API EXTERN_C __declspec(dllimport)\r
+#define SDBWIN_API_CLASS     __declspec(dllimport)\r
+#endif\r
+\r
+/** \brief Handle to an API object.\r
+\r
+  To access USB interface and its components clients must first obtain a\r
+  handle to the required object. API Objects that are represented by a\r
+  handle are:\r
+  1. Interface enumerator that provides access to a list of interfaces that\r
+     match certain criterias that were specified when interface enumerator\r
+     has been created. This handle is created in SdbEnumInterfaces routine.\r
+  2. Interface that is the major object this API deals with. In Windows\r
+     model of the USB stack each USB device (that is physical device,\r
+     attached to a USB port) exposes one or more interfaces that become the\r
+     major entities through which that device gets accessed. Each of these\r
+     interfaces are represented as Windows Device Objects on the USB stack.\r
+     So, to this extent, at least as this API is concerned, terms "interface"\r
+     and "device" are interchangeable, since each interface is represented by\r
+     a device object on the Windows USB stack. This handle is created in\r
+     either SdbCreateInterface or SdbCreateInterfaceByName routines.\r
+  3. Endpoint object (also called a pipe) represents an endpoint on interface\r
+     through which all I/O operations are performed. This handle is created in\r
+     one of these routines: SdbOpenEndpoint, SdbOpenDefaultBulkReadEndpoint,\r
+     or SdbOpenDefaultBulkWriteEndpoint.\r
+  4. I/O completion object that tracks completion information of asynchronous\r
+     I/O performed on an endpoint. When an endpoint object gets opened through\r
+     this API it is opened for asynchronous (or overlapped) I/O. And each time\r
+     an asynchronous I/O is performed by this API an I/O completion object is\r
+     created to track the result of that I/O when it gets completed. Clients\r
+     of the API can then use a handle to I/O completion object to query for\r
+     the status and result of asynchronous I/O as well as wait for this I/O\r
+     completion. This handle is created in one of these routines:\r
+     SdbReadEndpointAsync, or SdbWriteEndpointAsync.\r
+  After object is no longer needed by the client, its handle must be closed\r
+  using SdbCloseHandle routine.\r
+*/\r
+typedef void* SDBAPIHANDLE;\r
+\r
+/** \brief Defines access type with which an I/O object (endpoint)\r
+  should be opened.\r
+*/\r
+typedef enum _SdbOpenAccessType {\r
+  /// Opens for read and write access.\r
+  SdbOpenAccessTypeReadWrite,\r
+\r
+  /// Opens for read only access.\r
+  SdbOpenAccessTypeRead,\r
+\r
+  /// Opens for write only access.\r
+  SdbOpenAccessTypeWrite,\r
+\r
+  /// Opens for querying information.\r
+  SdbOpenAccessTypeQueryInfo,\r
+} SdbOpenAccessType;\r
+\r
+/** \brief Defines sharing mode with which an I/O object (endpoint)\r
+  should be opened.\r
+*/\r
+typedef enum _SdbOpenSharingMode {\r
+  /// Shares read and write.\r
+  SdbOpenSharingModeReadWrite,\r
+\r
+  /// Shares only read.\r
+  SdbOpenSharingModeRead,\r
+\r
+  /// Shares only write.\r
+  SdbOpenSharingModeWrite,\r
+\r
+  /// Opens exclusive.\r
+  SdbOpenSharingModeExclusive,\r
+} SdbOpenSharingMode;\r
+\r
+/** \brief Provides information about an interface.\r
+*/\r
+typedef struct _SdbInterfaceInfo {\r
+  /// Inteface's class id (see SP_DEVICE_INTERFACE_DATA for details)\r
+  GUID          class_id;\r
+\r
+  /// Interface flags (see SP_DEVICE_INTERFACE_DATA for details)\r
+  unsigned long flags;\r
+\r
+  /// Device name for the interface (see SP_DEVICE_INTERFACE_DETAIL_DATA\r
+  /// for details)\r
+  wchar_t       device_name[1];\r
+} SdbInterfaceInfo;\r
+\r
+/** \brief Creates USB interface enumerator\r
+\r
+  This routine enumerates all USB interfaces that match provided class ID.\r
+  This routine uses SetupDiGetClassDevs SDK routine to enumerate devices that\r
+  match class ID and then SetupDiEnumDeviceInterfaces SDK routine is called\r
+  to enumerate interfaces on the devices.\r
+  @param[in] class_id Device class ID, assigned by the driver.\r
+  @param[in] exclude_not_present If true enumation will include only those\r
+         devices that are currently present.\r
+  @param[in] exclude_removed If true interfaces with SPINT_REMOVED flag set\r
+         will be not included in the enumeration.\r
+  @param[in] active_only If true only active interfaces (with flag\r
+           SPINT_ACTIVE set) will be included in the enumeration.\r
+  @return Handle to the enumerator object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbEnumInterfaces(GUID class_id,\r
+                                          bool exclude_not_present,\r
+                                          bool exclude_removed,\r
+                                          bool active_only);\r
+\r
+/** \brief Gets next interface information\r
+\r
+  @param[in] sdb_handle Handle to interface enumerator object obtained via\r
+         SdbEnumInterfaces call.\r
+  @param[out] info Upon successful completion will receive interface\r
+         information. Can be NULL. If it is NULL, upon return from this\r
+         routine size parameter will contain memory size required for the\r
+         next entry.\r
+  @param[in,out] size On the way in provides size of the memory buffer\r
+         addressed by info parameter. On the way out (only if buffer was not\r
+         big enough) will provide memory size required for the next entry.\r
+  @return true on success, false on error. If false is returned\r
+          GetLastError() provides extended error information.\r
+          ERROR_INSUFFICIENT_BUFFER indicates that buffer provided in info\r
+          parameter was not big enough and size parameter contains memory size\r
+          required for the next entry. ERROR_NO_MORE_ITEMS indicates that\r
+          enumeration is over and there are no more entries to return.\r
+*/\r
+SDBWIN_API bool __cdecl SdbNextInterface(SDBAPIHANDLE sdb_handle,\r
+                                 SdbInterfaceInfo* info,\r
+                                 unsigned long* size);\r
+\r
+/** \brief Resets enumerator so next call to SdbNextInterface will start\r
+  from the beginning.\r
+\r
+  @param[in] sdb_handle Handle to interface enumerator object obtained via\r
+         SdbEnumInterfaces call.\r
+  @return true on success, false on error. If false is returned GetLastError()\r
+          provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbResetInterfaceEnum(SDBAPIHANDLE sdb_handle);\r
+\r
+/** \brief Creates USB interface object\r
+\r
+  This routine creates an object that represents a USB interface.\r
+  @param[in] interface_name Name of the interface.\r
+  @return Handle to the interface object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbCreateInterfaceByName(const wchar_t* interface_name);\r
+\r
+/** \brief Creates USB interface object based on vendor, product and\r
+  interface IDs.\r
+\r
+  This routine creates and object that represents a USB interface on our\r
+  device. It uses SdbCreateInterfaceByName to actually do the create.\r
+  @param[in] class_id Device class ID, assigned by the driver.\r
+  @param[in] vendor_id Device vendor ID\r
+  @param[in] product_id Device product ID\r
+  @param[in] interface_id Device interface ID. This parameter is optional.\r
+         Value 0xFF indicates that interface should be addressed by vendor\r
+         and product IDs only.\r
+  @return Handle to the interface object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbCreateInterface(GUID class_id,\r
+                                           unsigned short vendor_id,\r
+                                           unsigned short product_id,\r
+                                           unsigned char interface_id);\r
+\r
+/** \brief Gets interface name.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] buffer Buffer for the name. Can be NULL in which case\r
+         buffer_char_size will contain number of characters required for\r
+         the name.\r
+  @param[in,out] buffer_char_size On the way in supplies size (in characters)\r
+         of the buffer. On the way out, if method failed and GetLastError\r
+         reports ERROR_INSUFFICIENT_BUFFER, will contain number of characters\r
+         required for the name.\r
+  @param[in] ansi If true the name will be returned as single character\r
+         string. Otherwise name will be returned as wide character string.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetInterfaceName(SDBAPIHANDLE sdb_interface,\r
+                                    void* buffer,\r
+                                    unsigned long* buffer_char_size,\r
+                                    bool ansi);\r
+\r
+/** \brief Gets serial number for interface's device.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] buffer Buffer for the serail number string. Can be NULL in which\r
+         case buffer_char_size will contain number of characters required for\r
+         the string.\r
+  @param[in,out] buffer_char_size On the way in supplies size (in characters)\r
+         of the buffer. On the way out, if method failed and GetLastError\r
+         reports ERROR_INSUFFICIENT_BUFFER, will contain number of characters\r
+         required for the name.\r
+  @param[in] ansi If true the name will be returned as single character\r
+         string. Otherwise name will be returned as wide character string.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetSerialNumber(SDBAPIHANDLE sdb_interface,\r
+                                   void* buffer,\r
+                                   unsigned long* buffer_char_size,\r
+                                   bool ansi);\r
+\r
+/** \brief Gets device descriptor for the USB device associated with\r
+  the given interface.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] desc Upon successful completion will have usb device\r
+         descriptor.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetUsbDeviceDescriptor(SDBAPIHANDLE sdb_interface,\r
+                                          USB_DEVICE_DESCRIPTOR* desc);\r
+\r
+/** \brief Gets descriptor for the selected USB device configuration.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] desc Upon successful completion will have usb device\r
+         configuration descriptor.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetUsbConfigurationDescriptor(\r
+                    SDBAPIHANDLE sdb_interface,\r
+                    USB_CONFIGURATION_DESCRIPTOR* desc);\r
+\r
+/** \brief Gets descriptor for the given interface.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] desc Upon successful completion will have usb device\r
+         configuration descriptor.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetUsbInterfaceDescriptor(SDBAPIHANDLE sdb_interface,\r
+                                             USB_INTERFACE_DESCRIPTOR* desc);\r
+\r
+/** \brief Gets information about an endpoint on the given interface.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[in] endpoint_index Zero-based endpoint index. There are two\r
+         shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX\r
+         and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide information\r
+         about bulk write and bulk read endpoints respectively.\r
+  @param[out] info Upon successful completion will have endpoint information.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetEndpointInformation(SDBAPIHANDLE sdb_interface,\r
+                                          unsigned char endpoint_index,\r
+                                          SdbEndpointInformation* info);\r
+\r
+/** \brief Gets information about default bulk read endpoint on the given\r
+  interface.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] info Upon successful completion will have endpoint information.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetDefaultBulkReadEndpointInformation(\r
+                    SDBAPIHANDLE sdb_interface,\r
+                    SdbEndpointInformation* info);\r
+\r
+/** \brief Gets information about default bulk write endpoint on the given\r
+  interface.\r
+\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[out] info Upon successful completion will have endpoint information.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetDefaultBulkWriteEndpointInformation(\r
+                    SDBAPIHANDLE sdb_interface,\r
+                    SdbEndpointInformation* info);\r
+\r
+/** \brief Opens an endpoint on the given interface.\r
+\r
+  Endpoints are always opened for overlapped I/O.\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[in] endpoint_index Zero-based endpoint index. There are two\r
+         shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX\r
+         and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide information\r
+         about bulk write and bulk read endpoints respectively.\r
+  @param[in] access_type Desired access type. In the current implementation\r
+         this parameter has no effect on the way endpoint is opened. It's\r
+         always read / write access.\r
+  @param[in] sharing_mode Desired share mode. In the current implementation\r
+         this parameter has no effect on the way endpoint is opened. It's\r
+         always shared for read / write.\r
+  @return Handle to the opened endpoint object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbOpenEndpoint(SDBAPIHANDLE sdb_interface,\r
+                                        unsigned char endpoint_index,\r
+                                        SdbOpenAccessType access_type,\r
+                                        SdbOpenSharingMode sharing_mode);\r
+\r
+/** \brief Opens default bulk read endpoint on the given interface.\r
+\r
+  Endpoints are always opened for overlapped I/O.\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[in] access_type Desired access type. In the current implementation\r
+         this parameter has no effect on the way endpoint is opened. It's\r
+         always read / write access.\r
+  @param[in] sharing_mode Desired share mode. In the current implementation\r
+         this parameter has no effect on the way endpoint is opened. It's\r
+         always shared for read / write.\r
+  @return Handle to the opened endpoint object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbOpenDefaultBulkReadEndpoint(\r
+                            SDBAPIHANDLE sdb_interface,\r
+                            SdbOpenAccessType access_type,\r
+                            SdbOpenSharingMode sharing_mode);\r
+\r
+/** \brief Opens default bulk write endpoint on the given interface.\r
+\r
+  Endpoints are always opened for overlapped I/O.\r
+  @param[in] sdb_interface A handle to interface object created with \r
+         SdbCreateInterface call.\r
+  @param[in] access_type Desired access type. In the current implementation\r
+         this parameter has no effect on the way endpoint is opened. It's\r
+         always read / write access.\r
+  @param[in] sharing_mode Desired share mode. In the current implementation\r
+         this parameter has no effect on the way endpoint is opened. It's\r
+         always shared for read / write.\r
+  @return Handle to the opened endpoint object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbOpenDefaultBulkWriteEndpoint(\r
+                            SDBAPIHANDLE sdb_interface,\r
+                            SdbOpenAccessType access_type,\r
+                            SdbOpenSharingMode sharing_mode);\r
+\r
+/** \brief Gets handle to interface object for the given endpoint\r
+\r
+  @param[in] sdb_endpoint A handle to opened endpoint object, obtained via one\r
+         of the SdbOpenXxxEndpoint calls.\r
+  @return Handle to the interface for this endpoint or NULL on failure. If NULL\r
+          is returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbGetEndpointInterface(SDBAPIHANDLE sdb_endpoint);\r
+\r
+/** \brief Gets information about the given endpoint.\r
+\r
+  @param[in] sdb_endpoint A handle to opened endpoint object, obtained via one\r
+         of the SdbOpenXxxEndpoint calls.\r
+  @param[out] info Upon successful completion will have endpoint information.\r
+  @return true on success, false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbQueryInformationEndpoint(SDBAPIHANDLE sdb_endpoint,\r
+                                            SdbEndpointInformation* info);\r
+\r
+/** \brief Asynchronously reads from the given endpoint.\r
+\r
+  @param[in] sdb_endpoint A handle to opened endpoint object, obtained via one\r
+         of the SdbOpenXxxEndpoint calls.\r
+  @param[out] buffer Pointer to the buffer that receives the data.\r
+  @param[in] bytes_to_read Number of bytes to be read.\r
+  @param[out] bytes_read Number of bytes read. Can be NULL.\r
+  @param[in] event_handle Event handle that should be signaled when async I/O\r
+         completes. Can be NULL. If it's not NULL this handle will be used to\r
+         initialize OVERLAPPED structure for this I/O.\r
+  @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+         complete. Zero value for this parameter means that there is no\r
+         timeout for this I/O.\r
+  @return A handle to IO completion object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbReadEndpointAsync(SDBAPIHANDLE sdb_endpoint,\r
+                                             void* buffer,\r
+                                             unsigned long bytes_to_read,\r
+                                             unsigned long* bytes_read,\r
+                                             unsigned long time_out,\r
+                                             HANDLE event_handle);\r
+\r
+/** \brief Asynchronously writes to the given endpoint.\r
+\r
+  @param[in] sdb_endpoint A handle to opened endpoint object, obtained via one\r
+         of the SdbOpenXxxEndpoint calls.\r
+  @param[in] buffer Pointer to the buffer containing the data to be written.\r
+  @param[in] bytes_to_write Number of bytes to be written.\r
+  @param[out] bytes_written Number of bytes written. Can be NULL.\r
+  @param[in] event_handle Event handle that should be signaled when async I/O\r
+         completes. Can be NULL. If it's not NULL this handle will be used to\r
+         initialize OVERLAPPED structure for this I/O.\r
+  @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+         complete. Zero value for this parameter means that there is no\r
+         timeout for this I/O.\r
+  @return A handle to IO completion object or NULL on failure. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API SDBAPIHANDLE __cdecl SdbWriteEndpointAsync(SDBAPIHANDLE sdb_endpoint,\r
+                                              void* buffer,\r
+                                              unsigned long bytes_to_write,\r
+                                              unsigned long* bytes_written,\r
+                                              unsigned long time_out,\r
+                                              HANDLE event_handle);\r
+\r
+/** \brief Synchronously reads from the given endpoint.\r
+\r
+  @param[in] sdb_endpoint A handle to opened endpoint object, obtained via one\r
+         of the SdbOpenXxxEndpoint calls.\r
+  @param[out] buffer Pointer to the buffer that receives the data.\r
+  @param[in] bytes_to_read Number of bytes to be read.\r
+  @param[out] bytes_read Number of bytes read. Can be NULL.\r
+  @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+         complete. Zero value for this parameter means that there is no\r
+         timeout for this I/O.\r
+  @return true on success and false on failure. If false is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbReadEndpointSync(SDBAPIHANDLE sdb_endpoint,\r
+                                    void* buffer,\r
+                                    unsigned long bytes_to_read,\r
+                                    unsigned long* bytes_read,\r
+                                    unsigned long time_out);\r
+\r
+/** \brief Synchronously writes to the given endpoint.\r
+\r
+  @param[in] sdb_endpoint A handle to opened endpoint object, obtained via one\r
+         of the SdbOpenXxxEndpoint calls.\r
+  @param[in] buffer Pointer to the buffer containing the data to be written.\r
+  @param[in] bytes_to_write Number of bytes to be written.\r
+  @param[out] bytes_written Number of bytes written. Can be NULL.\r
+  @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+         complete. Zero value for this parameter means that there is no\r
+         timeout for this I/O.\r
+  @return true on success and false on failure. If false is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbWriteEndpointSync(SDBAPIHANDLE sdb_endpoint,\r
+                                     void* buffer,\r
+                                     unsigned long bytes_to_write,\r
+                                     unsigned long* bytes_written,\r
+                                     unsigned long time_out);\r
+\r
+/** \brief Gets overlapped I/O result for async I/O performed on the\r
+  given endpoint.\r
+\r
+  @param[in] sdb_io_completion A handle to an I/O completion object returned\r
+         from SdbRead/WriteAsync routines.\r
+  @param[out] ovl_data Buffer for the copy of this object's OVERLAPPED\r
+         structure. Can be NULL.\r
+  @param[out] bytes_transferred Pointer to a variable that receives the\r
+         number of bytes that were actually transferred by a read or write\r
+         operation. See SDK doc on GetOvelappedResult for more information.\r
+         Unlike regular GetOvelappedResult call this parameter can be NULL.\r
+  @param[in] wait If this parameter is true, the method does not return\r
+         until the operation has been completed. If this parameter is false\r
+         and the operation is still pending, the method returns false and\r
+         the GetLastError function returns ERROR_IO_INCOMPLETE.\r
+  @return true if I/O has been completed or false on failure or if request\r
+         is not yet completed. If false is returned GetLastError() provides\r
+         extended error information. If GetLastError returns\r
+         ERROR_IO_INCOMPLETE it means that I/O is not yet completed.\r
+*/\r
+SDBWIN_API bool __cdecl SdbGetOvelappedIoResult(SDBAPIHANDLE sdb_io_completion,\r
+                                        LPOVERLAPPED overlapped,\r
+                                        unsigned long* bytes_transferred,\r
+                                        bool wait);\r
+\r
+/** \brief Checks if overlapped I/O has been completed.\r
+\r
+  @param[in] sdb_io_completion A handle to an I/O completion object returned\r
+         from SdbRead/WriteAsync routines.\r
+  @return true if I/O has been completed or false if it's still\r
+          incomplete. Regardless of the returned value, caller should\r
+          check GetLastError to validate that handle was OK.\r
+*/\r
+SDBWIN_API bool __cdecl SdbHasOvelappedIoComplated(SDBAPIHANDLE sdb_io_completion);\r
+\r
+/** \brief Closes handle previously opened with one of the API calls\r
+\r
+  @param[in] sdb_handle SDB handle previously opened with one of the API calls\r
+  @return true on success or false on failure. If false is returned\r
+          GetLastError() provides extended error information.\r
+*/\r
+SDBWIN_API bool __cdecl SdbCloseHandle(SDBAPIHANDLE sdb_handle);\r
+\r
+#endif  // ANDROID_USB_API_SDBWINAPI_H__\r
diff --git a/src/sdbwinapi/sdb_api_instance.cpp b/src/sdbwinapi/sdb_api_instance.cpp
new file mode 100644 (file)
index 0000000..085f2c7
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbApiInstance that is a main\r
+  API object representing a device interface that is in the interest of\r
+  the API client. All device (interface) related operations go through this\r
+  class first.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api_instance.h"\r
+#include "sdb_helper_routines.h"\r
+\r
+/// Map that holds all instances of this object\r
+SdbApiInstanceMap sdb_app_instance_map;\r
+ULONG_PTR sdb_app_instance_id = 0;\r
+CComAutoCriticalSection sdb_app_instance_map_locker;\r
+\r
+SdbApiInstance::SdbApiInstance()\r
+    : ref_count_(1) {\r
+  // Generate inteface handle\r
+  sdb_app_instance_map_locker.Lock();\r
+  sdb_app_instance_id++;\r
+  sdb_app_instance_map_locker.Unlock();\r
+  instance_handle_ =\r
+    reinterpret_cast<SDBAPIINSTANCEHANDLE>(sdb_app_instance_id);\r
+}\r
+\r
+SdbApiInstance::~SdbApiInstance() {\r
+}\r
+\r
+void SdbApiInstance::LastReferenceReleased() {\r
+}\r
diff --git a/src/sdbwinapi/sdb_api_instance.h b/src/sdbwinapi/sdb_api_instance.h
new file mode 100644 (file)
index 0000000..50a5568
--- /dev/null
@@ -0,0 +1,113 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_API_INSTANCE_H__\r
+#define ANDROID_USB_API_SDB_API_INSTANCE_H__\r
+/** \file\r
+  This file consists of declaration of class SdbApiInstance that is a main\r
+  API object representing a device interface that is in the interest of\r
+  the API client. All device (interface) related operations go through this\r
+  class first.\r
+*/\r
+\r
+#include "sdb_api.h"\r
+#include "sdb_api_private_defines.h"\r
+\r
+/** Class SdbApiInstance is the main API interbal object representing a device\r
+  interface that is in the interest of the API client. All device (interface)\r
+  related operations go through this class first. So, before doing anything\r
+  meaningfull with the API a client must first create instance of the API\r
+  via CreateSdbApiInstance, select a device interface for that instance and\r
+  then do everything else.\r
+  Objects of this class are globally stored in the map that matches\r
+  SDBAPIINSTANCEHANDLE to the corresponded object.\r
+  This class is self-referenced with the following reference model:\r
+  1. When object of this class is created and added to the map, its recount\r
+     is set to 1.\r
+  2. Every time the client makes an API call that uses SDBAPIINSTANCEHANDLE\r
+     a corresponded SdbApiInstance object is looked up in the table and its\r
+     refcount is incremented. Upon return from the API call that incremented\r
+     the refcount refcount gets decremented.\r
+  3. When the client closes SDBAPIINSTANCEHANDLE via DeleteSdbApiInstance call\r
+     corresponded object gets deleted from the map and its refcount is\r
+     decremented.\r
+  So, at the end, this object destroys itself when refcount drops to zero.\r
+*/\r
+class SdbApiInstance {\r
+ public:\r
+  /** \brief Constructs the object\r
+    \r
+    @param handle[in] Instance handle associated with this object\r
+  */\r
+  SdbApiInstance();\r
+\r
+ private:\r
+  /// Destructs the object\r
+  ~SdbApiInstance();\r
+\r
+  /** \brief\r
+    This method is called when last reference to this object has been released\r
+\r
+    In this method object is uninitialized and deleted (that is "delete this"\r
+    is called).\r
+  */\r
+  void LastReferenceReleased();\r
+\r
+ public:\r
+   /// Gets name of the USB interface (device name) for this instance\r
+   const std::wstring& interface_name() const {\r
+     return interface_name_;\r
+   }\r
+\r
+   /// References the object and returns number of references\r
+   LONG AddRef() {\r
+     return InterlockedIncrement(&ref_count_);\r
+   }\r
+\r
+   /** \brief Dereferences the object and returns number of references\r
+\r
+    Object may be deleted in this method, so you cannot touch it after\r
+    this method returns, even if returned value is not zero, because object\r
+    can be deleted in another thread.\r
+   */\r
+   LONG Release() {\r
+     LONG ret = InterlockedDecrement(&ref_count_);\r
+     if (0 == ret)\r
+       LastReferenceReleased();\r
+\r
+     return ret;\r
+   }\r
+\r
+   /// Checks if instance has been initialized\r
+   bool IsInitialized() const {\r
+     return !interface_name_.empty();\r
+   }\r
+\r
+private:\r
+  /// Name of the USB interface (device name) for this instance\r
+  std::wstring          interface_name_;\r
+\r
+  /// Instance handle for this object\r
+  SDBAPIINSTANCEHANDLE  instance_handle_;\r
+\r
+  /// Reference counter for this instance\r
+  LONG                  ref_count_;\r
+};\r
+\r
+/// Defines map that matches SDBAPIINSTANCEHANDLE with SdbApiInstance object\r
+typedef std::map< SDBAPIINSTANCEHANDLE, SdbApiInstance* > SdbApiInstanceMap;\r
+\r
+#endif  // ANDROID_USB_API_SDB_API_INSTANCE_H__\r
diff --git a/src/sdbwinapi/sdb_api_legacy.h b/src/sdbwinapi/sdb_api_legacy.h
new file mode 100644 (file)
index 0000000..552d951
--- /dev/null
@@ -0,0 +1,190 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_API_LEGACY_H_\r
+#define ANDROID_USB_API_SDB_API_LEGACY_H_\r
+/** \file\r
+  This file consists of declarations of constants and structures required\r
+  for supporting communications of this API with a legacy (custom) USB\r
+  driver.\r
+*/\r
+\r
+// Enables compillation for "straight" C\r
+#ifdef __cplusplus\r
+  #define EXTERN_C    extern "C"\r
+#else\r
+  #define EXTERN_C    extern\r
+  typedef int bool;\r
+  #define true  1\r
+  #define false 0\r
+#endif\r
+\r
+/// Name for the default bulk read pipe\r
+#define DEVICE_BULK_READ_PIPE_NAME  L"BulkRead"\r
+\r
+/// Name for the default bulk write pipe\r
+#define DEVICE_BULK_WRITE_PIPE_NAME L"BulkWrite"\r
+\r
+/// Prefix for an index-based pipe name\r
+#define DEVICE_PIPE_NAME_PREFIX     L"PIPE_"\r
+\r
+/** \name IOCTL codes for the driver\r
+*/\r
+///@{\r
+\r
+/// Control code for IOCTL that gets USB_DEVICE_DESCRIPTOR\r
+#define SDB_CTL_GET_USB_DEVICE_DESCRIPTOR         10\r
+\r
+/// Control code for IOCTL that gets USB_CONFIGURATION_DESCRIPTOR\r
+#define SDB_CTL_GET_USB_CONFIGURATION_DESCRIPTOR  11\r
+\r
+/// Control code for IOCTL that gets USB_INTERFACE_DESCRIPTOR\r
+#define SDB_CTL_GET_USB_INTERFACE_DESCRIPTOR      12\r
+\r
+/// Control code for IOCTL that gets endpoint information\r
+#define SDB_CTL_GET_ENDPOINT_INFORMATION          13\r
+\r
+/// Control code for bulk read IOCTL\r
+#define SDB_CTL_BULK_READ                         14\r
+\r
+/// Control code for bulk write IOCTL\r
+#define SDB_CTL_BULK_WRITE                        15\r
+\r
+/// Control code for IOCTL that gets device serial number\r
+#define SDB_CTL_GET_SERIAL_NUMBER                 16\r
+\r
+/// IOCTL that gets USB_DEVICE_DESCRIPTOR\r
+#define SDB_IOCTL_GET_USB_DEVICE_DESCRIPTOR \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_GET_USB_DEVICE_DESCRIPTOR, \\r
+                       METHOD_BUFFERED, \\r
+                       FILE_READ_ACCESS)\r
+\r
+/// IOCTL that gets USB_CONFIGURATION_DESCRIPTOR\r
+#define SDB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_GET_USB_CONFIGURATION_DESCRIPTOR, \\r
+                       METHOD_BUFFERED, \\r
+                       FILE_READ_ACCESS)\r
+\r
+/// IOCTL that gets USB_INTERFACE_DESCRIPTOR\r
+#define SDB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_GET_USB_INTERFACE_DESCRIPTOR, \\r
+                       METHOD_BUFFERED, \\r
+                       FILE_READ_ACCESS)\r
+\r
+/// IOCTL that gets endpoint information\r
+#define SDB_IOCTL_GET_ENDPOINT_INFORMATION \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_GET_ENDPOINT_INFORMATION, \\r
+                       METHOD_BUFFERED, \\r
+                       FILE_READ_ACCESS)\r
+\r
+/// Bulk read IOCTL\r
+#define SDB_IOCTL_BULK_READ \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_BULK_READ, \\r
+                       METHOD_OUT_DIRECT, \\r
+                       FILE_READ_ACCESS)\r
+\r
+// For bulk write IOCTL we send request data in the form of SdbBulkTransfer\r
+// structure and output buffer is just ULONG that receives number of bytes\r
+// actually written. Since both of these are tiny we can use buffered I/O\r
+// for this IOCTL.\r
+/// Bulk write IOCTL\r
+#define SDB_IOCTL_BULK_WRITE \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_BULK_WRITE, \\r
+                       METHOD_BUFFERED, \\r
+                       FILE_WRITE_ACCESS)\r
+\r
+/// IOCTL that gets device serial number\r
+#define SDB_IOCTL_GET_SERIAL_NUMBER \\r
+              CTL_CODE(FILE_DEVICE_UNKNOWN, \\r
+                       SDB_CTL_GET_SERIAL_NUMBER, \\r
+                       METHOD_BUFFERED, \\r
+                       FILE_READ_ACCESS)\r
+\r
+///@}\r
+\r
+/** Structure SdbQueryEndpointInformation formats input for\r
+  SDB_IOCTL_GET_ENDPOINT_INFORMATION IOCTL request\r
+*/\r
+struct SdbQueryEndpointInformation {\r
+  /// Zero-based endpoint index for which information is queried.\r
+  /// See SDB_QUERY_BULK_xxx_ENDPOINT_INDEX for shortcuts.\r
+  UCHAR endpoint_index;\r
+};\r
+\r
+/** Structure SdbBulkTransfer formats parameters for SDB_CTL_BULK_READ and\r
+  SDB_CTL_BULK_WRITE IOCTL requests.\r
+*/\r
+struct SdbBulkTransfer {\r
+  /// Time in milliseconds to complete this request\r
+  ULONG time_out;\r
+\r
+  /// Size of the data to transfer. This parameter is used only for\r
+  /// SDB_CTL_BULK_WRITE request. For SDB_CTL_BULK_READ requests transfer\r
+  /// size is defined by the output buffer size.\r
+  ULONG transfer_size;\r
+\r
+  /// Initializes statically allocated structure\r
+  __forceinline SdbBulkTransfer() {\r
+    time_out = 0;\r
+    transfer_size = 0;\r
+    for_x64 = 0;\r
+  }\r
+\r
+  /// Provides access to protected write_buffer field\r
+  void* GetWriteBuffer() {\r
+    return write_buffer;\r
+  }\r
+\r
+  /// Provides access to protected write_buffer field\r
+  const void* GetWriteBuffer() const {\r
+    return write_buffer;\r
+  }\r
+\r
+  /// Sets write_buffer field.\r
+  void SetWriteBuffer(void* buffer) {\r
+    // For 32-bit we must zero out high 32 bit of the address, so 64-bit\r
+    // driver will see valid address when accessing 64-bit write_buffer.\r
+    for_x64 = 0;\r
+    write_buffer = buffer;\r
+  }\r
+\r
+protected:\r
+  /// Pointer to the actual buffer for SDB_CTL_BULK_WRITE request. This field\r
+  /// is not used in SDB_CTL_BULK_READ request. Note that in order to support\r
+  /// compatibility between 32-bit and 64-bit versions of both, driver and\r
+  /// application we must sizeof this field to the max pointer sizeof (which\r
+  /// is 64 bit in our case). The idea is that if IOCTL was issued by a 64-bit\r
+  /// process to a 64-bit driver, write_buffer will be valid 64-bit pointer to\r
+  /// the write buffer. Same is true for 32-bit app talking to 32-bit driver.\r
+  /// If, however, a 32-bit app is talking to 64-bit driver, then write_buffer\r
+  /// initialized by 32-bit app will contain 32-bit address, which will be\r
+  /// correctly picked up ("extended") by 64-bit driver. Since when setting\r
+  /// this field by a 32-bit app requires some extra work (see SetWriteBuffer)\r
+  /// we hide this field, making it accessible only throug the accessor\r
+  /// methods (Get/SetWriteBuffer).\r
+  union {\r
+    void* write_buffer;\r
+    __int64 for_x64;\r
+  };\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_API_LEGACY_H_\r
diff --git a/src/sdbwinapi/sdb_api_private_defines.h b/src/sdbwinapi/sdb_api_private_defines.h
new file mode 100644 (file)
index 0000000..ce3f1c9
--- /dev/null
@@ -0,0 +1,114 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_SDB_API_PRIVATE_DEFINES_H__\r
+#define ANDROID_USB_SDB_API_PRIVATE_DEFINES_H__\r
+/** \file\r
+  This file consists of private definitions used inside the API\r
+*/\r
+\r
+#include "sdb_api.h"\r
+\r
+/** \brief Encapsulates an entry in the array of enumerated interfaces.\r
+*/\r
+class SdbInstanceEnumEntry {\r
+ public:\r
+  /** \brief Constructs an empty object.\r
+  */\r
+  SdbInstanceEnumEntry()\r
+      : flags_(0) {\r
+    ZeroMemory(&class_id_, sizeof(class_id_));\r
+  }\r
+\r
+  /** \brief Copy constructor\r
+  */\r
+  SdbInstanceEnumEntry(const SdbInstanceEnumEntry& proto) {\r
+    Set(proto.device_name().c_str(), proto.class_id(), proto.flags());\r
+  }\r
+\r
+  /** \brief Constructs the object with parameters.\r
+  */\r
+  SdbInstanceEnumEntry(const wchar_t* dev_name, GUID cls_id, DWORD flgs) {\r
+    Set(dev_name, cls_id, flgs);\r
+  }\r
+\r
+  /** \brief Destructs the object.\r
+  */\r
+  ~SdbInstanceEnumEntry() {\r
+  }\r
+\r
+  /// Operator =\r
+  SdbInstanceEnumEntry& operator=(const SdbInstanceEnumEntry& proto) {\r
+    Set(proto.device_name().c_str(), proto.class_id(), proto.flags());\r
+    return *this;\r
+  }\r
+\r
+  /// Initializes instance with parameters\r
+  void Set(const wchar_t* dev_name, GUID cls_id, DWORD flgs) {\r
+    device_name_ = dev_name;\r
+    class_id_ = cls_id;\r
+    flags_ = flgs;\r
+  }\r
+\r
+  /// Calculates memory size needed to save this entry into SdbInterfaceInfo\r
+  /// structure\r
+  ULONG GetFlatSize() const {\r
+    return static_cast<ULONG>(FIELD_OFFSET(SdbInterfaceInfo, device_name) +\r
+                              (device_name_.length() + 1) * sizeof(wchar_t));\r
+  }\r
+\r
+  /** \brief Saves this entry into SdbInterfaceInfo structure.\r
+\r
+    @param[in] info Buffer to save this entry to. Must be big enough to fit it.\r
+           Use GetFlatSize() method to get buffer size needed for that.\r
+\r
+  */\r
+  void Save(SdbInterfaceInfo* info) const {\r
+    info->class_id = class_id();\r
+    info->flags = flags();\r
+    wcscpy(info->device_name, device_name().c_str());\r
+  }\r
+\r
+  /// Gets interface's device name\r
+  const std::wstring& device_name() const {\r
+    return device_name_;\r
+  }\r
+\r
+  /// Gets inteface's class id\r
+  GUID class_id() const {\r
+    return class_id_;\r
+  }\r
+\r
+  /// Gets interface flags\r
+  DWORD flags() const {\r
+    return flags_;\r
+  }\r
+\r
+ private:\r
+  /// Inteface's class id (see SP_DEVICE_INTERFACE_DATA)\r
+  GUID          class_id_;\r
+\r
+  /// Interface's device name\r
+  std::wstring  device_name_;\r
+\r
+  /// Interface flags (see SP_DEVICE_INTERFACE_DATA)\r
+  DWORD         flags_;\r
+};\r
+\r
+/// Defines array of enumerated interface entries\r
+typedef std::vector< SdbInstanceEnumEntry > SdbEnumInterfaceArray;\r
+\r
+#endif  // ANDROID_USB_SDB_API_PRIVATE_DEFINES_H__\r
diff --git a/src/sdbwinapi/sdb_endpoint_object.cpp b/src/sdbwinapi/sdb_endpoint_object.cpp
new file mode 100644 (file)
index 0000000..f099ab5
--- /dev/null
@@ -0,0 +1,96 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbEndpointObject that\r
+  encapsulates a handle opened to an endpoint on our device.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_endpoint_object.h"\r
+\r
+SdbEndpointObject::SdbEndpointObject(SdbInterfaceObject* parent_interf,\r
+                                     UCHAR endpoint_id,\r
+                                     UCHAR endpoint_index)\r
+    : SdbObjectHandle(SdbObjectTypeEndpoint),\r
+      parent_interface_(parent_interf),\r
+      endpoint_id_(endpoint_id),\r
+      endpoint_index_(endpoint_index) {\r
+  if (NULL != parent_interface_)\r
+    parent_interface_->AddRef();\r
+}\r
+\r
+SdbEndpointObject::~SdbEndpointObject() {\r
+  if (NULL != parent_interface_)\r
+    parent_interface_->Release();\r
+}\r
+\r
+bool SdbEndpointObject::GetEndpointInformation(SdbEndpointInformation* info) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  return parent_interface()->GetEndpointInformation(endpoint_index(), info);\r
+}\r
+\r
+SDBAPIHANDLE SdbEndpointObject::AsyncRead(void* buffer,\r
+                                    ULONG bytes_to_read,\r
+                                    ULONG* bytes_read,\r
+                                    HANDLE event_handle,\r
+                                    ULONG time_out) {\r
+  return CommonAsyncReadWrite(true,\r
+                              buffer,\r
+                              bytes_to_read,\r
+                              bytes_read,\r
+                              event_handle,\r
+                              time_out);\r
+}\r
+\r
+SDBAPIHANDLE SdbEndpointObject::AsyncWrite(void* buffer,\r
+                                     ULONG bytes_to_write,\r
+                                     ULONG* bytes_written,\r
+                                     HANDLE event_handle,\r
+                                     ULONG time_out) {\r
+  return CommonAsyncReadWrite(false,\r
+                              buffer,\r
+                              bytes_to_write,\r
+                              bytes_written,\r
+                              event_handle,\r
+                              time_out);\r
+}\r
+\r
+bool SdbEndpointObject::SyncRead(void* buffer,\r
+                           ULONG bytes_to_read,\r
+                           ULONG* bytes_read,\r
+                           ULONG time_out) {\r
+  return CommonSyncReadWrite(true,\r
+                             buffer,\r
+                             bytes_to_read,\r
+                             bytes_read,\r
+                             time_out);\r
+}\r
+\r
+bool SdbEndpointObject::SyncWrite(void* buffer,\r
+                            ULONG bytes_to_write,\r
+                            ULONG* bytes_written,\r
+                            ULONG time_out) {\r
+  return CommonSyncReadWrite(false,\r
+                             buffer,\r
+                             bytes_to_write,\r
+                             bytes_written,\r
+                             time_out);\r
+}\r
diff --git a/src/sdbwinapi/sdb_endpoint_object.h b/src/sdbwinapi/sdb_endpoint_object.h
new file mode 100644 (file)
index 0000000..f670ebe
--- /dev/null
@@ -0,0 +1,222 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_ENDPOINT_OBJECT_H__\r
+#define ANDROID_USB_API_SDB_ENDPOINT_OBJECT_H__\r
+/** \file\r
+  This file consists of declaration of class SdbEndpointObject that\r
+  encapsulates a handle opened to an endpoint on our device.\r
+*/\r
+\r
+#include "sdb_interface.h"\r
+\r
+/** Class SdbEndpointObject encapsulates a handle opened to an endpoint on\r
+  our device.\r
+\r
+  This class implement functionality that is common for both, WinUsb and\r
+  legacy APIs.\r
+*/\r
+class SDBWIN_API_CLASS SdbEndpointObject : public SdbObjectHandle {\r
+ public:\r
+  /** \brief Constructs the object\r
+    \r
+    @param[in] interface Parent interface for this object. Interface will be\r
+           referenced in this object's constructur and released in the\r
+           destructor.\r
+    @param[in] endpoint_id Endpoint ID (endpoint address) on the device.\r
+    @param[in] endpoint_index Zero-based endpoint index in the interface's\r
+          array of endpoints.\r
+  */\r
+  SdbEndpointObject(SdbInterfaceObject* parent_interf,\r
+                    UCHAR endpoint_id,\r
+                    UCHAR endpoint_index);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+    We hide destructor in order to prevent ourseves from accidentaly allocating\r
+    instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbEndpointObject();\r
+\r
+  //\r
+  // Abstract\r
+  //\r
+\r
+ protected:\r
+  /** \brief Common code for async read / write\r
+\r
+    @param[in] is_read Read or write selector.\r
+    @param[in,out] buffer Pointer to the buffer for read / write.\r
+    @param[in] bytes_to_transfer Number of bytes to be read / written.\r
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.\r
+    @param[in] event_handle Event handle that should be signaled when async I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be used to\r
+           initialize OVERLAPPED structure for this I/O.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return A handle to IO completion object or NULL on failure. If NULL is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual SDBAPIHANDLE CommonAsyncReadWrite(bool is_read,\r
+                                            void* buffer,\r
+                                            ULONG bytes_to_transfer,\r
+                                            ULONG* bytes_transferred,\r
+                                            HANDLE event_handle,\r
+                                            ULONG time_out) = 0;\r
+\r
+  /** \brief Common code for sync read / write\r
+\r
+    @param[in] is_read Read or write selector.\r
+    @param[in,out] buffer Pointer to the buffer for read / write.\r
+    @param[in] bytes_to_transfer Number of bytes to be read / written.\r
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool CommonSyncReadWrite(bool is_read,\r
+                                   void* buffer,\r
+                                   ULONG bytes_to_transfer,\r
+                                   ULONG* bytes_transferred,\r
+                                   ULONG time_out) = 0;\r
+\r
+  //\r
+  // Operations\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets information about this endpoint.\r
+\r
+    @param[out] info Upon successful completion will have endpoint information.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetEndpointInformation(SdbEndpointInformation* info);\r
+\r
+  /** \brief Reads from opened I/O object asynchronously\r
+\r
+    @param[out] buffer Pointer to the buffer that receives the data.\r
+    @param[in] bytes_to_read Number of bytes to be read.\r
+    @param[out] bytes_read Number of bytes read. Can be NULL.\r
+    @param[in] event_handle Event handle that should be signaled when async I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be used to\r
+           initialize OVERLAPPED structure for this I/O.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return A handle to IO completion object or NULL on failure. If NULL is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual SDBAPIHANDLE AsyncRead(void* buffer,\r
+                                 ULONG bytes_to_read,\r
+                                 ULONG* bytes_read,\r
+                                 HANDLE event_handle,\r
+                                 ULONG time_out);\r
+\r
+  /** \brief Writes to opened I/O object asynchronously\r
+\r
+    @param[in] buffer Pointer to the buffer containing the data to be written.\r
+    @param[in] bytes_to_write Number of bytes to be written.\r
+    @param[out] bytes_written Number of bytes written. Can be NULL.\r
+    @param[in] event_handle Event handle that should be signaled when async I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be used to\r
+           initialize OVERLAPPED structure for this I/O.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return A handle to IO completion object or NULL on failure. If NULL is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual SDBAPIHANDLE AsyncWrite(void* buffer,\r
+                                  ULONG bytes_to_write,\r
+                                  ULONG* bytes_written,\r
+                                  HANDLE event_handle,\r
+                                  ULONG time_out);\r
+\r
+  /** \brief Reads from opened I/O object synchronously\r
+\r
+    @param[out] buffer Pointer to the buffer that receives the data.\r
+    @param[in] bytes_to_read Number of bytes to be read.\r
+    @param[out] bytes_read Number of bytes read. Can be NULL.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return true on success and false on failure. If false is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual bool SyncRead(void* buffer,\r
+                        ULONG bytes_to_read,\r
+                        ULONG* bytes_read,\r
+                        ULONG time_out);\r
+\r
+  /** \brief Writes to opened I/O object synchronously\r
+\r
+    @param[in] buffer Pointer to the buffer containing the data to be written.\r
+    @param[in] bytes_to_write Number of bytes to be written.\r
+    @param[out] bytes_written Number of bytes written. Can be NULL.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return true on success and false on failure. If false is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual bool SyncWrite(void* buffer,\r
+                         ULONG bytes_to_write,\r
+                         ULONG* bytes_written,\r
+                         ULONG time_out);\r
+\r
+ public:\r
+  /// This is a helper for extracting object from the SdbObjectHandleMap\r
+  static SdbObjectType Type() {\r
+    return SdbObjectTypeEndpoint;\r
+  }\r
+\r
+  /// Gets parent interface \r
+  SdbInterfaceObject* parent_interface() const {\r
+    return parent_interface_;\r
+  }\r
+  /// Gets this endpoint ID\r
+  UCHAR endpoint_id() const {\r
+    return endpoint_id_;\r
+  }\r
+\r
+  /// Gets this endpoint index on the interface\r
+  UCHAR endpoint_index() const {\r
+    return endpoint_index_;\r
+  }\r
+\r
+  /// Gets parent interface handle\r
+  SDBAPIHANDLE GetParentInterfaceHandle() const {\r
+    return (NULL != parent_interface()) ? parent_interface()->sdb_handle() :\r
+                                          NULL;\r
+  }\r
+\r
+ protected:\r
+  /// Parent interface\r
+  SdbInterfaceObject* parent_interface_;\r
+\r
+  /// This endpoint id\r
+  UCHAR               endpoint_id_;\r
+\r
+  /// This endpoint index on the interface\r
+  UCHAR               endpoint_index_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_ENDPOINT_OBJECT_H__\r
diff --git a/src/sdbwinapi/sdb_helper_routines.cpp b/src/sdbwinapi/sdb_helper_routines.cpp
new file mode 100644 (file)
index 0000000..4dbff40
--- /dev/null
@@ -0,0 +1,276 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of helper routines used\r
+  in the API.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api.h"\r
+#include "sdb_api_legacy.h"\r
+#include "sdb_helper_routines.h"\r
+#include "sdb_interface_enum.h"\r
+\r
+bool GetSDKComplientParam(SdbOpenAccessType access_type,\r
+                          SdbOpenSharingMode sharing_mode,\r
+                          ULONG* desired_access,\r
+                          ULONG* desired_sharing) {\r
+  if (NULL != desired_access) {\r
+    switch (access_type) {\r
+      case SdbOpenAccessTypeReadWrite:\r
+        *desired_access = GENERIC_READ | GENERIC_WRITE;\r
+        break;\r
+\r
+      case SdbOpenAccessTypeRead:\r
+        *desired_access = GENERIC_READ;\r
+        break;\r
+\r
+      case SdbOpenAccessTypeWrite:\r
+        *desired_access = GENERIC_WRITE;\r
+        break;\r
+\r
+      case SdbOpenAccessTypeQueryInfo:\r
+        *desired_access = FILE_READ_ATTRIBUTES | FILE_READ_EA;\r
+        break;\r
+\r
+      default:\r
+        SetLastError(ERROR_INVALID_ACCESS);\r
+        return false;\r
+    }\r
+  }\r
+\r
+  if (NULL != desired_sharing) {\r
+    switch (sharing_mode) {\r
+      case SdbOpenSharingModeReadWrite:\r
+        *desired_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;\r
+        break;\r
+\r
+      case SdbOpenSharingModeRead:\r
+        *desired_sharing = FILE_SHARE_READ;\r
+        break;\r
+\r
+      case SdbOpenSharingModeWrite:\r
+        *desired_sharing = FILE_SHARE_WRITE;\r
+        break;\r
+\r
+      case SdbOpenSharingModeExclusive:\r
+        *desired_sharing = 0;\r
+        break;\r
+\r
+      default:\r
+        SetLastError(ERROR_INVALID_PARAMETER);\r
+        return false;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,\r
+                               GUID class_id,\r
+                               bool exclude_removed,\r
+                               bool active_only,\r
+                               SdbEnumInterfaceArray* interfaces) {\r
+  SdbEnumInterfaceArray tmp;\r
+  bool ret = false;\r
+\r
+  // Enumerate interfaces on this device\r
+  for (ULONG index = 0; ; index++) {\r
+    SP_DEVICE_INTERFACE_DATA interface_data;\r
+    interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);\r
+\r
+    // SetupDiEnumDeviceInterfaces() returns information about device\r
+    // interfaces exposed by one or more devices defined by our interface\r
+    // class. Each call returns information about one interface. The routine\r
+    // can be called repeatedly to get information about several interfaces\r
+    // exposed by one or more devices.\r
+    if (SetupDiEnumDeviceInterfaces(hardware_dev_info,\r
+                                    0, \r
+                                    &class_id,\r
+                                    index,\r
+                                    &interface_data)) {\r
+      // Satisfy "exclude removed" and "active only" filters.\r
+      if ((!exclude_removed || (0 == (interface_data.Flags & SPINT_REMOVED))) &&\r
+          (!active_only || (interface_data.Flags & SPINT_ACTIVE))) {\r
+        std::wstring dev_name;\r
+\r
+        if (GetUsbDeviceName(hardware_dev_info, &interface_data, &dev_name)) {\r
+          try {\r
+            // Add new entry to the array\r
+            tmp.push_back(SdbInstanceEnumEntry(dev_name.c_str(),\r
+                                               interface_data.InterfaceClassGuid,\r
+                                               interface_data.Flags));\r
+          } catch (... ) {\r
+            SetLastError(ERROR_OUTOFMEMORY);\r
+            break;\r
+          }\r
+        } else {\r
+          // Something went wrong in getting device name\r
+          break;\r
+        }\r
+      }\r
+    } else {\r
+      if (ERROR_NO_MORE_ITEMS == GetLastError()) {\r
+        // There are no more items in the list. Enum is completed.\r
+        ret = true;\r
+        break;\r
+      } else {\r
+        // Something went wrong in SDK enum\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  // On success, swap temp array with the returning one\r
+  if (ret)\r
+    interfaces->swap(tmp);\r
+\r
+  return ret;\r
+}\r
+\r
+bool EnumerateDeviceInterfaces(GUID class_id,\r
+                               ULONG flags,\r
+                               bool exclude_removed,\r
+                               bool active_only,\r
+                               SdbEnumInterfaceArray* interfaces) {\r
+  // Open a handle to the plug and play dev node.\r
+  // SetupDiGetClassDevs() returns a device information set that\r
+  // contains info on all installed devices of a specified class.\r
+  HDEVINFO hardware_dev_info =\r
+    SetupDiGetClassDevs(&class_id, NULL, NULL, flags);\r
+\r
+  bool ret = false;\r
+\r
+  if (INVALID_HANDLE_VALUE != hardware_dev_info) {\r
+    // Do the enum\r
+    ret = EnumerateDeviceInterfaces(hardware_dev_info,\r
+                                    class_id,\r
+                                    exclude_removed,\r
+                                    active_only,\r
+                                    interfaces);\r
+\r
+    // Preserve last error accross hardware_dev_info destruction\r
+    ULONG error_to_report = ret ? NO_ERROR : GetLastError();\r
+\r
+    SetupDiDestroyDeviceInfoList(hardware_dev_info);\r
+\r
+    if (NO_ERROR != error_to_report)\r
+      SetLastError(error_to_report);\r
+  }\r
+\r
+  return ret;\r
+}\r
+\r
+bool GetUsbDeviceDetails(\r
+    HDEVINFO hardware_dev_info,\r
+    PSP_DEVICE_INTERFACE_DATA dev_info_data,\r
+    PSP_DEVICE_INTERFACE_DETAIL_DATA* dev_info_detail_data) {\r
+  ULONG required_len = 0;\r
+\r
+  // First query for the structure size. At this point we expect this call\r
+  // to fail with ERROR_INSUFFICIENT_BUFFER error code.\r
+  if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,\r
+                                      dev_info_data,\r
+                                      NULL,\r
+                                      0,\r
+                                      &required_len,\r
+                                      NULL)) {\r
+    return false;\r
+  }\r
+\r
+  if (ERROR_INSUFFICIENT_BUFFER != GetLastError())\r
+    return false;\r
+\r
+  // Allocate buffer for the structure\r
+  PSP_DEVICE_INTERFACE_DETAIL_DATA buffer =\r
+    reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(required_len));\r
+\r
+  if (NULL == buffer) {\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return false;\r
+  }\r
+\r
+  buffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);\r
+\r
+  // Retrieve the information from Plug and Play.\r
+  if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,\r
+                                      dev_info_data,\r
+                                      buffer,\r
+                                      required_len,\r
+                                      &required_len,\r
+                                      NULL)) {\r
+    *dev_info_detail_data = buffer;\r
+    return true;\r
+  } else {\r
+    // Free the buffer if this call failed\r
+    free(buffer);\r
+\r
+    return false;\r
+  }\r
+}\r
+\r
+bool GetUsbDeviceName(HDEVINFO hardware_dev_info,\r
+                      PSP_DEVICE_INTERFACE_DATA dev_info_data,\r
+                      std::wstring* name) {\r
+  PSP_DEVICE_INTERFACE_DETAIL_DATA func_class_dev_data = NULL;\r
+  if (!GetUsbDeviceDetails(hardware_dev_info,\r
+                           dev_info_data,\r
+                           &func_class_dev_data)) {\r
+    return false;\r
+  }\r
+\r
+  try {\r
+    *name = func_class_dev_data->DevicePath;\r
+  } catch (...) {\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+  }\r
+\r
+  free(func_class_dev_data);\r
+\r
+  return !name->empty();\r
+}\r
+\r
+bool IsLegacyInterface(const wchar_t* interface_name) {\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name,\r
+                                        GENERIC_READ | GENERIC_WRITE,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+       printf("INVALID_HANDLE_VALUE == usb_device_handle\n");\r
+    return NULL;\r
+       }\r
+       printf("INVALID_HANDLE_VALUE != usb_device_handle\n");\r
+  // Try to issue SDB_IOCTL_GET_USB_DEVICE_DESCRIPTOR IOCTL that is supported\r
+  // by the legacy driver, but is not implemented in the WinUsb driver.\r
+  DWORD ret_bytes = 0;\r
+  USB_DEVICE_DESCRIPTOR descriptor;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             SDB_IOCTL_GET_USB_DEVICE_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &descriptor,\r
+                             sizeof(descriptor),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  // If IOCTL succeeded we've got legacy driver underneath.\r
+  return ret ? true : false;\r
+}\r
diff --git a/src/sdbwinapi/sdb_helper_routines.h b/src/sdbwinapi/sdb_helper_routines.h
new file mode 100644 (file)
index 0000000..37580d3
--- /dev/null
@@ -0,0 +1,137 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_HELPER_ROUTINES_H__\r
+#define ANDROID_USB_API_SDB_HELPER_ROUTINES_H__\r
+/** \file\r
+  This file consists of declarations of helper routines used\r
+  in the API.\r
+*/\r
+\r
+#include "sdb_api_private_defines.h"\r
+\r
+/** \brief Converts access type and share mode from our enum into\r
+  SDK - complient values.\r
+\r
+  @param[in] access_type Enumerated access type\r
+  @param[in] sharing_mode Enumerated share mode\r
+  @param[out] desired_access Will receive SDK - complient desired access\r
+         flags. This parameter can be NULL.\r
+  @param[out] desired_sharing Will receive SDK - complient share mode.\r
+         This parameter can be NULL.\r
+  @return True on success, false on failure, in which case GetLastError()\r
+          provides extended information about the error that occurred.\r
+*/\r
+bool GetSDKComplientParam(SdbOpenAccessType access_type,\r
+                          SdbOpenSharingMode sharing_mode,\r
+                          ULONG* desired_access,\r
+                          ULONG* desired_sharing);\r
+\r
+/** \brief Given the hardware device information enumerates interfaces for\r
+  this device.\r
+\r
+  @param[in] hardware_dev_info A handle to hardware device information obtained\r
+         from PnP manager via SetupDiGetClassDevs()\r
+  @param[in] class_id Device class ID how it is specified by our USB driver.\r
+  @param[in] exclude_removed If true interfaces with SPINT_REMOVED flag set\r
+         will be not included in the enumeration.\r
+  @param[in] active_only If true only active interfaces (with flag\r
+         SPINT_ACTIVE set) will be included in the enumeration.\r
+  @param[out] interfaces Upon successfull completion will consist of array of\r
+         all interfaces found for this device (matching all filters).\r
+  @return True on success, false on failure, in which case GetLastError()\r
+          provides extended information about the error that occurred.\r
+*/\r
+bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,\r
+                               GUID class_id,\r
+                               bool exclude_removed,\r
+                               bool active_only,\r
+                               SdbEnumInterfaceArray* interfaces);\r
+\r
+/** \brief Enumerates all interfaces for our device class.\r
+\r
+  This routine uses SetupDiGetClassDevs to get our device info and calls\r
+  EnumerateDeviceInterfaces to perform the enumeration.\r
+  @param[in] class_id Device class ID how it is specified by our USB driver\r
+  @param[in] flags Flags to pass to SetupDiGetClassDevs to filter devices. See\r
+         SetupDiGetClassDevs() in SDK for more info on these flags.\r
+  @param[in] exclude_removed If true interfaces with SPINT_REMOVED flag set\r
+         will be not included in the enumeration.\r
+  @param[in] active_only If true only active interfaces (with flag\r
+         SPINT_ACTIVE set) will be included in the enumeration.\r
+  @param[out] interfaces Upon successfull completion will consist of array of\r
+         all interfaces found for this device (matching all filters).\r
+  @return True on success, false on failure, in which case GetLastError()\r
+          provides extended information about the error that occurred.\r
+*/\r
+bool EnumerateDeviceInterfaces(GUID class_id,\r
+                               ULONG flags,\r
+                               bool exclude_removed,\r
+                               bool active_only,\r
+                               SdbEnumInterfaceArray* interfaces);\r
+\r
+/** \brief Given the hardware device information and data gets data details.\r
+\r
+  Given the hardware_dev_info, representing a handle to the plug and\r
+  play information, and dev_info_data, representing a specific usb device,\r
+  gets detailed data about the device (interface).\r
+  @param[in] hardware_dev_info A handle to hardware device information obtained\r
+         from PnP manager via SetupDiGetClassDevs()\r
+  @param[in] dev_info_data Device information data obtained via call to\r
+         SetupDiEnumDeviceInterfaces()\r
+  @param[out] dev_info_detail_data Upon successfull completion will consist of\r
+         the detailed data about device interface. This routine always\r
+         allocates memory for the output structure so content of this pointer\r
+         doesn't matter and will be overwritten by this routine. The caller\r
+         of this method is responsible for freeing allocated data using free()\r
+         routine.\r
+  @return True on success, false on failure, in which case GetLastError()\r
+          provides extended information about the error that occurred.\r
+*/\r
+bool GetUsbDeviceDetails(HDEVINFO hardware_dev_info,\r
+                       PSP_DEVICE_INTERFACE_DATA dev_info_data,\r
+                       PSP_DEVICE_INTERFACE_DETAIL_DATA* dev_info_detail_data);\r
+\r
+/** \brief Given the hardware device information and data gets device name.\r
+\r
+  Given the hardware_dev_info, representing a handle to the plug and\r
+  play information, and dev_info_data, representing a specific usb device,\r
+  gets device name. This routine uses GetUsbDeviceDetails to extract device\r
+  name.\r
+  @param[in] hardware_dev_info A handle to hardware device information obtained\r
+         from PnP manager via SetupDiGetClassDevs()\r
+  @param[in] dev_info_data Device information data obtained via call to\r
+         SetupDiEnumDeviceInterfaces()\r
+  @param[out] name Upon successfull completion will have name for the device.\r
+  @return True on success, false on failure, in which case GetLastError()\r
+          provides extended information about the error that occurred.\r
+*/\r
+bool GetUsbDeviceName(HDEVINFO hardware_dev_info,\r
+                      PSP_DEVICE_INTERFACE_DATA dev_info_data,\r
+                      std::wstring* name);\r
+\r
+/** \brief Checks if given interface is available via custom USB driver.\r
+\r
+  In this routine we will query the given interface with an IOCTL that should\r
+  be supported by the custom driver. If IOCTL fails, we make a conclusion that\r
+  this interface is available via WinUsb, and not via custom USB driver.\r
+  @param[in] interface_name Name of the interface to check.\r
+  @return true if interface is available via custom USB driver, or false\r
+          otherwise.\r
+*/\r
+bool IsLegacyInterface(const wchar_t* interface_name);\r
+\r
+#endif  // ANDROID_USB_API_SDB_HELPER_ROUTINES_H__\r
diff --git a/src/sdbwinapi/sdb_interface.cpp b/src/sdbwinapi/sdb_interface.cpp
new file mode 100644 (file)
index 0000000..08baa3c
--- /dev/null
@@ -0,0 +1,117 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbInterfaceObject that\r
+  encapsulates a generic interface on our USB device.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_interface.h"\r
+\r
+SdbInterfaceObject::SdbInterfaceObject(const wchar_t* interf_name)\r
+    : SdbObjectHandle(SdbObjectTypeInterface),\r
+      interface_name_(interf_name) {\r
+  ATLASSERT(NULL != interf_name);\r
+}\r
+\r
+SdbInterfaceObject::~SdbInterfaceObject() {\r
+}\r
+\r
+bool SdbInterfaceObject::GetInterfaceName(void* buffer,\r
+                                          unsigned long* buffer_char_size,\r
+                                          bool ansi) {\r
+  if (NULL == buffer_char_size) {\r
+    SetLastError(ERROR_INVALID_PARAMETER);\r
+    return false;\r
+  }\r
+\r
+  // Lets see if buffer is big enough\r
+  ULONG name_len = static_cast<ULONG>(interface_name_.length() + 1);\r
+  if ((NULL == buffer) || (*buffer_char_size < name_len)) {\r
+    *buffer_char_size = name_len;\r
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);\r
+    return false;\r
+  }\r
+\r
+  if (!ansi) {\r
+    // If user asked for wide char name just return it\r
+    wcscpy(reinterpret_cast<wchar_t*>(buffer), interface_name().c_str());\r
+    return true;\r
+  }\r
+\r
+  // We need to convert name from wide char to ansi string\r
+  int res = WideCharToMultiByte(CP_ACP,\r
+                                0,\r
+                                interface_name().c_str(),\r
+                                static_cast<int>(name_len),\r
+                                reinterpret_cast<PSTR>(buffer),\r
+                                static_cast<int>(*buffer_char_size),\r
+                                NULL,\r
+                                NULL);\r
+  return (res != 0);\r
+}\r
+\r
+bool SdbInterfaceObject::GetUsbDeviceDescriptor(USB_DEVICE_DESCRIPTOR* desc) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  if (NULL == desc) {\r
+    SetLastError(ERROR_INVALID_PARAMETER);\r
+    return false;\r
+  }\r
+\r
+  CopyMemory(desc, usb_device_descriptor(), sizeof(USB_DEVICE_DESCRIPTOR));\r
+\r
+  return true;\r
+}\r
+\r
+bool SdbInterfaceObject::GetUsbConfigurationDescriptor(\r
+    USB_CONFIGURATION_DESCRIPTOR* desc) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  if (NULL == desc) {\r
+    SetLastError(ERROR_INVALID_PARAMETER);\r
+    return false;\r
+  }\r
+\r
+  CopyMemory(desc, usb_config_descriptor(),\r
+             sizeof(USB_CONFIGURATION_DESCRIPTOR));\r
+\r
+  return true;\r
+}\r
+\r
+bool SdbInterfaceObject::GetUsbInterfaceDescriptor(\r
+    USB_INTERFACE_DESCRIPTOR* desc) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  if (NULL == desc) {\r
+    SetLastError(ERROR_INVALID_PARAMETER);\r
+    return false;\r
+  }\r
+\r
+  CopyMemory(desc, usb_interface_descriptor(), sizeof(USB_INTERFACE_DESCRIPTOR));\r
+\r
+  return true;\r
+}\r
diff --git a/src/sdbwinapi/sdb_interface.h b/src/sdbwinapi/sdb_interface.h
new file mode 100644 (file)
index 0000000..2937d4a
--- /dev/null
@@ -0,0 +1,203 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_INTERFACE_H__\r
+#define ANDROID_USB_API_SDB_INTERFACE_H__\r
+/** \file\r
+  This file consists of declaration of class SdbInterfaceObject that\r
+  encapsulates a generic interface on our USB device.\r
+*/\r
+\r
+#include "sdb_object_handle.h"\r
+\r
+// 'SdbInterfaceObject::interface_name_' : class 'std::basic_string<_E,_Tr,_A>'\r
+// needs to have dll-interface to be used by clients of class\r
+// 'SdbInterfaceObject' We're ok with that, since interface_name_ will not\r
+// be referenced by name from outside of this class.\r
+#pragma warning(disable: 4251)\r
+/** \brief Encapsulates an interface on our USB device.\r
+\r
+  This is an abstract class that implements functionality common for both,\r
+  legacy, and WinUsb based interfaces.\r
+*/\r
+class SDBWIN_API_CLASS SdbInterfaceObject : public SdbObjectHandle {\r
+ public:\r
+  /** \brief Constructs the object.\r
+    \r
+    @param[in] interf_name Name of the interface\r
+  */\r
+  explicit SdbInterfaceObject(const wchar_t* interf_name);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+   We hide destructor in order to prevent ourseves from accidentaly allocating\r
+   instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbInterfaceObject();\r
+\r
+  //\r
+  // Abstract\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets serial number for interface's device.\r
+\r
+    @param[out] buffer Buffer for the serail number string. Can be NULL in\r
+           which case buffer_char_size will contain number of characters\r
+           required for the string.\r
+    @param[in,out] buffer_char_size On the way in supplies size (in characters)\r
+           of the buffer. On the way out, if method failed and GetLastError\r
+           reports ERROR_INSUFFICIENT_BUFFER, will contain number of characters\r
+           required for the name.\r
+    @param[in] ansi If true the name will be returned as single character\r
+           string. Otherwise name will be returned as wide character string.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetSerialNumber(void* buffer,\r
+                               unsigned long* buffer_char_size,\r
+                               bool ansi) = 0;\r
+\r
+\r
+  /** \brief Gets information about an endpoint on this interface.\r
+\r
+    @param[in] endpoint_index Zero-based endpoint index. There are two\r
+           shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX\r
+           and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide infor about\r
+           (default?) bulk write and read endpoints respectively.\r
+    @param[out] info Upon successful completion will have endpoint information.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetEndpointInformation(UCHAR endpoint_index,\r
+                                      SdbEndpointInformation* info) = 0;\r
+\r
+  /** \brief Opens an endpoint on this interface.\r
+\r
+    @param[in] endpoint_index Zero-based endpoint index. There are two\r
+           shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX\r
+           and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide infor about\r
+           (default?) bulk write and read endpoints respectively.\r
+    @param[in] access_type Desired access type. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always read / write access.\r
+    @param[in] sharing_mode Desired share mode. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always shared for read / write.\r
+    @return Handle to the opened endpoint object or NULL on failure.\r
+            If NULL is returned GetLastError() provides extended information\r
+            about the error that occurred.\r
+  */\r
+  virtual SDBAPIHANDLE OpenEndpoint(UCHAR endpoint_index,\r
+                                    SdbOpenAccessType access_type,\r
+                                    SdbOpenSharingMode sharing_mode) = 0;\r
+\r
+  //\r
+  // Operations\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets interface device name.\r
+\r
+    @param[out] buffer Buffer for the name. Can be NULL in which case\r
+           buffer_char_size will contain number of characters required to fit\r
+           the name.\r
+    @param[in,out] buffer_char_size On the way in supplies size (in characters)\r
+           of the buffer. On the way out if method failed and GetLastError\r
+           reports ERROR_INSUFFICIENT_BUFFER will contain number of characters\r
+           required to fit the name.\r
+    @param[in] ansi If true the name will be returned as single character\r
+           string. Otherwise name will be returned as wide character string.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetInterfaceName(void* buffer,\r
+                                unsigned long* buffer_char_size,\r
+                                bool ansi);\r
+\r
+  /** \brief Gets device descriptor for the USB device associated with\r
+    this interface.\r
+\r
+    @param[out] desc Upon successful completion will have usb device\r
+           descriptor.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetUsbDeviceDescriptor(USB_DEVICE_DESCRIPTOR* desc);\r
+\r
+  /** \brief Gets descriptor for the selected USB device configuration.\r
+\r
+    @param[out] desc Upon successful completion will have usb device\r
+           configuration descriptor.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetUsbConfigurationDescriptor(\r
+                  USB_CONFIGURATION_DESCRIPTOR* desc);\r
+\r
+  /** \brief Gets descriptor for this interface.\r
+\r
+    @param[out] desc Upon successful completion will have interface\r
+           descriptor.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetUsbInterfaceDescriptor(USB_INTERFACE_DESCRIPTOR* desc);\r
+\r
+ public:\r
+  /// Gets name of the USB interface (device name) for this object\r
+  const std::wstring& interface_name() const {\r
+    return interface_name_;\r
+  }\r
+\r
+  /// This is a helper for extracting object from the SdbObjectHandleMap\r
+  static SdbObjectType Type() {\r
+    return SdbObjectTypeInterface;\r
+  }\r
+\r
+  /// Gets cached usb device descriptor\r
+  const USB_DEVICE_DESCRIPTOR* usb_device_descriptor() const {\r
+    return &usb_device_descriptor_;\r
+  }\r
+\r
+  /// Gets cached usb configuration descriptor\r
+  const USB_CONFIGURATION_DESCRIPTOR* usb_config_descriptor() const {\r
+    return &usb_config_descriptor_;\r
+  }\r
+\r
+  /// Gets cached usb interface descriptor\r
+  const USB_INTERFACE_DESCRIPTOR* usb_interface_descriptor() const {\r
+    return &usb_interface_descriptor_;\r
+  }\r
+\r
+ protected:\r
+  /// Cached usb device descriptor\r
+  USB_DEVICE_DESCRIPTOR         usb_device_descriptor_;\r
+\r
+  /// Cached usb configuration descriptor\r
+  USB_CONFIGURATION_DESCRIPTOR  usb_config_descriptor_;\r
+\r
+  /// Cached usb interface descriptor\r
+  USB_INTERFACE_DESCRIPTOR      usb_interface_descriptor_;\r
+\r
+ private:\r
+  /// Name of the USB interface (device name) for this object\r
+  std::wstring                  interface_name_;\r
+};\r
+#pragma warning(default: 4251)\r
+\r
+#endif  // ANDROID_USB_API_SDB_INTERFACE_H__\r
diff --git a/src/sdbwinapi/sdb_interface_enum.cpp b/src/sdbwinapi/sdb_interface_enum.cpp
new file mode 100644 (file)
index 0000000..693ae20
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of SdbInterfaceEnumObject class that\r
+  encapsulates enumerator of USB interfaces available through this API.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api.h"\r
+#include "sdb_interface_enum.h"\r
+#include "sdb_helper_routines.h"\r
+\r
+SdbInterfaceEnumObject::SdbInterfaceEnumObject()\r
+    : SdbObjectHandle(SdbObjectTypeInterfaceEnumerator) {\r
+  current_interface_ = interfaces_.begin();\r
+}\r
+\r
+SdbInterfaceEnumObject::~SdbInterfaceEnumObject() {\r
+}\r
+\r
+bool SdbInterfaceEnumObject::InitializeEnum(GUID class_id,\r
+                                            bool exclude_not_present,\r
+                                            bool exclude_removed,\r
+                                            bool active_only) {\r
+  // Calc flags for SetupDiGetClassDevs\r
+  DWORD flags = DIGCF_DEVICEINTERFACE;\r
+  if (exclude_not_present)\r
+    flags |= DIGCF_PRESENT;\r
+\r
+  // Do the enum\r
+  bool ret = EnumerateDeviceInterfaces(class_id,\r
+                                       flags,\r
+                                       exclude_removed,\r
+                                       active_only,\r
+                                       &interfaces_);\r
+\r
+  // If enum was successfull set current enum pointer\r
+  // to the beginning of the array\r
+  if (ret)\r
+    current_interface_ = interfaces_.begin();\r
+\r
+  return ret;\r
+}\r
+\r
+bool SdbInterfaceEnumObject::Next(SdbInterfaceInfo* info, ULONG* size) {\r
+  // Make sure that it's opened\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  ATLASSERT(NULL != size);\r
+  if (NULL == size) {\r
+    SetLastError(ERROR_INVALID_PARAMETER);\r
+    return false;\r
+  }\r
+\r
+  // Lets see if enum is over\r
+  if (interfaces_.end() == current_interface_) {\r
+    SetLastError(ERROR_NO_MORE_ITEMS);\r
+    return false;\r
+  }\r
+\r
+  SdbInstanceEnumEntry& entry = *current_interface_;\r
+\r
+  // Big enough?\r
+  if ((NULL == info) || (*size < entry.GetFlatSize())) {\r
+    *size = entry.GetFlatSize();\r
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);\r
+    return false;\r
+  }\r
+\r
+  // All checks passed\r
+  entry.Save(info);\r
+  current_interface_++;\r
+  return true;\r
+}\r
+\r
+bool SdbInterfaceEnumObject::Reset() {\r
+  // Make sure that it's opened\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  current_interface_ = interfaces_.begin();\r
+\r
+  return true;\r
+}\r
diff --git a/src/sdbwinapi/sdb_interface_enum.h b/src/sdbwinapi/sdb_interface_enum.h
new file mode 100644 (file)
index 0000000..4d2d634
--- /dev/null
@@ -0,0 +1,98 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_INTERFACE_ENUM_H__\r
+#define ANDROID_USB_API_SDB_INTERFACE_ENUM_H__\r
+/** \file\r
+  This file consists of declaration of SdbInterfaceEnumObject class that\r
+  encapsulates enumerator of USB interfaces available through this API.\r
+*/\r
+\r
+#include "sdb_object_handle.h"\r
+\r
+/** \brief Enumerator of USB interfaces available through this API.\r
+*/\r
+class SdbInterfaceEnumObject : public SdbObjectHandle {\r
+ public:\r
+  /** \brief Constructs the object.\r
+  */\r
+  SdbInterfaceEnumObject();\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+   We hide destructor in order to prevent ourseves from accidentaly allocating\r
+   instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbInterfaceEnumObject();\r
+\r
+ public:\r
+  /** \brief Enumerates all interfaces for the given device class.\r
+\r
+    This routine uses SetupDiGetClassDevs to get our device info and calls\r
+    EnumerateDeviceInterfaces to perform the enumeration.\r
+    @param[in] class_id Device class ID that is specified by our USB driver\r
+    @param[in] exclude_not_present If set include only those devices that are\r
+           currently present.\r
+    @param[in] exclude_removed If true interfaces with SPINT_REMOVED flag set\r
+           will be not included in the enumeration.\r
+    @param[in] active_only If true only active interfaces (with flag\r
+           SPINT_ACTIVE set) will be included in the enumeration.\r
+    @return True on success, false on failure, in which case GetLastError()\r
+            provides extended information about the error that occurred.\r
+  */\r
+  bool InitializeEnum(GUID class_id,\r
+                      bool exclude_not_present,\r
+                      bool exclude_removed,\r
+                      bool active_only);\r
+\r
+  /** \brief Gets next enumerated interface information\r
+    @param[out] info Upon successful completion will receive interface\r
+           information. Can be NULL. If it is NULL, upon return from this\r
+           method *size will have memory size required to fit this entry.\r
+    @param[in,out] size On the way in provides size of the memory buffer\r
+           addressed by info param. On the way out (only if buffer is not\r
+           big enough) will provide memory size required to fit this entry.\r
+    @return true on success, false on error. If false is returned\r
+            GetLastError() provides extended information about the error that\r
+            occurred. ERROR_INSUFFICIENT_BUFFER indicates that buffer provided\r
+            in info param was not big enough and *size specifies memory size\r
+            required to fit this entry. ERROR_NO_MORE_ITEMS indicates that\r
+            enumeration is over and there are no more entries to return.\r
+  */\r
+  bool Next(SdbInterfaceInfo* info, ULONG* size);\r
+\r
+  /** \brief Makes enumerator to start from the beginning.\r
+    @return true on success, false on error. If false is returned\r
+            GetLastError() provides extended information about the error that\r
+            occurred.\r
+  */\r
+  bool Reset();\r
+\r
+  // This is a helper for extracting object from the SdbObjectHandleMap\r
+  static SdbObjectType Type() {\r
+    return SdbObjectTypeInterfaceEnumerator;\r
+  }\r
+\r
+ protected:\r
+  /// Array of interfaces enumerated with this object\r
+  SdbEnumInterfaceArray           interfaces_;\r
+\r
+  /// Current enumerator\r
+  SdbEnumInterfaceArray::iterator current_interface_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_INTERFACE_ENUM_H__\r
diff --git a/src/sdbwinapi/sdb_io_completion.cpp b/src/sdbwinapi/sdb_io_completion.cpp
new file mode 100644 (file)
index 0000000..b8b62d4
--- /dev/null
@@ -0,0 +1,50 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbIOCompletion that\r
+  encapsulates a generic wrapper around OVERLAPPED Win32 structure\r
+  returned from asynchronous I/O requests.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_io_completion.h"\r
+\r
+SdbIOCompletion::SdbIOCompletion(SdbEndpointObject* parent_io_obj,\r
+                                 ULONG expected_trans_size,\r
+                                 HANDLE event_hndl)\r
+    : SdbObjectHandle(SdbObjectTypeIoCompletion),\r
+      expected_transfer_size_(expected_trans_size),\r
+      parent_io_object_(parent_io_obj) {\r
+  ATLASSERT(NULL != parent_io_obj);\r
+  parent_io_obj->AddRef();\r
+  ZeroMemory(&overlapped_, sizeof(overlapped_));\r
+  overlapped_.hEvent = event_hndl;\r
+}\r
+\r
+SdbIOCompletion::~SdbIOCompletion() {\r
+  parent_io_object_->Release();\r
+}\r
+\r
+bool SdbIOCompletion::IsCompleted() {\r
+  SetLastError(NO_ERROR);\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return true;\r
+  }\r
+\r
+  return HasOverlappedIoCompleted(overlapped()) ? true : false;\r
+}\r
diff --git a/src/sdbwinapi/sdb_io_completion.h b/src/sdbwinapi/sdb_io_completion.h
new file mode 100644 (file)
index 0000000..954789a
--- /dev/null
@@ -0,0 +1,133 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_IO_COMPLETION_H__\r
+#define ANDROID_USB_API_SDB_IO_COMPLETION_H__\r
+/** \file\r
+  This file consists of declaration of class SdbIOCompletion that encapsulates\r
+  a generic wrapper around OVERLAPPED Win32 structure returned from\r
+  asynchronous I/O requests.\r
+*/\r
+\r
+#include "sdb_endpoint_object.h"\r
+\r
+/** \brief Encapsulates encapsulates a generic wrapper around OVERLAPPED Win32\r
+  structure returned from asynchronous I/O requests.\r
+\r
+  This is an abstract class that implements functionality common for I/O\r
+  performed via WinUsb as well as legacy driver APIs. A handle to this object\r
+  is returned to the caller of each successful asynchronous I/O request. Just\r
+  like all other handles this handle must be closed after it's no longer\r
+  needed.\r
+*/\r
+class SDBWIN_API_CLASS SdbIOCompletion : public SdbObjectHandle {\r
+ public:\r
+  /** \brief Constructs the object\r
+    \r
+    @param[in] parent_io_obj Parent I/O object that created this instance.\r
+           Parent object will be referenced in this object's constructor and\r
+           released in the destructor.\r
+    @param[in] expected_trans_size Number of bytes expected to be transferred\r
+          with the I/O.\r
+    @param[in] event_hndl Event handle that should be signaled when I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be\r
+           used to initialize OVERLAPPED structure for this object.\r
+  */\r
+  SdbIOCompletion(SdbEndpointObject* parent_io_obj,\r
+                  ULONG expected_trans_size,\r
+                  HANDLE event_hndl);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+    We hide destructor in order to prevent ourseves from accidentaly allocating\r
+    instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbIOCompletion();\r
+\r
+  //\r
+  // Abstract\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets overlapped I/O result\r
+\r
+    @param[out] ovl_data Buffer for the copy of this object's OVERLAPPED\r
+           structure. Can be NULL.\r
+    @param[out] bytes_transferred Pointer to a variable that receives the\r
+           number of bytes that were actually transferred by a read or write\r
+           operation. See SDK doc on GetOvelappedResult for more information.\r
+           Unlike regular GetOvelappedResult call this parameter can be NULL.\r
+    @param[in] wait If this parameter is true, the method does not return\r
+           until the operation has been completed. If this parameter is false\r
+           and the operation is still pending, the method returns false and\r
+           the GetLastError function returns ERROR_IO_INCOMPLETE.\r
+    @return true if I/O has been completed or false on failure or if request\r
+           is not yet completed. If false is returned GetLastError() provides\r
+           extended error information. If GetLastError returns\r
+           ERROR_IO_INCOMPLETE it means that I/O is not yet completed.\r
+  */\r
+  virtual bool GetOvelappedIoResult(LPOVERLAPPED ovl_data,\r
+                                    ULONG* bytes_transferred,\r
+                                    bool wait) = 0;\r
+\r
+  //\r
+  // Operations\r
+  //\r
+\r
+ public:\r
+  /** \brief Checks if I/O that this object represents has completed.\r
+\r
+    @return true if I/O has been completed or false if it's still\r
+            incomplete. Regardless of the returned value, caller should\r
+            check GetLastError to validate that handle was OK.\r
+  */\r
+  virtual bool IsCompleted();\r
+\r
+ public:\r
+  /// Gets overlapped structure for this I/O\r
+  LPOVERLAPPED overlapped() {\r
+    return &overlapped_;\r
+  }\r
+\r
+  /// Gets parent object\r
+  SdbEndpointObject* parent_io_object() const {\r
+    return parent_io_object_;\r
+  }\r
+\r
+  /// Gets parent object handle\r
+  SDBAPIHANDLE GetParentObjectHandle() const {\r
+    return (NULL != parent_io_object()) ? parent_io_object()->sdb_handle() :\r
+                                          NULL;\r
+  }\r
+\r
+  // This is a helper for extracting object from the SdbObjectHandleMap\r
+  static SdbObjectType Type() {\r
+    return SdbObjectTypeIoCompletion;\r
+  }\r
+\r
+ protected:\r
+  /// Overlapped structure for this I/O\r
+  OVERLAPPED          overlapped_;\r
+\r
+  /// Parent I/O object\r
+  SdbEndpointObject*  parent_io_object_;\r
+\r
+  /// Expected number of bytes transferred in thi I/O\r
+  ULONG               expected_transfer_size_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_IO_COMPLETION_H__\r
diff --git a/src/sdbwinapi/sdb_legacy_endpoint_object.cpp b/src/sdbwinapi/sdb_legacy_endpoint_object.cpp
new file mode 100644 (file)
index 0000000..8f7d16a
--- /dev/null
@@ -0,0 +1,237 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbLegacyEndpointObject that\r
+  encapsulates a handle opened to an endpoint on our device controlled by\r
+  a custom (legacy) USB driver.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api_legacy.h"\r
+#include "sdb_legacy_endpoint_object.h"\r
+#include "sdb_legacy_io_completion.h"\r
+#include "sdb_helper_routines.h"\r
+\r
+SdbLegacyEndpointObject::SdbLegacyEndpointObject(\r
+    SdbLegacyInterfaceObject* parent_interf,\r
+    UCHAR endpoint_id,\r
+    UCHAR endpoint_index)\r
+    : SdbEndpointObject(parent_interf, endpoint_id, endpoint_index),\r
+      usb_handle_(INVALID_HANDLE_VALUE) {\r
+}\r
+\r
+SdbLegacyEndpointObject::~SdbLegacyEndpointObject() {\r
+  if (INVALID_HANDLE_VALUE != usb_handle_) {\r
+    ::CloseHandle(usb_handle_);\r
+  }\r
+}\r
+\r
+SDBAPIHANDLE SdbLegacyEndpointObject::CommonAsyncReadWrite(\r
+    bool is_read,\r
+    void* buffer,\r
+    ULONG bytes_to_transfer,\r
+    ULONG* bytes_transferred,\r
+    HANDLE event_handle,\r
+    ULONG time_out) {\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = 0;\r
+  }\r
+\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  bool is_ioctl_write = is_read ? false : (0 != time_out);\r
+\r
+  // Create completion i/o object\r
+  SdbLegacyIOCompletion* sdb_io_completion = NULL;\r
+\r
+  try {\r
+    sdb_io_completion = new SdbLegacyIOCompletion(this,\r
+                                                  bytes_to_transfer,\r
+                                                  event_handle,\r
+                                                  is_ioctl_write);\r
+  } catch (... ) {\r
+    // We don't expect exceptions other than OOM thrown here.\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return NULL;\r
+  }\r
+\r
+  // Create a handle for it\r
+  SDBAPIHANDLE ret = sdb_io_completion->CreateHandle();\r
+  ULONG transferred = 0;\r
+  if (NULL != ret) {\r
+    BOOL res = TRUE;\r
+    if (0 == time_out) {\r
+      // Go the read / write file way\r
+      res = is_read ? ReadFile(usb_handle(),\r
+                               buffer,\r
+                               bytes_to_transfer,\r
+                               &transferred,\r
+                               sdb_io_completion->overlapped()) :\r
+                      WriteFile(usb_handle(),\r
+                                buffer,\r
+                                bytes_to_transfer,\r
+                                &transferred,\r
+                                sdb_io_completion->overlapped());\r
+    } else {\r
+      // Go IOCTL way\r
+      SdbBulkTransfer transfer_param;\r
+      transfer_param.time_out = time_out;\r
+      transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;\r
+      transfer_param.SetWriteBuffer(is_read ? NULL : buffer);\r
+\r
+      res = DeviceIoControl(usb_handle(),\r
+        is_read ? SDB_IOCTL_BULK_READ : SDB_IOCTL_BULK_WRITE,\r
+        &transfer_param, sizeof(transfer_param),\r
+        is_read ? buffer : sdb_io_completion->transferred_bytes_ptr(),\r
+        is_read ? bytes_to_transfer : sizeof(ULONG),\r
+        &transferred,\r
+        sdb_io_completion->overlapped());\r
+    }\r
+\r
+    if (NULL != bytes_transferred) {\r
+      *bytes_transferred = transferred;\r
+    }\r
+\r
+    ULONG error = GetLastError();\r
+    if (!res && (ERROR_IO_PENDING != error)) {\r
+      // I/O failed immediatelly. We need to close i/o completion object\r
+      // before we return NULL to the caller.\r
+      sdb_io_completion->CloseHandle();\r
+      ret = NULL;\r
+      SetLastError(error);\r
+    }\r
+  }\r
+\r
+  // Offseting 'new'\r
+  sdb_io_completion->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool SdbLegacyEndpointObject::CommonSyncReadWrite(bool is_read,\r
+                                                  void* buffer,\r
+                                                  ULONG bytes_to_transfer,\r
+                                                  ULONG* bytes_transferred,\r
+                                                  ULONG time_out) {\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = 0;\r
+  }\r
+\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  bool is_ioctl_write = is_read ? false : (0 != time_out);\r
+\r
+  // This is synchronous I/O. Since we always open I/O items for\r
+  // overlapped I/O we're obligated to always provide OVERLAPPED\r
+  // structure to read / write routines. Prepare it now.\r
+  OVERLAPPED overlapped;\r
+  ZeroMemory(&overlapped, sizeof(overlapped));\r
+\r
+  BOOL ret = TRUE;\r
+  ULONG ioctl_write_transferred = 0;\r
+  if (0 == time_out) {\r
+    // Go the read / write file way\r
+    ret = is_read ?\r
+      ReadFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped) :\r
+      WriteFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped);\r
+  } else {\r
+    // Go IOCTL way\r
+    SdbBulkTransfer transfer_param;\r
+    transfer_param.time_out = time_out;\r
+    transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;\r
+    transfer_param.SetWriteBuffer(is_read ? NULL : buffer);\r
+\r
+    ULONG tmp;\r
+    ret = DeviceIoControl(usb_handle(),\r
+      is_read ? SDB_IOCTL_BULK_READ : SDB_IOCTL_BULK_WRITE,\r
+      &transfer_param, sizeof(transfer_param),\r
+      is_read ? buffer : &ioctl_write_transferred,\r
+      is_read ? bytes_to_transfer : sizeof(ULONG),\r
+      &tmp,\r
+      &overlapped);\r
+  }\r
+\r
+  // Lets see the result\r
+  if (!ret && (ERROR_IO_PENDING != GetLastError())) {\r
+    // I/O failed.\r
+    return false;\r
+  }\r
+\r
+  // Lets wait till I/O completes\r
+  ULONG transferred = 0;\r
+  ret = GetOverlappedResult(usb_handle(), &overlapped, &transferred, TRUE);\r
+  if (ret && (NULL != bytes_transferred)) {\r
+    *bytes_transferred = is_ioctl_write ? ioctl_write_transferred :\r
+                                          transferred;\r
+  }\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+SDBAPIHANDLE SdbLegacyEndpointObject::CreateHandle(\r
+    const wchar_t* item_path,\r
+    SdbOpenAccessType access_type,\r
+    SdbOpenSharingMode share_mode) {\r
+  // Convert access / share parameters into CreateFile - compatible\r
+  ULONG desired_access;\r
+  ULONG desired_sharing;\r
+\r
+  if (!GetSDKComplientParam(access_type, share_mode,\r
+                            &desired_access, &desired_sharing)) {\r
+    return NULL;\r
+  }\r
+\r
+  // Open USB handle\r
+  usb_handle_ = CreateFile(item_path,\r
+                           desired_access,\r
+                           share_mode,\r
+                           NULL,\r
+                           OPEN_EXISTING,\r
+                           FILE_FLAG_OVERLAPPED,  // Always overlapped!\r
+                           NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_handle_) {\r
+    return NULL;\r
+  }\r
+\r
+  // Create SDB handle\r
+  SDBAPIHANDLE ret = SdbObjectHandle::CreateHandle();\r
+\r
+  if (NULL == ret) {\r
+    // If creation of SDB handle failed we have to close USB handle too.\r
+    ULONG error = GetLastError();\r
+    ::CloseHandle(usb_handle());\r
+    usb_handle_ = INVALID_HANDLE_VALUE;\r
+    SetLastError(error);\r
+  }\r
+\r
+  return ret;\r
+}\r
+\r
+bool SdbLegacyEndpointObject::CloseHandle() {\r
+  if (INVALID_HANDLE_VALUE != usb_handle_) {\r
+    ::CloseHandle(usb_handle_);\r
+    usb_handle_ = INVALID_HANDLE_VALUE;\r
+  }\r
+\r
+  return SdbEndpointObject::CloseHandle();\r
+}\r
diff --git a/src/sdbwinapi/sdb_legacy_endpoint_object.h b/src/sdbwinapi/sdb_legacy_endpoint_object.h
new file mode 100644 (file)
index 0000000..5ae8290
--- /dev/null
@@ -0,0 +1,142 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_LEGACY_ENDPOINT_OBJECT_H__\r
+#define ANDROID_USB_API_SDB_LEGACY_ENDPOINT_OBJECT_H__\r
+/** \file\r
+  This file consists of declaration of class SdbLegacyEndpointObject that\r
+  encapsulates a handle opened to an endpoint on our device controlled by\r
+  a custom (legacy) USB driver.\r
+*/\r
+\r
+#include "sdb_endpoint_object.h"\r
+#include "sdb_legacy_interface.h"\r
+\r
+/** Encapsulates a handle opened to an endpoint on our device controlled by\r
+  a custom (legacy) USB driver.\r
+*/\r
+class SdbLegacyEndpointObject : public SdbEndpointObject {\r
+ public:\r
+  /** \brief Constructs the object\r
+\r
+    @param[in] interface Parent legacy USB interface for this object.\r
+    @param[in] endpoint_id Endpoint ID (endpoint address) on the device.\r
+    @param[in] endpoint_index Zero-based endpoint index in the interface's\r
+          array of endpoints.\r
+  */\r
+  SdbLegacyEndpointObject(SdbLegacyInterfaceObject* parent_interf,\r
+                          UCHAR endpoint_id,\r
+                          UCHAR endpoint_index);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+    We hide destructor in order to prevent ourseves from accidentaly allocating\r
+    instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbLegacyEndpointObject();\r
+\r
+  //\r
+  // Abstract overrides\r
+  //\r
+\r
+ protected:\r
+  /** \brief Common code for async read / write\r
+\r
+    @param[in] is_read Read or write selector.\r
+    @param[in,out] buffer Pointer to the buffer for read / write.\r
+    @param[in] bytes_to_transfer Number of bytes to be read / written.\r
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.\r
+    @param[in] event_handle Event handle that should be signaled when async I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be used to\r
+           initialize OVERLAPPED structure for this I/O.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return A handle to IO completion object or NULL on failure. If NULL is\r
+            returned GetLastError() provides extended error information.\r
+  */\r
+  virtual SDBAPIHANDLE CommonAsyncReadWrite(bool is_read,\r
+                                            void* buffer,\r
+                                            ULONG bytes_to_transfer,\r
+                                            ULONG* bytes_transferred,\r
+                                            HANDLE event_handle,\r
+                                            ULONG time_out);\r
+\r
+  /** \brief Common code for sync read / write\r
+\r
+    @param[in] is_read Read or write selector.\r
+    @param[in,out] buffer Pointer to the buffer for read / write.\r
+    @param[in] bytes_to_transfer Number of bytes to be read / written.\r
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.\r
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to\r
+           complete. Zero value in this parameter means that there is no\r
+           timeout set for this I/O.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool CommonSyncReadWrite(bool is_read,\r
+                                   void* buffer,\r
+                                   ULONG bytes_to_transfer,\r
+                                   ULONG* bytes_transferred,\r
+                                   ULONG time_out);\r
+\r
+  //\r
+  // Operations\r
+  //\r
+\r
+ public:\r
+  /** \brief Opens endpoint and creates a handle to this object\r
+\r
+    @param item_path[in] Path to the endpoint on our USB device.\r
+    @param access_type[in] Desired access type. In the current implementation\r
+          this parameter has no effect on the way item is opened. It's\r
+          always read / write access.\r
+    @param sharing_mode[in] Desired share mode. In the current implementation\r
+          this parameter has no effect on the way item is opened. It's\r
+          always shared for read / write.\r
+    @return A handle to this object on success or NULL on an error.\r
+            If NULL is returned GetLastError() provides extended error\r
+            information. ERROR_GEN_FAILURE is set if an attempt was\r
+            made to create already opened object.\r
+  */\r
+  virtual SDBAPIHANDLE CreateHandle(const wchar_t* item_path,\r
+                                    SdbOpenAccessType access_type,\r
+                                    SdbOpenSharingMode share_mode);\r
+\r
+\r
+  /** \brief This method is called when handle to this object gets closed.\r
+\r
+    We override this method in order to close handle to the endpoint opened\r
+    in CreateHandle method of this class.\r
+    @return true on success or false if object is already closed. If\r
+            false is returned GetLastError() provides extended error\r
+            information.\r
+  */\r
+  virtual bool CloseHandle();\r
+\r
+ public:\r
+  /// Gets handle to the endpoint opened on our USB device.\r
+  HANDLE usb_handle() const {\r
+    return usb_handle_;\r
+  }\r
+\r
+ protected:\r
+  /// Handle to the endpoint opened on our USB device.\r
+  HANDLE              usb_handle_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_LEGACY_ENDPOINT_OBJECT_H__\r
diff --git a/src/sdbwinapi/sdb_legacy_interface.cpp b/src/sdbwinapi/sdb_legacy_interface.cpp
new file mode 100644 (file)
index 0000000..3011bf7
--- /dev/null
@@ -0,0 +1,324 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbLegacyInterfaceObject\r
+  that encapsulates an interface on our USB device that is accessible\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api_legacy.h"\r
+#include "sdb_legacy_interface.h"\r
+#include "sdb_legacy_endpoint_object.h"\r
+\r
+SdbLegacyInterfaceObject::SdbLegacyInterfaceObject(const wchar_t* interf_name)\r
+    : SdbInterfaceObject(interf_name),\r
+      def_read_endpoint_(0xFF),\r
+      read_endpoint_id_(0xFF),\r
+      def_write_endpoint_(0xFF),\r
+      write_endpoint_id_(0xFF) {\r
+}\r
+\r
+SdbLegacyInterfaceObject::~SdbLegacyInterfaceObject() {\r
+}\r
+\r
+SDBAPIHANDLE SdbLegacyInterfaceObject::CreateHandle() {\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name().c_str(),\r
+                                        GENERIC_READ | GENERIC_WRITE,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+    return NULL;\r
+  }\r
+\r
+  // Now, we ensured that our usb device / interface is up and running.\r
+  // Lets collect device, interface and pipe information\r
+  bool ok = true;\r
+  if (!CacheUsbDeviceDescriptor(usb_device_handle) ||\r
+      !CacheUsbConfigurationDescriptor(usb_device_handle) ||\r
+      !CacheUsbInterfaceDescriptor(usb_device_handle)) {\r
+    ok = false;\r
+  }\r
+\r
+  // Preserve error accross handle close\r
+  ULONG error = ok ? NO_ERROR : GetLastError();\r
+\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  if (NO_ERROR != error) {\r
+    SetLastError(error);\r
+  }\r
+\r
+  if (!ok) {\r
+    return false;\r
+  }\r
+\r
+  // Save indexes and IDs for bulk read / write endpoints. We will use them to\r
+  // convert SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX and\r
+  // SDB_QUERY_BULK_READ_ENDPOINT_INDEX into actual endpoint indexes and IDs.\r
+  for (UCHAR endpoint = 0; endpoint < usb_interface_descriptor_.bNumEndpoints;\r
+       endpoint++) {\r
+    // Get endpoint information\r
+    SdbEndpointInformation pipe_info;\r
+    if (!GetEndpointInformation(endpoint, &pipe_info)) {\r
+      return false;\r
+    }\r
+\r
+    if (SdbEndpointTypeBulk == pipe_info.endpoint_type) {\r
+      // This is a bulk endpoint. Cache its index and ID.\r
+      if (0 != (pipe_info.endpoint_address & USB_ENDPOINT_DIRECTION_MASK)) {\r
+        // Use this endpoint as default bulk read endpoint\r
+        ATLASSERT(0xFF == def_read_endpoint_);\r
+        def_read_endpoint_ = endpoint;\r
+        read_endpoint_id_ = pipe_info.endpoint_address;\r
+      } else {\r
+        // Use this endpoint as default bulk write endpoint\r
+        ATLASSERT(0xFF == def_write_endpoint_);\r
+        def_write_endpoint_ = endpoint;\r
+        write_endpoint_id_ = pipe_info.endpoint_address;\r
+      }\r
+    }\r
+  }\r
+\r
+  return SdbObjectHandle::CreateHandle();\r
+}\r
+\r
+bool SdbLegacyInterfaceObject::GetSerialNumber(void* buffer,\r
+                                               unsigned long* buffer_char_size,\r
+                                               bool ansi) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name().c_str(),\r
+                                        GENERIC_READ,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+    return NULL;\r
+  }\r
+\r
+  WCHAR serial_number[512];\r
+\r
+  // Send IOCTL\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             SDB_IOCTL_GET_SERIAL_NUMBER,\r
+                             NULL, 0,\r
+                             serial_number, sizeof(serial_number),\r
+                             &ret_bytes,\r
+                             NULL);\r
+\r
+  // Preserve error accross CloseHandle\r
+  ULONG error = ret ? NO_ERROR : GetLastError();\r
+\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  if (NO_ERROR != error) {\r
+    SetLastError(error);\r
+    return false;\r
+  }\r
+\r
+  unsigned long str_len =\r
+    static_cast<unsigned long>(wcslen(serial_number) + 1);\r
+\r
+  if ((NULL == buffer) || (*buffer_char_size < str_len)) {\r
+    *buffer_char_size = str_len;\r
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);\r
+    return false;\r
+  }\r
+\r
+  if (!ansi) {\r
+    // If user asked for wide char name just return it\r
+    wcscpy(reinterpret_cast<wchar_t*>(buffer), serial_number);\r
+    return true;\r
+  }\r
+\r
+  // We need to convert name from wide char to ansi string\r
+  int res = WideCharToMultiByte(CP_ACP,\r
+                                0,\r
+                                serial_number,\r
+                                static_cast<int>(str_len),\r
+                                reinterpret_cast<PSTR>(buffer),\r
+                                static_cast<int>(*buffer_char_size),\r
+                                NULL,\r
+                                NULL);\r
+  return (res != 0);\r
+}\r
+\r
+bool SdbLegacyInterfaceObject::GetEndpointInformation(\r
+    UCHAR endpoint_index,\r
+    SdbEndpointInformation* info) {\r
+  // Open USB device for this intefface\r
+  HANDLE usb_device_handle = CreateFile(interface_name().c_str(),\r
+                                        GENERIC_READ,\r
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                                        NULL,\r
+                                        OPEN_EXISTING,\r
+                                        0,\r
+                                        NULL);\r
+  if (INVALID_HANDLE_VALUE == usb_device_handle) {\r
+    return NULL;\r
+  }\r
+\r
+  // Init ICTL param\r
+  SdbQueryEndpointInformation param;\r
+  param.endpoint_index = endpoint_index;\r
+\r
+  // Send IOCTL\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             SDB_IOCTL_GET_ENDPOINT_INFORMATION,\r
+                             &param, sizeof(param),\r
+                             info, sizeof(SdbEndpointInformation),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(SdbEndpointInformation) == ret_bytes));\r
+\r
+  // Preserve error accross CloseHandle\r
+  ULONG error = ret ? NO_ERROR : GetLastError();\r
+\r
+  ::CloseHandle(usb_device_handle);\r
+\r
+  if (NO_ERROR != error) {\r
+    SetLastError(error);\r
+  }\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+SDBAPIHANDLE SdbLegacyInterfaceObject::OpenEndpoint(\r
+    UCHAR endpoint_index,\r
+    SdbOpenAccessType access_type,\r
+    SdbOpenSharingMode sharing_mode) {\r
+  // Convert index into name and ID.\r
+  std::wstring endpoint_name;\r
+  UCHAR endpoint_id;\r
+\r
+  try {\r
+    if ((SDB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) ||\r
+        (def_read_endpoint_ == endpoint_index)) {\r
+      endpoint_name = DEVICE_BULK_READ_PIPE_NAME;\r
+      endpoint_id = read_endpoint_id_;\r
+      endpoint_index = def_read_endpoint_;\r
+    } else if ((SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) ||\r
+               (def_write_endpoint_ == endpoint_index)) {\r
+      endpoint_name = DEVICE_BULK_WRITE_PIPE_NAME;\r
+      endpoint_id = write_endpoint_id_;\r
+      endpoint_index = def_write_endpoint_;\r
+    } else {\r
+      SetLastError(ERROR_INVALID_PARAMETER);\r
+      return false;\r
+    }\r
+  } catch (...) {\r
+    // We don't expect exceptions other than OOM thrown here.\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return NULL;\r
+  }\r
+\r
+  return OpenEndpoint(endpoint_name.c_str(), endpoint_id, endpoint_index,\r
+                      access_type, sharing_mode);\r
+}\r
+\r
+SDBAPIHANDLE SdbLegacyInterfaceObject::OpenEndpoint(\r
+    const wchar_t* endpoint_name,\r
+    UCHAR endpoint_id,\r
+    UCHAR endpoint_index,\r
+    SdbOpenAccessType access_type,\r
+    SdbOpenSharingMode sharing_mode) {\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  SdbLegacyEndpointObject* sdb_endpoint = NULL;\r
+\r
+  try {\r
+    sdb_endpoint =\r
+        new SdbLegacyEndpointObject(this, endpoint_id, endpoint_index);\r
+  } catch (...) {\r
+    // We don't expect exceptions other than OOM thrown here.\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+    return NULL;\r
+  }\r
+\r
+  // Build full path to the object\r
+  std::wstring endpoint_path = interface_name();\r
+  endpoint_path += L"\\";\r
+  endpoint_path += endpoint_name;\r
+\r
+  SDBAPIHANDLE ret = sdb_endpoint->CreateHandle(endpoint_path.c_str(),\r
+                                                access_type,\r
+                                                sharing_mode);\r
+\r
+  sdb_endpoint->Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool SdbLegacyInterfaceObject::CacheUsbDeviceDescriptor(\r
+    HANDLE usb_device_handle) {\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             SDB_IOCTL_GET_USB_DEVICE_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &usb_device_descriptor_,\r
+                             sizeof(usb_device_descriptor_),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(USB_DEVICE_DESCRIPTOR) == ret_bytes));\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+bool SdbLegacyInterfaceObject::CacheUsbConfigurationDescriptor(\r
+    HANDLE usb_device_handle) {\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             SDB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &usb_config_descriptor_,\r
+                             sizeof(usb_config_descriptor_),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(USB_CONFIGURATION_DESCRIPTOR) == ret_bytes));\r
+\r
+  return ret ? true : false;\r
+}\r
+\r
+bool SdbLegacyInterfaceObject::CacheUsbInterfaceDescriptor(\r
+    HANDLE usb_device_handle) {\r
+  DWORD ret_bytes = 0;\r
+  BOOL ret = DeviceIoControl(usb_device_handle,\r
+                             SDB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR,\r
+                             NULL, 0,\r
+                             &usb_interface_descriptor_,\r
+                             sizeof(usb_interface_descriptor_),\r
+                             &ret_bytes,\r
+                             NULL);\r
+  ATLASSERT(!ret || (sizeof(USB_INTERFACE_DESCRIPTOR) == ret_bytes));\r
+\r
+  return ret ? true : false;\r
+}\r
diff --git a/src/sdbwinapi/sdb_legacy_interface.h b/src/sdbwinapi/sdb_legacy_interface.h
new file mode 100644 (file)
index 0000000..6f88669
--- /dev/null
@@ -0,0 +1,190 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_LEGACY_INTERFACE_H__\r
+#define ANDROID_USB_API_SDB_LEGACY_INTERFACE_H__\r
+/** \file\r
+  This file consists of declaration of class SdbLegacyInterfaceObject\r
+  that encapsulates an interface on our USB device that is accessible\r
+  via custom USB driver.\r
+*/\r
+\r
+#include "sdb_interface.h"\r
+\r
+/** \brief Encapsulates an interface on our USB device that is accessible\r
+  via custom USB driver.\r
+*/\r
+class SdbLegacyInterfaceObject : public SdbInterfaceObject {\r
+ public:\r
+  /** \brief Constructs the object.\r
+\r
+    @param[in] interf_name Name of the interface\r
+  */\r
+  explicit SdbLegacyInterfaceObject(const wchar_t* interf_name);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+   We hide destructor in order to prevent ourseves from accidentaly allocating\r
+   instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbLegacyInterfaceObject();\r
+\r
+  //\r
+  // Virtual overrides\r
+  //\r
+\r
+ public:\r
+  /** \brief Creates handle to this object.\r
+\r
+    In this call a handle for this object is generated and object is added\r
+    to the SdbObjectHandleMap. We override this method in order to initialize\r
+    access to the custom driver.\r
+    @return A handle to this object on success or NULL on an error.\r
+            If NULL is returned GetLastError() provides extended error\r
+            information. ERROR_GEN_FAILURE is set if an attempt was\r
+            made to create already opened object.\r
+  */\r
+  virtual SDBAPIHANDLE CreateHandle();\r
+\r
+  //\r
+  // Abstract overrides\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets serial number for interface's device.\r
+\r
+    @param[out] buffer Buffer for the serail number string. Can be NULL in\r
+           which case buffer_char_size will contain number of characters\r
+           required for the string.\r
+    @param[in,out] buffer_char_size On the way in supplies size (in characters)\r
+           of the buffer. On the way out, if method failed and GetLastError\r
+           reports ERROR_INSUFFICIENT_BUFFER, will contain number of characters\r
+           required for the name.\r
+    @param[in] ansi If true the name will be returned as single character\r
+           string. Otherwise name will be returned as wide character string.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetSerialNumber(void* buffer,\r
+                               unsigned long* buffer_char_size,\r
+                               bool ansi);\r
+\r
+  /** \brief Gets information about an endpoint on this interface.\r
+\r
+    @param[in] endpoint_index Zero-based endpoint index. There are two\r
+           shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX\r
+           and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide infor about\r
+           (default?) bulk write and read endpoints respectively.\r
+    @param[out] info Upon successful completion will have endpoint information.\r
+    @return true on success, false on failure. If false is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  virtual bool GetEndpointInformation(UCHAR endpoint_index,\r
+                                      SdbEndpointInformation* info);\r
+\r
+  /** \brief Opens an endpoint on this interface.\r
+\r
+    @param[in] endpoint_index Zero-based endpoint index. There are two\r
+           shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX\r
+           and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide infor about\r
+           (default?) bulk write and read endpoints respectively.\r
+    @param[in] access_type Desired access type. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always read / write access.\r
+    @param[in] sharing_mode Desired share mode. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always shared for read / write.\r
+    @return Handle to the opened endpoint object or NULL on failure.\r
+            If NULL is returned GetLastError() provides extended information\r
+            about the error that occurred.\r
+  */\r
+  virtual SDBAPIHANDLE OpenEndpoint(UCHAR endpoint_index,\r
+                                    SdbOpenAccessType access_type,\r
+                                    SdbOpenSharingMode sharing_mode);\r
+\r
+  //\r
+  // Internal operations\r
+  //\r
+\r
+ protected:\r
+  /** \brief Opens an endpoint on this interface.\r
+\r
+    @param[in] endpoint_name Endpoint file name.\r
+    @param[in] endpoint_id Endpoint (pipe) address on the device.\r
+    @param[in] endpoint_index Zero-based endpoint index.\r
+    @param[in] access_type Desired access type. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always read / write access.\r
+    @param[in] sharing_mode Desired share mode. In the current implementation\r
+           this parameter has no effect on the way endpoint is opened. It's\r
+           always shared for read / write.\r
+    @return Handle to the opened endpoint object or NULL on failure.\r
+            If NULL is returned GetLastError() provides extended information\r
+            about the error that occurred.\r
+  */\r
+  SDBAPIHANDLE OpenEndpoint(const wchar_t* endpoint_name,\r
+                            UCHAR endpoint_id,\r
+                            UCHAR endpoint_index,\r
+                            SdbOpenAccessType access_type,\r
+                            SdbOpenSharingMode sharing_mode);\r
+\r
+  /** \brief Caches device descriptor for the USB device associated with\r
+    this interface.\r
+\r
+    This method is called from CreateHandle method to cache some interface\r
+    information.\r
+    @param[in] usb_device_handle Handle to USB device.\r
+    @return 'true' on success, 'false' on failure. If 'false' is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  bool CacheUsbDeviceDescriptor(HANDLE usb_device_handle);\r
+\r
+  /** \brief Caches descriptor for the selected USB device configuration.\r
+\r
+    This method is called from CreateHandle method to cache some interface\r
+    information.\r
+    @param[in] usb_device_handle Handle to USB device.\r
+    @return 'true' on success, 'false' on failure. If 'false' is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  bool CacheUsbConfigurationDescriptor(HANDLE usb_device_handle);\r
+\r
+  /** \brief Caches descriptor for this interface.\r
+\r
+    This method is called from CreateHandle method to cache some interface\r
+    information.\r
+    @param[in] usb_device_handle Handle to USB device.\r
+    @return 'true' on success, 'false' on failure. If 'false' is returned\r
+            GetLastError() provides extended error information.\r
+  */\r
+  bool CacheUsbInterfaceDescriptor(HANDLE usb_device_handle);\r
+\r
+ protected:\r
+  /// Index for the default bulk read endpoint\r
+  UCHAR                         def_read_endpoint_;\r
+\r
+  /// ID for the default bulk read endpoint\r
+  UCHAR                         read_endpoint_id_;\r
+\r
+  /// Index for the default bulk write endpoint\r
+  UCHAR                         def_write_endpoint_;\r
+\r
+  /// ID for the default bulk write endpoint\r
+  UCHAR                         write_endpoint_id_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_LEGACY_INTERFACE_H__\r
diff --git a/src/sdbwinapi/sdb_legacy_io_completion.cpp b/src/sdbwinapi/sdb_legacy_io_completion.cpp
new file mode 100644 (file)
index 0000000..1cf1f8a
--- /dev/null
@@ -0,0 +1,90 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of class SdbLegacyIOCompletion that\r
+  encapsulates a wrapper around OVERLAPPED Win32 structure returned from\r
+  asynchronous I/O requests issued via legacy USB API.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_legacy_io_completion.h"\r
+\r
+SdbLegacyIOCompletion::SdbLegacyIOCompletion(\r
+    SdbLegacyEndpointObject* parent_io_obj,\r
+    ULONG expected_trans_size,\r
+    HANDLE event_hndl,\r
+    bool is_write_ctl)\r
+    : SdbIOCompletion(parent_io_obj, expected_trans_size, event_hndl),\r
+      transferred_bytes_(0),\r
+      is_write_ioctl_(is_write_ctl) {\r
+}\r
+\r
+SdbLegacyIOCompletion::~SdbLegacyIOCompletion() {\r
+}\r
+\r
+bool SdbLegacyIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data,\r
+                                                 ULONG* bytes_transferred,\r
+                                                 bool wait) {\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = 0;\r
+  }\r
+\r
+  if (!IsOpened()) {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+    return false;\r
+  }\r
+\r
+  ULONG transfer;\r
+  bool ret = GetOverlappedResult(parent_legacy_io_object()->usb_handle(),\r
+                                 overlapped(),\r
+                                 &transfer,\r
+                                 wait) ? true :\r
+                                         false;\r
+\r
+  // TODO: This is bizzare but I've seen it happening\r
+  // that GetOverlappedResult with wait set to true returns "prematurely",\r
+  // with wrong transferred bytes value and GetLastError reporting\r
+  // ERROR_IO_PENDING. So, lets give it an up to a 20 ms loop!\r
+  ULONG error = GetLastError();\r
+\r
+  if (wait && ret && (0 == transfer) && (0 != expected_transfer_size_) &&\r
+      ((ERROR_IO_INCOMPLETE == error) || (ERROR_IO_PENDING == error))) {\r
+    for (int trying = 0; trying < 10; trying++) {\r
+      Sleep(2);\r
+      ret = GetOverlappedResult(parent_legacy_io_object()->usb_handle(),\r
+                                overlapped(),\r
+                                &transfer,\r
+                                wait) ? true :\r
+                                        false;\r
+      error = GetLastError();\r
+      if (!ret || (0 != transfer) ||\r
+          ((ERROR_IO_INCOMPLETE != error) && (ERROR_IO_PENDING != error))) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (NULL != ovl_data) {\r
+    CopyMemory(ovl_data, overlapped(), sizeof(OVERLAPPED));\r
+  }\r
+\r
+  if (NULL != bytes_transferred) {\r
+    *bytes_transferred = is_write_ioctl() ? transferred_bytes_ : transfer;\r
+  }\r
+\r
+  return ret;\r
+}\r
diff --git a/src/sdbwinapi/sdb_legacy_io_completion.h b/src/sdbwinapi/sdb_legacy_io_completion.h
new file mode 100644 (file)
index 0000000..f51e5b8
--- /dev/null
@@ -0,0 +1,115 @@
+/*\r
+ * Copyright (C) 2009 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_LEGACY_IO_COMPLETION_H__\r
+#define ANDROID_USB_API_SDB_LEGACY_IO_COMPLETION_H__\r
+/** \file\r
+  This file consists of declaration of class SdbLegacyIOCompletion that\r
+  encapsulates a wrapper around OVERLAPPED Win32 structure returned from\r
+  asynchronous I/O requests issued via legacy USB API.\r
+*/\r
+\r
+#include "sdb_io_completion.h"\r
+#include "sdb_legacy_endpoint_object.h"\r
+\r
+/** \brief Encapsulates a wrapper around OVERLAPPED Win32 structure returned\r
+  from asynchronous I/O requests issued via legacy USB API.\r
+\r
+  A handle to this object is returned to the caller of each successful\r
+  asynchronous I/O request. Just like all other handles this handle\r
+  must be closed after it's no longer needed.\r
+*/\r
+class SdbLegacyIOCompletion : public SdbIOCompletion {\r
+ public:\r
+  /** \brief Constructs the object.\r
+\r
+    @param[in] parent_io_obj Parent legacy endpoint that created this\r
+           instance.\r
+    @param[in] expected_trans_size Number of bytes expected to be transferred\r
+          with the I/O.\r
+    @param[in] event_hndl Event handle that should be signaled when I/O\r
+           completes. Can be NULL. If it's not NULL this handle will be\r
+           used to initialize OVERLAPPED structure for this object.\r
+    @param[in] is_write_ctl Flag indicating whether or not this completion\r
+           object is created for SDB_IOCTL_BULK_WRITE I/O.\r
+  */\r
+  SdbLegacyIOCompletion(SdbLegacyEndpointObject* parent_io_obj,\r
+                        ULONG expected_trans_size,\r
+                        HANDLE event_hndl,\r
+                        bool is_write_ctl);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+    We hide destructor in order to prevent ourseves from accidentaly allocating\r
+    instances on the stack. If such attemp occur, compiler will error.\r
+  */\r
+  virtual ~SdbLegacyIOCompletion();\r
+\r
+  //\r
+  // Abstract overrides\r
+  //\r
+\r
+ public:\r
+  /** \brief Gets overlapped I/O result\r
+\r
+    This method uses GetOverlappedResult to get results of the overlapped I/O\r
+    operation.\r
+    @param[out] ovl_data Buffer for the copy of this object's OVERLAPPED\r
+           structure. Can be NULL.\r
+    @param[out] bytes_transferred Pointer to a variable that receives the\r
+           number of bytes that were actually transferred by a read or write\r
+           operation. See SDK doc on GetOvelappedResult for more information.\r
+           Unlike regular GetOvelappedResult call this parameter can be NULL.\r
+    @param[in] wait If this parameter is true, the method does not return\r
+           until the operation has been completed. If this parameter is false\r
+           and the operation is still pending, the method returns false and\r
+           the GetLastError function returns ERROR_IO_INCOMPLETE.\r
+    @return true if I/O has been completed or false on failure or if request\r
+           is not yet completed. If false is returned GetLastError() provides\r
+           extended error information. If GetLastError returns\r
+           ERROR_IO_INCOMPLETE it means that I/O is not yet completed.\r
+  */\r
+  virtual bool GetOvelappedIoResult(LPOVERLAPPED ovl_data,\r
+                                    ULONG* bytes_transferred,\r
+                                    bool wait);\r
+\r
+ public:\r
+  /// Gets parent legacy endpoint.\r
+  SdbLegacyEndpointObject* parent_legacy_io_object() const {\r
+    return reinterpret_cast<SdbLegacyEndpointObject*>(parent_io_object());\r
+  }\r
+\r
+  /// Gets write IOCTL flag.\r
+  bool is_write_ioctl() const {\r
+    return is_write_ioctl_;\r
+  }\r
+\r
+  /// Gets address for SDB_IOCTL_BULK_WRITE output buffer.\r
+  ULONG* transferred_bytes_ptr() {\r
+    ATLASSERT(is_write_ioctl());\r
+    return &transferred_bytes_;\r
+  }\r
+\r
+ protected:\r
+  /// Recepient for number of transferred bytes in write IOCTL.\r
+  ULONG         transferred_bytes_;\r
+\r
+  /// Write IOCTL flag.\r
+  bool          is_write_ioctl_;\r
+};\r
+\r
+#endif  // ANDROID_USB_API_SDB_LEGACY_IO_COMPLETION_H__\r
diff --git a/src/sdbwinapi/sdb_object_handle.cpp b/src/sdbwinapi/sdb_object_handle.cpp
new file mode 100644 (file)
index 0000000..256a5be
--- /dev/null
@@ -0,0 +1,167 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  This file consists of implementation of a class SdbObjectHandle that\r
+  encapsulates an internal API object that is visible to the outside\r
+  of the API through a handle.\r
+*/\r
+\r
+#include "stdafx.h"\r
+#include "sdb_api.h"\r
+#include "sdb_object_handle.h"\r
+\r
+/// Global SDBAPIHANDLE -> SdbObjectHandle* map\r
+SdbObjectHandleMap      the_map;\r
+\r
+/// Locker for the SdbObjectHandleMap instance\r
+CComAutoCriticalSection the_map_locker;\r
+\r
+/// Next sdb handle value generator\r
+ULONG_PTR               next_sdb_handle_value = 0;\r
+\r
+SdbObjectHandle::SdbObjectHandle(SdbObjectType obj_type)\r
+    : sdb_handle_(NULL),\r
+      object_type_(obj_type),\r
+      ref_count_(1) {\r
+  ATLASSERT(obj_type < SdbObjectTypeMax);\r
+}\r
+\r
+SdbObjectHandle::~SdbObjectHandle() {\r
+  ATLASSERT(0 == ref_count_);\r
+  ATLASSERT(NULL == sdb_handle_);\r
+}\r
+\r
+LONG SdbObjectHandle::AddRef() {\r
+  ATLASSERT(ref_count_ > 0);\r
+  return InterlockedIncrement(&ref_count_);\r
+}\r
+\r
+LONG SdbObjectHandle::Release() {\r
+  ATLASSERT(ref_count_ > 0);\r
+  LONG ret = InterlockedDecrement(&ref_count_);\r
+  ATLASSERT(ret >= 0);\r
+  if (0 == ret) {\r
+    LastReferenceReleased();\r
+    delete this;\r
+  }\r
+  return ret;\r
+}\r
+\r
+SDBAPIHANDLE SdbObjectHandle::CreateHandle() {\r
+  SDBAPIHANDLE ret = NULL;\r
+\r
+  // We have to hold this lock while we're dealing with the handle\r
+  // and the table\r
+  the_map_locker.Lock();\r
+  \r
+  ATLASSERT(!IsOpened());\r
+\r
+  if (!IsOpened()) {\r
+    try {\r
+      // Generate next handle value\r
+      next_sdb_handle_value++;\r
+      ret = reinterpret_cast<SDBAPIHANDLE>(next_sdb_handle_value);\r
+\r
+      // Add ourselves to the map\r
+      the_map[ret] = this;\r
+\r
+      // Save handle, addref and return\r
+      sdb_handle_ = ret;\r
+      AddRef();\r
+    } catch (...) {\r
+      ret = NULL;\r
+      SetLastError(ERROR_OUTOFMEMORY);\r
+    }\r
+  } else {\r
+    // Signaling that this object is already opened\r
+    SetLastError(ERROR_GEN_FAILURE);\r
+  }\r
+\r
+  the_map_locker.Unlock();\r
+\r
+  return ret;\r
+}\r
+\r
+bool SdbObjectHandle::CloseHandle() {\r
+  bool ret = false;\r
+\r
+  // Addref just in case that last reference to this object is being\r
+  // held in the map\r
+  AddRef();\r
+\r
+  the_map_locker.Lock();\r
+  \r
+  ATLASSERT(IsOpened());\r
+\r
+  if (IsOpened()) {\r
+    try {\r
+      // Look us up in the map.\r
+      SdbObjectHandleMap::iterator found = the_map.find(sdb_handle());\r
+      ATLASSERT((found != the_map.end()) && (this == found->second));\r
+\r
+      if ((found != the_map.end()) && (this == found->second)) {\r
+        // Remove ourselves from the map, close and release the object\r
+        the_map.erase(found);\r
+        sdb_handle_ = NULL;\r
+        Release();\r
+        ret = true;\r
+      } else {\r
+        SetLastError(ERROR_INVALID_HANDLE);\r
+      }\r
+    } catch (...) {\r
+      ret = false;\r
+      SetLastError(ERROR_OUTOFMEMORY);\r
+    }\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+  }\r
+\r
+  the_map_locker.Unlock();\r
+\r
+  Release();\r
+\r
+  return ret;\r
+}\r
+\r
+bool SdbObjectHandle::IsObjectOfType(SdbObjectType obj_type) const {\r
+  return (obj_type == object_type());\r
+}\r
+\r
+void SdbObjectHandle::LastReferenceReleased() {\r
+  ATLASSERT(!IsOpened());\r
+}\r
+\r
+SdbObjectHandle* SdbObjectHandle::Lookup(SDBAPIHANDLE sdb_hndl) {\r
+  SdbObjectHandle* ret = NULL;\r
+\r
+  the_map_locker.Lock();\r
+\r
+  try {\r
+    // Look us up in the map.\r
+    SdbObjectHandleMap::iterator found = the_map.find(sdb_hndl);\r
+    if (found != the_map.end()) {\r
+      ret = found->second;\r
+      ret->AddRef();\r
+    }\r
+  } catch (...) {\r
+    SetLastError(ERROR_OUTOFMEMORY);\r
+  }\r
+\r
+  the_map_locker.Unlock();\r
+\r
+  return ret;\r
+}\r
diff --git a/src/sdbwinapi/sdb_object_handle.h b/src/sdbwinapi/sdb_object_handle.h
new file mode 100644 (file)
index 0000000..c46690d
--- /dev/null
@@ -0,0 +1,212 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDB_OBJECT_HANDLE_H__\r
+#define ANDROID_USB_API_SDB_OBJECT_HANDLE_H__\r
+/** \file\r
+  This file consists of declaration of a class SdbObjectHandle that\r
+  encapsulates an internal API object that is visible to the outside\r
+  of the API through a handle.\r
+*/\r
+\r
+#include "sdb_api.h"\r
+#include "sdb_api_private_defines.h"\r
+\r
+/** \brief Defines types of internal API objects\r
+*/\r
+enum SdbObjectType {\r
+  /// Object is SdbInterfaceEnumObject.\r
+  SdbObjectTypeInterfaceEnumerator,\r
+\r
+  /// Object is SdbInterfaceObject.\r
+  SdbObjectTypeInterface,\r
+\r
+  /// Object is SdbEndpointObject.\r
+  SdbObjectTypeEndpoint,\r
+\r
+  /// Object is SdbIOCompletion.\r
+  SdbObjectTypeIoCompletion,\r
+\r
+  SdbObjectTypeMax\r
+};\r
+\r
+/** \brief Encapsulates an internal API basic object that is visible to the\r
+  outside of the API through a handle.\r
+  \r
+  In order to prevent crashes when API client tries to access an object through\r
+  an invalid or already closed handle, we keep track of all opened handles in\r
+  SdbObjectHandleMap that maps association between valid SDBAPIHANDLE and\r
+  an object that this handle represents. All objects that are exposed to the\r
+  outside of API via SDBAPIHANDLE are self-destructing referenced objects.\r
+  The reference model for these objects is as such:\r
+  1. When CreateHandle() method is called on an object, a handle (SDBAPIHANDLE\r
+     that is) is assigned to it, a pair <handle, object> is added to the global\r
+     SdbObjectHandleMap instance, object is referenced and then handle is\r
+     returned to the API client.\r
+  2. Every time API is called with a handle, a lookup is performed in \r
+     SdbObjectHandleMap to find an object that is associated with the handle.\r
+     If object is not found then ERROR_INVALID_HANDLE is immediatelly returned\r
+     (via SetLastError() call). If object is found then it is referenced and\r
+     API call is dispatched to appropriate method of the found object. Upon\r
+     return from this method, just before returning from the API call, object\r
+     is dereferenced back to match lookup reference.\r
+  3. When object handle gets closed, assuming object is found in the map, that\r
+     <handle, object> pair is deleted from the map and object's refcount is\r
+     decremented to match refcount increment performed when object has been\r
+     added to the map.\r
+  4. When object's refcount drops to zero, the object commits suicide by\r
+     calling "delete this".\r
+  All API objects that have handles that are sent back to API client must be\r
+  derived from this class.\r
+*/\r
+class SDBWIN_API_CLASS SdbObjectHandle {\r
+ public:\r
+  /** \brief Constructs the object\r
+\r
+    Refernce counter is set to 1 in the constructor.\r
+    @param[in] obj_type Object type from SdbObjectType enum\r
+  */\r
+  explicit SdbObjectHandle(SdbObjectType obj_type);\r
+\r
+ protected:\r
+  /** \brief Destructs the object.\r
+\r
+   We hide destructor in order to prevent ourseves from accidentaly allocating\r
+   instances on the stack. If such attempt occurs, compiler will error.\r
+  */\r
+  virtual ~SdbObjectHandle();\r
+\r
+ public:\r
+  /** \brief References the object.\r
+\r
+    @return Value of the reference counter after object is referenced in this\r
+            method.\r
+  */\r
+  virtual LONG AddRef();\r
+\r
+  /** \brief Releases the object.\r
+\r
+    If refcount drops to zero as the result of this release, the object is\r
+    destroyed in this method. As a general rule, objects must not be touched\r
+    after this method returns even if returned value is not zero.\r
+    @return Value of the reference counter after object is released in this\r
+            method.\r
+  */\r
+  virtual LONG Release();\r
+\r
+  /** \brief Creates handle to this object.\r
+\r
+    In this call a handle for this object is generated and object is added\r
+    to the SdbObjectHandleMap.\r
+    @return A handle to this object on success or NULL on an error.\r
+            If NULL is returned GetLastError() provides extended error\r
+            information. ERROR_GEN_FAILURE is set if an attempt was\r
+            made to create already opened object.\r
+  */\r
+  virtual SDBAPIHANDLE CreateHandle();\r
+\r
+  /** \brief This method is called when handle to this object gets closed.\r
+\r
+    In this call object is deleted from the SdbObjectHandleMap.\r
+    @return true on success or false if object is already closed. If\r
+            false is returned GetLastError() provides extended error\r
+            information.\r
+  */\r
+  virtual bool CloseHandle();\r
+\r
+  /** \brief Checks if this object is of the given type.\r
+\r
+    @param[in] obj_type One of the SdbObjectType types to check\r
+    @return true is this object type matches obj_type, or false otherwise.\r
+  */\r
+  virtual bool IsObjectOfType(SdbObjectType obj_type) const;\r
+\r
+  /** \brief Looks up SdbObjectHandle instance associated with the given handle\r
+    in the SdbObjectHandleMap.\r
+\r
+    This method increments reference counter for the returned found object.\r
+    @param[in] sdb_handle SDB handle to the object\r
+    @return API object associated with the handle or NULL if object is not\r
+            found. If NULL is returned GetLastError() provides extended error\r
+            information.\r
+  */\r
+  static SdbObjectHandle* Lookup(SDBAPIHANDLE sdb_handle);\r
+\r
+ protected:\r
+  /** \brief Called when last reference to this object is released.\r
+\r
+    Derived object should override this method to perform cleanup that is not\r
+    suitable for destructors.\r
+  */\r
+  virtual void LastReferenceReleased();\r
+\r
+ public:\r
+  /// Gets SDB handle associated with this object\r
+  SDBAPIHANDLE sdb_handle() const {\r
+    return sdb_handle_;\r
+  }\r
+\r
+  /// Gets type of this object\r
+  SdbObjectType object_type() const {\r
+    return object_type_;\r
+  }\r
+\r
+  /// Checks if object is still opened. Note that it is not guaranteed that\r
+  /// object remains opened when this method returns.\r
+  bool IsOpened() const {\r
+    return (NULL != sdb_handle());\r
+  }\r
+\r
+ protected:\r
+  /// API handle associated with this object\r
+  SDBAPIHANDLE  sdb_handle_;\r
+\r
+  /// Type of this object\r
+  SdbObjectType object_type_;\r
+\r
+  /// This object's reference counter\r
+  LONG          ref_count_;\r
+};\r
+\r
+/// Maps SDBAPIHANDLE to associated SdbObjectHandle object\r
+typedef std::map< SDBAPIHANDLE, SdbObjectHandle* > SdbObjectHandleMap;\r
+\r
+/** \brief Template routine that unifies extracting of objects of different\r
+  types from the SdbObjectHandleMap\r
+\r
+  @param[in] sdb_handle API handle for the object\r
+  @return Object associated with the handle or NULL on error. If NULL is\r
+          returned GetLastError() provides extended error information.\r
+*/\r
+template<class obj_class>\r
+obj_class* LookupObject(SDBAPIHANDLE sdb_handle) {\r
+  // Lookup object for the handle in the map\r
+  SdbObjectHandle* sdb_object = SdbObjectHandle::Lookup(sdb_handle);\r
+  if (NULL != sdb_object) {\r
+    // Make sure it's of the correct type\r
+    if (!sdb_object->IsObjectOfType(obj_class::Type())) {\r
+      sdb_object->Release();\r
+      sdb_object = NULL;\r
+      SetLastError(ERROR_INVALID_HANDLE);\r
+    }\r
+  } else {\r
+    SetLastError(ERROR_INVALID_HANDLE);\r
+  }\r
+  return (sdb_object != NULL) ? reinterpret_cast<obj_class*>(sdb_object) :\r
+                                NULL;\r
+}\r
+\r
+#endif  // ANDROID_USB_API_SDB_OBJECT_HANDLE_H__\r
diff --git a/src/sdbwinapi/sdb_winusb_api.h b/src/sdbwinapi/sdb_winusb_api.h
new file mode 100644 (file)
index 0000000..d3b2525
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef ANDROID_USB_API_SDBWINUSBAPI_H__\r
+#define ANDROID_USB_API_SDBWINUSBAPI_H__\r
+\r
+/** \file\r
+  Contains declarations required to link SdbWinApi and SdbWinUsbApi DLLs.\r
+*/\r
+\r
+/** \brief Function prototype for InstantiateWinUsbInterface routine exported\r
+  from SdbWinUsbApi.dll\r
+\r
+  In order to provide backward compatibility with the systems that still run\r
+  legacy (custom) USB drivers, and have not installed WINUSB.DLL we need to\r
+  split functionality of our SDB API on Windows between two DLLs: SdbWinApi,\r
+  and SdbWinUsbApi. SdbWinApi is fully capable of working on top of the legacy\r
+  driver, but has no traces to WinUsb. SdbWinUsbApi is capable of working on\r
+  top of WinUsb API. We are forced to do this split, because we can have\r
+  dependency on WINUSB.DLL in the DLL that implements legacy API. The problem\r
+  is that customers may have a legacy driver that they don't want to upgrade\r
+  to WinUsb, so they may not have WINUSB.DLL installed on their machines, but\r
+  they still must be able to use SDB. So, the idea behind the split is as\r
+  such. When SdbWinApi.dll is loaded into a process, it will check WINUSB.DLL\r
+  installation (by checking existance of C:\Windows\System32\winusb.dll). If\r
+  WINUSB.DLL is installed, SdbWinApi will also load SdbWinUsbApi.dll (by\r
+  calling LoadLibrary), and will extract address of InstantiateWinUsbInterface\r
+  routine exported from SdbWinUsbApi.dll. Then this routine will be used to\r
+  instantiate SdbInterfaceObject instance on condition that it is confirmed\r
+  that USB driver underneath us is in deed WinUsb.\r
+*/\r
+typedef class SdbInterfaceObject* \\r
+    (__cdecl *PFN_INSTSDBWINUSBINTERFACE)(const wchar_t*);\r
+\r
+#endif  // ANDROID_USB_API_SDBWINUSBAPI_H__\r
diff --git a/src/sdbwinapi/stdafx.cpp b/src/sdbwinapi/stdafx.cpp
new file mode 100644 (file)
index 0000000..a2701f6
--- /dev/null
@@ -0,0 +1,21 @@
+/*\r
+ * Copyright (C) 2008 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+// stdafx.cpp : source file that includes just the standard includes\r
+// SdbWinApi.pch will be the pre-compiled header\r
+// stdafx.obj will contain the pre-compiled type information\r
+\r
+#include "stdafx.h"\r
diff --git a/src/sdbwinapi/stdafx.h b/src/sdbwinapi/stdafx.h
new file mode 100644 (file)
index 0000000..d57bec7
--- /dev/null
@@ -0,0 +1,79 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/** \file\r
+  Visual Studio generated include file for standard system include files, or\r
+  project specific include files that are used frequently, but are changed\r
+  infrequently.\r
+*/\r
+\r
+#pragma once\r
+\r
+#ifndef STRICT\r
+#define STRICT\r
+#endif\r
+\r
+// Modify the following defines if you have to target a platform prior to the ones specified below.\r
+// Refer to MSDN for the latest info on corresponding values for different platforms.\r
+#ifndef WINVER                         // Allow use of features specific to Windows 95 and Windows NT 4 or later.\r
+#define WINVER 0x0500          // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.\r
+#endif\r
+\r
+#ifndef _WIN32_WINNT           // Allow use of features specific to Windows NT 4 or later.\r
+#define _WIN32_WINNT 0x0500    // Change this to the appropriate value to target Windows 2000 or later.\r
+#endif                                         \r
+\r
+#ifndef _WIN32_WINDOWS         // Allow use of features specific to Windows 98 or later.\r
+#define _WIN32_WINDOWS 0x0500 // Change this to the appropriate value to target Windows Me or later.\r
+#endif\r
+\r
+#ifndef _WIN32_IE                      // Allow use of features specific to IE 4.0 or later.\r
+#define _WIN32_IE 0x0501       // Change this to the appropriate value to target IE 5.0 or later.\r
+#endif\r
+\r
+// These defines prevent the MS header files from ejecting #pragma comment\r
+// statements with the manifest information of the used ATL, STL, and CRT\r
+#define _ATL_NOFORCE_MANIFEST\r
+#define _STL_NOFORCE_MANIFEST\r
+#define _CRT_NOFORCE_MANIFEST\r
+\r
+#define _ATL_APARTMENT_THREADED\r
+#define _ATL_NO_AUTOMATIC_NAMESPACE\r
+\r
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS     // some CString constructors will be explicit\r
+\r
+// turns off ATL's hiding of some common and often safely ignored warning messages\r
+#define _ATL_ALL_WARNINGS\r
+\r
+// #define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\r
+\r
+#include <windows.h>\r
+#pragma warning(disable: 4702)\r
+#pragma warning(disable: 4201)\r
+#include <atlbase.h>\r
+#include <winioctl.h>\r
+#include <setupapi.h>\r
+#include <vector>\r
+#include <map>\r
+#include <string>\r
+#pragma warning(default: 4201)\r
+#pragma warning(disable: 4200)\r
+#include <usbdi.h>\r
+#include <usb100.h>\r
+\r
+#include "resource.h"\r
+\r
+using namespace ATL;\r
diff --git a/src/sdbwinusbapi/BUILDME.TXT b/src/sdbwinusbapi/BUILDME.TXT
new file mode 100644 (file)
index 0000000..b130472
--- /dev/null
@@ -0,0 +1,7 @@
+In order to build SdbWinUsbApi.dll you will need to install Windows Driver Kit,
+which can be obtained from Microsoft. Assuming that WDK is installed, you
+need to set one of the WDK's build environments, "cd" back into this directory,
+and execute "build -cbeEIFZ" to clean and rebuild this project, or you can
+execute "build -befEIF" to do a minimal build.
+Note that you need to build SdbWinApi.dll (..\api) before you build
+SdbWinUsbApi.dll, as it depends on SdbWinApi.lib library.
diff --git a/src/sdbwinusbapi/MAKEFILE b/src/sdbwinusbapi/MAKEFILE
new file mode 100644 (file)
index 0000000..87a1295
--- /dev/null
@@ -0,0 +1,22 @@
+#
+#  Copyright (C) 2009 The Android Open Source Project
+# 
+#  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.
+#
+
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/src/sdbwinusbapi/Resource.h b/src/sdbwinusbapi/Resource.h
new file mode 100644 (file)
index 0000000..7d883c7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by SdbWinApi.rc
+//
+
+#define IDS_PROJNAME                    100
+#define IDR_SDBWINAPI  101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        201
+#define _APS_NEXT_COMMAND_VALUE         32768
+#define _APS_NEXT_CONTROL_VALUE         201
+#define _APS_NEXT_SYMED_VALUE           102
+#endif
+#endif
diff --git a/src/sdbwinusbapi/SOURCES b/src/sdbwinusbapi/SOURCES
new file mode 100644 (file)
index 0000000..90be2c1
--- /dev/null
@@ -0,0 +1,91 @@
+#
+#  Copyright (C) 2009 The Android Open Source Project
+# 
+#  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.
+#
+
+TARGETNAME = SdbWinUsbApi
+TARGETPATH = obj
+TARGETTYPE = DYNLINK
+
+UMTYPE = windows
+DLLDEF = SdbWinUsbApi.def
+
+# Use statically linked atl libraries:
+# - atls.lib for free build
+# - atlsd.lib for checked build
+USE_STATIC_ATL  = 1
+# Use ATL v. 7.1
+ATL_VER         = 71
+# Use STL v. 6.0
+USE_STL         = 1
+STL_VER         = 60
+# Use multithreaded libraries
+USE_LIBCMT      = 1
+
+# Include directories
+INCLUDES = $(DDK_INC_PATH);           \
+           $(SDK_INC_PATH);           \
+           $(CRT_INC_PATH);           \
+           $(SDK_INC_PATH)\crt;       \
+           $(CRT_INC_PATH)\atl71;     \
+           $(SDK_INC_PATH)\crt\stl60
+
+# Common target libraries
+TARGETLIBS = $(SDK_LIB_PATH)\ole32.lib    \
+             $(SDK_LIB_PATH)\Advapi32.lib \
+             $(SDK_LIB_PATH)\Kernel32.lib \
+             $(SDK_LIB_PATH)\User32.lib   \
+             $(SDK_LIB_PATH)\oleaut32.lib \
+             $(SDK_LIB_PATH)\wbemuuid.lib \
+             $(SDK_LIB_PATH)\uuid.lib     \
+             $(SDK_LIB_PATH)\setupapi.lib \
+             $(SDK_LIB_PATH)\usbd.lib     \
+             $(SDK_LIB_PATH)\winusb.lib   \
+             ..\sdbwinapi\obj$(BUILD_ALT_DIR)\i386\SdbWinApi.lib
+
+!IF "$(DDKBUILDENV)" == "fre"
+# Libraries for release (free) builds
+TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atls.lib
+!ELSE
+# Libraries for debug (checked) builds
+TARGETLIBS = $(TARGETLIBS) $(ATL_LIB_PATH)\atlsd.lib
+!ENDIF
+
+# Common C defines
+C_DEFINES= $(C_DEFINES) -DSDBWINUSB_EXPORTS -D_UNICODE \
+           -DUNICODE -DWIN32 -D_WINDOWS -D_USRDLL -D_WINDLL
+
+!IF "$(DDKBUILDENV)" == "fre"
+# C defines for release (free) builds
+C_DEFINES = $(C_DEFINES) -DNDEBUG
+!ELSE
+# C defines for debug (checked) builds
+C_DEFINES = $(C_DEFINES) -D_DEBUG
+!ENDIF
+
+# Turn on all warnings, and treat warnings as errors
+MSC_WARNING_LEVEL = /W4 /Wp64 /WX
+# Common C defines
+USER_C_FLAGS = $(USER_C_FLAGS) /FD /EHsc /wd4100 /wd4200 /wd4702 /nologo
+# Set precompiled header information
+PRECOMPILED_CXX = 1
+PRECOMPILED_INCLUDE = stdafx.h
+PRECOMPILED_SOURCEFILE = stdafx.cpp
+
+# Define source files for SdbWinUsbApi.dll
+SOURCES = sdb_winusb_endpoint_object.cpp  \
+          sdb_winusb_interface.cpp        \
+          sdb_winusb_io_completion.cpp    \
+          SdbWinUsbApi.cpp                \
+                     SdbWinUsbApi.rc
diff --git a/src/sdbwinusbapi/SdbWinUsbApi.cpp b/src/sdbwinusbapi/SdbWinUsbApi.cpp
new file mode 100644 (file)
index 0000000..e656e94
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+// SdbWinUsbApi.cpp : Implementation of DLL Exports.
+
+#include "stdafx.h"
+#include "sdb_winusb_interface.h"
+
+class CSdbWinApiModule : public CAtlDllModuleT< CSdbWinApiModule > {
+public:
+};
+
+CSdbWinApiModule _AtlModule;
+
+// DLL Entry Point
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance,
+                               DWORD reason,
+                               LPVOID reserved) {
+    return _AtlModule.DllMain(reason, reserved);
+}
+
+/** \brief Instantiates interface instance that uses WinUsb API to communicate
+  with USB driver.
+
+  This is the only exported routine from this DLL. This routine instantiates an
+  object of SdbWinUsbInterfaceObject on request from SdbWinApi.dll when it is
+  detected that underlying USB driver is WinUsb.sys.
+  @param[in] interface_name Name of the interface.
+  @return SdbInterfaceObject - casted instance of SdbWinUsbInterfaceObject
+          object on success, or NULL on failure with GetLastError providing
+          information on an error that occurred.
+*/
+extern "C" __declspec(dllexport)
+SdbInterfaceObject* __cdecl InstantiateSdbWinUsbInterface(
+    const wchar_t* interface_name) {
+    // Validate parameter.
+    if (NULL == interface_name) {
+        return NULL;
+    }
+
+    // Instantiate requested object.
+    try {
+        return new SdbWinUsbInterfaceObject(interface_name);
+    } catch (...) {
+        // We expect only OOM exceptions here.
+        SetLastError(ERROR_OUTOFMEMORY);
+        return NULL;
+    }
+}
diff --git a/src/sdbwinusbapi/SdbWinUsbApi.def b/src/sdbwinusbapi/SdbWinUsbApi.def
new file mode 100644 (file)
index 0000000..06aac0b
--- /dev/null
@@ -0,0 +1,5 @@
+; SdbWinUsbApi.def : Declares the module parameters.
+
+LIBRARY      "SdbWinUsbApi.DLL"
+
+EXPORTS
diff --git a/src/sdbwinusbapi/SdbWinUsbApi.rc b/src/sdbwinusbapi/SdbWinUsbApi.rc
new file mode 100644 (file)
index 0000000..d19be52
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+//Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#include ""winres.h""\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 2,0,0,0
+ PRODUCTVERSION 2,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "Google, inc"
+            VALUE "FileDescription", "Android SDB API (WinUsb)"
+            VALUE "FileVersion", "2.0.0.0"
+            VALUE "LegalCopyright", "Copyright (C) 2006 The Android Open Source Project"
+            VALUE "InternalName", "SdbWinUsbApi.dll"
+            VALUE "OriginalFilename", "SdbWinUsbApi.dll"
+            VALUE "ProductName", "Android SDK"
+            VALUE "ProductVersion", "2.0.0.0"
+            VALUE "OLESelfRegister", ""
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+               VALUE "Translation", 0x0409, 1252
+    END
+END
+
+#endif    // !_MAC
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+       IDS_PROJNAME                                    "SdbWinUsbApi"
+END
+
+////////////////////////////////////////////////////////////////////////////
+
+
+#endif
+
+#ifndef APSTUDIO_INVOKED
+#endif    // not APSTUDIO_INVOKED
diff --git a/src/sdbwinusbapi/sdb_winusb_endpoint_object.cpp b/src/sdbwinusbapi/sdb_winusb_endpoint_object.cpp
new file mode 100644 (file)
index 0000000..8b5e891
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/** \file
+  This file consists of implementation of class SdbWinUsbEndpointObject that
+  encapsulates a handle opened to a WinUsb endpoint on our device.
+*/
+
+#include "stdafx.h"
+#include "sdb_winusb_endpoint_object.h"
+#include "sdb_winusb_io_completion.h"
+
+SdbWinUsbEndpointObject::SdbWinUsbEndpointObject(
+    SdbWinUsbInterfaceObject* parent_interf,
+    UCHAR endpoint_id,
+    UCHAR endpoint_index)
+    : SdbEndpointObject(parent_interf, endpoint_id, endpoint_index) {
+}
+
+SdbWinUsbEndpointObject::~SdbWinUsbEndpointObject() {
+}
+
+LONG SdbWinUsbEndpointObject::Release() {
+  ATLASSERT(ref_count_ > 0);
+  LONG ret = InterlockedDecrement(&ref_count_);
+  ATLASSERT(ret >= 0);
+  if (0 == ret) {
+    LastReferenceReleased();
+    delete this;
+  }
+  return ret;
+}
+
+SDBAPIHANDLE SdbWinUsbEndpointObject::CommonAsyncReadWrite(
+    bool is_read,
+    void* buffer,
+    ULONG bytes_to_transfer,
+    ULONG* bytes_transferred,
+    HANDLE event_handle,
+    ULONG time_out) {
+  if (!SetTimeout(time_out))
+    return false;
+
+  // Create completion i/o object
+  SdbIOCompletion* sdb_io_completion = NULL;
+
+  try {
+    sdb_io_completion = new SdbWinUsbIOCompletion(this,
+                                                  bytes_to_transfer,
+                                                  event_handle);
+  } catch (... ) {
+    SetLastError(ERROR_OUTOFMEMORY);
+    return NULL;
+  }
+
+  // Create a handle for it
+  SDBAPIHANDLE ret = sdb_io_completion->CreateHandle();
+  ULONG transferred = 0;
+  if (NULL != ret) {
+    BOOL res = TRUE;
+    // Go the read / write file way
+    res = is_read ?
+        WinUsb_ReadPipe(parent_winusb_interface()->winusb_handle(),
+                        endpoint_id(),
+                        reinterpret_cast<PUCHAR>(buffer),
+                        bytes_to_transfer,
+                        &transferred,
+                        sdb_io_completion->overlapped()) :
+        WinUsb_WritePipe(parent_winusb_interface()->winusb_handle(),
+                         endpoint_id(),
+                         reinterpret_cast<PUCHAR>(buffer),
+                         bytes_to_transfer,
+                         &transferred,
+                         sdb_io_completion->overlapped());
+
+    if (NULL != bytes_transferred)
+      *bytes_transferred = transferred;
+
+    ULONG error = GetLastError();
+    if (!res && (ERROR_IO_PENDING != error)) {
+      // I/O failed immediatelly. We need to close i/o completion object
+      // before we return NULL to the caller.
+      sdb_io_completion->CloseHandle();
+      ret = NULL;
+      SetLastError(error);
+    }
+  }
+
+  // Offseting 'new'
+  sdb_io_completion->Release();
+
+  return ret;
+}
+
+bool SdbWinUsbEndpointObject::CommonSyncReadWrite(bool is_read,
+                                                  void* buffer,
+                                                  ULONG bytes_to_transfer,
+                                                  ULONG* bytes_transferred,
+                                                  ULONG time_out) {
+  if (!SetTimeout(time_out))
+    return false;
+
+  // This is synchronous I/O. Since we always open I/O items for
+  // overlapped I/O we're obligated to always provide OVERLAPPED
+  // structure to read / write routines. Prepare it now.
+  OVERLAPPED overlapped;
+  ZeroMemory(&overlapped, sizeof(overlapped));
+  overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  BOOL ret = TRUE;
+  ULONG transferred = 0;
+  // Go the read / write file way
+  ret = is_read ?
+        WinUsb_ReadPipe(parent_winusb_interface()->winusb_handle(),
+                        endpoint_id(),
+                        reinterpret_cast<PUCHAR>(buffer),
+                        bytes_to_transfer,
+                        &transferred,
+                        &overlapped) :
+        WinUsb_WritePipe(parent_winusb_interface()->winusb_handle(),
+                         endpoint_id(),
+                         reinterpret_cast<PUCHAR>(buffer),
+                         bytes_to_transfer,
+                         &transferred,
+                         &overlapped);
+
+  // Lets see the result
+  if (!ret && (ERROR_IO_PENDING != GetLastError())) {
+    // I/O failed.
+    if (NULL != overlapped.hEvent)
+      ::CloseHandle(overlapped.hEvent);
+    return false;
+  }
+
+  // Lets wait till I/O completes
+  ret = WinUsb_GetOverlappedResult(parent_winusb_interface()->winusb_handle(), &overlapped,
+                                   &transferred, TRUE);
+  if (ret && (NULL != bytes_transferred)) {
+    *bytes_transferred = transferred;
+  }
+
+  if (NULL != overlapped.hEvent)
+    ::CloseHandle(overlapped.hEvent);
+
+  return ret ? true : false;
+}
+
+bool SdbWinUsbEndpointObject::SetTimeout(ULONG timeout) {
+  if (!WinUsb_SetPipePolicy(parent_winusb_interface()->winusb_handle(),
+                            endpoint_id(), PIPE_TRANSFER_TIMEOUT,
+                            sizeof(ULONG), &timeout)) {
+    return false;
+  }
+
+  return true;
+}
diff --git a/src/sdbwinusbapi/sdb_winusb_endpoint_object.h b/src/sdbwinusbapi/sdb_winusb_endpoint_object.h
new file mode 100644 (file)
index 0000000..bd7b38b
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 ANDROID_USB_API_SDB_WINUSB_ENDPOINT_OBJECT_H__
+#define ANDROID_USB_API_SDB_WINUSB_ENDPOINT_OBJECT_H__
+/** \file
+  This file consists of declaration of class SdbWinUsbEndpointObject that
+  encapsulates a handle opened to a WinUsb endpoint on our device.
+*/
+
+#include "..\sdbwinapi\sdb_endpoint_object.h"
+#include "sdb_winusb_interface.h"
+
+/** Class SdbWinUsbEndpointObject encapsulates a handle opened to an endpoint on
+  our device.
+*/
+class SdbWinUsbEndpointObject : public SdbEndpointObject {
+ public:
+  /** \brief Constructs the object
+
+    @param[in] interface Parent WinUsb interface for this object.
+    @param[in] endpoint_id Endpoint ID (endpoint address) on the device.
+    @param[in] endpoint_index Zero-based endpoint index in the interface's
+          array of endpoints.
+  */
+  SdbWinUsbEndpointObject(SdbWinUsbInterfaceObject* parent_interf,
+                          UCHAR endpoint_id,
+                          UCHAR endpoint_index);
+
+ protected:
+  /** \brief Destructs the object.
+
+    We hide destructor in order to prevent ourseves from accidentaly allocating
+    instances on the stack. If such attemp occur, compiler will error.
+  */
+  virtual ~SdbWinUsbEndpointObject();
+
+  //
+  // Virtual overrides
+  //
+
+ public:
+  /** \brief Releases the object.
+
+    If refcount drops to zero as the result of this release, the object is
+    destroyed in this method. As a general rule, objects must not be touched
+    after this method returns even if returned value is not zero. We override
+    this method in order to make sure that objects of this class are deleted
+    in contect of the DLL they were created in. The problem is that since
+    objects of this class were created in context of SdbWinUsbApi module, they
+    are allocated from the heap assigned to that module. Now, if these objects
+    are deleted outside of SdbWinUsbApi module, this will lead to the heap
+    corruption in the module that deleted these objects. Since all objects of
+    this class are deleted in the Release method only, by overriding it we make
+    sure that we free memory in the context of the module where it was
+    allocated.
+    @return Value of the reference counter after object is released in this
+            method.
+  */
+  virtual LONG Release();
+
+  //
+  // Abstract overrides
+  //
+
+ protected:
+  /** \brief Common code for async read / write
+
+    @param[in] is_read Read or write selector.
+    @param[in,out] buffer Pointer to the buffer for read / write.
+    @param[in] bytes_to_transfer Number of bytes to be read / written.
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.
+    @param[in] event_handle Event handle that should be signaled when async I/O
+           completes. Can be NULL. If it's not NULL this handle will be used to
+           initialize OVERLAPPED structure for this I/O.
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to
+           complete. Zero value in this parameter means that there is no
+           timeout set for this I/O.
+    @return A handle to IO completion object or NULL on failure. If NULL is
+            returned GetLastError() provides extended error information.
+  */
+  virtual SDBAPIHANDLE CommonAsyncReadWrite(bool is_read,
+                                            void* buffer,
+                                            ULONG bytes_to_transfer,
+                                            ULONG* bytes_transferred,
+                                            HANDLE event_handle,
+                                            ULONG time_out);
+
+  /** \brief Common code for sync read / write
+
+    @param[in] is_read Read or write selector.
+    @param[in,out] buffer Pointer to the buffer for read / write.
+    @param[in] bytes_to_transfer Number of bytes to be read / written.
+    @param[out] bytes_transferred Number of bytes read / written. Can be NULL.
+    @param[in] time_out A timeout (in milliseconds) required for this I/O to
+           complete. Zero value in this parameter means that there is no
+           timeout set for this I/O.
+    @return true on success, false on failure. If false is returned
+            GetLastError() provides extended error information.
+  */
+  virtual bool CommonSyncReadWrite(bool is_read,
+                                   void* buffer,
+                                   ULONG bytes_to_transfer,
+                                   ULONG* bytes_transferred,
+                                   ULONG time_out);
+
+  //
+  // Operations
+  //
+
+ protected:
+  /** \brief Sets read / write operation timeout.
+
+    @param[in] timeout Timeout value in milliseconds to use for current read
+          or write operation. Zero value passed in this parameters indicate
+          not timeout at all. Note that timeout that is set with this method is
+          global per endpoint (pipe). I.e. once set, it will be used against
+          all read / write operations performed on this endpoint, untill
+          another call to this method modifies it. This is a WinUsb design
+          flaw. Microsoft is aware of this and (hopefuly) future versions of
+          WinUsb framework will accept a timeout parameter in WinUsb_Read/Write
+          routines. For the purposes of SDB this flaw doesn't apperar to be an
+          issue, since we use single-threaded synchronous read / writes, so
+          there is no conflict in setting per-endpoint timeouts.
+    @return true on success, false on failure. If false is returned
+            GetLastError() provides extended error information.
+  */
+  virtual bool SetTimeout(ULONG timeout);
+
+ public:
+  /// Gets parent WinUsb interface
+  SdbWinUsbInterfaceObject* parent_winusb_interface() const {
+    return reinterpret_cast<SdbWinUsbInterfaceObject*>(parent_interface());
+  }
+
+  /// Gets parent interface WinUsb handle
+  WINUSB_INTERFACE_HANDLE winusb_handle() const {
+    return parent_winusb_interface()->winusb_handle();
+  }
+};
+
+#endif  // ANDROID_USB_API_SDB_WINUSB_ENDPOINT_OBJECT_H__
diff --git a/src/sdbwinusbapi/sdb_winusb_interface.cpp b/src/sdbwinusbapi/sdb_winusb_interface.cpp
new file mode 100644 (file)
index 0000000..3fcdce7
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/** \file
+  This file consists of implementation of class SdbWinUsbInterfaceObject
+  that encapsulates an interface on our USB device that is accessible
+  via WinUsb API.
+*/
+
+#include "stdafx.h"
+#include "sdb_winusb_interface.h"
+#include "sdb_winusb_endpoint_object.h"
+
+SdbWinUsbInterfaceObject::SdbWinUsbInterfaceObject(const wchar_t* interf_name)
+    : SdbInterfaceObject(interf_name),
+      usb_device_handle_(INVALID_HANDLE_VALUE),
+      winusb_handle_(NULL),
+      interface_number_(0xFF),
+      def_read_endpoint_(0xFF),
+      read_endpoint_id_(0xFF),
+      def_write_endpoint_(0xFF),
+      write_endpoint_id_(0xFF) {
+}
+
+SdbWinUsbInterfaceObject::~SdbWinUsbInterfaceObject() {
+  ATLASSERT(NULL == winusb_handle_);
+  ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_);
+}
+
+LONG SdbWinUsbInterfaceObject::Release() {
+  ATLASSERT(ref_count_ > 0);
+  LONG ret = InterlockedDecrement(&ref_count_);
+  ATLASSERT(ret >= 0);
+  if (0 == ret) {
+    LastReferenceReleased();
+    delete this;
+  }
+  return ret;
+}
+
+SDBAPIHANDLE SdbWinUsbInterfaceObject::CreateHandle() {
+  // Open USB device for this inteface Note that WinUsb API
+  // requires the handle to be opened for overlapped I/O.
+  usb_device_handle_ = CreateFile(interface_name().c_str(),
+                                  GENERIC_READ | GENERIC_WRITE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                  NULL, OPEN_EXISTING,
+                                  FILE_FLAG_OVERLAPPED, NULL);
+  if (INVALID_HANDLE_VALUE == usb_device_handle_)
+    return NULL;
+
+  // Initialize WinUSB API for this interface
+  if (!WinUsb_Initialize(usb_device_handle_, &winusb_handle_))
+    return NULL;
+
+  // Cache current interface number that will be used in
+  // WinUsb_Xxx calls performed on this interface.
+  if (!WinUsb_GetCurrentAlternateSetting(winusb_handle(), &interface_number_))
+    return false;
+
+  // Cache interface properties
+  unsigned long bytes_written;
+
+  // Cache USB device descriptor
+  if (!WinUsb_GetDescriptor(winusb_handle(), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0,
+                            reinterpret_cast<PUCHAR>(&usb_device_descriptor_),
+                            sizeof(usb_device_descriptor_), &bytes_written)) {
+    return false;
+  }
+
+  // Cache USB configuration descriptor
+  if (!WinUsb_GetDescriptor(winusb_handle(), USB_CONFIGURATION_DESCRIPTOR_TYPE,
+                            0, 0,
+                            reinterpret_cast<PUCHAR>(&usb_config_descriptor_),
+                            sizeof(usb_config_descriptor_), &bytes_written)) {
+    return false;
+  }
+
+  // Cache USB interface descriptor
+  if (!WinUsb_QueryInterfaceSettings(winusb_handle(), interface_number(),
+                                     &usb_interface_descriptor_)) {
+    return false;
+  }
+
+  // Save indexes and IDs for bulk read / write endpoints. We will use them to
+  // convert SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX and
+  // SDB_QUERY_BULK_READ_ENDPOINT_INDEX into actual endpoint indexes and IDs.
+  for (UCHAR endpoint = 0; endpoint < usb_interface_descriptor_.bNumEndpoints;
+       endpoint++) {
+    // Get endpoint information
+    WINUSB_PIPE_INFORMATION pipe_info;
+    if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint,
+                          &pipe_info)) {
+      return false;
+    }
+
+    if (UsbdPipeTypeBulk == pipe_info.PipeType) {
+      // This is a bulk endpoint. Cache its index and ID.
+      if (0 != (pipe_info.PipeId & USB_ENDPOINT_DIRECTION_MASK)) {
+        // Use this endpoint as default bulk read endpoint
+        ATLASSERT(0xFF == def_read_endpoint_);
+        def_read_endpoint_ = endpoint;
+        read_endpoint_id_ = pipe_info.PipeId;
+      } else {
+        // Use this endpoint as default bulk write endpoint
+        ATLASSERT(0xFF == def_write_endpoint_);
+        def_write_endpoint_ = endpoint;
+        write_endpoint_id_ = pipe_info.PipeId;
+      }
+    }
+  }
+
+  return SdbInterfaceObject::CreateHandle();
+}
+
+bool SdbWinUsbInterfaceObject::CloseHandle() {
+  if (NULL != winusb_handle_) {
+    WinUsb_Free(winusb_handle_);
+    winusb_handle_ = NULL;
+  }
+  if (INVALID_HANDLE_VALUE != usb_device_handle_) {
+    ::CloseHandle(usb_device_handle_);
+    usb_device_handle_ = INVALID_HANDLE_VALUE;
+  }
+
+  return SdbInterfaceObject::CloseHandle();
+}
+
+bool SdbWinUsbInterfaceObject::GetSerialNumber(void* buffer,
+                                               unsigned long* buffer_char_size,
+                                               bool ansi) {
+  if (!IsOpened()) {
+    SetLastError(ERROR_INVALID_HANDLE);
+    return false;
+  }
+
+  if (NULL == buffer_char_size) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return false;
+  }
+
+  // Calculate serial number string size. Note that WinUsb_GetDescriptor
+  // API will not return number of bytes needed to store serial number
+  // string. So we will have to start with a reasonably large preallocated
+  // buffer and then loop through WinUsb_GetDescriptor calls, doubling up
+  // string buffer size every time ERROR_INSUFFICIENT_BUFFER is returned.
+  union {
+    // Preallocate reasonably sized buffer on the stack.
+    char small_buffer[64];
+    USB_STRING_DESCRIPTOR initial_ser_num;
+  };
+  USB_STRING_DESCRIPTOR* ser_num = &initial_ser_num;
+  // Buffer byte size
+  unsigned long ser_num_size = sizeof(small_buffer);
+  // After successful call to WinUsb_GetDescriptor will contain serial
+  // number descriptor size.
+  unsigned long bytes_written;
+  while (!WinUsb_GetDescriptor(winusb_handle(), USB_STRING_DESCRIPTOR_TYPE,
+                               usb_device_descriptor_.iSerialNumber,
+                               0x0409, // English (US)
+                               reinterpret_cast<PUCHAR>(ser_num),
+                               ser_num_size, &bytes_written)) {
+    // Any error other than ERROR_INSUFFICIENT_BUFFER is terminal here.
+    if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+      if (ser_num != &initial_ser_num)
+        delete[] reinterpret_cast<char*>(ser_num);
+      return false;
+    }
+
+    // Double up buffer size and reallocate string buffer
+    ser_num_size *= 2;
+    if (ser_num != &initial_ser_num)
+      delete[] reinterpret_cast<char*>(ser_num);
+    try {
+      ser_num =
+          reinterpret_cast<USB_STRING_DESCRIPTOR*>(new char[ser_num_size]);
+    } catch (...) {
+      SetLastError(ERROR_OUTOFMEMORY);
+      return false;
+    }
+  }
+
+  // Serial number string length
+  unsigned long str_len = (ser_num->bLength -
+                           FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) /
+                          sizeof(wchar_t);
+
+  // Lets see if requested buffer is big enough to fit the string
+  if ((NULL == buffer) || (*buffer_char_size < (str_len + 1))) {
+    // Requested buffer is too small.
+    if (ser_num != &initial_ser_num)
+      delete[] reinterpret_cast<char*>(ser_num);
+    *buffer_char_size = str_len + 1;
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return false;
+  }
+
+  bool ret = true;
+  if (ansi) {
+    // We need to convert name from wide char to ansi string
+    if (0 != WideCharToMultiByte(CP_ACP, 0, ser_num->bString,
+                                 static_cast<int>(str_len),
+                                 reinterpret_cast<PSTR>(buffer),
+                                 static_cast<int>(*buffer_char_size),
+                                 NULL, NULL)) {
+      // Zero-terminate output string.
+      reinterpret_cast<char*>(buffer)[str_len] = '\0';
+    } else {
+      ret = false;
+    }
+  } else {
+    // For wide char output just copy string buffer,
+    // and zero-terminate output string.
+    CopyMemory(buffer, ser_num->bString, bytes_written);
+    reinterpret_cast<wchar_t*>(buffer)[str_len] = L'\0';
+  }
+
+  if (ser_num != &initial_ser_num)
+    delete[] reinterpret_cast<char*>(ser_num);
+
+  return ret;
+}
+
+bool SdbWinUsbInterfaceObject::GetEndpointInformation(
+    UCHAR endpoint_index,
+    SdbEndpointInformation* info) {
+  if (!IsOpened()) {
+    SetLastError(ERROR_INVALID_HANDLE);
+    return false;
+  }
+
+  if (NULL == info) {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return false;
+  }
+
+  // Get actual endpoint index for predefined read / write endpoints.
+  if (SDB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) {
+    endpoint_index = def_read_endpoint_;
+  } else if (SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) {
+    endpoint_index = def_write_endpoint_;
+  }
+
+  // Query endpoint information
+  WINUSB_PIPE_INFORMATION pipe_info;
+  if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint_index,
+                        &pipe_info)) {
+    return false;
+  }
+
+  // Save endpoint information into output.
+  info->max_packet_size = pipe_info.MaximumPacketSize;
+  info->max_transfer_size = 0xFFFFFFFF;
+  info->endpoint_address = pipe_info.PipeId;
+  info->polling_interval = pipe_info.Interval;
+  info->setting_index = interface_number();
+  switch (pipe_info.PipeType) {
+    case UsbdPipeTypeControl:
+      info->endpoint_type = SdbEndpointTypeControl;
+      break;
+
+    case UsbdPipeTypeIsochronous:
+      info->endpoint_type = SdbEndpointTypeIsochronous;
+      break;
+
+    case UsbdPipeTypeBulk:
+      info->endpoint_type = SdbEndpointTypeBulk;
+      break;
+
+    case UsbdPipeTypeInterrupt:
+      info->endpoint_type = SdbEndpointTypeInterrupt;
+      break;
+
+    default:
+      info->endpoint_type = SdbEndpointTypeInvalid;
+      break;
+  }
+
+  return true;
+}
+
+SDBAPIHANDLE SdbWinUsbInterfaceObject::OpenEndpoint(
+    UCHAR endpoint_index,
+    SdbOpenAccessType access_type,
+    SdbOpenSharingMode sharing_mode) {
+  // Convert index into id
+  UCHAR endpoint_id;
+
+  if ((SDB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) ||
+      (def_read_endpoint_ == endpoint_index)) {
+    endpoint_id = read_endpoint_id_;
+    endpoint_index = def_read_endpoint_;
+  } else if ((SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) ||
+             (def_write_endpoint_ == endpoint_index)) {
+    endpoint_id = write_endpoint_id_;
+    endpoint_index = def_write_endpoint_;
+  } else {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return false;
+  }
+
+  return OpenEndpoint(endpoint_id, endpoint_index);
+}
+
+SDBAPIHANDLE SdbWinUsbInterfaceObject::OpenEndpoint(UCHAR endpoint_id,
+                                                    UCHAR endpoint_index) {
+  if (!IsOpened()) {
+    SetLastError(ERROR_INVALID_HANDLE);
+    return false;
+  }
+
+  SdbEndpointObject* sdb_endpoint = NULL;
+  
+  try {
+    sdb_endpoint =
+        new SdbWinUsbEndpointObject(this, endpoint_id, endpoint_index);
+  } catch (...) {
+    SetLastError(ERROR_OUTOFMEMORY);
+    return NULL;
+  }
+
+  SDBAPIHANDLE ret = sdb_endpoint->CreateHandle();
+
+  sdb_endpoint->Release();
+
+  return ret;
+}
diff --git a/src/sdbwinusbapi/sdb_winusb_interface.h b/src/sdbwinusbapi/sdb_winusb_interface.h
new file mode 100644 (file)
index 0000000..6a37996
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 ANDROID_USB_API_SDB_WINUSB_INTERFACE_H__
+#define ANDROID_USB_API_SDB_WINUSB_INTERFACE_H__
+/** \file
+  This file consists of declaration of class SdbWinUsbInterfaceObject
+  that encapsulates an interface on our USB device that is accessible
+  via WinUsb API.
+*/
+
+#include "..\sdbwinapi\sdb_interface.h"
+
+/** \brief Encapsulates an interface on our USB device that is accessible
+  via WinUsb API.
+*/
+class SdbWinUsbInterfaceObject : public SdbInterfaceObject {
+ public:
+  /** \brief Constructs the object.
+
+    @param[in] interf_name Name of the interface
+  */
+  explicit SdbWinUsbInterfaceObject(const wchar_t* interf_name);
+
+ protected:
+  /** \brief Destructs the object.
+
+   We hide destructor in order to prevent ourseves from accidentaly allocating
+   instances on the stack. If such attemp occur, compiler will error.
+  */
+  virtual ~SdbWinUsbInterfaceObject();
+
+  //
+  // Virtual overrides
+  //
+
+ public:
+  /** \brief Releases the object.
+
+    If refcount drops to zero as the result of this release, the object is
+    destroyed in this method. As a general rule, objects must not be touched
+    after this method returns even if returned value is not zero. We override
+    this method in order to make sure that objects of this class are deleted
+    in contect of the DLL they were created in. The problem is that since
+    objects of this class were created in context of SdbWinUsbApi module, they
+    are allocated from the heap assigned to that module. Now, if these objects
+    are deleted outside of SdbWinUsbApi module, this will lead to the heap
+    corruption in the module that deleted these objects. Since all objects of
+    this class are deleted in the Release method only, by overriding it we make
+    sure that we free memory in the context of the module where it was
+    allocated.
+    @return Value of the reference counter after object is released in this
+            method.
+  */
+  virtual LONG Release();
+
+  /** \brief Creates handle to this object.
+
+    In this call a handle for this object is generated and object is added
+    to the SdbObjectHandleMap. We override this method in order to initialize
+    WinUsb API for the given interface.
+    @return A handle to this object on success or NULL on an error.
+            If NULL is returned GetLastError() provides extended error
+            information. ERROR_GEN_FAILURE is set if an attempt was
+            made to create already opened object.
+  */
+  virtual SDBAPIHANDLE CreateHandle();
+
+  /** \brief This method is called when handle to this object gets closed.
+
+    In this call object is deleted from the SdbObjectHandleMap. We override
+    this method in order close WinUsb handle created in CreateHandle method
+    of this class.
+    @return true on success or false if object is already closed. If
+            false is returned GetLastError() provides extended error
+            information.
+  */
+  virtual bool CloseHandle();
+
+  //
+  // Abstract overrides
+  //
+
+ public:
+  /** \brief Gets serial number for interface's device.
+
+    @param[out] buffer Buffer for the serail number string. Can be NULL in
+           which case buffer_char_size will contain number of characters
+           required for the string.
+    @param[in,out] buffer_char_size On the way in supplies size (in characters)
+           of the buffer. On the way out, if method failed and GetLastError
+           reports ERROR_INSUFFICIENT_BUFFER, will contain number of characters
+           required for the name.
+    @param[in] ansi If true the name will be returned as single character
+           string. Otherwise name will be returned as wide character string.
+    @return true on success, false on failure. If false is returned
+            GetLastError() provides extended error information.
+  */
+  virtual bool GetSerialNumber(void* buffer,
+                               unsigned long* buffer_char_size,
+                               bool ansi);
+
+  /** \brief Gets information about an endpoint on this interface.
+
+    @param[in] endpoint_index Zero-based endpoint index. There are two
+           shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX
+           and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide infor about
+           (default?) bulk write and read endpoints respectively.
+    @param[out] info Upon successful completion will have endpoint information.
+    @return true on success, false on failure. If false is returned
+            GetLastError() provides extended error information.
+  */
+  virtual bool GetEndpointInformation(UCHAR endpoint_index,
+                                      SdbEndpointInformation* info);
+
+  /** \brief Opens an endpoint on this interface.
+
+    @param[in] endpoint_index Zero-based endpoint index. There are two
+           shortcuts for this parameter: SDB_QUERY_BULK_WRITE_ENDPOINT_INDEX
+           and SDB_QUERY_BULK_READ_ENDPOINT_INDEX that provide infor about
+           (default?) bulk write and read endpoints respectively.
+    @param[in] access_type Desired access type. In the current implementation
+           this parameter has no effect on the way endpoint is opened. It's
+           always read / write access.
+    @param[in] sharing_mode Desired share mode. In the current implementation
+           this parameter has no effect on the way endpoint is opened. It's
+           always shared for read / write.
+    @return Handle to the opened endpoint object or NULL on failure.
+            If NULL is returned GetLastError() provides extended information
+            about the error that occurred.
+  */
+  virtual SDBAPIHANDLE OpenEndpoint(UCHAR endpoint_index,
+                                    SdbOpenAccessType access_type,
+                                    SdbOpenSharingMode sharing_mode);
+
+  //
+  // Operations
+  //
+
+ protected:
+  /** \brief Opens an endpoint on this interface.
+
+    @param[in] endpoint_id Endpoint (pipe) address on the device.
+    @param[in] endpoint_index Zero-based endpoint index.
+    @return Handle to the opened endpoint object or NULL on failure.
+            If NULL is returned GetLastError() provides extended information
+            about the error that occurred.
+  */
+  SDBAPIHANDLE OpenEndpoint(UCHAR endpoint_id, UCHAR endpoint_index);
+
+ public:
+  /// Gets handle to the USB device
+  HANDLE usb_device_handle() const {
+    return usb_device_handle_;
+  }
+
+  /// Gets interface handle used by WinUSB API
+  WINUSB_INTERFACE_HANDLE winusb_handle() const {
+    return winusb_handle_;
+  }
+
+  /// Gets current interface number.
+  UCHAR interface_number() const {
+    return interface_number_;
+  }
+
+ protected:
+  /// Handle to the USB device
+  HANDLE                        usb_device_handle_;
+
+  /// Interface handle used by WinUSB API
+  WINUSB_INTERFACE_HANDLE       winusb_handle_;
+
+  /// Current interface number. This value is obtained via call to
+  /// WinUsb_GetCurrentAlternateSetting and is used in WinUsb_Xxx
+  /// calls that require interface number.
+  UCHAR                         interface_number_;
+
+  /// Index for the default bulk read endpoint
+  UCHAR                         def_read_endpoint_;
+
+  /// ID for the default bulk read endpoint
+  UCHAR                         read_endpoint_id_;
+
+  /// Index for the default bulk write endpoint
+  UCHAR                         def_write_endpoint_;
+
+  /// ID for the default bulk write endpoint
+  UCHAR                         write_endpoint_id_;
+};
+
+#endif  // ANDROID_USB_API_SDB_WINUSB_INTERFACE_H__
diff --git a/src/sdbwinusbapi/sdb_winusb_io_completion.cpp b/src/sdbwinusbapi/sdb_winusb_io_completion.cpp
new file mode 100644 (file)
index 0000000..283f689
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/** \file
+  This file consists of implementation of class SdbWinUsbIOCompletion that
+  encapsulates a wrapper around OVERLAPPED Win32 structure returned from
+  asynchronous I/O requests issued via WinUsb API.
+*/
+
+#include "stdafx.h"
+#include "sdb_winusb_io_completion.h"
+
+SdbWinUsbIOCompletion::SdbWinUsbIOCompletion(
+    SdbWinUsbEndpointObject* parent_io_obj,
+    ULONG expected_trans_size,
+    HANDLE event_hndl)
+    : SdbIOCompletion(parent_io_obj, expected_trans_size, event_hndl) {
+}
+
+SdbWinUsbIOCompletion::~SdbWinUsbIOCompletion() {
+}
+
+LONG SdbWinUsbIOCompletion::Release() {
+  ATLASSERT(ref_count_ > 0);
+  LONG ret = InterlockedDecrement(&ref_count_);
+  ATLASSERT(ret >= 0);
+  if (0 == ret) {
+    LastReferenceReleased();
+    delete this;
+  }
+  return ret;
+}
+
+bool SdbWinUsbIOCompletion::GetOvelappedIoResult(LPOVERLAPPED ovl_data,
+                                                 ULONG* bytes_transferred,
+                                                 bool wait) {
+  if (NULL != bytes_transferred) {
+    *bytes_transferred = 0;
+  }
+
+  if (!IsOpened()) {
+    SetLastError(ERROR_INVALID_HANDLE);
+    return false;
+  }
+
+  ULONG transfer;
+  bool ret = WinUsb_GetOverlappedResult(
+                  parent_winusb_io_object()->winusb_handle(),
+                  overlapped(),
+                  &transfer,
+                  wait ? TRUE : FALSE) ? true : false;
+
+  // TODO: This is bizzare but I've seen it happening
+  // that GetOverlappedResult with wait set to true returns "prematurely",
+  // with wrong transferred bytes value and GetLastError reporting
+  // ERROR_IO_PENDING. So, lets give it an up to a 20 ms loop!
+  ULONG error = GetLastError();
+
+  if (wait && ret && (0 == transfer) && (0 != expected_transfer_size_) &&
+      ((ERROR_IO_INCOMPLETE == error) || (ERROR_IO_PENDING == error))) {
+    for (int trying = 0; trying < 10; trying++) {
+      Sleep(2);
+      ret = WinUsb_GetOverlappedResult(
+                parent_winusb_io_object()->winusb_handle(),
+                overlapped(),
+                &transfer,
+                wait ? TRUE : FALSE) ? true : false;
+      error = GetLastError();
+      if (!ret || (0 != transfer) ||
+          ((ERROR_IO_INCOMPLETE != error) && (ERROR_IO_PENDING != error))) {
+        break;
+      }
+    }
+  }
+
+  if (NULL != ovl_data) {
+    CopyMemory(ovl_data, overlapped(), sizeof(OVERLAPPED));
+  }
+
+  if (NULL != bytes_transferred) {
+    *bytes_transferred = transfer;
+  }
+
+  return ret;
+}
diff --git a/src/sdbwinusbapi/sdb_winusb_io_completion.h b/src/sdbwinusbapi/sdb_winusb_io_completion.h
new file mode 100644 (file)
index 0000000..e75a7b2
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 ANDROID_USB_API_SDB_WINUSB_IO_COMPLETION_H__
+#define ANDROID_USB_API_SDB_WINUSB_IO_COMPLETION_H__
+/** \file
+  This file consists of declaration of class SdbWinUsbIOCompletion that
+  encapsulates a wrapper around OVERLAPPED Win32 structure returned from
+  asynchronous I/O requests issued via WinUsb API.
+*/
+
+#include "..\sdbwinapi\sdb_io_completion.h"
+#include "sdb_winusb_endpoint_object.h"
+
+/** \brief Encapsulates encapsulates a wrapper around OVERLAPPED Win32
+  structure returned from asynchronous I/O requests issued via WinUsb API.
+
+  A handle to this object is returned to the caller of each successful
+  asynchronous I/O request. Just like all other handles this handle
+  must be closed after it's no longer needed.
+*/
+class SdbWinUsbIOCompletion : public SdbIOCompletion {
+ public:
+  /** \brief Constructs the object
+
+    @param[in] parent_io_obj Parent WinUsb I/O object that created this
+           instance.
+    @param[in] expected_trans_size Number of bytes expected to be transferred
+          with the I/O.
+    @param[in] event_hndl Event handle that should be signaled when I/O
+           completes. Can be NULL. If it's not NULL this handle will be
+           used to initialize OVERLAPPED structure for this object.
+  */
+  SdbWinUsbIOCompletion(SdbWinUsbEndpointObject* parent_io_obj,
+                        ULONG expected_trans_size,
+                        HANDLE event_hndl);
+
+ protected:
+  /** \brief Destructs the object.
+
+    We hide destructor in order to prevent ourseves from accidentaly allocating
+    instances on the stack. If such attemp occur, compiler will error.
+  */
+  virtual ~SdbWinUsbIOCompletion();
+
+  //
+  // Virtual overrides
+  //
+
+ public:
+  /** \brief Releases the object.
+
+    If refcount drops to zero as the result of this release, the object is
+    destroyed in this method. As a general rule, objects must not be touched
+    after this method returns even if returned value is not zero. We override
+    this method in order to make sure that objects of this class are deleted
+    in contect of the DLL they were created in. The problem is that since
+    objects of this class were created in context of SdbWinUsbApi module, they
+    are allocated from the heap assigned to that module. Now, if these objects
+    are deleted outside of SdbWinUsbApi module, this will lead to the heap
+    corruption in the module that deleted these objects. Since all objects of
+    this class are deleted in the Release method only, by overriding it we make
+    sure that we free memory in the context of the module where it was
+    allocated.
+    @return Value of the reference counter after object is released in this
+            method.
+  */
+  virtual LONG Release();
+
+  //
+  // Abstract overrides
+  //
+
+ public:
+  /** \brief Gets overlapped I/O result
+
+    This method uses WinUsb_GetOverlappedResult to get results of the
+    overlapped I/O operation.
+    @param[out] ovl_data Buffer for the copy of this object's OVERLAPPED
+           structure. Can be NULL.
+    @param[out] bytes_transferred Pointer to a variable that receives the
+           number of bytes that were actually transferred by a read or write
+           operation. See SDK doc on GetOvelappedResult for more information.
+           Unlike regular GetOvelappedResult call this parameter can be NULL.
+    @param[in] wait If this parameter is true, the method does not return
+           until the operation has been completed. If this parameter is false
+           and the operation is still pending, the method returns false and
+           the GetLastError function returns ERROR_IO_INCOMPLETE.
+    @return true if I/O has been completed or false on failure or if request
+           is not yet completed. If false is returned GetLastError() provides
+           extended error information. If GetLastError returns
+           ERROR_IO_INCOMPLETE it means that I/O is not yet completed.
+  */
+  virtual bool GetOvelappedIoResult(LPOVERLAPPED ovl_data,
+                                    ULONG* bytes_transferred,
+                                    bool wait);
+
+ public:
+  /// Gets WinUsb parent object
+  SdbWinUsbEndpointObject* parent_winusb_io_object() const {
+    return reinterpret_cast<SdbWinUsbEndpointObject*>(parent_io_object());
+  }
+};
+
+#endif  // ANDROID_USB_API_SDB_WINUSB_IO_COMPLETION_H__
diff --git a/src/sdbwinusbapi/stdafx.cpp b/src/sdbwinusbapi/stdafx.cpp
new file mode 100644 (file)
index 0000000..83c6e13
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+// stdafx.cpp : source file that includes just the standard includes
+// SdbWinUsbApi.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/src/sdbwinusbapi/stdafx.h b/src/sdbwinusbapi/stdafx.h
new file mode 100644 (file)
index 0000000..88cd963
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/** \file
+  Visual Studio generated include file for standard system include files, or
+  project specific include files that are used frequently, but are changed
+  infrequently.
+*/
+
+#pragma once
+
+#ifndef STRICT
+#define STRICT
+#endif
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER                         // Allow use of features specific to Windows 95 and Windows NT 4 or later.
+#define WINVER 0x0500          // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#endif
+
+#ifndef _WIN32_WINNT           // Allow use of features specific to Windows NT 4 or later.
+#define _WIN32_WINNT 0x0500    // Change this to the appropriate value to target Windows 2000 or later.
+#endif
+
+#ifndef _WIN32_WINDOWS         // Allow use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0500 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE                      // Allow use of features specific to IE 4.0 or later.
+#define _WIN32_IE 0x0501       // Change this to the appropriate value to target IE 5.0 or later.
+#endif
+
+// These defines prevent the MS header files from ejecting #pragma comment
+// statements with the manifest information of the used ATL, STL, and CRT
+#define _ATL_NOFORCE_MANIFEST
+#define _STL_NOFORCE_MANIFEST
+#define _CRT_NOFORCE_MANIFEST
+
+#define _ATL_APARTMENT_THREADED
+#define _ATL_NO_AUTOMATIC_NAMESPACE
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS     // some CString constructors will be explicit
+
+// turns off ATL's hiding of some common and often safely ignored warning messages
+#define _ATL_ALL_WARNINGS
+
+// #define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
+
+#include <windows.h>
+#pragma warning(disable: 4702)
+#pragma warning(disable: 4201)
+#include <atlbase.h>
+#include <winioctl.h>
+#include <setupapi.h>
+#include <vector>
+#include <map>
+#include <string>
+#pragma warning(default: 4201)
+#pragma warning(disable: 4200)
+#include <winusb.h>
+
+#include "resource.h"
+
+using namespace ATL;
index 0b82a68dfdcdba1b6637bc7414e17b33655a7e1a..555c91df1a8bd6cfd11aba1db8f2881f62578495 100755 (executable)
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-#include "utils.h"
-#include "fdevent.h"
+
+#include "sysdeps.h"
 
 #define  TRACE_TAG  TRACE_SERVICES
 #include "sdb.h"
 #include "file_sync_service.h"
 
-#  ifndef OS_WINDOWS
+#if SDB_HOST
+#  ifndef HAVE_WINSOCK
 #    include <netinet/in.h>
 #    include <netdb.h>
 #    include <sys/ioctl.h>
 #  endif
+#else
+#   include "android_reboot.h"
+#   include <sys/inotify.h>
+#endif
 
 typedef struct stinfo stinfo;
 
@@ -49,8 +54,239 @@ void *service_bootstrap_func(void *x)
     return 0;
 }
 
+#if SDB_HOST
 SDB_MUTEX_DEFINE( dns_lock );
 
+static void dns_service(int fd, void *cookie)
+{
+    char *hostname = cookie;
+    struct hostent *hp;
+    unsigned zero = 0;
+
+    sdb_mutex_lock(&dns_lock);
+    hp = gethostbyname(hostname);
+    free(cookie);
+    if(hp == 0) {
+        writex(fd, &zero, 4);
+    } else {
+        writex(fd, hp->h_addr, 4);
+    }
+    sdb_mutex_unlock(&dns_lock);
+    sdb_close(fd);
+}
+#else
+
+#if 0
+extern int recovery_mode;
+
+static void recover_service(int s, void *cookie)
+{
+    unsigned char buf[4096];
+    unsigned count = (unsigned) cookie;
+    int fd;
+
+    fd = sdb_creat("/tmp/update", 0644);
+    if(fd < 0) {
+        sdb_close(s);
+        return;
+    }
+
+    while(count > 0) {
+        unsigned xfer = (count > 4096) ? 4096 : count;
+        if(readx(s, buf, xfer)) break;
+        if(writex(fd, buf, xfer)) break;
+        count -= xfer;
+    }
+
+    if(count == 0) {
+        writex(s, "OKAY", 4);
+    } else {
+        writex(s, "FAIL", 4);
+    }
+    sdb_close(fd);
+    sdb_close(s);
+
+    fd = sdb_creat("/tmp/update.begin", 0644);
+    sdb_close(fd);
+}
+
+void restart_root_service(int fd, void *cookie)
+{
+    char buf[100];
+    char value[PROPERTY_VALUE_MAX];
+
+    if (getuid() == 0) {
+        snprintf(buf, sizeof(buf), "sdbd is already running as root\n");
+        writex(fd, buf, strlen(buf));
+        sdb_close(fd);
+    } else {
+        property_get("ro.debuggable", value, "");
+        if (strcmp(value, "1") != 0) {
+            snprintf(buf, sizeof(buf), "sdbd cannot run as root in production builds\n");
+            writex(fd, buf, strlen(buf));
+            sdb_close(fd);
+            return;
+        }
+
+        property_set("service.sdb.root", "1");
+        snprintf(buf, sizeof(buf), "restarting sdbd as root\n");
+        writex(fd, buf, strlen(buf));
+        sdb_close(fd);
+    }
+}
+#endif
+
+void restart_tcp_service(int fd, void *cookie)
+{
+    char buf[100];
+    char value[PROPERTY_VALUE_MAX];
+    int port = (int)cookie;
+
+    if (port <= 0) {
+        snprintf(buf, sizeof(buf), "invalid port\n");
+        writex(fd, buf, strlen(buf));
+        sdb_close(fd);
+        return;
+    }
+
+    snprintf(value, sizeof(value), "%d", port);
+    property_set("service.sdb.tcp.port", value);
+    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
+    writex(fd, buf, strlen(buf));
+    sdb_close(fd);
+}
+
+void restart_usb_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    property_set("service.sdb.tcp.port", "0");
+    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
+    writex(fd, buf, strlen(buf));
+    sdb_close(fd);
+}
+
+void reboot_service(int fd, void *arg)
+{
+    char buf[100];
+    int pid, ret;
+
+    sync();
+
+    /* Attempt to unmount the SD card first.
+     * No need to bother checking for errors.
+     */
+    pid = fork();
+    if (pid == 0) {
+        /* ask vdc to unmount it */
+        execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
+                getenv("EXTERNAL_STORAGE"), "force", NULL);
+    } else if (pid > 0) {
+        /* wait until vdc succeeds or fails */
+        waitpid(pid, &ret, 0);
+    }
+
+    ret = android_reboot(ANDROID_RB_RESTART2, 0, (char *) arg);
+    if (ret < 0) {
+        snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
+        writex(fd, buf, strlen(buf));
+    }
+    free(arg);
+    sdb_close(fd);
+}
+
+#if !SDB_HOST
+#define EVENT_SIZE  ( sizeof (struct inotify_event) )
+#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )
+#define CS_PATH     "/opt/usr/share/crash/report"
+static int inoti_once = 0;
+void inoti_service(int fd, void *arg)
+{
+    int wd;
+    int ifd;
+    char buffer[BUF_LEN];
+
+    D( "inoti_service start\n");
+    ifd = inotify_init();
+
+    if ( ifd < 0 ) {
+        D( "inotify_init failed\n");
+        return;
+    }
+
+    wd = inotify_add_watch( ifd, CS_PATH, IN_CREATE);
+    inoti_once = 1;
+    for ( ; ; ) {
+        int length, i = 0;
+        length = sdb_read( ifd, buffer, BUF_LEN );
+
+        if ( length < 0 ) {
+            D( "inoti read failed\n");
+            goto done;
+        }
+
+        while ( i < length ) {
+            struct inotify_event *event = ( struct inotify_event * )&buffer[i];
+            if (event->len) {
+                if ( event->mask & IN_CREATE) {
+                    if (!(event->mask & IN_ISDIR)) {
+                        char *cspath = NULL;
+                        int len = asprintf(&cspath, "%s/%s", CS_PATH, event->name);
+                        D( "The file %s was created.\n", cspath);
+                        if (cspath != NULL) {
+                            writex(fd, cspath, len);
+                            free(cspath);
+                        }
+                    }
+                }
+            }
+            i += EVENT_SIZE + event->len;
+        }
+    }
+
+done:
+    inotify_rm_watch( ifd, wd );
+    sdb_close(ifd);
+    sdb_close(fd);
+    D( "inoti_service end\n");
+}
+#endif
+#endif
+
+#if 0
+static void echo_service(int fd, void *cookie)
+{
+    char buf[4096];
+    int r;
+    char *p;
+    int c;
+
+    for(;;) {
+        r = read(fd, buf, 4096);
+        if(r == 0) goto done;
+        if(r < 0) {
+            if(errno == EINTR) continue;
+            else goto done;
+        }
+
+        c = r;
+        p = buf;
+        while(c > 0) {
+            r = write(fd, p, c);
+            if(r > 0) {
+                c -= r;
+                p += r;
+                continue;
+            }
+            if((r < 0) && (errno == EINTR)) continue;
+            goto done;
+        }
+    }
+done:
+    close(fd);
+}
+#endif
+
 static int create_service_thread(void (*func)(int, void *), void *cookie)
 {
     stinfo *sti;
@@ -80,6 +316,150 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
     return s[0];
 }
 
+#if !SDB_HOST
+static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+#ifdef HAVE_WIN32_PROC
+    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else /* !HAVE_WIN32_PROC */
+    char *devname;
+    int ptm;
+
+    ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
+    if(ptm < 0){
+        printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
+        return -1;
+    }
+    fcntl(ptm, F_SETFD, FD_CLOEXEC);
+
+    if(grantpt(ptm) || unlockpt(ptm) ||
+       ((devname = (char*) ptsname(ptm)) == 0)){
+        printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
+        sdb_close(ptm);
+        return -1;
+    }
+
+    *pid = fork();
+    if(*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        sdb_close(ptm);
+        return -1;
+    }
+
+    if(*pid == 0){
+        int pts;
+
+        setsid();
+
+        pts = unix_open(devname, O_RDWR);
+        if(pts < 0) {
+            fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
+            exit(-1);
+        }
+
+        dup2(pts, 0);
+        dup2(pts, 1);
+        dup2(pts, 2);
+
+        sdb_close(pts);
+        sdb_close(ptm);
+
+        // set OOM adjustment to zero
+        char text[64];
+        snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
+        int fd = sdb_open(text, O_WRONLY);
+        if (fd >= 0) {
+            sdb_write(fd, "0", 1);
+            sdb_close(fd);
+        } else {
+           D("sdb: unable to open %s\n", text);
+        }
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        // Don't set child's OOM adjustment to zero.
+        // Let the child do it itself, as sometimes the parent starts
+        // running before the child has a /proc/pid/oom_adj.
+        // """sdb: unable to open /proc/644/oom_adj""" seen in some logs.
+        return ptm;
+    }
+#endif /* !HAVE_WIN32_PROC */
+}
+#endif  /* !SDB_HOST */
+
+#if SDB_HOST
+#define SHELL_COMMAND "/bin/sh"
+#else
+#define SHELL_COMMAND "/bin/sh" /* tizen specific */
+#endif
+
+#if !SDB_HOST
+static void subproc_waiter_service(int fd, void *cookie)
+{
+    pid_t pid = (pid_t)cookie;
+
+    D("entered. fd=%d of pid=%d\n", fd, pid);
+    for (;;) {
+        int status;
+        pid_t p = waitpid(pid, &status, 0);
+        if (p == pid) {
+            D("fd=%d, post waitpid(pid=%d) status=%04x\n", fd, p, status);
+            if (WIFSIGNALED(status)) {
+                D("*** Killed by signal %d\n", WTERMSIG(status));
+                break;
+            } else if (!WIFEXITED(status)) {
+                D("*** Didn't exit!!. status %d\n", status);
+                break;
+            } else if (WEXITSTATUS(status) >= 0) {
+                D("*** Exit code %d\n", WEXITSTATUS(status));
+                break;
+            }
+         }
+    }
+    D("shell exited fd=%d of pid=%d err=%d\n", fd, pid, errno);
+    if (SHELL_EXIT_NOTIFY_FD >=0) {
+      int res;
+      res = writex(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd));
+      D("notified shell exit via fd=%d for pid=%d res=%d errno=%d\n",
+        SHELL_EXIT_NOTIFY_FD, pid, res, errno);
+    }
+}
+
+static int create_subproc_thread(const char *name)
+{
+    stinfo *sti;
+    sdb_thread_t t;
+    int ret_fd;
+    pid_t pid;
+    if(name) {
+        ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+    } else {
+        ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+    }
+    D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
+
+    sti = malloc(sizeof(stinfo));
+    if(sti == 0) fatal("cannot allocate stinfo");
+    sti->func = subproc_waiter_service;
+    sti->cookie = (void*)pid;
+    sti->fd = ret_fd;
+
+    if(sdb_thread_create( &t, service_bootstrap_func, sti)){
+        free(sti);
+        sdb_close(ret_fd);
+        printf("cannot create service thread\n");
+        return -1;
+    }
+
+    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+    return ret_fd;
+}
+#endif
+
 int service_to_fd(const char *name)
 {
     int ret = -1;
@@ -92,11 +472,84 @@ int service_to_fd(const char *name)
             if (ret >= 0)
                 disable_tcp_nagle(ret);
         } else {
-
+#if SDB_HOST
             sdb_mutex_lock(&dns_lock);
             ret = socket_network_client(name + 1, port, SOCK_STREAM);
             sdb_mutex_unlock(&dns_lock);
+#else
+            return -1;
+#endif
         }
+#ifndef HAVE_WINSOCK   /* winsock doesn't implement unix domain sockets */
+    } else if(!strncmp(name, "local:", 6)) {
+        ret = socket_local_client(name + 6,
+                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    } else if(!strncmp(name, "localreserved:", 14)) {
+        ret = socket_local_client(name + 14,
+                ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    } else if(!strncmp(name, "localabstract:", 14)) {
+        ret = socket_local_client(name + 14,
+                ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+    } else if(!strncmp(name, "localfilesystem:", 16)) {
+        ret = socket_local_client(name + 16,
+                ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+#endif
+#if SDB_HOST
+    } else if(!strncmp("dns:", name, 4)){
+        char *n = strdup(name + 4);
+        if(n == 0) return -1;
+        ret = create_service_thread(dns_service, n);
+#else /* !SDB_HOST */
+    }/* else if(!strncmp("dev:", name, 4)) {// tizen specific
+        ret = unix_open(name + 4, O_RDWR);
+    } else if(!strncmp(name, "framebuffer:", 12)) {
+        ret = create_service_thread(framebuffer_service, 0);
+    } else if(recovery_mode && !strncmp(name, "recover:", 8)) {
+        ret = create_service_thread(recover_service, (void*) atoi(name + 8));
+    } else if (!strncmp(name, "jdwp:", 5)) {
+        ret = create_jdwp_connection_fd(atoi(name+5));
+    } else if (!strncmp(name, "log:", 4)) {
+        ret = create_service_thread(log_service, get_log_file_path(name + 4));
+    }*/ else if(!HOST && !strncmp(name, "shell:", 6)) {
+        if(name[6]) {
+            ret = create_subproc_thread(name + 6);
+        } else {
+            ret = create_subproc_thread(0);
+        }
+    } else if(!strncmp(name, "sync:", 5)) {
+        ret = create_service_thread(file_sync_service, NULL);
+    }/*  else if(!strncmp(name, "remount:", 8)) {
+        ret = create_service_thread(remount_service, NULL);
+    } else if(!strncmp(name, "reboot:", 7)) {
+        void* arg = strdup(name + 7);
+        if(arg == 0) return -1;
+        ret = create_service_thread(reboot_service, arg);
+    } else if(!strncmp(name, "root:", 5)) {
+        ret = create_service_thread(restart_root_service, NULL);
+    } else if(!strncmp(name, "backup:", 7)) {
+        char* arg = strdup(name+7);
+        if (arg == NULL) return -1;
+        ret = backup_service(BACKUP, arg);
+    } else if(!strncmp(name, "restore:", 8)) {
+        ret = backup_service(RESTORE, NULL);
+    }*/ else if(!strncmp(name, "tcpip:", 6)) {
+        int port;
+        /*if (sscanf(name + 6, "%d", &port) == 0) {
+            port = 0;
+        }*/
+        port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
+        ret = create_service_thread(restart_tcp_service, (void *)port);
+    } else if(!strncmp(name, "usb:", 4)) {
+        ret = create_service_thread(restart_usb_service, NULL);
+    } else if(!strncmp(name, "cs:", 5)) {
+        if (inoti_once == 0) {
+            ret = create_service_thread(inoti_service, NULL);
+        }
+#endif
+#if 0
+    } else if(!strncmp(name, "echo:", 5)){
+        ret = create_service_thread(echo_service, 0);
+#endif
     }
     if (ret >= 0) {
         close_on_exec(ret);
@@ -104,6 +557,7 @@ int service_to_fd(const char *name)
     return ret;
 }
 
+#if SDB_HOST
 struct state_info {
     transport_type transport;
     char* serial;
@@ -130,7 +584,9 @@ static void wait_for_state(int fd, void* cookie)
     sdb_close(fd);
     D("wait_for_state is done\n");
 }
+#endif
 
+#if SDB_HOST
 asocket*  host_service_to_socket(const char*  name, const char *serial)
 {
     if (!strcmp(name,"track-devices")) {
@@ -164,4 +620,4 @@ asocket*  host_service_to_socket(const char*  name, const char *serial)
     }
     return NULL;
 }
-
+#endif /* SDB_HOST */
diff --git a/src/socket_inaddr_any_server.c b/src/socket_inaddr_any_server.c
new file mode 100644 (file)
index 0000000..41d7491
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+// libs/cutils/socket_inaddr_any_server.c
+
+#include "sockets.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+#define LISTEN_BACKLOG 4
+
+/* open listen() port on any interface */
+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));
+
+    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1; 
+        }
+    }
+
+    return s;
+}
diff --git a/src/socket_local.h b/src/socket_local.h
new file mode 100644 (file)
index 0000000..dc274ac
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 __SOCKET_LOCAL_H
+#define __SOCKET_LOCAL_H
+
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/" 
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+
+/*
+ * Set up a given sockaddr_un, to have it refer to the given
+ * name in the given namespace. The namespace must be one
+ * of <code>ANDROID_SOCKET_NAMESPACE_ABSTRACT</code>,
+ * <code>ANDROID_SOCKET_NAMESPACE_RESERVED</code>, or
+ * <code>ANDROID_SOCKET_NAMESPACE_FILESYSTEM</code>. Upon success,
+ * the pointed at sockaddr_un is filled in and the pointed at
+ * socklen_t is set to indicate the final length. This function
+ * will fail if the namespace is invalid (not one of the indicated
+ * constants) or if the name is too long.
+ * 
+ * @return 0 on success or -1 on failure
+ */ 
+int socket_make_sockaddr_un(const char *name, int namespaceId, 
+        struct sockaddr_un *p_addr, socklen_t *alen);
+
+#endif
diff --git a/src/socket_local_client.c b/src/socket_local_client.c
new file mode 100644 (file)
index 0000000..63d17ef
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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 "sockets.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifdef HAVE_WINSOCK
+
+int socket_local_client(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+#include "socket_local.h"
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int socket_make_sockaddr_un(const char *name, int namespaceId, 
+        struct sockaddr_un *p_addr, socklen_t *alen)
+{
+    memset (p_addr, 0, sizeof (*p_addr));
+    size_t namelen;
+
+    switch (namespaceId) {
+        case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+            namelen  = strlen(name);
+
+            // Test with length +1 for the *initial* '\0'.
+            if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+                goto error;
+            }
+
+            /*
+             * Note: The path in this case is *not* supposed to be
+             * '\0'-terminated. ("man 7 unix" for the gory details.)
+             */
+            
+            p_addr->sun_path[0] = 0;
+            memcpy(p_addr->sun_path + 1, name, namelen);
+#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+            /* this OS doesn't have the Linux abstract namespace */
+
+            namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+            strcat(p_addr->sun_path, name);
+#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+        break;
+
+        case ANDROID_SOCKET_NAMESPACE_RESERVED:
+            namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+            strcat(p_addr->sun_path, name);
+        break;
+
+        case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+            namelen = strlen(name);
+            /* unix_path_max appears to be missing on linux */
+            if (namelen > sizeof(*p_addr) 
+                    - offsetof(struct sockaddr_un, sun_path) - 1) {
+                goto error;
+            }
+
+            strcpy(p_addr->sun_path, name);
+        break;
+        default:
+            // invalid namespace id
+            return -1;
+    }
+
+    p_addr->sun_family = AF_LOCAL;
+    *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+    return 0;
+error:
+    return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ * 
+ * Used by AndroidSocketImpl
+ */
+int socket_local_client_connect(int fd, const char *name, int namespaceId, 
+        int type)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        goto error;
+    }
+
+    if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+        goto error;
+    }
+
+    return fd;
+
+error:
+    return -1;
+}
+
+/** 
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int socket_local_client(const char *name, int namespaceId, int type)
+{
+    int s;
+
+    s = socket(AF_LOCAL, type, 0);
+    if(s < 0) return -1;
+
+    if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
diff --git a/src/socket_local_server.c b/src/socket_local_server.c
new file mode 100644 (file)
index 0000000..489d17c
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+// libs/cutils/socket_local_server.c
+
+#include "sockets.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifdef HAVE_WINSOCK
+
+int socket_local_server(const char *name, int namespaceId, int type)
+{
+    errno = ENOSYS;
+    return -1;
+}
+
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "socket_local.h"
+
+#define LISTEN_BACKLOG 4
+
+
+/**
+ * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
+ * returns 's' on success, -1 on fail
+ *
+ * Does not call listen()
+ */
+int socket_local_server_bind(int s, const char *name, int namespaceId)
+{
+    struct sockaddr_un addr;
+    socklen_t alen;
+    int n;
+    int err;
+
+    err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+    if (err < 0) {
+        return -1;
+    }
+
+    /* basically: if this is a filesystem path, unlink first */
+#ifndef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+    if (1) {
+#else
+    if (namespaceId == ANDROID_SOCKET_NAMESPACE_RESERVED
+        || namespaceId == ANDROID_SOCKET_NAMESPACE_FILESYSTEM) {
+#endif
+        /*ignore ENOENT*/
+        unlink(addr.sun_path);
+    }
+
+    n = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+    if(bind(s, (struct sockaddr *) &addr, alen) < 0) {
+        return -1;
+    }
+
+    return s;
+
+}
+
+
+/** Open a server-side UNIX domain datagram socket in the Linux non-filesystem 
+ *  namespace
+ *
+ *  Returns fd on success, -1 on fail
+ */
+
+int socket_local_server(const char *name, int namespace, int type)
+{
+    int err;
+    int s;
+    
+    s = socket(AF_LOCAL, type, 0);
+    if (s < 0) return -1;
+
+    err = socket_local_server_bind(s, name, namespace);
+
+    if (err < 0) {
+        close(s);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            close(s);
+            return -1;
+        }
+    }
+
+    return s;
+}
+
+#endif /* !HAVE_WINSOCK */
diff --git a/src/socket_loopback_client.c b/src/socket_loopback_client.c
new file mode 100644 (file)
index 0000000..69fd87f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+// libs/cutils/socket_loopback_client.c
+
+#include "sockets.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#endif
+
+/* Connect to port on the loopback IP interface. type is
+ * SOCK_STREAM or SOCK_DGRAM. 
+ * return is a file descriptor or -1 on error
+ */
+int socket_loopback_client(int port, int type)
+{
+    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) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+
+}
+
diff --git a/src/socket_loopback_server.c b/src/socket_loopback_server.c
new file mode 100644 (file)
index 0000000..e38731d
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+// libs/cutils/socket_loopback_server.c
+
+#include "sockets.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#define LISTEN_BACKLOG 4
+#define LOOPBACK_UP 1
+#define LOOPBACK_DOWN 0
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#endif
+#include "sysdeps.h"
+
+int get_loopback_status(void) {
+
+       int           s;
+       struct ifconf ifc;
+       struct ifreq *ifr;
+       int           ifcnt;
+       char          buf[1024];
+       int i;
+
+       s = socket(AF_INET, SOCK_DGRAM, 0);
+       if(s < 0)
+       {
+               perror("socket");
+               return LOOPBACK_DOWN;
+       }
+
+       // query available interfaces
+       ifc.ifc_len = sizeof(buf);
+       ifc.ifc_buf = buf;
+       if(ioctl(s, SIOCGIFCONF, &ifc) < 0)
+       {
+               perror("ioctl(SIOCGIFCONF)");
+               return LOOPBACK_DOWN;
+       }
+
+       // iterate the list of interfaces
+       ifr = ifc.ifc_req;
+       ifcnt = ifc.ifc_len / sizeof(struct ifreq);
+       for(i = 0; i < ifcnt; i++)
+       {
+               struct sockaddr_in *addr;
+               addr = (struct sockaddr_in *)&ifr->ifr_addr;
+
+               if (ntohl(addr->sin_addr.s_addr) == INADDR_LOOPBACK)
+               {
+                       return LOOPBACK_UP;
+               }
+       }
+       return LOOPBACK_DOWN;
+}
+
+/* open listen() port on loopback interface */
+int socket_loopback_server(int port, int type)
+{
+    struct sockaddr_in addr;
+    int s, n;
+    int cnt_max = 30;
+
+    /* tizen specific */
+#if !SDB_HOST
+    // check the loopback interface has been up in 30 sec
+    while(cnt_max > 0) {
+        if(get_loopback_status() == LOOPBACK_DOWN) {
+            cnt_max--;
+            sdb_sleep_ms(1000);
+        }
+        else {
+            break;
+        }
+    }
+#endif
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_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);
+        return -1;
+    }
+
+    if (type == SOCK_STREAM) {
+        int ret;
+
+        ret = listen(s, LISTEN_BACKLOG);
+
+        if (ret < 0) {
+            sdb_close(s);
+            return -1; 
+        }
+    }
+
+    return s;
+}
+
diff --git a/src/socket_network_client.c b/src/socket_network_client.c
new file mode 100644 (file)
index 0000000..d2b436a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+// libs/cutils/socket_network_client.c
+
+#include "sockets.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifndef HAVE_WINSOCK
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+
+
+/* Connect to port on the IP interface. type is
+ * SOCK_STREAM or SOCK_DGRAM. 
+ * return is a file descriptor or -1 on error
+ */
+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(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+
+}
+
index b4e27e858d18dd2fb4cf12e57eda958a7f2d49b0..c621f473df6857ea5442b0e05292a38e64c41b17 100644 (file)
@@ -20,9 +20,8 @@
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
-#include "utils.h"
-#include "fdevent.h"
-#include "sdb_constants.h"
+
+#include "sysdeps.h"
 
 #define  TRACE_TAG  TRACE_SOCKETS
 #include "sdb.h"
@@ -413,15 +412,35 @@ asocket *create_local_service_socket(const char *name)
     asocket *s;
     int fd;
 
+#if 0 /* not support in tizen */
+#if !SDB_HOST
+    if (!strcmp(name,"jdwp")) {
+        return create_jdwp_service_socket();
+    }
+    if (!strcmp(name,"track-jdwp")) {
+        return create_jdwp_tracker_service_socket();
+    }
+#endif
+#endif
     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);
 
+#if !SDB_HOST
+    if ((!strncmp(name, "root:", 5) && getuid() != 0)
+        || !strncmp(name, "usb:", 4)
+        || !strncmp(name, "tcpip:", 6)) {
+        D("LS(%d): enabling exit_on_close\n", s->id);
+        s->exit_on_close = 1;
+    }
+#endif
+
     return s;
 }
 
+#if SDB_HOST
 static asocket *create_host_service_socket(const char *name, const char* serial)
 {
     asocket *s;
@@ -435,6 +454,7 @@ static asocket *create_host_service_socket(const char *name, const char* serial)
 
     return s;
 }
+#endif /* SDB_HOST */
 
 /* 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
@@ -619,9 +639,11 @@ char *skip_host_serial(char *service) {
 static int smart_socket_enqueue(asocket *s, apacket *p)
 {
     unsigned len;
+#if SDB_HOST
     char *service = NULL;
     char* serial = NULL;
     transport_type ttype = kTransportAny;
+#endif
 
     D("SS(%d): enqueue %d\n", s->id, p->len);
 
@@ -663,10 +685,11 @@ static int smart_socket_enqueue(asocket *s, apacket *p)
 
     D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
 
+#if SDB_HOST
     service = (char *)p->data + 4;
-    if(!strncmp(service, PREFIX_HOST_SERIAL, strlen(PREFIX_HOST_SERIAL))) {
+    if(!strncmp(service, "host-serial:", strlen("host-serial:"))) {
         char* serial_end;
-        service += strlen(PREFIX_HOST_SERIAL);
+        service += strlen("host-serial:");
 
         // serial number should follow "host:" and could be a host:port string.
         serial_end = skip_host_serial(service);
@@ -675,15 +698,15 @@ static int smart_socket_enqueue(asocket *s, apacket *p)
             serial = service;
             service = serial_end + 1;
         }
+    } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
         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))) {
+        service += strlen("host-usb:");
+    } else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
         ttype = kTransportLocal;
-        service += strlen(PREFIX_HOST_LOCAL);
-    } else if (!strncmp(service, PREFIX_HOST, strlen(PREFIX_HOST))) {
+        service += strlen("host-local:");
+    } else if (!strncmp(service, "host:", strlen("host:"))) {
         ttype = kTransportAny;
-        service += strlen(PREFIX_HOST);
+        service += strlen("host:");
     } else {
         service = NULL;
     }
@@ -739,6 +762,18 @@ static int smart_socket_enqueue(asocket *s, apacket *p)
         s2->ready(s2);
         return 0;
     }
+#else /* !SDB_HOST */
+    if (s->transport == NULL) {
+        char* error_string = "unknown failure";
+        s->transport = acquire_one_transport (CS_ANY,
+                kTransportAny, NULL, &error_string);
+
+        if (s->transport == NULL) {
+            sendfailmsg(s->peer->fd, error_string);
+            goto fail;
+        }
+    }
+#endif
 
     if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
            /* if there's no remote we fail the connection
diff --git a/src/sockets.dia b/src/sockets.dia
new file mode 100644 (file)
index 0000000..c626f20
Binary files /dev/null and b/src/sockets.dia differ
diff --git a/src/sockets.h b/src/sockets.h
new file mode 100644 (file)
index 0000000..8e8196a
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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 __CUTILS_SOCKETS_H
+#define __CUTILS_SOCKETS_H
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_WINSOCK
+#include <winsock2.h>
+typedef int  socklen_t;
+#elif HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#define ANDROID_SOCKET_ENV_PREFIX      "ANDROID_SOCKET_"
+#define ANDROID_SOCKET_DIR             "/dev/socket"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * android_get_control_socket - simple helper function to get the file
+ * descriptor of our init-managed Unix domain socket. `name' is the name of the
+ * socket, as given in init.rc. Returns -1 on error.
+ *
+ * This is inline and not in libcutils proper because we want to use this in
+ * third-party daemons with minimal modification.
+ */
+static inline int android_get_control_socket(const char *name)
+{
+       char key[64] = ANDROID_SOCKET_ENV_PREFIX;
+       const char *val;
+       int fd;
+
+       /* build our environment variable, counting cycles like a wolf ... */
+#if HAVE_STRLCPY
+       strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+               name,
+               sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+#else  /* for the host, which may lack the almightly strncpy ... */
+       strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
+               name,
+               sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
+       key[sizeof(key)-1] = '\0';
+#endif
+
+       val = getenv(key);
+       if (!val)
+               return -1;
+
+       errno = 0;
+       fd = strtol(val, NULL, 10);
+       if (errno)
+               return -1;
+
+       return fd;
+}
+
+/*
+ * See also android.os.LocalSocketAddress.Namespace
+ */
+// Linux "abstract" (non-filesystem) namespace
+#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
+// Android "reserved" (/dev/socket) namespace
+#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
+// Normal filesystem namespace
+#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
+
+extern int socket_loopback_client(int port, int type);
+extern int socket_network_client(const char *host, int port, int type);
+extern int socket_loopback_server(int port, int type);
+extern int socket_local_server(const char *name, int namespaceId, int type);
+extern int socket_local_server_bind(int s, const char *name, int namespaceId);
+extern int socket_local_client_connect(int fd, 
+        const char *name, int namespaceId, int type);
+extern int socket_local_client(const char *name, int namespaceId, int type);
+extern int socket_inaddr_any_server(int port, int type);
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_SOCKETS_H */ 
index 2823e1222b341fa25adf47474fbc0a753cd0b0bd..40fee05e67e460248c9605096c4e6d56814f4ae6 100644 (file)
@@ -1,8 +1,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "sysdeps.h"
 #include "strutils.h"
-#include "utils.h"
+
 #ifndef PATH_MAX
 #define PATH_MAX 4096
 #endif
diff --git a/src/sysdeps.h b/src/sysdeps.h
new file mode 100644 (file)
index 0000000..f2b4ad8
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+/* this file contains system-dependent definitions used by SDB
+ * they're related to threads, sockets and file descriptors
+ */
+#ifndef _SDB_SYSDEPS_H
+#define _SDB_SYSDEPS_H
+
+#ifdef __CYGWIN__
+#  undef _WIN32
+#endif
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <process.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define OS_PATH_SEPARATOR '\\'
+#define OS_PATH_SEPARATOR_STR "\\"
+
+typedef CRITICAL_SECTION          sdb_mutex_t;
+
+#define  SDB_MUTEX_DEFINE(x)     sdb_mutex_t   x
+
+/* declare all mutexes */
+/* For win32, sdb_sysdeps_init() will do the mutex runtime initialization. */
+#define  SDB_MUTEX(x)   extern sdb_mutex_t  x;
+#include "mutex_list.h"
+
+extern void  sdb_sysdeps_init(void);
+
+static __inline__ char* ansi_to_utf8(const char *str)
+{
+    int len;
+    char *utf8;
+    wchar_t *unicode;
+
+    //ANSI( MutiByte ) -> UCS-2( WideByte ) -> UTF-8( MultiByte )
+    len = MultiByteToWideChar (CP_ACP, 0, str, -1, NULL, 0);
+    unicode = (wchar_t *)calloc (len+1, sizeof(wchar_t));
+    MultiByteToWideChar (CP_ACP, 0, str, -1, unicode, len);
+
+    len = WideCharToMultiByte (CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
+    utf8 = (char *)calloc (len+1, sizeof(char));
+
+    WideCharToMultiByte (CP_UTF8, 0, unicode, -1, utf8, len, NULL, NULL);
+    free (unicode);
+
+    return utf8;
+}
+
+static __inline__ void sdb_mutex_lock( sdb_mutex_t*  lock )
+{
+    EnterCriticalSection( lock );
+}
+
+static __inline__ void  sdb_mutex_unlock( sdb_mutex_t*  lock )
+{
+    LeaveCriticalSection( lock );
+}
+
+typedef struct { unsigned  tid; }  sdb_thread_t;
+
+typedef  void*  (*sdb_thread_func_t)(void*  arg);
+
+typedef  void (*win_thread_func_t)(void*  arg);
+
+static __inline__ int  sdb_thread_create( sdb_thread_t  *thread, sdb_thread_func_t  func, void*  arg)
+{
+    thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
+    if (thread->tid == (unsigned)-1L) {
+        return -1;
+    }
+    return 0;
+}
+
+static __inline__ void  close_on_exec(int  fd)
+{
+    /* nothing really */
+}
+
+extern void  disable_tcp_nagle(int  fd);
+
+#define  lstat    stat   /* no symlinks on Win32 */
+
+#define  S_ISLNK(m)   0   /* no symlinks on Win32 */
+
+static __inline__  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;
+}
+#undef  unlink
+#define unlink  ___xxx_unlink
+
+static __inline__ int  sdb_mkdir(const char*  path, int mode)
+{
+    return _mkdir(path);
+}
+#undef   mkdir
+#define  mkdir  ___xxx_mkdir
+
+extern int  sdb_open(const char*  path, int  options);
+extern int  sdb_creat(const char*  path, int  mode);
+extern int  sdb_read(int  fd, void* buf, int len);
+extern int  sdb_write(int  fd, const void*  buf, int  len);
+extern int  sdb_lseek(int  fd, int  pos, int  where);
+extern int  sdb_shutdown(int  fd);
+extern int  sdb_close(int  fd);
+
+static __inline__ int  unix_close(int fd)
+{
+    return close(fd);
+}
+#undef   close
+#define  close   ____xxx_close
+
+static __inline__  int  unix_read(int  fd, void*  buf, size_t  len)
+{
+    return read(fd, buf, len);
+}
+#undef   read
+#define  read  ___xxx_read
+
+static __inline__  int  unix_write(int  fd, const void*  buf, size_t  len)
+{
+    return write(fd, buf, len);
+}
+#undef   write
+#define  write  ___xxx_write
+
+static __inline__ int  sdb_open_mode(const char* path, int options, int mode)
+{
+    return sdb_open(path, options);
+}
+
+static __inline__ 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);
+    }
+}
+#define  open    ___xxx_unix_open
+
+
+/* normally provided by <cutils/misc.h> */
+extern void*  load_file(const char*  pathname, unsigned*  psize);
+
+/* normally provided by <cutils/sockets.h> */
+extern int socket_loopback_client(int port, int type);
+extern int socket_network_client(const char *host, int port, int type);
+extern int socket_loopback_server(int port, int type);
+extern int socket_inaddr_any_server(int port, int type);
+
+/* normally provided by "fdevent.h" */
+
+#define FDE_READ              0x0001
+#define FDE_WRITE             0x0002
+#define FDE_ERROR             0x0004
+#define FDE_DONT_CLOSE        0x0080
+
+typedef struct fdevent fdevent;
+
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+
+fdevent *fdevent_create(int fd, fd_func func, void *arg);
+void     fdevent_destroy(fdevent *fde);
+void     fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
+void     fdevent_remove(fdevent *item);
+void     fdevent_set(fdevent *fde, unsigned events);
+void     fdevent_add(fdevent *fde, unsigned events);
+void     fdevent_del(fdevent *fde, unsigned events);
+void     fdevent_loop();
+
+struct fdevent {
+    fdevent *next;
+    fdevent *prev;
+
+    int fd;
+    int force_eof;
+
+    unsigned short state;
+    unsigned short events;
+
+    fd_func func;
+    void *arg;
+};
+
+static __inline__ void  sdb_sleep_ms( int  mseconds )
+{
+    Sleep( mseconds );
+}
+
+extern int  sdb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
+
+#undef   accept
+#define  accept  ___xxx_accept
+
+static __inline__  int  sdb_socket_setbufsize( int   fd, int  bufsize )
+{
+    int opt = bufsize;
+    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt));
+}
+
+extern int  sdb_socketpair( int  sv[2] );
+
+static __inline__  char*  sdb_dirstart( const char*  path )
+{
+    char*  p  = strchr(path, '/');
+    char*  p2 = strchr(path, '\\');
+
+    if ( !p )
+        p = p2;
+    else if ( p2 && p2 > p )
+        p = p2;
+
+    return p;
+}
+
+static __inline__  char*  sdb_dirstop( const char*  path )
+{
+    char*  p  = strrchr(path, '/');
+    char*  p2 = strrchr(path, '\\');
+
+    if ( !p )
+        p = p2;
+    else if ( p2 && p2 > p )
+        p = p2;
+
+    return p;
+}
+
+static __inline__  int  sdb_is_absolute_host_path( const char*  path )
+{
+    return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
+}
+
+#else /* !_WIN32 a.k.a. Unix */
+
+#include "fdevent.h"
+#include "sockets.h"
+#include "properties.h"
+// tizen specific #include <cutils/misc.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <string.h>
+
+#define OS_PATH_SEPARATOR '/'
+#define OS_PATH_SEPARATOR_STR "/"
+
+typedef  pthread_mutex_t          sdb_mutex_t;
+
+#define  SDB_MUTEX_INITIALIZER    PTHREAD_MUTEX_INITIALIZER
+#define  sdb_mutex_init           pthread_mutex_init
+#define  sdb_mutex_lock           pthread_mutex_lock
+#define  sdb_mutex_unlock         pthread_mutex_unlock
+#define  sdb_mutex_destroy        pthread_mutex_destroy
+
+#define  SDB_MUTEX_DEFINE(m)      sdb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
+
+#define  sdb_cond_t               pthread_cond_t
+#define  sdb_cond_init            pthread_cond_init
+#define  sdb_cond_wait            pthread_cond_wait
+#define  sdb_cond_broadcast       pthread_cond_broadcast
+#define  sdb_cond_signal          pthread_cond_signal
+#define  sdb_cond_destroy         pthread_cond_destroy
+
+/* declare all mutexes */
+#define  SDB_MUTEX(x)   extern sdb_mutex_t  x;
+#include "mutex_list.h"
+
+static __inline__ void  close_on_exec(int  fd)
+{
+    fcntl( fd, F_SETFD, FD_CLOEXEC );
+}
+
+static __inline__ 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);
+    }
+}
+
+static __inline__ int  sdb_open_mode( const char*  pathname, int  options, int  mode )
+{
+    return open( pathname, options, mode );
+}
+
+
+static __inline__ int  sdb_open( const char*  pathname, int  options )
+{
+    int  fd = open( pathname, options );
+    if (fd < 0)
+        return -1;
+    close_on_exec( fd );
+    return fd;
+}
+#undef   open
+#define  open    ___xxx_open
+
+static __inline__ int  sdb_shutdown(int fd)
+{
+    return shutdown(fd, SHUT_RDWR);
+}
+#undef   shutdown
+#define  shutdown   ____xxx_shutdown
+
+static __inline__ int  sdb_close(int fd)
+{
+    return close(fd);
+}
+#undef   close
+#define  close   ____xxx_close
+
+
+static __inline__  int  sdb_read(int  fd, void*  buf, size_t  len)
+{
+    return read(fd, buf, len);
+}
+
+#undef   read
+#define  read  ___xxx_read
+
+static __inline__  int  sdb_write(int  fd, const void*  buf, size_t  len)
+{
+    return write(fd, buf, len);
+}
+#undef   write
+#define  write  ___xxx_write
+
+static __inline__ int   sdb_lseek(int  fd, int  pos, int  where)
+{
+    return lseek(fd, pos, where);
+}
+#undef   lseek
+#define  lseek   ___xxx_lseek
+
+static __inline__  int    sdb_unlink(const char*  path)
+{
+    return  unlink(path);
+}
+#undef  unlink
+#define unlink  ___xxx_unlink
+
+static __inline__  int  sdb_creat(const char*  path, int  mode)
+{
+    int  fd = creat(path, mode);
+
+    if ( fd < 0 )
+        return -1;
+
+    close_on_exec(fd);
+    return fd;
+}
+#undef   creat
+#define  creat  ___xxx_creat
+
+static __inline__ int  sdb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
+{
+    int fd;
+
+    fd = accept(serverfd, addr, addrlen);
+    if (fd >= 0)
+        close_on_exec(fd);
+
+    return fd;
+}
+
+#undef   accept
+#define  accept  ___xxx_accept
+
+#define  unix_read   sdb_read
+#define  unix_write  sdb_write
+#define  unix_close  sdb_close
+
+typedef  pthread_t                 sdb_thread_t;
+
+typedef void*  (*sdb_thread_func_t)( void*  arg );
+
+static __inline__ int  sdb_thread_create( sdb_thread_t  *pthread, sdb_thread_func_t  start, void*  arg )
+{
+    pthread_attr_t   attr;
+
+    pthread_attr_init (&attr);
+    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+    return pthread_create( pthread, &attr, start, arg );
+}
+
+static __inline__  int  sdb_socket_setbufsize( int   fd, int  bufsize )
+{
+    int opt = bufsize;
+    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
+}
+
+static __inline__ void  disable_tcp_nagle(int fd)
+{
+    int  on = 1;
+    setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
+}
+
+
+static __inline__ int  unix_socketpair( int  d, int  type, int  protocol, int sv[2] )
+{
+    return socketpair( d, type, protocol, sv );
+}
+
+static __inline__ int  sdb_socketpair( int  sv[2] )
+{
+    int  rc;
+
+    rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
+    if (rc < 0)
+        return -1;
+
+    close_on_exec( sv[0] );
+    close_on_exec( sv[1] );
+    return 0;
+}
+
+#undef   socketpair
+#define  socketpair   ___xxx_socketpair
+
+static __inline__ void  sdb_sleep_ms( int  mseconds )
+{
+    usleep( mseconds*1000 );
+}
+
+static __inline__ int  sdb_mkdir(const char*  path, int mode)
+{
+    return mkdir(path, mode);
+}
+#undef   mkdir
+#define  mkdir  ___xxx_mkdir
+
+static __inline__ void  sdb_sysdeps_init(void)
+{
+}
+
+static __inline__ char*  sdb_dirstart(const char*  path)
+{
+    return strchr(path, '/');
+}
+
+static __inline__ char*  sdb_dirstop(const char*  path)
+{
+    return strrchr(path, '/');
+}
+
+static __inline__  int  sdb_is_absolute_host_path( const char*  path )
+{
+    return path[0] == '/';
+}
+
+static __inline__  char* ansi_to_utf8(const char *str)
+{
+    // Not implement!
+    // If need, use iconv later event though unix system is using utf8 encoding.
+    int len;
+    char *utf8;
+
+    len = strlen(str);
+    utf8 = (char *)calloc(len+1, sizeof(char));
+    strcpy(utf8, str);
+    return utf8;
+}
+
+#endif /* !_WIN32 */
+
+#endif /* _SDB_SYSDEPS_H */
diff --git a/src/sysdeps_win32.c b/src/sysdeps_win32.c
new file mode 100644 (file)
index 0000000..97399bf
--- /dev/null
@@ -0,0 +1,1982 @@
+/*
+ * 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 "sysdeps.h"
+#include <windows.h>
+#include <winsock2.h>
+#include <stdio.h>
+#include <errno.h>
+#define  TRACE_TAG  TRACE_SYSDEPS
+#include "sdb.h"
+
+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)
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****      replaces libs/cutils/load_file.c                          *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+void *load_file(const char *fn, unsigned *_sz)
+{
+    HANDLE    file;
+    char     *data;
+    DWORD     file_size;
+
+    file = CreateFile( fn,
+                       GENERIC_READ,
+                       FILE_SHARE_READ,
+                       NULL,
+                       OPEN_EXISTING,
+                       0,
+                       NULL );
+
+    if (file == INVALID_HANDLE_VALUE)
+        return NULL;
+
+    file_size = GetFileSize( file, NULL );
+    data      = NULL;
+
+    if (file_size > 0) {
+        data = (char*) malloc( file_size + 1 );
+        if (data == NULL) {
+            D("load_file: could not allocate %ld bytes\n", file_size );
+            file_size = 0;
+        } else {
+            DWORD  out_bytes;
+
+            if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
+                 out_bytes != file_size )
+            {
+                D("load_file: could not read %ld bytes from '%s'\n", file_size, fn);
+                free(data);
+                data      = NULL;
+                file_size = 0;
+            }
+        }
+    }
+    CloseHandle( file );
+
+    *_sz = (unsigned) file_size;
+    return  data;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    common file descriptor handling                             *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+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;
+
+/* 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;
+
+    HANDLE    event;
+    int       mask;
+
+    char  name[32];
+
+} FHRec;
+
+#define  fh_handle  u.handle
+#define  fh_socket  u.socket
+#define  fh_pair    u.pair
+
+#define  WIN32_FH_BASE    100
+
+#define  WIN32_MAX_FHS    128
+
+static sdb_mutex_t   _win32_lock;
+static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
+static  int          _win32_fh_count;
+
+static 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;
+    }
+
+    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;
+}
+
+
+static 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;
+}
+
+static FH
+_fh_alloc( FHClass  clazz )
+{
+    int  nn;
+    FH   f = NULL;
+
+    sdb_mutex_lock( &_win32_lock );
+
+    if (_win32_fh_count < WIN32_MAX_FHS) {
+        f = &_win32_fhs[ _win32_fh_count++ ];
+        goto Exit;
+    }
+
+    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;
+}
+
+/* forward definitions */
+static const FHClassRec   _fh_file_class;
+static const FHClassRec   _fh_socket_class;
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    file-based descriptor handling                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+static void
+_fh_file_init( FH  f )
+{
+    f->fh_handle = INVALID_HANDLE_VALUE;
+}
+
+static int
+_fh_file_close( FH  f )
+{
+    CloseHandle( f->fh_handle );
+    f->fh_handle = INVALID_HANDLE_VALUE;
+    return 0;
+}
+
+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
+_fh_file_write( FH  f,  const void*  buf, int   len )
+{
+    DWORD  wrote_bytes;
+
+    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;
+    }
+    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;
+    }
+
+    result = SetFilePointer( f->fh_handle, pos, NULL, method );
+    if (result == INVALID_SET_FILE_POINTER) {
+        errno = EIO;
+        return -1;
+    } else {
+        f->eof = 0;
+    }
+    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                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+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);
+            errno = EINVAL;
+            return -1;
+    }
+
+    f = _fh_alloc( &_fh_file_class );
+    if ( !f ) {
+        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);
+}
+
+/* ignore mode on Win32 */
+int  sdb_creat(const char*  path, int  mode)
+{
+    FH  f;
+
+    f = _fh_alloc( &_fh_file_class );
+    if ( !f ) {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    f->fh_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;
+        }
+    }
+    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);
+}
+
+
+int  sdb_read(int  fd, void* buf, int len)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (f == NULL) {
+        return -1;
+    }
+
+    return f->clazz->_fh_read( f, buf, len );
+}
+
+
+int  sdb_write(int  fd, const void*  buf, int  len)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (f == NULL) {
+        return -1;
+    }
+
+    return f->clazz->_fh_write(f, buf, len);
+}
+
+
+int  sdb_lseek(int  fd, int  pos, int  where)
+{
+    FH     f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    return f->clazz->_fh_lseek(f, pos, where);
+}
+
+
+int  sdb_shutdown(int  fd)
+{
+    FH   f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    D( "sdb_shutdown: %s\n", f->name);
+    shutdown( f->fh_socket, SD_BOTH );
+    return 0;
+}
+
+
+int  sdb_close(int  fd)
+{
+    FH   f = _fh_from_int(fd);
+
+    if (!f) {
+        return -1;
+    }
+
+    D( "sdb_close: %s\n", f->name);
+    _fh_close(f);
+    return 0;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    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 )
+{
+    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" );
+        }
+        atexit( _cleanup_winsock );
+        _winsock_init = 1;
+    }
+}
+
+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
+
+int socket_loopback_server(int port, int type)
+{
+    FH   f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+    int  n;
+
+    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) 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);
+        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(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);
+}
+
+
+int socket_network_client(const char *host, int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct hostent *hp;
+    struct sockaddr_in addr;
+    SOCKET s;
+
+    if (!f)
+        return -1;
+
+    if (!_winsock_init)
+        _init_winsock();
+
+    hp = gethostbyname(host);
+    if(hp == 0) {
+        _fh_close(f);
+        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 == INVALID_SOCKET) {
+        _fh_close(f);
+        return -1;
+    }
+    f->fh_socket = s;
+
+    if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        _fh_close(f);
+        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);
+}
+
+
+int socket_inaddr_any_server(int port, int type)
+{
+    FH  f = _fh_alloc( &_fh_socket_class );
+    struct sockaddr_in addr;
+    SOCKET  s;
+    int n;
+
+    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_ANY);
+
+    s = socket(AF_INET, type, 0);
+    if(s == INVALID_SOCKET) {
+        _fh_close(f);
+        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);
+        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);
+}
+
+#undef accept
+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() );
+        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);
+}
+
+
+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);
+}
+
+#else
+#  define  BIPD(x)        do {} while (0)
+#  define  BIPDUMP(p,l)   BIPD(p)
+#endif
+
+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;
+
+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 );
+    }
+}
+
+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 );
+}
+
+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;
+
+        memcpy( bip->buff + bip->a_end, src, avail );
+        src   += avail;
+        count += avail;
+        len   -= avail;
+
+        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 (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;
+
+    if (bip->b_end == bip->a_start) {
+        bip->can_write = 0;
+        ResetEvent( bip->evt_write );
+    }
+
+Exit:
+    assert( count > 0 );
+
+    if ( !bip->can_read ) {
+        bip->can_read = 1;
+        SetEvent( bip->evt_read );
+    }
+
+    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;
+        return -1;
+#else    
+        int  ret;
+        LeaveCriticalSection( &bip->lock );
+
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+
+        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;
+        }
+        if (bip->closed) {
+            errno = EPIPE;
+            return -1;
+        }
+        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;
+        }
+
+        bip_buffer_close( &pair->b2a_bip );
+        bip_buffer_close( &pair->a2b_bip );
+
+        if ( --pair->used == 0 ) {
+            bip_buffer_done( &pair->b2a_bip );
+            bip_buffer_done( &pair->a2b_bip );
+            free( pair );
+        }
+        f->fh_pair = NULL;
+    }
+    return 0;
+}
+
+static int
+_fh_socketpair_lseek( FH  f, int pos, int  origin )
+{
+    errno = ESPIPE;
+    return -1;
+}
+
+static int
+_fh_socketpair_read( FH  f, void* buf, int  len )
+{
+    SocketPair  pair = f->fh_pair;
+    BipBuffer   bip;
+
+    if (!pair)
+        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;
+
+    if (!pair)
+        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
+};
+
+
+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 );
+
+    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];
+
+    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] );
+    return 0;
+
+Fail:
+    _fh_close(fb);
+    _fh_close(fa);
+    return -1;
+}
+
+/**************************************************************************/
+/**************************************************************************/
+/*****                                                                *****/
+/*****    fdevents emulation                                          *****/
+/*****                                                                *****/
+/*****   this is a very simple implementation, we rely on the fact    *****/
+/*****   that SDB doesn't use FDE_ERROR.                              *****/
+/*****                                                                *****/
+/**************************************************************************/
+/**************************************************************************/
+
+#define FATAL(x...) fatal(__FUNCTION__, x)
+
+#if DEBUG
+static 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
+
+#define FDE_EVENTMASK  0x00ff
+#define FDE_STATEMASK  0xff00
+
+#define FDE_ACTIVE     0x0100
+#define FDE_PENDING    0x0200
+#define FDE_CREATED    0x0400
+
+static void fdevent_plist_enqueue(fdevent *node);
+static void fdevent_plist_remove(fdevent *node);
+static fdevent *fdevent_plist_dequeue(void);
+
+static fdevent list_pending = {
+    .next = &list_pending,
+    .prev = &list_pending,
+};
+
+static fdevent **fd_table = 0;
+static int       fd_table_max = 0;
+
+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;
+
+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" );
+    }
+    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;
+}
+
+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
+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;
+    }
+}
+
+
+#define  MAX_LOOPER_HANDLES  WIN32_MAX_FHS
+
+typedef struct EventLooperRec_
+{
+    EventHook    hooks;
+    HANDLE       htab[ MAX_LOOPER_HANDLES ];
+    int          htab_count;
+
+} EventLooperRec;
+
+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;
+    }
+    return  pnode;
+}
+
+static void
+event_looper_hook( EventLooper  looper, int  fd, int  events )
+{
+    FH          f = _fh_from_int(fd);
+    EventHook  *pnode;
+    EventHook   node;
+
+    if (f == NULL)  /* invalid arg */ {
+        D("event_looper_hook: invalid fd=%d\n", fd);
+        return;
+    }
+
+    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);
+    }
+}
+
+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 EventLooperRec  win32_looper;
+
+static void fdevent_init(void)
+{
+    win32_looper.htab_count = 0;
+    win32_looper.hooks      = NULL;
+}
+
+static void fdevent_connect(fdevent *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 );
+}
+
+static void fdevent_update(fdevent *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 );
+        }
+    }
+}
+
+static void fdevent_process()
+{
+    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)
+    {
+        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 (looper->htab_count == 0) {
+            D( "fdevent_process: nothing to wait for !!\n" );
+            return;
+        }
+
+        do
+        {
+            int   wait_ret;
+
+            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 );
+
+                /* 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 );
+    }
+}
+
+
+static void fdevent_register(fdevent *fde)
+{
+    int  fd = fde->fd - WIN32_FH_BASE;
+
+    if(fd < 0) {
+        FATAL("bogus negative fd (%d)\n", fde->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_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));
+    }
+
+    fd_table[fd] = fde;
+}
+
+static void fdevent_unregister(fdevent *fde)
+{
+    int  fd = fde->fd - WIN32_FH_BASE;
+
+    if((fd < 0) || (fd >= fd_table_max)) {
+        FATAL("fd out of range (%d)\n", fde->fd);
+    }
+
+    if(fd_table[fd] != fde) {
+        FATAL("fd_table out of sync");
+    }
+
+    fd_table[fd] = 0;
+
+    if(!(fde->state & FDE_DONT_CLOSE)) {
+        dump_fde(fde, "close");
+        sdb_close(fde->fd);
+    }
+}
+
+static void fdevent_plist_enqueue(fdevent *node)
+{
+    fdevent *list = &list_pending;
+
+    node->next = list;
+    node->prev = list->prev;
+    node->prev->next = node;
+    list->prev = node;
+}
+
+static void fdevent_plist_remove(fdevent *node)
+{
+    node->prev->next = node->next;
+    node->next->prev = node->prev;
+    node->next = 0;
+    node->prev = 0;
+}
+
+static 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);
+    }
+    fdevent_remove(fde);
+}
+
+void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) 
+{
+    memset(fde, 0, sizeof(fdevent));
+    fde->state = FDE_ACTIVE;
+    fde->fd = fd;
+    fde->func = func;
+    fde->arg = arg;
+
+    fdevent_register(fde);
+    dump_fde(fde, "connect");
+    fdevent_connect(fde);
+    fde->state |= FDE_ACTIVE;
+}
+
+void fdevent_remove(fdevent *fde)
+{
+    if(fde->state & FDE_PENDING) {
+        fdevent_plist_remove(fde);
+    }
+
+    if(fde->state & FDE_ACTIVE) {
+        fdevent_disconnect(fde);
+        dump_fde(fde, "disconnect");    
+        fdevent_unregister(fde);
+    }
+
+    fde->state = 0;
+    fde->events = 0;
+}
+
+
+void fdevent_set(fdevent *fde, unsigned events)
+{
+    events &= FDE_EVENTMASK;
+
+    if((fde->state & FDE_EVENTMASK) == (int)events) return;
+
+    if(fde->state & FDE_ACTIVE) {
+        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));
+}
+
+void fdevent_del(fdevent *fde, unsigned events)
+{
+    fdevent_set(
+        fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
+}
+
+void fdevent_loop()
+{
+    fdevent *fde;
+
+    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);
+        }
+    }
+}
+
+/**  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;
+}
+
+
+void
+sdb_sysdeps_init( void )
+{
+#define  SDB_MUTEX(x)  InitializeCriticalSection( & x );
+#include "mutex_list.h"
+    InitializeCriticalSection( &_win32_lock );
+}
diff --git a/src/threads.h b/src/threads.h
new file mode 100644 (file)
index 0000000..dc587b9
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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 _LIBS_CUTILS_THREADS_H
+#define _LIBS_CUTILS_THREADS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****         local thread storage                                *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#ifdef HAVE_PTHREADS
+
+#include  <pthread.h>
+
+typedef struct {
+    pthread_mutex_t   lock;
+    int               has_tls;
+    pthread_key_t     tls;
+
+} thread_store_t;
+
+#define  THREAD_STORE_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, 0 }
+
+#elif defined HAVE_WIN32_THREADS
+
+#include <windows.h>
+
+typedef struct {
+    int               lock_init;
+    int               has_tls;
+    DWORD             tls;
+    CRITICAL_SECTION  lock;
+
+} thread_store_t;
+
+#define  THREAD_STORE_INITIALIZER  { 0, 0, 0, {0, 0, 0, 0, 0, 0} }
+
+#else
+#  error  "no thread_store_t implementation for your platform !!"
+#endif
+
+typedef void  (*thread_store_destruct_t)(void*  value);
+
+extern void*  thread_store_get(thread_store_t*  store);
+
+extern void   thread_store_set(thread_store_t*          store,
+                               void*                    value,
+                               thread_store_destruct_t  destroy);
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****         mutexes                                             *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#ifdef HAVE_PTHREADS
+
+typedef pthread_mutex_t   mutex_t;
+
+#define  MUTEX_INITIALIZER  PTHREAD_MUTEX_INITIALIZER
+
+static __inline__ void  mutex_lock(mutex_t*  lock)
+{
+    pthread_mutex_lock(lock);
+}
+static __inline__ void  mutex_unlock(mutex_t*  lock)
+{
+    pthread_mutex_unlock(lock);
+}
+static __inline__ int  mutex_init(mutex_t*  lock)
+{
+    return pthread_mutex_init(lock, NULL);
+}
+static __inline__ void mutex_destroy(mutex_t*  lock)
+{
+    pthread_mutex_destroy(lock);
+}
+#endif
+
+#ifdef HAVE_WIN32_THREADS
+typedef struct {
+    int                init;
+    CRITICAL_SECTION   lock[1];
+} mutex_t;
+
+#define  MUTEX_INITIALIZER  { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} }
+
+static __inline__ void  mutex_lock(mutex_t*  lock)
+{
+    if (!lock->init) {
+        lock->init = 1;
+        InitializeCriticalSection( lock->lock );
+        lock->init = 2;
+    } else while (lock->init != 2)
+        Sleep(10);
+
+    EnterCriticalSection(lock->lock);
+}
+
+static __inline__ void  mutex_unlock(mutex_t*  lock)
+{
+    LeaveCriticalSection(lock->lock);
+}
+static __inline__ int  mutex_init(mutex_t*  lock)
+{
+    InitializeCriticalSection(lock->lock);
+    lock->init = 2;
+    return 0;
+}
+static __inline__ void  mutex_destroy(mutex_t*  lock)
+{
+    if (lock->init) {
+        lock->init = 0;
+        DeleteCriticalSection(lock->lock);
+    }
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBS_CUTILS_THREADS_H */
index a082ad497ef24edac6bbb8014204146bf1dfe39c..4e7ff0bdaa077c910e173a95f5ff8be9daf8a91f 100755 (executable)
@@ -19,8 +19,9 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-#include "fdevent.h"
-#include "utils.h"
+
+#include "sysdeps.h"
+
 #define   TRACE_TAG  TRACE_TRANSPORT
 #include "sdb.h"
 
@@ -390,6 +391,7 @@ static int transport_registration_recv = -1;
 static fdevent transport_registration_fde;
 
 
+#if SDB_HOST
 static int list_transports_msg(char*  buffer, size_t  bufferlen)
 {
     char  head[5];
@@ -530,6 +532,12 @@ void  update_transports(void)
         tracker = next;
     }
 }
+#else
+void  update_transports(void)
+{
+    // nothing to do on the device side
+}
+#endif // SDB_HOST
 
 typedef struct tmsg tmsg;
 struct tmsg
@@ -582,9 +590,9 @@ transport_write_action(int  fd, struct tmsg*  m)
     return 0;
 }
 
-
-static sdb_cond_t cond;// = PTHREAD_COND_INITIALIZER;
-
+#ifndef _WIN32 /* FIXME : change for windows build */
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+#endif
 static void transport_registration_func(int _fd, unsigned ev, void *data)
 {
     tmsg m;
@@ -615,9 +623,9 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
         sdb_mutex_lock(&transport_lock);
         t->next->prev = t->prev;
         t->prev->next = t->next;
-
-        sdb_cond_broadcast(&cond);
-
+#ifndef _WIN32
+        pthread_cond_broadcast(&cond);
+#endif
         sdb_mutex_unlock(&transport_lock);
 
         run_transport_disconnects(t);
@@ -672,9 +680,9 @@ static void transport_registration_func(int _fd, unsigned ev, void *data)
     t->prev = transport_list.prev;
     t->next->prev = t;
     t->prev->next = t;
-
-    sdb_cond_broadcast(&cond);
-
+#ifndef _WIN32
+    pthread_cond_broadcast(&cond);
+#endif
     sdb_mutex_unlock(&transport_lock);
 
     t->disconnects.next = t->disconnects.prev = &t->disconnects;
@@ -864,6 +872,7 @@ retry:
     return result;
 }
 
+#if SDB_HOST
 static const char *statename(atransport *t)
 {
     switch(t->connection_state){
@@ -960,6 +969,7 @@ void close_usb_devices()
     }
     sdb_mutex_unlock(&transport_lock);
 }
+#endif // SDB_HOST
 
 void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name)
 {
@@ -974,18 +984,20 @@ void register_socket_transport(int s, const char *serial, int port, int local, c
     if ( init_socket_transport(t, s, port, local) < 0 ) {
         sdb_close(s);
         free(t);
+#if SDB_HOST /* tizen specific */
         atransport *old_t = find_transport(serial);
         if (old_t) {
            unregister_transport(old_t);
         } else {
            D("No such device %s", serial);
         }
+#endif
         return;
     }
     if(serial) {
         t->serial = strdup(serial);
     }
-
+#if SDB_HOST /* tizen specific */
     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.
@@ -994,10 +1006,11 @@ void register_socket_transport(int s, const char *serial, int port, int local, c
             t->device_name = strdup(device_name);
         }
     }
-
+#endif
     register_transport(t);
 }
 
+#if SDB_HOST
 atransport *find_transport(const char *serial)
 {
     atransport *t;
@@ -1050,7 +1063,9 @@ void unregister_all_tcp_transports()
     sdb_mutex_unlock(&transport_lock);
 }
 
-static int get_connected_device_count(transport_type type)
+#endif
+
+int get_connected_device_count(transport_type type) /* tizen specific */
 {
     int cnt = 0;
     atransport *t;
@@ -1059,7 +1074,6 @@ static int get_connected_device_count(transport_type type)
         if (type == t->type)
             cnt++;
      }
-
     sdb_mutex_unlock(&transport_lock);
     D("connected device count:%d\n",cnt);
     return cnt;
@@ -1081,9 +1095,9 @@ void register_usb_transport(usb_handle *usb, const char *serial, unsigned writea
      */
      sdb_mutex_lock(&transport_lock);
      register_transport(t);
-     sdb_cond_init(&cond, NULL);
-     sdb_cond_wait(&cond, &transport_lock);
-
+#ifndef _WIN32
+     pthread_cond_wait(&cond, &transport_lock);
+#endif
      sdb_mutex_unlock(&transport_lock);
     /* tizen specific */
     sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb));
index 8fca32d08512d4aa06772fd9adc87382ef1253d0..f1e7dc0c06932d36a73b69993bc8be2429738c14 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include "fdevent.h"
-#include "utils.h"
+
+#include "sysdeps.h"
 #include <sys/types.h>
 
-#ifndef OS_WINDOWS
+#ifndef HAVE_WIN32_IPC
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <unistd.h>
@@ -46,6 +46,7 @@ static inline void fix_endians(apacket *p)
 #define fix_endians(p) do {} while (0)
 #endif
 
+#if SDB_HOST
 /* 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.
@@ -55,6 +56,7 @@ static inline void fix_endians(apacket *p)
 SDB_MUTEX_DEFINE( local_transports_lock );
 
 static atransport*  local_transports[ SDB_LOCAL_TRANSPORT_MAX ];
+#endif /* SDB_HOST */
 
 static int remote_read(apacket *p, atransport *t)
 {
@@ -115,7 +117,15 @@ int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *de
     char buf[64];
     int  fd = -1;
 
-    fd = socket_loopback_client(sdb_port, SOCK_STREAM);
+#if SDB_HOST
+    const char *host = getenv("SDBHOST");
+    if (host) {
+        fd = socket_network_client(host, sdb_port, SOCK_STREAM);
+    }
+#endif
+    if (fd < 0) {
+        fd = socket_loopback_client(sdb_port, SOCK_STREAM);
+    }
 
     if (fd >= 0) {
         D("client: connected on remote on fd %d\n", fd);
@@ -128,10 +138,11 @@ int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *de
     return -1;
 }
 
+#if SDB_HOST /* tizen specific */
 int get_devicename_from_shdmem(int port, char *device_name)
 {
     char *vms = NULL;
-#ifndef OS_WINDOWS
+#ifndef HAVE_WIN32_IPC
     int shm_id;
     void *shared_memory = (void *)0;
 
@@ -193,8 +204,11 @@ int get_devicename_from_shdmem(int port, char *device_name)
     return 0;
 }
 
-static void *register_local_connections(void *x)
+#endif
+
+static void *client_socket_thread(void *x)
 {
+#if SDB_HOST
     int  port  = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
     int  count = SDB_LOCAL_TRANSPORT_MAX;
 
@@ -203,22 +217,189 @@ static void *register_local_connections(void *x)
     /* 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 ) {
+    for ( ; count > 0; count--, port += 10 ) { /* tizen specific */
         (void) local_connect(port, NULL);
     }
+#endif
+    return 0;
+}
+
+static void *server_socket_thread(void * arg)
+{
+    int serverfd, fd;
+    struct sockaddr addr;
+    socklen_t alen;
+    int port = (int)arg;
+
+    D("transport: server_socket_thread() starting\n");
+    serverfd = -1;
+    for(;;) {
+        if(serverfd == -1) {
+            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
+            if(serverfd < 0) {
+                D("server: cannot bind socket yet\n");
+                sdb_sleep_ms(1000);
+                continue;
+            }
+            close_on_exec(serverfd);
+        }
 
+        alen = sizeof(addr);
+        D("server: trying to get new connection from %d\n", port);
+        fd = sdb_socket_accept(serverfd, &addr, &alen);
+        if(fd >= 0) {
+            D("server: new connection on fd %d\n", fd);
+            close_on_exec(fd);
+            disable_tcp_nagle(fd);
+            register_socket_transport(fd, "host", port, 1, NULL);
+        }
+    }
+    D("transport: server_socket_thread() exiting\n");
     return 0;
 }
 
-/**
- * register local connections
+/* This is relevant only for SDB daemon running inside the emulator. */
+#if !SDB_HOST
+/*
+ * Redefine open and write for qemu_pipe.h that contains inlined references
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ */
+#undef open
+#undef write
+#define open    sdb_open
+#define write   sdb_write
+#include "qemu_pipe.h"
+#undef open
+#undef write
+#define open    ___xxx_open
+#define write   ___xxx_write
+
+/* A worker thread that monitors host connections, and registers a transport for
+ * every new host connection. This thread replaces server_socket_thread on
+ * condition that sdbd daemon runs inside the emulator, and emulator uses QEMUD
+ * pipe to communicate with sdbd daemon inside the guest. This is done in order
+ * to provide more robust communication channel between SDB host and guest. The
+ * main issue with server_socket_thread approach is that it runs on top of TCP,
+ * and thus is sensitive to network disruptions. For instance, the
+ * ConnectionManager may decide to reset all network connections, in which case
+ * the connection between SDB host and guest will be lost. To make SDB traffic
+ * independent from the network, we use here 'sdb' QEMUD service to transfer data
+ * between the host, and the guest. See external/qemu/android/sdb-*.* that
+ * implements the emulator's side of the protocol. Another advantage of using
+ * QEMUD approach is that SDB will be up much sooner, since it doesn't depend
+ * anymore on network being set up.
+ * The guest side of the protocol contains the following phases:
+ * - Connect with sdb QEMUD service. In this phase a handle to 'sdb' QEMUD service
+ *   is opened, and it becomes clear whether or not emulator supports that
+ *   protocol.
+ * - Wait for the SDB host to create connection with the guest. This is done by
+ *   sending an 'accept' request to the sdb QEMUD service, and waiting on
+ *   response.
+ * - When new SDB host connection is accepted, the connection with sdb QEMUD
+ *   service is registered as the transport, and a 'start' request is sent to the
+ *   sdb QEMUD service, indicating that the guest is ready to receive messages.
+ *   Note that the guest will ignore messages sent down from the emulator before
+ *   the transport registration is completed. That's why we need to send the
+ *   'start' request after the transport is registered.
  */
+#if 0
+static void *qemu_socket_thread(void * arg)
+{
+/* 'accept' request to the sdb QEMUD service. */
+static const char _accept_req[] = "accept";
+/* 'start' request to the sdb QEMUD service. */
+static const char _start_req[]  = "start";
+/* 'ok' reply from the sdb QEMUD service. */
+static const char _ok_resp[]    = "ok";
+
+    const int port = (int)arg;
+    int res, fd;
+    char tmp[256];
+    char con_name[32];
+
+    D("transport: qemu_socket_thread() starting\n");
+
+    /* sdb QEMUD service connection request. */
+    snprintf(con_name, sizeof(con_name), "qemud:sdb:%d", port);
+
+    /* Connect to the sdb QEMUD service. */
+    fd = qemu_pipe_open(con_name);
+    if (fd < 0) {
+        /* This could be an older version of the emulator, that doesn't
+         * implement sdb QEMUD service. Fall back to the old TCP way. */
+        sdb_thread_t thr;
+        D("sdb service is not available. Falling back to TCP socket.\n");
+        sdb_thread_create(&thr, server_socket_thread, arg);
+        return 0;
+    }
+
+    for(;;) {
+        /*
+         * Wait till the host creates a new connection.
+         */
+
+        /* Send the 'accept' request. */
+        res = sdb_write(fd, _accept_req, strlen(_accept_req));
+        if (res == strlen(_accept_req)) {
+            /* Wait for the response. In the response we expect 'ok' on success,
+             * or 'ko' on failure. */
+            res = sdb_read(fd, tmp, sizeof(tmp));
+            if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
+                D("Accepting SDB host connection has failed.\n");
+                sdb_close(fd);
+            } else {
+                /* Host is connected. Register the transport, and start the
+                 * exchange. */
+                register_socket_transport(fd, "host", port, 1, NULL);
+                sdb_write(fd, _start_req, strlen(_start_req));
+            }
+
+            /* Prepare for accepting of the next SDB host connection. */
+            fd = qemu_pipe_open(con_name);
+            if (fd < 0) {
+                D("sdb service become unavailable.\n");
+                return 0;
+            }
+        } else {
+            D("Unable to send the '%s' request to SDB service.\n", _accept_req);
+            return 0;
+        }
+    }
+    D("transport: qemu_socket_thread() exiting\n");
+    return 0;
+}
+#endif  // !SDB_HOST
+#endif
+
 void local_init(int port)
 {
     sdb_thread_t thr;
     void* (*func)(void *);
 
-    func = register_local_connections;
+    if(HOST) {
+        func = client_socket_thread;
+    } else {
+#if SDB_HOST
+        func = server_socket_thread;
+#else
+        /* For the sdbd daemon in the system image we need to distinguish
+         * between the device, and the emulator. */
+#if 0 /* tizen specific */
+        char is_qemu[PROPERTY_VALUE_MAX];
+        property_get("ro.kernel.qemu", is_qemu, "");
+        if (!strcmp(is_qemu, "1")) {
+            /* Running inside the emulator: use QEMUD pipe as the transport. */
+            func = qemu_socket_thread;
+        } else
+#endif
+        {
+            /* Running inside the device: use TCP socket as the transport. */
+            func = server_socket_thread;
+        }
+#endif // !SDB_HOST
+    }
+
+    D("transport: local %s init\n", HOST ? "client" : "server");
 
     if(sdb_thread_create(&thr, func, (void *)port)) {
         fatal_errno("cannot create local socket %s thread",
@@ -229,21 +410,23 @@ void local_init(int port)
 static void remote_kick(atransport *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;
+#if SDB_HOST
+    if(HOST) {
+        int  nn;
+        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 );
     }
-
-    sdb_mutex_unlock( &local_transports_lock );
+#endif
 }
 
 static void remote_close(atransport *t)
@@ -252,6 +435,7 @@ static void remote_close(atransport *t)
 }
 
 
+#if SDB_HOST
 /* Only call this function if you already hold local_transports_lock. */
 atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port)
 {
@@ -291,6 +475,7 @@ int get_available_local_transport_index()
     sdb_mutex_unlock( &local_transports_lock );
     return result;
 }
+#endif
 
 int init_socket_transport(atransport *t, int s, int sdb_port, int local)
 {
@@ -306,6 +491,7 @@ int init_socket_transport(atransport *t, int s, int sdb_port, int local)
     t->type = kTransportLocal;
     t->sdb_port = 0;
 
+#if SDB_HOST
     if (HOST && local) {
         sdb_mutex_lock( &local_transports_lock );
         {
@@ -328,6 +514,6 @@ int init_socket_transport(atransport *t, int s, int sdb_port, int local)
        }
        sdb_mutex_unlock( &local_transports_lock );
     }
-
+#endif
     return fail;
 }
index d809086428d7254e95904805aad7bb766242bfb9..e4de29ab5b0813b19750179c7f12d525d0cec6da 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include "fdevent.h"
-#include "utils.h"
+#include <sysdeps.h>
+
 #define  TRACE_TAG  TRACE_TRANSPORT
 #include "sdb.h"
 
+#if SDB_HOST
+#include "usb_vendors.h"
+#endif
+
 #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)
@@ -48,7 +52,7 @@ unsigned host_to_le32(unsigned n)
 
 static int remote_read(apacket *p, atransport *t)
 {
-    if(sdb_usb_read(t->usb, &p->msg, sizeof(amessage))){
+    if(usb_read(t->usb, &p->msg, sizeof(amessage))){
         D("remote usb: read terminated (message)\n");
         return -1;
     }
@@ -61,7 +65,7 @@ static int remote_read(apacket *p, atransport *t)
     }
 
     if(p->msg.data_length) {
-        if(sdb_usb_read(t->usb, p->data, p->msg.data_length)){
+        if(usb_read(t->usb, p->data, p->msg.data_length)){
             D("remote usb: terminated (data)\n");
             return -1;
         }
@@ -81,12 +85,12 @@ static int remote_write(apacket *p, atransport *t)
 
     fix_endians(p);
 
-    if(sdb_usb_write(t->usb, &p->msg, sizeof(amessage))) {
+    if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
         D("remote usb: 1 - write terminated\n");
         return -1;
     }
     if(p->msg.data_length == 0) return 0;
-    if(sdb_usb_write(t->usb, &p->data, size)) {
+    if(usb_write(t->usb, &p->data, size)) {
         D("remote usb: 2 - write terminated\n");
         return -1;
     }
@@ -96,13 +100,13 @@ static int remote_write(apacket *p, atransport *t)
 
 static void remote_close(atransport *t)
 {
-    sdb_usb_close(t->usb);
+    usb_close(t->usb);
     t->usb = 0;
 }
 
 static void remote_kick(atransport *t)
 {
-    sdb_usb_kick(t->usb);
+    usb_kick(t->usb);
 }
 
 void init_usb_transport(atransport *t, usb_handle *h, int state)
@@ -117,5 +121,28 @@ void init_usb_transport(atransport *t, usb_handle *h, int state)
     t->type = kTransportUsb;
     t->usb = h;
 
+#if SDB_HOST
     HOST = 1;
+#else
+    HOST = 0;
+#endif
 }
+
+#if SDB_HOST
+int is_sdb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
+{
+    unsigned i;
+    for (i = 0; i < vendorIdCount; i++) {
+        if (vid == vendorIds[i]) {
+            if (usb_class == SDB_CLASS && usb_subclass == SDB_SUBCLASS &&
+                    usb_protocol == SDB_PROTOCOL) {
+                return 1;
+            }
+
+            return 0;
+        }
+    }
+
+    return 0;
+}
+#endif
diff --git a/src/usb_libusb.c b/src/usb_libusb.c
new file mode 100644 (file)
index 0000000..ab847bf
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * 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 <sys/endian.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <libusb.h>
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "sdb.h"
+
+static sdb_mutex_t usb_lock = SDB_MUTEX_INITIALIZER;
+static libusb_context *ctx = NULL;
+
+struct usb_handle
+{
+    usb_handle            *prev;
+    usb_handle            *next;
+
+    libusb_device         *dev;
+    libusb_device_handle  *devh;
+    int                   interface;
+    uint8_t               dev_bus;
+    uint8_t               dev_addr;
+       
+    int                   zero_mask;
+    unsigned char         end_point_address[2];
+    char                  serial[128];
+    
+    sdb_cond_t            notify;
+    sdb_mutex_t           lock;
+};
+
+static struct usb_handle handle_list = {
+        .prev = &handle_list,
+        .next = &handle_list,
+};
+
+void
+usb_cleanup()
+{
+       libusb_exit(ctx);
+}
+
+void
+report_bulk_libusb_error(int r)
+{
+    switch (r) {
+    case LIBUSB_ERROR_TIMEOUT:
+        D("Transfer timeout\n");
+        break;
+
+    case LIBUSB_ERROR_PIPE:
+        D("Control request is not supported\n");
+        break;
+
+    case LIBUSB_ERROR_OVERFLOW:
+        D("Device offered more data\n");
+        break;
+
+    case LIBUSB_ERROR_NO_DEVICE :
+        D("Device was disconnected\n");
+        break;
+
+    default:
+        D("Error %d during transfer\n", r);
+        break;
+    };
+}
+
+static int
+usb_bulk_write(usb_handle *uh, const void *data, int len)
+{
+    int r = 0;
+    int transferred = 0;
+
+    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[1], (void *)data, len,
+                             &transferred, 0);
+   
+    if (r != 0) {
+        D("usb_bulk_write(): ");
+        report_bulk_libusb_error(r);
+        return r;
+    }
+   
+    return (transferred);
+}
+
+static int
+usb_bulk_read(usb_handle *uh, void *data, int len)
+{
+    int r = 0;
+    int transferred = 0;
+
+    r = libusb_bulk_transfer(uh->devh, uh->end_point_address[0], data, len,
+                             &transferred, 0);
+
+    if (r != 0) {
+        D("usb_bulk_read(): ");
+        report_bulk_libusb_error(r);
+        return r;
+    }
+   
+    return (transferred);
+}
+
+int
+usb_write(struct usb_handle *uh, const void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+    int need_zero = 0;
+
+    if (uh->zero_mask == 1) {
+        if (!(len & uh->zero_mask)) {
+            need_zero = 1;
+        }
+    }
+
+    D("usb_write(): %p:%d -> transport %p\n", _data, len, uh);
+    
+    while (len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        n = usb_bulk_write(uh, data, xfer);
+        
+        if (n != xfer) {
+            D("usb_write(): failed for transport %p (%d bytes left)\n", uh, len);
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    if (need_zero){
+        n = usb_bulk_write(uh, _data, 0);
+        
+        if (n < 0) {
+            D("usb_write(): failed to finish operation for transport %p\n", uh);
+        }
+        return n;
+    }
+
+    return 0;
+}
+
+int
+usb_read(struct usb_handle *uh, void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+
+    D("usb_read(): %p:%d <- transport %p\n", _data, len, uh);
+    
+    while (len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        n = usb_bulk_read(uh, data, xfer);
+        
+        if (n != xfer) {
+            if (n > 0) {
+                data += n;
+                len -= n;
+                continue;
+            }
+            
+            D("usb_read(): failed for transport %p (%d bytes left)\n", uh, len);
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    return 0;
+ }
+
+int
+usb_close(struct usb_handle *h)
+{
+    D("usb_close(): closing transport %p\n", h);
+    sdb_mutex_lock(&usb_lock);
+    
+    h->next->prev = h->prev;
+    h->prev->next = h->next;
+    h->prev = NULL;
+    h->next = NULL;
+
+    libusb_release_interface(h->devh, h->interface);
+    libusb_close(h->devh);
+    libusb_unref_device(h->dev);
+    
+    sdb_mutex_unlock(&usb_lock);
+
+    free(h);
+
+    return (0);
+}
+
+void usb_kick(struct usb_handle *h)
+{
+    D("usb_cick(): kicking transport %p\n", h);
+    
+    sdb_mutex_lock(&h->lock);
+    unregister_usb_transport(h);
+    sdb_mutex_unlock(&h->lock);
+    
+    h->next->prev = h->prev;
+    h->prev->next = h->next;
+    h->prev = NULL;
+    h->next = NULL;
+
+    libusb_release_interface(h->devh, h->interface);
+    libusb_close(h->devh);
+    libusb_unref_device(h->dev);
+    free(h);
+}
+
+int
+check_usb_interface(libusb_interface *interface,
+                    libusb_device_descriptor *desc,
+                    struct usb_handle *uh)
+{    
+    int e;
+    
+    if (interface->num_altsetting == 0) {
+        D("check_usb_interface(): No interface settings\n");
+        return -1;
+    }
+    
+    libusb_interface_descriptor *idesc = &interface->altsetting[0];
+    
+    if (idesc->bNumEndpoints != 2) {
+        D("check_usb_interface(): Interface have not 2 endpoints, ignoring\n");
+        return -1;
+    }
+
+    for (e = 0; e < idesc->bNumEndpoints; e++) {
+        libusb_endpoint_descriptor *edesc = &idesc->endpoint[e];
+        
+        if (edesc->bmAttributes != LIBUSB_TRANSFER_TYPE_BULK) {
+            D("check_usb_interface(): Endpoint (%u) is not bulk (%u), ignoring\n",
+                    edesc->bmAttributes, LIBUSB_TRANSFER_TYPE_BULK);
+            return -1;
+        }
+        
+        if (edesc->bEndpointAddress & LIBUSB_ENDPOINT_IN)
+            uh->end_point_address[0] = edesc->bEndpointAddress;
+        else
+            uh->end_point_address[1] = edesc->bEndpointAddress;
+        
+            /* aproto 01 needs 0 termination */
+        if (idesc->bInterfaceProtocol == 0x01) {
+            uh->zero_mask = edesc->wMaxPacketSize - 1;
+            D("check_usb_interface(): Forced Android interface protocol v.1\n");
+        }
+    }
+
+    D("check_usb_interface(): Device: %04x:%04x "
+      "iclass: %x, isclass: %x, iproto: %x ep: %x/%x-> ",
+        desc->idVendor, desc->idProduct, idesc->bInterfaceClass,
+       idesc->bInterfaceSubClass, idesc->bInterfaceProtocol,
+       uh->end_point_address[0], uh->end_point_address[1]);
+    
+    if (!is_sdb_interface(desc->idVendor, desc->idProduct,
+            idesc->bInterfaceClass, idesc->bInterfaceSubClass,
+            idesc->bInterfaceProtocol))
+    {
+        D("not matches\n");
+        return -1;
+    }
+
+    D("matches\n");
+    return 1;
+}
+
+int
+check_usb_interfaces(libusb_config_descriptor *config,
+                     libusb_device_descriptor *desc, struct usb_handle *uh)
+{  
+    int i;
+    
+    for (i = 0; i < config->bNumInterfaces; ++i) {
+        if (check_usb_interface(&config->interface[i], desc, uh) != -1) {
+            /* found some interface and saved information about it */
+            D("check_usb_interfaces(): Interface %d of %04x:%04x "
+              "matches Android device\n", i, desc->idVendor,
+             desc->idProduct);
+            
+            return  i;
+        }
+    }
+    
+    return -1;
+}
+
+int
+register_device(struct usb_handle *uh, const char *serial)
+{
+    D("register_device(): Registering %p [%s] as USB transport\n",
+       uh, serial);
+
+    struct usb_handle *usb= NULL;
+
+    usb = calloc(1, sizeof(struct usb_handle));
+    memcpy(usb, uh, sizeof(struct usb_handle));
+    strcpy(usb->serial, uh->serial);
+
+    sdb_cond_init(&usb->notify, 0);
+    sdb_mutex_init(&usb->lock, 0);
+
+    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, 1); 
+
+    return (1);
+}
+
+int
+already_registered(usb_handle *uh)
+{
+    struct usb_handle *usb= NULL;
+    int exists = 0;
+    
+    sdb_mutex_lock(&usb_lock);
+
+    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        if ((usb->dev_bus == uh->dev_bus) &&
+            (usb->dev_addr == uh->dev_addr))
+        {
+            exists = 1;
+            break;
+        }
+    }
+
+    sdb_mutex_unlock(&usb_lock);
+
+    return exists;
+}
+
+void
+check_device(libusb_device *dev) 
+{
+    struct usb_handle uh;
+    int i = 0;
+    int found = -1;
+    char serial[256] = {0};
+
+    libusb_device_descriptor desc;
+    libusb_config_descriptor *config = NULL;
+    
+    int r = libusb_get_device_descriptor(dev, &desc);
+
+    if (r != LIBUSB_SUCCESS) {
+        D("check_device(): Failed to get device descriptor\n");
+        return;
+    }
+    
+    if ((desc.idVendor == 0) && (desc.idProduct == 0))
+        return;
+    
+    D("check_device(): Probing usb device %04x:%04x\n",
+        desc.idVendor, desc.idProduct);
+    
+    if (!is_sdb_interface (desc.idVendor, desc.idProduct,
+                           SDB_CLASS, SDB_SUBCLASS, SDB_PROTOCOL))
+    {
+        D("check_device(): Ignored due unknown vendor id\n");
+        return;
+    }
+    
+    uh.dev_bus = libusb_get_bus_number(dev);
+    uh.dev_addr = libusb_get_device_address(dev);
+    
+    if (already_registered(&uh)) {
+        D("check_device(): Device (bus: %d, address: %d) "
+          "is already registered\n", uh.dev_bus, uh.dev_addr);
+        return;
+    }
+    
+    D("check_device(): Device bus: %d, address: %d\n",
+        uh.dev_bus, uh.dev_addr);
+
+    r = libusb_get_active_config_descriptor(dev, &config);
+    
+    if (r != 0) {
+        if (r == LIBUSB_ERROR_NOT_FOUND) {
+            D("check_device(): Device %4x:%4x is unconfigured\n", 
+                desc.idVendor, desc.idProduct);
+            return;
+        }
+        
+        D("check_device(): Failed to get configuration for %4x:%4x\n",
+            desc.idVendor, desc.idProduct);
+        return;
+    }
+    
+    if (config == NULL) {
+        D("check_device(): Sanity check failed after "
+          "getting active config\n");
+        return;
+    }
+    
+    if (config->interface != NULL) {
+        found = check_usb_interfaces(config, &desc, &uh);
+    }
+    
+    /* not needed anymore */
+    libusb_free_config_descriptor(config);
+    
+    r = libusb_open(dev, &uh.devh);
+    uh.dev = dev;
+
+    if (r != 0) {
+        switch (r) {
+            case LIBUSB_ERROR_NO_MEM:
+                D("check_device(): Memory allocation problem\n");
+                break;
+                
+            case LIBUSB_ERROR_ACCESS:
+                D("check_device(): Permissions problem, "
+                  "current user priveleges are messed up?\n");
+                break;
+                
+            case LIBUSB_ERROR_NO_DEVICE:
+                D("check_device(): Device disconected, bad cable?\n");
+                break;
+            
+            default:
+                D("check_device(): libusb triggered error %d\n", r);
+        }
+        // skip rest
+        found = -1;
+    }
+    
+    if (found >= 0) {
+        D("check_device(): Device matches Android interface\n");
+        // read the device's serial number
+        memset(serial, 0, sizeof(serial));
+        uh.interface = found;
+        
+        r = libusb_claim_interface(uh.devh, uh.interface);
+        
+        if (r < 0) {
+            D("check_device(): Failed to claim interface %d\n",
+                uh.interface);
+
+            goto fail;
+        }
+
+        if (desc.iSerialNumber) {
+            // reading serial
+            uint16_t    buffer[128] = {0};
+            uint16_t    languages[128] = {0};
+            int languageCount = 0;
+
+            memset(languages, 0, sizeof(languages));
+            r = libusb_control_transfer(uh.devh, 
+                LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+                LIBUSB_REQUEST_GET_DESCRIPTOR, LIBUSB_DT_STRING << 8,
+               0, (uint8_t *)languages, sizeof(languages), 0);
+
+            if (r <= 0) {
+                D("check_device(): Failed to get languages count\n");
+                goto fail;
+            } 
+            
+            languageCount = (r - 2) / 2;
+            
+            for (i = 1; i <= languageCount; ++i) {
+                memset(buffer, 0, sizeof(buffer));
+
+                r = libusb_control_transfer(uh.devh, 
+                    LIBUSB_ENDPOINT_IN |  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+                    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc.iSerialNumber,
+                   languages[i], (uint8_t *)buffer, sizeof(buffer), 0);
+            
+                if (r > 0) { /* converting serial */
+                    int j = 0;
+                    r /= 2;
+                
+                    for (j = 1; j < r; ++j) {
+                        serial[j - 1] = buffer[j];
+                    }
+                
+                    serial[j - 1] = '\0';
+                    break; /* languagesCount cycle */
+                }
+            }
+            
+            if (register_device(&uh, serial) == 0) {
+                D("check_device(): Failed to register device\n");
+                goto fail_interface;
+            }
+            
+            libusb_ref_device(dev);
+        }
+    }
+    
+    return;
+
+fail_interface:
+    libusb_release_interface(uh.devh, uh.interface);
+
+fail:
+    libusb_close(uh.devh);
+    uh.devh = NULL;
+}
+
+int
+check_device_connected(struct usb_handle *uh)
+{
+    int r = libusb_kernel_driver_active(uh->devh, uh->interface);
+    
+    if (r == LIBUSB_ERROR_NO_DEVICE)
+        return 0;
+    
+    if (r < 0)
+        return -1;
+    
+    return 1;
+}
+
+void
+kick_disconnected()
+{
+    struct usb_handle *usb= NULL;
+    
+    sdb_mutex_lock(&usb_lock);
+
+    for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        
+        if (check_device_connected(usb) == 0) {
+            D("kick_disconnected(): Transport %p is not online anymore\n",
+                usb);
+
+            usb_kick(usb);
+        }
+    }
+    
+    sdb_mutex_unlock(&usb_lock);
+}
+
+void
+scan_usb_devices()
+{
+    D("scan_usb_devices(): started\n");
+    
+    libusb_device **devs= NULL;
+    libusb_device *dev= NULL;
+    ssize_t cnt = libusb_get_device_list(ctx, &devs);
+
+    if (cnt < 0) {
+        D("scan_usb_devices(): Failed to get device list (error: %d)\n",
+            cnt);
+
+        return;
+    }
+    
+    int i = 0;
+
+    while ((dev = devs[i++]) != NULL) {
+        check_device(dev);
+    }
+
+    libusb_free_device_list(devs, 1);
+}
+
+void *
+device_poll_thread(void* unused)
+{
+    D("device_poll_thread(): Created USB scan thread\n");
+    
+    for (;;) {
+        sleep(5);
+        kick_disconnected();
+        scan_usb_devices();
+    }
+
+    /* never reaching this point */
+    return (NULL);
+}
+
+static void
+sigalrm_handler(int signo)
+{
+    /* nothing */
+}
+
+void
+usb_init()
+{
+    D("usb_init(): started\n");
+    sdb_thread_t        tid;
+    struct sigaction actions;
+
+    int r = libusb_init(&ctx);
+
+    if (r != LIBUSB_SUCCESS) {
+        err(EX_IOERR, "Failed to init libusb\n");
+    }
+
+    memset(&actions, 0, sizeof(actions));
+    
+    sigemptyset(&actions.sa_mask);
+    
+    actions.sa_flags = 0;
+    actions.sa_handler = sigalrm_handler;
+    
+    sigaction(SIGALRM, &actions, NULL);
+
+       /* initial device scan */
+       scan_usb_devices();
+       
+       /* starting USB event polling thread */
+    if (sdb_thread_create(&tid, device_poll_thread, NULL)) {
+            err(EX_IOERR, "cannot create USB scan thread\n");
+    }
+    
+    D("usb_init(): finished\n");
+}
+
diff --git a/src/usb_linux.c b/src/usb_linux.c
new file mode 100755 (executable)
index 0000000..158c686
--- /dev/null
@@ -0,0 +1,715 @@
+/*
+ * 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 <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 <linux/usb/ch9.h>
+#else
+#include <linux/usb_ch9.h>
+#endif
+#include <asm/byteorder.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "sdb.h"
+
+
+/* usb scan debugging is waaaay too verbose */
+#define DBGX(x...)
+
+SDB_MUTEX_DEFINE( usb_lock );
+
+struct usb_handle
+{
+    usb_handle *prev;
+    usb_handle *next;
+
+    char fname[64];
+    int desc;
+    unsigned char ep_in;
+    unsigned char ep_out;
+
+    unsigned zero_mask;
+    unsigned writeable;
+
+    struct usbdevfs_urb urb_in;
+    struct usbdevfs_urb urb_out;
+
+    int urb_in_busy;
+    int urb_out_busy;
+    int dead;
+
+    sdb_cond_t notify;
+    sdb_mutex_t lock;
+
+    // for garbage collecting disconnected devices
+    int mark;
+
+    // ID of thread currently in REAPURB
+    pthread_t reaper_thread;
+};
+
+static usb_handle handle_list = {
+    .prev = &handle_list,
+    .next = &handle_list,
+};
+
+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;
+        }
+    }
+    sdb_mutex_unlock(&usb_lock);
+    return 0;
+}
+
+static void 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) {
+            usb_kick(usb);
+        } else {
+            usb->mark = 0;
+        }
+    }
+    sdb_mutex_unlock(&usb_lock);
+
+}
+
+static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
+                            int ifc, int serial_index, unsigned zero_mask);
+
+static inline int badname(const char *name)
+{
+    while(*name) {
+        if(!isdigit(*name++)) return 1;
+    }
+    return 0;
+}
+
+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;
+            }
+
+//            DBGX("[ scanning %s ]\n", devname);
+            if((fd = unix_open(devname, O_RDONLY)) < 0) {
+                continue;
+            }
+
+            desclength = sdb_read(fd, devdesc, sizeof(devdesc));
+            bufend = bufptr + desclength;
+
+                // 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;
+            }
+
+            device = (struct usb_device_descriptor*)bufptr;
+            bufptr += USB_DT_DEVICE_SIZE;
+
+            if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
+                sdb_close(fd);
+                continue;
+            }
+
+            vid = device->idVendor;
+            pid = device->idProduct;
+            DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
+
+                // should have config descriptor next
+            config = (struct usb_config_descriptor *)bufptr;
+
+            /* tizen specific */
+            if (device->bNumConfigurations > 1) {
+                bufptr += config->wTotalLength;
+                config = (struct usb_config_descriptor *)bufptr;
+                bufend = bufptr + config->wTotalLength;
+            }
+
+            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;
+            }
+
+                // loop through all the descriptors and look for the SDB interface
+            while (bufptr < bufend) {
+                unsigned char length = bufptr[0];
+                unsigned char type = bufptr[1];
+
+                if (type == USB_DT_INTERFACE) {
+                    interface = (struct usb_interface_descriptor *)bufptr;
+                    bufptr += length;
+
+                    if (length != USB_DT_INTERFACE_SIZE) {
+                        D("interface descriptor has wrong size\n");
+                        break;
+                    }
+
+                    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, pid, 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;
+                    }
+                } else {
+                    bufptr += length;
+                }
+            } // end of while
+
+            sdb_close(fd);
+        } // end of devdir while
+        closedir(devdir);
+    } //end of busdir while
+    closedir(busdir);
+}
+
+void usb_cleanup()
+{
+}
+
+static int usb_bulk_write(usb_handle *h, const void *data, int len)
+{
+    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));
+
+    if(res < 0) {
+        goto fail;
+    }
+
+    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;
+        }
+    }
+fail:
+    sdb_mutex_unlock(&h->lock);
+    D("-- write --\n");
+    return res;
+}
+
+static int usb_bulk_read(usb_handle *h, void *data, int len)
+{
+    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;
+    }
+    do {
+        res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
+    } while((res < 0) && (errno == EINTR));
+
+    if(res < 0) {
+        goto fail;
+    }
+
+    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;
+        }
+        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;
+            }
+            break;
+        }
+        if(out == &h->urb_out) {
+            D("[ reap urb - OUT compelete ]\n");
+            h->urb_out_busy = 0;
+            sdb_cond_broadcast(&h->notify);
+        }
+    }
+fail:
+    sdb_mutex_unlock(&h->lock);
+    return res;
+}
+
+
+int 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;
+        }
+    }
+
+    while(len > 0) {
+        int xfer = (len > 4096) ? 4096 : len;
+
+        n = usb_bulk_write(h, data, xfer);
+        if(n != xfer) {
+            D("ERROR: n = %d, errno = %d (%s)\n",
+                n, errno, strerror(errno));
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    if(need_zero){
+        n = usb_bulk_write(h, _data, 0);
+        return n;
+    }
+
+    return 0;
+}
+
+int usb_read(usb_handle *h, void *_data, int len)
+{
+    unsigned char *data = (unsigned char*) _data;
+    int n;
+
+    D("++ usb_read ++\n");
+    while(len > 0) {
+        int xfer = (len > 4096) ? 4096 : 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);
+        if(n != xfer) {
+            if((errno == ETIMEDOUT) && (h->desc != -1)) {
+                D("[ timeout ]\n");
+                if(n > 0){
+                    data += n;
+                    len -= n;
+                }
+                continue;
+            }
+            D("ERROR: n = %d, errno = %d (%s)\n",
+                n, errno, strerror(errno));
+            return -1;
+        }
+
+        len -= xfer;
+        data += xfer;
+    }
+
+    D("-- usb_read --\n");
+    return 0;
+}
+
+void 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);
+}
+
+int 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;
+}
+
+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);
+        /* tizen specific */
+        n = ioctl(usb->desc, USBDEVFS_RESET);
+        if(n != 0) {
+            D("[ usb reset failed %s fd = %d]\n", usb->fname, usb->desc);
+            goto fail;
+        }
+        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);
+            goto fail;
+        }
+    }
+
+        /* 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);
+        kick_disconnected_devices();
+        sleep(1);
+    }
+    return NULL;
+}
+
+static void sigalrm_handler(int signo)
+{
+    // don't need to do anything here
+}
+
+void 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");
+    }
+}
diff --git a/src/usb_linux_client.c b/src/usb_linux_client.c
new file mode 100644 (file)
index 0000000..e15690f
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "sdb.h"
+
+
+struct usb_handle
+{
+    int fd;
+    sdb_cond_t notify;
+    sdb_mutex_t lock;
+};
+
+void usb_cleanup()
+{
+    // nothing to do here
+}
+
+static void *usb_open_thread(void *x)
+{
+    struct usb_handle *usb = (struct usb_handle *)x;
+    int fd;
+
+    while (1) {
+        // wait until the USB device needs opening
+        sdb_mutex_lock(&usb->lock);
+        while (usb->fd != -1) {
+            sdb_cond_wait(&usb->notify, &usb->lock);
+        }
+        sdb_mutex_unlock(&usb->lock);
+
+        D("[ usb_thread - opening device ]\n");
+        do {
+            /* XXX use inotify? */
+            fd = unix_open("/dev/samsung_sdb", O_RDWR); /* tizen-specific */
+            if (fd < 0) {
+                // to support older kernels
+                //fd = unix_open("/dev/android", O_RDWR);
+                D("[ opening /dev/samsung_sdb device failed ]\n");
+            }
+            if (fd < 0) {
+                sdb_sleep_ms(1000);
+            }
+        } while (fd < 0);
+        D("[ opening device succeeded ]\n");
+
+        close_on_exec(fd);
+        usb->fd = fd;
+
+        D("[ usb_thread - registering device ]\n");
+        register_usb_transport(usb, 0, 1);
+    }
+
+    // never gets here
+    return 0;
+}
+
+int usb_write(usb_handle *h, const void *data, int len)
+{
+    int n;
+
+    D("about to write (fd=%d, len=%d)\n", h->fd, len);
+    n = sdb_write(h->fd, data, len);
+    if(n != len) {
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->fd, n, errno, strerror(errno));
+        return -1;
+    }
+    D("[ done fd=%d ]\n", h->fd);
+    return 0;
+}
+
+int usb_read(usb_handle *h, void *data, int len)
+{
+    int n;
+
+    D("about to read (fd=%d, len=%d)\n", h->fd, len);
+    n = sdb_read(h->fd, data, len);
+    if(n != len) {
+        D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
+            h->fd, n, errno, strerror(errno));
+        return -1;
+    }
+    D("[ done fd=%d ]\n", h->fd);
+    return 0;
+}
+
+void usb_init()
+{
+    usb_handle *h;
+    sdb_thread_t tid;
+//  int fd;
+
+    h = calloc(1, sizeof(usb_handle));
+    h->fd = -1;
+    sdb_cond_init(&h->notify, 0);
+    sdb_mutex_init(&h->lock, 0);
+
+    // Open the file /dev/android_sdb_enable to trigger 
+    // the enabling of the sdb USB function in the kernel.
+    // We never touch this file again - just leave it open
+    // indefinitely so the kernel will know when we are running
+    // and when we are not.
+#if 0 /* tizen specific */
+    fd = unix_open("/dev/android_sdb_enable", O_RDWR);
+    if (fd < 0) {
+       D("failed to open /dev/android_sdb_enable\n");
+    } else {
+        close_on_exec(fd);
+    }
+#endif
+    D("[ usb_init - starting thread ]\n");
+    if(sdb_thread_create(&tid, usb_open_thread, h)){
+        fatal_errno("cannot create usb thread");
+    }
+}
+
+void usb_kick(usb_handle *h)
+{
+    D("usb_kick\n");
+    sdb_mutex_lock(&h->lock);
+    sdb_close(h->fd);
+    h->fd = -1;
+
+    // notify usb_open_thread that we are disconnected
+    sdb_cond_signal(&h->notify);
+    sdb_mutex_unlock(&h->lock);
+}
+
+int usb_close(usb_handle *h)
+{
+    // nothing to do here
+    return 0;
+}
diff --git a/src/usb_osx.c b/src/usb_osx.c
new file mode 100644 (file)
index 0000000..683dadd
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * 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 <CoreFoundation/CoreFoundation.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOMessage.h>
+#include <mach/mach_port.h>
+
+#include "sysdeps.h"
+
+#include <stdio.h>
+
+#define TRACE_TAG   TRACE_USB
+#include "sdb.h"
+#include "usb_vendors.h"
+
+#define  DBG   D
+
+static IONotificationPortRef    notificationPort = 0;
+static io_iterator_t*           notificationIterators;
+
+struct usb_handle
+{
+    UInt8                     bulkIn;
+    UInt8                     bulkOut;
+    IOUSBInterfaceInterface   **interface;
+    io_object_t               usbNotification;
+    unsigned int              zero_mask;
+};
+
+static CFRunLoopRef currentRunLoop = 0;
+static pthread_mutex_t start_lock;
+static pthread_cond_t start_cond;
+
+
+static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
+static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
+                                   natural_t messageType,
+                                   void *messageArgument);
+static usb_handle* CheckInterface(IOUSBInterfaceInterface **iface,
+                                  UInt16 vendor, UInt16 product);
+
+static int
+InitUSB()
+{
+    CFMutableDictionaryRef  matchingDict;
+    CFRunLoopSourceRef      runLoopSource;
+    SInt32                  vendor, if_subclass, if_protocol;
+    unsigned                i;
+
+    //* To set up asynchronous notifications, create a notification port and
+    //* add its run loop event source to the program's run loop
+    notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
+    runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
+
+    memset(notificationIterators, 0, sizeof(notificationIterators));
+
+    //* loop through all supported vendors
+    for (i = 0; i < vendorIdCount; i++) {
+        //* Create our matching dictionary to find the Android device's
+        //* sdb interface
+        //* IOServiceAddMatchingNotification consumes the reference, so we do
+        //* not need to release this
+        matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
+
+        if (!matchingDict) {
+            DBG("ERR: Couldn't create USB matching dictionary.\n");
+            return -1;
+        }
+
+        //* Match based on vendor id, interface subclass and protocol
+        vendor = vendorIds[i];
+        if_subclass = SDB_SUBCLASS;
+        if_protocol = SDB_PROTOCOL;
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID),
+                             CFNumberCreate(kCFAllocatorDefault,
+                                            kCFNumberSInt32Type, &vendor));
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass),
+                             CFNumberCreate(kCFAllocatorDefault,
+                                            kCFNumberSInt32Type, &if_subclass));
+        CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol),
+                             CFNumberCreate(kCFAllocatorDefault,
+                                            kCFNumberSInt32Type, &if_protocol));
+        IOServiceAddMatchingNotification(
+                notificationPort,
+                kIOFirstMatchNotification,
+                matchingDict,
+                AndroidInterfaceAdded,
+                NULL,
+                &notificationIterators[i]);
+
+        //* Iterate over set of matching interfaces to access already-present
+        //* devices and to arm the notification
+        AndroidInterfaceAdded(NULL, notificationIterators[i]);
+    }
+
+    return 0;
+}
+
+static void
+AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
+{
+    kern_return_t            kr;
+    io_service_t             usbDevice;
+    io_service_t             usbInterface;
+    IOCFPlugInInterface      **plugInInterface = NULL;
+    IOUSBInterfaceInterface220  **iface = NULL;
+    IOUSBDeviceInterface197  **dev = NULL;
+    HRESULT                  result;
+    SInt32                   score;
+    UInt16                   vendor;
+    UInt16                   product;
+    UInt8                    serialIndex;
+    char                     serial[256];
+
+    while ((usbInterface = IOIteratorNext(iterator))) {
+        //* Create an intermediate interface plugin
+        kr = IOCreatePlugInInterfaceForService(usbInterface,
+                                               kIOUSBInterfaceUserClientTypeID,
+                                               kIOCFPlugInInterfaceID,
+                                               &plugInInterface, &score);
+        IOObjectRelease(usbInterface);
+        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
+            DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
+            continue;
+        }
+
+        //* This gets us the interface object
+        result = (*plugInInterface)->QueryInterface(plugInInterface,
+                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
+                &iface);
+        //* We only needed the plugin to get the interface, so discard it
+        (*plugInInterface)->Release(plugInInterface);
+        if (result || !iface) {
+            DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
+            continue;
+        }
+
+        //* this gets us an ioservice, with which we will find the actual
+        //* device; after getting a plugin, and querying the interface, of
+        //* course.
+        //* Gotta love OS X
+        kr = (*iface)->GetDevice(iface, &usbDevice);
+        if (kIOReturnSuccess != kr || !usbDevice) {
+            DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
+            continue;
+        }
+
+        plugInInterface = NULL;
+        score = 0;
+        //* create an intermediate device plugin
+        kr = IOCreatePlugInInterfaceForService(usbDevice,
+                                               kIOUSBDeviceUserClientTypeID,
+                                               kIOCFPlugInInterfaceID,
+                                               &plugInInterface, &score);
+        //* only needed this to find the plugin
+        (void)IOObjectRelease(usbDevice);
+        if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
+            DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
+            continue;
+        }
+
+        result = (*plugInInterface)->QueryInterface(plugInInterface,
+                CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
+        //* only needed this to query the plugin
+        (*plugInInterface)->Release(plugInInterface);
+        if (result || !dev) {
+            DBG("ERR: Couldn't create a device interface (%08x)\n",
+                (int) result);
+            continue;
+        }
+
+        //* Now after all that, we actually have a ref to the device and
+        //* the interface that matched our criteria
+
+        kr = (*dev)->GetDeviceVendor(dev, &vendor);
+        kr = (*dev)->GetDeviceProduct(dev, &product);
+        kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
+
+       if (serialIndex > 0) {
+               IOUSBDevRequest req;
+               UInt16          buffer[256];
+               UInt16          languages[128];
+
+               memset(languages, 0, sizeof(languages));
+
+               req.bmRequestType =
+                       USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+               req.bRequest = kUSBRqGetDescriptor;
+               req.wValue = (kUSBStringDesc << 8) | 0;
+               req.wIndex = 0;
+               req.pData = languages;
+               req.wLength = sizeof(languages);
+               kr = (*dev)->DeviceRequest(dev, &req);
+
+               if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+
+                       int langCount = (req.wLenDone - 2) / 2, lang;
+
+                       for (lang = 1; lang <= langCount; lang++) {
+
+                                memset(buffer, 0, sizeof(buffer));
+                                memset(&req, 0, sizeof(req));
+
+                               req.bmRequestType =
+                                       USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+                               req.bRequest = kUSBRqGetDescriptor;
+                               req.wValue = (kUSBStringDesc << 8) | serialIndex;
+                               req.wIndex = languages[lang];
+                               req.pData = buffer;
+                               req.wLength = sizeof(buffer);
+                               kr = (*dev)->DeviceRequest(dev, &req);
+
+                               if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+                                       int i, count;
+
+                                       // skip first word, and copy the rest to the serial string,
+                                       // changing shorts to bytes.
+                                       count = (req.wLenDone - 1) / 2;
+                                       for (i = 0; i < count; i++) {
+                                               serial[i] = buffer[i + 1];
+                    }
+                                       serial[i] = 0;
+                                        break;
+                               }
+                       }
+               }
+       }
+        (*dev)->Release(dev);
+
+        DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
+            serial);
+
+        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface**)iface,
+                                            vendor, product);
+        if (handle == NULL) {
+            DBG("ERR: Could not find device interface: %08x\n", kr);
+            (*iface)->Release(iface);
+            continue;
+        }
+
+        DBG("AndroidDeviceAdded calling register_usb_transport\n");
+        register_usb_transport(handle, (serial[0] ? serial : NULL), 1);
+
+        // Register for an interest notification of this device being removed.
+        // Pass the reference to our private data as the refCon for the
+        // notification.
+        kr = IOServiceAddInterestNotification(notificationPort,
+                usbInterface,
+                kIOGeneralInterest,
+                AndroidInterfaceNotify,
+                handle,
+                &handle->usbNotification);
+
+        if (kIOReturnSuccess != kr) {
+            DBG("ERR: Unable to create interest notification (%08x)\n", kr);
+        }
+    }
+}
+
+static void
+AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
+{
+    usb_handle *handle = (usb_handle *)refCon;
+
+    if (messageType == kIOMessageServiceIsTerminated) {
+        if (!handle) {
+            DBG("ERR: NULL handle\n");
+            return;
+        }
+        DBG("AndroidInterfaceNotify\n");
+        IOObjectRelease(handle->usbNotification);
+        usb_kick(handle);
+    }
+}
+
+//* TODO: simplify this further since we only register to get SDB interface
+//* subclass+protocol events
+static usb_handle*
+CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product)
+{
+    usb_handle*                 handle = NULL;
+    IOReturn                    kr;
+    UInt8  interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
+    UInt8  endpoint;
+
+
+    //* Now open the interface.  This will cause the pipes associated with
+    //* the endpoints in the interface descriptor to be instantiated
+    kr = (*interface)->USBInterfaceOpen(interface);
+    if (kr != kIOReturnSuccess) {
+        DBG("ERR: Could not open interface: (%08x)\n", kr);
+        return NULL;
+    }
+
+    //* Get the number of endpoints associated with this interface
+    kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
+    if (kr != kIOReturnSuccess) {
+        DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
+        goto err_get_num_ep;
+    }
+
+    //* Get interface class, subclass and protocol
+    if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
+            (*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
+            DBG("ERR: Unable to get interface class, subclass and protocol\n");
+            goto err_get_interface_class;
+    }
+
+    //* check to make sure interface class, subclass and protocol match SDB
+    //* avoid opening mass storage endpoints
+    if (!is_sdb_interface(vendor, product, interfaceClass,
+                interfaceSubClass, interfaceProtocol))
+        goto err_bad_sdb_interface;
+
+    handle = calloc(1, sizeof(usb_handle));
+
+    //* Iterate over the endpoints for this interface and find the first
+    //* bulk in/out pipes available.  These will be our read/write pipes.
+    for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+        UInt8   transferType;
+        UInt16  maxPacketSize;
+        UInt8   interval;
+        UInt8   number;
+        UInt8   direction;
+
+        kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
+                &number, &transferType, &maxPacketSize, &interval);
+
+        if (kIOReturnSuccess == kr) {
+            if (kUSBBulk != transferType)
+                continue;
+
+            if (kUSBIn == direction)
+                handle->bulkIn = endpoint;
+
+            if (kUSBOut == direction)
+                handle->bulkOut = endpoint;
+
+            handle->zero_mask = maxPacketSize - 1;
+        } else {
+            DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+            goto err_get_pipe_props;
+        }
+    }
+
+    handle->interface = interface;
+    return handle;
+
+err_get_pipe_props:
+    free(handle);
+err_bad_sdb_interface:
+err_get_interface_class:
+err_get_num_ep:
+    (*interface)->USBInterfaceClose(interface);
+    return NULL;
+}
+
+
+void* RunLoopThread(void* unused)
+{
+    unsigned i;
+
+    InitUSB();
+
+    currentRunLoop = CFRunLoopGetCurrent();
+
+    // Signal the parent that we are running
+    sdb_mutex_lock(&start_lock);
+    sdb_cond_signal(&start_cond);
+    sdb_mutex_unlock(&start_lock);
+
+    CFRunLoopRun();
+    currentRunLoop = 0;
+
+    for (i = 0; i < vendorIdCount; i++) {
+        IOObjectRelease(notificationIterators[i]);
+    }
+    IONotificationPortDestroy(notificationPort);
+
+    DBG("RunLoopThread done\n");
+    return NULL;    
+}
+
+
+static int initialized = 0;
+void usb_init()
+{
+    if (!initialized)
+    {
+        sdb_thread_t    tid;
+
+        notificationIterators = (io_iterator_t*)malloc(
+            vendorIdCount * sizeof(io_iterator_t));
+
+        sdb_mutex_init(&start_lock, NULL);
+        sdb_cond_init(&start_cond, NULL);
+
+        if(sdb_thread_create(&tid, RunLoopThread, NULL))
+            fatal_errno("cannot create input thread");
+
+        // Wait for initialization to finish
+        sdb_mutex_lock(&start_lock);
+        sdb_cond_wait(&start_cond, &start_lock);
+        sdb_mutex_unlock(&start_lock);
+
+        sdb_mutex_destroy(&start_lock);
+        sdb_cond_destroy(&start_cond);
+
+        initialized = 1;
+    }
+}
+
+void usb_cleanup()
+{
+    DBG("usb_cleanup\n");
+    close_usb_devices();
+    if (currentRunLoop)
+        CFRunLoopStop(currentRunLoop);
+
+    if (notificationIterators != NULL) {
+        free(notificationIterators);
+        notificationIterators = NULL;
+    }
+}
+
+int usb_write(usb_handle *handle, const void *buf, int len)
+{
+    IOReturn    result;
+
+    if (!len)
+        return 0;
+
+    if (!handle)
+        return -1;
+
+    if (NULL == handle->interface) {
+        DBG("ERR: usb_write interface was null\n");
+        return -1;
+    }
+
+    if (0 == handle->bulkOut) {
+        DBG("ERR: bulkOut endpoint not assigned\n");
+        return -1;
+    }
+
+    result =
+        (*handle->interface)->WritePipe(
+                              handle->interface, handle->bulkOut, (void *)buf, len);
+
+    if ((result == 0) && (handle->zero_mask)) {
+        /* we need 0-markers and our transfer */
+        if(!(len & handle->zero_mask)) {
+            result =
+                (*handle->interface)->WritePipe(
+                        handle->interface, handle->bulkOut, (void *)buf, 0);
+        }
+    }
+
+    if (0 == result)
+        return 0;
+
+    DBG("ERR: usb_write failed with status %d\n", result);
+    return -1;
+}
+
+int usb_read(usb_handle *handle, void *buf, int len)
+{
+    IOReturn result;
+    UInt32  numBytes = len;
+
+    if (!len) {
+        return 0;
+    }
+
+    if (!handle) {
+        return -1;
+    }
+
+    if (NULL == handle->interface) {
+        DBG("ERR: usb_read interface was null\n");
+        return -1;
+    }
+
+    if (0 == handle->bulkIn) {
+        DBG("ERR: bulkIn endpoint not assigned\n");
+        return -1;
+    }
+
+    result =
+      (*handle->interface)->ReadPipe(handle->interface,
+                                    handle->bulkIn, buf, &numBytes);
+
+    if (0 == result)
+        return 0;
+    else {
+        DBG("ERR: usb_read failed with status %d\n", result);
+    }
+
+    return -1;
+}
+
+int usb_close(usb_handle *handle)
+{
+    return 0;
+}
+
+void usb_kick(usb_handle *handle)
+{
+    /* release the interface */
+    if (!handle)
+        return;
+
+    if (handle->interface)
+    {
+        (*handle->interface)->USBInterfaceClose(handle->interface);
+        (*handle->interface)->Release(handle->interface);
+        handle->interface = 0;
+    }
+}
diff --git a/src/usb_vendors.c b/src/usb_vendors.c
new file mode 100644 (file)
index 0000000..217aa8a
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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 "usb_vendors.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include "windows.h"
+#  include "shlobj.h"
+#else
+#  include <unistd.h>
+#  include <sys/stat.h>
+#endif
+
+#include "sysdeps.h"
+#include "sdb.h"
+
+#define ANDROID_PATH            ".android"
+#define ANDROID_SDB_INI         "sdb_usb.ini"
+
+#define TRACE_TAG               TRACE_USB
+
+// Google's USB Vendor ID
+#define VENDOR_ID_GOOGLE        0x18d1
+// Intel's USB Vendor ID
+#define VENDOR_ID_INTEL         0x8087
+// HTC's USB Vendor ID
+#define VENDOR_ID_HTC           0x0bb4
+// Samsung's USB Vendor ID
+#define VENDOR_ID_SAMSUNG       0x04e8
+// Motorola's USB Vendor ID
+#define VENDOR_ID_MOTOROLA      0x22b8
+// LG's USB Vendor ID
+#define VENDOR_ID_LGE           0x1004
+// Huawei's USB Vendor ID
+#define VENDOR_ID_HUAWEI        0x12D1
+// Acer's USB Vendor ID
+#define VENDOR_ID_ACER          0x0502
+// Sony Ericsson's USB Vendor ID
+#define VENDOR_ID_SONY_ERICSSON 0x0FCE
+// Foxconn's USB Vendor ID
+#define VENDOR_ID_FOXCONN       0x0489
+// Dell's USB Vendor ID
+#define VENDOR_ID_DELL          0x413c
+// Nvidia's USB Vendor ID
+#define VENDOR_ID_NVIDIA        0x0955
+// Garmin-Asus's USB Vendor ID
+#define VENDOR_ID_GARMIN_ASUS   0x091E
+// Sharp's USB Vendor ID
+#define VENDOR_ID_SHARP         0x04dd
+// ZTE's USB Vendor ID
+#define VENDOR_ID_ZTE           0x19D2
+// Kyocera's USB Vendor ID
+#define VENDOR_ID_KYOCERA       0x0482
+// Pantech's USB Vendor ID
+#define VENDOR_ID_PANTECH       0x10A9
+// Qualcomm's USB Vendor ID
+#define VENDOR_ID_QUALCOMM      0x05c6
+// On-The-Go-Video's USB Vendor ID
+#define VENDOR_ID_OTGV          0x2257
+// NEC's USB Vendor ID
+#define VENDOR_ID_NEC           0x0409
+// Panasonic Mobile Communication's USB Vendor ID
+#define VENDOR_ID_PMC           0x04DA
+// Toshiba's USB Vendor ID
+#define VENDOR_ID_TOSHIBA       0x0930
+// SK Telesys's USB Vendor ID
+#define VENDOR_ID_SK_TELESYS    0x1F53
+// KT Tech's USB Vendor ID
+#define VENDOR_ID_KT_TECH       0x2116
+// Asus's USB Vendor ID
+#define VENDOR_ID_ASUS          0x0b05
+// Philips's USB Vendor ID
+#define VENDOR_ID_PHILIPS       0x0471
+// Texas Instruments's USB Vendor ID
+#define VENDOR_ID_TI            0x0451
+// Funai's USB Vendor ID
+#define VENDOR_ID_FUNAI         0x0F1C
+// Gigabyte's USB Vendor ID
+#define VENDOR_ID_GIGABYTE      0x0414
+// IRiver's USB Vendor ID
+#define VENDOR_ID_IRIVER        0x2420
+// Compal's USB Vendor ID
+#define VENDOR_ID_COMPAL        0x1219
+// T & A Mobile Phones' USB Vendor ID
+#define VENDOR_ID_T_AND_A       0x1BBB
+// LenovoMobile's USB Vendor ID
+#define VENDOR_ID_LENOVOMOBILE  0x2006
+// Lenovo's USB Vendor ID
+#define VENDOR_ID_LENOVO        0x17EF
+// Vizio's USB Vendor ID
+#define VENDOR_ID_VIZIO         0xE040
+// K-Touch's USB Vendor ID
+#define VENDOR_ID_K_TOUCH       0x24E3
+// Pegatron's USB Vendor ID
+#define VENDOR_ID_PEGATRON      0x1D4D
+// Archos's USB Vendor ID
+#define VENDOR_ID_ARCHOS        0x0E79
+// Positivo's USB Vendor ID
+#define VENDOR_ID_POSITIVO      0x1662
+// Fujitsu's USB Vendor ID
+#define VENDOR_ID_FUJITSU       0x04C5
+// Lumigon's USB Vendor ID
+#define VENDOR_ID_LUMIGON       0x25E3
+// Quanta's USB Vendor ID
+#define VENDOR_ID_QUANTA        0x0408
+// INQ Mobile's USB Vendor ID
+#define VENDOR_ID_INQ_MOBILE    0x2314
+// Sony's USB Vendor ID
+#define VENDOR_ID_SONY          0x054C
+// Lab126's USB Vendor ID
+#define VENDOR_ID_LAB126        0x1949
+// Yulong Coolpad's USB Vendor ID
+#define VENDOR_ID_YULONG_COOLPAD 0x1EBF
+
+/** built-in vendor list */
+int builtInVendorIds[] = {
+    VENDOR_ID_GOOGLE,
+    VENDOR_ID_INTEL,
+    VENDOR_ID_HTC,
+    VENDOR_ID_SAMSUNG,
+    VENDOR_ID_MOTOROLA,
+    VENDOR_ID_LGE,
+    VENDOR_ID_HUAWEI,
+    VENDOR_ID_ACER,
+    VENDOR_ID_SONY_ERICSSON,
+    VENDOR_ID_FOXCONN,
+    VENDOR_ID_DELL,
+    VENDOR_ID_NVIDIA,
+    VENDOR_ID_GARMIN_ASUS,
+    VENDOR_ID_SHARP,
+    VENDOR_ID_ZTE,
+    VENDOR_ID_KYOCERA,
+    VENDOR_ID_PANTECH,
+    VENDOR_ID_QUALCOMM,
+    VENDOR_ID_OTGV,
+    VENDOR_ID_NEC,
+    VENDOR_ID_PMC,
+    VENDOR_ID_TOSHIBA,
+    VENDOR_ID_SK_TELESYS,
+    VENDOR_ID_KT_TECH,
+    VENDOR_ID_ASUS,
+    VENDOR_ID_PHILIPS,
+    VENDOR_ID_TI,
+    VENDOR_ID_FUNAI,
+    VENDOR_ID_GIGABYTE,
+    VENDOR_ID_IRIVER,
+    VENDOR_ID_COMPAL,
+    VENDOR_ID_T_AND_A,
+    VENDOR_ID_LENOVOMOBILE,
+    VENDOR_ID_LENOVO,
+    VENDOR_ID_VIZIO,
+    VENDOR_ID_K_TOUCH,
+    VENDOR_ID_PEGATRON,
+    VENDOR_ID_ARCHOS,
+    VENDOR_ID_POSITIVO,
+    VENDOR_ID_FUJITSU,
+    VENDOR_ID_LUMIGON,
+    VENDOR_ID_QUANTA,
+    VENDOR_ID_INQ_MOBILE,
+    VENDOR_ID_SONY,
+    VENDOR_ID_LAB126,
+    VENDOR_ID_YULONG_COOLPAD,
+};
+
+#define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
+
+/* max number of supported vendor ids (built-in + 3rd party). increase as needed */
+#define VENDOR_COUNT_MAX         128
+
+int vendorIds[VENDOR_COUNT_MAX];
+unsigned vendorIdCount = 0;
+
+int get_sdb_usb_ini(char* buff, size_t len);
+
+void usb_vendors_init(void)
+{
+    if (VENDOR_COUNT_MAX < BUILT_IN_VENDOR_COUNT) {
+        fprintf(stderr, "VENDOR_COUNT_MAX not big enough for built-in vendor list.\n");
+        exit(2);
+    }
+
+    /* add the built-in vendors at the beginning of the array */
+    memcpy(vendorIds, builtInVendorIds, sizeof(builtInVendorIds));
+
+    /* default array size is the number of built-in vendors */
+    vendorIdCount = BUILT_IN_VENDOR_COUNT;
+
+    if (VENDOR_COUNT_MAX == BUILT_IN_VENDOR_COUNT)
+        return;
+
+    char temp[PATH_MAX];
+    if (get_sdb_usb_ini(temp, sizeof(temp)) == 0) {
+        FILE * f = fopen(temp, "rt");
+
+        if (f != NULL) {
+            /* The vendor id file is pretty basic. 1 vendor id per line.
+               Lines starting with # are comments */
+            while (fgets(temp, sizeof(temp), f) != NULL) {
+                if (temp[0] == '#')
+                    continue;
+
+                long value = strtol(temp, NULL, 0);
+                if (errno == EINVAL || errno == ERANGE || value > INT_MAX || value < 0) {
+                    fprintf(stderr, "Invalid content in %s. Quitting.\n", ANDROID_SDB_INI);
+                    fclose(f);
+                    exit(2);
+                }
+
+                vendorIds[vendorIdCount++] = (int)value;
+
+                /* make sure we don't go beyond the array */
+                if (vendorIdCount == VENDOR_COUNT_MAX) {
+                    break;
+                }
+            }
+            fclose(f);
+        }
+    }
+}
+
+/* Utils methods */
+
+/* builds the path to the sdb vendor id file. returns 0 if success */
+int build_path(char* buff, size_t len, const char* format, const char* home)
+{
+    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_SDB_INI) >= (signed)len) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/* fills buff with the path to the sdb vendor id file. returns 0 if success */
+int get_sdb_usb_ini(char* buff, size_t len)
+{
+#ifdef _WIN32
+    const char* home = getenv("ANDROID_SDK_HOME");
+    if (home != NULL) {
+        return build_path(buff, len, "%s\\%s\\%s", home);
+    } else {
+        char path[MAX_PATH];
+        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, path);
+        return build_path(buff, len, "%s\\%s\\%s", path);
+    }
+#else
+    const char* home = getenv("HOME");
+    if (home == NULL)
+        home = "/tmp";
+
+    return build_path(buff, len, "%s/%s/%s", home);
+#endif
+}
diff --git a/src/usb_vendors.h b/src/usb_vendors.h
new file mode 100644 (file)
index 0000000..9e09d9a
--- /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 __USB_VENDORS_H
+#define __USB_VENDORS_H
+
+extern int vendorIds[];
+extern unsigned  vendorIdCount;
+
+void usb_vendors_init(void);
+
+#endif
diff --git a/src/usb_windows.c b/src/usb_windows.c
new file mode 100644 (file)
index 0000000..37eef1b
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * 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 <winerror.h>
+#include <errno.h>
+#include <usb100.h>
+#include <sdb_api.h>
+#include <stdio.h>
+
+#include "sysdeps.h"
+
+#define   TRACE_TAG  TRACE_USB
+#include "sdb.h"
+
+/** Structure usb_handle describes our connection to the usb device via
+  AdbWinApi.dll. This structure is returned from usb_open() routine and
+  is expected in each subsequent call that is accessing the device.
+*/
+struct usb_handle {
+  /// Previous entry in the list of opened usb handles
+  usb_handle *prev;
+
+  /// Next entry in the list of opened usb handles
+  usb_handle *next;
+
+  /// Handle to USB interface
+  SDBAPIHANDLE  sdb_interface;
+
+  /// Handle to USB read pipe (endpoint)
+  SDBAPIHANDLE  sdb_read_pipe;
+
+  /// Handle to USB write pipe (endpoint)
+  SDBAPIHANDLE  sdb_write_pipe;
+
+  /// Interface name
+  char*         interface_name;
+
+  /// Mask for determining when to use zero length packets
+  unsigned zero_mask;
+};
+
+/// Class ID assigned to the device by androidusb.sys
+static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
+
+/// List of opened usb handles
+static usb_handle handle_list = {
+  .prev = &handle_list,
+  .next = &handle_list,
+};
+
+/// Locker for the list of opened usb handles
+SDB_MUTEX_DEFINE( usb_lock );
+
+/// Checks if there is opened usb handle in handle_list for this device.
+int known_device(const char* dev_name);
+
+/// Checks if there is opened usb handle in handle_list for this device.
+/// usb_lock mutex must be held before calling this routine.
+int known_device_locked(const char* dev_name);
+
+/// Registers opened usb handle (adds it to handle_list).
+int register_new_device(usb_handle* handle);
+
+/// Checks if interface (device) matches certain criteria
+int recognized_device(usb_handle* handle);
+
+/// Enumerates present and available interfaces (devices), opens new ones and
+/// registers usb transport for them.
+void find_devices();
+
+/// Entry point for thread that polls (every second) for new usb interfaces.
+/// This routine calls find_devices in infinite loop.
+void* device_poll_thread(void* unused);
+
+/// Initializes this module
+void usb_init();
+
+/// Cleans up this module
+void usb_cleanup();
+
+/// Opens usb interface (device) by interface (device) name.
+usb_handle* do_usb_open(const wchar_t* interface_name);
+
+/// Writes data to the opened usb handle
+int usb_write(usb_handle* handle, const void* data, int len);
+
+/// Reads data using the opened usb handle
+int usb_read(usb_handle *handle, void* data, int len);
+
+/// Cleans up opened usb handle
+void usb_cleanup_handle(usb_handle* handle);
+
+/// Cleans up (but don't close) opened usb handle
+void usb_kick(usb_handle* handle);
+
+/// Closes opened usb handle
+int usb_close(usb_handle* handle);
+
+/// Gets interface (device) name for an opened usb handle
+const char *usb_name(usb_handle* handle);
+
+int known_device_locked(const char* dev_name) {
+  usb_handle* usb;
+
+  if (NULL != dev_name) {
+    // Iterate through the list looking for the name match.
+    for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+      // In Windows names are not case sensetive!
+      if((NULL != usb->interface_name) &&
+         (0 == stricmp(usb->interface_name, dev_name))) {
+        return 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+int known_device(const char* dev_name) {
+  int ret = 0;
+
+  if (NULL != dev_name) {
+    sdb_mutex_lock(&usb_lock);
+    ret = known_device_locked(dev_name);
+    sdb_mutex_unlock(&usb_lock);
+  }
+
+  return ret;
+}
+
+int register_new_device(usb_handle* handle) {
+  if (NULL == handle)
+    return 0;
+
+  sdb_mutex_lock(&usb_lock);
+
+  // Check if device is already in the list
+  if (known_device_locked(handle->interface_name)) {
+    sdb_mutex_unlock(&usb_lock);
+    return 0;
+  }
+
+  // Not in the list. Add this handle to the list.
+  handle->next = &handle_list;
+  handle->prev = handle_list.prev;
+  handle->prev->next = handle;
+  handle->next->prev = handle;
+
+  sdb_mutex_unlock(&usb_lock);
+
+  return 1;
+}
+
+void* device_poll_thread(void* unused) {
+  D("Created device thread\n");
+
+  while(1) {
+    find_devices();
+    sdb_sleep_ms(1000);
+  }
+
+  return NULL;
+}
+
+void usb_init() {
+  sdb_thread_t tid;
+
+  if(sdb_thread_create(&tid, device_poll_thread, NULL)) {
+    fatal_errno("cannot create input thread");
+  }
+}
+
+void usb_cleanup() {
+}
+
+usb_handle* do_usb_open(const wchar_t* interface_name) {
+  // Allocate our handle
+  usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
+  if (NULL == ret)
+    return NULL;
+
+  // Set linkers back to the handle
+  ret->next = ret;
+  ret->prev = ret;
+
+  // Create interface.
+  ret->sdb_interface = SdbCreateInterfaceByName(interface_name);
+
+  if (NULL == ret->sdb_interface) {
+    free(ret);
+    errno = GetLastError();
+    return NULL;
+  }
+
+  // Open read pipe (endpoint)
+  ret->sdb_read_pipe =
+    SdbOpenDefaultBulkReadEndpoint(ret->sdb_interface,
+                                   SdbOpenAccessTypeReadWrite,
+                                   SdbOpenSharingModeReadWrite);
+  if (NULL != ret->sdb_read_pipe) {
+    // Open write pipe (endpoint)
+    ret->sdb_write_pipe =
+      SdbOpenDefaultBulkWriteEndpoint(ret->sdb_interface,
+                                      SdbOpenAccessTypeReadWrite,
+                                      SdbOpenSharingModeReadWrite);
+    if (NULL != ret->sdb_write_pipe) {
+      // Save interface name
+      unsigned long name_len = 0;
+
+      // First get expected name length
+      SdbGetInterfaceName(ret->sdb_interface,
+                          NULL,
+                          &name_len,
+                          true);
+      if (0 != name_len) {
+        ret->interface_name = (char*)malloc(name_len);
+
+        if (NULL != ret->interface_name) {
+          // Now save the name
+          if (SdbGetInterfaceName(ret->sdb_interface,
+                                  ret->interface_name,
+                                  &name_len,
+                                  true)) {
+            // We're done at this point
+            return ret;
+          }
+        } else {
+          SetLastError(ERROR_OUTOFMEMORY);
+        }
+      }
+    }
+  }
+
+  // Something went wrong.
+  int saved_errno = GetLastError();
+  usb_cleanup_handle(ret);
+  free(ret);
+  SetLastError(saved_errno);
+
+  return NULL;
+}
+
+int usb_write(usb_handle* handle, const void* data, int len) {
+  unsigned long time_out = 5000;
+  unsigned long written = 0;
+  int ret;
+
+  D("usb_write %d\n", len);
+  if (NULL != handle) {
+    // Perform write
+    ret = SdbWriteEndpointSync(handle->sdb_write_pipe,
+                               (void*)data,
+                               (unsigned long)len,
+                               &written,
+                               time_out);
+    int saved_errno = GetLastError();
+
+    if (ret) {
+      // Make sure that we've written what we were asked to write
+      D("usb_write got: %ld, expected: %d\n", written, len);
+      if (written == (unsigned long)len) {
+        if(handle->zero_mask && (len & handle->zero_mask) == 0) {
+          // Send a zero length packet
+          SdbWriteEndpointSync(handle->sdb_write_pipe,
+                               (void*)data,
+                               0,
+                               &written,
+                               time_out);
+        }
+        return 0;
+      }
+    } else {
+      // assume ERROR_INVALID_HANDLE indicates we are disconnected
+      if (saved_errno == ERROR_INVALID_HANDLE)
+        usb_kick(handle);
+    }
+    errno = saved_errno;
+  } else {
+    D("usb_write NULL handle\n");
+    SetLastError(ERROR_INVALID_HANDLE);
+  }
+
+  D("usb_write failed: %d\n", errno);
+
+  return -1;
+}
+
+int usb_read(usb_handle *handle, void* data, int len) {
+  unsigned long time_out = 0;
+  unsigned long read = 0;
+  int ret;
+
+  D("usb_read %d\n", len);
+  if (NULL != handle) {
+    while (len > 0) {
+      int xfer = (len > 4096) ? 4096 : len;
+
+      ret = SdbReadEndpointSync(handle->sdb_read_pipe,
+                                  (void*)data,
+                                  (unsigned long)xfer,
+                                  &read,
+                                  time_out);
+      int saved_errno = GetLastError();
+      D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
+      if (ret) {
+        data += read;
+        len -= read;
+
+        if (len == 0)
+          return 0;
+      } else {
+        // assume ERROR_INVALID_HANDLE indicates we are disconnected
+        if (saved_errno == ERROR_INVALID_HANDLE)
+          usb_kick(handle);
+        break;
+      }
+      errno = saved_errno;
+    }
+  } else {
+    D("usb_read NULL handle\n");
+    SetLastError(ERROR_INVALID_HANDLE);
+  }
+
+  D("usb_read failed: %d\n", errno);
+
+  return -1;
+}
+
+void usb_cleanup_handle(usb_handle* handle) {
+  if (NULL != handle) {
+    if (NULL != handle->interface_name)
+      free(handle->interface_name);
+    if (NULL != handle->sdb_write_pipe)
+      SdbCloseHandle(handle->sdb_write_pipe);
+    if (NULL != handle->sdb_read_pipe)
+      SdbCloseHandle(handle->sdb_read_pipe);
+    if (NULL != handle->sdb_interface)
+      SdbCloseHandle(handle->sdb_interface);
+
+    handle->interface_name = NULL;
+    handle->sdb_write_pipe = NULL;
+    handle->sdb_read_pipe = NULL;
+    handle->sdb_interface = NULL;
+  }
+}
+
+void usb_kick(usb_handle* handle) {
+  if (NULL != handle) {
+    sdb_mutex_lock(&usb_lock);
+
+    usb_cleanup_handle(handle);
+
+    sdb_mutex_unlock(&usb_lock);
+  } else {
+    SetLastError(ERROR_INVALID_HANDLE);
+    errno = ERROR_INVALID_HANDLE;
+  }
+}
+
+int usb_close(usb_handle* handle) {
+  D("usb_close\n");
+
+  if (NULL != handle) {
+    // Remove handle from the list
+    sdb_mutex_lock(&usb_lock);
+
+    if ((handle->next != handle) && (handle->prev != handle)) {
+      handle->next->prev = handle->prev;
+      handle->prev->next = handle->next;
+      handle->prev = handle;
+      handle->next = handle;
+    }
+
+    sdb_mutex_unlock(&usb_lock);
+
+    // Cleanup handle
+    usb_cleanup_handle(handle);
+    free(handle);
+  }
+
+  return 0;
+}
+
+const char *usb_name(usb_handle* handle) {
+  if (NULL == handle) {
+    SetLastError(ERROR_INVALID_HANDLE);
+    errno = ERROR_INVALID_HANDLE;
+    return NULL;
+  }
+
+  return (const char*)handle->interface_name;
+}
+
+int recognized_device(usb_handle* handle) {
+  if (NULL == handle)
+    return 0;
+
+  // Check vendor and product id first
+  USB_DEVICE_DESCRIPTOR device_desc;
+
+  if (!SdbGetUsbDeviceDescriptor(handle->sdb_interface,
+                                 &device_desc)) {
+    return 0;
+  }
+
+  // Then check interface properties
+  USB_INTERFACE_DESCRIPTOR interf_desc;
+
+  if (!SdbGetUsbInterfaceDescriptor(handle->sdb_interface,
+                                    &interf_desc)) {
+    return 0;
+  }
+
+  // Must have two endpoints
+  if (2 != interf_desc.bNumEndpoints) {
+    return 0;
+  }
+
+  if (is_sdb_interface(device_desc.idVendor, device_desc.idProduct,
+      interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass, interf_desc.bInterfaceProtocol)) {
+
+    if(interf_desc.bInterfaceProtocol == 0x01) {
+      SdbEndpointInformation endpoint_info;
+      // assuming zero is a valid bulk endpoint ID
+      if (SdbGetEndpointInformation(handle->sdb_interface, 0, &endpoint_info)) {
+        handle->zero_mask = endpoint_info.max_packet_size - 1;
+      }
+    }
+
+    return 1;
+  }
+
+  return 0;
+}
+
+void find_devices() {
+        usb_handle* handle = NULL;
+  char entry_buffer[2048];
+  char interf_name[2048];
+  SdbInterfaceInfo* next_interface = (SdbInterfaceInfo*)(&entry_buffer[0]);
+  unsigned long entry_buffer_size = sizeof(entry_buffer);
+  char* copy_name;
+
+  // Enumerate all present and active interfaces.
+  SDBAPIHANDLE enum_handle =
+    SdbEnumInterfaces(usb_class_id, true, true, true);
+
+  if (NULL == enum_handle)
+    return;
+
+  while (SdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
+    // TODO: FIXME - temp hack converting wchar_t into char.
+    // It would be better to change AdbNextInterface so it will return
+    // interface name as single char string.
+    const wchar_t* wchar_name = next_interface->device_name;
+    for(copy_name = interf_name;
+        L'\0' != *wchar_name;
+        wchar_name++, copy_name++) {
+      *copy_name = (char)(*wchar_name);
+    }
+    *copy_name = '\0';
+
+    // Lets see if we already have this device in the list
+    if (!known_device(interf_name)) {
+      // This seems to be a new device. Open it!
+        handle = do_usb_open(next_interface->device_name);
+        if (NULL != handle) {
+        // Lets see if this interface (device) belongs to us
+        if (recognized_device(handle)) {
+          D("adding a new device %s\n", interf_name);
+          char serial_number[512];
+          unsigned long serial_number_len = sizeof(serial_number);
+          if (SdbGetSerialNumber(handle->sdb_interface,
+                                serial_number,
+                                &serial_number_len,
+                                true)) {
+            // Lets make sure that we don't duplicate this device
+            if (register_new_device(handle)) {
+              register_usb_transport(handle, serial_number, 1);
+            } else {
+              D("register_new_device failed for %s\n", interf_name);
+              usb_cleanup_handle(handle);
+              free(handle);
+            }
+          } else {
+            D("cannot get serial number\n");
+            usb_cleanup_handle(handle);
+            free(handle);
+          }
+        } else {
+          usb_cleanup_handle(handle);
+          free(handle);
+        }
+      }
+    }
+
+    entry_buffer_size = sizeof(entry_buffer);
+  }
+
+  SdbCloseHandle(enum_handle);
+}
index 28d16a3ff1bd31a6e7bfe07404a47169b3bbed3a..963e9bc7d32f617511763cb4eabd5d169e0a9ed4 100644 (file)
  * limitations under the License.
  */
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include <limits.h>
-#include <sys/time.h>
 
 #include "utils.h"
-#include "utils_backend.h"
-
-#include "fdevent.h"
-#include "sdb_constants.h"
-#include "sdb.h"
-
-#if defined(OS_WINDOWS)
-const struct utils_os_backend* utils_backend = &utils_windows_backend;
-#elif defined(OS_DARWIN)
-const struct utils_os_backend* utils_backend = &utils_unix_backend;
-#elif defined(OS_LINUX)
-const struct utils_os_backend* utils_backend = &utils_unix_backend;
-#else
-#error "unsupported OS"
-#endif
-
-int is_directory(char* path) {
-    struct stat st;
-
-    if(stat(path, &st)) {
-        fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
-        return -1;
-    }
-
-    if(S_ISDIR(st.st_mode)) {
-        return 1;
-    }
-
-    return 0;
-}
-
-int mkdirs(char *name)
+#define STRING_MAXLEN 1024
+char*
+buff_addc (char*  buff, char*  buffEnd, int  c)
 {
-    int ret;
-    char *x = name + 1;
-
-    for(;;) {
-        x = sdb_dirstart(x);
-        if(x == 0) return 1;
-        *x = 0;
-        ret = sdb_mkdir(name, 0775);
-        if(ret < 0 && (errno != EEXIST || is_directory(name) != 1)) {
-            *x = OS_PATH_SEPARATOR;
-            return ret;
-        }
-        *x = OS_PATH_SEPARATOR;
-        x++;
-    }
-    return 1;
-}
-
-void append_separator(char* result_path, char* path) {
-
-    int path_len = strlen(path);
-    if(path_len > 0 && (path)[path_len -1] != '/') {
-        snprintf(result_path, PATH_MAX, "%s/",path);
-    }
-    else {
-        snprintf(result_path, PATH_MAX, "%s",path);
-    }
-}
+    int  avail = buffEnd - buff;
 
-void append_file(char* result_path, char* dir, char* append_dir) {
-    char* tmp_append;
+    if (avail <= 0)  /* already in overflow mode */
+        return buff;
 
-    int len = strlen(append_dir);
-    if(len > 0) {
-        if(append_dir[0] == '/') {
-            tmp_append = append_dir + 1;
-        }
-        else {
-            tmp_append = append_dir;
-        }
-    }
-    else {
-        tmp_append = (char*)EMPTY_STRING;
+    if (avail == 1) {  /* overflowing, the last byte is reserved for zero */
+        buff[0] = 0;
+        return buff + 1;
     }
 
-    int dir_len = strlen(dir);
-    if(dir_len > 0 && dir[dir_len -1] != '/') {
-        snprintf(result_path, PATH_MAX, "%s/%s",dir, tmp_append);
-    }
-    else {
-        snprintf(result_path, PATH_MAX, "%s%s",dir, tmp_append);
-    }
+    buff[0] = (char) c;  /* add char and terminating zero */
+    buff[1] = 0;
+    return buff + 1;
 }
 
-char* get_filename(char* full_name) {
-    char *name = sdb_dirstop(full_name);
-    if(name == 0) {
-        name = full_name;
-    } else {
-        name++;
-    }
-
-    return name;
-}
-
-void append_args(char *dest, int argc, const char** argv, size_t n) {
-    int full_cmd_len = strlen(dest);
-    int i;
-    for(i = 1; i < argc; i++) {
-        int arglen = strlen(argv[i]);
-        int size_checker = n - full_cmd_len - arglen - 1;
-        if(size_checker <0) {
-            break;
-        }
-
-        strncat(dest, " ", n - full_cmd_len);
-        ++full_cmd_len;
-        strncat(dest, argv[i], n - full_cmd_len);
-        full_cmd_len += arglen;
-    }
-}
-
-long long NOW()
-{
-    struct timeval tv;
-    gettimeofday(&tv, 0);
-    return ((long long) tv.tv_usec) +
-        1000000LL * ((long long) tv.tv_sec);
-}
-
-/** duplicate string and quote all \ " ( ) chars + space character. */
-void dup_quote(char* result_string, const char *source, int max_len)
+char*
+buff_adds (char*  buff, char*  buffEnd, const char*  s)
 {
-    int i = 0;
-    for (; i < max_len-1; i++) {
-        if(*source == '\0') {
-            break;
-        }
-        char* quoted = (char*)QUOTE_CHAR;
-        while(*quoted != '\0') {
-            if(*source == *quoted++) {
-                i++;
-                *result_string++ = '\\';
-                break;
-            }
-        }
-        *result_string++ = *source;
-        source++;
-    }
-
-    if( i != max_len) {
-        *result_string = '\0';
-    }
-    else {
-        *(--result_string) = '\0';
-    }
-}
-
-/**************************************************/
-/***           OS dependent helpers             ***/
-/**************************************************/
-int launch_server(int server_port) {
-    return utils_backend->launch_server(server_port);
-}
-
-void start_logging(void) {
-    return utils_backend->start_logging();
-}
+    int  slen = strlen(s);
 
-char* ansi_to_utf8(const char *str) {
-    return utils_backend->ansi_to_utf8(str);
+    return buff_addb(buff, buffEnd, s, slen);
 }
 
-int sdb_open(const char* path, int 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 sdb_creat(const char* path, int mode) {
-    return utils_backend->sdb_creat(path, mode);
-}
-
-int sdb_read(int fd, void* buf, size_t len) {
-    return utils_backend->sdb_read(fd, buf, len);
-}
-
-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);
-}
-
-int sdb_close(int fd) {
-    return utils_backend->sdb_close(fd);
-}
-
-int sdb_unlink(const char* path) {
-    return utils_backend->sdb_unlink(path);
-}
-
-int sdb_mkdir(const char* path, int mode) {
-    return utils_backend->sdb_mkdir(path, mode);
-}
-
-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);
-}
+char*
+buff_addb (char*  buff, char*  buffEnd, const void*  data, int  len)
+{
+    int  avail = (buffEnd - buff);
 
-int sdb_socketpair(int sv[2]) {
-    return utils_backend->sdb_socketpair(sv);
-}
+    if (avail <= 0 || len <= 0)  /* already overflowing */
+        return buff;
 
-void sdb_sleep_ms(int mseconds) {
-    return utils_backend->sdb_sleep_ms(mseconds);
-}
+    if (len > avail)
+        len = avail;
 
-char* sdb_dirstart(const char* path) {
-    return utils_backend->sdb_dirstart(path);
-}
+    memcpy(buff, data, len);
 
-char* sdb_dirstop(const char* path) {
-    return utils_backend->sdb_dirstop(path);
-}
+    buff += len;
 
-int sdb_socket_setbufsize(int fd, int bufsize) {
-    return utils_backend->sdb_socket_setbufsize(fd, bufsize);
-}
+    /* ensure there is a terminating zero */
+    if (buff >= buffEnd) {  /* overflow */
+        buff[-1] = 0;
+    } else
+        buff[0] = 0;
 
-void disable_tcp_nagle(int fd) {
-    return utils_backend->disable_tcp_nagle(fd);
+    return buff;
 }
 
-int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg) {
-    return utils_backend->sdb_thread_create(pthread, start, arg);
-}
+char*
+buff_add  (char*  buff, char*  buffEnd, const char*  format, ... )
+{
+    int      avail;
 
-int sdb_mutex_lock(sdb_mutex_t *mutex) {
-    return utils_backend->sdb_mutex_lock(mutex);
-}
+    avail = (buffEnd - buff);
 
-int sdb_mutex_unlock(sdb_mutex_t *mutex) {
-    return utils_backend->sdb_mutex_unlock(mutex);
-}
+    if (avail > 0) {
+        va_list  args;
+        int      nn;
 
-int sdb_cond_init(sdb_cond_t *cond, const void *unused) {
-    return utils_backend->sdb_cond_init(cond, unused);
-}
+        va_start(args, format);
+        nn = vsnprintf( buff, avail, format, args);
+        va_end(args);
 
-int sdb_cond_wait(sdb_cond_t *cond, sdb_mutex_t *mutex) {
-    return utils_backend->sdb_cond_wait(cond, mutex);
-}
+        if (nn < 0) {
+            /* some C libraries return -1 in case of overflow,
+             * but they will also do that if the format spec is
+             * invalid. We assume SDB is not buggy enough to
+             * trigger that last case. */
+            nn = avail;
+        }
+        else if (nn > avail) {
+            nn = avail;
+        }
 
-int sdb_cond_broadcast(sdb_cond_t *cond) {
-    return utils_backend->sdb_cond_broadcast(cond);
-}
+        buff += nn;
 
-void sdb_sysdeps_init(void) {
-    return utils_backend->sdb_sysdeps_init();
+        /* ensure that there is a terminating zero */
+        if (buff >= buffEnd)
+            buff[-1] = 0;
+        else
+            buff[0] = 0;
+    }
+    return buff;
 }
 
-int socket_loopback_client(int port, int type) {
-    return utils_backend->socket_loopback_client(port, type);
-}
+char *str_trim(const char* string)
+{
+    const char* s = string;
+    const char* e = string + (strlen(string) - 1);
+    char* ret;
 
-int socket_network_client(const char *host, int port, int type) {
-    return utils_backend->socket_network_client(host, port, type);
-}
+    while(*s == ' ' || *s == '\t') { // ltrim
+        s++;
+    }
+    while(*e == ' ' || *e == '\t') { // rtrim
+        e--;
+    }
 
-int socket_loopback_server(int port, int type) {
-    return utils_backend->socket_loopback_server(port, type);
-}
+    ret = strdup(s);
+    ret[e - s + 1] = 0;
 
-int socket_inaddr_any_server(int port, int type) {
-    return utils_backend->socket_inaddr_any_server(port, type);
+    return  ret;
 }
index 42ec7ae503b42db855bf7736fdb9579f1a1cbf2d..e6755487da5e260658bddedd4a9bdb888990c8d3 100644 (file)
 #ifndef _SDB_UTILS_H
 #define _SDB_UTILS_H
 
-// TODO: move to c file
-#if defined(OS_WINDOWS)
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <process.h>
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
-#include "pthread_win32.h"
+/* bounded buffer functions */
 
-#else
-#include <stdio.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#endif
-
-//append strings with white space at most n+1 character. (last char is \0)
-void append_args(char *dest, int argc, const char** argv, size_t n);
-//get file name from full path. For example, /usr/opt/app -> app, app -> app
-char* get_filename(char* full_name);
-//append separator to the end of path.
-//If return value is 1, it allocates new memory and appends separator at the end of path. Therefore, users should free memory.
-void append_separator(char* result_path, char* path);
-//returns 1 if path is directory, returns 0 if path is file, returns -1 if error occurred.
-int is_directory(char* path);
-int mkdirs(char *name);
-void append_file(char* result_path, char* dir, char* append_dir);
-long long NOW();
-void dup_quote(char* result_string, const char *source, int max_len);
-
-// OS dependent helpers
-
-#if defined(OS_WINDOWS)
-#define OS_PATH_SEPARATOR '\\'
-#define OS_PATH_SEPARATOR_STR "\\"
-
-#define  lstat    stat   /* no symlinks on Win32 */
-#define  S_ISLNK(m)   0   /* no symlinks on Win32 */
-
-extern int unix_read(int fd, void* buf, size_t len);
-
-#else
-#define OS_PATH_SEPARATOR '/'
-#define OS_PATH_SEPARATOR_STR "/"
-
-#define  unix_read   sdb_read
-#define  SDB_MUTEX_DEFINE(m)      sdb_mutex_t   m = PTHREAD_MUTEX_INITIALIZER
-#endif
-// thread helpers
-typedef  pthread_t                sdb_thread_t;
-typedef  pthread_mutex_t          sdb_mutex_t;
-#define  sdb_cond_t               pthread_cond_t
-
-typedef void*  (*sdb_thread_func_t)( void*  arg );
+/* all these functions are used to append data to a bounded buffer.
+ *
+ * after each operation, the buffer is guaranteed to be zero-terminated,
+ * even in the case of an overflow. they all return the new buffer position
+ * which allows one to use them in succession, only checking for overflows
+ * at the end. For example:
+ *
+ *    BUFF_DECL(temp,p,end,1024);
+ *    char*    p;
+ *
+ *    p = buff_addc(temp, end, '"');
+ *    p = buff_adds(temp, end, string);
+ *    p = buff_addc(temp, end, '"');
+ *
+ *    if (p >= end) {
+ *        overflow detected. note that 'temp' is
+ *        zero-terminated for safety. 
+ *    }
+ *    return strdup(temp);
+ */
 
-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_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);
+/* tries to add a character to the buffer, in case of overflow
+ * this will only write a terminating zero and return buffEnd.
+ */
+char*   buff_addc (char*  buff, char*  buffEnd, int  c);
 
-#define  SDB_MUTEX(x)   sdb_mutex_t  x;
+/* tries to add a string to the buffer */
+char*   buff_adds (char*  buff, char*  buffEnd, const char*  s);
 
-SDB_MUTEX(dns_lock)
-SDB_MUTEX(socket_list_lock)
-SDB_MUTEX(transport_lock)
-SDB_MUTEX(local_transports_lock)
-SDB_MUTEX(usb_lock)
-SDB_MUTEX(D_lock)
+/* tries to add a bytes to the buffer. the input can contain zero bytes,
+ * but a terminating zero will always be appended at the end anyway
+ */
+char*   buff_addb (char*  buff, char*  buffEnd, const void*  data, int  len);
 
-int launch_server(int server_port);
-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_socketpair(int sv[2]);
-void sdb_sleep_ms(int mseconds);
-char* sdb_dirstart(const char* path);
-char* sdb_dirstop(const char* path);
-int sdb_socket_setbufsize(int fd, int bufsize);
-void disable_tcp_nagle(int fd);
+/* tries to add a formatted string to a bounded buffer */
+char*   buff_add  (char*  buff, char*  buffEnd, const char*  format, ... );
 
-// 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);
+/* convenience macro used to define a bounded buffer, as well as
+ * a 'cursor' and 'end' variables all in one go.
+ *
+ * note: this doesn't place an initial terminating zero in the buffer,
+ * you need to use one of the buff_ functions for this. or simply
+ * do _cursor[0] = 0 manually.
+ */
+#define  BUFF_DECL(_buff,_cursor,_end,_size)   \
+    char   _buff[_size], *_cursor=_buff, *_end = _cursor + (_size)
 
-#define DEVICEMAP_SEPARATOR ":"
-#define DEVICENAME_MAX 256
-#define VMS_PATH OS_PATH_SEPARATOR_STR "vms" OS_PATH_SEPARATOR_STR
-#define DEFAULT_DEVICENAME "<unknown>"
+char *str_trim(const char* string);
 
 #endif /* _SDB_UTILS_H */
diff --git a/src/utils_backend.h b/src/utils_backend.h
deleted file mode 100644 (file)
index 39d0295..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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 _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;
-
-/* 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;
-
-    HANDLE    event;
-    int       mask;
-
-    char  name[32];
-
-} FHRec;
-
-#define  fh_handle  u.handle
-#define  fh_socket  u.socket
-#define  fh_pair    u.pair
-
-#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
-
-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 );
-
-#else
-#endif // end of unix
-
-struct utils_os_backend {
-    // human-readable name
-    const char *name;
-
-    int (*launch_server)(int server_port);
-    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_socketpair)(int sv[2]);
-    void (*sdb_sleep_ms)(int mseconds);
-    char* (*sdb_dirstart)(const char* path);
-    char* (*sdb_dirstop)(const char* path);
-    int (*sdb_socket_setbufsize)(int fd, int bufsize);
-    void (*disable_tcp_nagle)(int fd);
-    // simple implementation of pthread
-    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);
-
-    /*
-     * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
-     * Implement simple condition variable for Windows threads, based on ACE
-     * See original implementation: http://github.com/git
-     */
-    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);
-    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);
-
-};
-
-extern const struct utils_os_backend* utils_backend;
-extern const struct utils_os_backend utils_unix_backend;
-extern const struct utils_os_backend utils_windows_backend;
-
-#endif /* _SDB_BACKEND_UTILS_H */
diff --git a/src/utils_unix.c b/src/utils_unix.c
deleted file mode 100644 (file)
index c9227a1..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * 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.
- */
-
-#if defined(OS_DARWIN)
-#import <Carbon/Carbon.h>
-#include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/un.h>
-
-#include "utils.h"
-#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);
-
-#if defined(OS_DARWIN)
-
-void _get_sdb_path(char *s, size_t max_len)
-{
-    ProcessSerialNumber psn;
-    GetCurrentProcess(&psn);
-    CFDictionaryRef dict;
-    dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
-    CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("CFBundleExecutable"));
-    CFStringGetCString(value, s, max_len, kCFStringEncodingUTF8);
-}
-
-#elif defined(OS_LINUX)
-
-static void _get_sdb_path(char *exe, size_t max_len)
-{
-    char proc[64];
-    snprintf(proc, sizeof proc, "/proc/%d/exe", getpid());
-    int err = readlink(proc, exe, max_len - 1);
-    if(err > 0) {
-        exe[err] = '\0';
-    } else {
-        exe[0] = '\0';
-    }
-}
-#endif
-
-static int _launch_server(int server_port)
-{
-    char    path[PATH_MAX];
-    int     fd[2];
-
-    // set up a pipe so the child can tell us when it is ready.
-    // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
-    if (pipe(fd)) {
-        fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
-        return -1;
-    }
-    _get_sdb_path(path, PATH_MAX);
-    pid_t pid = fork();
-    if(pid < 0) return -1;
-
-    if (pid == 0) {
-        // child side of the fork
-
-        // redirect stderr to the pipe
-        // we use stderr instead of stdout due to stdout's buffering behavior.
-        sdb_close(fd[0]);
-        dup2(fd[1], STDERR_FILENO);
-        sdb_close(fd[1]);
-
-        // child process
-        int result = execl(path, "sdb", "fork-server", "server", NULL);
-        // this should not return
-        fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
-    } else  {
-        // parent side of the fork
-
-        char  temp[3];
-
-        temp[0] = 'A'; temp[1] = 'B'; temp[2] = 'C';
-        // wait for the "OK\n" message
-        sdb_close(fd[1]);
-        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;
-        }
-        if (ret != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
-            fprintf(stderr, "SDB server didn't ACK\n" );
-            return -1;
-        }
-
-        setsid();
-    }
-    return 0;
-}
-
-
-static void _start_logging(void)
-{
-    const char*  p = getenv("SDB_TRACE");
-    if (p == NULL) {
-        return;
-    }
-    int fd;
-
-    fd = unix_open("/dev/null", O_RDONLY);
-    dup2(fd, 0);
-    sdb_close(fd);
-
-    fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
-    if(fd < 0) {
-        fd = unix_open("/dev/null", O_WRONLY);
-    }
-    dup2(fd, 1);
-    dup2(fd, 2);
-    sdb_close(fd);
-    fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid());
-}
-
-static char* _ansi_to_utf8(const char *str)
-{
-    // Not implement!
-    // If need, use iconv later event though unix system is using utf8 encoding.
-    int len;
-    char *utf8;
-
-    len = strlen(str);
-    utf8 = (char *)calloc(len+1, sizeof(char));
-    strcpy(utf8, str);
-    return utf8;
-}
-
-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);
-    }
-}
-
-static int _sdb_open( const char*  pathname, int  options )
-{
-    int  fd = open( pathname, options );
-    if (fd < 0)
-        return -1;
-    _close_on_exec( fd );
-    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);
-
-    if ( fd < 0 )
-        return -1;
-
-    _close_on_exec(fd);
-    return fd;
-}
-
-static int  _sdb_read(int  fd, void*  buf, size_t  len)
-{
-    return read(fd, buf, len);
-}
-
-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);
-}
-
-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)
-{
-    int fd;
-
-    fd = accept(serverfd, addr, addrlen);
-    if (fd >= 0) {
-        _close_on_exec(fd);
-    }
-
-    return fd;
-}
-
-static int _unix_socketpair( int  d, int  type, int  protocol, int sv[2] )
-{
-    return socketpair( d, type, protocol, sv );
-}
-
-static int _sdb_socketpair( int  sv[2] )
-{
-    int  rc;
-
-    rc = _unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
-    if (rc < 0)
-        return -1;
-
-    _close_on_exec( sv[0] );
-    _close_on_exec( sv[1] );
-    return 0;
-}
-
-static void  _sdb_sleep_ms( int  mseconds )
-{
-    usleep( mseconds*1000 );
-}
-
-static char*  _sdb_dirstart(const char*  path)
-{
-    return strchr(path, '/');
-}
-
-static char*  _sdb_dirstop(const char*  path)
-{
-    return strrchr(path, '/');
-}
-
-static int _sdb_socket_setbufsize( int   fd, int  bufsize )
-{
-    int opt = bufsize;
-    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
-}
-
-static void _disable_tcp_nagle(int fd)
-{
-    int  on = 1;
-    setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on) );
-}
-
-static int  _sdb_thread_create( sdb_thread_t  *pthread, sdb_thread_func_t  start, void*  arg )
-{
-    pthread_attr_t   attr;
-
-    pthread_attr_init (&attr);
-    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); // don't need to call join
-
-    return pthread_create( pthread, &attr, start, arg );
-}
-
-static int _sdb_mutex_lock(sdb_mutex_t *mutex) {
-    return pthread_mutex_lock(mutex);
-}
-
-static int _sdb_mutex_unlock(sdb_mutex_t *mutex) {
-    return pthread_mutex_unlock(mutex);
-}
-
-static int _sdb_cond_init(sdb_cond_t *cond, const void *unused) {
-    return pthread_cond_init(cond, unused);
-}
-
-static int _sdb_cond_wait(sdb_cond_t *cond, sdb_mutex_t *mutex) {
-    return pthread_cond_wait(cond, mutex);
-}
-
-static int _sdb_cond_broadcast(sdb_cond_t *cond) {
-    return pthread_cond_broadcast(cond);
-}
-
-static void  _sdb_sysdeps_init(void)
-{
-}
-
-static int _socket_loopback_client(int port, int type)
-{
-    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);
-        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(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        sdb_close(s);
-        return -1;
-    }
-
-    return s;
-
-}
-
-static int _socket_loopback_server(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_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);
-        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));
-
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        sdb_close(s);
-        return -1;
-    }
-
-    if (type == SOCK_STREAM) {
-        int ret;
-
-        ret = listen(s, LISTEN_BACKLOG);
-
-        if (ret < 0) {
-            sdb_close(s);
-            return -1;
-        }
-    }
-
-    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,
-    .sdb_sleep_ms = _sdb_sleep_ms,
-    .sdb_dirstart = _sdb_dirstart,
-    .sdb_dirstop = _sdb_dirstop,
-    .sdb_socket_setbufsize = _sdb_socket_setbufsize,
-    .disable_tcp_nagle = _disable_tcp_nagle,
-    // simple pthread implementations
-    .sdb_thread_create = _sdb_thread_create,
-    .sdb_mutex_lock = _sdb_mutex_lock,
-    .sdb_mutex_unlock = _sdb_mutex_unlock,
-    .sdb_cond_init = _sdb_cond_init,
-    .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
-};
diff --git a/src/utils_windows.c b/src/utils_windows.c
deleted file mode 100644 (file)
index 5b66145..0000000
+++ /dev/null
@@ -1,1642 +0,0 @@
-/*
- * 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 <winsock2.h>
-#include <stdio.h>
-#include <errno.h>
-#include "utils.h"
-#include "fdevent.h"
-#include "fdevent_backend.h"
-
-#define  TRACE_TAG  TRACE_SYSDEPS
-#include "sdb.h"
-#include "utils_backend.h"
-
-/*
- * from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
- */
-static int _launch_server(int server_port) {
-    HANDLE g_hChildStd_OUT_Rd = NULL;
-    HANDLE g_hChildStd_OUT_Wr = NULL;
-    SECURITY_ATTRIBUTES saAttr;
-
-    // Set the bInheritHandle flag so pipe handles are inherited.
-    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
-    saAttr.bInheritHandle = TRUE;
-    saAttr.lpSecurityDescriptor = NULL;
-
-    // Create a pipe for the child process's STDOUT.
-    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) {
-        fprintf(stderr, "failed to StdoutRd CreatePipe: %ld\n", GetLastError());
-        return -1;
-    }
-
-    // Ensure the read handle to the pipe for STDOUT is not inherited.
-    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
-        fprintf(stderr, "failed to set Stdout SetHandleInformation: %ld\n", GetLastError());
-        return -1;
-    }
-
-    // Create a child process that uses the previously created pipes for STDIN and STDOUT.
-    {
-        PROCESS_INFORMATION piProcInfo;
-        STARTUPINFO siStartInfo;
-        BOOL bSuccess = FALSE;
-        char module_path[MAX_PATH];
-        TCHAR szCmdline[] = TEXT("sdb fork-server server");
-
-        // Set up members of the PROCESS_INFORMATION structure.
-        ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
-
-        // Set up members of the STARTUPINFO structure.
-        // This structure specifies the STDIN and STDOUT handles for redirection.
-        ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
-        siStartInfo.cb = sizeof(STARTUPINFO);
-        siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-        siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
-        siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
-        siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
-
-        // Get current module path
-        GetModuleFileName(NULL, module_path, sizeof(module_path));
-
-        // Create the child process.
-        bSuccess = CreateProcess(module_path, szCmdline, // command line
-                NULL, // process security attributes
-                NULL, // primary thread security attributes
-                TRUE, // handles are inherited
-                DETACHED_PROCESS, // creation flags
-                NULL, // use parent's environment
-                NULL, // use parent's current directory
-                &siStartInfo, // STARTUPINFO pointer
-                &piProcInfo); // receives PROCESS_INFORMATION
-
-        // If an error occurs, exit the application.
-        if (!bSuccess) {
-            fprintf(stderr, "fail to create sdb server process: %ld\n", GetLastError());
-            CloseHandle(g_hChildStd_OUT_Wr);
-            CloseHandle(g_hChildStd_OUT_Rd);
-            return -1;
-        }
-        else {
-            CloseHandle(g_hChildStd_OUT_Wr);
-            // Close handles to the child process and its primary thread.
-            // Some applications might keep these handles to monitor the status
-            // of the child process, for example.
-
-            CloseHandle(piProcInfo.hProcess);
-            CloseHandle(piProcInfo.hThread);
-
-            //Read "OK\n" stdout message from sdb server
-            DWORD dwRead;
-            char chBuf[3];
-
-            bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, sizeof(chBuf), &dwRead, NULL);
-            CloseHandle(g_hChildStd_OUT_Rd);
-
-            if( ! bSuccess || dwRead == 0 ) {
-                fprintf(stderr, "fail to read ok message from sdb server: %ld\n", GetLastError());
-                return -1;
-            }
-            if (dwRead != 3 || chBuf[0] != 'O' || chBuf[1] != 'K' || chBuf[2] != '\n') {
-                fprintf(stderr, "fail to get OK\\n from sdb server: [%s]\n", chBuf);
-                return -1;
-            }
-        }
-    }
-    return 0;
-}
-
-static void _start_logging(void)
-{
-    const char*  p = getenv("SDB_TRACE");
-    if (p == NULL) {
-        return;
-    }
-
-    char    temp[ MAX_PATH ];
-    FILE*   fnul;
-    FILE*   flog;
-
-    GetTempPath( sizeof(temp) - 8, temp );
-    strcat( temp, "sdb.log" );
-
-    /* Win32 specific redirections */
-    fnul = fopen( "NUL", "rt" );
-    if (fnul != NULL)
-        stdin[0] = fnul[0];
-
-    flog = fopen( temp, "at" );
-    if (flog == NULL)
-        flog = fnul;
-
-    setvbuf( flog, NULL, _IONBF, 0 );
-
-    stdout[0] = flog[0];
-    stderr[0] = flog[0];
-    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)
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    common file descriptor handling                             *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-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;
-    }
-
-    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;
-}
-
-static FH _fh_alloc(FHClass clazz) {
-    int nn;
-    FH f = NULL;
-
-    sdb_mutex_lock(&_win32_lock);
-
-    if (_win32_fh_count < WIN32_MAX_FHS) {
-        f = &_win32_fhs[_win32_fh_count++];
-        goto Exit;
-    }
-
-    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;
-}
-
-/* forward definitions */
-static const FHClassRec _fh_file_class;
-static const FHClassRec _fh_socket_class;
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    file-based descriptor handling                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static void _fh_file_init(FH f) {
-    f->fh_handle = INVALID_HANDLE_VALUE;
-}
-
-static int _fh_file_close(FH f) {
-    CloseHandle(f->fh_handle);
-    f->fh_handle = INVALID_HANDLE_VALUE;
-    return 0;
-}
-
-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 _fh_file_write(FH f, const void* buf, int len) {
-    DWORD wrote_bytes;
-
-    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;
-    }
-    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;
-    }
-
-    result = SetFilePointer(f->fh_handle, pos, NULL, method);
-    if (result == INVALID_SET_FILE_POINTER) {
-        errno = EIO;
-        return -1;
-    } else {
-        f->eof = 0;
-    }
-    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);
-        errno = EINVAL;
-        return -1;
-    }
-
-    f = _fh_alloc(&_fh_file_class);
-    if (!f) {
-        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);
-}
-
-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);
-    }
-}
-
-/* ignore mode on Win32 */
-static int _sdb_creat(const char* path, int mode) {
-    FH f;
-
-    f = _fh_alloc(&_fh_file_class);
-    if (!f) {
-        errno = ENOMEM;
-        return -1;
-    }
-
-    f->fh_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;
-        }
-    }
-    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);
-}
-
-static int _sdb_read(int fd, void* buf, size_t len) {
-    FH f = _fh_from_int(fd);
-
-    if (f == NULL) {
-        return -1;
-    }
-
-    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;
-    }
-
-    return f->clazz->_fh_write(f, buf, len);
-}
-
-static int _sdb_lseek(int fd, int pos, int where) {
-    FH f = _fh_from_int(fd);
-
-    if (!f) {
-        return -1;
-    }
-
-    return f->clazz->_fh_lseek(f, pos, where);
-}
-
-static int _sdb_shutdown(int fd) {
-    FH f = _fh_from_int(fd);
-
-    if (!f) {
-        return -1;
-    }
-
-    D( "sdb_shutdown: %s\n", f->name);
-    shutdown(f->fh_socket, SD_BOTH);
-    return 0;
-}
-
-static int _sdb_close(int fd) {
-    FH f = _fh_from_int(fd);
-
-    if (!f) {
-        return -1;
-    }
-
-    D( "sdb_close: %s\n", f->name);
-    _fh_close(f);
-    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);
-}
-
-static __inline__ int unix_close(int fd) {
-    return close(fd);
-}
-
-int unix_read(int fd, void* buf, size_t len) {
-    return read(fd, buf, len);
-}
-
-int unix_write(int fd, const void* buf, size_t len) {
-    return write(fd, buf, len);
-}
-
-static void _close_on_exec(int fd) {
-    /* nothing really */
-}
-
-static void _sdb_sleep_ms(int mseconds) {
-    Sleep(mseconds);
-}
-
-static int _sdb_socket_setbufsize(int fd, int bufsize) {
-    int opt = bufsize;
-    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &opt, sizeof(opt));
-}
-
-static char* _sdb_dirstart(const char* path) {
-    char* p = strchr(path, '/');
-    char* p2 = strchr(path, '\\');
-
-    if (!p)
-        p = p2;
-    else if (p2 && p2 > p)
-        p = p2;
-
-    return p;
-}
-
-static char* _sdb_dirstop(const char* path) {
-    char* p = strrchr(path, '/');
-    char* p2 = strrchr(path, '\\');
-
-    if (!p)
-        p = p2;
-    else if (p2 && p2 > p)
-        p = p2;
-
-    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) {
-    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");
-        }
-        atexit(_cleanup_winsock);
-        _winsock_init = 1;
-    }
-}
-
-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);
-    struct sockaddr_in addr;
-    SOCKET s;
-    int n;
-
-    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)
-        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);
-        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(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);
-}
-
-static int _socket_network_client(const char *host, int port, int type) {
-    FH f = _fh_alloc(&_fh_socket_class);
-    struct hostent *hp;
-    struct sockaddr_in addr;
-    SOCKET s;
-
-    if (!f)
-        return -1;
-
-    if (!_winsock_init)
-        _init_winsock();
-
-    hp = gethostbyname(host);
-    if (hp == 0) {
-        _fh_close(f);
-        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 == INVALID_SOCKET) {
-        _fh_close(f);
-        return -1;
-    }
-    f->fh_socket = s;
-
-    if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        _fh_close(f);
-        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);
-}
-
-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;
-
-    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_ANY);
-
-    s = socket(AF_INET, type, 0);
-    if (s == INVALID_SOCKET) {
-        _fh_close(f);
-        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);
-        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());
-        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);
-}
-
-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);
-}
-
-#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);
-    }
-}
-
-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);
-}
-
-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;
-
-        memcpy(bip->buff + bip->a_end, src, avail);
-        src += avail;
-        count += avail;
-        len -= avail;
-
-        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 (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;
-
-    if (bip->b_end == bip->a_start) {
-        bip->can_write = 0;
-        ResetEvent(bip->evt_write);
-    }
-
-    Exit:
-    assert( count > 0);
-
-    if (!bip->can_read) {
-        bip->can_read = 1;
-        SetEvent(bip->evt_read);
-    }
-
-    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;
-        return -1;
-#else
-        int ret;
-        LeaveCriticalSection(&bip->lock);
-
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-
-        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;
-        }
-        if (bip->closed) {
-            errno = EPIPE;
-            return -1;
-        }
-        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;
-        }
-
-        bip_buffer_close(&pair->b2a_bip);
-        bip_buffer_close(&pair->a2b_bip);
-
-        if (--pair->used == 0) {
-            bip_buffer_done(&pair->b2a_bip);
-            bip_buffer_done(&pair->a2b_bip);
-            free(pair);
-        }
-        f->fh_pair = NULL;
-    }
-    return 0;
-}
-
-static int _fh_socketpair_lseek(FH f, int pos, int origin) {
-    errno = ESPIPE;
-    return -1;
-}
-
-static int _fh_socketpair_read(FH f, void* buf, int len) {
-    SocketPair pair = f->fh_pair;
-    BipBuffer bip;
-
-    if (!pair)
-        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;
-
-    if (!pair)
-        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);
-
-    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];
-
-    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]);
-    return 0;
-
-    Fail: _fh_close(fb);
-    _fh_close(fa);
-    return -1;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/*****                                                                *****/
-/*****    fdevents emulation                                          *****/
-/*****                                                                *****/
-/*****   this is a very simple implementation, we rely on the fact    *****/
-/*****   that SDB doesn't use FDE_ERROR.                              *****/
-/*****                                                                *****/
-/**************************************************************************/
-/**************************************************************************/
-
-
-/**  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(D_lock)
-    SDB_MUTEX(_win32_lock);
-}
-
-typedef  void (*win_thread_func_t)(void*  arg);
-
-static int _sdb_thread_create(sdb_thread_t *thread, sdb_thread_func_t func, void* arg) {
-    thread->tid = _beginthread((win_thread_func_t) func, 0, arg);
-    if (thread->tid == (unsigned) -1L) {
-        return -1;
-    }
-    return 0;
-}
-
-static int _pthread_mutex_lock(pthread_mutex_t *mutex) {
-    // Request ownership of the critical section.
-    EnterCriticalSection(mutex);
-
-    return 0;
-}
-
-static int _pthread_mutex_unlock(pthread_mutex_t* mutex) {
-    // Release ownership of the critical section.
-    LeaveCriticalSection(mutex);
-
-    return 0;
-}
-
-static int _pthread_cond_init(pthread_cond_t *cond, const void *unused)
-{
-    cond->waiters = 0;
-    cond->was_broadcast = 0;
-    InitializeCriticalSection(&cond->waiters_lock);
-
-    cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
-    if (!cond->sema) {
-        //die("CreateSemaphore() failed");
-    }
-
-    cond->continue_broadcast = CreateEvent(NULL,    /* security */
-                FALSE,          /* auto-reset */
-                FALSE,          /* not signaled */
-                NULL);          /* name */
-    if (!cond->continue_broadcast) {
-        //die("CreateEvent() failed");
-    }
-
-    return 0;
-}
-
-static int _pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) {
-    int last_waiter;
-
-    EnterCriticalSection(&cond->waiters_lock);
-    cond->waiters++;
-    LeaveCriticalSection(&cond->waiters_lock);
-
-    /*
-     * Unlock external mutex and wait for signal.
-     * NOTE: we've held mutex locked long enough to increment
-     * waiters count above, so there's no problem with
-     * leaving mutex unlocked before we wait on semaphore.
-     */
-    LeaveCriticalSection(mutex);
-
-    /* let's wait - ignore return value */
-    WaitForSingleObject(cond->sema, INFINITE);
-
-    /*
-     * Decrease waiters count. If we are the last waiter, then we must
-     * notify the broadcasting thread that it can continue.
-     * But if we continued due to cond_signal, we do not have to do that
-     * because the signaling thread knows that only one waiter continued.
-     */
-    EnterCriticalSection(&cond->waiters_lock);
-    cond->waiters--;
-    last_waiter = cond->was_broadcast && cond->waiters == 0;
-    LeaveCriticalSection(&cond->waiters_lock);
-
-    if (last_waiter) {
-        /*
-         * cond_broadcast was issued while mutex was held. This means
-         * that all other waiters have continued, but are contending
-         * for the mutex at the end of this function because the
-         * broadcasting thread did not leave cond_broadcast, yet.
-         * (This is so that it can be sure that each waiter has
-         * consumed exactly one slice of the semaphor.)
-         * The last waiter must tell the broadcasting thread that it
-         * can go on.
-         */
-        SetEvent(cond->continue_broadcast);
-        /*
-         * Now we go on to contend with all other waiters for
-         * the mutex. Auf in den Kampf!
-         */
-    }
-    /* lock external mutex again */
-    EnterCriticalSection(mutex);
-
-    return 0;
-}
-
-static int _pthread_cond_broadcast(pthread_cond_t *cond)
-{
-    EnterCriticalSection(&cond->waiters_lock);
-
-    if ((cond->was_broadcast = cond->waiters > 0)) {
-        /* wake up all waiters */
-        ReleaseSemaphore(cond->sema, cond->waiters, NULL);
-        LeaveCriticalSection(&cond->waiters_lock);
-        /*
-         * At this point all waiters continue. Each one takes its
-         * slice of the semaphor. Now it's our turn to wait: Since
-         * the external mutex is held, no thread can leave cond_wait,
-         * yet. For this reason, we can be sure that no thread gets
-         * a chance to eat *more* than one slice. OTOH, it means
-         * that the last waiter must send us a wake-up.
-         */
-        WaitForSingleObject(cond->continue_broadcast, INFINITE);
-        /*
-         * Since the external mutex is held, no thread can enter
-         * cond_wait, and, hence, it is safe to reset this flag
-         * without cond->waiters_lock held.
-         */
-        cond->was_broadcast = 0;
-    } else {
-        LeaveCriticalSection(&cond->waiters_lock);
-    }
-    return 0;
-}
-
-static char* _ansi_to_utf8(const char *str) {
-    int len;
-    char *utf8;
-    wchar_t *unicode;
-
-    //ANSI( MutiByte ) -> UCS-2( WideByte ) -> UTF-8( MultiByte )
-    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
-    unicode = (wchar_t *) calloc(len + 1, sizeof(wchar_t));
-    MultiByteToWideChar(CP_ACP, 0, str, -1, unicode, len);
-
-    len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
-    utf8 = (char *) calloc(len + 1, sizeof(char));
-
-    WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len, NULL, NULL);
-    free(unicode);
-
-    return utf8;
-}
-const struct utils_os_backend utils_windows_backend = {
-    .name = "windows 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,
-    .sdb_sleep_ms = _sdb_sleep_ms,
-    .sdb_dirstart = _sdb_dirstart,
-    .sdb_dirstop = _sdb_dirstop,
-    .sdb_socket_setbufsize = _sdb_socket_setbufsize,
-    .disable_tcp_nagle = _disable_tcp_nagle,
-// simple pthread implementations
-    .sdb_thread_create = _sdb_thread_create,
-    .sdb_mutex_lock = _pthread_mutex_lock,
-    .sdb_mutex_unlock = _pthread_mutex_unlock,
-    .sdb_cond_wait = _pthread_cond_wait,
-    .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
-};