#
#
-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 \
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)/*
--- /dev/null
+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)
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+5
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+#!/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
+
--- /dev/null
+usr/sbin/sdbd
+etc/init.d/sdbd
+etc/rc.d/rc3.d/S06sdbd
+* 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
-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>
--- /dev/null
+#!/bin/sh
+/etc/init.d/sdbd start
--- /dev/null
+#! /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
--- /dev/null
+# 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
--- /dev/null
+
+ 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
+
--- /dev/null
+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.
--- /dev/null
+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
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+###########################################################
+## 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))
+++ /dev/null
-/*
-* 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;
-}
+++ /dev/null
-/*
-* 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_ */
#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 */
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;
}
}
+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);
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);
+}
+++ /dev/null
-/*
-* 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_ */
--- /dev/null
+/*
+ * 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;
+}
* 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);
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);
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");
}
}
-void fdevent_plist_enqueue(fdevent *node)
+static void fdevent_plist_enqueue(fdevent *node)
{
fdevent *list = &list_pending;
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;
node->prev = 0;
}
-fdevent *fdevent_plist_dequeue(void)
+static fdevent *fdevent_plist_dequeue(void)
{
fdevent *list = &list_pending;
fdevent *node = list->next;
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));
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;
}
}
if(fde->state & FDE_ACTIVE) {
- fdevent_backend->fdevent_disconnect(fde);
+ fdevent_disconnect(fde);
dump_fde(fde, "disconnect");
fdevent_unregister(fde);
}
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");
}
}
}
-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);
+ }
+ }
}
#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
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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
-};
+++ /dev/null
-/*
- * 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
-};
-
-
/*
-* 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, ×tamp, &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, ×tamp, &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;
+ }
}
+++ /dev/null
-/*
-* 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_ */
+++ /dev/null
-/*
-* 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;
-}
+++ /dev/null
-/*
-* 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_ */
--- /dev/null
+/*
+ * 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);
+}
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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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';
+}
+
--- /dev/null
+/*
+ * 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';
+ }
+}
+
--- /dev/null
+/*
+ * 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';
+ }
+}
+
--- /dev/null
+/*
+ * 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 */
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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;
-}
-
+++ /dev/null
-/*
- * 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";
-}
-
+++ /dev/null
-/*
- * 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_ */
-
+++ /dev/null
-/*
- * 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;
-}
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-/*
- * 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);
-}
-
+++ /dev/null
-/*
- * 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__ */
-
+++ /dev/null
-/*
- * 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_ */
-
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
-* 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);
- }
-}
+++ /dev/null
-/*
-* 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_ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+--- 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>
+
+++ /dev/null
-/*
- * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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);
+}
+
#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 );
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, ...)
}
}
+#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));
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)
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;
}
{
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) {
return 0;
}
-#ifdef OS_WINDOWS
+#ifdef HAVE_WIN32_PROC
static BOOL WINAPI ctrlc_handler(DWORD type)
{
exit(STATUS_CONTROL_C_EXIT);
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.
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];
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();
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;
console_port, sdb_port);
}
}
+#endif
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
{
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
local_connect(port, NULL);
return 0;
}
+#endif // SDB_HOST
if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
char *local, *remote, *err;
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
}
#include <limits.h>
#include "transport.h" /* readx(), writex() */
-#include "sdb_usb.h"
#define MAX_PAYLOAD 4096
#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
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 */
*/
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;
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);
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);
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);
#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;
#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);
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
#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)) {
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;
}
}
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;
}
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 {
// 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? */
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");
}
}
-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;
}
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;
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);
- }
-}
#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);
** 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
+++ /dev/null
-/*
-* 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";
+++ /dev/null
-/*
-* 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_*/
+++ /dev/null
-/*
-* 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;
-}
+++ /dev/null
-/*
-* 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_ */
+++ /dev/null
-/*
- * 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
+++ /dev/null
-
-#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
--- /dev/null
+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
--- /dev/null
+#\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
--- /dev/null
+#\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
--- /dev/null
+/*\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
--- /dev/null
+#\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
--- /dev/null
+/*\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
--- /dev/null
+; 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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
+ ¶m, 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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+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.
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+; SdbWinUsbApi.def : Declares the module parameters.
+
+LIBRARY "SdbWinUsbApi.DLL"
+
+EXPORTS
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__
--- /dev/null
+/*
+ * 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"
--- /dev/null
+/*
+ * 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;
#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;
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;
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;
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);
return ret;
}
+#if SDB_HOST
struct state_info {
transport_type transport;
char* serial;
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")) {
}
return NULL;
}
-
+#endif /* SDB_HOST */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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;
+
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+
+}
+
#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"
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;
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
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);
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);
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;
}
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
--- /dev/null
+/*
+ * 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 */
#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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 );
+}
--- /dev/null
+/*
+ * 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 */
#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"
static fdevent transport_registration_fde;
+#if SDB_HOST
static int list_transports_msg(char* buffer, size_t bufferlen)
{
char head[5];
tracker = next;
}
}
+#else
+void update_transports(void)
+{
+ // nothing to do on the device side
+}
+#endif // SDB_HOST
typedef struct tmsg tmsg;
struct tmsg
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;
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);
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;
return result;
}
+#if SDB_HOST
static const char *statename(atransport *t)
{
switch(t->connection_state){
}
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)
{
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.
t->device_name = strdup(device_name);
}
}
-
+#endif
register_transport(t);
}
+#if SDB_HOST
atransport *find_transport(const char *serial)
{
atransport *t;
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;
if (type == t->type)
cnt++;
}
-
sdb_mutex_unlock(&transport_lock);
D("connected device count:%d\n",cnt);
return cnt;
*/
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));
#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>
#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.
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)
{
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);
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;
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;
/* 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",
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)
}
+#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)
{
sdb_mutex_unlock( &local_transports_lock );
return result;
}
+#endif
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 );
{
}
sdb_mutex_unlock( &local_transports_lock );
}
-
+#endif
return fail;
}
#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)
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;
}
}
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;
}
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;
}
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)
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
--- /dev/null
+/*
+ * 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");
+}
+
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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,
+ ¬ificationIterators[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;
+ }
+}
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
* 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;
}
#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 */
+++ /dev/null
-/*
- * 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 */
+++ /dev/null
-/*
- * 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
-};
+++ /dev/null
-/*
- * 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
-};