From: Sehong Na Date: Thu, 14 Nov 2013 06:05:08 +0000 (+0900) Subject: init tizen_2.2.1 X-Git-Tag: 2.2.1_release X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1287dc8b6baa57753eeee7705a765932a80b24fe;p=sdk%2Ftools%2Fsdb.git init tizen_2.2.1 --- diff --git a/Makefile b/Makefile index 07d4853..45c645e 100644 --- a/Makefile +++ b/Makefile @@ -5,22 +5,27 @@ # HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1) +LBITS := $(shell getconf LONG_BIT) +OBJDIR := bin +MODULE := sdb # sdb host tool # ========================================================= -CC := gcc +ifeq ($(HOST_OS),darwin) + CC := clang +endif # ifeq ($(HOST_OS),linux) LOCAL_USB_SRC := src/usb_linux.c LOCAL_UTIL_SRC := src/utils_unix.c LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c - LOCAL_LFLAGS := -lrt -lpthread + LOCAL_LFLAGS := -lrt -lpthread -ludev LOCAL_CFLAGS := -DOS_LINUX -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1 -D_FILE_OFFSET_BITS=64 endif ifeq ($(HOST_OS),darwin) - LOCAL_USB_SRC := src/libusb/darwin.c src/sdb_usb.c src/libusb/error.c src/libusb/usb.c src/libusb/descriptors.c + LOCAL_USB_SRC := src/usb_darwin.c LOCAL_UTIL_SRC := src/utils_unix.c LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon @@ -28,7 +33,7 @@ ifeq ($(HOST_OS),darwin) endif ifeq ($(HOST_OS),mingw32) - LOCAL_USB_SRC := src/libusb/windows.c + LOCAL_USB_SRC := src/usb_windows.c LOCAL_UTIL_SRC := src/utils_windows.c LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_windows.c LOCAL_CFLAGS := -DOS_WINDOWS @@ -46,18 +51,22 @@ SDB_SRC_FILES := \ src/commandline.c \ src/sdb_client.c \ src/sockets.c \ - src/services.c \ src/file_sync_client.c \ $(LOCAL_USB_SRC) \ + src/device_vendors.c \ $(LOCAL_UTIL_SRC) \ $(LOCAL_OTHER_SRC) \ src/utils.c \ src/strutils.c \ + src/memutils.c \ src/linkedlist.c \ src/sdb_model.c \ src/sdb_constants.c \ src/file_sync_functions.c \ - src/command_function.c + src/command_function.c \ + src/log.c \ + src/listener.c \ + src/sdb_map.c SDB_CFLAGS := -O2 -g -Wall -Wno-unused-parameter SDB_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE @@ -66,16 +75,11 @@ SDB_CFLAGS += $(LOCAL_CFLAGS) SDB_LFLAGS := $(LOCAL_LFLAGS) STATIC_LFLAGS := $(LOCAL_STATIC_LFLAGS) -OBJDIR := bin - -MODULE := sdb - all : $(MODULE) sdb : $(SDB_SRC_FILES) - rm -rf $(OBJDIR) mkdir -p $(OBJDIR) $(CC) $(SDB_CFLAGS) -o $(OBJDIR)/$(MODULE) $(SDB_SRC_FILES) $(LOCAL_IFLAGS) $(SDB_LFLAGS) $(STATIC_LFLAGS) clean : - rm -rf $(OBJDIR)/* + rm -rf $(OBJDIR) diff --git a/package/changelog b/package/changelog index e482594..ef1bb35 100644 --- a/package/changelog +++ b/package/changelog @@ -1,48 +1,93 @@ +* 2.2.31 +- bug fix web debug in Unix +== ho.namkoong 2013-10-31 +* 2.2.30 +- removed fatal error if there is no winusb dll & removed unused file +== yoonki.park 2013-10-29 +* 2.2.29 +- fix Windows disconnect bug (sdb 2.2.27) +== ho.namkoong 2013-10-28 +* 2.2.28 +- sync source from public (sdb 2.2.26) +== yoonki.park 2013-10-28 +* 2.2.27 +- fix connect bug +== ho.namkoong 2013-10-25 +* 2.2.26 +- fix map bug +== ho.namkoong 2013-10-24 +* 2.2.25 +- revert devices list format +== yoonki.park 2013-10-23 16:00 +* 2.2.24 +- refactoring by protex +== yoonki.park 2013-10-23 16:00 +* 2.2.23 +- refactoring by protex +== yoonki.park 2013-10-23 16:00 +* 2.2.22 +- refactoring usb module from windows +== yoonki.park 2013-10-23 16:00 +* 2.2.21 +- sync source from dev branch +== yoonki.park 2013-10-22 24:00 +* 2.2.20 +- fix offline bug +== ho.namkoong 2013-09-16 21:35 +* 2.2.19 +- fix device undetected bug +== ho.namkoong 2013-09-16 20:36 +* 2.2.18 +- Fix duplicated target bug +== ho.namkoong 2013-09-16 13:50 +* 2.2.17 +- fix pull/ push bug +== ho.namkoong 2013-09-14 20:06 * 2.2.16 -- fixed build script for tsudo -== ho.namkoong 2013-07-15 +- fix bugs about sdb test cases +== ho.namkoong 2013-09-01 * 2.2.15 -- give abs path to tsudo -== ho.namkoong 2013-07-12 +- version up for refactoring test +== ho.namkoong 2013-08-23 * 2.2.14 -- Change PATH_MAX in Windows 256 -> 4096 -== ho.namkoong 2013-07-11 +- version up 2.2.14 +== ho.namkoong 2013-08-07 * 2.2.13 -- echo stdout in install script -== ho.namkoong 2013-07-11 +- version up 2.2.13 +== ho.namkoong 2013-08-05 * 2.2.12 -- use tsudo instead of gksudo -== ho.namkoong 2013-07-11 +- fix socket close bug +== ho.namkoong 2013-07-24 * 2.2.11 -- Fixed sdbd version checking without rpm query -== ho.namkoong 2013-07-08 +- fix web debugging bug +== ho.namkoong 2013-07-24 * 2.2.10 -- Fixed argument append util for da/oprofile command -== kh5325.kim 2013-07-08 +- fix forward bug +== ho.namkoong 2013-07-24 * 2.2.9 -- Fix pull/push message -== ho.namkoong 2013-07-04 +- remove setting sdb path +== yoonki.park 2013-07-23 * 2.2.8 -- Fix window install bug -== ho.namkoong 2013-06-28 +- fixed to install on windows +== ho.namkoong 2013-07-22 * 2.2.7 -- rollback linux usb control -== ho.namkoong 2013-06-25 +- fixed to add sdb path to windows shell +== ho.namkoong 2013-07-19 * 2.2.6 -- change lstat to stat for treating link file as regular file -== ho.namkoong 2013-06-24 +- change PATH_MAX in Windows 256 -> 4096 +== ho.namkoong 2013-07-11 * 2.2.5 -- modify debug launchpad applied sdbd version -== ho.namkoong 2013-06-24 +- use tsudo +== ho.namkoong 2013-07-11 * 2.2.4 -- change sdb version in help page -== ho.namkoong 2013-06-23 +- use libusb.so +== ho.namkoong 2013-07-11 * 2.2.3 -- remove printf in lauchapp -== ho.namkoong 2013-06-23 +- fix da and oprofile arg appending bug +== ho.namkoong 2013-07-04 * 2.2.2 -- apply debug launch pad -== ho.namkoong 2013-06-23 +- sdb for tizen2.2 +== yoonki.park 2013-07-04 * 2.2.1 - fixed crash on Windows == yoonki.park 2013-06-21 diff --git a/package/pkginfo.manifest b/package/pkginfo.manifest index 731fb11..5fbb322 100644 --- a/package/pkginfo.manifest +++ b/package/pkginfo.manifest @@ -1,4 +1,4 @@ -Version:2.2.16 +Version:2.2.31 Source:sdb Maintainer:Kangho Kim , Yoonki Park, Hyunsik Noh, Gun Kim, Ho Namkoong, Taeyoung Son diff --git a/package/sdb.install.linux b/package/sdb.install.linux index 456cba7..256b648 100755 --- a/package/sdb.install.linux +++ b/package/sdb.install.linux @@ -1,54 +1,3 @@ #!/bin/bash -ex -## Set sdb's environment path -bashrc=${HOME}/.bashrc -if [ -f ${bashrc} ]; then - s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` -else - s= -fi - -if [ "x${s}" = "x" ]; then -cat >> ${bashrc} << END -## Tizen SDK configuration -# This is generated by Tizen SDK. Please do not modify by yourself. -# Set sdb environment path -export PATH=\$PATH:${INSTALLED_PATH}/tools -## End Tizen SDK configuration -END -fi - -source ${HOME}/.bashrc - -# set udev rules file - -TMP_FILE=99-samsung-device.rules -echo "# Add a udev rules when you want to develop a Tizen application with your device." >> $TMP_FILE -echo "# Use this format to add each vendor to the file:" >> $TMP_FILE -echo "# SUBSYSTEM==\"usb\", ATTR{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE -echo "# In the example, the vendor ID is for Samsung manufacture. The mode specifies read/write permissions, and group defines which Unix group owns the device node." >> $TMP_FILE -echo "#" >> $TMP_FILE -echo "# Contact : Kangho Kim , Yoonki Park, Ho Namkoong " >> $TMP_FILE -echo "# See also udev(7) for an overview of rule syntax." >> $TMP_FILE -echo "" >> $TMP_FILE -echo "# Samsung" >> $TMP_FILE -echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE -echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6863\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE - -chmod +x $TMP_FILE -CURRENT_DIR=`pwd` - -if [ -z "$TSUDO" ]; then - if [ -f /usr/bin/gksudo ] - then gksudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/ - else if [ -f /usr/bin/sudo ] - then sudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/ - fi - fi - exit 0 -else - $TSUDO -m "Enter your password to install sdb." mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/ - exit 0 -fi - exit 0 diff --git a/package/sdb.install.macos-64 b/package/sdb.install.macos-64 index 08a8365..256b648 100755 --- a/package/sdb.install.macos-64 +++ b/package/sdb.install.macos-64 @@ -1,24 +1,3 @@ #!/bin/bash -ex -## Set sdb's environment path - -bashrc=${HOME}/.bashrc -if [ -f ${bashrc} ]; then - s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` -else - s= -fi - -if [ "x${s}" = "x" ]; then -cat >> ${bashrc} << END -## Tizen SDK configuration -# This is generated by Tizen SDK. Please do not modify by yourself. -# Set sdb environment path -export PATH=\$PATH:${INSTALLED_PATH}/tools -## End Tizen SDK configuration -END -fi - -source ${HOME}/.bashrc - exit 0 diff --git a/package/sdb.install.windows b/package/sdb.install.windows index 02753b7..83cb140 100644 --- a/package/sdb.install.windows +++ b/package/sdb.install.windows @@ -1,5 +1 @@ @echo off - -echo "setting path..." -setx -m PATH "%PATH%;${INSTALLED_PATH}\tools -exit 0 diff --git a/package/sdb.remove.linux b/package/sdb.remove.linux index b849590..8f3cbf8 100755 --- a/package/sdb.remove.linux +++ b/package/sdb.remove.linux @@ -2,35 +2,23 @@ SDB_PATH=tools/sdb ${INSTALLED_PATH}/${SDB_PATH} kill-server rm -rf ${INSTALLED_PATH}/${SDB_PATH} -## remove sdb environment path -s=`cat ${HOME}/.bashrc | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` -if [ "x${s}" = "x" ] ; then - exit 0 -fi +UDEV_RULE=/etc/udev/rules.d/99-samsung-device.rules -if [ ${s} -ge 0 ] ; then - e=`cat ${HOME}/.bashrc | grep -n "## End Tizen SDK configuration" | cut -f1 -d":"` - if [ $e -ge $s ] ; then - cp ${HOME}/.bashrc ${HOME}/.bashrc.tizen - sed "${s},${e}d" ${HOME}/.bashrc > ${HOME}/.bashrc.swap - mv ${HOME}/.bashrc.swap ${HOME}/.bashrc - source ${HOME}/.bashrc - fi +if [ ! -f ${UDEV_RULE} ]; then + exit 0 fi - ## remove udev rule file - if [ -z "$TSUDO" ]; then if [ -f /usr/bin/gksudo ] - then gksudo rm -rf /etc/udev/rules.d/99-samsung-device.rules + then gksudo rm -rf ${UDEV_RULE} else if [ -f /usr/bin/sudo ] - then sudo rm -rf /etc/udev/rules.d/99-samsung-device.rules + then sudo rm -rf ${UDEV_RULE} fi fi exit 0 else - $TSUDO -m "Enter your password to uninstall sdb." rm -rf /etc/udev/rules.d/99-samsung-device.rules + $TSUDO -m "Enter your password to uninstall sdb." rm -rf ${UDEV_RULE} exit 0 fi diff --git a/package/sdb.remove.macos-64 b/package/sdb.remove.macos-64 index 7632317..10a8dda 100755 --- a/package/sdb.remove.macos-64 +++ b/package/sdb.remove.macos-64 @@ -2,21 +2,5 @@ SDB_PATH=tools/sdb ${INSTALLED_PATH}/${SDB_PATH} kill-server rm -rf ${INSTALLED_PATH}/${SDB_PATH} -## remove sdb environment path -s=`cat ${HOME}/.bashrc | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` - -if [ "x${s}" = "x" ] ; then - exit 1 -fi - -if [ ${s} -ge 0 ] ; then - e=`cat ${HOME}/.bashrc | grep -n "## End Tizen SDK configuration" | cut -f1 -d":"` - if [ $e -ge $s ] ; then - cp ${HOME}/.bashrc ${HOME}/.bashrc.tizen - sed "${s},${e}d" ${HOME}/.bashrc > ${HOME}/.bashrc.swap - mv ${HOME}/.bashrc.swap ${HOME}/.bashrc - source ${HOME}/.bashrc - fi -fi exit 0 diff --git a/package/sdb.remove.windows b/package/sdb.remove.windows index 1c3c664..1d845d3 100644 --- a/package/sdb.remove.windows +++ b/package/sdb.remove.windows @@ -1,8 +1,18 @@ @echo off -set execute_path=tools -%INSTALLED_PATH%\%execute_path%\sdb.exe kill-server -del %INSTALLED_PATH%\%execute_path%\sdb.exe -del %INSTALLED_PATH%\%execute_path%\ansicon.exe -del %INSTALLED_PATH%\%execute_path%\ANSI32.dll -exit 0 +set SDB_PATH=%INSTALLED_PATH%\tools + +%SDB_PATH%\sdb.exe kill-server +del %SDB_PATH%\sdb.exe +del %SDB_PATH%\ansicon.exe +del %SDB_PATH%\ANSI32.dll + +::echo "removing sdb path..." + +::set replace= +::set search=%SDB_PATH% +::set subject=%PATH% +:: update path +::call set subject=%%subject:%search%=%replace%%% +::setx -m PATH "%subject%" +exit 0 \ No newline at end of file diff --git a/package/usb-connection-for-ssh.install.linux b/package/usb-connection-for-ssh.install.linux deleted file mode 100755 index b314d9d..0000000 --- a/package/usb-connection-for-ssh.install.linux +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -samsung_udev="99-samsung-device.rules" -rules_dir=${INSTALLED_PATH}/tools/ssh -rules_path=${rules_dir}/${samsung_udev} - -sed "s|TIZEN_SDK_SSH_PATH|${rules_dir}|g" ${rules_path} > ${rules_path}.mod -mv ${rules_path}.mod ${rules_path} diff --git a/src/command_function.c b/src/command_function.c index 47f3eb1..51815ef 100644 --- a/src/command_function.c +++ b/src/command_function.c @@ -28,7 +28,6 @@ #include #include "utils.h" #include "fdevent.h" -#include "sdb.h" #include "commandline.h" #include "command_function.h" @@ -39,6 +38,10 @@ #include "strutils.h" #include "file_sync_client.h" #include "file_sync_functions.h" +#include "common_modules.h" + +#include "log.h" +#include "sdb.h" static const char *SDK_TOOL_PATH="/home/developer/sdk_tools"; static const char *APP_PATH_PREFIX="/opt/apps"; @@ -295,6 +298,23 @@ int __connect(int argc, char ** argv, void** extargv) { } } +int device_con(int argc, char ** argv, void** extargv) { + + char *tmp; + char full_cmd[PATH_MAX]; + + snprintf(full_cmd, sizeof full_cmd, "host:device_con:%s:%s", argv[1], argv[2]); + D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd); + tmp = sdb_query(full_cmd, extargv); + + if(tmp != NULL) { + printf("%s", tmp); + return 0; + } + + return 1; +} + int get_state_serialno(int argc, char ** argv, void** extargv) { char* serial = (char *)extargv[0]; transport_type* ttype = (transport_type*)extargv[1]; @@ -340,8 +360,11 @@ int status_window(int argc, char ** argv, void** extargv) { #else int fd; fd = unix_open("/dev/null", O_WRONLY); - dup2(fd, 2); - sdb_close(fd); + + if(fd >= 0) { + dup2(fd, 2); + sdb_close(fd); + } #endif format_host_command(full_cmd, sizeof full_cmd, "get-state", *ttype, serial); @@ -397,7 +420,7 @@ int version(int argc, char ** argv, void** extargv) { 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); + SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_VERSION_PATCH); } return 0; } @@ -487,23 +510,20 @@ int shell(int argc, char ** argv, void** extargv) { strcat(buf, "\""); } - for(;;) { - D("interactive shell loop. buff=%s\n", buf); - fd = sdb_connect(buf, extargv); - if(fd >= 0) { - D("about to read_and_dump(fd=%d)\n", fd); - read_and_dump(fd); - D("read_and_dump() done.\n"); - sdb_close(fd); - r = 0; - } else { - r = 1; - } - - D("interactive shell loop. return r=%d\n", r); - return r; + D("interactive shell loop. buff=%s\n", buf); + fd = sdb_connect(buf, extargv); + if(fd >= 0) { + D("about to read_and_dump(fd=%d)\n", fd); + read_and_dump(fd); + D("read_and_dump() done.\n"); + sdb_close(fd); + r = 0; + } else { + r = 1; } - return 1; + + D("interactive shell loop. return r=%d\n", r); + return r; } int forkserver(int argc, char** argv, void** extargv) { diff --git a/src/command_function.h b/src/command_function.h index f9c6801..42816ee 100644 --- a/src/command_function.h +++ b/src/command_function.h @@ -30,16 +30,17 @@ #define TRACE_TAG TRACE_SDB #ifdef OS_WINDOWS +#undef PATH_MAX #define PATH_MAX 4096 #endif - int da(int argc, char ** argv, void** extargv); int oprofile(int argc, char ** argv, void** extargv); int launch(int argc, char ** argv, void** extargv); int devices(int argc, char ** argv, void** extargv); int __disconnect(int argc, char ** argv, void** extargv); int __connect(int argc, char ** argv, void** extargv); +int device_con(int argc, char ** argv, void** extargv); int get_state_serialno(int argc, char ** argv, void** extargv); int root(int argc, char ** argv, void** extargv); int status_window(int argc, char ** argv, void** extargv); diff --git a/src/commandline.c b/src/commandline.c index f5bd80d..46b8e1b 100755 --- a/src/commandline.c +++ b/src/commandline.c @@ -35,10 +35,9 @@ #include #endif #include "utils.h" -#include "sdb.h" #include "sdb_client.h" #include "file_sync_service.h" - +#include "log.h" #include "linkedlist.h" #include "sdb_constants.h" @@ -100,6 +99,7 @@ void read_and_dump(int fd) fwrite(buf, 1, len, stdout); fflush(stdout); } + } static void *stdin_read_thread(void *x) @@ -135,7 +135,6 @@ static void *stdin_read_thread(void *x) stdin_raw_restore(INPUT_FD, tio_save); free(tio_save); #endif - free(args); exit(0); } } @@ -263,7 +262,7 @@ const char* get_basename(const char* filename) } } -int __inline__ get_server_port() { +int get_server_port() { return DEFAULT_SDB_PORT; } @@ -272,17 +271,17 @@ static void create_opt_list(LIST_NODE** opt_list) { OPTION* serial = NULL; create_option(&serial, COMMANDLINE_SERIAL_LONG_OPT, COMMANDLINE_SERIAL_SHORT_OPT, COMMANDLINE_SERIAL_DESC, COMMANDLINE_SERIAL_DESC_SIZE, COMMANDLINE_SERIAL_ARG_DESC, COMMANDLINE_SERIAL_HAS_ARG); - append(opt_list, serial); + prepend(opt_list, serial); OPTION* device = NULL; create_option(&device, COMMANDLINE_DEVICE_LONG_OPT, COMMANDLINE_DEVICE_SHORT_OPT, COMMANDLINE_DEVICE_DESC, COMMANDLINE_DEVICES_DESC_SIZE, EMPTY_STRING, COMMANDLINE_DEVICE_HAS_ARG); - append(opt_list, device); + prepend(opt_list, device); OPTION* emulator = NULL; create_option(&emulator, COMMANDLINE_EMULATOR_LONG_OPT, COMMANDLINE_EMULATOR_SHORT_OPT, COMMANDLINE_EMULATOR_DESC, COMMANDLINE_EMULATOR_DESC_SIZE, EMPTY_STRING, COMMANDLINE_EMULATOR_HAS_ARG); - append(opt_list, emulator); + prepend(opt_list, emulator); } static void create_cmd_list(LIST_NODE** cmd_list) { @@ -290,112 +289,119 @@ static void create_cmd_list(LIST_NODE** cmd_list) { COMMAND* devices_cmd = NULL; create_command(&devices_cmd, COMMANDLINE_DEVICES_NAME, COMMANDLINE_DEVICES_DESC, COMMANDLINE_DEVICES_DESC_SIZE, EMPTY_STRING, devices, COMMANDLINE_DEVICES_MAX_ARG, COMMANDLINE_DEVICES_MIN_ARG); - append(cmd_list, devices_cmd); + prepend(cmd_list, devices_cmd); COMMAND* connect_cmd = NULL; create_command(&connect_cmd, COMMANDLINE_CONNECT_NAME, COMMANDLINE_CONNECT_DESC, COMMANDLINE_CONNECT_DESC_SIZE, COMMANDLINE_CONNECT_ARG_DESC, __connect, COMMANDLINE_CONNECT_MAX_ARG, COMMANDLINE_CONNECT_MIN_ARG); - append(cmd_list, connect_cmd); + prepend(cmd_list, connect_cmd); + //TODO REMOTE_DEVICE_CONNECT security issue should be resolved first +#if 0 + COMMAND* device_con_cmd = NULL; + create_command(&device_con_cmd, COMMANDLINE_DEVICE_CON_NAME, COMMANDLINE_DEVICE_CON_DESC, + COMMANDLINE_DEVICE_CON_DESC_SIZE, COMMANDLINE_DEVICE_CON_ARG_DESC, device_con, COMMANDLINE_DEVICE_CON_MAX_ARG, COMMANDLINE_DEVICE_CON_MIN_ARG); + prepend(cmd_list, device_con_cmd); +#endif COMMAND* disconnect_cmd = NULL; create_command(&disconnect_cmd, COMMANDLINE_DISCONNECT_NAME, COMMANDLINE_DISCONNECT_DESC, COMMANDLINE_DISCONNECT_DESC_SIZE, COMMANDLINE_DISCONNECT_ARG_DESC, __disconnect, COMMANDLINE_DISCONNECT_MAX_ARG, COMMANDLINE_DISCONNECT_MIN_ARG); - append(cmd_list, disconnect_cmd); + prepend(cmd_list, disconnect_cmd); COMMAND* push_cmd = NULL; create_command(&push_cmd, COMMANDLINE_PUSH_NAME, COMMANDLINE_PUSH_DESC, COMMANDLINE_PUSH_DESC_SIZE, COMMANDLINE_PUSH_ARG_DESC, push, COMMANDLINE_PUSH_MAX_ARG, COMMANDLINE_PUSH_MIN_ARG); - append(cmd_list, push_cmd); + prepend(cmd_list, push_cmd); COMMAND* pull_cmd = NULL; create_command(&pull_cmd, COMMANDLINE_PULL_NAME, COMMANDLINE_PULL_DESC, COMMANDLINE_PULL_DESC_SIZE, COMMANDLINE_PULL_ARG_DESC, pull, COMMANDLINE_PULL_MAX_ARG, COMMANDLINE_PULL_MIN_ARG); - append(cmd_list, pull_cmd); + prepend(cmd_list, pull_cmd); COMMAND* shell_cmd = NULL; create_command(&shell_cmd, COMMANDLINE_SHELL_NAME, COMMANDLINE_SHELL_DESC, COMMANDLINE_SHELL_DESC_SIZE, COMMANDLINE_SHELL_ARG_DESC, shell, COMMANDLINE_SHELL_MAX_ARG, COMMANDLINE_SHELL_MIN_ARG); - append(cmd_list, shell_cmd); + prepend(cmd_list, shell_cmd); COMMAND* dlog_cmd = NULL; create_command(&dlog_cmd, COMMANDLINE_DLOG_NAME, COMMANDLINE_DLOG_DESC, COMMANDLINE_DLOG_DESC_SIZE, COMMANDLINE_DLOG_ARG_DESC, dlog, COMMANDLINE_DLOG_MAX_ARG, COMMANDLINE_DLOG_MIN_ARG); - append(cmd_list, dlog_cmd); + prepend(cmd_list, dlog_cmd); COMMAND* install_cmd = NULL; create_command(&install_cmd, COMMANDLINE_INSTALL_NAME, COMMANDLINE_INSTALL_DESC, COMMANDLINE_INSTALL_DESC_SIZE, COMMANDLINE_INSTALL_ARG_DESC, install, COMMANDLINE_INSTALL_MAX_ARG, COMMANDLINE_INSTALL_MIN_ARG); - append(cmd_list, install_cmd); + prepend(cmd_list, install_cmd); COMMAND* uninstall_cmd = NULL; create_command(&uninstall_cmd, COMMANDLINE_UNINSTALL_NAME, COMMANDLINE_UNINSTALL_DESC, COMMANDLINE_UNINSTALL_DESC_SIZE, COMMANDLINE_UNINSTALL_ARG_DESC, uninstall, COMMANDLINE_UNINSTALL_MAX_ARG, COMMANDLINE_UNINSTALL_MIN_ARG); - append(cmd_list, uninstall_cmd); + prepend(cmd_list, uninstall_cmd); COMMAND* forward_cmd = NULL; create_command(&forward_cmd, COMMANDLINE_FORWARD_NAME, COMMANDLINE_FORWARD_DESC, COMMANDLINE_FORWARD_DESC_SIZE, COMMANDLINE_FORWARD_ARG_DESC, forward, COMMANDLINE_FORWARD_MAX_ARG, COMMANDLINE_FORWARD_MIN_ARG); - append(cmd_list, forward_cmd); + prepend(cmd_list, forward_cmd); COMMAND* help_cmd = NULL; create_command(&help_cmd, COMMANDLINE_HELP_NAME, COMMANDLINE_HELP_DESC, COMMANDLINE_HELP_DESC_SIZE, EMPTY_STRING, NULL, 0, 0); - append(cmd_list, help_cmd); + prepend(cmd_list, help_cmd); COMMAND* version_cmd = NULL; create_command(&version_cmd, COMMANDLINE_VERSION_NAME, COMMANDLINE_VERSION_DESC, COMMANDLINE_VERSION_DESC_SIZE, EMPTY_STRING, version, COMMANDLINE_VERSION_MAX_ARG, COMMANDLINE_VERSION_MIN_ARG); - append(cmd_list, version_cmd); + prepend(cmd_list, version_cmd); COMMAND* sserver_cmd = NULL; create_command(&sserver_cmd, COMMANDLINE_SSERVER_NAME, COMMANDLINE_SSERVER_DESC, COMMANDLINE_SSERVER_DESC_SIZE, EMPTY_STRING, start_server, COMMANDLINE_SSERVER_MAX_ARG, COMMANDLINE_SSERVER_MIN_ARG); - append(cmd_list, sserver_cmd); + prepend(cmd_list, sserver_cmd); COMMAND* kserver_cmd = NULL; create_command(&kserver_cmd, COMMANDLINE_KSERVER_NAME, COMMANDLINE_KSERVER_DESC, COMMANDLINE_KSERVER_DESC_SIZE, EMPTY_STRING, kill_server, COMMANDLINE_KSERVER_MAX_ARG, COMMANDLINE_KSERVER_MIN_ARG); - append(cmd_list, kserver_cmd); + prepend(cmd_list, kserver_cmd); COMMAND* gstate_cmd = NULL; create_command(&gstate_cmd, COMMANDLINE_GSTATE_NAME, COMMANDLINE_GSTATE_DESC, COMMANDLINE_GSTATE_DESC_SIZE, EMPTY_STRING, get_state_serialno, COMMANDLINE_GSTATE_MAX_ARG, COMMANDLINE_GSTATE_MIN_ARG); - append(cmd_list, gstate_cmd); + prepend(cmd_list, gstate_cmd); COMMAND* gserial_cmd = NULL; create_command(&gserial_cmd, COMMANDLINE_GSERIAL_NAME, COMMANDLINE_GSERIAL_DESC, COMMANDLINE_GSERIAL_DESC_SIZE, EMPTY_STRING, get_state_serialno, COMMANDLINE_GSERIAL_MAX_ARG, COMMANDLINE_GSERIAL_MIN_ARG); - append(cmd_list, gserial_cmd); + prepend(cmd_list, gserial_cmd); COMMAND* swindow_cmd = NULL; create_command(&swindow_cmd, COMMANDLINE_SWINDOW_NAME, COMMANDLINE_SWINDOW_DESC, COMMANDLINE_SWINDOW_DESC_SIZE, EMPTY_STRING, status_window, COMMANDLINE_SWINDOW_MAX_ARG, COMMANDLINE_SWINDOW_MIN_ARG); - append(cmd_list, swindow_cmd); + prepend(cmd_list, swindow_cmd); COMMAND* root_cmd = NULL; create_command(&root_cmd, COMMANDLINE_ROOT_NAME, COMMANDLINE_ROOT_DESC, COMMANDLINE_ROOT_DESC_SIZE, COMMANDLINE_ROOT_ARG_DESC, root, COMMANDLINE_ROOT_MAX_ARG, COMMANDLINE_ROOT_MIN_ARG); - append(cmd_list, root_cmd); + prepend(cmd_list, root_cmd); COMMAND* launch_cmd = NULL; create_command(&launch_cmd, COMMANDLINE_LAUNCH_NAME, NULL, 0, EMPTY_STRING, launch, COMMANDLINE_LAUNCH_MAX_ARG, COMMANDLINE_LAUNCH_MIN_ARG); - append(cmd_list, launch_cmd); + prepend(cmd_list, launch_cmd); COMMAND* forkserver_cmd = NULL; create_command(&forkserver_cmd, COMMANDLINE_FORKSERVER_NAME, NULL, 0, EMPTY_STRING, forkserver, COMMANDLINE_FORKSERVER_MAX_ARG, COMMANDLINE_FORKSERVER_MIN_ARG); - append(cmd_list, forkserver_cmd); + prepend(cmd_list, forkserver_cmd); COMMAND* oprofile_cmd = NULL; create_command(&oprofile_cmd, COMMANDLINE_OPROFILE_NAME, NULL, 0, EMPTY_STRING, oprofile, COMMANDLINE_OPROFILE_MAX_ARG, COMMANDLINE_OPROFILE_MIN_ARG); - append(cmd_list, oprofile_cmd); + prepend(cmd_list, oprofile_cmd); COMMAND* da_cmd = NULL; create_command(&da_cmd , COMMANDLINE_DA_NAME, NULL, 0, EMPTY_STRING, da, COMMANDLINE_DA_MAX_ARG, COMMANDLINE_DA_MIN_ARG); - append(cmd_list, da_cmd ); + prepend(cmd_list, da_cmd ); } int process_cmdline(int argc, char** argv) { @@ -469,10 +475,16 @@ int process_cmdline(int argc, char** argv) { if(argc < minargs + 1) { fprintf(stderr, "%s command has following args: %s, and it requires at least %d arguments\n", argv[0], command->argdesc, minargs); + if (serial != NULL) { + free(serial); + } return 1; } if(argc > maxargs + 1 && maxargs > -1) { fprintf(stderr, "command %s require at most %d arguments\n", argv[0], maxargs); + if (serial != NULL) { + free(serial); + } return 1; } extraarg[0] = serial; @@ -485,13 +497,16 @@ int process_cmdline(int argc, char** argv) { } print_help(opt_list, cmd_list); + if (serial != NULL) { + free(serial); + } return 1; } 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); + SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_VERSION_PATCH); fprintf(stderr, "\n Usage : sdb [option] [parameters]\n\n"); fprintf(stderr, " options:\n"); @@ -501,6 +516,7 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) { char* help_str = (char*)malloc(sizeof(char)*append_len*3); while(curptr != NULL) { OPTION* opt = (OPTION*)curptr->data; + curptr = curptr->next_ptr; const char** des = opt->desc; if(des != NULL) { snprintf(help_str, append_len*3, " -%s, --%s %s", opt->shortopt, opt->longopt, opt->argdesc); @@ -512,21 +528,20 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) { snprintf(append_str, append_len - opt_len + 1, "%s", HELP_APPEND_STR); fprintf(stderr, "%s%s", help_str, append_str); } + int array_len = opt->desc_size; + fprintf(stderr, "- %s\n", des[0]); + int i = 1; + for(; i< array_len; i++) { + fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]); + } } - - int array_len = opt->desc_size; - fprintf(stderr, "- %s\n", des[0]); - int i = 1; - for(; i< array_len; i++) { - fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]); - } - curptr = curptr->next_ptr; } fprintf(stderr, "\n commands:\n"); curptr = cmdlist; while(curptr != NULL) { COMMAND* cmd = (COMMAND*)curptr ->data; + curptr = curptr->next_ptr; const char** des = cmd->desc; if(des != NULL) { snprintf(help_str, append_len*3, " sdb %s %s", cmd->name, cmd->argdesc); @@ -545,10 +560,10 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) { fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]); } } - curptr = curptr->next_ptr; } - + free(append_str); + free(help_str); } diff --git a/src/commandline.h b/src/commandline.h index ea018a9..92486c9 100644 --- a/src/commandline.h +++ b/src/commandline.h @@ -47,7 +47,7 @@ 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 get_server_port(); int __sdb_command(const char* cmd, void** extargv); #endif /* COMMANDLINE_H_ */ diff --git a/src/common_modules.h b/src/common_modules.h new file mode 100644 index 0000000..1cdf866 --- /dev/null +++ b/src/common_modules.h @@ -0,0 +1,146 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef COMMON_MODULES_H_ +#define COMMON_MODULES_H_ + +#include "linkedlist.h" +#include "fdevent.h" +#include "sdb_usb.h" + +#define MAX_PAYLOAD 4096 +#define CHUNK_SIZE (64*1024) +#define DEFAULT_SDB_PORT 26099 + +#define A_VERSION 0x0100000 +#define SDB_VERSION_MAJOR 2 // increments upon significant architectural changes or the achievement of important milestones +#define SDB_VERSION_MINOR 2 // progress is made within a major version +#define SDB_VERSION_PATCH 29 // increments for small sets of changes +#define SDB_VERSION_MAX_LENGTH 128 + +extern MAP hex_map; + +typedef struct message MESSAGE; +struct message { + unsigned command; /* command identifier constant */ + unsigned arg0; /* first argument */ + unsigned arg1; /* second argument */ + unsigned data_length; /* length of payload (0 is allowed) */ + unsigned data_check; /* checksum of data payload */ + unsigned magic; /* command ^ 0xffffffff */ +}; + +typedef struct packet PACKET; +struct packet +{ + LIST_NODE* node; + + unsigned len; + void *ptr; + + MESSAGE msg; + unsigned char data[MAX_PAYLOAD]; +}; + +typedef enum transport_type { + kTransportUsb, + kTransportLocal, + kTransportAny, + kTransportRemoteDevCon +} transport_type; + +typedef struct transport TRANSPORT; +struct transport +{ + LIST_NODE* node; + //list for remote sockets which wait for CNXN + LIST_NODE* remote_cnxn_socket; + + int (*read_from_remote)(TRANSPORT* t, void* data, int len); + int (*write_to_remote)(PACKET *p, TRANSPORT *t); + void (*close)(TRANSPORT *t); + void (*kick)(TRANSPORT *t); + + int connection_state; + transport_type type; + + usb_handle *usb; + int sfd; + + char *serial; + int sdb_port; + char *device_name; + + int kicked; + unsigned req; + unsigned res; +}; + +typedef struct listener LISTENER; +struct listener +{ + LIST_NODE* node; + + FD_EVENT fde; + int fd; + + const char *local_name; + const char *connect_to; + TRANSPORT *transport; +}; + +typedef struct t_packet T_PACKET; +struct t_packet { + TRANSPORT* t; + PACKET* p; +}; + +typedef struct socket SDB_SOCKET; +struct socket { + int status; + LIST_NODE* node; + + unsigned local_id; + unsigned remote_id; + + int closing; + FD_EVENT fde; + int fd; + + //TODO HOT PATCH FOR 2048. + char char_2048; + int check_2048; + + LIST_NODE* pkt_list; + TRANSPORT *transport; + + PACKET* read_packet; +}; + +int readx(int fd, void *ptr, size_t len); +int writex(int fd, const void *ptr, size_t len); + +#endif /* SDB_TYPES_H_ */ diff --git a/src/device_vendors.c b/src/device_vendors.c new file mode 100644 index 0000000..5faa95e --- /dev/null +++ b/src/device_vendors.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "device_vendors.h" +#include "log.h" + + +VENDOR tizen_device_vendors[] = { + {"samsung", 0x04e8} //1256 +}; + + +void init_device_vendors(void) +{ + LOG_FIXME("should implement later\n"); + vendor_total_cnt = (sizeof(tizen_device_vendors)/sizeof(VENDOR)); +} diff --git a/src/device_vendors.h b/src/device_vendors.h new file mode 100644 index 0000000..476198b --- /dev/null +++ b/src/device_vendors.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DEVICE_VENDORS_H +#define __DEVICE_VENDORS_H + +#define VENDOR_COUNT_MAX 64 + +typedef struct +{ + const char *vendor; + int id; +} VENDOR; + +VENDOR tizen_device_vendors[VENDOR_COUNT_MAX]; + +unsigned vendor_total_cnt; + +void init_device_vendors(void); + +#endif diff --git a/src/fdevent.c b/src/fdevent.c old mode 100644 new mode 100755 index 32dd05f..826cb8f --- a/src/fdevent.c +++ b/src/fdevent.c @@ -28,214 +28,98 @@ #include "fdevent_backend.h" #include "transport.h" #include "utils.h" +#include "fdevent.h" +#include "log.h" -#if defined(OS_LINUX) -const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend; -#elif defined(OS_DARWIN) +#ifndef OS_WINDOWS +int max_select = 0; const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend; -#elif defined(OS_WINDOWS) -const struct fdevent_os_backend* fdevent_backend = &fdevent_windows_backend; -#define WIN32_FH_BASE 100 #else -#error "unsupported OS" +const struct fdevent_os_backend* fdevent_backend = &fdevent_windows_backend; #endif -fdevent list_pending = { - .next = &list_pending, - .prev = &list_pending, -}; +#define TRACE_TAG TRACE_SDB -fdevent **fd_table = 0; -int fd_table_max = 0; - -void _fatal(const char *fn, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:", fn); - vfprintf(stderr, fmt, ap); - va_end(ap); - abort(); -} +MAP event_map; -void fdevent_register(fdevent *fde) -{ #if defined(OS_WINDOWS) - int fd = fde->fd - WIN32_FH_BASE; -#else - int fd = fde->fd; +MAP sdb_handle_map; +HANDLE socket_event_handle[WIN32_MAX_FHS]; +int event_location_to_fd[WIN32_MAX_FHS]; +int current_socket_location = 0; #endif +void fdevent_register(FD_EVENT *fde) +{ + int fd = fde->fd; + if(fd < 0) { - FATAL("bogus negative fd (%d)\n", fde->fd); + LOG_FATAL("bogus negative fd (%d)\n", fd); } - if(fd >= fd_table_max) { - int oldmax = fd_table_max; - if(fde->fd > 32000) { - FATAL("bogus huuuuge fd (%d)\n", fde->fd); - } - if(fd_table_max == 0) { - fdevent_backend->fdevent_init(); - fd_table_max = 256; - } - while(fd_table_max <= fd) { - fd_table_max *= 2; - } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); - if(fd_table == 0) { - FATAL("could not expand fd_table to %d entries\n", fd_table_max); - } - memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); + if(fd > 32000) { + LOG_FATAL("bogus huuuuge FD(%d)\n", fd); + } + else { + fdevent_map_put(fd, fde); } - - fd_table[fd] = fde; } -void fdevent_unregister(fdevent *fde) +void fdevent_unregister(FD_EVENT *fde) { -#if defined(OS_WINDOWS) - int fd = fde->fd - WIN32_FH_BASE; -#else - int fd = fde->fd; -#endif - if((fd < 0) || (fd >= fd_table_max)) { - FATAL("fd out of range (%d)\n", fde->fd); - } + int fd = fde->fd; - if(fd_table[fd] != fde) { - FATAL("fd_table out of sync"); + if((fd < 0)) { + LOG_FATAL("fdevent out of range FD(%d)\n", fd); } - - fd_table[fd] = 0; - - if(!(fde->state & FDE_DONT_CLOSE)) { - dump_fde(fde, "close"); - sdb_close(fde->fd); + else if(fdevent_map_get(fd) != fde) { + LOG_FATAL("fd event out of sync"); } -} - -void fdevent_plist_enqueue(fdevent *node) -{ - fdevent *list = &list_pending; - - node->next = list; - node->prev = list->prev; - node->prev->next = node; - list->prev = node; -} - -void fdevent_plist_remove(fdevent *node) -{ - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; -} - -fdevent *fdevent_plist_dequeue(void) -{ - fdevent *list = &list_pending; - fdevent *node = list->next; - - if(node == list) return 0; - - list->next = node->next; - list->next->prev = list; - node->next = 0; - node->prev = 0; - - return node; -} - -fdevent *fdevent_create(int fd, fd_func func, void *arg) -{ - fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); - if(fde == 0) return 0; - fdevent_install(fde, fd, func, arg); - fde->state |= FDE_CREATED; - return fde; -} - -void fdevent_destroy(fdevent *fde) -{ - if(fde == 0) return; - if(!(fde->state & FDE_CREATED)) { - FATAL("fde %p not created by fdevent_create()\n", fde); + else { + fdevent_map_remove(fd); + sdb_close(fde->fd); } - fdevent_remove(fde); } -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) +void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg) { - memset(fde, 0, sizeof(fdevent)); - fde->state = FDE_ACTIVE; + D("FD(%d)\n", fd); + memset(fde, 0, sizeof(FD_EVENT)); fde->fd = fd; - fde->force_eof = 0; fde->func = func; fde->arg = arg; + fde->events = 0; #ifndef OS_WINDOWS fcntl(fd, F_SETFL, O_NONBLOCK); + if(fd >= max_select) { + max_select = fd + 1; + } #endif fdevent_register(fde); - dump_fde(fde, "connect"); - fdevent_backend->fdevent_connect(fde); - fde->state |= FDE_ACTIVE; } -void fdevent_remove(fdevent *fde) +void fdevent_remove(FD_EVENT *fde) { - if(fde->state & FDE_PENDING) { - fdevent_plist_remove(fde); - } - - if(fde->state & FDE_ACTIVE) { - fdevent_backend->fdevent_disconnect(fde); - dump_fde(fde, "disconnect"); - fdevent_unregister(fde); - } - - fde->state = 0; + fdevent_backend->fdevent_disconnect(fde); + fdevent_unregister(fde); fde->events = 0; } - -void fdevent_set(fdevent *fde, unsigned events) -{ - events &= FDE_EVENTMASK; - - if((fde->state & FDE_EVENTMASK) == events) return; - - if(fde->state & FDE_ACTIVE) { - fdevent_backend->fdevent_update(fde, events); - dump_fde(fde, "update"); - } - - fde->state = (fde->state & FDE_STATEMASK) | events; - - if(fde->state & FDE_PENDING) { - /* if we're pending, make sure - ** we don't signal an event that - ** is no longer wanted. - */ - fde->events &= (~events); - if(fde->events == 0) { - fdevent_plist_remove(fde); - fde->state &= (~FDE_PENDING); - } - } -} - -void fdevent_add(fdevent *fde, unsigned events) { - fdevent_set(fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); +FD_EVENT* fdevent_map_get(int _key) { + MAP_KEY key; + key.key_int = _key; + return map_get(&event_map, key); } -void fdevent_del(fdevent *fde, unsigned events) { - fdevent_set(fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); +void fdevent_map_put(int _key, FD_EVENT* _value) { + MAP_KEY key; + key.key_int = _key; + map_put(&event_map, key, _value); } -void fdevent_loop() -{ - fdevent_backend->fdevent_loop(); +void fdevent_map_remove(int _key) { + MAP_KEY key; + key.key_int = _key; + map_remove(&event_map, key); } diff --git a/src/fdevent.h b/src/fdevent.h old mode 100644 new mode 100755 index 6bb2d4b..2e876be --- a/src/fdevent.h +++ b/src/fdevent.h @@ -18,74 +18,88 @@ #define __FDEVENT_H #include /* for int64_t */ +#include "linkedlist.h" +#include "sdb_map.h" /* events that may be observed */ -#define FDE_READ 0x0001 -#define FDE_WRITE 0x0002 -#define FDE_ERROR 0x0004 -#define FDE_TIMEOUT 0x0008 +#define FDE_READ 1 +#define FDE_WRITE 2 +#define FDE_MASK 3 -#define FDE_EVENTMASK 0x00ff -#define FDE_STATEMASK 0xff00 - -#define FDE_ACTIVE 0x0100 -#define FDE_PENDING 0x0200 -#define FDE_CREATED 0x0400 +typedef struct fd_event FD_EVENT; +typedef void (*fd_func)(int fd, unsigned events, void *userdata); -/* features that may be set (via the events set/add/del interface) */ -#define FDE_DONT_CLOSE 0x0080 +struct fd_event +{ + LIST_NODE* node; -typedef struct fdevent fdevent; + int fd; + unsigned events; -typedef void (*fd_func)(int fd, unsigned events, void *userdata); + fd_func func; + void *arg; +}; -/* Allocate and initialize a new fdevent object - * Note: use FD_TIMER as 'fd' to create a fd-less object - * (used to implement timers). -*/ -fdevent *fdevent_create(int fd, fd_func func, void *arg); +int fdevent_wakeup_send; +int fdevent_wakeup_recv; -/* Uninitialize and deallocate an fdevent object that was -** created by fdevent_create() -*/ -void fdevent_destroy(fdevent *fde); +FD_EVENT fdevent_wakeup_fde; /* Initialize an fdevent object that was externally allocated */ -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); +void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg); /* Uninitialize an fdevent object that was initialized by ** fdevent_install() */ -void fdevent_remove(fdevent *item); +void fdevent_remove(FD_EVENT *item); -/* Change which events should cause notifications -*/ -void fdevent_set(fdevent *fde, unsigned events); -void fdevent_add(fdevent *fde, unsigned events); -void fdevent_del(fdevent *fde, unsigned events); +#define EVENT_MAP_SIZE 256 -void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); +extern MAP event_map; -/* loop forever, handling events. +FD_EVENT* fdevent_map_get(int key); +void fdevent_map_put(int key, FD_EVENT* value); +void fdevent_map_remove(int key); + +/* Change which events should cause notifications */ -void fdevent_loop(); -struct fdevent -{ - fdevent *next; - fdevent *prev; +#define FDEVENT_SET(fde, events) \ + fdevent_backend->fdevent_update(fde, events) - int fd; - int force_eof; +#define FDEVENT_ADD(fde, _events) \ + fdevent_backend->fdevent_update(fde, (fde)->events | _events) - unsigned short state; - unsigned short events; +#define FDEVENT_DEL(fde, _events) \ + fdevent_backend->fdevent_update(fde, (fde)->events & ~_events) - fd_func func; - void *arg; +#define FDEVENT_LOOP() \ + fdevent_backend->fdevent_loop() + +struct fdevent_os_backend { + void (*fdevent_loop)(void); + void (*fdevent_disconnect)(FD_EVENT *fde); + void (*fdevent_update)(FD_EVENT *fde, unsigned events); }; +extern const struct fdevent_os_backend* fdevent_backend; +#ifndef OS_WINDOWS +extern int max_select; +extern const struct fdevent_os_backend fdevent_unix_backend; +#else +extern const struct fdevent_os_backend fdevent_windows_backend; +#endif + +#if defined(OS_WINDOWS) +#include + +#define WIN32_MAX_FHS 128 +extern MAP sdb_handle_map; +extern HANDLE socket_event_handle[]; +extern int event_location_to_fd[]; +extern int current_socket_location; +#endif #endif diff --git a/src/fdevent_backend.h b/src/fdevent_backend.h old mode 100644 new mode 100755 index 3213f58..851243b --- a/src/fdevent_backend.h +++ b/src/fdevent_backend.h @@ -17,45 +17,11 @@ #define __FDEVENT_I_H #include "fdevent.h" - -extern fdevent list_pending; -extern fdevent **fd_table; +extern FD_EVENT **fd_table; extern int fd_table_max; -void fdevent_plist_enqueue(fdevent *node); -void fdevent_plist_remove(fdevent *node); -fdevent *fdevent_plist_dequeue(void); -void fdevent_register(fdevent *fde); -void fdevent_unregister(fdevent *fde); - -void _fatal(const char *fn, const char *fmt, ...); -#define FATAL(x...) _fatal(__FUNCTION__, x) - -#if DEBUG -void dump_fde(fdevent *fde, const char *info) -{ - fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, - fde->state & FDE_READ ? 'R' : ' ', - fde->state & FDE_WRITE ? 'W' : ' ', - fde->state & FDE_ERROR ? 'E' : ' ', - info); -} -#else -#define dump_fde(fde, info) do { } while(0) -#endif - -struct fdevent_os_backend { - // human-readable name - const char *name; - void (*fdevent_loop)(void); - void (*fdevent_init)(void); - void (*fdevent_connect)(fdevent *fde); - void (*fdevent_disconnect)(fdevent *fde); - void (*fdevent_update)(fdevent *fde, unsigned events); -}; - -extern const struct fdevent_os_backend* fdevent_backend; -extern const struct fdevent_os_backend fdevent_unix_backend; -extern const struct fdevent_os_backend fdevent_windows_backend; +FD_EVENT *fdevent_plist_dequeue(void); +void fdevent_register(FD_EVENT *fde); +void fdevent_unregister(FD_EVENT *fde); #endif diff --git a/src/fdevent_unix.c b/src/fdevent_unix.c old mode 100644 new mode 100755 index d5b6807..9f44c70 --- a/src/fdevent_unix.c +++ b/src/fdevent_unix.c @@ -30,8 +30,8 @@ #include "fdevent_backend.h" #include "transport.h" #include "utils.h" +#include "log.h" -#define D(...) ((void)0) // This socket is used when a subproc shell service exists. // It wakes up the fdevent_loop() and cause the correct handling // of the shell's pseudo-tty master. I.e. force close it. @@ -39,293 +39,124 @@ int SHELL_EXIT_NOTIFY_FD = -1; #include +#define FD_CLR_ALL(fde) \ + FD_CLR(fde->fd, &fds_read); \ + FD_CLR(fde->fd, &fds_write); -static fd_set read_fds; -static fd_set write_fds; -static fd_set error_fds; +static fd_set fds_write; +static fd_set fds_read; -static int select_n = 0; - -static void _fdevent_init(void) +static void _fdevent_disconnect(FD_EVENT *fde) { - 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; + FD_CLR_ALL(fde); + //selectn should be reset + int fd = fde->fd; + if(fd >= max_select -1) { + int i = fd - 1; + while(i > -1) { + if(fdevent_map_get(i) != NULL) { + max_select = i+1; + break; + } + --i; + } } - select_n = n + 1; } -static void _fdevent_update(fdevent *fde, unsigned events) +static void _fdevent_update(FD_EVENT *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); + if(fde->events == events) { + return; } - 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; + int fd = fde->fd; + events = events & FDE_MASK; + fde->events = events; - } + switch (events ) { + case FDE_READ: + FD_SET(fd, &fds_read); + FD_CLR(fd, &fds_write); + break; + case FDE_WRITE: + FD_SET(fd, &fds_write); + FD_CLR(fd, &fds_read); + break; + case 0: + FD_CLR(fd, &fds_read); + FD_CLR(fd, &fds_write); + break; + default: + FD_SET(fd, &fds_read); + FD_SET(fd, &fds_write); + break; } - return n; } -#if !DEBUG -static inline void dump_all_fds(const char *extra_msg) {} -#else -static void dump_all_fds(const char *extra_msg) +static void _fdevent_loop() { -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; + LIST_NODE* event_list = NULL; - memcpy(&rfd, &read_fds, sizeof(fd_set)); - memcpy(&wfd, &write_fds, sizeof(fd_set)); - memcpy(&efd, &error_fds, sizeof(fd_set)); + while(1) { - dump_all_fds("pre select()"); + fd_set rfd, wfd; - 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); + memcpy(&rfd, &fds_read, sizeof(fd_set)); + memcpy(&wfd, &fds_write, sizeof(fd_set)); - dump_all_fds("post select()"); + LOG_INFO("before select function, max_select %d\n", max_select); + int n = select(max_select, &rfd, &wfd, NULL, NULL); + LOG_INFO("%d events happens\n", n); - if(n < 0) { - switch(saved_errno) { - case EINTR: return -1; - case EBADF: - // Can't trust the FD sets after an error. + if(n < 0) { + LOG_ERROR("fatal error happens in select loop errno %d, strerr %s\n", errno, strerror(errno)); FD_ZERO(&wfd); - FD_ZERO(&efd); FD_ZERO(&rfd); - break; - default: - D("Unexpected select() error=%d\n", saved_errno); - return 0; + continue; } - } - 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); + if(n == 0) { + LOG_ERROR("select returns 0\n"); + continue; } - } - - 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; + int i = 0; + while( i < max_select) { + unsigned events = 0; + + if(FD_ISSET(i, &rfd)) { + events |= FDE_READ; + } + if(FD_ISSET(i, &wfd)) { + events |= FDE_WRITE; + } + + if(events) { + LOG_INFO("FD(%d) got events=%04x\n", i, events); + FD_EVENT* fde = fdevent_map_get(i); + if(fde == NULL) { + LOG_INFO("fdevent FD(%d) may be already closed\n", i); + i++; + continue; + } + + fde->node = prepend(&event_list, fde); + events |= fde->events; + } + i++; } - while((fde = fdevent_plist_dequeue())) { - fdevent_call_fdfunc(fde); + while(event_list != NULL) { + FD_EVENT* fde = event_list->data; + remove_first(&event_list, no_free); + LOG_INFO("FD(%d) start!\n", fde->fd); + fde->func(fde->fd, fde->events, fde->arg); + LOG_INFO("FD(%d) end!\n", fde->fd); } } } const struct fdevent_os_backend fdevent_unix_backend = { - .name = "unix fdevent", - .fdevent_init = _fdevent_init, - .fdevent_connect = _fdevent_connect, .fdevent_disconnect = _fdevent_disconnect, .fdevent_update = _fdevent_update, .fdevent_loop = _fdevent_loop diff --git a/src/fdevent_windows.c b/src/fdevent_windows.c old mode 100644 new mode 100755 index 5f750a4..202a79b --- a/src/fdevent_windows.c +++ b/src/fdevent_windows.c @@ -31,300 +31,167 @@ #include "utils_backend.h" #include "fdevent_backend.h" #include "transport.h" +#include "log.h" -#define D(...) ((void)0) +static void alloc_event(SDB_SOCK_HANDLE* h) { + LOG_INFO("FD(%d), LOCATION(%d)\n", h->handle.fd, current_socket_location); + HANDLE event = WSACreateEvent(); + socket_event_handle[current_socket_location] = event; + event_location_to_fd[current_socket_location] = h->handle.fd; -static EventHook _free_hooks; - -static EventHook -event_hook_alloc( FH fh ) -{ - EventHook hook = _free_hooks; - if (hook != NULL) - _free_hooks = hook->next; - else { - hook = malloc( sizeof(*hook) ); - if (hook == NULL) { - //_fatal( "could not allocate event hook\n" ); - //TODO: - } - } - hook->next = NULL; - hook->fh = fh; - hook->wanted = 0; - hook->ready = 0; - hook->h = INVALID_HANDLE_VALUE; - hook->aux = NULL; - - hook->prepare = NULL; - hook->start = NULL; - hook->stop = NULL; - hook->check = NULL; - hook->peek = NULL; - - return hook; + h->event_location = current_socket_location; + current_socket_location++; } -static void -event_hook_free( EventHook hook ) -{ - hook->fh = NULL; - hook->wanted = 0; - hook->ready = 0; - hook->next = _free_hooks; - _free_hooks = hook; +static void free_event(SDB_SOCK_HANDLE* remove_h) { + + LOG_INFO("FD(%d), LOCATION(%d), CUR_SOCKET(%d)\n", remove_h->handle.fd, remove_h->event_location, current_socket_location); + + current_socket_location--; + int remove_location = remove_h->event_location; + remove_h->event_location = -1; + WSACloseEvent(socket_event_handle[remove_location]); + if(current_socket_location != remove_location) { + SDB_SOCK_HANDLE* replace_h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(event_location_to_fd[current_socket_location]); + replace_h->event_location = remove_location; + socket_event_handle[remove_location] = socket_event_handle[current_socket_location]; + int replace_fd = event_location_to_fd[current_socket_location]; + event_location_to_fd[remove_location] = replace_fd; + } } - -static void -event_hook_signal( EventHook hook ) -{ - FH f = hook->fh; - int fd = _fh_to_int(f); - fdevent* fde = fd_table[ fd - WIN32_FH_BASE ]; - - if (fde != NULL && fde->fd == fd) { - if ((fde->state & FDE_PENDING) == 0) { - fde->state |= FDE_PENDING; - fdevent_plist_enqueue( fde ); - } - fde->events |= hook->wanted; +static int _event_socket_verify(FD_EVENT* fde, WSANETWORKEVENTS* evts) { + if ((fde->events & FDE_READ) && (evts->lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))) { + return 1; } -} - -static EventHook* -event_looper_find_p( EventLooper looper, FH fh ) -{ - EventHook *pnode = &looper->hooks; - EventHook node = *pnode; - for (;;) { - if ( node == NULL || node->fh == fh ) - break; - pnode = &node->next; - node = *pnode; + if ((fde->events & FDE_WRITE) && (evts->lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE))) { + return 1; } - return pnode; + return 0; } -static void -event_looper_hook( EventLooper looper, int fd, int events ) -{ - FH f = _fh_from_int(fd); - EventHook *pnode; - EventHook node; +static int _socket_wanted_to_flags(int wanted) { + int flags = 0; + if (wanted & FDE_READ) + flags |= FD_READ | FD_ACCEPT | FD_CLOSE; - if (f == NULL) /* invalid arg */ { - D("event_looper_hook: invalid fd=%d\n", fd); - return; - } - - pnode = event_looper_find_p( looper, f ); - node = *pnode; - if ( node == NULL ) { - node = event_hook_alloc( f ); - node->next = *pnode; - *pnode = node; - } + if (wanted & FDE_WRITE) + flags |= FD_WRITE | FD_CONNECT | FD_CLOSE; - if ( (node->wanted & events) != events ) { - /* this should update start/stop/check/peek */ - D("event_looper_hook: call hook for %d (new=%x, old=%x)\n", - fd, node->wanted, events); - f->clazz->_fh_hook( f, events & ~node->wanted, node ); - node->wanted |= events; - } else { - D("event_looper_hook: ignoring events %x for %d wanted=%x)\n", - events, fd, node->wanted); - } + return flags; } -static void -event_looper_unhook( EventLooper looper, int fd, int events ) -{ - FH fh = _fh_from_int(fd); - EventHook *pnode = event_looper_find_p( looper, fh ); - EventHook node = *pnode; - - if (node != NULL) { - int events2 = events & node->wanted; - if ( events2 == 0 ) { - D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd ); - return; - } - node->wanted &= ~events2; - if (!node->wanted) { - *pnode = node->next; - event_hook_free( node ); - } +static int _event_socket_start(FD_EVENT* fde) { + /* create an event which we're going to wait for */ + int fd = fde->fd; + long flags = _socket_wanted_to_flags(fde->events); + SDB_SOCK_HANDLE* __h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fd); + LOG_INFO("FD(%d) LOCATION(%d)\n", fd, __h->event_location); + HANDLE event = socket_event_handle[__h->event_location]; + + if (event == INVALID_HANDLE_VALUE) { + LOG_ERROR( "no event for FD(%d)\n", fd); + return 0; } + D( "_event_socket_start: hooking FD(%d) for %x (flags %ld)\n", fd, fde->events, flags); + if (WSAEventSelect(__h->handle.u.socket, event, flags)) { + LOG_ERROR( "_event_socket_start: WSAEventSelect() for FD(%d) failed, error %d\n", fd, WSAGetLastError()); + exit(1); + return 0; + } + return 1; } -static EventLooperRec win32_looper; - -static void _fdevent_init(void) +static void _fdevent_disconnect(FD_EVENT *fde) { - 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 ); + int events = fde->events; + + if (events) { + SDB_SOCK_HANDLE* h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd); + if(h == NULL) { + LOG_ERROR("FDE of FD(%d) has no socket event handle\n", fde->fd); + return; + } + free_event(h); + } } -static void _fdevent_disconnect(fdevent *fde) +static void _fdevent_update(FD_EVENT *fde, unsigned events) { - EventLooper looper = &win32_looper; - int events = fde->state & FDE_EVENTMASK; + unsigned _event = events & FDE_MASK; - 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 ); - } + if(fde->events == events) { + return; } + fde->events = events; + + if(_event == 0) { + free_event((SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd)); + return; + } + SDB_SOCK_HANDLE* h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd); + if(h == NULL) { + LOG_ERROR("invalid FD(%d)\n", fde->fd); + return; + } + + if(h->event_location == -1) { + alloc_event(h); + } + _event_socket_start(fde); } -static void fdevent_process() +void _fdevent_loop() { - EventLooper looper = &win32_looper; - EventHook hook; - int gotone = 0; - - /* if we have at least one ready hook, execute it/them */ - for (hook = looper->hooks; hook; hook = hook->next) { - hook->ready = 0; - if (hook->prepare) { - hook->prepare(hook); - if (hook->ready != 0) { - event_hook_signal( hook ); - gotone = 1; - } - } - } - - /* nothing's ready yet, so wait for something to happen */ - if (!gotone) + do { - looper->htab_count = 0; - - for (hook = looper->hooks; hook; hook = hook->next) - { - if (hook->start && !hook->start(hook)) { - D( "fdevent_process: error when starting a hook\n" ); - return; - } - if (hook->h != INVALID_HANDLE_VALUE) { - int nn; - - for (nn = 0; nn < looper->htab_count; nn++) - { - if ( looper->htab[nn] == hook->h ) - goto DontAdd; - } - looper->htab[ looper->htab_count++ ] = hook->h; - DontAdd: - ; - } + if (current_socket_location == 0) { + D( "fdevent_process: nothing to wait for !!\n" ); + continue; + } + LOG_INFO( "sdb_win32: fdevevnt loop for %d events start\n", current_socket_location ); + if (current_socket_location > MAXIMUM_WAIT_OBJECTS) { + LOG_ERROR("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", current_socket_location); + abort(); } + int wait_ret = WaitForMultipleObjects( current_socket_location, socket_event_handle, FALSE, INFINITE ); - if (looper->htab_count == 0) { - D( "fdevent_process: nothing to wait for !!\n" ); - return; + if(wait_ret == (int)WAIT_FAILED) { + LOG_ERROR( "sdb_win32: wait failed, error %ld\n", GetLastError() ); + continue; } + else { - do - { - int wait_ret; - - 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); + int _fd = event_location_to_fd[wait_ret]; + LOG_INFO("wait success. FD(%d), LOCATION(%d)\n", _fd, wait_ret); + SDB_HANDLE* _h = sdb_handle_map_get(_fd); + WSANETWORKEVENTS evts; - for (hook = looper->hooks; hook; hook = hook->next) { - if (hook->stop) - hook->stop( hook ); - } - } + HANDLE event = socket_event_handle[wait_ret]; + if(!WSAEnumNetworkEvents(_h->u.socket, event, &evts)) { + FD_EVENT* fde = fdevent_map_get(_fd); + if(_event_socket_verify(fde, &evts)) { - 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); + if (fde != NULL && fde->fd == _fd) { + LOG_INFO("FD(%d) start\n", fde->fd); + fde->func(fde->fd, fde->events, fde->arg); + LOG_INFO("FD(%d) end\n", fde->fd); + } + } + else { + LOG_INFO("verify failed\n"); + } + + + } } } + while (1); } const struct fdevent_os_backend fdevent_windows_backend = { - .name = "windows fdevent", - .fdevent_init = _fdevent_init, - .fdevent_connect = _fdevent_connect, .fdevent_disconnect = _fdevent_disconnect, .fdevent_update = _fdevent_update, .fdevent_loop = _fdevent_loop diff --git a/src/file_sync_client.c b/src/file_sync_client.c index ffc8f11..d37ed7f 100644 --- a/src/file_sync_client.c +++ b/src/file_sync_client.c @@ -34,11 +34,11 @@ #include "utils.h" #include "strutils.h" #include "fdevent.h" -#include "sdb.h" +#include "log.h" static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC* dstF); -__inline__ void create_copy_info(COPY_INFO** info, char* srcp, char* dstp) { +void create_copy_info(COPY_INFO** info, char* srcp, char* dstp) { *info = (COPY_INFO*)malloc(sizeof(COPY_INFO)); (*info)->src = srcp; (*info)->dst = dstp; @@ -49,36 +49,35 @@ static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC dstF->finalize(dstfd); } -static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes) { +static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes, struct stat* src_stat, char* copy_flag) { D("file is copied from 'fd:%d' '%s' to 'fd:%d' '%s'\n", src_fd, srcp, dst_fd, dstp); - void* srcstat; - if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) { - return -1; - } - src_fd = srcF->readopen(src_fd, srcp, srcstat); + //unsigned file_byte = src_stat->st_size; + unsigned written_byte = 0; + + src_fd = srcF->readopen(src_fd, srcp, src_stat); if(src_fd < 0) { return -1; } - dst_fd = dstF->writeopen(dst_fd, dstp, srcstat); + dst_fd = dstF->writeopen(dst_fd, dstp, src_stat); if(dst_fd < 0) { return -1; } FILE_BUFFER srcbuf; - srcbuf.id = ID_DATA; + srcbuf.id = sync_data; while(1) { - int ret = srcF->readfile(src_fd, srcp, srcstat, &srcbuf); + int ret = srcF->readfile(src_fd, srcp, src_stat, &srcbuf); if(ret == 0) { break; } else if(ret == 1) { - ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes); + ret = dstF->writefile(dst_fd, dstp, &srcbuf, &written_byte); if(ret < 0) { srcF->readclose(src_fd); - dstF->writeclose(dst_fd, dstp, srcstat); + dstF->writeclose(dst_fd, dstp, src_stat); return -1; } } @@ -86,27 +85,31 @@ static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* continue; } else if(ret == 3) { - ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes); + ret = dstF->writefile(dst_fd, dstp, &srcbuf, &written_byte); if(ret < 0) { srcF->readclose(src_fd); - dstF->writeclose(dst_fd, dstp, srcstat); + dstF->writeclose(dst_fd, dstp, src_stat); return -1; } break; } else { srcF->readclose(src_fd); - dstF->writeclose(dst_fd, dstp, srcstat); + dstF->writeclose(dst_fd, dstp, src_stat); if(ret == 4) { return 0; } return -1; } + //TODO pull / push progress bar + //fprintf(stderr,"%s [%u / %u]: %s -> %s \r", copy_flag, written_byte, file_byte, srcp, dstp); } - if(srcF->readclose(src_fd) < 0 || dstF->writeclose(dst_fd, dstp, srcstat) < 0) { + if(srcF->readclose(src_fd) < 0 || dstF->writeclose(dst_fd, dstp, src_stat) < 0) { return -1; } - free(srcstat); + + fprintf(stderr,"%s: %s -> %s \n", copy_flag, srcp, dstp); + *total_bytes = *total_bytes + written_byte; return 1; } @@ -115,16 +118,27 @@ static void free_copyinfo(void* data) { if(info != NULL) { if(info->src != NULL) { free(info->src); + info->src = NULL; } if(info->dst != NULL) { free(info->dst); + info->dst = NULL; } free(info); + info = NULL; } } int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int is_utf8, void** ext_argv) { + char copy_flag[7]; + if(srcF->local) { + snprintf(copy_flag, sizeof(copy_flag), "%s", "pushed"); + } + else { + snprintf(copy_flag, sizeof(copy_flag), "%s", "pulled"); + } + D("copy %s to the %s\n", srcp, dstp); unsigned total_bytes = 0; long long start_time = NOW(); @@ -132,8 +146,6 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i int src_fd = 0; int dst_fd = 0; - void* srcstat = NULL; - void* dststat = NULL; int pushed = 0; int skiped = 0; src_fd = srcF->initialize(srcp, ext_argv); @@ -141,15 +153,19 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i if(src_fd < 0 || dst_fd < 0) { return 1; } - if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) { + + struct stat src_stat; + struct stat dst_stat; + + if(srcF->_stat(src_fd, srcp, &src_stat, 1) < 0) { finalize(src_fd, dst_fd, srcF, dstF); return 1; } - int src_dir = srcF->is_dir(srcp, srcstat, 1); + int src_dir = srcF->is_dir(srcp, &src_stat, 1); int dst_dir = 0; - if(dstF->_stat(dst_fd, dstp, &dststat, 0) >= 0) { - dst_dir = dstF->is_dir(dstp, dststat, 0); + if(dstF->_stat(dst_fd, dstp, &dst_stat, 0) >= 0) { + dst_dir = dstF->is_dir(dstp, &dst_stat, 0); } else { int dst_len = strlen(dstp); @@ -157,9 +173,9 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i dst_dir = 1; } } - free(dststat); - free(srcstat); + if(src_dir == -1 || dst_dir == -1) { + LOG_ERROR("src_dir: %d, dst_dir %d\n", src_dir, dst_dir); finalize(src_fd, dst_fd, srcF, dstF); return 1; } @@ -167,9 +183,9 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i /* if we're copying a local file to a remote directory, ** we *really* want to copy to remotedir + "/" + localfilename */ + char full_dstpath[PATH_MAX]; if(dst_dir == 1) { char* src_filename = get_filename(srcp); - char full_dstpath[PATH_MAX]; append_file(full_dstpath, dstp, src_filename); if(is_utf8 != 0) { @@ -179,12 +195,13 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i dstp = full_dstpath; } } - int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes); + int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes, &src_stat, copy_flag); if(result == 1) { pushed++; } else { + fprintf(stderr,"skipped: %s -> %s\n", srcp, dstp); skiped++; } } @@ -221,13 +238,12 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i char* src_p = (char*)info->src; char* dst_p = (char*)info->dst; - if(srcF->_stat(src_fd, src_p, &srcstat, 1) < 0) { + if(srcF->_stat(src_fd, src_p, &src_stat, 1) < 0) { finalize(src_fd, dst_fd, srcF, dstF); return 1; } - src_dir = srcF->is_dir(src_p, srcstat, 1); - free(srcstat); + src_dir = srcF->is_dir(src_p, &src_stat, 1); if(src_dir < 0) { finalize(src_fd, dst_fd, srcF, dstF); return 1; @@ -237,13 +253,13 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i } else { if(src_dir == 0) { - fprintf(stderr,"push: %s -> %s\n", src_p, dst_p); - int result = file_copy(src_fd, dst_fd, src_p, dst_p, srcF, dstF, &total_bytes); + int result = file_copy(src_fd, dst_fd, src_p, dst_p, srcF, dstF, &total_bytes, &src_stat, copy_flag); if(result == 1) { pushed++; } else { + fprintf(stderr,"skipped: %s -> %s\n", src_p, dst_p); skiped++; } } @@ -261,14 +277,8 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i } } - if(srcF == &REMOTE_FILE_FUNC) { - fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n", - pushed, "pulled", skiped); - } - else { - fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n", - pushed, "pushed", skiped); - } + fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n", + pushed, copy_flag, skiped); long long end_time = NOW() - start_time; diff --git a/src/file_sync_client.h b/src/file_sync_client.h index 7bb53bb..8381a1c 100644 --- a/src/file_sync_client.h +++ b/src/file_sync_client.h @@ -29,7 +29,7 @@ #include "file_sync_functions.h" -__inline__ void create_copy_info(COPY_INFO** info, char* srcp, char* dstp); +void create_copy_info(COPY_INFO** info, char* srcp, char* dstp); int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int is_utf8, void** ext_argv); #endif /* FILE_SYNC_CLIENT_H_ */ diff --git a/src/file_sync_functions.c b/src/file_sync_functions.c index baceb3b..ad833b3 100644 --- a/src/file_sync_functions.c +++ b/src/file_sync_functions.c @@ -34,12 +34,25 @@ #include "linkedlist.h" #include "strutils.h" #include "file_sync_client.h" +#include "log.h" + +const unsigned sync_stat = MKSYNC('S','T','A','T'); +const unsigned sync_list = MKSYNC('L','I','S','T'); +const unsigned sync_send = MKSYNC('S','E','N','D'); +const unsigned sync_recv = MKSYNC('R','E','C','V'); +const unsigned sync_dent = MKSYNC('D','E','N','T'); +const unsigned sync_done = MKSYNC('D','O','N','E'); +const unsigned sync_data = MKSYNC('D','A','T','A'); +const unsigned sync_okay = MKSYNC('O','K','A','Y'); +const unsigned sync_fail = MKSYNC('F','A','I','L'); +const unsigned sync_quit = MKSYNC('Q','U','I','T'); const FILE_FUNC LOCAL_FILE_FUNC = { + 1, initialize_local, finalize_local, _stat_local, - is_directory_local, + is_directory_common, readopen_local, readclose_local, writeopen_local, @@ -50,10 +63,11 @@ const FILE_FUNC LOCAL_FILE_FUNC = { }; const FILE_FUNC REMOTE_FILE_FUNC = { + 0, initialize_remote, finalize_remote, _stat_remote, - is_directory_remote, + is_directory_common, readopen_remote, readclose_remote, writeopen_remote, @@ -63,18 +77,18 @@ const FILE_FUNC REMOTE_FILE_FUNC = { getdirlist_remote, }; -static int sync_readmode(int fd, const char *path, unsigned *mode); +static int sync_readstat(int fd, const char *path, struct stat* st); //return > 0 fd, = 0 success, < 0 fail. int initialize_local(char* path, void** extargv) { - D("initialize local file '%s'", path); + D("initialize local file '%s'\n", path); return 0; } //return fd int initialize_remote(char* path, void** extargv) { - D("initialize remote file '%s'", path); + D("initialize remote file '%s'\n", path); int fd = sdb_connect("sync:", extargv); if(fd < 0) { @@ -86,14 +100,14 @@ int initialize_remote(char* path, void** extargv) { } void finalize_local(int fd) { - D("finalize local fd '%d'", fd); + D("finalize local fd '%d'\n", fd); } void finalize_remote(int fd) { - D("finalize remote fd '%d'", fd); - syncmsg msg; + D("finalize remote fd '%d'\n", fd); + SYNC_MSG msg; - msg.req.id = ID_QUIT; + msg.req.id = sync_quit; msg.req.namelen = 0; writex(fd, &msg.req, sizeof(msg.req)); @@ -103,40 +117,36 @@ void finalize_remote(int fd) { } } -//TODO stat should be freed. -int _stat_local(int fd, char* path, void** _stat, int show_error) { - D("stat local file 'fd:%d' '%s'", fd, path); - struct stat* st = (struct stat*)malloc(sizeof(struct stat)); +int _stat_local(int fd, char* path, struct stat* st, int show_error) { + + D("stat local file 'fd:%d' '%s'\n", fd, path); if(stat(path, st)) { if(show_error) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); } + st->st_mode = 0; return -1; } - *_stat = st; return 1; } -int _stat_remote(int fd, char* path, void** stat, int show_error) { +int _stat_remote(int fd, char* path, struct stat* st, int show_error) { - D("stat remote file 'fd:%d' '%s'", fd, path); - unsigned* mode = (unsigned*)malloc(sizeof(unsigned)); - if(sync_readmode(fd, path, mode)) { + D("stat remote file 'fd:%d' '%s'\n", fd, path); + if(sync_readstat(fd, path, st)) { if(show_error) { fprintf(stderr,"cannot read mode '%s': %s\n", path, strerror(errno)); } + st->st_mode = 0; return -1; } - *stat = mode; return 1; } -int is_directory_local(char* path, void* stat, int show_error) { - struct stat* st = (struct stat*)stat; - - if(st == NULL) { +int is_directory_common(char* path, struct stat* st, int show_error) { + if(st->st_mode == 0) { if(show_error) { fprintf(stderr,"'%s': No such file or directory\n", path); } @@ -153,29 +163,10 @@ int is_directory_local(char* path, void* stat, int show_error) { return 2; } -int is_directory_remote(char* path, void* stat, int show_error) { - int* mode = (int*)stat; - - if(mode == NULL) { - if(show_error) { - fprintf(stderr,"'%s': No such file or directory\n", path); - } - return -1; - } - if(S_ISREG(*mode) || S_ISLNK(*mode)) { - return 0; - } - if(S_ISDIR(*mode)) { - return 1; - } - return 2; -} - //return fd. -int readopen_local(int fd, char* srcp, void* srcstat) { +int readopen_local(int fd, char* srcp, struct stat* st) { - D("read open local file 'fd:%d' '%s'", fd, srcp); - struct stat* st = srcstat; + D("read open local file 'fd:%d' '%s'\n", fd, srcp); if(S_ISREG(st->st_mode)) { fd = sdb_open(srcp, O_RDONLY); @@ -190,9 +181,9 @@ int readopen_local(int fd, char* srcp, void* srcstat) { return fd; } -int readopen_remote(int fd, char* srcp, void* srcstat) { - D("read open remote file 'fd:%d' '%s'", fd, srcp); - syncmsg msg; +int readopen_remote(int fd, char* srcp, struct stat* st) { + D("read open remote file 'fd:%d' '%s'\n", fd, srcp); + SYNC_MSG msg; int len; len = strlen(srcp); @@ -201,7 +192,7 @@ int readopen_remote(int fd, char* srcp, void* srcstat) { return -1; } - msg.req.id = ID_RECV; + msg.req.id = sync_recv; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, srcp, len)) { @@ -212,7 +203,7 @@ int readopen_remote(int fd, char* srcp, void* srcstat) { } int readclose_local(int lfd) { - D("read close local file 'fd:%d'", lfd); + D("read close local file 'fd:%d'\n", lfd); if(lfd > 0) { sdb_close(lfd); } @@ -220,13 +211,13 @@ int readclose_local(int lfd) { } int readclose_remote(int fd) { - D("read close remote file 'fd:%d'", fd); + D("read close remote file 'fd:%d'\n", fd); return fd; } -int writeopen_local(int fd, char* dstp, void* stat) { - D("write open local file 'fd:%d' '%s'", fd, dstp); - sdb_unlink(dstp); +int writeopen_local(int fd, char* dstp, struct stat* st) { + D("write open local file 'fd:%d' '%s'\n", fd, dstp); + unix_unlink(dstp); mkdirs(dstp); fd = sdb_creat(dstp, 0644); @@ -239,10 +230,9 @@ int writeopen_local(int fd, char* dstp, void* stat) { } //return fd. -int writeopen_remote(int fd, char* dstp, void* stat) { - D("write open remote file 'fd:%d' '%s'", fd, dstp); - syncmsg msg; - struct stat* st = (struct stat*)stat; +int writeopen_remote(int fd, char* dstp, struct stat* st) { + D("write open remote file 'fd:%d' '%s'\n", fd, dstp); + SYNC_MSG msg; int len, r; int total_len; @@ -258,7 +248,7 @@ int writeopen_remote(int fd, char* dstp, void* stat) { return -1; } - msg.req.id = ID_SEND; + msg.req.id = sync_send; msg.req.namelen = htoll(total_len); if(writex(fd, &msg.req, sizeof(msg.req)) || @@ -271,19 +261,18 @@ int writeopen_remote(int fd, char* dstp, void* stat) { return fd; } -int writeclose_local(int fd, char*dstp, void* stat) { - D("write close local file 'fd:%d' '%s'", fd, dstp); +int writeclose_local(int fd, char*dstp, struct stat* st) { + D("write close local file 'fd:%d' '%s'\n", fd, dstp); if(fd > 0) { sdb_close(fd); } return fd; } -int writeclose_remote(int fd, char* dstp, void* stat) { - D("write close remote file 'fd:%d' '%s'", fd, dstp); - struct stat* st = (struct stat*)stat; - syncmsg msg; - msg.data.id = ID_DONE; +int writeclose_remote(int fd, char* dstp, struct stat* st) { + D("write close remote file 'fd:%d' '%s'\n", fd, dstp); + SYNC_MSG msg; + msg.data.id = sync_done; msg.data.size = htoll(st->st_mtime); if(writex(fd, &msg.data, sizeof(msg.data))) { @@ -296,11 +285,11 @@ int writeclose_remote(int fd, char* dstp, void* stat) { return -1; } - if(msg.status.id != ID_OKAY) { + if(msg.status.id != sync_okay) { char buf[256]; - if(msg.status.id == ID_FAIL) { + if(msg.status.id == sync_fail) { int len = ltohl(msg.status.msglen); - if(len > 256) { + if(len > 255) { len = 255; } if(readx(fd, buf, len)) { @@ -325,9 +314,8 @@ int writeclose_remote(int fd, char* dstp, void* stat) { //-1:fail //1: write and continue load //3: write and stop -int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) { - D("read local file 'fd:%d' '%s'", lfd, srcpath); - struct stat* st = (struct stat*)stat; +int readfile_local(int lfd, char* srcpath, struct stat* st, FILE_BUFFER* sbuf) { + D("read local file 'fd:%d' '%s'\n", lfd, srcpath); if (S_ISREG(st->st_mode)) { int ret; @@ -375,9 +363,9 @@ int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) { return -1; } -int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) { - D("read remote file 'fd:%d' '%s'", fd, srcpath); - syncmsg msg; +int readfile_remote(int fd, char* srcpath, struct stat* st, FILE_BUFFER* buffer) { + D("read remote file 'fd:%d' '%s'\n", fd, srcpath); + SYNC_MSG msg; unsigned id; if(readx(fd, &(msg.data), sizeof(msg.data))) { @@ -387,14 +375,14 @@ int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) { id = msg.data.id; buffer->size = ltohl(msg.data.size); - if(id == ID_DONE) { + if(id == sync_done) { //Finish normally. return 0; } //fail - if(id != ID_DATA) { - int len; - if(id == ID_FAIL) { + if(id != sync_data) { + int len = 0; + if(id == sync_fail) { int len = buffer->size; if(len > 256) { len = 255; @@ -430,7 +418,7 @@ int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) { } int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) { - D("write local file 'fd:%d' '%s'", fd, dstp); + D("write local file 'fd:%d' '%s'\n", fd, dstp); char* data = sbuf->data; unsigned len = sbuf->size; @@ -444,7 +432,7 @@ int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes } int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) { - D("write remote file 'fd:%d' '%s'", fd, dstp); + D("write remote file 'fd:%d' '%s'\n", fd, dstp); int size = ltohl(sbuf->size); if(writex(fd, sbuf, sizeof(unsigned)*2 + size)) { @@ -457,7 +445,7 @@ int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_byte } int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) { - D("get list of local file 'fd:%d' '%s'", fd, src_dir); + D("get list of local file 'fd:%d' '%s'\n", fd, src_dir); DIR* d; d = opendir(src_dir); @@ -488,7 +476,7 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) COPY_INFO* info; create_copy_info(&info, src_full_path, dst_full_path); - append(dirlist, info); + prepend(dirlist, info); } closedir(d); @@ -496,8 +484,8 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) } int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) { - D("get list of remote file 'fd:%d' '%s'", fd, src_dir); - syncmsg msg; + D("get list of remote file 'fd:%d' '%s'\n", fd, src_dir); + SYNC_MSG msg; int len; len = strlen(src_dir); @@ -507,36 +495,36 @@ int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) return -1; } - msg.req.id = ID_LIST; + msg.req.id = sync_list; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, src_dir, len)) { - fprintf(stderr,"cannot request directory entry: '%s'", src_dir); + fprintf(stderr,"cannot request directory entry: '%s'\n", src_dir); return -1; } while(1) { if(readx(fd, &msg.dent, sizeof(msg.dent))) { - fprintf(stderr,"cannot read dirlist: '%s'", src_dir); + fprintf(stderr,"cannot read dirlist: '%s'\n", src_dir); return -1; } - if(msg.dent.id == ID_DONE) { + if(msg.dent.id == sync_done) { return fd; } - if(msg.dent.id != ID_DENT) { - fprintf(stderr,"received dent msg '%d' is not DENT", msg.dent.id); + if(msg.dent.id != sync_dent) { + fprintf(stderr,"received dent msg '%d' is not DENT\n", msg.dent.id); return -1; } len = ltohl(msg.dent.namelen); if(len > 256) { - fprintf(stderr,"some file in the remote '%s' exceeds 256", src_dir); + fprintf(stderr,"some file in the remote '%s' exceeds 256\n", src_dir); return -1; } char file_name[257]; if(readx(fd, file_name, len)) { - fprintf(stderr,"cannot read file in the remote directory '%s'", src_dir); + fprintf(stderr,"cannot read file in the remote directory '%s'\n", src_dir); return -1; } file_name[len] = 0; @@ -558,27 +546,39 @@ int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) COPY_INFO* info; create_copy_info(&info, src_full_path, dst_full_path); - append(dirlist, info); + prepend(dirlist, info); + D("!!!!!!!!!!!!!!!!!!!\n"); } + D("getting list of remote file 'fd:%d' '%s' is done\n", fd, src_dir); return fd; } -static int sync_readmode(int fd, const char *path, unsigned *mode) { - syncmsg msg; +static int sync_readstat(int fd, const char *path, struct stat* st) { + SYNC_MSG msg; int len = strlen(path); - msg.req.id = ID_STAT; + msg.req.id = sync_stat; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { + LOG_ERROR("fail to send request ID_STAT with name length %d\n", len); return -1; } + if(readx(fd, &msg.stat, sizeof(msg.stat))) { + LOG_ERROR("fail to read response of ID_STAT with name length %d\n", len); return -1; } - if(msg.stat.id != ID_STAT) { + if(msg.stat.id != sync_stat) { + return -1; + } + st->st_mode = ltohl(msg.stat.mode); + + if(!st->st_mode) { + LOG_ERROR("fail to stat remote file: '%s'", path); return -1; } - *mode = ltohl(msg.stat.mode); + st->st_size = ltohl(msg.stat.size); + D("remote stat: mode %u, size %u\n", st->st_mode, st->st_size); return 0; } diff --git a/src/file_sync_functions.h b/src/file_sync_functions.h index ddba671..6897c90 100644 --- a/src/file_sync_functions.h +++ b/src/file_sync_functions.h @@ -29,6 +29,7 @@ #define TRACE_TAG TRACE_SDB +#include #include "file_sync_service.h" #include "linkedlist.h" @@ -51,26 +52,25 @@ int initialize_remote(char* path, void** extargv); void finalize_local(int fd); void finalize_remote(int fd); -int _stat_local(int fd, char* path, void** _stat, int show_error); -int _stat_remote(int fd, char* path, void** stat, int show_error); +int _stat_local(int fd, char* path, struct stat* st, int show_error); +int _stat_remote(int fd, char* path, struct stat* st, int show_error); -int is_directory_local(char* path, void* stat, int show_error); -int is_directory_remote(char* path, void* stat, int show_error); +int is_directory_common(char* path, struct stat* st, int show_error); -int readopen_local(int fd, char* srcp, void* srcstat); -int readopen_remote(int fd, char* srcp, void* srcstat); +int readopen_local(int fd, char* srcp, struct stat* st); +int readopen_remote(int fd, char* srcp, struct stat* st); int readclose_local(int lfd); int readclose_remote(int fd); -int writeopen_local(int fd, char* dstp, void* stat); -int writeopen_remote(int fd, char* dstp, void* stat); +int writeopen_local(int fd, char* dstp, struct stat* st); +int writeopen_remote(int fd, char* dstp, struct stat* st); -int writeclose_local(int fd, char*dstp, void* stat); -int writeclose_remote(int fd, char* dstp, void* stat); +int writeclose_local(int fd, char*dstp, struct stat* st); +int writeclose_remote(int fd, char* dstp, struct stat* st); -int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf); -int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer); +int readfile_local(int lfd, char* srcpath, struct stat* st, FILE_BUFFER* sbuf); +int readfile_remote(int fd, char* srcpath, struct stat* st, FILE_BUFFER* buffer); int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes); int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes); @@ -79,21 +79,22 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist); int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist); struct file_function { + int local; int(*initialize)(char* path, void** extargv); void(*finalize)(int fd); - int(*_stat)(int fd, char* path, void** stat, int show_error); - int(*is_dir)(char* path, void* stat, int show_error); - int(*readopen)(int fd, char* dstp, void* stat); + int(*_stat)(int fd, char* path, struct stat* st, int show_error); + int(*is_dir)(char* path, struct stat* st, int show_error); + int(*readopen)(int fd, char* dstp, struct stat* st); int(*readclose)(int fd); - int(*writeopen)(int fd, char* dstp, void* stat); - int(*writeclose)(int fd, char* dstp, void* stat); - int(*readfile)(int fd, char* path, void* stat, FILE_BUFFER* buf); + int(*writeopen)(int fd, char* dstp, struct stat* st); + int(*writeclose)(int fd, char* dstp, struct stat* st); + int(*readfile)(int fd, char* path, struct stat* st, FILE_BUFFER* buf); int(*writefile)(int fd, char* path, FILE_BUFFER* buf, unsigned* total_bytes); int(*get_dirlist)(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist); }; typedef struct file_function FILE_FUNC; -const FILE_FUNC LOCAL_FILE_FUNC; -const FILE_FUNC REMOTE_FILE_FUNC; +extern const FILE_FUNC LOCAL_FILE_FUNC; +extern const FILE_FUNC REMOTE_FILE_FUNC; #endif /* FILE_SYNC_FUNCTIONS_H_ */ diff --git a/src/file_sync_service.h b/src/file_sync_service.h old mode 100644 new mode 100755 index 6f01979..50de665 --- a/src/file_sync_service.h +++ b/src/file_sync_service.h @@ -17,70 +17,64 @@ #ifndef _FILE_SYNC_SERVICE_H_ #define _FILE_SYNC_SERVICE_H_ -#ifdef HAVE_BIG_ENDIAN -static inline unsigned __swap_uint32(unsigned x) -{ - return (((x) & 0xFF000000) >> 24) - | (((x) & 0x00FF0000) >> 8) - | (((x) & 0x0000FF00) << 8) - | (((x) & 0x000000FF) << 24); -} -#define htoll(x) __swap_uint32(x) -#define ltohl(x) __swap_uint32(x) -#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)) -#else #define htoll(x) (x) #define ltohl(x) (x) -#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#endif +#define MKSYNC(a,b,c,d) ( (d << 24) | (c << 16) | (b << 8) | a ) + +extern const unsigned sync_stat; +extern const unsigned sync_list; +extern const unsigned sync_send; +extern const unsigned sync_recv; +extern const unsigned sync_dent; +extern const unsigned sync_done; +extern const unsigned sync_data; +extern const unsigned sync_okay; +extern const unsigned sync_fail; +extern const unsigned sync_quit; + +typedef struct req REQ; +struct req { + unsigned id; + unsigned namelen; +}; -#define ID_STAT MKID('S','T','A','T') -#define ID_LIST MKID('L','I','S','T') -#define ID_ULNK MKID('U','L','N','K') -#define ID_SEND MKID('S','E','N','D') -#define ID_RECV MKID('R','E','C','V') -#define ID_DENT MKID('D','E','N','T') -#define ID_DONE MKID('D','O','N','E') -#define ID_DATA MKID('D','A','T','A') -#define ID_OKAY MKID('O','K','A','Y') -#define ID_FAIL MKID('F','A','I','L') -#define ID_QUIT MKID('Q','U','I','T') +typedef struct sdb_stat SDB_STAT; +struct sdb_stat { + unsigned id; + unsigned mode; + unsigned size; + unsigned time; +}; + +typedef struct dent DENT; +struct dent { + unsigned id; + unsigned mode; + unsigned size; + unsigned time; + unsigned namelen; +}; -typedef union { +typedef struct data DATA; +struct data { unsigned id; - struct { - unsigned id; - unsigned namelen; - } req; - struct { - unsigned id; - unsigned mode; - unsigned size; - unsigned time; - } stat; - struct { - unsigned id; - unsigned mode; - unsigned size; - unsigned time; - unsigned namelen; - } dent; - struct { - unsigned id; - unsigned size; - } data; - struct { - unsigned id; - unsigned msglen; - } status; -} syncmsg; + unsigned size; +}; +typedef struct status STATUS; +struct status { + unsigned id; + unsigned msglen; +}; -void file_sync_service(int fd, void *cookie); -int do_sync_ls(const char *path); -int do_sync_push(const char *lpath, const char *rpath, int isUtf8); -int do_sync_sync(const char *lpath, const char *rpath, int listonly); -int do_sync_pull(const char *rpath, const char *lpath); +typedef union syncmsg SYNC_MSG; +union syncmsg { + REQ req; + SDB_STAT stat; + DENT dent; + DATA data; + STATUS status; +}; #define SYNC_DATA_MAX (64*1024) #define SYNC_CHAR_MAX 1024 diff --git a/src/libusb/darwin.c b/src/libusb/darwin.c deleted file mode 100644 index c330eb0..0000000 --- a/src/libusb/darwin.c +++ /dev/null @@ -1,1329 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Darwin/MacOS X Support - * - * (c) 2002-2007 Nathan Hjelm - * - * (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 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 -#include -#include - -/* standard includes for darwin/os10 (IOKit) */ -#include -#include -#include -#include - -#include "usbi.h" - -/* some defines */ -/* IOUSBInterfaceInferface */ -#if defined (kIOUSBInterfaceInterfaceID220) - -// #warning "libusb being compiled for 10.4 or later" -#define usb_interface_t IOUSBInterfaceInterface220 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 -#define InterfaceVersion 220 - -#elif defined (kIOUSBInterfaceInterfaceID197) - -// #warning "libusb being compiled for 10.3 or later" -#define usb_interface_t IOUSBInterfaceInterface197 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 -#define InterfaceVersion 197 - -#elif defined (kIOUSBInterfaceInterfaceID190) - -// #warning "libusb being compiled for 10.2 or later" -#define usb_interface_t IOUSBInterfaceInterface190 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 -#define InterfaceVersion 190 - -#elif defined (kIOUSBInterfaceInterfaceID182) - -// #warning "libusb being compiled for 10.1 or later" -#define usb_interface_t IOUSBInterfaceInterface182 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 -#define InterfaceVersion 182 - -#else - -/* No timeout functions available! Time to upgrade your os. */ -#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up" -#define usb_interface_t IOUSBInterfaceInterface -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID -#define LIBUSB_NO_TIMEOUT_INTERFACE -#define InterfaceVersion 180 - -#endif - -/* IOUSBDeviceInterface */ -#if defined (kIOUSBDeviceInterfaceID197) - -#define usb_device_t IOUSBDeviceInterface197 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 -#define DeviceVersion 197 - -#elif defined (kIOUSBDeviceInterfaceID187) - -#define usb_device_t IOUSBDeviceInterface187 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 -#define DeviceVersion 187 - -#elif defined (kIOUSBDeviceInterfaceID182) - -#define usb_device_t IOUSBDeviceInterface182 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 -#define DeviceVersion 182 - -#else - -#define usb_device_t IOUSBDeviceInterface -#define DeviceInterfaceID kIOUSBDeviceInterfaceID -#define LIBUSB_NO_TIMEOUT_DEVICE -#define LIBUSB_NO_SEIZE_DEVICE -#define DeviceVersion 180 - -#endif - -typedef IOReturn io_return_t; -typedef IOCFPlugInInterface *io_cf_plugin_ref_t; -typedef SInt32 s_int32_t; -typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size, - IOAsyncCallback1 callback, void *refcon); -typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size, - UInt32 noDataTimeout, UInt32 completionTimeout, - IOAsyncCallback1 callback, void *refcon); - -#if !defined(IO_OBJECT_NULL) -#define IO_OBJECT_NULL ((io_object_t)0) -#endif - -struct darwin_dev_handle { - usb_device_t **device; - usb_interface_t **interface; - int open; - - /* stored translation table for pipes to endpoints */ - int num_endpoints; - unsigned char *endpoint_addrs; -}; - -static IONotificationPortRef gNotifyPort; -static mach_port_t masterPort = MACH_PORT_NULL; - -static void darwin_cleanup (void) -{ - IONotificationPortDestroy(gNotifyPort); - mach_port_deallocate(mach_task_self(), masterPort); -} - -static char *darwin_error_str (int result) { - switch (result) { - case kIOReturnSuccess: - return "no error"; - case kIOReturnNotOpen: - return "device not opened for exclusive access"; - case kIOReturnNoDevice: - return "no connection to an IOService"; - case kIOUSBNoAsyncPortErr: - return "no async port has been opened for interface"; - case kIOReturnExclusiveAccess: - return "another process has device opened for exclusive access"; - case kIOUSBPipeStalled: - return "pipe is stalled"; - case kIOReturnError: - return "could not establish a connection to the Darwin kernel"; - case kIOUSBTransactionTimeout: - return "transaction timed out"; - case kIOReturnBadArgument: - return "invalid argument"; - case kIOReturnAborted: - return "transaction aborted"; - case kIOReturnNotResponding: - return "device not responding"; - default: - return "unknown error"; - } -} - -/* not a valid errorno outside darwin.c */ -#define LUSBDARWINSTALL (ELAST+1) - -static int darwin_to_errno (int result) { - switch (result) { - case kIOReturnSuccess: - return 0; - case kIOReturnNotOpen: - return EBADF; - case kIOReturnNoDevice: - case kIOUSBNoAsyncPortErr: - return ENXIO; - case kIOReturnExclusiveAccess: - return EBUSY; - case kIOUSBPipeStalled: - return LUSBDARWINSTALL; - case kIOReturnBadArgument: - return EINVAL; - case kIOUSBTransactionTimeout: - return ETIMEDOUT; - case kIOReturnNotResponding: - return EIO; - case kIOReturnError: - default: - return 1; - } -} - -static int usb_setup_iterator (io_iterator_t *deviceIterator) -{ - int result; - CFMutableDictionaryRef matchingDict; - - /* set up the matching dictionary for class IOUSBDevice and its subclasses. - It will be consumed by the IOServiceGetMatchingServices call */ - if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) { - darwin_cleanup (); - - USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n"); - } - - result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator); - matchingDict = NULL; - - if (result != kIOReturnSuccess) - USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n", - darwin_error_str(result)); - - return 0; -} - -static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) -{ - io_cf_plugin_ref_t *plugInInterface = NULL; - usb_device_t **device; - io_service_t usbDevice; - long result, score; - - if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator))) - return NULL; - - result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, - &score); - - result = IOObjectRelease(usbDevice); - if (result || !plugInInterface) - return NULL; - - (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), - (LPVOID)&device); - - (*plugInInterface)->Stop(plugInInterface); - IODestroyPlugInInterface (plugInInterface); - plugInInterface = NULL; - - (*(device))->GetLocationID(device, locationp); - - return device; -} - -int usb_os_open(usb_dev_handle *dev) -{ - struct darwin_dev_handle *device; - - io_return_t result; - io_iterator_t deviceIterator; - - usb_device_t **darwin_device; - - UInt32 location = *((UInt32 *)dev->device->dev); - UInt32 dlocation; - - if (!dev) - USB_ERROR(-ENXIO); - - if (masterPort == MACH_PORT_NULL) - USB_ERROR(-EINVAL); - - device = calloc(1, sizeof(struct darwin_dev_handle)); - if (!device) - USB_ERROR(-ENOMEM); - - if (usb_debug > 3) - fprintf(stderr, "usb_os_open: %04x:%04x\n", - dev->device->descriptor.idVendor, - dev->device->descriptor.idProduct); - - if ((result = usb_setup_iterator (&deviceIterator)) < 0) - return result; - - /* This port of libusb uses locations to keep track of devices. */ - while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) { - if (dlocation == location) - break; - - (*darwin_device)->Release(darwin_device); - } - - IOObjectRelease(deviceIterator); - device->device = darwin_device; - - if (device->device == NULL) - USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!"); - -#if !defined (LIBUSB_NO_SEIZE_DEVICE) - result = (*(device->device))->USBDeviceOpenSeize (device->device); -#else - /* No Seize in OS X 10.0 (Darwin 1.4) */ - result = (*(device->device))->USBDeviceOpen (device->device); -#endif - - if (result != kIOReturnSuccess) { - switch (result) { - case kIOReturnExclusiveAccess: - if (usb_debug > 0) - fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result)); - break; - default: - (*(device->device))->Release (device->device); - USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s", - darwin_error_str(result)); - } - - device->open = 0; - } else - device->open = 1; - - dev->impl_info = device; - dev->interface = -1; - dev->altsetting = -1; - - device->num_endpoints = 0; - device->endpoint_addrs = NULL; - - return 0; -} - -int usb_os_close(usb_dev_handle *dev) -{ - struct darwin_dev_handle *device; - io_return_t result; - - if (!dev) - USB_ERROR(-ENXIO); - - if ((device = dev->impl_info) == NULL) - USB_ERROR(-ENOENT); - - usb_release_interface(dev, dev->interface); - - if (usb_debug > 3) - fprintf(stderr, "usb_os_close: %04x:%04x\n", - dev->device->descriptor.idVendor, - dev->device->descriptor.idProduct); - - if (device->open == 1) - result = (*(device->device))->USBDeviceClose(device->device); - else - result = kIOReturnSuccess; - - /* device may not need to be released, but if it has to... */ - (*(device->device))->Release(device->device); - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result)); - - free (device); - - return 0; -} - -static int get_endpoints (struct darwin_dev_handle *device) -{ - io_return_t ret; - - u_int8_t numep, direction, number; - u_int8_t dont_care1, dont_care3; - u_int16_t dont_care2; - - int i; - - if (device == NULL || device->interface == NULL) - return -EINVAL; - - if (usb_debug > 1) - fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n"); - - /* retrieve the total number of endpoints on this interface */ - ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep); - if ( ret ) { - if ( usb_debug > 1 ) - fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface ); - - USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" ); - } - - free (device->endpoint_addrs); - device->endpoint_addrs = calloc (sizeof (unsigned char), numep); - - /* iterate through pipe references */ - for (i = 1 ; i <= numep ; i++) { - ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number, - &dont_care1, &dont_care2, &dont_care3); - - if (ret != kIOReturnSuccess) { - fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n", - i ); - USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret)); - } - - if (usb_debug > 1) - fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number); - - device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) | - (number & USB_ENDPOINT_ADDRESS_MASK)); - } - - device->num_endpoints = numep; - - if (usb_debug > 1) - fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n"); - - return 0; -} - -static int claim_interface (usb_dev_handle *dev, int interface) -{ - io_iterator_t interface_iterator; - io_service_t usbInterface = IO_OBJECT_NULL; - io_return_t result; - io_cf_plugin_ref_t *plugInInterface = NULL; - - IOUSBFindInterfaceRequest request; - - struct darwin_dev_handle *device; - long score; - int current_interface; - - device = dev->impl_info; - - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator); - if (result != kIOReturnSuccess) - USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s", - darwin_error_str(result)); - - for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) { - usbInterface = IOIteratorNext(interface_iterator); - if ( usb_debug > 3 ) - fprintf ( stderr, "Interface %d of device is 0x%08x\n", - current_interface, usbInterface ); - } - - current_interface--; - - /* the interface iterator is no longer needed, release it */ - IOObjectRelease(interface_iterator); - - if (!usbInterface) { - u_int8_t nConfig; /* Index of configuration to use */ - IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */ - /* Only a composite class device with no vendor-specific driver will - be configured. Otherwise, we need to do it ourselves, or there - will be no interfaces for the device. */ - - if ( usb_debug > 3 ) - fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" ); - - result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig ); - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s", - darwin_error_str(result)); - - if (nConfig < 1) - USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations"); - else if ( nConfig > 1 && usb_debug > 0 ) - fprintf ( stderr, "claim_interface: device has more than one" - " configuration, using the first (warning)\n" ); - - if ( usb_debug > 3 ) - fprintf ( stderr, "claim_interface: device has %d configuration%s\n", - (int)nConfig, (nConfig>1?"s":"") ); - - /* Always use the first configuration */ - result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc ); - if (result != kIOReturnSuccess) { - if (device->open == 1) { - (*(device->device))->USBDeviceClose ( (device->device) ); - (*(device->device))->Release ( (device->device) ); - } - - USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s", - darwin_error_str(result)); - } else if ( usb_debug > 3 ) - fprintf ( stderr, "claim_interface: configuration value is %d\n", - configDesc->bConfigurationValue ); - - if (device->open == 1) { - result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue ); - - if (result != kIOReturnSuccess) { - (*(device->device))->USBDeviceClose ( (device->device) ); - (*(device->device))->Release ( (device->device) ); - - USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s", - darwin_error_str(result)); - } - - dev->config = configDesc->bConfigurationValue; - } - - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - /* Now go back and get the chosen interface */ - result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator); - if (result != kIOReturnSuccess) - USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s", - darwin_error_str(result)); - - for (current_interface = 0 ; current_interface <= interface ; current_interface++) { - usbInterface = IOIteratorNext(interface_iterator); - - if ( usb_debug > 3 ) - fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n", - current_interface, usbInterface ); - } - current_interface--; - - /* the interface iterator is no longer needed, release it */ - IOObjectRelease(interface_iterator); - - if (!usbInterface) - USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL"); - } - - result = IOCreatePlugInInterfaceForService(usbInterface, - kIOUSBInterfaceUserClientTypeID, - kIOCFPlugInInterfaceID, - &plugInInterface, &score); - /* No longer need the usbInterface object after getting the plug-in */ - result = IOObjectRelease(usbInterface); - if (result || !plugInInterface) - USB_ERROR(-ENOENT); - - /* Now create the device interface for the interface */ - result = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(InterfaceInterfaceID), - (LPVOID) &device->interface); - - /* No longer need the intermediate plug-in */ - (*plugInInterface)->Stop(plugInInterface); - IODestroyPlugInInterface (plugInInterface); - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s", - darwin_error_str(result)); - - if (!device->interface) - USB_ERROR(-EACCES); - - if ( usb_debug > 3 ) - fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n", - current_interface, device->interface); - - /* claim the interface */ - result = (*(device->interface))->USBInterfaceOpen(device->interface); - if (result) - USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s", - darwin_error_str(result)); - - result = get_endpoints (device); - - if (result) { - /* this should not happen */ - usb_release_interface (dev, interface); - USB_ERROR_STR ( result, "claim_interface: could not build endpoint table"); - } - - return 0; -} - -int usb_set_configuration (usb_dev_handle *dev, int configuration) -{ - struct darwin_dev_handle *device; - io_return_t result; - int interface; - - if ( usb_debug > 3 ) - fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration ); - - if (!dev) - USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" ); - - if ((device = dev->impl_info) == NULL) - USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" ); - - /* Setting configuration will invalidate the interface, so we need - to reclaim it. First, dispose of existing interface, if any. */ - interface = dev->interface; - - if ( device->interface ) - usb_release_interface(dev, dev->interface); - - result = (*(device->device))->SetConfiguration(device->device, configuration); - - if (result) - USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s", - darwin_error_str(result)); - - /* Reclaim interface */ - if (interface != -1) - result = usb_claim_interface (dev, interface); - - dev->config = configuration; - - return result; -} - -int usb_claim_interface(usb_dev_handle *dev, int interface) -{ - struct darwin_dev_handle *device = dev->impl_info; - - io_return_t result; - - if ( usb_debug > 3 ) - fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface ); - - if (!device) - USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" ); - - if (!(device->device)) - USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" ); - - /* If we have already claimed an interface, release it */ - if ( device->interface ) - usb_release_interface(dev, dev->interface); - - result = claim_interface ( dev, interface ); - if ( result ) - USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" ); - - dev->interface = interface; - - /* interface is claimed and async IO is set up: return 0 */ - return 0; -} - -int usb_release_interface(usb_dev_handle *dev, int interface) -{ - struct darwin_dev_handle *device; - io_return_t result; - - if (!dev) - USB_ERROR(-ENXIO); - - if ((device = dev->impl_info) == NULL) - USB_ERROR(-ENOENT); - - /* interface is not open */ - if (!device->interface) - return 0; - - result = (*(device->interface))->USBInterfaceClose(device->interface); - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s", - darwin_error_str(result)); - - result = (*(device->interface))->Release(device->interface); - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s", - darwin_error_str(result)); - - device->interface = NULL; - - free (device->endpoint_addrs); - - device->num_endpoints = 0; - device->endpoint_addrs = NULL; - - dev->interface = -1; - dev->altsetting = -1; - - return 0; -} - -int usb_set_altinterface(usb_dev_handle *dev, int alternate) -{ - struct darwin_dev_handle *device; - io_return_t result; - - if (!dev) - USB_ERROR(-ENXIO); - - if ((device = dev->impl_info) == NULL) - USB_ERROR(-ENOENT); - - /* interface is not open */ - if (!device->interface) - USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed"); - - result = (*(device->interface))->SetAlternateInterface(device->interface, alternate); - - if (result) - USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface"); - - dev->altsetting = alternate; - - result = get_endpoints (device); - if (result) { - /* this should not happen */ - USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table"); - } - - return 0; -} - -/* simple function that figures out what pipeRef is associated with an endpoint */ -static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep) -{ - int i; - - if (usb_debug > 1) - fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n"); - - for (i = 0 ; i < device->num_endpoints ; i++) - if (device->endpoint_addrs[i] == ep) - return i + 1; - - /* No pipe found with the correct endpoint address */ - if (usb_debug > 1) - fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep); - - return -1; -} - -static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read) -{ - struct darwin_dev_handle *device; - - io_return_t result = -1; - - int pipeRef; - - u_int8_t transferType, direction, number, interval; - u_int16_t maxPacketSize; - - if (!dev) - USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" ); - - if ((device = dev->impl_info) == NULL) - USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" ); - - /* interface is not open */ - if (!device->interface) - USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened"); - - - /* Set up transfer */ - if ((pipeRef = ep_to_pipeRef(device, ep)) < 0) - USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" ); - - (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - /* Transfer set up complete */ - - if (usb_debug > 0) - fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep); - - /* Do bulk transfer */ - if (transferType == kUSBInterrupt && usb_debug > 3) - fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); - -#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE) - if ( transferType != kUSBInterrupt) { - if (usb_bt_read != 0) - result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout); - else - result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout); - - /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */ - if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled) - usb_clear_halt (dev, ep); - } else -#endif - { - if (usb_bt_read != 0) - result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size); - else - result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size); - } - - if (result != kIOReturnSuccess) - USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result)); - - return size; -} - -#if 0 -/* NOT USED */ -/* argument to handle multiple parameters to rw_completed */ -struct rw_complete_arg { - UInt32 io_size; - IOReturn result; - CFRunLoopRef cf_loop; -}; - -static void rw_completed(void *refcon, io_return_t result, void *io_size) -{ - struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon; - - if (usb_debug > 2) - fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result), - (UInt32)io_size, result); - - rw_arg->io_size = (UInt32)io_size; - rw_arg->result = result; - - CFRunLoopStop(rw_arg->cf_loop); -} - -static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout, - rw_async_func_t rw_async, rw_async_to_func_t rw_async_to) -{ - struct darwin_dev_handle *device; - - io_return_t result = -1; - - CFRunLoopSourceRef cfSource; - int pipeRef; - - struct rw_complete_arg rw_arg; - - u_int8_t transferType; - - /* None of the values below are used in libusb for bulk transfers */ - u_int8_t direction, number, interval; - u_int16_t maxPacketSize; - - if (!dev) - USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" ); - - if ((device = dev->impl_info) == NULL) - USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" ); - - /* interface is not open */ - if (!device->interface) - USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened"); - - - /* Set up transfer */ - if ((pipeRef = ep_to_pipeRef(device, ep)) < 0) - USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" ); - - (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - - bzero((void *)&rw_arg, sizeof(struct rw_complete_arg)); - rw_arg.cf_loop = CFRunLoopGetCurrent(); - CFRetain (rw_arg.cf_loop); - - (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource); - CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); - /* Transfer set up complete */ - - if (usb_debug > 0) - fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", - size, ep); - - /* Bulk transfer */ - if (transferType == kUSBInterrupt && usb_debug > 3) - fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); - - if ( transferType != kUSBInterrupt && rw_async_to != NULL) - - result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout, - (IOAsyncCallback1)rw_completed, (void *)&rw_arg); - else - result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed, - (void *)&rw_arg); - - if (result == kIOReturnSuccess) { - /* wait for write to complete */ - if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) { - (*(device->interface))->AbortPipe(device->interface, pipeRef); - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */ - if (usb_debug) - fprintf(stderr, "usb_bulk_transfer: timed out\n"); - } - } - - CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); - CFRelease (rw_arg.cf_loop); - - /* Check the return code of both the write and completion functions. */ - if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess && - rw_arg.result != kIOReturnAborted) ) { - int error_code; - char *error_str; - - if (result == kIOReturnSuccess) { - error_code = darwin_to_errno (rw_arg.result); - error_str = darwin_error_str (rw_arg.result); - } else { - error_code = darwin_to_errno(result); - error_str = darwin_error_str (result); - } - - if (transferType != kUSBInterrupt && rw_async_to != NULL) - USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str); - else - USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str); - } - - return rw_arg.io_size; -} -#endif - -int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) -{ - int result; - - if (dev == NULL || dev->impl_info == NULL) - return -EINVAL; - - if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0) - USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)"); - - return result; -} - -int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) -{ - int result; - - if (dev == NULL || dev->impl_info == NULL) - return -EINVAL; - - ep |= 0x80; - - if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0) - USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)"); - - return result; -} - -/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */ -int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - return usb_bulk_write (dev, ep, bytes, size, timeout); -} - -int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - return usb_bulk_read (dev, ep, bytes, size, timeout); -} - -int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, - int value, int index, char *bytes, int size, int timeout) -{ - struct darwin_dev_handle *device = dev->impl_info; - - io_return_t result; - -#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) - IOUSBDevRequestTO urequest; -#else - IOUSBDevRequest urequest; -#endif - - if (usb_debug >= 3) - fprintf(stderr, "libusb/darwin.c usb_control_msg (device: %s): %d %d %d %d %p %d %d\n", - dev->device->filename, requesttype, request, value, index, bytes, size, timeout); - - bzero(&urequest, sizeof(urequest)); - - urequest.bmRequestType = requesttype; - urequest.bRequest = request; - urequest.wValue = value; - urequest.wIndex = index; - urequest.wLength = size; - urequest.pData = bytes; -#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) - urequest.completionTimeout = timeout; - urequest.noDataTimeout = timeout; - - result = (*(device->device))->DeviceRequestTO(device->device, &urequest); -#else - result = (*(device->device))->DeviceRequest(device->device, &urequest); -#endif - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "libusb/darwin.c usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result)); - - /* Bytes transfered is stored in the wLenDone field*/ - return urequest.wLenDone; -} - -int usb_os_find_busses(struct usb_bus **busses) -{ - struct usb_bus *fbus = NULL; - - io_iterator_t deviceIterator; - io_return_t result; - - usb_device_t **device; - - UInt32 location; - - char buf[20]; - int i = 1; - - /* Create a master port for communication with IOKit (this should - have been created if the user called usb_init() )*/ - if (masterPort == MACH_PORT_NULL) { - usb_init (); - - if (masterPort == MACH_PORT_NULL) - USB_ERROR(-ENOENT); - } - - if ((result = usb_setup_iterator (&deviceIterator)) < 0) - return result; - - while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { - struct usb_bus *bus; - - if (location & 0x00ffffff) - continue; - - bus = calloc(1, sizeof(struct usb_bus)); - if (bus == NULL) - USB_ERROR(-ENOMEM); - - sprintf(buf, "%03i", i++); - bus->location = location; - - strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1); - bus->dirname[sizeof(bus->dirname) - 1] = 0; - - LIST_ADD(fbus, bus); - - if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname); - - (*(device))->Release(device); - } - - IOObjectRelease(deviceIterator); - - *busses = fbus; - - return 0; -} - -int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) -{ - struct usb_device *fdev = NULL; - - io_iterator_t deviceIterator; - io_return_t result; - - usb_device_t **device; - - u_int16_t address; - UInt32 location; - UInt32 bus_loc = bus->location; - int devnum; - - /* for use in retrieving device description */ - IOUSBDevRequest req; - - /* a master port should have been created by usb_os_init */ - if (masterPort == MACH_PORT_NULL) - USB_ERROR(-ENOENT); - - if ((result = usb_setup_iterator (&deviceIterator)) < 0) - return result; - - /* Set up request for device descriptor */ - req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); - req.bRequest = kUSBRqGetDescriptor; - req.wValue = kUSBDeviceDesc << 8; - req.wIndex = 0; - req.wLength = sizeof(IOUSBDeviceDescriptor); - - devnum = 0; - - while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { - unsigned char device_desc[DEVICE_DESC_LENGTH]; - UInt8 bDeviceClass, bDeviceSubClass; - UInt16 idVendor, idProduct; - - result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address); - - if (result == kIOReturnSuccess) { - (*(device))->GetDeviceClass (device, &bDeviceClass); - (*(device))->GetDeviceSubClass (device, &bDeviceSubClass); - (*(device))->GetDeviceProduct (device, &idProduct); - (*(device))->GetDeviceVendor (device, &idVendor); - - if ((location >> 24) == (bus_loc >> 24)) { - struct usb_device *dev; - - if (usb_debug >= 2) - fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found USB device on bus 0x%08lx: 0x%08lx\n", - bus_loc, location); - - dev = calloc(1, sizeof(struct usb_device)); - if (dev == NULL) - USB_ERROR(-ENOMEM); - - dev->bus = bus; - - /* retrieve device descriptor */ - req.pData = device_desc; - result = (*(device))->DeviceRequest(device, &req); - - if (result != kIOReturnSuccess) { - free (dev); - - if (usb_debug) - fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device descriptor: %s. Skipping device.\n", - darwin_error_str(result)); - - /* release the device now */ - (*(device))->Release(device); - continue; /* can't continue without a descriptor */ - } - - usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor); - - /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices */ - if (dev->descriptor.idProduct != idProduct) { - free (dev); - - if (usb_debug) - fprintf (stderr, "libusb/darwin.c usb_os_find_devices: idProduct from iokit does not match idProduct in descriptor. Skipping device\n"); - - /* release the device now */ - (*(device))->Release(device); - continue; /* can't continue without a descriptor */ - } - - dev->devnum = devnum++; - - sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass); - - dev->dev = (USBDeviceAddress *) calloc (1, 4); - if (dev->dev == NULL) - USB_ERROR(-ENOMEM); - - memcpy(dev->dev, &location, 4); - - LIST_ADD(fdev, dev); - - if (usb_debug >= 2) - fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found %s on %s at location 0x%08lx\n", - dev->filename, bus->dirname, location); - } - } else if (usb_debug) - fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device address: %s\n", - darwin_error_str(result)); - - /* release the device now */ - (*(device))->Release(device); - } - - IOObjectRelease(deviceIterator); - - *devices = fdev; - - if (usb_debug) - fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Complete\n"); - - return 0; -} - -int usb_os_determine_children(struct usb_bus *bus) -{ - /* Nothing yet */ - return 0; -} - -void usb_os_init(void) -{ - if (masterPort == MACH_PORT_NULL) { - IOMasterPort(masterPort, &masterPort); - - gNotifyPort = IONotificationPortCreate(masterPort); - } -} - -void usb_os_cleanup (void) -{ - if (masterPort != MACH_PORT_NULL) - darwin_cleanup (); -} - -int usb_resetep(usb_dev_handle *dev, unsigned int ep) -{ - struct darwin_dev_handle *device; - - io_return_t result = -1; - - int pipeRef; - - if (!dev) - USB_ERROR(-ENXIO); - - if ((device = dev->impl_info) == NULL) - USB_ERROR(-ENOENT); - - /* interface is not open */ - if (!device->interface) - USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed"); - - if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) - USB_ERROR(-EINVAL); - - result = (*(device->interface))->ResetPipe(device->interface, pipeRef); - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result)); - - return 0; -} - -int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) -{ - struct darwin_dev_handle *device; - - io_return_t result = -1; - - int pipeRef; - - if (!dev) - USB_ERROR(-ENXIO); - - if ((device = dev->impl_info) == NULL) - USB_ERROR(-ENOENT); - - /* interface is not open */ - if (!device->interface) - USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed"); - - if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) - USB_ERROR(-EINVAL); - -#if (InterfaceVersion < 190) - result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef); -#else - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef); -#endif - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result)); - - return 0; -} - -int usb_reset(usb_dev_handle *dev) -{ - struct darwin_dev_handle *device; - - io_return_t result; - - if (!dev) - USB_ERROR(-ENXIO); - - if ((device = dev->impl_info) == NULL) - USB_ERROR(-ENOENT); - - if (!device->device) - USB_ERROR_STR(-ENOENT, "usb_reset: no such device"); - - result = (*(device->device))->ResetDevice(device->device); - - if (result != kIOReturnSuccess) - USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result)); - - return 0; -} diff --git a/src/libusb/descriptors.c b/src/libusb/descriptors.c deleted file mode 100644 index f7fc784..0000000 --- a/src/libusb/descriptors.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Parses descriptors - * - * Copyright (c) 2001 Johannes Erdfelt - * - * This library is covered by the LGPL, read LICENSE for details. - */ - -#include -#include -#include -#include "usbi.h" - -int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, - unsigned char type, unsigned char index, void *buf, int size) -{ - memset(buf, 0, size); - - return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, - (type << 8) + index, 0, buf, size, 1000); -} - -int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, - unsigned char index, void *buf, int size) -{ - memset(buf, 0, size); - - return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, - (type << 8) + index, 0, buf, size, 1000); -} - -int usb_parse_descriptor(unsigned char *source, char *description, void *dest) -{ - unsigned char *sp = source, *dp = dest; - uint16_t w; - uint32_t d; - char *cp; - - for (cp = description; *cp; cp++) { - switch (*cp) { - case 'b': /* 8-bit byte */ - *dp++ = *sp++; - break; - case 'w': /* 16-bit word, convert from little endian to CPU */ - w = (sp[1] << 8) | sp[0]; sp += 2; - dp += ((unsigned long)dp & 1); /* Align to word boundary */ - *((uint16_t *)dp) = w; dp += 2; - break; - case 'd': /* 32-bit dword, convert from little endian to CPU */ - d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4; - dp += ((unsigned long)dp & 2); /* Align to dword boundary */ - *((uint32_t *)dp) = d; dp += 4; - break; - /* These two characters are undocumented and just a hack for Linux */ - case 'W': /* 16-bit word, keep CPU endianess */ - dp += ((unsigned long)dp & 1); /* Align to word boundary */ - memcpy(dp, sp, 2); sp += 2; dp += 2; - break; - case 'D': /* 32-bit dword, keep CPU endianess */ - dp += ((unsigned long)dp & 2); /* Align to dword boundary */ - memcpy(dp, sp, 4); sp += 4; dp += 4; - break; - } - } - - return sp - source; -} - -/* - * This code looks surprisingly similar to the code I wrote for the Linux - * kernel. It's not a coincidence :) - */ - -static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) -{ - struct usb_descriptor_header header; - unsigned char *begin; - int parsed = 0, len, numskipped; - - usb_parse_descriptor(buffer, "bb", &header); - - /* Everything should be fine being passed into here, but we sanity */ - /* check JIC */ - if (header.bLength > size) { - if (usb_debug >= 1) - fprintf(stderr, "ran out of descriptors parsing\n"); - return -1; - } - - if (header.bDescriptorType != USB_DT_ENDPOINT) { - if (usb_debug >= 2) - fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n", - header.bDescriptorType, USB_DT_ENDPOINT); - return parsed; - } - - if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) - usb_parse_descriptor(buffer, "bbbbwbbb", endpoint); - else if (header.bLength >= ENDPOINT_DESC_LENGTH) - usb_parse_descriptor(buffer, "bbbbwb", endpoint); - - buffer += header.bLength; - size -= header.bLength; - parsed += header.bLength; - - /* Skip over the rest of the Class Specific or Vendor Specific */ - /* descriptors */ - begin = buffer; - numskipped = 0; - while (size >= DESC_HEADER_LENGTH) { - usb_parse_descriptor(buffer, "bb", &header); - - if (header.bLength < 2) { - if (usb_debug >= 1) - fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header.bDescriptorType == USB_DT_ENDPOINT) || - (header.bDescriptorType == USB_DT_INTERFACE) || - (header.bDescriptorType == USB_DT_CONFIG) || - (header.bDescriptorType == USB_DT_DEVICE)) - break; - - if (usb_debug >= 1) - fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); - numskipped++; - - buffer += header.bLength; - size -= header.bLength; - parsed += header.bLength; - } - - if (numskipped && usb_debug >= 2) - fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); - - /* Copy any unknown descriptors into a storage area for drivers */ - /* to later parse */ - len = (int)(buffer - begin); - if (!len) { - endpoint->extra = NULL; - endpoint->extralen = 0; - return parsed; - } - - endpoint->extra = malloc(len); - if (!endpoint->extra) { - if (usb_debug >= 1) - fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n"); - endpoint->extralen = 0; - return parsed; - } - - memcpy(endpoint->extra, begin, len); - endpoint->extralen = len; - - return parsed; -} - -static int usb_parse_interface(struct usb_interface *interface, - unsigned char *buffer, int size) -{ - int i, len, numskipped, retval, parsed = 0; - struct usb_descriptor_header header; - struct usb_interface_descriptor *ifp; - unsigned char *begin; - - interface->num_altsetting = 0; - - while (size >= INTERFACE_DESC_LENGTH) { - interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1)); - if (!interface->altsetting) { - if (usb_debug >= 1) - fprintf(stderr, "couldn't malloc interface->altsetting\n"); - return -1; - } - - ifp = interface->altsetting + interface->num_altsetting; - interface->num_altsetting++; - - usb_parse_descriptor(buffer, "bbbbbbbbb", ifp); - - /* Skip over the interface */ - buffer += ifp->bLength; - parsed += ifp->bLength; - size -= ifp->bLength; - - begin = buffer; - numskipped = 0; - - /* Skip over any interface, class or vendor descriptors */ - while (size >= DESC_HEADER_LENGTH) { - usb_parse_descriptor(buffer, "bb", &header); - - if (header.bLength < 2) { - if (usb_debug >= 1) - fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header.bDescriptorType == USB_DT_INTERFACE) || - (header.bDescriptorType == USB_DT_ENDPOINT) || - (header.bDescriptorType == USB_DT_CONFIG) || - (header.bDescriptorType == USB_DT_DEVICE)) - break; - - numskipped++; - - buffer += header.bLength; - parsed += header.bLength; - size -= header.bLength; - } - - if (numskipped && usb_debug >= 2) - fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped); - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (!len) { - ifp->extra = NULL; - ifp->extralen = 0; - } else { - ifp->extra = malloc(len); - if (!ifp->extra) { - if (usb_debug >= 1) - fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n"); - ifp->extralen = 0; - return -1; - } - memcpy(ifp->extra, begin, len); - ifp->extralen = len; - } - - /* Did we hit an unexpected descriptor? */ - usb_parse_descriptor(buffer, "bb", &header); - if ((size >= DESC_HEADER_LENGTH) && - ((header.bDescriptorType == USB_DT_CONFIG) || - (header.bDescriptorType == USB_DT_DEVICE))) - return parsed; - - if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { - if (usb_debug >= 1) - fprintf(stderr, "too many endpoints\n"); - return -1; - } - - if (ifp->bNumEndpoints > 0) { - ifp->endpoint = (struct usb_endpoint_descriptor *) - malloc(ifp->bNumEndpoints * - sizeof(struct usb_endpoint_descriptor)); - if (!ifp->endpoint) { - if (usb_debug >= 1) - fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n"); - return -1; - } - - memset(ifp->endpoint, 0, ifp->bNumEndpoints * - sizeof(struct usb_endpoint_descriptor)); - - for (i = 0; i < ifp->bNumEndpoints; i++) { - usb_parse_descriptor(buffer, "bb", &header); - - if (header.bLength > size) { - if (usb_debug >= 1) - fprintf(stderr, "ran out of descriptors parsing\n"); - return -1; - } - - retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); - if (retval < 0) - return retval; - - buffer += retval; - parsed += retval; - size -= retval; - } - } else - ifp->endpoint = NULL; - - /* We check to see if it's an alternate to this one */ - ifp = (struct usb_interface_descriptor *)buffer; - if (size < USB_DT_INTERFACE_SIZE || - ifp->bDescriptorType != USB_DT_INTERFACE || - !ifp->bAlternateSetting) - return parsed; - } - - return parsed; -} - -int usb_parse_configuration(struct usb_config_descriptor *config, - unsigned char *buffer) -{ - int i, retval, size; - struct usb_descriptor_header header; - - usb_parse_descriptor(buffer, "bbwbbbbb", config); - size = config->wTotalLength; - - if (config->bNumInterfaces > USB_MAXINTERFACES) { - if (usb_debug >= 1) - fprintf(stderr, "too many interfaces\n"); - return -1; - } - - config->interface = (struct usb_interface *) - malloc(config->bNumInterfaces * - sizeof(struct usb_interface)); - if (!config->interface) { - if (usb_debug >= 1) - fprintf(stderr, "out of memory\n"); - return -1; - } - - memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface)); - - buffer += config->bLength; - size -= config->bLength; - - config->extra = NULL; - config->extralen = 0; - - for (i = 0; i < config->bNumInterfaces; i++) { - int numskipped, len; - unsigned char *begin; - - /* Skip over the rest of the Class Specific or Vendor */ - /* Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= DESC_HEADER_LENGTH) { - usb_parse_descriptor(buffer, "bb", &header); - - if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { - if (usb_debug >= 1) - fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header.bDescriptorType == USB_DT_ENDPOINT) || - (header.bDescriptorType == USB_DT_INTERFACE) || - (header.bDescriptorType == USB_DT_CONFIG) || - (header.bDescriptorType == USB_DT_DEVICE)) - break; - - if (usb_debug >= 2) - fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); - numskipped++; - - buffer += header.bLength; - size -= header.bLength; - } - - if (numskipped && usb_debug >= 2) - fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - /* FIXME: We should realloc and append here */ - if (!config->extralen) { - config->extra = malloc(len); - if (!config->extra) { - if (usb_debug >= 1) - fprintf(stderr, "couldn't allocate memory for config extra descriptors\n"); - config->extralen = 0; - return -1; - } - - memcpy(config->extra, begin, len); - config->extralen = len; - } - } - - retval = usb_parse_interface(config->interface + i, buffer, size); - if (retval < 0) - return retval; - - buffer += retval; - size -= retval; - } - - return size; -} - -void usb_destroy_configuration(struct usb_device *dev) -{ - int c, i, j, k; - - if (!dev->config) - return; - - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { - struct usb_config_descriptor *cf = &dev->config[c]; - - if (!cf->interface) - continue; - - for (i = 0; i < cf->bNumInterfaces; i++) { - struct usb_interface *ifp = &cf->interface[i]; - - if (!ifp->altsetting) - continue; - - for (j = 0; j < ifp->num_altsetting; j++) { - struct usb_interface_descriptor *as = &ifp->altsetting[j]; - - if (as->extra) - free(as->extra); - - if (!as->endpoint) - continue; - - for (k = 0; k < as->bNumEndpoints; k++) { - if (as->endpoint[k].extra) - free(as->endpoint[k].extra); - } - free(as->endpoint); - } - - free(ifp->altsetting); - } - - free(cf->interface); - } - - free(dev->config); -} - -void usb_fetch_and_parse_descriptors(usb_dev_handle *udev) -{ - struct usb_device *dev = udev->device; - int i; - - if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { - if (usb_debug >= 1) - fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG); - return; - } - - if (dev->descriptor.bNumConfigurations < 1) { - if (usb_debug >= 1) - fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1); - return; - } - - dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); - if (!dev->config) { - if (usb_debug >= 1) - fprintf(stderr, "Unable to allocate memory for config descriptor\n"); - return; - } - - memset(dev->config, 0, dev->descriptor.bNumConfigurations * - sizeof(struct usb_config_descriptor)); - - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - unsigned char buffer[8], *bigbuffer; - struct usb_config_descriptor config; - int res; - - /* Get the first 8 bytes so we can figure out what the total length is */ - res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8); - if (res < 8) { - if (usb_debug >= 1) { - if (res < 0) - fprintf(stderr, "Unable to get descriptor (%d)\n", res); - else - fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res); - } - - goto err; - } - - usb_parse_descriptor(buffer, "bbw", &config); - - bigbuffer = malloc(config.wTotalLength); - if (!bigbuffer) { - if (usb_debug >= 1) - fprintf(stderr, "Unable to allocate memory for descriptors\n"); - goto err; - } - - res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength); - if (res < config.wTotalLength) { - if (usb_debug >= 1) { - if (res < 0) - fprintf(stderr, "Unable to get descriptor (%d)\n", res); - else - fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res); - } - - free(bigbuffer); - goto err; - } - - res = usb_parse_configuration(&dev->config[i], bigbuffer); - if (usb_debug >= 2) { - if (res > 0) - fprintf(stderr, "Descriptor data still left\n"); - else if (res < 0) - fprintf(stderr, "Unable to parse descriptors\n"); - } - - free(bigbuffer); - } - - return; - -err: - free(dev->config); - - dev->config = NULL; -} - diff --git a/src/libusb/error.c b/src/libusb/error.c deleted file mode 100644 index 9212e86..0000000 --- a/src/libusb/error.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * USB Error messages - * - * Copyright (c) 2000-2001 Johannes Erdfelt - * - * This library is covered by the LGPL, read LICENSE for details. - */ - -#include -#include - -#include "usb.h" -#include "error.h" - -char usb_error_str[1024] = ""; -int usb_error_errno = 0; -usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE; - -char *usb_strerror(void) -{ - switch (usb_error_type) { - case USB_ERROR_TYPE_NONE: - return "No error"; - case USB_ERROR_TYPE_STRING: - return usb_error_str; - case USB_ERROR_TYPE_ERRNO: - if (usb_error_errno > -USB_ERROR_BEGIN) - return strerror(usb_error_errno); - else - /* Any error we don't know falls under here */ - return "Unknown error"; - } - - return "Unknown error"; -} - diff --git a/src/libusb/error.h b/src/libusb/error.h deleted file mode 100644 index c980e22..0000000 --- a/src/libusb/error.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _ERROR_H_ -#define _ERROR_H_ - -typedef enum { - USB_ERROR_TYPE_NONE = 0, - USB_ERROR_TYPE_STRING, - USB_ERROR_TYPE_ERRNO, -} usb_error_type_t; - -extern char usb_error_str[1024]; -extern int usb_error_errno; -extern usb_error_type_t usb_error_type; - -#define USB_ERROR(x) \ - do { \ - usb_error_type = USB_ERROR_TYPE_ERRNO; \ - usb_error_errno = x; \ - return x; \ - } while (0) - -#define USB_ERROR_STR(x, format, args...) \ - do { \ - usb_error_type = USB_ERROR_TYPE_STRING; \ - snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ - if (usb_debug >= 2) \ - fprintf(stderr, "USB error: %s\n", usb_error_str); \ - return x; \ - } while (0) - -#endif /* _ERROR_H_ */ - diff --git a/src/libusb/linux.c b/src/libusb/linux.c deleted file mode 100644 index 6b13afb..0000000 --- a/src/libusb/linux.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Linux USB support - * - * Copyright (c) 2000-2003 Johannes Erdfelt - * - * This library is covered by the LGPL, read LICENSE for details. - */ - -#include /* getenv, etc */ -#include -#include -#include -#include -#include -#include -#include - -#include "linux.h" -#include "usbi.h" - -static char usb_path[PATH_MAX + 1] = ""; - -static int device_open(struct usb_device *dev) -{ - char filename[PATH_MAX + 1]; - int fd; - - snprintf(filename, sizeof(filename) - 1, "%s/%s/%s", - usb_path, dev->bus->dirname, dev->filename); - - fd = open(filename, O_RDWR); - if (fd < 0) { - fd = open(filename, O_RDONLY); - if (fd < 0) - USB_ERROR_STR(-errno, "failed to open %s: %s", - filename, strerror(errno)); - } - - return fd; -} - -int usb_os_open(usb_dev_handle *dev) -{ - dev->fd = device_open(dev->device); - - return 0; -} - -int usb_os_close(usb_dev_handle *dev) -{ - if (dev->fd < 0) - return 0; - - if (close(dev->fd) == -1) - /* Failing trying to close a file really isn't an error, so return 0 */ - USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd, - strerror(errno)); - - return 0; -} - -int usb_set_configuration(usb_dev_handle *dev, int configuration) -{ - int ret; - - ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration); - if (ret < 0) - USB_ERROR_STR(-errno, "could not set config %d: %s", configuration, - strerror(errno)); - - dev->config = configuration; - - return 0; -} - -int usb_claim_interface(usb_dev_handle *dev, int interface) -{ - int ret; - - ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface); - if (ret < 0) { - if (errno == EBUSY && usb_debug > 0) - fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename); - - USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface, - strerror(errno)); - } - - dev->interface = interface; - - return 0; -} - -int usb_release_interface(usb_dev_handle *dev, int interface) -{ - int ret; - - ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface); - if (ret < 0) - USB_ERROR_STR(-errno, "could not release intf %d: %s", interface, - strerror(errno)); - - dev->interface = -1; - - return 0; -} - -int usb_set_altinterface(usb_dev_handle *dev, int alternate) -{ - int ret; - struct usb_setinterface setintf; - - if (dev->interface < 0) - USB_ERROR(-EINVAL); - - setintf.interface = dev->interface; - setintf.altsetting = alternate; - - ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf); - if (ret < 0) - USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s", - dev->interface, alternate, strerror(errno)); - - dev->altsetting = alternate; - - return 0; -} - -/* - * Linux usbfs has a limit of one page size for synchronous bulk read/write. - * 4096 is the most portable maximum we can do for now. - * Linux usbfs has a limit of 16KB for the URB interface. We use this now - * to get better performance for USB 2.0 devices. - */ -#define MAX_READ_WRITE (16 * 1024) - -int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, - int value, int index, char *bytes, int size, int timeout) -{ - struct usb_ctrltransfer ctrl; - int ret; - - ctrl.bRequestType = requesttype; - ctrl.bRequest = request; - ctrl.wValue = value; - ctrl.wIndex = index; - ctrl.wLength = size; - - ctrl.data = bytes; - ctrl.timeout = timeout; - - ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl); - if (ret < 0) - USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno)); - - return ret; -} - -#define URB_USERCONTEXT_COOKIE ((void *)0x1) - -/* Reading and writing are the same except for the endpoint */ -static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype, - char *bytes, int size, int timeout) -{ - struct usb_urb urb; - int bytesdone = 0, requested; - struct timeval tv, tv_ref, tv_now; - struct usb_urb *context; - int ret, waiting; - - /* - * HACK: The use of urb.usercontext is a hack to get threaded applications - * sort of working again. Threaded support is still not recommended, but - * this should allow applications to work in the common cases. Basically, - * if we get the completion for an URB we're not waiting for, then we update - * the usercontext pointer to 1 for the other threads URB and it will see - * the change after it wakes up from the the timeout. Ugly, but it works. - */ - - /* - * Get actual time, and add the timeout value. The result is the absolute - * time where we have to quit waiting for an message. - */ - gettimeofday(&tv_ref, NULL); - tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000; - tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000; - - if (tv_ref.tv_usec > 1000000) { - tv_ref.tv_usec -= 1000000; - tv_ref.tv_sec++; - } - - do { - fd_set writefds; - - requested = size - bytesdone; - if (requested > MAX_READ_WRITE) - requested = MAX_READ_WRITE; - - urb.type = urbtype; - urb.endpoint = ep; - urb.flags = 0; - urb.buffer = bytes + bytesdone; - urb.buffer_length = requested; - urb.signr = 0; - urb.actual_length = 0; - urb.number_of_packets = 0; /* don't do isochronous yet */ - urb.usercontext = NULL; - - ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb); - if (ret < 0) { - USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno)); - return ret; - } - - FD_ZERO(&writefds); - FD_SET(dev->fd, &writefds); - -restart: - waiting = 1; - context = NULL; - while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) { - tv.tv_sec = 0; - tv.tv_usec = 1000; // 1 msec - select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait - - if (timeout) { - /* compare with actual time, as the select timeout is not that precise */ - gettimeofday(&tv_now, NULL); - - if ((tv_now.tv_sec > tv_ref.tv_sec) || - ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec))) - waiting = 0; - } - } - - if (context && context != &urb) { - context->usercontext = URB_USERCONTEXT_COOKIE; - /* We need to restart since we got a successful URB, but not ours */ - goto restart; - } - - /* - * If there was an error, that wasn't EAGAIN (no completion), then - * something happened during the reaping and we should return that - * error now - */ - if (ret < 0 && !urb.usercontext && errno != EAGAIN) - USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno)); - - bytesdone += urb.actual_length; - } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested); - - /* If the URB didn't complete in success or error, then let's unlink it */ - if (ret < 0 && !urb.usercontext) { - int rc; - - if (!waiting) - rc = -ETIMEDOUT; - else - rc = urb.status; - - ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb); - if (ret < 0 && errno != EINVAL && usb_debug >= 1) - fprintf(stderr, "error discarding URB: %s", strerror(errno)); - - /* - * When the URB is unlinked, it gets moved to the completed list and - * then we need to reap it or else the next time we call this function, - * we'll get the previous completion and exit early - */ - ioctl(dev->fd, IOCTL_USB_REAPURB, &context); - - return rc; - } - - return bytesdone; -} - -int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - /* Ensure the endpoint address is correct */ - return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size, - timeout); -} - -int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - /* Ensure the endpoint address is correct */ - ep |= USB_ENDPOINT_IN; - return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size, - timeout); -} - -/* - * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked - * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need - * to lookup the endpoint packet size and packetize appropriately here. - */ -int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - /* Ensure the endpoint address is correct */ - return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size, - timeout); -} - -int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout) -{ - /* Ensure the endpoint address is correct */ - ep |= USB_ENDPOINT_IN; - return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size, - timeout); -} - -int usb_os_find_busses(struct usb_bus **busses) -{ - struct usb_bus *fbus = NULL; - DIR *dir; - struct dirent *entry; - - dir = opendir(usb_path); - if (!dir) - USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path, - strerror(errno)); - - while ((entry = readdir(dir)) != NULL) { - struct usb_bus *bus; - - /* Skip anything starting with a . */ - if (entry->d_name[0] == '.') - continue; - - if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) { - if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n", - entry->d_name); - continue; - } - - bus = malloc(sizeof(*bus)); - if (!bus) - USB_ERROR(-ENOMEM); - - memset((void *)bus, 0, sizeof(*bus)); - - strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1); - bus->dirname[sizeof(bus->dirname) - 1] = 0; - - LIST_ADD(fbus, bus); - - if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname); - } - - closedir(dir); - - *busses = fbus; - - return 0; -} - -int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) -{ - struct usb_device *fdev = NULL; - DIR *dir; - struct dirent *entry; - char dirpath[PATH_MAX + 1]; - - snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname); - - dir = opendir(dirpath); - if (!dir) - USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath, - strerror(errno)); - - while ((entry = readdir(dir)) != NULL) { - unsigned char device_desc[DEVICE_DESC_LENGTH]; - char filename[PATH_MAX + 1]; - struct usb_device *dev; - struct usb_connectinfo connectinfo; - int i, fd, ret; - - /* Skip anything starting with a . */ - if (entry->d_name[0] == '.') - continue; - - dev = malloc(sizeof(*dev)); - if (!dev) - USB_ERROR(-ENOMEM); - - memset((void *)dev, 0, sizeof(*dev)); - - dev->bus = bus; - - strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1); - dev->filename[sizeof(dev->filename) - 1] = 0; - - snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name); - fd = open(filename, O_RDWR); - if (fd < 0) { - fd = open(filename, O_RDONLY); - if (fd < 0) { - if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n", - filename); - - free(dev); - continue; - } - } - - /* Get the device number */ - ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo); - if (ret < 0) { - if (usb_debug) - fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n"); - } else - dev->devnum = connectinfo.devnum; - - ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH); - if (ret < 0) { - if (usb_debug) - fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n"); - - free(dev); - - goto err; - } - - /* - * Linux kernel converts the words in this descriptor to CPU endian, so - * we use the undocumented W character for usb_parse_descriptor() that - * doesn't convert endianess when parsing the descriptor - */ - usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor); - - LIST_ADD(fdev, dev); - - if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_devices: Found %s on %s\n", - dev->filename, bus->dirname); - - /* Now try to fetch the rest of the descriptors */ - if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) - /* Silent since we'll try again later */ - goto err; - - if (dev->descriptor.bNumConfigurations < 1) - /* Silent since we'll try again later */ - goto err; - - dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); - if (!dev->config) - /* Silent since we'll try again later */ - goto err; - - memset(dev->config, 0, dev->descriptor.bNumConfigurations * - sizeof(struct usb_config_descriptor)); - - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - unsigned char buffer[8], *bigbuffer; - struct usb_config_descriptor config; - - /* Get the first 8 bytes so we can figure out what the total length is */ - ret = read(fd, (void *)buffer, 8); - if (ret < 8) { - if (usb_debug >= 1) { - if (ret < 0) - fprintf(stderr, "Unable to get descriptor (%d)\n", ret); - else - fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret); - } - - goto err; - } - - usb_parse_descriptor(buffer, "bbw", &config); - - bigbuffer = malloc(config.wTotalLength); - if (!bigbuffer) { - if (usb_debug >= 1) - fprintf(stderr, "Unable to allocate memory for descriptors\n"); - goto err; - } - - /* Read the rest of the config descriptor */ - memcpy(bigbuffer, buffer, 8); - - ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8); - if (ret < config.wTotalLength - 8) { - if (usb_debug >= 1) { - if (ret < 0) - fprintf(stderr, "Unable to get descriptor (%d)\n", ret); - else - fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret); - } - - free(bigbuffer); - goto err; - } - - ret = usb_parse_configuration(&dev->config[i], bigbuffer); - if (usb_debug >= 2) { - if (ret > 0) - fprintf(stderr, "Descriptor data still left\n"); - else if (ret < 0) - fprintf(stderr, "Unable to parse descriptors\n"); - } - - free(bigbuffer); - } - -err: - close(fd); - } - - closedir(dir); - - *devices = fdev; - - return 0; -} - -int usb_os_determine_children(struct usb_bus *bus) -{ - struct usb_device *dev, *devices[256]; - struct usb_ioctl command; - int ret, i, i1; - - /* Create a list of devices first */ - memset(devices, 0, sizeof(devices)); - for (dev = bus->devices; dev; dev = dev->next) - if (dev->devnum) - devices[dev->devnum] = dev; - - /* Now fetch the children for each device */ - for (dev = bus->devices; dev; dev = dev->next) { - struct usb_hub_portinfo portinfo; - int fd; - - fd = device_open(dev); - if (fd < 0) - continue; - - /* Query the hub driver for the children of this device */ - if (dev->config && dev->config->interface && dev->config->interface->altsetting) - command.ifno = dev->config->interface->altsetting->bInterfaceNumber; - else - command.ifno = 0; - command.ioctl_code = IOCTL_USB_HUB_PORTINFO; - command.data = &portinfo; - ret = ioctl(fd, IOCTL_USB_IOCTL, &command); - if (ret < 0) { - /* errno == ENOSYS means the device probably wasn't a hub */ - if (errno != ENOSYS && usb_debug > 1) - fprintf(stderr, "error obtaining child information: %s\n", - strerror(errno)); - - close(fd); - continue; - } - - dev->num_children = 0; - for (i = 0; i < portinfo.numports; i++) - if (portinfo.port[i]) - dev->num_children++; - - /* Free any old children first */ - free(dev->children); - - dev->children = malloc(sizeof(struct usb_device *) * dev->num_children); - if (!dev->children) { - if (usb_debug > 1) - fprintf(stderr, "error allocating %zu bytes memory for dev->children\n", - sizeof(struct usb_device *) * dev->num_children); - - dev->num_children = 0; - close(fd); - continue; - } - - for (i = 0, i1 = 0; i < portinfo.numports; i++) { - if (!portinfo.port[i]) - continue; - - dev->children[i1++] = devices[portinfo.port[i]]; - - devices[portinfo.port[i]] = NULL; - } - - close(fd); - } - - /* - * There should be one device left in the devices list and that should be - * the root device - */ - for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) { - if (devices[i]) - bus->root_dev = devices[i]; - } - - return 0; -} - -static int check_usb_vfs(const char *dirname) -{ - DIR *dir; - struct dirent *entry; - int found = 0; - - dir = opendir(dirname); - if (!dir) - return 0; - - while ((entry = readdir(dir)) != NULL) { - /* Skip anything starting with a . */ - if (entry->d_name[0] == '.') - continue; - - /* We assume if we find any files that it must be the right place */ - found = 1; - break; - } - - closedir(dir); - - return found; -} - -void usb_os_init(void) -{ - /* Find the path to the virtual filesystem */ - if (getenv("USB_DEVFS_PATH")) { - if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) { - strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1); - usb_path[sizeof(usb_path) - 1] = 0; - } else if (usb_debug) - fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n"); - } - - if (!usb_path[0]) { - if (check_usb_vfs("/dev/bus/usb")) { - strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1); - usb_path[sizeof(usb_path) - 1] = 0; - } else if (check_usb_vfs("/proc/bus/usb")) { - strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1); - usb_path[sizeof(usb_path) - 1] = 0; - } else - usb_path[0] = 0; /* No path, no USB support */ - } - - if (usb_debug) { - if (usb_path[0]) - fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path); - else - fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n"); - } -} - -int usb_resetep(usb_dev_handle *dev, unsigned int ep) -{ - int ret; - - ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep); - if (ret) - USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep, - strerror(errno)); - - return 0; -} - -int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) -{ - int ret; - - ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep); - if (ret) - USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep, - strerror(errno)); - - return 0; -} - -int usb_reset(usb_dev_handle *dev) -{ - int ret; - - ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL); - if (ret) - USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno)); - - return 0; -} - -int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, - unsigned int namelen) -{ - struct usb_getdriver getdrv; - int ret; - - getdrv.interface = interface; - ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv); - if (ret) - USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno)); - - strncpy(name, getdrv.driver, namelen - 1); - name[namelen - 1] = 0; - - return 0; -} - -int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface) -{ - struct usb_ioctl command; - int ret; - - command.ifno = interface; - command.ioctl_code = IOCTL_USB_DISCONNECT; - command.data = NULL; - - ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command); - if (ret) - USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s", - interface, strerror(errno)); - - return 0; -} - diff --git a/src/libusb/linux.h b/src/libusb/linux.h deleted file mode 100644 index e544c09..0000000 --- a/src/libusb/linux.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __LINUX_H__ -#define __LINUX_H__ - -#include -#include -#include - -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 give correct values */ - void *data; /* param buffer (in, or out) */ -}; - -struct usb_hub_portinfo { - unsigned char numports; - unsigned char port[127]; /* port to device num mapping */ -}; - -#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer) -#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer) -#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int) -#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface) -#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int) -#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver) -#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb) -#define IOCTL_USB_DISCARDURB _IO('U', 11) -#define IOCTL_USB_REAPURB _IOW('U', 12, void *) -#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *) -#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int) -#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int) -#define IOCTL_USB_CONNECTINFO _IOW('U', 17, struct usb_connectinfo) -#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl) -#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct usb_hub_portinfo) -#define IOCTL_USB_RESET _IO('U', 20) -#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int) -#define IOCTL_USB_DISCONNECT _IO('U', 22) -#define IOCTL_USB_CONNECT _IO('U', 23) - -/* - * IOCTL_USB_HUB_PORTINFO, IOCTL_USB_DISCONNECT and IOCTL_USB_CONNECT - * all work via IOCTL_USB_IOCTL - */ - -#endif - diff --git a/src/libusb/usb.c b/src/libusb/usb.c deleted file mode 100644 index ea4b375..0000000 --- a/src/libusb/usb.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Main API entry point - * - * Copyright (c) 2000-2003 Johannes Erdfelt - * - * This library is covered by the LGPL, read LICENSE for details. - */ - -#include /* getenv */ -#include /* stderr */ -#include /* strcmp */ -#include - -#include "usbi.h" - -int usb_debug = 0; -struct usb_bus *usb_busses = NULL; - -int usb_find_busses(void) -{ - struct usb_bus *busses, *bus; - int ret, changes = 0; - - ret = usb_os_find_busses(&busses); - if (ret < 0) - return ret; - - /* - * Now walk through all of the busses we know about and compare against - * this new list. Any duplicates will be removed from the new list. - * If we don't find it in the new list, the bus was removed. Any - * busses still in the new list, are new to us. - */ - bus = usb_busses; - while (bus) { - int found = 0; - struct usb_bus *nbus, *tbus = bus->next; - - nbus = busses; - while (nbus) { - struct usb_bus *tnbus = nbus->next; - - if (!strcmp(bus->dirname, nbus->dirname)) { - /* Remove it from the new busses list */ - LIST_DEL(busses, nbus); - - usb_free_bus(nbus); - found = 1; - break; - } - - nbus = tnbus; - } - - if (!found) { - /* The bus was removed from the system */ - LIST_DEL(usb_busses, bus); - usb_free_bus(bus); - changes++; - } - - bus = tbus; - } - - /* - * Anything on the *busses list is new. So add them to usb_busses and - * process them like the new bus it is. - */ - bus = busses; - while (bus) { - struct usb_bus *tbus = bus->next; - - /* - * Remove it from the temporary list first and add it to the real - * usb_busses list. - */ - LIST_DEL(busses, bus); - - LIST_ADD(usb_busses, bus); - - changes++; - - bus = tbus; - } - - return changes; -} - -int usb_find_devices(void) -{ - struct usb_bus *bus; - int ret, changes = 0; - - for (bus = usb_busses; bus; bus = bus->next) { - struct usb_device *devices, *dev; - - /* Find all of the devices and put them into a temporary list */ - ret = usb_os_find_devices(bus, &devices); - if (ret < 0) - return ret; - - /* - * Now walk through all of the devices we know about and compare - * against this new list. Any duplicates will be removed from the new - * list. If we don't find it in the new list, the device was removed. - * Any devices still in the new list, are new to us. - */ - dev = bus->devices; - while (dev) { - int found = 0; - struct usb_device *ndev, *tdev = dev->next; - - ndev = devices; - while (ndev) { - struct usb_device *tndev = ndev->next; - - if (!strcmp(dev->filename, ndev->filename)) { - /* Remove it from the new devices list */ - LIST_DEL(devices, ndev); - - usb_free_dev(ndev); - found = 1; - break; - } - - ndev = tndev; - } - - if (!found) { - /* The device was removed from the system */ - LIST_DEL(bus->devices, dev); - usb_free_dev(dev); - changes++; - } - - dev = tdev; - } - - /* - * Anything on the *devices list is new. So add them to bus->devices and - * process them like the new device it is. - */ - dev = devices; - while (dev) { - struct usb_device *tdev = dev->next; - - /* - * Remove it from the temporary list first and add it to the real - * bus->devices list. - */ - LIST_DEL(devices, dev); - - LIST_ADD(bus->devices, dev); - - /* - * Some ports fetch the descriptors on scanning (like Linux) so we don't - * need to fetch them again. - */ - if (!dev->config) { - usb_dev_handle *udev; - - udev = usb_open(dev); - if (udev) { - usb_fetch_and_parse_descriptors(udev); - - usb_close(udev); - } - } - - changes++; - - dev = tdev; - } - - usb_os_determine_children(bus); - } - - return changes; -} - -void usb_set_debug(int level) -{ - if (usb_debug || level) - fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n", - level, level ? "on" : "off"); - - usb_debug = level; -} - -void usb_init(void) -{ - if (getenv("USB_DEBUG")) - usb_set_debug(atoi(getenv("USB_DEBUG"))); - - usb_os_init(); -} - -usb_dev_handle *usb_open(struct usb_device *dev) -{ - usb_dev_handle *udev; - - udev = malloc(sizeof(*udev)); - if (!udev) - return NULL; - - udev->fd = -1; - udev->device = dev; - udev->bus = dev->bus; - udev->config = udev->interface = udev->altsetting = -1; - - if (usb_os_open(udev) < 0) { - free(udev); - return NULL; - } - - return udev; -} - -int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, - size_t buflen) -{ - /* - * We can't use usb_get_descriptor() because it's lacking the index - * parameter. This will be fixed in libusb 1.0 - */ - return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, - (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000); -} - -int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen) -{ - char tbuf[255]; /* Some devices choke on size > 255 */ - int ret, langid, si, di; - - /* - * Asking for the zero'th index is special - it returns a string - * descriptor that contains all the language IDs supported by the - * device. Typically there aren't many - often only one. The - * language IDs are 16 bit numbers, and they start at the third byte - * in the descriptor. See USB 2.0 specification, section 9.6.7, for - * more information on this. */ - ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf)); - if (ret < 0) - return ret; - - if (ret < 4) - return -EIO; - - langid = tbuf[2] | (tbuf[3] << 8); - - ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf)); - if (ret < 0) - return ret; - - if (tbuf[1] != USB_DT_STRING) - return -EIO; - - if (tbuf[0] > ret) - return -EFBIG; - - for (di = 0, si = 2; si < tbuf[0]; si += 2) { - if (di >= (buflen - 1)) - break; - - if (tbuf[si + 1]) /* high byte */ - buf[di++] = '?'; - else - buf[di++] = tbuf[si]; - } - - buf[di] = 0; - - return di; -} - -int usb_close(usb_dev_handle *dev) -{ - int ret; - - ret = usb_os_close(dev); - free(dev); - - return ret; -} - -struct usb_device *usb_device(usb_dev_handle *dev) -{ - return dev->device; -} - -void usb_free_dev(struct usb_device *dev) -{ - usb_destroy_configuration(dev); - free(dev->children); - free(dev); -} - -struct usb_bus *usb_get_busses(void) -{ - return usb_busses; -} - -void usb_free_bus(struct usb_bus *bus) -{ - free(bus); -} - diff --git a/src/libusb/usb.h b/src/libusb/usb.h deleted file mode 100644 index 35955b7..0000000 --- a/src/libusb/usb.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Prototypes, structure definitions and macros. - * - * Copyright (c) 2000-2003 Johannes Erdfelt - * - * 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 -#include -#include - -#include - -/* - * 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); - -/* .c */ -int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout); -int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout); -int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout); -int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, - int timeout); -int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, - int value, int index, char *bytes, int size, int timeout); -int usb_set_configuration(usb_dev_handle *dev, int configuration); -int usb_claim_interface(usb_dev_handle *dev, int interface); -int usb_release_interface(usb_dev_handle *dev, int interface); -int usb_set_altinterface(usb_dev_handle *dev, int alternate); -int usb_resetep(usb_dev_handle *dev, unsigned int ep); -int usb_clear_halt(usb_dev_handle *dev, unsigned int ep); -int usb_reset(usb_dev_handle *dev); - -#if LINUX_API -#define LIBUSB_HAS_GET_DRIVER_NP 1 -int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, - unsigned int namelen); -#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1 -int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface); -#endif - -char *usb_strerror(void); - -void usb_init(void); -void usb_set_debug(int level); -int usb_find_busses(void); -int usb_find_devices(void); -struct usb_device *usb_device(usb_dev_handle *dev); -struct usb_bus *usb_get_busses(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __USB_H__ */ - diff --git a/src/libusb/usbi.h b/src/libusb/usbi.h deleted file mode 100644 index d71b5c4..0000000 --- a/src/libusb/usbi.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _USBI_H_ -#define _USBI_H_ - -#include "usb.h" - -#include "error.h" - -extern int usb_debug; - -/* Some quick and generic macros for the simple kind of lists we use */ -#define LIST_ADD(begin, ent) \ - do { \ - if (begin) { \ - ent->next = begin; \ - ent->next->prev = ent; \ - } else \ - ent->next = NULL; \ - ent->prev = NULL; \ - begin = ent; \ - } while(0) - -#define LIST_DEL(begin, ent) \ - do { \ - if (ent->prev) \ - ent->prev->next = ent->next; \ - else \ - begin = ent->next; \ - if (ent->next) \ - ent->next->prev = ent->prev; \ - ent->prev = NULL; \ - ent->next = NULL; \ - } while (0) - -#define DESC_HEADER_LENGTH 2 -#define DEVICE_DESC_LENGTH 18 -#define CONFIG_DESC_LENGTH 9 -#define INTERFACE_DESC_LENGTH 9 -#define ENDPOINT_DESC_LENGTH 7 -#define ENDPOINT_AUDIO_DESC_LENGTH 9 - -struct usb_dev_handle { - int fd; - - struct usb_bus *bus; - struct usb_device *device; - - int config; - int interface; - int altsetting; - - /* Added by RMT so implementations can store other per-open-device data */ - void *impl_info; -}; - -/* descriptors.c */ -int usb_parse_descriptor(unsigned char *source, char *description, void *dest); -int usb_parse_configuration(struct usb_config_descriptor *config, - unsigned char *buffer); -void usb_fetch_and_parse_descriptors(usb_dev_handle *udev); -void usb_destroy_configuration(struct usb_device *dev); - -/* OS specific routines */ -int usb_os_find_busses(struct usb_bus **busses); -int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices); -int usb_os_determine_children(struct usb_bus *bus); -void usb_os_init(void); -int usb_os_open(usb_dev_handle *dev); -int usb_os_close(usb_dev_handle *dev); - -void usb_free_dev(struct usb_device *dev); -void usb_free_bus(struct usb_bus *bus); - -#endif /* _USBI_H_ */ - diff --git a/src/libusb/windows.c b/src/libusb/windows.c deleted file mode 100644 index 929ffcf..0000000 --- a/src/libusb/windows.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include "winusb.h" - -#include -#include -#include -#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 \ - 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) { - D("fail to create device file: %s due to: %d\n", device_path, GetLastError()); - return NULL; - } - - // Initialize WinUSB for this device and get a WinUSB handle for it - WINUSB_INTERFACE_HANDLE fd; - if (!WinUsb_Initialize(hnd, &fd)) { - return NULL; - } - - // fetch USB device descriptor - USB_DEVICE_DESCRIPTOR usb_device_descriptor; - unsigned long bytes_written; - - if (!WinUsb_GetDescriptor(fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, - (PUCHAR)&usb_device_descriptor, sizeof(usb_device_descriptor), &bytes_written)) { - return NULL; - } - - USB_INTERFACE_DESCRIPTOR usb_interface_descriptor; - - // fetch usb interface descriptor - UCHAR interface_number; - if (!WinUsb_GetCurrentAlternateSetting(fd, &interface_number)) { - return NULL; - } - - if (!WinUsb_QueryInterfaceSettings(fd, interface_number, &usb_interface_descriptor)) { - return NULL; - } - - if (2 != usb_interface_descriptor.bNumEndpoints) { - D("the number of endpoint should be two\n"); - return NULL; - } - - if (!is_sdb_interface(usb_device_descriptor.idVendor, usb_interface_descriptor.bInterfaceClass, usb_interface_descriptor.bInterfaceSubClass, - usb_interface_descriptor.bInterfaceProtocol)) { - return NULL; - } - UCHAR endpoint_index = 0; - - for (endpoint_index = 0; endpoint_index < usb_interface_descriptor.bNumEndpoints; endpoint_index++) { - // fetch endpoint information - WINUSB_PIPE_INFORMATION pipe_info; - if (!WinUsb_QueryPipe(fd, interface_number, endpoint_index, &pipe_info)) { - return NULL; - } - - if(usb_interface_descriptor.bInterfaceProtocol == 0x01) { - if (endpoint_index == 0) { - usb->zero_mask = pipe_info.MaximumPacketSize - 1; - } - } - // only interested in bulk type - if (UsbdPipeTypeBulk == pipe_info.PipeType) { - if (USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) { - D("builk in endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId); - usb->end_point[0] = pipe_info.PipeId; - } - - if (USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) { - D("builk out endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId); - usb->end_point[1] = pipe_info.PipeId; - } - - } - } - usb->hnd = hnd; - usb->fd = fd; - - return usb; -} - -int register_device(usb_handle *hnd) { - if (is_device_registered(hnd->unique_node_path)) { - return 0; - } - - sdb_mutex_lock(&usb_lock); - - 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); -} - -static int get_serial_number(usb_handle *dev, char *buf, int buflen) { - USB_DEVICE_DESCRIPTOR usb_device_descriptor; - ULONG actlen = 0; - - if (!WinUsb_GetDescriptor(dev->fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (unsigned char*) &usb_device_descriptor, - sizeof(usb_device_descriptor), &actlen)) { - return 0; - } - - return usb_get_string_simple(dev, usb_device_descriptor.iSerialNumber, buf, buflen); -} - -int usb_find_devices(GUID deviceClassID) { - SP_DEVINFO_DATA deviceInfoData; - char devicePath[PATH_MAX + 1]; - BOOL bResult = TRUE; - PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL; - int index = 0; - - // from http://msdn.microsoft.com/en-us/library/windows/hardware/ff540174(v=vs.85).aspx - // Get information about all the installed devices for the specified device interface class. - HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&deviceClassID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (hDeviceInfo == INVALID_HANDLE_VALUE) { - D("fail to find any device: %d\n", GetLastError()); - return 0; - } - - //Enumerate all the device interfaces in the device information set. - deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); - - for (index = 0; ; index++) { - - //Get information about the device interface. - SP_DEVICE_INTERFACE_DATA interfaceData; - interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); - - bResult = SetupDiEnumDeviceInterfaces(hDeviceInfo, NULL, &deviceClassID, index, &interfaceData); - // Check if last item - if (GetLastError() == ERROR_NO_MORE_ITEMS) { - break; - } - - //Check for some other error - if (!bResult) - { - D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); - break; - } - - // Determine required size for interface detail data - ULONG requiredLength = 0; - - //Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA - //which we need to allocate, so we have to call this function twice. - //First to get the size so that we know how much to allocate - //Second, the actual call with the allocated buffer - bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL); - - //Check for some other error - if (!bResult) { - if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (requiredLength > 0)) { - // Allocate storage for interface detail data - detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredLength); - - if (detailData == NULL) { - D("fail to allocate memory\n"); - break; - } - } else { - D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); - break; - } - } - - // Finally, do fetch interface detail data - detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - //Now call it with the correct size and allocated buffer - bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, detailData, requiredLength, NULL, - &deviceInfoData); - - //Check for some other error - if (!bResult) { - D("fail to setdup get device interface detail: %d\n", GetLastError()); - if (detailData != NULL) { - free(detailData); - } - break; - } - - //copy device path - s_strncpy(devicePath, detailData->DevicePath, sizeof(devicePath)); - - if (detailData != NULL) { - free(detailData); - } - - if (!is_device_registered(devicePath)) { - struct usb_handle *hnd = usb_open(devicePath); - if (hnd != NULL) { - char serial[256]; - if (get_serial_number(hnd, serial, sizeof(serial)) > 0) { - D("register usb for: %s\n", serial); - if (register_device(hnd)) { - register_usb_transport(hnd, serial, 1); - } else { - D("fail to register usb\n"); - win_usb_close(hnd); - free(hnd); - } - } else { - D("fail to get usb serial name: kick? close?\n"); - win_usb_close(hnd); - free(hnd); - } - } - } - } - // Cleanup - bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo); - - return bResult; -} - -void* device_poll_thread(void* sleep_msec) { - D("Created device thread\n"); - - int mseconds = (int) sleep_msec; - while (1) { - do_lsusb(); - sdb_sleep_ms(mseconds); - } - - return NULL; -} - -void sdb_usb_init() { - sdb_thread_t tid; - - win_usb_init(); - if (sdb_thread_create(&tid, device_poll_thread, (void*)3000)) { - 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; -} - -int win_usb_close(usb_handle *handle) { - D("+usb win_usb_close\n"); - if (NULL != handle) { - if (NULL != handle->fd) { - WinUsb_Free(handle->fd); - handle->fd = NULL; - } - if (NULL != handle->hnd) { - CloseHandle(handle->hnd); - handle->hnd = NULL; - } - handle = NULL; - } - D("-usb win_usb_close\n"); - return 0; -} - -void sdb_usb_kick(usb_handle* handle) { - D("+sdb_usb_kick: %p\n", handle); - // called from transport remote kick if already registered - // so only clean for win usb handle resources - sdb_mutex_lock(&usb_lock); - win_usb_close(handle); - sdb_mutex_unlock(&usb_lock); - 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); - free(handle); - } - D("-sdb_usb_close: %p\n", handle); - return 0; -} - -void do_lsusb() { - usb_find_devices(TIZEN_CLASSID); -} diff --git a/src/libusb/winusb.h b/src/libusb/winusb.h deleted file mode 100755 index 8e5cf8a..0000000 --- a/src/libusb/winusb.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __WINUSB_H -#define __WINUSB_H - -#include "ddk/usb100.h" -#include "ddk/usbioctl.h" - -// Windows API default is uppercase - ugh! -#if !defined(bool) -#define bool BOOLEAN -#endif -#if !defined(true) -#define true TRUE -#endif -#if !defined(false) -#define false FALSE -#endif - - -/* - * Some of the EX stuff is not yet in MinGW => define it - */ -#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX -#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 -#endif - -#ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \ - METHOD_BUFFERED, FILE_ANY_ACCESS) -#endif - -#ifndef USB_NODE_CONNECTION_INFORMATION_EX -typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { - ULONG ConnectionIndex; - USB_DEVICE_DESCRIPTOR DeviceDescriptor; - UCHAR CurrentConfigurationValue; - UCHAR Speed; - BOOLEAN DeviceIsHub; - USHORT DeviceAddress; - ULONG NumberOfOpenPipes; - USB_CONNECTION_STATUS ConnectionStatus; - USB_PIPE_INFO PipeList[0]; -} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; -#endif - -#ifndef USB_HUB_CAP_FLAGS -typedef union _USB_HUB_CAP_FLAGS { - ULONG ul; - struct { - ULONG HubIsHighSpeedCapable:1; - ULONG HubIsHighSpeed:1; - ULONG HubIsMultiTtCapable:1; - ULONG HubIsMultiTt:1; - ULONG HubIsRoot:1; - ULONG HubIsArmedWakeOnConnect:1; - ULONG ReservedMBZ:26; - }; -} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; -#endif - -#ifndef USB_HUB_CAPABILITIES_EX -typedef struct _USB_HUB_CAPABILITIES_EX { - USB_HUB_CAP_FLAGS CapabilityFlags; -} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; -#endif - -#ifndef USB_GET_HUB_CAPABILITIES_EX -#define USB_GET_HUB_CAPABILITIES_EX 276 -#endif - -#ifndef IOCTL_USB_GET_HUB_CAPABILITIES_EX -#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ - CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, \ - METHOD_BUFFERED, FILE_ANY_ACCESS ) -#endif - -/* - * WinUSB macros - from libusb-win32 1.x - */ - -#define DLL_DECLARE(api, ret, name, args) \ - typedef ret (api * __dll_##name##_t)args; \ - static __dll_##name##_t name - -#define DLL_LOAD(dll, name) \ - do { \ - HMODULE h = GetModuleHandle(#dll); \ - if(!h) \ - h = LoadLibrary(#dll); \ - if(!h) \ - break; \ - if((name = (__dll_##name##_t)GetProcAddress(h, #name))) \ - break; \ - if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \ - break; \ - if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \ - break; \ - } while(0) - - -/* winusb.dll interface */ - -#define SHORT_PACKET_TERMINATE 0x01 -#define AUTO_CLEAR_STALL 0x02 -#define PIPE_TRANSFER_TIMEOUT 0x03 -#define IGNORE_SHORT_PACKETS 0x04 -#define ALLOW_PARTIAL_READS 0x05 -#define AUTO_FLUSH 0x06 -#define RAW_IO 0x07 -#define MAXIMUM_TRANSFER_SIZE 0x08 -#define AUTO_SUSPEND 0x81 -#define SUSPEND_DELAY 0x83 -#define DEVICE_SPEED 0x01 -#define LowSpeed 0x01 -#define FullSpeed 0x02 -#define HighSpeed 0x03 - -typedef enum _USBD_PIPE_TYPE { - UsbdPipeTypeControl, - UsbdPipeTypeIsochronous, - UsbdPipeTypeBulk, - UsbdPipeTypeInterrupt -} USBD_PIPE_TYPE; - -typedef struct { - USBD_PIPE_TYPE PipeType; - UCHAR PipeId; - USHORT MaximumPacketSize; - UCHAR Interval; -} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; - -#pragma pack(1) -typedef struct { - UCHAR RequestType; - UCHAR Request; - USHORT Value; - USHORT Index; - USHORT Length; -} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; -#pragma pack() - -typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; - -#endif // __WINUSB_H diff --git a/src/linkedlist.c b/src/linkedlist.c index 93aa7bb..4c6beb4 100644 --- a/src/linkedlist.c +++ b/src/linkedlist.c @@ -31,7 +31,7 @@ static void default_free(void* data); -void append(LIST_NODE** listptr, void* value) { +LIST_NODE* append(LIST_NODE** listptr, void* value) { LIST_NODE* prev_ptr = NULL; LIST_NODE* current_ptr = *listptr; @@ -47,14 +47,34 @@ void append(LIST_NODE** listptr, void* value) { //listptr is empty. if(prev_ptr == NULL) { + new_ptr->prev_ptr = NULL; *listptr = new_ptr; } else { prev_ptr->next_ptr = new_ptr; + new_ptr->prev_ptr = prev_ptr; } + + return new_ptr; +} + +LIST_NODE* prepend(LIST_NODE** listptr, void* value) { + + LIST_NODE* new_ptr = (LIST_NODE*)malloc(sizeof(LIST_NODE)); + new_ptr->data = value; + new_ptr->next_ptr = *listptr; + new_ptr->prev_ptr = NULL; + + if(*listptr != NULL) { + (*listptr)->prev_ptr = new_ptr; + } + + *listptr = new_ptr; + + return new_ptr; } -void no_free() { +void no_free(void* data) { //do nothing. } @@ -64,17 +84,39 @@ void free_list(LIST_NODE* listptr, void(free_func)(void*)) { free_func = default_free; } - LIST_NODE* nextptr = NULL; LIST_NODE* currentptr = listptr; while(currentptr != NULL) { - nextptr = currentptr->next_ptr; - free_func(currentptr->data); - free(currentptr); - currentptr = nextptr; + LIST_NODE* prev = currentptr; + currentptr = currentptr->next_ptr; + free_func(prev->data); + free(prev); } } +void remove_node(LIST_NODE** listptr, LIST_NODE* remove_node, void(free_func)(void*)) { + + if(free_func == NULL) { + free_func = default_free; + } + LIST_NODE* next = remove_node->next_ptr; + LIST_NODE* prev = remove_node->prev_ptr; + + if(*listptr == remove_node) { + *listptr = next; + } + else { + //if remove_node is not listptr, prev is always not NULL. + prev->next_ptr = next; + } + if (next != NULL) { + next->prev_ptr = prev; + } + + free_func(remove_node->data); + free(remove_node); +} + static void default_free(void* data) { if(data != NULL) { free(data); @@ -89,6 +131,9 @@ void remove_first(LIST_NODE** listptr, void(free_func)(void*)) { if(*listptr != NULL) { LIST_NODE* curptr = (*listptr)->next_ptr; + if(curptr != NULL) { + curptr->prev_ptr = NULL; + } LIST_NODE* removeptr = *listptr; *listptr = curptr; free_func(removeptr->data); diff --git a/src/linkedlist.h b/src/linkedlist.h index b88a5de..11d7aed 100644 --- a/src/linkedlist.h +++ b/src/linkedlist.h @@ -30,13 +30,16 @@ struct list_node { void* data; struct list_node* next_ptr; + struct list_node* prev_ptr; }; typedef struct list_node LIST_NODE; -void no_free(); -void append( LIST_NODE** listptr, void* value); -void free_list(LIST_NODE* listptr, void(free_func)(void*)); -void remove_first(LIST_NODE** listptr, void(free_func)(void*)); +void no_free(void* data); +LIST_NODE* append( LIST_NODE** listptr, void* value); +LIST_NODE* prepend(LIST_NODE** listptr, void* value); +void free_list(LIST_NODE* listptr, void(free_func)(void* data)); +void remove_first(LIST_NODE** listptr, void(free_func)(void* data)); +void remove_node(LIST_NODE** listptr, LIST_NODE* remove_node, void(free_func)(void* data)); #endif /* LINKEDLIST_H_ */ diff --git a/src/listener.c b/src/listener.c new file mode 100644 index 0000000..c66ec70 --- /dev/null +++ b/src/listener.c @@ -0,0 +1,182 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* 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 +#include +#include + +#include "log.h" +#include "listener.h" +#include "fdevent.h" +#include "utils.h" +#include "sockets.h" + +LIST_NODE* listener_list = NULL; + +static void listener_event_func(int _fd, unsigned ev, void *_l); +static LISTENER* find_listener(const char *local_name); + +void free_listener(void* data) +{ + LISTENER* listener = data; + fdevent_remove(&(listener->fde)); + free((void*)listener->local_name); + free((void*)listener->connect_to); + free(listener); +} + +int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport) +{ + D("LN(%s)\n", local_name); + + LISTENER* listener = find_listener(local_name); + + if(listener != NULL) { + char *cto; + + /* can't repurpose a smartsocket */ + if(listener->connect_to[0] == '*') { + return -1; + } + + cto = strdup(connect_to); + if(cto == 0) { + return -1; + } + + //printf("rebinding '%s' to '%s'\n", local_name, connect_to); + free((void*) listener->connect_to); + listener->connect_to = cto; + if (listener->transport != transport) { + listener->transport = transport; + } + return 0; + } + + if(strncmp("tcp:", local_name, 4)){ + LOG_FATAL("LN(%s) unknown local portname\n", local_name); + return -2; + } + + int port = atoi(local_name + 4); + + //TODO REMOTE_DEVICE_CONNECT block remote connect until security issue is cleard +// int fd = sdb_port_listen(INADDR_ANY, port, SOCK_STREAM); + int fd = sdb_port_listen(INADDR_LOOPBACK, port, SOCK_STREAM); + + if(fd < 0) { + LOG_FATAL("LN(%s) cannot bind\n", local_name); + return -2; + } + + listener = calloc(1, sizeof(LISTENER)); + listener->local_name = strdup(local_name); + listener->connect_to = strdup(connect_to); + listener->fd = fd; + listener->node = prepend(&listener_list, listener); + listener->transport = transport; + close_on_exec(fd); + fdevent_install(&listener->fde, fd, listener_event_func, listener); + FDEVENT_SET(&listener->fde, FDE_READ); + return 0; +} + +int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport) +{ + D("LN(%s)\n", local_name); + LISTENER* listener = find_listener(local_name); + + if(listener != NULL && + !strcmp(connect_to, listener->connect_to) && + listener->transport != NULL && + listener->transport == transport) { + remove_node(&listener_list, listener->node, free_listener); + D("LN(%s) removed\n", local_name); + return 0; + } + + D("LN(%s) could not find\n", local_name); + return -1; +} + +static void listener_event_func(int _fd, unsigned ev, void *_l) +{ + LISTENER *l = _l; + D("LN(%s)\n", l->local_name); + + if(ev & FDE_READ) { + int fd = sdb_socket_accept(_fd); + + if(fd < 0) { + D("LN(%s) fail to create\n", l->local_name); + return; + } + + SDB_SOCKET *s = create_local_socket(fd); + + int ss = 0; + if(!strcmp(l->connect_to, "*smartsocket*")) { + ss = 1; + } + + if(ss) { + sdb_socket_setbufsize(fd, CHUNK_SIZE); + } + if(s) { + + if(ss) { + local_socket_ready(s); + } + else { + + if(l->transport->type == kTransportRemoteDevCon) { + if(assign_remote_connect_socket_rid(s)) { + local_socket_close(s); + return; + } + } + + s->transport = l->transport; + connect_to_remote(s, l->connect_to); + } + return; + } + + sdb_close(fd); + } +} + +static LISTENER* find_listener(const char *local_name) { + LIST_NODE* currentptr = listener_list; + while(currentptr != NULL) { + LISTENER* l = currentptr->data; + currentptr = currentptr->next_ptr; + if(!strcmp(local_name, l->local_name)) { + return l; + } + } + return NULL; +} diff --git a/src/listener.h b/src/listener.h new file mode 100644 index 0000000..b2850cc --- /dev/null +++ b/src/listener.h @@ -0,0 +1,37 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef LISTENER_H_ +#define LISTENER_H_ + +#include "common_modules.h" +extern LIST_NODE* listener_list; + +int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport); +int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport); +void free_listener(void* data); + +#endif /* LISTENER_H_ */ diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..711c4bb --- /dev/null +++ b/src/log.c @@ -0,0 +1,154 @@ +/* + * 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 +#include +#include +#include +#include // for using va_list +#include "log.h" +#include "utils.h" +#include "strutils.h" + +int loglevel_mask; + +static struct { + char* name; + LogLevel level; +} log_levels[] = { + { "all", 0 }, + { "fatal", SDBLOG_FATAL }, + { "error", SDBLOG_ERROR }, + { "debug", SDBLOG_DEBUG }, + { "info", SDBLOG_INFO }, + { "fixme", SDBLOG_FIXME }, + { NULL, 0 } +}; + +void logging_hex(char* hex, char* asci) { + + int hex_len = s_strnlen(hex, 4096); + + char* hex_ptr = hex; + + fprintf(stderr, "HEX:\n"); + while(hex_len > 512) { + char hex_tmp = hex_ptr[512]; + hex_ptr[512] = '\0'; + + fprintf(stderr, "%s", hex_ptr); + hex_len = hex_len - 512; + hex_ptr[512] = hex_tmp; + hex_ptr = hex_ptr + 512; + } + + fprintf(stderr, "%s\n", hex_ptr); + + + int asci_len = s_strnlen(asci, 4096); + char* asci_ptr = asci; + + fprintf(stderr, "ASCI:\n"); + while(asci_len > 512) { + char asci_tmp = asci_ptr[512]; + asci_ptr[512] = '\0'; + + fprintf(stderr, "%s", asci_ptr); + asci_len = asci_len - 512; + asci_ptr[512] = asci_tmp; + asci_ptr = asci_ptr + 512; + } + + fprintf(stderr, "%s\n", asci_ptr); + + +} + +void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...) { + char *name = NULL; + char mbuf[1024]; + char fbuf[1024]; + va_list args; + + va_start(args, fmt); + + switch (level) { + case SDBLOG_FATAL: + name = log_levels[SDBLOG_FATAL].name; + break; + case SDBLOG_ERROR: + name = log_levels[SDBLOG_ERROR].name; + break; + case SDBLOG_INFO: + name = log_levels[SDBLOG_INFO].name; + break; + case SDBLOG_DEBUG: + name = log_levels[SDBLOG_DEBUG].name;; + break; + case SDBLOG_FIXME: + name = log_levels[SDBLOG_FIXME].name; + break; + default: + name = log_levels[SDBLOG_INFO].name; + break; + } + snprintf(fbuf, sizeof(fbuf), "[%s][%s:%s():%d]%s", name, filename, funcname, line_number, fmt); + vsnprintf(mbuf, sizeof(mbuf), fbuf, args); + sdb_mutex_lock(&D_lock, NULL); + fprintf(stderr, "%s", mbuf); + sdb_mutex_unlock(&D_lock, NULL); + fflush(stderr); + va_end(args); +} + +static void log_parse(char* args) { + char *level, *levels, *next; + + levels = strdup(args); + if (levels == NULL) { + return; + } + int i=0; + for (level = levels; level; level = next) { + next = strchr(level, ',' ); + if (next != NULL) { + *next++ = 0; + } + + for (i = 0; log_levels[i].name != NULL; i++) { + if (!strcmp(level, log_levels[i].name)) + { + if (!strcmp("all",log_levels[i].name)) { + loglevel_mask = ~0; + free(levels); + return; + } + loglevel_mask |= 1 << log_levels[i].level; + break; + } + } + } + free(levels); +} + +void log_init(void) +{ + char* sdb_debug = NULL; + + if ((sdb_debug = getenv(DEBUG_ENV))) { + log_parse(sdb_debug); + } +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..6701158 --- /dev/null +++ b/src/log.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LOG_H +#define __LOG_H + +#define SDB_TRACE 1 +#define DEBUG_ENV "SDB_DEBUG" +extern int loglevel_mask; + +typedef enum { + SDBLOG_FATAL = 1, + SDBLOG_ERROR, + SDBLOG_DEBUG, + SDBLOG_INFO, + SDBLOG_FIXME +} LogLevel; + +#define LOG_FATAL(args...) \ + do { \ + logging(SDBLOG_FATAL, __FILE__, __FUNCTION__, __LINE__, args);\ + exit(255);} while(0) + +#define LOG_ASSERT(cond) do { if (!(cond)) LOG_FATAL( "assertion failed '%s'\n", #cond); } while (0) + + +#define LOG_ERROR(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_ERROR)) != 0) { \ + logging(SDBLOG_ERROR, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_DEBUG(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0) { \ + logging(SDBLOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_INFO(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_INFO)) != 0) { \ + logging(SDBLOG_INFO, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_FIXME(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_FIXME)) != 0) { \ + logging(SDBLOG_FIXME, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_HEX(hex, asci) \ + do { \ + logging_hex(hex, asci); } while(0) + + + +void log_init(void); +void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...); +void logging_hex(char* hex, char* asci); + +// define for a while for testing +#undef D +#define D LOG_DEBUG +#undef DR +#define DR LOG_DEBUG +#define SDB_TRACING ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0) + +#endif diff --git a/src/memutils.c b/src/memutils.c new file mode 100644 index 0000000..4fdd686 --- /dev/null +++ b/src/memutils.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "log.h" +#include "strutils.h" + +static size_t total_mem = 0; + +// added size of size_t to know how many bytes have been allocated. + +void *s_malloc(size_t size) { + void *ptr = malloc(size + sizeof(size_t)); + + if (ptr == NULL) { + LOG_FATAL("cannot allocate memory:%d bytes\n", (int ) size); + } + *(size_t*) ptr = size; + + total_mem += size; + + LOG_DEBUG("memory allocated:%u bytes / %u bytes\n", size, total_mem); + + return ptr + sizeof(size_t); +} + +void *s_realloc(void *ptr, size_t new_size) { + void *new_ptr; + size_t org_size; + + if (ptr == NULL) { + LOG_FATAL("null argument in!!\n"); + } + + new_ptr = realloc(ptr - sizeof(size_t), new_size + sizeof(size_t)); + if (new_ptr == NULL) { + LOG_FATAL("cannot allocate new memory:%d bytes\n", (int ) new_size); + } + org_size = *(size_t*) (ptr - sizeof(size_t)); + *(size_t*) new_ptr = new_size; + total_mem += new_size - org_size; + + LOG_DEBUG("memory allocated:%u bytes -> %u bytes / %u bytes\n", org_size, new_size, total_mem); + + return new_ptr + sizeof(size_t); +} + +void s_free(void *ptr) { + size_t size; + + if (ptr == NULL) { + return; + } + + size = *(size_t*) (ptr - sizeof(size_t)); + total_mem -= size; + + free(ptr - sizeof(size_t)); + + LOG_DEBUG("memory freed:%u bytes / %u\n", size, total_mem); + +} + +char *s_strdup(const char *str) { + if (str == NULL) { + return NULL; + } + int len = strlen(str) + 1; + + char *ptr = s_malloc(len); + + s_strncpy(ptr, str, len); + return ptr; +} diff --git a/src/memutils.h b/src/memutils.h new file mode 100644 index 0000000..082bf59 --- /dev/null +++ b/src/memutils.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _MEMUTILS_H_ +#define _MEMUTILS_H_ + +void *s_malloc(size_t size); +void *s_realloc(void *ptr, size_t new_size); +void s_free(void *ptr); +char *s_strdup(const char *str); + +#endif + diff --git a/src/sdb.c b/src/sdb.c index d33b6b8..e17c34f 100755 --- a/src/sdb.c +++ b/src/sdb.c @@ -30,561 +30,17 @@ #include "fdevent.h" #include "sdb.h" #include "commandline.h" +#include "sdb_constants.h" +#include "listener.h" #if SDB_TRACE SDB_MUTEX_DEFINE( D_lock ); #endif -int HOST = 0; +MAP hex_map; -static const char *sdb_device_banner = "device"; - -void fatal(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(-1); -} - -void fatal_errno(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "error: %s: ", strerror(errno)); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(-1); -} - -int sdb_trace_mask; - -/* read a comma/space/colum/semi-column separated list of tags - * from the SDB_TRACE environment variable and build the trace - * mask from it. note that '1' and 'all' are special cases to - * enable all tracing - */ -void sdb_trace_init(void) -{ - const char* p = getenv("SDB_TRACE"); - const char* q; - - static const struct { - const char* tag; - int flag; - } tags[] = { - { "1", 0 }, - { "all", 0 }, - { "sdb", TRACE_SDB }, - { "sockets", TRACE_SOCKETS }, - { "packets", TRACE_PACKETS }, - { "rwx", TRACE_RWX }, - { "usb", TRACE_USB }, - { "sync", TRACE_SYNC }, - { "sysdeps", TRACE_SYSDEPS }, - { "transport", TRACE_TRANSPORT }, - { "jdwp", TRACE_JDWP }, - { "services", TRACE_SERVICES }, - { "properties", TRACE_PROPERTIES }, - { NULL, 0 } - }; - - if (p == NULL) - return; - - /* use a comma/column/semi-colum/space separated list */ - while (*p) { - int len, tagn; - - q = strpbrk(p, " ,:;"); - if (q == NULL) { - q = p + strlen(p); - } - len = q - p; - - for (tagn = 0; tags[tagn].tag != NULL; tagn++) - { - int taglen = strlen(tags[tagn].tag); - - if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) - { - int flag = tags[tagn].flag; - if (flag == 0) { - sdb_trace_mask = ~0; - return; - } - sdb_trace_mask |= (1 << flag); - break; - } - } - p = q; - if (*p) - p++; - } -} - -apacket *get_apacket(void) -{ - apacket *p = malloc(sizeof(apacket)); - if(p == 0) fatal("failed to allocate an apacket"); - memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); - return p; -} - -void put_apacket(apacket *p) -{ - free(p); -} - -void handle_online(void) -{ - D("sdb: online\n"); -} - -void handle_offline(atransport *t) -{ - D("sdb: offline\n"); - //Close the associated usb - run_transport_disconnects(t); -} - -#if TRACE_PACKETS -#define DUMPMAX 32 -void print_packet(const char *label, apacket *p) -{ - char *tag; - char *x; - unsigned count; - - switch(p->msg.command){ - case A_SYNC: tag = "SYNC"; break; - case A_CNXN: tag = "CNXN" ; break; - case A_OPEN: tag = "OPEN"; break; - case A_OKAY: tag = "OKAY"; break; - case A_CLSE: tag = "CLSE"; break; - case A_WRTE: tag = "WRTE"; break; - default: tag = "????"; break; - } - - fprintf(stderr, "%s: %s %08x %08x %04x \"", - label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length); - count = p->msg.data_length; - x = (char*) p->data; - if(count > DUMPMAX) { - count = DUMPMAX; - tag = "\n"; - } else { - tag = "\"\n"; - } - while(count-- > 0){ - if((*x >= ' ') && (*x < 127)) { - fputc(*x, stderr); - } else { - fputc('.', stderr); - } - x++; - } - fprintf(stderr, tag); -} -#endif - -static void send_ready(unsigned local, unsigned remote, atransport *t) -{ - D("Calling send_ready \n"); - apacket *p = get_apacket(); - p->msg.command = A_OKAY; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -static void send_close(unsigned local, unsigned remote, atransport *t) -{ - D("Calling send_close \n"); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -static void send_connect(atransport *t) -{ - D("Calling send_connect \n"); - apacket *cp = get_apacket(); - cp->msg.command = A_CNXN; - cp->msg.arg0 = A_VERSION; - cp->msg.arg1 = MAX_PAYLOAD; - snprintf((char*) cp->data, sizeof cp->data, "%s::", - HOST ? "host" : sdb_device_banner); - cp->msg.data_length = strlen((char*) cp->data) + 1; - send_packet(cp, t); - - /* XXX why sleep here? */ - // allow the device some time to respond to the connect message - sdb_sleep_ms(1000); - -} - -static char *connection_state_name(atransport *t) -{ - if (t == NULL) { - return "unknown"; - } - - switch(t->connection_state) { - case CS_BOOTLOADER: - return "bootloader"; - case CS_DEVICE: - return "device"; - case CS_OFFLINE: - return "offline"; - default: - return "unknown"; - } -} - -void parse_banner(char *banner, atransport *t) -{ - char *type, *product, *end; - - D("parse_banner: %s\n", banner); - type = banner; - product = strchr(type, ':'); - if(product) { - *product++ = 0; - } else { - product = ""; - } - - /* remove trailing ':' */ - end = strchr(product, ':'); - if(end) *end = 0; - - /* save product name in device structure */ - if (t->product == NULL) { - t->product = strdup(product); - } else if (strcmp(product, t->product) != 0) { - free(t->product); - t->product = strdup(product); - } - - if(!strcmp(type, "bootloader")){ - D("setting connection_state to CS_BOOTLOADER\n"); - t->connection_state = CS_BOOTLOADER; - update_transports(); - return; - } - - if(!strcmp(type, "device")) { - D("setting connection_state to CS_DEVICE\n"); - t->connection_state = CS_DEVICE; - update_transports(); - return; - } - - if(!strcmp(type, "recovery")) { - D("setting connection_state to CS_RECOVERY\n"); - t->connection_state = CS_RECOVERY; - update_transports(); - return; - } - - if(!strcmp(type, "sideload")) { - D("setting connection_state to CS_SIDELOAD\n"); - t->connection_state = CS_SIDELOAD; - update_transports(); - return; - } - - t->connection_state = CS_HOST; -} - -void handle_packet(apacket *p, atransport *t) -{ - asocket *s; - - D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0], - ((char*) (&(p->msg.command)))[1], - ((char*) (&(p->msg.command)))[2], - ((char*) (&(p->msg.command)))[3]); - - print_packet("recv", p); - - switch(p->msg.command){ - case A_SYNC: - if(p->msg.arg0){ - send_packet(p, t); - if(HOST) send_connect(t); - } else { - t->connection_state = CS_OFFLINE; - handle_offline(t); - send_packet(p, t); - } - return; - - case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ - /* XXX verify version, etc */ - if(t->connection_state != CS_OFFLINE) { - t->connection_state = CS_OFFLINE; - handle_offline(t); - } - parse_banner((char*) p->data, t); - handle_online(); - if(!HOST) send_connect(t); - break; - - case A_OPEN: /* OPEN(local-id, 0, "destination") */ - if(t->connection_state != CS_OFFLINE) { - char *name = (char*) p->data; - name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; - s = create_local_service_socket(name); - if(s == 0) { - send_close(0, p->msg.arg0, t); - } else { - s->peer = create_remote_socket(p->msg.arg0, t); - s->peer->peer = s; - send_ready(s->id, s->peer->id, t); - s->ready(s); - } - } - break; - - case A_OKAY: /* READY(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - if(s->peer == 0) { - s->peer = create_remote_socket(p->msg.arg0, t); - s->peer->peer = s; - } - s->ready(s); - } - } - break; - - case A_CLSE: /* CLOSE(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - s->close(s); - } - } - break; - - case A_WRTE: - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - unsigned rid = p->msg.arg0; - p->len = p->msg.data_length; - - if(s->enqueue(s, p) == 0) { - D("Enqueue the socket\n"); - send_ready(s->id, rid, t); - } - return; - } - } - break; - - default: - printf("handle_packet: what is %08x?!\n", p->msg.command); - } - - put_apacket(p); -} - -alistener listener_list = { - .next = &listener_list, - .prev = &listener_list, -}; - -static void ss_listener_event_func(int _fd, unsigned ev, void *_l) -{ - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = sdb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - sdb_socket_setbufsize(fd, CHUNK_SIZE); - - s = create_local_socket(fd); - if(s) { - connect_to_smartsocket(s); - return; - } - - sdb_close(fd); - } -} - -static void listener_event_func(int _fd, unsigned ev, void *_l) -{ - alistener *l = _l; - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = sdb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - s = create_local_socket(fd); - if(s) { - s->transport = l->transport; - connect_to_remote(s, l->connect_to); - return; - } - - sdb_close(fd); - } -} - -static void free_listener(alistener* l) -{ - if (l->next) { - l->next->prev = l->prev; - l->prev->next = l->next; - l->next = l->prev = l; - } - - // closes the corresponding fd - fdevent_remove(&l->fde); - - if (l->local_name) - free((char*)l->local_name); - - if (l->connect_to) - free((char*)l->connect_to); - - if (l->transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - } - free(l); -} - -static void listener_disconnect(void* _l, atransport* t) -{ - alistener* l = _l; - - free_listener(l); -} - -int local_name_to_fd(const char *name) -{ - int port; - - if(!strncmp("tcp:", name, 4)){ - int ret; - port = atoi(name + 4); - ret = socket_loopback_server(port, SOCK_STREAM); - D("add loopback listen to %d", port); - return ret; - } - - printf("unknown local portname '%s'\n", name); - return -1; -} - -static int remove_listener(const char *local_name, const char *connect_to, atransport* transport) -{ - alistener *l; - - for (l = listener_list.next; l != &listener_list; l = l->next) { - if (!strcmp(local_name, l->local_name) && - !strcmp(connect_to, l->connect_to) && - l->transport && l->transport == transport) { - - listener_disconnect(l, transport); - return 0; - } - } - - return -1; -} - -static int install_listener(const char *local_name, const char *connect_to, atransport* transport) -{ - alistener *l; - - D("install_listener('%s','%s')\n", local_name, connect_to); - - for(l = listener_list.next; l != &listener_list; l = l->next){ - if(strcmp(local_name, l->local_name) == 0) { - char *cto; - - /* can't repurpose a smartsocket */ - if(l->connect_to[0] == '*') { - return -1; - } - - cto = strdup(connect_to); - if(cto == 0) { - return -1; - } - - //printf("rebinding '%s' to '%s'\n", local_name, connect_to); - free((void*) l->connect_to); - l->connect_to = cto; - if (l->transport != transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - l->transport = transport; - add_transport_disconnect(l->transport, &l->disconnect); - } - return 0; - } - } - - if((l = calloc(1, sizeof(alistener))) == 0) goto nomem; - if((l->local_name = strdup(local_name)) == 0) goto nomem; - if((l->connect_to = strdup(connect_to)) == 0) goto nomem; - - - l->fd = local_name_to_fd(local_name); - if(l->fd < 0) { - free((void*) l->local_name); - free((void*) l->connect_to); - free(l); - printf("cannot bind '%s'\n", local_name); - return -2; - } - - close_on_exec(l->fd); - if(!strcmp(l->connect_to, "*smartsocket*")) { - fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); - } else { - fdevent_install(&l->fde, l->fd, listener_event_func, l); - } - fdevent_set(&l->fde, FDE_READ); - - l->next = &listener_list; - l->prev = listener_list.prev; - l->next->prev = l; - l->prev->next = l; - l->transport = transport; - - if (transport) { - l->disconnect.opaque = l; - l->disconnect.func = listener_disconnect; - add_transport_disconnect(transport, &l->disconnect); - } - return 0; - -nomem: - fatal("cannot allocate listener"); - return 0; -} +static void local_init(int port); +static void init_wakeup_select_func(); #ifdef OS_WINDOWS static BOOL WINAPI ctrlc_handler(DWORD type) @@ -594,11 +50,65 @@ static BOOL WINAPI ctrlc_handler(DWORD type) } #endif -static void sdb_cleanup(void) +void sdb_cleanup(void) { sdb_usb_cleanup(); } +static void init_map() { + initialize_map(&event_map, EVENT_MAP_SIZE, NULL, NULL, no_free); + initialize_map(&hex_map, 16, NULL, NULL, no_free); + MAP_KEY key; + key.key_int = (int)'0'; + map_put(&hex_map, key, 0); + key.key_int = (int)'1'; + map_put(&hex_map, key, (void*)('1' - '0')); + key.key_int = (int)'2'; + map_put(&hex_map, key, (void*)('2' - '0')); + key.key_int = (int)'3'; + map_put(&hex_map, key, (void*)('3' - '0')); + key.key_int = (int)'4'; + map_put(&hex_map, key, (void*)('4' - '0')); + key.key_int = (int)'5'; + map_put(&hex_map, key, (void*)('5' - '0')); + key.key_int = (int)'6'; + map_put(&hex_map, key, (void*)('6' - '0')); + key.key_int = (int)'7'; + map_put(&hex_map, key, (void*)('7' - '0')); + key.key_int = (int)'8'; + map_put(&hex_map, key, (void*)('8' - '0')); + key.key_int = (int)'9'; + map_put(&hex_map, key, (void*)('9' - '0')); + key.key_int = (int)'a'; + map_put(&hex_map, key, (void*)10); + key.key_int = (int)'b'; + map_put(&hex_map, key, (void*)(10 + 'b' - 'a')); + key.key_int = (int)'c'; + map_put(&hex_map, key, (void*)(10 + 'c' - 'a')); + key.key_int = (int)'d'; + map_put(&hex_map, key, (void*)(10 + 'd' - 'a')); + key.key_int = (int)'e'; + map_put(&hex_map, key, (void*)(10 + 'e' - 'a')); + key.key_int = (int)'f'; + map_put(&hex_map, key, (void*)(10 + 'f' - 'a')); + key.key_int = (int)'A'; + map_put(&hex_map, key, (void*)10); + key.key_int = (int)'B'; + map_put(&hex_map, key, (void*)(10 + 'B' - 'A')); + key.key_int = (int)'C'; + map_put(&hex_map, key, (void*)(10 + 'C' - 'A')); + key.key_int = (int)'D'; + map_put(&hex_map, key, (void*)(10 + 'D' - 'A')); + key.key_int = (int)'E'; + map_put(&hex_map, key, (void*)(10 + 'E' - 'A')); + key.key_int = (int)'F'; + map_put(&hex_map, key, (void*)(10 + 'F' - 'A')); + +#if defined(OS_WINDOWS) + initialize_map(&sdb_handle_map, WIN32_MAX_FHS / 2, NULL, NULL, no_free); +#endif +} + /* Constructs a local name of form tcp:port. * target_str points to the target string, it's content will be overwritten. * target_size is the capacity of the target string. @@ -618,360 +128,64 @@ int sdb_main(int is_daemon, int server_port) signal(SIGPIPE, SIG_IGN); #endif - init_transport_registration(); + init_wakeup_select_func(); - HOST = 1; -// usb_vendors_init(); sdb_usb_init(); local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT); char local_name[30]; build_local_name(local_name, sizeof(local_name), server_port); if(install_listener(local_name, "*smartsocket*", NULL)) { - exit(1); + _exit(1); } - if (is_daemon) - { - // inform our parent that we are up and running. -#ifdef OS_WINDOWS - DWORD count; - WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL ); -#else - fprintf(stderr, "OK\n"); -#endif + if (is_daemon) { start_logging(); } - D("Event loop starting\n"); - - fdevent_loop(); + LOG_INFO("Event loop starting\n"); + FDEVENT_LOOP(); atexit(sdb_cleanup); - return 0; } -void connect_device(char* host, char* buffer, int buffer_size) +static void local_init(int port) { - int port, fd; - char* portstr = strchr(host, ':'); - char hostbuf[100]; - char serial[100]; - - strncpy(hostbuf, host, sizeof(hostbuf) - 1); - if (portstr) { - if (portstr - host >= sizeof(hostbuf)) { - snprintf(buffer, buffer_size, "bad host name %s", host); - return; - } - // zero terminate the host at the point we found the colon - hostbuf[portstr - host] = 0; - if (sscanf(portstr + 1, "%d", &port) == 0) { - snprintf(buffer, buffer_size, "bad port number %s", portstr); - return; - } - } else { + if(port < 1024) { port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT; } + int count = SDB_LOCAL_TRANSPORT_MAX; - snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port); - if (find_transport(serial)) { - snprintf(buffer, buffer_size, "already connected to %s", serial); - return; - } - - fd = socket_network_client(hostbuf, port, SOCK_STREAM); - if (fd < 0) { - snprintf(buffer, buffer_size, "unable to connect to %s", host); - return; + LOG_INFO("try to connect to emulator instances when booting sdb server up\n"); + for ( ; count > 0; count--, port += 10 ) { + (void) local_connect(port, NULL); } - - D("client: connected on remote on fd %d\n", fd); - close_on_exec(fd); - disable_tcp_nagle(fd); - register_socket_transport(fd, serial, port, 0, NULL); - snprintf(buffer, buffer_size, "connected to %s", serial); } -void connect_emulator(char* port_spec, char* buffer, int buffer_size) -{ - char* port_separator = strchr(port_spec, ','); - if (!port_separator) { - snprintf(buffer, buffer_size, - "unable to parse '%s' as ,", - port_spec); - return; - } - // Zero-terminate console port and make port_separator point to 2nd port. - *port_separator++ = 0; - int console_port = strtol(port_spec, NULL, 0); - int sdb_port = strtol(port_separator, NULL, 0); - if (!(console_port > 0 && sdb_port > 0)) { - *(port_separator - 1) = ','; - snprintf(buffer, buffer_size, - "Invalid port numbers: Expected positive numbers, got '%s'", - port_spec); - return; - } - - /* Check if the emulator is already known. - * Note: There's a small but harmless race condition here: An emulator not - * present just yet could be registered by another invocation right - * after doing this check here. However, local_connect protects - * against double-registration too. From here, a better error message - * can be produced. In the case of the race condition, the very specific - * error message won't be shown, but the data doesn't get corrupted. */ - atransport* known_emulator = find_emulator_transport_by_sdb_port(sdb_port); - if (known_emulator != NULL) { - snprintf(buffer, buffer_size, - "Emulator on port %d already registered.", sdb_port); - return; - } +void init_wakeup_select_func() { + D("initialize select wakeup func\n"); + int socket_pair[2]; - /* Check if more emulators can be registered. Similar unproblematic - * race condition as above. */ - int candidate_slot = get_available_local_transport_index(); - if (candidate_slot < 0) { - snprintf(buffer, buffer_size, "Cannot accept more emulators."); + if(sdb_socketpair(socket_pair)){ + D("cannot open select wakeup socketpair\n"); return; } + fdevent_wakeup_send = socket_pair[0]; + fdevent_wakeup_recv = socket_pair[1]; - /* Preconditions met, try to connect to the emulator. */ - if (!local_connect_arbitrary_ports(console_port, sdb_port, NULL)) { - snprintf(buffer, buffer_size, - "Connected to emulator on ports %d,%d", console_port, sdb_port); - } else { - snprintf(buffer, buffer_size, - "Could not connect to emulator on ports %d,%d", - console_port, sdb_port); - } -} - -int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s) -{ - atransport *transport = NULL; - char buf[4096]; - - if(!strcmp(service, "kill")) { - fprintf(stderr,"sdb server killed by remote request\n"); - fflush(stdout); - sdb_write(reply_fd, "OKAY", 4); - sdb_cleanup(); - exit(0); - } - - // "transport:" is used for switching transport with a specified serial number - // "transport-usb:" is used for switching transport to the only USB transport - // "transport-local:" is used for switching transport to the only local transport - // "transport-any:" is used for switching transport to the only transport - if (!strncmp(service, "transport", strlen("transport"))) { - char* error_string = "unknown failure"; - transport_type type = kTransportAny; - - if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { - type = kTransportUsb; - } else if (!strncmp(service, "transport-local", strlen("transport-local"))) { - type = kTransportLocal; - } else if (!strncmp(service, "transport-any", strlen("transport-any"))) { - type = kTransportAny; - } else if (!strncmp(service, "transport:", strlen("transport:"))) { - service += strlen("transport:"); - serial = service; - } - - transport = acquire_one_transport(CS_ANY, type, serial, &error_string); - - if (transport) { - s->transport = transport; - sdb_write(reply_fd, "OKAY", 4); - } else { - sendfailmsg(reply_fd, error_string); - } - return 1; - } - - // find a device which prefix match the partial serial num - // for example, there are two devices - // fjldsads9uq2oeu - // fjkuiaoejlfamck - // to make user's life more easier, it can specify a device with - // it's uniq prefix, in the above example, that means - // fjl <==> fjldsads9uq2oeu - // fjk <==> fjkuiaoejlfamck - if (!strncmp(service, "serial-match:", 13)) { - char *tmp = service + 13; - char *serial = NULL; - int ret = -1; - D("Try to find device for: %s\n", tmp); - ret = find_transports(&serial, tmp); - if (ret <= 0) { - D("No device found\n"); - snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(serial), serial); - } else if (ret == 1) { - D("found device: %s\n", serial); - snprintf(buf, sizeof(buf), "OKAY%04x%s", (unsigned)strlen(serial), serial); - } else { - D("found more than one devices matched: %d\n", ret); - snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(serial), serial); - } - - writex(reply_fd, buf, strlen(buf)); - free(serial); - return 0; - } - // return a list of all connected devices - if (!strcmp(service, "devices")) { - char buffer[4096]; - memset(buf, 0, sizeof(buf)); - memset(buffer, 0, sizeof(buffer)); - D("Getting device list \n"); - list_transports(buffer, sizeof(buffer)); - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer); - D("Wrote device list \n"); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - // add a new TCP transport, device or emulator - if (!strncmp(service, "connect:", 8)) { - char buffer[4096]; - char* host = service + 8; - if (!strncmp(host, "emu:", 4)) { - connect_emulator(host + 4, buffer, sizeof(buffer)); - } else { - connect_device(host, buffer, sizeof(buffer)); - } - // Send response for emulator and device - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - // remove TCP transport - if (!strncmp(service, "disconnect:", 11)) { - char buffer[4096]; - memset(buffer, 0, sizeof(buffer)); - char* serial = service + 11; - if (serial[0] == 0) { - // disconnect from all TCP devices - unregister_all_tcp_transports(); - } else { - char hostbuf[100]; - // assume port 26101 if no port is specified - if (!strchr(serial, ':')) { - snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:26101", serial); - serial = hostbuf; - } - atransport *t = find_transport(serial); - - if (t) { - unregister_transport(t); - } else { - snprintf(buffer, sizeof(buffer), "No such device %s", serial); - } - } - - snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - - // returns our value for SDB_SERVER_VERSION - if (!strcmp(service, "version")) { - char version[12]; - snprintf(version, sizeof version, "%04x", SDB_SERVER_VERSION); - snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version); - writex(reply_fd, buf, strlen(buf)); - return 0; - } + fdevent_install(&fdevent_wakeup_fde, + fdevent_wakeup_recv, + wakeup_select_func, + 0); - if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { - char *out = "unknown"; - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - if (transport && transport->serial) { - out = transport->serial; - } - snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - // indicates a new emulator instance has started - if (!strncmp(service,"emulator:",9)) { /* tizen specific */ - char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR); - int port = 0; - - if (tmp == NULL) { - port = atoi(service+9); - } else { - port = atoi(tmp); - tmp = strtok(NULL, DEVICEMAP_SEPARATOR); - if (tmp != NULL) { - local_connect(port, tmp); - } - } - local_connect(port, NULL); - return 0; - } - - if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) { - char *local, *remote, *err; - int r; - atransport *transport; - - int createForward = strncmp(service,"kill",4); - - local = service + (createForward ? 8 : 12); - remote = strchr(local,';'); - if(remote == 0) { - sendfailmsg(reply_fd, "malformed forward spec"); - return 0; - } - - *remote++ = 0; - if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){ - sendfailmsg(reply_fd, "malformed forward spec"); - return 0; - } - - transport = acquire_one_transport(CS_ANY, ttype, serial, &err); - if (!transport) { - sendfailmsg(reply_fd, err); - return 0; - } - - if (createForward) { - r = install_listener(local, remote, transport); - } else { - r = remove_listener(local, remote, transport); - } - if(r == 0) { - /* 1st OKAY is connect, 2nd OKAY is status */ - writex(reply_fd, "OKAYOKAY", 8); - return 0; - } - - if (createForward) { - sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket"); - } else { - sendfailmsg(reply_fd, "cannot remove listener"); - } - return 0; - } - - if(!strncmp(service,"get-state",strlen("get-state"))) { - transport = acquire_one_transport(CS_ANY, ttype, serial, NULL); - char *state = connection_state_name(transport); - snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state); - writex(reply_fd, buf, strlen(buf)); - return 0; - } - return -1; + FDEVENT_SET(&fdevent_wakeup_fde, FDE_READ); } int main(int argc, char **argv) { - sdb_trace_init(); + log_init(); sdb_sysdeps_init(); + init_map(); return process_cmdline(argc - 1, argv + 1); } diff --git a/src/sdb.h b/src/sdb.h index 16964b0..70733dc 100755 --- a/src/sdb.h +++ b/src/sdb.h @@ -19,393 +19,21 @@ #include +#include "linkedlist.h" #include "transport.h" /* readx(), writex() */ #include "sdb_usb.h" - -#define MAX_PAYLOAD 4096 - -#define A_SYNC 0x434e5953 -#define A_CNXN 0x4e584e43 -#define A_OPEN 0x4e45504f -#define A_OKAY 0x59414b4f -#define A_CLSE 0x45534c43 -#define A_WRTE 0x45545257 - -#define A_VERSION 0x01000000 // SDB protocol version - -#define SDB_VERSION_MAJOR 2 // Used for help/version information -#define SDB_VERSION_MINOR 2 // Used for help/version information - -#define SDB_SERVER_VERSION 5 // Increment this when we want to force users to start a new sdb server - -typedef struct amessage amessage; -typedef struct apacket apacket; -typedef struct asocket asocket; -typedef struct alistener alistener; -typedef struct aservice aservice; -typedef struct atransport atransport; -typedef struct adisconnect adisconnect; - -struct amessage { - unsigned command; /* command identifier constant */ - unsigned arg0; /* first argument */ - unsigned arg1; /* second argument */ - unsigned data_length; /* length of payload (0 is allowed) */ - unsigned data_check; /* checksum of data payload */ - unsigned magic; /* command ^ 0xffffffff */ -}; - -struct apacket -{ - apacket *next; - - unsigned len; - unsigned char *ptr; - - amessage msg; - unsigned char data[MAX_PAYLOAD]; -}; - -/* An asocket represents one half of a connection between a local and -** remote entity. A local asocket is bound to a file descriptor. A -** remote asocket is bound to the protocol engine. -*/ -struct asocket { - /* chain pointers for the local/remote list of - ** asockets that this asocket lives in - */ - asocket *next; - asocket *prev; - - /* the unique identifier for this asocket - */ - unsigned id; - - /* flag: set when the socket's peer has closed - ** but packets are still queued for delivery - */ - int closing; - - /* flag: quit sdbd when both ends close the - ** local service socket - */ - int exit_on_close; - - /* the asocket we are connected to - */ - - asocket *peer; - - /* For local asockets, the fde is used to bind - ** us to our fd event system. For remote asockets - ** these fields are not used. - */ - fdevent fde; - int fd; - - /* queue of apackets waiting to be written - */ - apacket *pkt_first; - apacket *pkt_last; - - /* enqueue is called by our peer when it has data - ** for us. It should return 0 if we can accept more - ** data or 1 if not. If we return 1, we must call - ** peer->ready() when we once again are ready to - ** receive data. - */ - int (*enqueue)(asocket *s, apacket *pkt); - - /* ready is called by the peer when it is ready for - ** us to send data via enqueue again - */ - void (*ready)(asocket *s); - - /* close is called by the peer when it has gone away. - ** we are not allowed to make any further calls on the - ** peer once our close method is called. - */ - void (*close)(asocket *s); - - /* socket-type-specific extradata */ - void *extra; - - /* A socket is bound to atransport */ - atransport *transport; -}; - - -/* the adisconnect structure is used to record a callback that -** will be called whenever a transport is disconnected (e.g. by the user) -** this should be used to cleanup objects that depend on the -** transport (e.g. remote sockets, listeners, etc...) -*/ -struct adisconnect -{ - void (*func)(void* opaque, atransport* t); - void* opaque; - adisconnect* next; - adisconnect* prev; -}; - - -/* a transport object models the connection to a remote device or emulator -** there is one transport per connected device/emulator. a "local transport" -** connects through TCP (for the emulator), while a "usb transport" through -** USB (for real devices) -** -** note that kTransportHost doesn't really correspond to a real transport -** object, it's a special value used to indicate that a client wants to -** connect to a service implemented within the SDB server itself. -*/ -typedef enum transport_type { - kTransportUsb, - kTransportLocal, - kTransportAny, - kTransportHost, -} transport_type; - -struct atransport -{ - atransport *next; - atransport *prev; - - int (*read_from_remote)(apacket *p, atransport *t); - int (*write_to_remote)(apacket *p, atransport *t); - void (*close)(atransport *t); - void (*kick)(atransport *t); - - int fd; - int transport_socket; - fdevent transport_fde; - int ref_count; - unsigned sync_token; - int connection_state; - transport_type type; - - /* usb handle or socket fd as needed */ - usb_handle *usb; - int sfd; - - /* used to identify transports for clients */ - char *serial; - char *product; - int sdb_port; // Use for emulators (local transport) - char *device_name; // for connection explorer - - /* a list of adisconnect callbacks called when the transport is kicked */ - int kicked; - adisconnect disconnects; -}; - - -/* A listener is an entity which binds to a local port -** and, upon receiving a connection on that port, creates -** an asocket to connect the new local connection to a -** specific remote service. -** -** TODO: some listeners read from the new connection to -** determine what exact service to connect to on the far -** side. -*/ -struct alistener -{ - alistener *next; - alistener *prev; - - fdevent fde; - int fd; - - const char *local_name; - const char *connect_to; - atransport *transport; - adisconnect disconnect; -}; - - -void print_packet(const char *label, apacket *p); - -asocket *find_local_socket(unsigned id); -void install_local_socket(asocket *s); -void remove_socket(asocket *s); -void close_all_sockets(atransport *t); - -#define LOCAL_CLIENT_PREFIX "emulator-" - -asocket *create_local_socket(int fd); -asocket *create_local_service_socket(const char *destination); - -asocket *create_remote_socket(unsigned id, atransport *t); -void connect_to_remote(asocket *s, const char *destination); -void connect_to_smartsocket(asocket *s); - -void fatal(const char *fmt, ...); -void fatal_errno(const char *fmt, ...); - -void handle_packet(apacket *p, atransport *t); -void send_packet(apacket *p, atransport *t); +#include "log.h" +#include "sdb_map.h" int sdb_main(int is_daemon, int server_port); - -/* transports are ref-counted -** get_device_transport does an acquire on your behalf before returning -*/ -void init_transport_registration(void); -int find_transports(char **serial, const char *prefix); -int list_transports(char *buf, size_t bufsize); -void update_transports(void); - -asocket* create_device_tracker(void); - -/* Obtain a transport from the available transports. -** If state is != CS_ANY, only transports in that state are considered. -** If serial is non-NULL then only the device with that serial will be chosen. -** If no suitable transport is found, error is set. -*/ -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); -void add_transport_disconnect( atransport* t, adisconnect* dis ); -void remove_transport_disconnect( atransport* t, adisconnect* dis ); -void run_transport_disconnects( atransport* t ); -void kick_transport( atransport* t ); - -/* initialize a transport object's func pointers and state */ -int get_available_local_transport_index(); -int init_socket_transport(atransport *t, int s, int port, int local); -void init_usb_transport(atransport *t, usb_handle *usb, int state); -void close_usb_devices(); - - -/* cause new transports to be init'd and added to the list */ -void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name); - -/* these should only be used for the "sdb disconnect" command */ -void unregister_transport(atransport *t); -void unregister_all_tcp_transports(); - -void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable); - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb); - -atransport *find_transport(const char *serial); -atransport* find_emulator_transport_by_sdb_port(int sdb_port); - -int service_to_fd(const char *name); -asocket *host_service_to_socket(const char* name, const char *serial); - -/* packet allocator */ -apacket *get_apacket(void); -void put_apacket(apacket *p); - -int check_header(apacket *p); -int check_data(apacket *p); - -/* define SDB_TRACE to 1 to enable tracing support, or 0 to disable it */ - -#define SDB_TRACE 1 - -/* IMPORTANT: if you change the following list, don't - * forget to update the corresponding 'tags' table in - * the sdb_trace_init() function implemented in sdb.c - */ -typedef enum { - TRACE_SDB = 0, - TRACE_SOCKETS, - TRACE_PACKETS, - TRACE_TRANSPORT, - TRACE_RWX, - TRACE_USB, - TRACE_SYNC, - TRACE_SYSDEPS, - TRACE_JDWP, - TRACE_SERVICES, - TRACE_PROPERTIES -} SdbTrace; - -#if SDB_TRACE - -#define DQ(...) ((void)0) - - - extern int sdb_trace_mask; - extern unsigned char sdb_trace_output_count; - void sdb_trace_init(void); - -# define SDB_TRACING ((sdb_trace_mask & (1 << TRACE_TAG)) != 0) - - /* you must define TRACE_TAG before using this macro */ -# define D(...) \ - do { \ - if (SDB_TRACING) { \ - int save_errno = errno; \ - sdb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - sdb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -# define DR(...) \ - do { \ - if (SDB_TRACING) { \ - int save_errno = errno; \ - sdb_mutex_lock(&D_lock); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - sdb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -#else -# define D(...) ((void)0) -# define DR(...) ((void)0) -# define SDB_TRACING 0 -#endif - - -#if !TRACE_PACKETS -#define print_packet(tag,p) do {} while (0) -#endif - - -/* sdb and sdbd are coexisting on the target, so use 26099 for sdb - * to avoid conflicting with sdbd's usage of 26098 - */ -#define DEFAULT_SDB_PORT 26099 /* tizen specific */ -#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 /* tizen specific */ - -void local_init(int port); -int local_connect(int port, const char *device_name); -int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name); - - unsigned host_to_le32(unsigned n); int sdb_commandline(int argc, char **argv); -int connection_state(atransport *t); +int connection_state(TRANSPORT *t); -#define CS_ANY -1 -#define CS_OFFLINE 0 -#define CS_BOOTLOADER 1 -#define CS_DEVICE 2 -#define CS_HOST 3 -#define CS_RECOVERY 4 -#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ -#define CS_SIDELOAD 6 - -extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; -#define CHUNK_SIZE (64*1024) - -int sendfailmsg(int fd, const char *reason); -int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); +void sdb_cleanup(void); -void register_device_name(const char *device_type, const char *device_name, int port); -int get_devicename_from_shdmem(int port, char *device_name); #endif diff --git a/src/sdb_client.c b/src/sdb_client.c index 62dadc3..74f22ff 100644 --- a/src/sdb_client.c +++ b/src/sdb_client.c @@ -25,34 +25,69 @@ #include "fdevent.h" #include "sdb_constants.h" #include "utils.h" +#include "strutils.h" #define TRACE_TAG TRACE_SDB #include "sdb_client.h" +#include "log.h" static int switch_socket_transport(int fd, void** extra_args); -static int send_service_with_length(int fd, const char* service); -static int sdb_status(int fd); +static int __inline__ write_msg_size(int fd, int size, int host_fd); -static int send_service_with_length(int fd, const char* service) { +void sendokmsg(int fd, const char *msg) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "OKAY%04x%s", (unsigned)strlen(msg), msg); + writex(fd, buf, strlen(buf)); +} + +void sendfailmsg(int fd, const char *reason) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(reason), reason); + writex(fd, buf, strlen(buf)); +} + +int send_service_with_length(int fd, const char* service, int host_fd) { int len; len = strlen(service); if(len < 1) { - fprintf(stderr,"error: service name is empty\n"); + if(host_fd == 0) { + fprintf(stderr,"error: service name is empty\n"); + } + else { + sendfailmsg(host_fd, "error: service name is empty\n"); + } return -1; } else if (len > 1024) { - fprintf(stderr,"error: service name too long\n"); + if(host_fd == 0) { + fprintf(stderr,"error: service name too long\n"); + } + else { + sendfailmsg(host_fd, "error: service name too long\n"); + } return -1; } - if(write_msg_size(fd, len) < 0) { + if(write_msg_size(fd, len, host_fd) < 0) { + D("fail to write msg size\n"); + if(host_fd != 0) { + sendfailmsg(host_fd, "fail to write msg size\n"); + } return -1; } if(writex(fd, service, len)) { - fprintf(stderr,"error: write failure during connection\n"); + D("error: write failure during connection\n"); + if(host_fd == 0) { + fprintf(stderr,"error: write failure during connection\n"); + } + else { + sendfailmsg(host_fd, "error: write failure during connection\n"); + } return -1; } @@ -68,19 +103,14 @@ static int switch_socket_transport(int fd, void** extra_args) get_host_prefix(service, sizeof service, ttype, serial, transport); - if(!strcmp(service, PREFIX_HOST)) { - // no switch necessary - return 0; - } - - if(send_service_with_length(fd, service) < 0) { + if(send_service_with_length(fd, service, 0) < 0) { sdb_close(fd); return -1; } D("Switch transport in progress\n"); - if(sdb_status(fd)) { + if(sdb_status(fd, 0)) { sdb_close(fd); D("Switch transport failed\n"); return -1; @@ -123,7 +153,7 @@ int sdk_launch_exist(void* extargv) { const char* expected_result = "/usr/sbin/sdk_launch"; - if(!strncmp(expected_result, query_result, sizeof(expected_result))) { + if(!strncmp(expected_result, query_result, strlen(expected_result))) { return 1; } return 0; @@ -172,14 +202,17 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) { null = strchr(ver_num, '-'); if(null == NULL) { - fprintf(stderr, "error: cannot parse sdbd version\n"); - return -1; + goto error; } *null = '\0'; D("sdbd version: %s\n", ver_num); null = strchr(ver_num, '.'); + if(null == NULL) { + goto error; + } + *null = '\0'; version = atoi(ver_num); if(version > first) { @@ -191,6 +224,10 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) { ver_num = ++null; null = strchr(ver_num, '.'); + if(null == NULL) { + goto error; + } + version = atoi(ver_num); *null = '\0'; if(version > middle) { @@ -206,14 +243,23 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) { return 1; } return 0; + +error: + LOG_ERROR("wrong version format %s", ver); + return -1; } -static int sdb_status(int fd) +int sdb_status(int fd, int host_fd) { unsigned char buf[5]; if(readx(fd, buf, 4)) { - fprintf(stderr,"error: protocol fault (no status)\n"); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (no status)\n"); + } + else { + sendfailmsg(host_fd, "error: protocol fault (no status)\n"); + } return -1; } @@ -222,53 +268,88 @@ static int sdb_status(int fd) } if(memcmp(buf, "FAIL", 4)) { - fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n", - buf[0], buf[1], buf[2], buf[3]); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n", + buf[0], buf[1], buf[2], buf[3]); + } + else { + char err_msg[255]; + snprintf(err_msg, sizeof(err_msg), "error: protocol fault (status %02x %02x %02x %02x?!)\n", + buf[0], buf[1], buf[2], buf[3]); + sendfailmsg(host_fd, err_msg); + } return -1; } int len = read_msg_size(fd); if(len < 0) { - fprintf(stderr,"error: protocol fault (status len)\n"); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (status len)\n"); + } + else { + sendfailmsg(host_fd, "error: protocol fault (status len)\n"); + } return -1; } - if(len > 255) len = 255; + if(len > 254) len = 254; char error[255]; if(readx(fd, error, len)) { - fprintf(stderr,"error: protocol fault (status read)\n"); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (status read)\n"); + } + else { + sendfailmsg(host_fd, "error: protocol fault (status read)\n"); + } return -1; } error[len] = '\0'; - fprintf(stderr,"error: %s\n", error); + if(host_fd == 0) { + fprintf(stderr,"error msg: %s\n", error); + } + else { + char err_msg[255]; + snprintf(err_msg, sizeof(err_msg), "error msg: %s\n", error); + sendfailmsg(host_fd, err_msg); + } return -1; } +/** + * First check whether host service or transport service, + * If transport service, send transport prefix. Then, do the service. + * If host service, do the service. does not have to get transport. + */ int _sdb_connect(const char *service, void** ext_args) { int fd; D("_sdb_connect: %s\n", service); + if (!strcmp(service, "host:start-server")) { + return 0; + } + int server_port = *(int*)ext_args[2]; - fd = socket_loopback_client(server_port, SOCK_STREAM); + fd = sdb_host_connect("127.0.0.1", server_port, SOCK_STREAM); if(fd < 0) { D("error: cannot connect to daemon\n"); return -2; } + //If service is not host, send transport_prefix if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd, ext_args)) { return -1; } - if(send_service_with_length(fd, service) < 0) { + if(send_service_with_length(fd, service, 0) < 0) { sdb_close(fd); return -1; } - if(sdb_status(fd)) { + if(sdb_status(fd, 0)) { sdb_close(fd); return -1; } @@ -277,7 +358,7 @@ int _sdb_connect(const char *service, void** ext_args) return fd; } -int __inline__ read_msg_size(int fd) { +int read_msg_size(int fd) { char buf[5]; if(readx(fd, buf, 4)) { @@ -288,78 +369,106 @@ int __inline__ read_msg_size(int fd) { return strtoul(buf, NULL, 16); } -int __inline__ write_msg_size(int fd, int size) { +static int __inline__ write_msg_size(int fd, int size, int host_fd) { char tmp[5]; snprintf(tmp, sizeof tmp, "%04x", size); if(writex(fd, tmp, 4)) { - fprintf(stderr,"error: write msg size failure\n"); + D("error: write msg size failure\n"); + if(host_fd == 0) { + fprintf(stderr,"error: write msg size failure\n"); + } + else { + sendfailmsg(host_fd, "error: write msg size failure\n"); + } return -1; } return 1; } +/** + * First, check the host version. + * Then, send the service using _sdb_connect + */ int sdb_connect(const char *service, void** ext_args) { - // first query the sdb server's version + // check version before sending a sdb command int fd = _sdb_connect("host:version", ext_args); int server_port = *(int*)ext_args[2]; D("sdb_connect: service %s\n", service); - if(fd == -2) { - fprintf(stdout,"* daemon not running. starting it now on port %d *\n", - server_port); - start_server: - if(launch_server(server_port)) { - fprintf(stderr,"* failed to start daemon *\n"); + + if (fd >= 0) { + int len = read_msg_size(fd); + char buf[SDB_VERSION_MAX_LENGTH] = {0,}; + int restarting = 0; + if (len < 0) { + sdb_close(fd); return -1; - } else { - fprintf(stdout,"* daemon started successfully *\n"); } - /* give the server some time to start properly and detect devices */ - sdb_sleep_ms(3000); - // fall through to _sdb_connect - } else { - // if server was running, check its version to make sure it is not out of date - 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, len) != 0 ){ sdb_close(fd); + return -1; + } + sdb_close(fd); + char *tokens[3]; + size_t cnt = tokenize(buf, ".", tokens, 3); + + if (cnt == 3) { // since tizen2.2.1 rc 15 + int major = strtoul(tokens[0], 0, 10); + int minor = strtoul(tokens[1], 0, 10); + int patch = strtoul(tokens[2], 0, 10); + if (major != SDB_VERSION_MAJOR || minor != SDB_VERSION_MINOR || patch != SDB_VERSION_PATCH ) { + fprintf(stdout, + "* sdb (%s) already running, and restarting sdb(%d.%d.%d) again *\n", + buf, SDB_VERSION_MAJOR, SDB_VERSION_MINOR, + SDB_VERSION_PATCH); + restarting = 1; + } } else { - return fd; + int ver = 0; + if (sscanf(buf, "%04x", &ver) != 1) { + LOG_ERROR("version format is wrong:%s\n", buf); + // restart anyway! + restarting = 1; + } else { + if (ver != SDB_VERSION_PATCH) { + fprintf(stdout, + "* another version of sdb already running, and restarting sdb(%d.%d.%d) again *\n", + SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_VERSION_PATCH); + restarting = 1; + } + } } - - if(version != SDB_SERVER_VERSION) { - printf("sdb server is out of date. killing...\n"); - fd = _sdb_connect("host:kill", ext_args); - sdb_close(fd); - - /* XXX can we better detect its death? */ + if (restarting) { + if (cnt) { + free_strings(tokens, cnt); + } + int fd2 = _sdb_connect("host:kill", ext_args); + sdb_close(fd2); sdb_sleep_ms(2000); - goto start_server; + goto launch_server; } } - // if the command is start-server, we are done. - if (!strcmp(service, "host:start-server")) - return 0; + if(fd == -2) { + fprintf(stdout,"* daemon not running. starting it now on port %d *\n", server_port); +launch_server: + if(launch_server()) { + fprintf(stderr,"* failed to start daemon *\n"); + return -1; + } else { + fprintf(stdout,"* daemon started successfully *\n"); + } + } fd = _sdb_connect(service, ext_args); if(fd == -2) { - fprintf(stderr,"** daemon still not running"); + fprintf(stderr,"** daemon still not running\n"); } - D("sdb_connect: return fd %d\n", fd); + D("sdb_connect: return fd %d\n", fd); return fd; -error: - sdb_close(fd); - return -1; } @@ -370,7 +479,7 @@ int sdb_command(const char *service, void** extra_args) return -1; } - if(sdb_status(fd)) { + if(sdb_status(fd, 0)) { sdb_close(fd); return -1; } @@ -418,7 +527,7 @@ void get_host_prefix(char* prefix, int size, transport_type ttype, const char* s } } else { - char* temp_prefix; + char* temp_prefix = NULL; if(ttype == kTransportUsb) { if(host_type == host) { temp_prefix = (char*)PREFIX_HOST_USB; @@ -435,12 +544,9 @@ void get_host_prefix(char* prefix, int size, transport_type ttype, const char* s temp_prefix = (char*)PREFIX_TRANSPORT_LOCAL; } } - else if(ttype == kTransportHost) { - temp_prefix = (char*)PREFIX_HOST; - } else if(ttype == kTransportAny) { if(host_type == host) { - temp_prefix = (char*)PREFIX_HOST; + temp_prefix = (char*)PREFIX_HOST_ANY; } else if(host_type == transport) { temp_prefix = (char*)PREFIX_TRANSPORT_ANY; diff --git a/src/sdb_client.h b/src/sdb_client.h index 04d9da2..31be98e 100644 --- a/src/sdb_client.h +++ b/src/sdb_client.h @@ -17,12 +17,15 @@ #ifndef _SDB_CLIENT_H_ #define _SDB_CLIENT_H_ -#include "sdb.h" #include "sdb_constants.h" +#include "common_modules.h" // debug launch pad is applied after sdbd 2.2.3 #define SDB_HIGHER_THAN_2_2_3(extargv) sdk_launch_exist(extargv) +int send_service_with_length(int fd, const char* service, int host_fd); +int sdb_status(int fd, int host_fd); + /* connect to sdb, connect to the named service, and return ** a valid fd for interacting with that service upon success ** or a negative number on failure @@ -64,8 +67,10 @@ int sdk_launch_exist(void* extargv); ** return 0 in the event of OKAY, -1 in the event of FAIL ** or protocol error */ -int __inline__ read_msg_size(int fd); -int __inline__ write_msg_size(int fd, int size); +int read_msg_size(int fd); + +void sendokmsg(int fd, const char *msg); +void sendfailmsg(int fd, const char *reason); void get_host_prefix(char* prefix, int size, transport_type ttype, const char* serial, HOST_TYPE host_type); #endif diff --git a/src/sdb_constants.c b/src/sdb_constants.c index 0c4acc9..57a9e63 100644 --- a/src/sdb_constants.c +++ b/src/sdb_constants.c @@ -35,6 +35,7 @@ const char* QUOTE_CHAR = " \"\\()"; const char* PREFIX_HOST = "host:"; + const char* PREFIX_HOST_ANY = "host-any:"; const char* PREFIX_HOST_USB = "host-usb:"; const char* PREFIX_HOST_LOCAL = "host-local:"; const char* PREFIX_HOST_SERIAL = "host-serial:"; @@ -87,6 +88,15 @@ const int COMMANDLINE_CONNECT_MAX_ARG = 1; const int COMMANDLINE_CONNECT_MIN_ARG = 1; + const char* COMMANDLINE_DEVICE_CON_NAME = "device_con"; + const char* COMMANDLINE_DEVICE_CON_DESC[] = { + "connect to a remote device" + }; + const int COMMANDLINE_DEVICE_CON_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DEVICE_CON_DESC, char*); + const char* COMMANDLINE_DEVICE_CON_ARG_DESC = " "; + const int COMMANDLINE_DEVICE_CON_MAX_ARG = 2; + const int COMMANDLINE_DEVICE_CON_MIN_ARG = 2; + const char* COMMANDLINE_GSERIAL_NAME = "get-serialno"; const char* COMMANDLINE_GSERIAL_DESC[] = { "print: " @@ -97,7 +107,7 @@ const char* COMMANDLINE_GSTATE_NAME = "get-state"; const char* COMMANDLINE_GSTATE_DESC[] = { - "print: offline | bootloader | device" + "print: offline | locked | device" }; const int COMMANDLINE_GSTATE_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_GSTATE_DESC, char*); const int COMMANDLINE_GSTATE_MAX_ARG = 0; @@ -249,3 +259,19 @@ const int COMMANDLINE_EMULATOR_HAS_ARG = 0; const char* COMMANDLINE_ERROR_ARG_MISSING = "argument %s is missing for command %s"; + + const char* STATE_OFFLINE = "offline"; + const char* STATE_BOOTLOADER = "bootloader"; + const char* STATE_DEVICE = "device"; + const char* STATE_HOST = "host"; + const char* STATE_RECOVERY = "recovery"; + const char* STATE_SIDELOAD = "sideload"; + const char* STATE_NOPERM = "no permissions"; + const char* STATE_LOCKED = "locked"; + const char* STATE_UNKNOWN = "unknown"; + + const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET = "more than one target"; + const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL = "more than one emulator"; + const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV = "more than one device"; + const char* TRANSPORT_ERR_TARGET_OFFLINE = "target offline"; + const char* TRANSPORT_ERR_TARGET_NOT_FOUND = "target not found"; diff --git a/src/sdb_constants.h b/src/sdb_constants.h index caa88da..d0dda55 100644 --- a/src/sdb_constants.h +++ b/src/sdb_constants.h @@ -46,6 +46,7 @@ typedef enum host_type HOST_TYPE; extern const char* QUOTE_CHAR; extern const char* PREFIX_HOST; + extern const char* PREFIX_HOST_ANY; extern const char* PREFIX_HOST_USB; extern const char* PREFIX_HOST_LOCAL; extern const char* PREFIX_HOST_SERIAL; @@ -89,6 +90,13 @@ typedef enum host_type HOST_TYPE; extern const int COMMANDLINE_CONNECT_MAX_ARG; extern const int COMMANDLINE_CONNECT_MIN_ARG; + extern const char* COMMANDLINE_DEVICE_CON_NAME; + extern const char* COMMANDLINE_DEVICE_CON_DESC[]; + extern const int COMMANDLINE_DEVICE_CON_DESC_SIZE; + extern const char* COMMANDLINE_DEVICE_CON_ARG_DESC; + extern const int COMMANDLINE_DEVICE_CON_MAX_ARG; + extern const int COMMANDLINE_DEVICE_CON_MIN_ARG; + extern const char* COMMANDLINE_GSERIAL_NAME; extern const char* COMMANDLINE_GSERIAL_DESC[]; extern const int COMMANDLINE_GSERIAL_DESC_SIZE; @@ -210,4 +218,20 @@ typedef enum host_type HOST_TYPE; extern const char* COMMANDLINE_ERROR_ARG_MISSING; + extern const char* STATE_OFFLINE; + extern const char* STATE_BOOTLOADER; + extern const char* STATE_DEVICE; + extern const char* STATE_HOST; + extern const char* STATE_RECOVERY; + extern const char* STATE_SIDELOAD; + extern const char* STATE_NOPERM; + extern const char* STATE_LOCKED; + extern const char* STATE_UNKNOWN; + + extern const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET; + extern const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL; + extern const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV; + extern const char* TRANSPORT_ERR_TARGET_OFFLINE; + extern const char* TRANSPORT_ERR_TARGET_NOT_FOUND; + #endif /* SDB_CONSTANTS_H_*/ diff --git a/src/sdb_map.c b/src/sdb_map.c new file mode 100644 index 0000000..58577bb --- /dev/null +++ b/src/sdb_map.c @@ -0,0 +1,154 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* 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 +#include "sdb_map.h" +#include "linkedlist.h" + +static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key); +static int default_hash(MAP* this, MAP_KEY key); +static int default_equal(MAP_KEY key, MAP_KEY node_key); +static void default_free(void* node); + +void initialize_map(MAP* this, int size, int(*hash)(struct map* this, MAP_KEY key), + int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data)) { + + if(size < 1) { + this->size = DEFAULT_MAP_SIZE; + } + else { + this->size = size; + } + + if(equal == NULL) { + this->equal = default_equal; + } + else { + this->equal = equal; + } + + if(hash == NULL) { + this->hash = default_hash; + } + else { + this->hash = hash; + } + + if(freedata == NULL) { + this->freedata = default_free; + } + else { + this->freedata = freedata; + } + + this->map_node_list = (LIST_NODE**)calloc(this->size, sizeof(LIST_NODE*)); +} + +static void default_free(void* node) { + MAP_NODE* _node = node; + if(_node != NULL) { + if(_node->value != NULL ) { +// free(_node->value); + } + free(_node); + } +} + +static int default_hash(MAP* this, MAP_KEY key) { + return key.key_int%(this->size); +} + +static int default_equal(MAP_KEY key, MAP_KEY node_key) { + if(key.key_int != node_key.key_int) { + return 0; + } + return 1; +} + +static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key) { + + while(list != NULL) { + MAP_NODE* node = list->data; + if(this->equal(key, node->key)) { + return list; + } + list = list->next_ptr; + } + + return NULL; +} + +void map_put(MAP* this, MAP_KEY key, void* value) { + + int hash_key = this->hash(this, key); + LIST_NODE** hash_list = &(this->map_node_list[hash_key]); + + MAP_NODE* node = malloc(sizeof(MAP_NODE)); + node->key = key; + node->value = value; + + LIST_NODE* list_node = find_in_list(this, *hash_list, key); + if(list_node == NULL) { + prepend(hash_list, (void*)node); + } + else { + this->freedata(list_node->data); + list_node->data = node; + } +} + +void* map_get(MAP* this, MAP_KEY key) { + + int hash_key = this->hash(this, key); + LIST_NODE* hash_list = this->map_node_list[hash_key]; + LIST_NODE* result_node = find_in_list(this, hash_list, key); + if(result_node == NULL) { + return NULL; + } + + return ((MAP_NODE*)(result_node->data))->value; +} + +void map_remove(MAP* this, MAP_KEY key) { + + int hash_key = this->hash(this, key); + LIST_NODE** hash_list = &(this->map_node_list[hash_key]); + + LIST_NODE* result_node = find_in_list(this, *hash_list, key); + remove_node(hash_list, result_node, this->freedata); +} + +void map_clear(MAP* this) { + + if(this != NULL) { + int i =0; + for(; isize; i++) { + free_list(this->map_node_list[i], this->freedata); + } + + free(this->map_node_list); + } +} diff --git a/src/sdb_map.h b/src/sdb_map.h new file mode 100644 index 0000000..4af7bb9 --- /dev/null +++ b/src/sdb_map.h @@ -0,0 +1,62 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef SDB_MAP_H_ +#define SDB_MAP_H_ + +#include "linkedlist.h" + +#define DEFAULT_MAP_SIZE 30 + +union map_key { + int key_int; + void* key_void; +}; + +typedef union map_key MAP_KEY; + +struct map_node { + MAP_KEY key; + void* value; +}; +typedef struct map_node MAP_NODE; + +struct map { + int size; + int(*hash)(struct map* this, MAP_KEY key); + int(*equal)(MAP_KEY key, MAP_KEY node_key); + void(*freedata)(void* data); + LIST_NODE** map_node_list; +}; +typedef struct map MAP; + +void initialize_map(MAP* map, int size, int(*hash)(struct map* this, MAP_KEY key), + int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data)); +void map_put(MAP* map, MAP_KEY key, void* value); +void* map_get(MAP* map, MAP_KEY key); +void map_remove(MAP* this, MAP_KEY key); + +#endif /* SDB_MAP_H_ */ diff --git a/src/sdb_model.c b/src/sdb_model.c index 8b6162c..203def1 100644 --- a/src/sdb_model.c +++ b/src/sdb_model.c @@ -31,7 +31,7 @@ #include "fdevent.h" #include "sdb_model.h" #include "linkedlist.h" -#include "sdb.h" +#include "log.h" const COMMAND NULL_COMMAND = { NULL, @@ -157,7 +157,7 @@ int parse_opt(int argc, char** argv, LIST_NODE* opt_list, LIST_NODE** result_lis INPUT_OPTION* input = (INPUT_OPTION*)malloc(sizeof(INPUT_OPTION)); input->option = option; input->value = value; - append(result_list, input); + prepend(result_list, input); argv = argv + local_pass_arg; argc = argc - local_pass_arg; diff --git a/src/sdb_usb.c b/src/sdb_usb.c deleted file mode 100755 index 8abea36..0000000 --- a/src/sdb_usb.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#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(dev->descriptor.idVendor, 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; -} - -#ifdef _USE_UDEV_ - -#include -#include -#include -#include -#include - -int udev_notify(void) -{ - struct udev *udev; - struct udev_enumerate *enumerate; - struct udev_list_entry *devices, *dev_list_entry; - struct udev_device *dev; - - struct udev_monitor *mon; - int fd; - - /* Create the udev object */ - udev = udev_new(); - if (!udev) { - printf("Can't create udev\n"); - exit(1); - } - - /* This section sets up a monitor which will report events when - devices attached to the system change. Events include "add", - "remove", "change", "online", and "offline". - - This section sets up and starts the monitoring. Events are - polled for (and delivered) later in the file. - - It is important that the monitor be set up before the call to - udev_enumerate_scan_devices() so that events (and devices) are - not missed. For example, if enumeration happened first, there - would be no event generated for a device which was attached after - enumeration but before monitoring began. - - Note that a filter is added so that we only get events for - "hidraw" devices. */ - - /* Set up a monitor to monitor hidraw devices */ - mon = udev_monitor_new_from_netlink(udev, "udev"); - udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device"); - udev_monitor_enable_receiving(mon); - /* Get the file descriptor (fd) for the monitor. - This fd will get passed to select() */ - fd = udev_monitor_get_fd(mon); - - - /* Create a list of the devices in the 'hidraw' subsystem. */ - enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(enumerate, "usb"); - udev_enumerate_scan_devices(enumerate); - - - devices = udev_enumerate_get_list_entry(enumerate); - /* For each item enumerated, print out its information. - udev_list_entry_foreach is a macro which expands to - a loop. The loop will be executed for each member in - devices, setting dev_list_entry to a list entry - which contains the device's path in /sys. */ - udev_list_entry_foreach(dev_list_entry, devices) { - const char *path; - - /* Get the filename of the /sys entry for the device - and create a udev_device object (dev) representing it */ - path = udev_list_entry_get_name(dev_list_entry); - dev = udev_device_new_from_syspath(udev, path); - - /* usb_device_get_devnode() returns the path to the device node - itself in /dev. */ - printf("Device Node Path: %s\n", udev_device_get_devnode(dev)); - - /* The device pointed to by dev contains information about - the hidraw device. In order to get information about the - USB device, get the parent device with the - subsystem/devtype pair of "usb"/"usb_device". This will - be several levels up the tree, but the function will find - it.*/ - /*dev = udev_device_get_parent_with_subsystem_devtype( - dev, - "usb", - "usb_device"); - if (!dev) { - printf("Unable to find parent usb device."); - exit(1); - }*/ - - /* From here, we can call get_sysattr_value() for each file - in the device's /sys entry. The strings passed into these - functions (idProduct, idVendor, serial, etc.) correspond - directly to the files in the /sys directory which - represents the USB device. Note that USB strings are - Unicode, UCS2 encoded, but the strings returned from - udev_device_get_sysattr_value() are UTF-8 encoded. */ - printf(" VID/PID: %s %s\n", - udev_device_get_sysattr_value(dev,"idVendor"), - udev_device_get_sysattr_value(dev, "idProduct")); - printf(" %s\n %s\n", - udev_device_get_sysattr_value(dev,"manufacturer"), - udev_device_get_sysattr_value(dev,"product")); - printf(" serial: %s\n", - udev_device_get_sysattr_value(dev, "serial")); - udev_device_unref(dev); - } - /* Free the enumerator object */ - udev_enumerate_unref(enumerate); - - /* Begin polling for udev events. Events occur when devices - attached to the system are added, removed, or change state. - udev_monitor_receive_device() will return a device - object representing the device which changed and what type of - change occured. - - The select() system call is used to ensure that the call to - udev_monitor_receive_device() will not block. - - The monitor was set up earler in this file, and monitoring is - already underway. - - This section will run continuously, calling usleep() at the end - of each pass. This is to demonstrate how to use a udev_monitor - in a non-blocking way. */ - while (1) { - /* Set up the call to select(). In this case, select() will - only operate on a single file descriptor, the one - associated with our udev_monitor. Note that the timeval - object is set to 0, which will cause select() to not - block. */ - fd_set fds; - struct timeval tv; - int ret; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - tv.tv_sec = 0; - tv.tv_usec = 0; - - ret = select(fd+1, &fds, NULL, NULL, &tv); - - /* Check if our file descriptor has received data. */ - if (ret > 0 && FD_ISSET(fd, &fds)) { - printf("\nselect() says there should be data\n"); - - /* Make the call to receive the device. - select() ensured that this will not block. */ - dev = udev_monitor_receive_device(mon); - if (dev) { - printf("Got Device\n"); - printf(" Node: %s\n", udev_device_get_devnode(dev)); - printf(" Subsystem: %s\n", udev_device_get_subsystem(dev)); - printf(" Devtype: %s\n", udev_device_get_devtype(dev)); - - printf(" Action: %s\n", udev_device_get_action(dev)); - udev_device_unref(dev); - } - else { - printf("No Device from receive_device(). An error occured.\n"); - } - } - usleep(250*1000); - printf("."); - fflush(stdout); - } - - - udev_unref(udev); - - return 0; -} - -#endif diff --git a/src/sdb_usb.h b/src/sdb_usb.h index 9d55a09..533bcec 100755 --- a/src/sdb_usb.h +++ b/src/sdb_usb.h @@ -37,4 +37,5 @@ void kick_disconnected_devices(); */ #define MAX_READ_WRITE (16 * 1024) +#define MAX_SERIAL_NAME 128 #endif // __USB_H diff --git a/src/services.c b/src/services.c deleted file mode 100755 index 0b82a68..0000000 --- a/src/services.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include "utils.h" -#include "fdevent.h" - -#define TRACE_TAG TRACE_SERVICES -#include "sdb.h" -#include "file_sync_service.h" - -# ifndef OS_WINDOWS -# include -# include -# include -# endif - -typedef struct stinfo stinfo; - -struct stinfo { - void (*func)(int fd, void *cookie); - int fd; - void *cookie; -}; - - -void *service_bootstrap_func(void *x) -{ - stinfo *sti = x; - sti->func(sti->fd, sti->cookie); - free(sti); - return 0; -} - -SDB_MUTEX_DEFINE( dns_lock ); - -static int create_service_thread(void (*func)(int, void *), void *cookie) -{ - stinfo *sti; - sdb_thread_t t; - int s[2]; - - if(sdb_socketpair(s)) { - printf("cannot create service socket pair\n"); - return -1; - } - - sti = malloc(sizeof(stinfo)); - if(sti == 0) fatal("cannot allocate stinfo"); - sti->func = func; - sti->cookie = cookie; - sti->fd = s[1]; - - if(sdb_thread_create( &t, service_bootstrap_func, sti)){ - free(sti); - sdb_close(s[0]); - sdb_close(s[1]); - printf("cannot create service thread\n"); - return -1; - } - - D("service thread started, %d:%d\n",s[0], s[1]); - return s[0]; -} - -int service_to_fd(const char *name) -{ - int ret = -1; - - if(!strncmp(name, "tcp:", 4)) { - int port = atoi(name + 4); - name = strchr(name + 4, ':'); - if(name == 0) { - ret = socket_loopback_client(port, SOCK_STREAM); - if (ret >= 0) - disable_tcp_nagle(ret); - } else { - - sdb_mutex_lock(&dns_lock); - ret = socket_network_client(name + 1, port, SOCK_STREAM); - sdb_mutex_unlock(&dns_lock); - } - } - if (ret >= 0) { - close_on_exec(ret); - } - return ret; -} - -struct state_info { - transport_type transport; - char* serial; - int state; -}; - -static void wait_for_state(int fd, void* cookie) -{ - struct state_info* sinfo = cookie; - char* err = "unknown error"; - - D("wait_for_state %d\n", sinfo->state); - - atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err); - if(t != 0) { - writex(fd, "OKAY", 4); - } else { - sendfailmsg(fd, err); - } - - if (sinfo->serial) - free(sinfo->serial); - free(sinfo); - sdb_close(fd); - D("wait_for_state is done\n"); -} - -asocket* host_service_to_socket(const char* name, const char *serial) -{ - if (!strcmp(name,"track-devices")) { - return create_device_tracker(); - } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) { - struct state_info* sinfo = malloc(sizeof(struct state_info)); - - if (serial) - sinfo->serial = strdup(serial); - else - sinfo->serial = NULL; - - name += strlen("wait-for-"); - - if (!strncmp(name, "local", strlen("local"))) { - sinfo->transport = kTransportLocal; - sinfo->state = CS_DEVICE; - } else if (!strncmp(name, "usb", strlen("usb"))) { - sinfo->transport = kTransportUsb; - sinfo->state = CS_DEVICE; - } else if (!strncmp(name, "any", strlen("any"))) { - sinfo->transport = kTransportAny; - sinfo->state = CS_DEVICE; - } else { - free(sinfo); - return NULL; - } - - int fd = create_service_thread(wait_for_state, sinfo); - return create_local_socket(fd); - } - return NULL; -} - diff --git a/src/sockets.c b/src/sockets.c old mode 100644 new mode 100755 index b4e27e8..57be928 --- a/src/sockets.c +++ b/src/sockets.c @@ -23,800 +23,1152 @@ #include "utils.h" #include "fdevent.h" #include "sdb_constants.h" - -#define TRACE_TAG TRACE_SOCKETS +#include "sdb_map.h" +#include "sdb_client.h" +#include "sockets.h" +#include "transport.h" +#include "log.h" +#include "listener.h" #include "sdb.h" -SDB_MUTEX_DEFINE( socket_list_lock ); - -static void local_socket_close_locked(asocket *s); - -int sendfailmsg(int fd, const char *reason) -{ - char buf[9]; - int len; - len = strlen(reason); - if(len > 0xffff) len = 0xffff; - snprintf(buf, sizeof buf, "FAIL%04x", len); - if(writex(fd, buf, 8)) return -1; - return writex(fd, reason, len); -} +#define TRACE_TAG TRACE_SOCKETS -//extern int online; +static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p); +static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func); +static int peer_enqueue(SDB_SOCKET* socket, PACKET* p); +static void local_socket_destroy(SDB_SOCKET *s); +static void remove_socket(void* s); +static void destroy_socket(void* data); +static void local_socket_event_func(int fd, unsigned ev, void *_s); +static unsigned unhex(unsigned char*s, int len); +static int find_transports(char **serial_out, const char *prefix); +static void unregister_all_tcp_transports(); +static void connect_emulator(char* host, int port, char* buf, int buf_len); + +const unsigned int unsigned_int_bit = sizeof(unsigned int) * 8; +const unsigned int remote_con_right_padding = ~(~0 << sizeof(unsigned int) * 4); +const unsigned int remote_con_flag = 1 << (sizeof(unsigned int) * 8 - 1); +unsigned int remote_con_cur_r_id = 1; +unsigned int remote_con_cur_l_number = 0; +const unsigned int remote_con_l_max = 16; // Ox1111 +const unsigned int remote_con_r_max = ~(~0 << (sizeof(unsigned int) * 8 - 5)); +unsigned int remote_con_l_table[16] = {0,}; static unsigned local_socket_next_id = 1; -static asocket local_socket_list = { - .next = &local_socket_list, - .prev = &local_socket_list, -}; - -/* the the list of currently closing local sockets. -** these have no peer anymore, but still packets to -** write to their fd. -*/ -static asocket local_socket_closing_list = { - .next = &local_socket_closing_list, - .prev = &local_socket_closing_list, -}; - -asocket *find_local_socket(unsigned id) +LIST_NODE* local_socket_list = NULL; + +SDB_SOCKET *find_local_socket(unsigned id) { - asocket *s; - asocket *result = NULL; + SDB_SOCKET *result = NULL; + - sdb_mutex_lock(&socket_list_lock); - for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { - if (s->id == id) { + LIST_NODE* curptr = local_socket_list; + while(curptr != NULL) { + SDB_SOCKET* s = curptr->data; + curptr = curptr->next_ptr; + if(s->local_id == id) { result = s; break; } } - sdb_mutex_unlock(&socket_list_lock); return result; } -static void -insert_local_socket(asocket* s, asocket* list) +static void remove_socket(void* s) { - s->next = list; - s->prev = s->next->prev; - s->prev->next = s; - s->next->prev = s; + SDB_SOCKET* socket = s; + socket->node = NULL; } - -void install_local_socket(asocket *s) +int local_socket_enqueue(SDB_SOCKET *s, PACKET *p) { - sdb_mutex_lock(&socket_list_lock); + D("LS(%X) local enqueue\n", s->local_id); - s->id = local_socket_next_id++; - insert_local_socket(s, &local_socket_list); + if(s->pkt_list == NULL) { + int r = local_enqueue(s->fd, p, s, 0); + if( r == 0) { + //enqueue done normally + return 0; + } + if( r < 0) { + //error occurred + return 1; + } + } + //wait for next round + append(&(s->pkt_list), p); + FDEVENT_ADD(&s->fde, FDE_WRITE); - sdb_mutex_unlock(&socket_list_lock); + return 1; } -void remove_socket(asocket *s) +void local_socket_ready(SDB_SOCKET *s) { - // socket_list_lock should already be held - if (s->prev && s->next) - { - s->prev->next = s->next; - s->next->prev = s->prev; - s->next = 0; - s->prev = 0; - s->id = 0; + D("local socket ready. LS(%X)\n", s->local_id); + if(HAS_SOCKET_STATUS(s, NOTIFY)) { + D("local socket notify to the client FD(%d)\n", s->fd); + sdb_write(s->fd, "OKAY", 4); + REMOVE_SOCKET_STATUS(s, NOTIFY); } + FDEVENT_ADD(&s->fde, FDE_READ); } -void close_all_sockets(atransport *t) +void local_socket_close(SDB_SOCKET *s) { - asocket *s; - - /* this is a little gross, but since s->close() *will* modify - ** the list out from under you, your options are limited. - */ - sdb_mutex_lock(&socket_list_lock); -restart: - for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ - if(s->transport == t || (s->peer && s->peer->transport == t)) { - local_socket_close_locked(s); - goto restart; - } + D("LS(%X) FD(%d)\n", s->local_id, s->fd); + if(HAS_SOCKET_STATUS(s, NOTIFY)) { + D("LS(%X) fail to send notify\n", s->local_id); + sendfailmsg(s->fd, "closed"); + REMOVE_SOCKET_STATUS(s, NOTIFY); } - sdb_mutex_unlock(&socket_list_lock); -} -static int local_socket_enqueue(asocket *s, apacket *p) -{ - D("LS(%d): enqueue %d\n", s->id, p->len); - p->ptr = p->data; - - /* if there is already data queue'd, we will receive - ** events when it's time to write. just add this to - ** the tail - */ - if(s->pkt_first) { - goto enqueue; - } - - /* write as much as we can, until we - ** would block or there is an error/eof - */ - while(p->len > 0) { - int r = sdb_write(s->fd, p->ptr, p->len); - if(r > 0) { - p->len -= r; - p->ptr += r; - continue; - } - if((r == 0) || (errno != EAGAIN)) { - D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); - s->close(s); - return 1; /* not ready (error) */ - } else { - break; - } + if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) { + send_cmd(0, s->remote_id, A_CLSE, NULL, s->transport); } + int id = s->local_id; - if(p->len == 0) { - put_apacket(p); - return 0; /* ready for more data */ + if(!s->closing && s->pkt_list != NULL) { + s->closing = 1; + FDEVENT_DEL(&s->fde, FDE_READ); + remove_node(&local_socket_list, s->node, remove_socket); + D("LS(%X) pending close\n", id); } - -enqueue: - p->next = 0; - if(s->pkt_first) { - s->pkt_last->next = p; - } else { - s->pkt_first = p; + else { + local_socket_destroy(s); + D("LS(%X) closed\n", id); } - s->pkt_last = p; - - /* make sure we are notified when we can drain the queue */ - fdevent_add(&s->fde, FDE_WRITE); - - return 1; /* not ready (backlog) */ } -static void local_socket_ready(asocket *s) -{ - /* far side is ready for data, pay attention to - readable events */ - fdevent_add(&s->fde, FDE_READ); -// D("LS(%d): ready()\n", s->id); -} - -static void local_socket_close(asocket *s) -{ - sdb_mutex_lock(&socket_list_lock); - local_socket_close_locked(s); - sdb_mutex_unlock(&socket_list_lock); +static void destroy_socket(void* data) { + SDB_SOCKET* socket = data; + socket->node = NULL; + + if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) { + free(socket->read_packet); + unsigned int id = socket->local_id & ~remote_con_flag; + + TRANSPORT* t = socket->transport; + if(t != NULL) { + LIST_NODE* node = t->remote_cnxn_socket; + while(node != NULL) { + SDB_SOCKET* s = node->data; + node = node->next_ptr; + if(s == socket) { + remove_node(&(t->remote_cnxn_socket), s->node, no_free); + break; + } + } + } + remote_con_l_table[id] = 0; + } + socket->local_id = 0; + free(socket); } // be sure to hold the socket list lock when calling this -static void local_socket_destroy(asocket *s) +static void local_socket_destroy(SDB_SOCKET *s) { - apacket *p, *n; - int exit_on_close = s->exit_on_close; - - D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd); + D("LS(%X) FD(%d)\n", s->local_id, s->fd); - /* IMPORTANT: the remove closes the fd + /* IMPORTANT: fdevent_remove closes the fd ** that belongs to this socket */ fdevent_remove(&s->fde); /* dispose of any unwritten data */ - for(p = s->pkt_first; p; p = n) { - D("LS(%d): discarding %d bytes\n", s->id, p->len); - n = p->next; - put_apacket(p); + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + + if(s->node != NULL) { + remove_node(&local_socket_list, s->node, destroy_socket); } - remove_socket(s); - free(s); + else { + destroy_socket(s); + } +} + + //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared +#if 0 +//remote_ls_id is a socket in the remote server. +//local_ls_id is a socket of fowarding socket +// left half is local_ls_id and right half is remote_ls_id. +static unsigned int encoding_ls_id(unsigned int remote_ls_id, unsigned int local_ls_id) { + D("LS_R(%X), LS_L(%X)\n", remote_ls_id, local_ls_id); + return remote_ls_id | local_ls_id; +} + +static void send_remote_con_packet(SDB_SOCKET* sock, PACKET* p) { - if (exit_on_close) { - D("local_socket_destroy: exiting\n"); - exit(1); + //message and data are filled send it to the target. + if(p->msg.command != A_CNXN) { + //A_CNXN does not have to encode local socket id. + p->msg.arg0 = encoding_ls_id(p->msg.arg0, sock->local_id); + LOG_INFO("LS_L(%X) LS_E(%X) encoding done\n", sock->local_id, p->msg.arg0); + } + else { + //for notifying transport that it has remaning socket which wait for CNXN + LOG_INFO("LS_L(%X) message was CNXN\n", sock->local_id); + append(&sock->transport->remote_cnxn_socket, sock); + } + + encoding_packet(p); + //send packet to the target transport + if(sock->transport->write_to_remote(p, sock->transport)) { + LOG_ERROR("fail to write packet\n"); + dump_packet("write error", "remote_con_enqueue", p); } } +static int remote_con_enqueue(SDB_SOCKET* socket, PACKET* p) { + LOG_INFO("LS_L(%X)\n", socket->local_id); -static void local_socket_close_locked(asocket *s) -{ - D("entered. LS(%d) fd=%d\n", s->id, s->fd); - if(s->peer) { - D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", - s->id, s->peer->id, s->peer->fd); - s->peer->peer = 0; - // tweak to avoid deadlock - if (s->peer->close == local_socket_close) { - local_socket_close_locked(s->peer); - } else { - s->peer->close(s->peer); + PACKET* read_p = socket->read_packet; + + if(read_p->len == 0 && p->len >= sizeof(MESSAGE)) { + if(p->len == sizeof(MESSAGE) + p->msg.data_length) { + //send packet directly without memcpy. + if(check_header(p) || check_data(read_p)) { + LOG_ERROR("bad packet: terminated (data)\n"); + dump_packet("bad packet", "remote_con_enqueue", read_p); + put_apacket(p); + return 0; + } + + LOG_INFO("packet is complete send directly\n"); + send_remote_con_packet(socket, p); + put_apacket(p); + return 1; } - s->peer = 0; } - /* If we are already closing, or if there are no - ** pending packets, destroy immediately - */ - if (s->closing || s->pkt_first == NULL) { - int id = s->id; - local_socket_destroy(s); - D("LS(%d): closed\n", id); - return; + while(p != NULL) { + //read MESSAGE + if(read_p->len < sizeof(MESSAGE)) { + int read_length = 0; + int msg_done = 1; + if(read_p->len + p->len >= sizeof(MESSAGE)) { + read_length = sizeof(MESSAGE) - read_p->len; + } + else { + read_length = p->len; + msg_done = 0; + } + memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length); + p->ptr += read_length; + p->len -= read_length; + read_p->len += read_length; + if(msg_done) { + LOG_INFO("message reading done\n"); + + #if 0 && defined HAVE_BIG_ENDIAN + D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", + socket_p->msg.command, socket_p->msg.arg0, socket_p->msg.arg1, socket_p->msg.data_length, socket_p->msg.data_check, socket_p->msg.magic); + #endif + if(check_header(read_p)) { + LOG_ERROR("bad header: terminated (data)\n"); + dump_packet("bad header", "remote_con_enqueue", read_p); + read_p->len = 0; + put_apacket(p); + return 0; + } + } + else { + //wait for next round + LOG_INFO("wait for next round while reading message\n"); + put_apacket(p); + return 0; + } + } + //read data + unsigned data_length = read_p->msg.data_length + sizeof(MESSAGE); + int read_length = 0; + int data_done = 1; + if(read_p->len + p->len >= data_length) { + read_length = data_length - read_p->len; + } + else { + read_length = p->len; + data_done = 0; + } + + memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length); + p->ptr += read_length; + p->len -= read_length; + read_p->len += read_length; + + if(data_done) { + LOG_INFO("data reading done\n"); + if(check_data(read_p)) { + LOG_ERROR("bad data: terminated (data)\n"); + dump_packet("bad data", "remote_con_enqueue", read_p); + read_p->len = 0; + put_apacket(p); + return 0; + } + + send_remote_con_packet(socket, read_p); + read_p->len = 0; + } + + if(p->len == 0) { + LOG_INFO("reading all the packet is done\n"); + put_apacket(p); + p = NULL; + } } - /* otherwise, put on the closing list - */ - D("LS(%d): closing\n", s->id); - s->closing = 1; - fdevent_del(&s->fde, FDE_READ); - remove_socket(s); - D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd); - insert_local_socket(s, &local_socket_closing_list); + LOG_INFO("read_p->len: %d\n", read_p->len); + return 1; +} +#endif + +static int peer_enqueue(SDB_SOCKET* socket, PACKET* p) { + if(HAS_SOCKET_STATUS(socket, REMOTE_SOCKET)) { + D("entered remote_socket_enqueue RS(%d) WRTE fd=%d\n", + socket->remote_id, socket->fd); + p->msg.command = A_WRTE; + p->msg.arg0 = socket->local_id; + p->msg.arg1 = socket->remote_id; + p->msg.data_length = p->len; + send_packet(p, socket->transport); + put_apacket(p); + FDEVENT_DEL(&socket->fde, FDE_READ); + return 1; + } + + //TODO REMOTE_DEVICE_CONNECT block this code until security issue is resolved +#if 0 + if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) { + return remote_con_enqueue(socket, p); + } +#endif + + if(HAS_SOCKET_STATUS(socket, DEVICE_TRACKER)) { + D("close device tracker.fd: '%d', LS(%X)", socket->fd, socket->local_id); + put_apacket(p); + local_socket_close(socket); + return -1; + } + + //packet can be queued, so do not free it here. + return smart_socket_enqueue(socket, p); +} + +/** + * If returns 0, appending is done. packet is freed. + * 1, EAGAIN happens packet is put in the queue. wait for next round. + * -1, error happens. socket is closed. return immediately. + */ +static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func) { + D("LS(%X) FD(%d)\n", s->local_id, fd); + while(p->len > 0) { + dump_packet("0", "local_enqueue", p); + int r = sdb_write(fd, p->ptr, p->len); + if(r < 0) { + if(errno == EAGAIN) { + //packet is used next round do not free. + D( "LS(%X) EAGAIN pending to next round\n", s->local_id); + return 1; + } + //TODO if we handle EINTR when local_socket_enqueue calls this, Windows debug fails. + if(errno == EINTR && event_func) { + D( "LS(%X) EINTR continue\n", s->local_id); + continue; + } + } + if(r > 0) { + p->len -= r; + p->ptr += r; + continue; + } + //error happens. close the socket. + D( "LS(%X) error ER(%d) %s\n", s->local_id, errno, strerror(errno) ); + put_apacket(p); + local_socket_close(s); + return -1; /* not ready (error) */ + } + //append done. + D("LS(%X) enqueue done\n", s->local_id); + put_apacket(p); + return 0; } static void local_socket_event_func(int fd, unsigned ev, void *_s) { - asocket *s = _s; + SDB_SOCKET *s = _s; - D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); + D("LS(%X) FD(%d)\n", s->local_id, s->fd); /* put the FDE_WRITE processing before the FDE_READ ** in order to simplify the code. */ if(ev & FDE_WRITE){ - apacket *p; - - while((p = s->pkt_first) != 0) { - while(p->len > 0) { - int r = sdb_write(fd, p->ptr, p->len); - if(r > 0) { - p->ptr += r; - p->len -= r; - continue; - } - if(r < 0) { - /* returning here is ok because FDE_READ will - ** be processed in the next iteration loop - */ - if(errno == EAGAIN) return; - if(errno == EINTR) continue; - } - D(" closing after write because r=%d and errno is %d\n", r, errno); - s->close(s); - return; + D("LS(%X) gets a write event\n", s->local_id); + while(s->pkt_list != NULL) { + PACKET* p = s->pkt_list->data; + int r = local_enqueue(fd, p, s, 1); + + if ( r == 0) { + //packet enqueue done + remove_first(&s->pkt_list, no_free); } - - if(p->len == 0) { - s->pkt_first = p->next; - if(s->pkt_first == 0) s->pkt_last = 0; - put_apacket(p); + else { + //in both cases r = 1 and r = -1, return immediately. + return; } } - - /* if we sent the last packet of a closing socket, - ** we can now destroy it. - */ if (s->closing) { - D(" closing because 'closing' is set after write\n"); - s->close(s); + D("LS(%X) closing because 'closing' is set after write\n", s->local_id); + local_socket_close(s); return; } - - /* no more packets queued, so we can ignore - ** writable events again and tell our peer - ** to resume writing - */ - fdevent_del(&s->fde, FDE_WRITE); - s->peer->ready(s->peer); + //all the packet in the pkt_list is enqueued. write event is done. + FDEVENT_DEL(&s->fde, FDE_WRITE); + if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) { + send_cmd(s->local_id, s->remote_id, A_OKAY, NULL, s->transport); + } } if(ev & FDE_READ){ - apacket *p = get_apacket(); - unsigned char *x = p->data; + D("LS(%X) gets a read event\n", s->local_id); + //packet should be freed in peer_enqueue + PACKET *p = get_apacket(); + + void *x; + if(HAS_SOCKET_STATUS(s, REMOTE_CON)) { + x = &p->msg; + p->ptr = &p->msg; + } + else { + x = p->data; + } size_t avail = MAX_PAYLOAD; - int r; - int is_eof = 0; + int r = 1; while(avail > 0) { r = sdb_read(fd, x, avail); - D("LS(%d): post sdb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail); if(r > 0) { avail -= r; x += r; continue; } if(r < 0) { - if(errno == EAGAIN) break; - if(errno == EINTR) continue; + if(errno == EAGAIN) { + D("LS(%X) EAGAIN while reading\n", s->local_id); + break; + } + if(errno == EINTR) { + continue; + } + LOG_ERROR("LS(%X) error while reading ER(%d), %s\n", s->local_id, errno, strerror(errno)); + // r = 0 means EOF or unhandled error. + r = 0; } - - /* r = 0 or unhandled error */ - is_eof = 1; + D("LS(%X) reading done\n", s->local_id); break; } - D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", - s->id, s->fd, r, is_eof, s->fde.force_eof); - if((avail == MAX_PAYLOAD) || (s->peer == 0)) { + + if(avail == MAX_PAYLOAD) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; - r = s->peer->enqueue(s->peer, p); - D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); - - if(r < 0) { - /* error return means they closed us as a side-effect - ** and we must return immediately. - ** - ** note that if we still have buffered packets, the - ** socket will be placed on the closing socket list. - ** this handler function will be called again - ** to process FDE_WRITE events. - */ - return; + //TODO HOT PATCH FOR 2048. + if(p->len > 0 && p->len % 512 == 0) { + s->char_2048 = p->data[--p->len]; + s->check_2048 = 1; } - if(r > 0) { - /* if the remote cannot accept further events, - ** we disable notification of READs. They'll - ** be enabled again when we get a call to ready() - */ - fdevent_del(&s->fde, FDE_READ); + if(peer_enqueue(s, p) < 0) { + //local socket is already closed by peer or should not close the socket. + return; } } - /* Don't allow a forced eof if data is still there */ - if((s->fde.force_eof && !r) || is_eof) { - D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); - s->close(s); + if(r == 0) { + D("LS(%X) EOF. closing\n", s->local_id); + local_socket_close(s); } } - - if(ev & FDE_ERROR){ - /* this should be caught be the next read or write - ** catching it here means we may skip the last few - ** bytes of readable data. - */ -// s->close(s); - D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); - - return; - } } -asocket *create_local_socket(int fd) +SDB_SOCKET *create_local_socket(int fd) { - asocket *s = calloc(1, sizeof(asocket)); - if (s == NULL) fatal("cannot allocate socket"); + D("FD(%d)\n", fd); + SDB_SOCKET *s = calloc(1, sizeof(SDB_SOCKET)); + if (s == NULL) { + LOG_FATAL("cannot allocate socket\n"); + } + s->status = 0; + s->node = NULL; + s->pkt_list = NULL; s->fd = fd; - s->enqueue = local_socket_enqueue; - s->ready = local_socket_ready; - s->close = local_socket_close; - install_local_socket(s); + s->check_2048 = 0; + + s->local_id = local_socket_next_id++; + s->node = prepend(&local_socket_list, s); fdevent_install(&s->fde, fd, local_socket_event_func, s); -/* fdevent_add(&s->fde, FDE_ERROR); */ - //fprintf(stderr, "Created local socket in create_local_socket \n"); - D("LS(%d): created (fd=%d)\n", s->id, s->fd); + D("LS(%X) FD(%d) created\n", s->local_id, s->fd); return s; } -asocket *create_local_service_socket(const char *name) -{ - asocket *s; - int fd; - - fd = service_to_fd(name); - if(fd < 0) return 0; - - s = create_local_socket(fd); - D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); - - return s; +void create_remote_connection_socket(SDB_SOCKET* socket) { + LOG_INFO("FD(%d)\n", socket->fd); + SET_SOCKET_STATUS(socket, REMOTE_CON); + socket->read_packet = malloc(sizeof(PACKET)); + socket->read_packet->len = 0; } -static asocket *create_host_service_socket(const char *name, const char* serial) +void connect_to_remote(SDB_SOCKET *s, const char *destination) { - asocket *s; - - s = host_service_to_socket(name, serial); + D("LS(%X)\n", s->local_id); + PACKET *p = get_apacket(); + int len = strlen(destination) + 1; - if (s != NULL) { - D("LS(%d) bound to '%s'\n", s->id, name); - return s; + if(len > (MAX_PAYLOAD-1)) { + LOG_FATAL("destination oversized\n"); } - return s; + D("LS(%X): connect('%s')\n", s->local_id, destination); + p->msg.command = A_OPEN; + p->msg.arg0 = s->local_id; + p->msg.data_length = len; + strcpy((char*) p->data, destination); + send_packet(p, s->transport); + put_apacket(p); } -/* a Remote socket is used to send/receive data to/from a given transport object -** it needs to be closed when the transport is forcibly destroyed by the user -*/ -typedef struct aremotesocket { - asocket socket; - adisconnect disconnect; -} aremotesocket; +static unsigned unhex(unsigned char*s, int len) { -static int remote_socket_enqueue(asocket *s, apacket *p) -{ - D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n", - s->id, s->fd, s->peer->fd); - p->msg.command = A_WRTE; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - p->msg.data_length = p->len; - send_packet(p, s->transport); - return 1; + unsigned n = 0; + while(len > 0) { + MAP_KEY key; + key.key_int = (int)(0 | *s++); + void* _c = map_get(&hex_map, key); + unsigned c = (unsigned)_c; + n = (n << 4) | c; + len--; + } + return n; } -static void remote_socket_ready(asocket *s) -{ - D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n", - s->id, s->fd, s->peer->fd); - apacket *p = get_apacket(); - p->msg.command = A_OKAY; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - send_packet(p, s->transport); -} +/** + * return 0 for host + * return 1 for transport + */ +static int parse_host_service(char* host_str, char** service_ptr, TRANSPORT** t, char** err_str) { -static void remote_socket_close(asocket *s) -{ - D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", - s->id, s->fd, s->peer?s->peer->fd:-1); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - if(s->peer) { - p->msg.arg0 = s->peer->id; - s->peer->peer = 0; - D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n", - s->id, s->peer->id, s->peer->fd); - s->peer->close(s->peer); - } - p->msg.arg1 = s->id; - send_packet(p, s->transport); - D("RS(%d): closed\n", s->id); - remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); - free(s); + int prefix_len = strlen(PREFIX_HOST_USB); + if (!strncmp(host_str, PREFIX_HOST_USB, prefix_len)) { + *service_ptr = host_str + prefix_len; + *t = acquire_one_transport(kTransportUsb, NULL, err_str); + return 0; + } + prefix_len = strlen(PREFIX_HOST_LOCAL); + if (!strncmp(host_str, PREFIX_HOST_LOCAL, prefix_len)) { + *service_ptr = host_str + prefix_len; + *t = acquire_one_transport(kTransportLocal, NULL, err_str); + return 0; + } + prefix_len = strlen(PREFIX_HOST); + if (!strncmp(host_str, PREFIX_HOST, prefix_len)) { + if(!strncmp(host_str, PREFIX_TRANSPORT_ANY, strlen(PREFIX_TRANSPORT_ANY))) { + *t = acquire_one_transport(kTransportAny, NULL, err_str); + return 1; + } + if(!strncmp(host_str, PREFIX_TRANSPORT_LOCAL, strlen(PREFIX_TRANSPORT_LOCAL))) { + *t = acquire_one_transport(kTransportLocal, NULL, err_str); + return 1; + } + if(!strncmp(host_str, PREFIX_TRANSPORT_USB, strlen(PREFIX_TRANSPORT_USB))) { + *t = acquire_one_transport(kTransportUsb, NULL, err_str); + return 1; + } + if(!strncmp(host_str, PREFIX_TRANSPORT_SERIAL, strlen(PREFIX_TRANSPORT_SERIAL))) { + *t = acquire_one_transport(kTransportAny, host_str + strlen(PREFIX_TRANSPORT_SERIAL), err_str); + return 1; + } + *service_ptr = host_str + prefix_len; + //does not have to find transport. + *t = NULL; + *err_str = NULL; + return 0; + } + prefix_len = strlen(PREFIX_HOST_ANY); + if(!strncmp(host_str, PREFIX_HOST_ANY, prefix_len)) { + *service_ptr = host_str + prefix_len; + *t = acquire_one_transport(kTransportAny, NULL, err_str); + return 0; + } + prefix_len = strlen(PREFIX_HOST_SERIAL); + if(!strncmp(host_str, PREFIX_HOST_SERIAL, prefix_len)) { + char* serial = host_str + prefix_len; + char* end = strchr(serial, ':'); + if(end == NULL) { + *err_str = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND; + return 0; + } + *end = '\0'; + *service_ptr = end + 1; + *t = acquire_one_transport(kTransportAny, serial, err_str); + return 0; + } + *service_ptr = NULL; + return 0; } -static void remote_socket_disconnect(void* _s, atransport* t) -{ - asocket* s = _s; - asocket* peer = s->peer; +static int handle_request_with_t(SDB_SOCKET* socket, char* service, TRANSPORT* t, char* err_str) { + int forward = 0; + if(!strncmp(service,"forward:",8)) { + forward = 8; + } + else if (!strncmp(service,"killforward:",12)) { + forward = 12; + } + + if(forward) { + char* forward_err = NULL; + + char *local, *remote = NULL; + local = service + forward; + remote = strchr(local,';'); + + if (t == NULL || t->connection_state == CS_OFFLINE) { + if(t != NULL) { + forward_err = (char*)TRANSPORT_ERR_TARGET_OFFLINE; + } + else { + forward_err = err_str; + } + goto sendfail; + } + if(remote == 0 || remote[1] == '\0') { + forward_err = "malformed forward spec"; + goto sendfail; + } + *remote++ = 0; - D("remote_socket_disconnect RS(%d)\n", s->id); - if (peer) { - peer->peer = NULL; - peer->close(peer); + if (forward == 8) { + if(!install_listener(local, remote, t)) { + writex(socket->fd, "OKAYOKAY", 8); + return 0; + } + else { + LOG_INFO("LS(%X) T(%s) fail to install listener\n", socket->fd, t->serial); + forward_err = "cannot install listener"; + } + } else { + if(!remove_listener(local, remote, t)) { + writex(socket->fd, "OKAYOKAY", 8); + return 0; + } else { + LOG_INFO("LS(%X) T(%s) fail to remove listener\n", socket->fd, t->serial); + forward_err = "cannot remove listener"; + } + } +sendfail: + sendfailmsg(socket->fd, forward_err); + return 0; + } + else if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { + if (t) { + sendokmsg(socket->fd, t->serial); + } + else { + sendokmsg(socket->fd, "target not exist"); + } + return 0; + } + else if(!strncmp(service,"get-state",strlen("get-state"))) { + const char *state = connection_state_name(t); + sendokmsg(socket->fd, state); + return 0; } - remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); - free(s); -} -asocket *create_remote_socket(unsigned id, atransport *t) -{ - asocket *s = calloc(1, sizeof(aremotesocket)); - adisconnect* dis = &((aremotesocket*)s)->disconnect; - - if (s == NULL) fatal("cannot allocate socket"); - s->id = id; - s->enqueue = remote_socket_enqueue; - s->ready = remote_socket_ready; - s->close = remote_socket_close; - s->transport = t; - - dis->func = remote_socket_disconnect; - dis->opaque = s; - add_transport_disconnect( t, dis ); - D("RS(%d): created\n", s->id); - return s; + //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared +#if 0 + else if(!strncmp(service,"_dev_con",strlen("_dev_con"))) { + if(t == NULL) { + sendfailmsg(socket->fd, err_str); + return 0; + } + if(assign_remote_connect_socket_lid(socket)) { + sendfailmsg(socket->fd, "remote connect socket exceeds limit. cannot create remote socket\n"); + local_socket_close(socket); + return 0; + } + socket->transport = t; + create_remote_connection_socket(socket); + + char* buf = "OKAY"; + writex(socket->fd, buf, strlen(buf)); + return 0; + } +#endif + + return -1; } -void connect_to_remote(asocket *s, const char *destination) +static int find_transports(char **serial_out, const char *prefix) { - D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd); - apacket *p = get_apacket(); - int len = strlen(destination) + 1; + int nr = 0; // not found + char *match = NULL; - if(len > (MAX_PAYLOAD-1)) { - fatal("destination oversized"); - } + if (!serial_out || !prefix) + return -1; - D("LS(%d): connect('%s')\n", s->id, destination); - p->msg.command = A_OPEN; - p->msg.arg0 = s->id; - p->msg.data_length = len; - strcpy((char*) p->data, destination); - send_packet(p, s->transport); -} + sdb_mutex_lock(&transport_lock, "transport find_transports"); + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; + char* serial = t->serial; + if (!serial || !serial[0]) + continue; + if (!strncmp(prefix, serial, strlen(prefix))) { + match = serial; + nr++; + } -/* this is used by magic sockets to rig local sockets to - send the go-ahead message when they connect */ -static void local_socket_ready_notify(asocket *s) -{ - s->ready = local_socket_ready; - s->close = local_socket_close; - sdb_write(s->fd, "OKAY", 4); - s->ready(s); + if (nr > 1) { + match = NULL; + break; + } + } + sdb_mutex_unlock(&transport_lock, "transport find_transports"); + + if (nr == 1 && match) { + *serial_out = strdup(match); + } else if (nr == 0) { + asprintf(serial_out, "device not found"); + } else if (nr > 1) { + asprintf(serial_out, "more than one device and emulator"); + } + + return nr; } -/* this is used by magic sockets to rig local sockets to - send the failure message if they are closed before - connected (to avoid closing them without a status message) */ -static void local_socket_close_notify(asocket *s) +static void unregister_all_tcp_transports() { - s->ready = local_socket_ready; - s->close = local_socket_close; - sendfailmsg(s->fd, "closed"); - s->close(s); + sdb_mutex_lock(&transport_lock, "transport unregister_all_tcp_transports"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; + if (t->type == kTransportLocal && t->sdb_port == 0) { + //just kick the transport. transport is destroied by transport thread. + if(!t->kicked) { + t->kicked = 1; + t->kick(t); + } + } + } + + sdb_mutex_unlock(&transport_lock, "transport unregister_all_tcp_transports"); } -unsigned unhex(unsigned char *s, int len) +static int handle_host_request(char *service, SDB_SOCKET* socket) { - unsigned n = 0, c; - - while(len-- > 0) { - switch((c = *s++)) { - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': case '8': - case '9': - c -= '0'; - break; - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - c = c - 'a' + 10; - break; - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - c = c - 'A' + 10; - break; - default: - return 0xffffffff; + LOG_INFO("LS(%X)\n", socket->fd); + char cmd_buf[1024]; + int cbuf_size = sizeof cmd_buf; + + if (!strncmp(service, "serial-match:", 13)) { + char *tmp = service + 13; + char *serial = NULL; + int ret = -1; + D("Try to find device for: %s\n", tmp); + ret = find_transports(&serial, tmp); + if (ret <= 0) { + LOG_ERROR("No device found\n"); + sendfailmsg(socket->fd, serial); + } else if (ret == 1) { + sendokmsg(socket->fd, serial); + } else { + LOG_ERROR("found more than one devices matched: %d\n", ret); + sendfailmsg(socket->fd, serial); + } + free(serial); + return 0; + } + // return a list of all connected devices + if (!strcmp(service, "devices")) { + list_transports(cmd_buf, cbuf_size); + sendokmsg(socket->fd, cmd_buf); + return 0; + } + + // add a new TCP transport, device or emulator + if (!strncmp(service, "connect:", 8)) { + char* host = service + 8; + char* portstr = strchr(host, ':'); + int port = -1; + + if(portstr) { + *portstr++ = 0; + if(!sscanf(portstr, "%d", &port)) { + snprintf(cmd_buf, cbuf_size, "bad port format '%s'", portstr); + goto connect_done; + } } + connect_emulator(host, port, cmd_buf, cbuf_size); - n = (n << 4) | c; +connect_done: + sendokmsg(socket->fd, cmd_buf); + return 0; } - return n; -} + // remove TCP transport + if (!strncmp(service, "disconnect:", 11)) { + char* serial = service + 11; + if (serial[0]) { + if (!strchr(serial, ':')) { + snprintf(cmd_buf, cbuf_size, "%s:26101", serial); + serial = cmd_buf; + } + TRANSPORT *t = acquire_one_transport(kTransportAny, serial, NULL); -/* skip_host_serial return the position in a string - skipping over the 'serial' parameter in the SDB protocol, - where parameter string may be a host:port string containing - the protocol delimiter (colon). */ -char *skip_host_serial(char *service) { - char *first_colon, *serial_end; + if (t) { + cmd_buf[0] = '\0'; + kick_transport(t); + } else { + snprintf(cmd_buf, cbuf_size, "No such device %s", serial); + } + } else { + unregister_all_tcp_transports(); + cmd_buf[0] = '\0'; + } - first_colon = strchr(service, ':'); - if (!first_colon) { - /* No colon in service string. */ - return NULL; + sendokmsg(socket->fd, cmd_buf); + return 0; } - serial_end = first_colon; - if (isdigit(serial_end[1])) { - serial_end++; - while ((*serial_end) && isdigit(*serial_end)) { - serial_end++; + + if (!strncmp(service, "device_con:", 11)) { + char* _host = service + 11; + char host_buf[4096]; + char target_buf[4096]; + char full_cmd[4096]; + char full_serial[256]; + strncpy(host_buf, _host, sizeof(host_buf) - 1); + _host = host_buf; + char* serial = strchr(host_buf, ':'); + + if(serial == NULL) { + sendfailmsg(socket->fd, "serial number is NULL. cannot find the target device\n"); + } + *(serial) = '\0'; + serial++; + + int fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM); + if (fd < 0) { + snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host); + LOG_ERROR(target_buf); + sendfailmsg(socket->fd, target_buf); + return 0; + } + D("FD(%d) remote connected with host: %s\n", fd, _host); + + D("FULL_CMD %s\n", full_cmd); + snprintf(full_cmd, sizeof(full_cmd), "host:serial-match:%s", serial); + if(!send_service_with_length(fd, full_cmd, socket->fd)) { + if(!sdb_status(fd, socket->fd)) { + int n = read_msg_size(fd); + if(n > 0 && n < 256) { + if(!readx(fd, full_serial, n)) { + full_serial[n] = 0; + serial = full_serial; + goto success; + } + } + snprintf(target_buf, sizeof(target_buf), "fail to read full serial of %s", serial); + sendfailmsg(socket->fd, target_buf); + } + } + sdb_close(fd); + return 0; + +success: + sdb_close(fd); + fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM); + if (fd < 0) { + snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host); + LOG_ERROR(target_buf); + sendfailmsg(socket->fd, target_buf); + return 0; } - if ((*serial_end) != ':') { - // Something other than numbers was found, reset the end. - serial_end = first_colon; + D("FD(%d) remote connected\n", fd); + get_host_prefix(target_buf, sizeof target_buf, kTransportAny, serial, host); + snprintf(full_cmd, sizeof full_cmd, "%s_dev_con",target_buf); + + D("FULL_CMD: %s\n", full_cmd); + if(!send_service_with_length(fd, full_cmd, socket->fd)) { + if(!sdb_status(fd, socket->fd)) { + if(!register_device_con_transport(fd, serial)) { + snprintf(target_buf, sizeof target_buf, "success to connect with remote target '%s'\n", serial); + snprintf(full_cmd, sizeof(full_cmd), "OKAY%04x%s",(unsigned)strlen(target_buf), target_buf); + if(!writex(socket->fd, full_cmd, strlen(full_cmd))) { + return 0; + } + else { + sendfailmsg(socket->fd, "fail to write OKAY message\n"); + } + } + else { + sendfailmsg(socket->fd, "fail to connect with remote device\n"); + } + } } + sdb_close(fd); + return 0; + } + + // returns our value for SDB_VERSION_PATCH + if (!strcmp(service, "version")) { + char ver[SDB_VERSION_MAX_LENGTH-8] = {0,}; + char buf[SDB_VERSION_MAX_LENGTH] = {0,}; + + snprintf(ver, sizeof(ver), "%d.%d.%d", SDB_VERSION_MAJOR, SDB_VERSION_MINOR, SDB_VERSION_PATCH); + snprintf(buf, sizeof(buf), "OKAY%04x%s", strlen(ver), ver); + writex(socket->fd, buf, strlen(buf)); + return 0; } - return serial_end; + + // indicates a new emulator instance has started + if (!strncmp(service,"emulator:",9)) { /* tizen specific */ + D("new emulator is in\n"); + char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR); + int port = 0; + + if (tmp == NULL) { + port = atoi(service+9); + } else { + port = atoi(tmp); + tmp = strtok(NULL, DEVICEMAP_SEPARATOR); + } + local_connect(port, tmp); + return 0; + } + + if(!strcmp(service, "kill")) { + LOG_INFO("sdb is being killed\n"); + sdb_cleanup(); + sdb_write(socket->fd, "OKAY", 4); + exit(0); + } + + return -1; } -static int smart_socket_enqueue(asocket *s, apacket *p) +static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p) { unsigned len; - char *service = NULL; - char* serial = NULL; - transport_type ttype = kTransportAny; - D("SS(%d): enqueue %d\n", s->id, p->len); + D("LS(%X)\n", s->local_id); - if(s->pkt_first == 0) { - s->pkt_first = p; - s->pkt_last = p; - } else { - if((s->pkt_first->len + p->len) > MAX_PAYLOAD) { - D("SS(%d): overflow\n", s->id); + if(s->pkt_list == NULL) { + prepend(&s->pkt_list, p); + } + else { + PACKET* socket_packet = s->pkt_list->data; + if((socket_packet->len + p->len) > MAX_PAYLOAD) { + D("SS(%d): overflow\n", s->local_id); put_apacket(p); goto fail; } - memcpy(s->pkt_first->data + s->pkt_first->len, + memcpy(socket_packet->data + socket_packet->len, p->data, p->len); - s->pkt_first->len += p->len; + socket_packet->len += p->len; put_apacket(p); - p = s->pkt_first; + p = socket_packet; } /* don't bother if we can't decode the length */ if(p->len < 4) return 0; len = unhex(p->data, 4); + if((len < 1) || (len > 1024)) { - D("SS(%d): bad size (%d)\n", s->id, len); + D("LS(%X): bad size (%d)\n", s->local_id, len); goto fail; } - D("SS(%d): len is %d\n", s->id, len ); /* can't do anything until we have the full header */ if((len + 4) > p->len) { - D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len); + D("LS(%X): waiting for %d more bytes in smart socket\n", s->local_id, len+4 - p->len); return 0; } p->data[len + 4] = 0; + D("LS(%X) %s\n", s->local_id, p->data + 4); - D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4)); - - service = (char *)p->data + 4; - if(!strncmp(service, PREFIX_HOST_SERIAL, strlen(PREFIX_HOST_SERIAL))) { - char* serial_end; - service += strlen(PREFIX_HOST_SERIAL); - - // serial number should follow "host:" and could be a host:port string. - serial_end = skip_host_serial(service); - if (serial_end) { - *serial_end = 0; // terminate string - serial = service; - service = serial_end + 1; - } - ttype = kTransportUsb; - } else if (!strncmp(service, PREFIX_HOST_USB, strlen(PREFIX_HOST_USB))) { - service += strlen(PREFIX_HOST_USB); - } else if (!strncmp(service, PREFIX_HOST_LOCAL, strlen(PREFIX_HOST_LOCAL))) { - ttype = kTransportLocal; - service += strlen(PREFIX_HOST_LOCAL); - } else if (!strncmp(service, PREFIX_HOST, strlen(PREFIX_HOST))) { - ttype = kTransportAny; - service += strlen(PREFIX_HOST); - } else { - service = NULL; + char* host_str = (char *)p->data + 4; + char *service = NULL; + char* err_str = NULL; + TRANSPORT* t = NULL; + + if(parse_host_service(host_str, &service, &t, &err_str) == 1) { + if (t && t->connection_state != CS_OFFLINE) { + s->transport = t; + sdb_write(s->fd, "OKAY", 4); + D("LS(%X) get transport T(%s)", s->local_id, t->serial); + } else { + if(t != NULL) { + err_str = (char*)TRANSPORT_ERR_TARGET_OFFLINE; + } + LOG_ERROR("LS(%X) get no transport", s->local_id); + sendfailmsg(s->fd, err_str); + } + p->len = 0; + return 0; } if (service) { - asocket *s2; - - /* some requests are handled immediately -- in that - ** case the handle_host_request() routine has sent - ** the OKAY or FAIL message and all we have to do - ** is clean up. - */ - if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) { + if(handle_request_with_t(s, service, t, err_str) == 0) { + D( "LS(%X): handled host service with '%s'\n", s->local_id, service ); + goto fail; + } + + if(handle_host_request(service, s) == 0) { /* XXX fail message? */ - D( "SS(%d): handled host service '%s'\n", s->id, service ); + D( "LS(%X): handled host service '%s'\n", s->local_id, service ); goto fail; } - if (!strncmp(service, "transport", strlen("transport"))) { - D( "SS(%d): okay transport\n", s->id ); - p->len = 0; + + if (!strcmp(service,"track-devices")) { + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + D("LS(%X): OKAY\n", s->local_id); + SET_SOCKET_STATUS(s, DEVICE_TRACKER); + sdb_write(s->fd, "OKAY", 4); + + D( "LS(%X) fd: '%d' for device tracking\n", s->local_id, s->fd ); + char buffer[1024]; + int len; + len = list_transports_msg(buffer, sizeof(buffer)); + device_tracker_send(s, buffer, len); return 0; } - - /* try to find a local service with this name. - ** if no such service exists, we'll fail out - ** and tear down here. - */ - s2 = create_host_service_socket(service, serial); - if(s2 == 0) { - D( "SS(%d): couldn't create host service '%s'\n", s->id, service ); - sendfailmsg(s->peer->fd, "unknown host service"); + else { + D( "LS(%X): couldn't create host service '%s'\n", s->local_id, service ); + sendfailmsg(s->fd, "unknown host service"); goto fail; } - - /* we've connected to a local host service, - ** so we make our peer back into a regular - ** local socket and bind it to the new local - ** service socket, acknowledge the successful - ** connection, and close this smart socket now - ** that its work is done. - */ - sdb_write(s->peer->fd, "OKAY", 4); - - s->peer->ready = local_socket_ready; - s->peer->close = local_socket_close; - s->peer->peer = s2; - s2->peer = s->peer; - s->peer = 0; - D( "SS(%d): okay\n", s->id ); - s->close(s); - - /* initial state is "ready" */ - s2->ready(s2); - return 0; } if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) { - /* if there's no remote we fail the connection - ** right here and terminate it - */ - sendfailmsg(s->peer->fd, "device offline (x)"); + sendfailmsg(s->fd, "device offline (x)"); goto fail; } + if (!(s->transport) || (s->transport->connection_state == CS_PWLOCK)) { + sendfailmsg(s->fd, "device locked"); + goto fail; + } - /* instrument our peer to pass the success or fail - ** message back once it connects or closes, then - ** detach from it, request the connection, and - ** tear down - */ - s->peer->ready = local_socket_ready_notify; - s->peer->close = local_socket_close_notify; - s->peer->peer = 0; - /* give him our transport and upref it */ - s->peer->transport = s->transport; - - connect_to_remote(s->peer, (char*) (p->data + 4)); - s->peer = 0; - s->close(s); - return 1; + if(s->transport->type == kTransportRemoteDevCon) { + if(assign_remote_connect_socket_rid(s)) { + sendfailmsg(s->fd, "remote connect socket exceeds limit. cannot create remote socket\n"); + local_socket_close(s); + return -1; + } + } + + SET_SOCKET_STATUS(s, NOTIFY); + connect_to_remote(s, (char*) (p->data + 4)); + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + FDEVENT_DEL(&s->fde, FDE_READ); + return 0; fail: - /* we're going to close our peer as a side-effect, so - ** return -1 to signal that state to the local socket - ** who is enqueueing against us - */ - s->close(s); + + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + if(!HAS_SOCKET_STATUS(s, REMOTE_CON)) { + //do not close socket if it is remote connected socket + local_socket_close(s); + } return -1; } -static void smart_socket_ready(asocket *s) -{ - D("SS(%d): ready\n", s->id); +int assign_remote_connect_socket_rid (SDB_SOCKET* s) { + if(remote_con_cur_r_id > remote_con_r_max) { + LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd); + return -1; + } + int remote_id = (remote_con_cur_r_id << 4) | remote_con_flag; + LOG_INFO("LS(%X) -> LS_R(%X)\n", s->local_id, remote_id); + s->local_id = remote_id; + remote_con_cur_r_id++; + return 0; } -static void smart_socket_close(asocket *s) -{ - D("SS(%d): closed\n", s->id); - if(s->pkt_first){ - put_apacket(s->pkt_first); +int assign_remote_connect_socket_lid (SDB_SOCKET* s) { + if(remote_con_cur_l_number >= remote_con_l_max) { + LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd); + return -1; } - if(s->peer) { - s->peer->peer = 0; - s->peer->close(s->peer); - s->peer = 0; + int i = 0; + for(i = 0; i< remote_con_l_max; i++) { + if(remote_con_l_table[i] == 0) { + unsigned int remote_id = i | remote_con_flag; + remote_con_cur_l_number++; + LOG_INFO("LS(%X) -> LS_L(%X)\n", s->local_id, remote_id); + s->local_id = remote_id; + remote_con_l_table[i] = 1; + return 0; + } } - free(s); + LOG_ERROR("not enough space in remote_con_l_table\n"); + return -1; } -asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) +int +device_tracker_send( SDB_SOCKET* local_socket, + const char* buffer, + int len ) { - D("Creating smart socket \n"); - asocket *s = calloc(1, sizeof(asocket)); - if (s == NULL) fatal("cannot allocate socket"); - s->enqueue = smart_socket_enqueue; - s->ready = smart_socket_ready; - s->close = smart_socket_close; - s->extra = action_cb; - - D("SS(%d): created %p\n", s->id, action_cb); - return s; + D("device tracker send to the socket. LS(%X), fd: '%d'\n", local_socket->local_id, local_socket->fd); + PACKET* p = get_apacket(); + + memcpy(p->data, buffer, len); + p->len = len; + p->ptr = p->data; + //packet should not be freed after local_socket_enqueue because it can be still used in local socket packet queue. + return local_socket_enqueue( local_socket, p ); } -void smart_socket_action(asocket *s, const char *act) -{ +static void connect_emulator(char* host, int port, char* buf, int buf_len) { + if(port < 0) { + port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT; + } + LOG_INFO("connecting ip: '%s', port: '%d'\n", host, port); -} + int fd = sdb_host_connect(host, port, SOCK_STREAM); + if (fd < 0) { + snprintf(buf, buf_len, "fail to connect to %s", host); + return; + } -void connect_to_smartsocket(asocket *s) -{ - D("Connecting to smart socket \n"); - asocket *ss = create_smart_socket(smart_socket_action); - s->peer = ss; - ss->peer = s; - s->ready(s); + LOG_INFO("FD(%d) connected\n", fd); + close_on_exec(fd); + disable_tcp_nagle(fd); + char serial[100]; + snprintf(serial, sizeof(serial), "%s:%d", host, port); + + if (acquire_one_transport(kTransportAny, serial, NULL)) { + snprintf(buf, buf_len, "%s is already connected", serial); + return; + } + + register_socket_transport(fd, serial, port, 0, NULL); + snprintf(buf, buf_len, "connected to %s", serial); } diff --git a/src/sockets.h b/src/sockets.h new file mode 100644 index 0000000..51fe875 --- /dev/null +++ b/src/sockets.h @@ -0,0 +1,62 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef SOCKETS_H_ +#define SOCKETS_H_ + +#include "common_modules.h" + +#define SET_SOCKET_STATUS(asocket, _status) ((asocket)->status |= (1 << _status)) +#define REMOVE_SOCKET_STATUS(asocket, _status) ((asocket)->status &= ~(1 << _status)) +#define HAS_SOCKET_STATUS(asocket, _status) ((asocket)->status & (1 << _status)) + +extern const unsigned int unsigned_int_bit; +extern const unsigned int remote_con_right_padding; +extern const unsigned int remote_con_flag; +extern unsigned int remote_con_cur_r_id; +extern unsigned int remote_con_cur_l_number; +extern const unsigned int remote_con_l_max; // Ox1111 +extern const unsigned int remote_con_r_max; +extern unsigned int remote_con_l_table[16]; + +typedef enum { + NOTIFY = 0, + DEVICE_TRACKER, + REMOTE_SOCKET, + REMOTE_CON +} SOCKET_STATUS; + +extern LIST_NODE* local_socket_list; + +SDB_SOCKET *find_local_socket(unsigned id); +int local_socket_enqueue(SDB_SOCKET *s, PACKET *p); +void local_socket_ready(SDB_SOCKET *s); +void local_socket_close(SDB_SOCKET *s); +SDB_SOCKET *create_local_socket(int fd); +void connect_to_remote(SDB_SOCKET *s, const char *destination); +int assign_remote_connect_socket_rid (SDB_SOCKET* s); +int device_tracker_send( SDB_SOCKET* local_socket, const char* buffer, int len ); +#endif /* SOCKETS_H_ */ diff --git a/src/strutils.c b/src/strutils.c old mode 100644 new mode 100755 index 2823e12..e7444b7 --- a/src/strutils.c +++ b/src/strutils.c @@ -12,7 +12,7 @@ size_t tokenize(const char *str, const char *delim, char *tokens[], size_t max_t char tmp[PATH_MAX]; - strncpy(tmp, str, PATH_MAX); + strncpy(tmp, str, PATH_MAX - 1); char *p = strtok(tmp, delim); if (max_tokens < 1 || max_tokens > MAX_TOKENS) { max_tokens = 1; @@ -69,15 +69,31 @@ int read_line(const int fd, char* ptr, const unsigned int maxlen) * ntbs[sizeof(ntbs)-1] = '\0' */ char *s_strncpy(char *dest, const char *source, size_t n) { - char *start = dest; - while (n && (*dest++ = *source++)) { - n--; - } - if (n) { - while (--n) { - *dest++ = '\0'; - } - } - return start; + char *start = dest; + + if (n) { + while (--n) { + if (*source == '\0') { + break; + } + *dest++ = *source++; + } + *dest = '\0'; + } + + return start; +} + +/** + * Mingw doesn't have strnlen. + */ +size_t s_strnlen(const char *s, size_t maxlen) { + size_t len; + for (len = 0; len < maxlen; len++, s++) { + if (!*s) { + break; + } + } + return len; } diff --git a/src/strutils.h b/src/strutils.h index 897579f..d5bf30b 100644 --- a/src/strutils.h +++ b/src/strutils.h @@ -7,5 +7,6 @@ size_t tokenize(const char *str, const char *delim, char *tokens[], size_t max_t void free_strings(char **array, int n); int read_line(const int fd, char* ptr, const unsigned int maxlen); char *s_strncpy(char *dest, const char *source, size_t n); +size_t s_strnlen(const char *s, size_t maxlen); #endif diff --git a/src/transport.c b/src/transport.c index 51a6abd..778d539 100755 --- a/src/transport.c +++ b/src/transport.c @@ -21,17 +21,31 @@ #include #include "fdevent.h" #include "utils.h" +#include "transport.h" +#include "sockets.h" +#include "sdb_constants.h" +#include "strutils.h" +#include "memutils.h" +#include "listener.h" +#include "log.h" + #define TRACE_TAG TRACE_TRANSPORT -#include "sdb.h" -static void transport_unref(atransport *t); +static void transport_unref(TRANSPORT *t); +static void handle_packet(PACKET *p, TRANSPORT *t); +static void parse_banner(char *banner, TRANSPORT *t); +static void wakeup_select(T_PACKET* t_packet); +static void update_transports(void); +static void run_transport_close(TRANSPORT* t); +static void encoding_packet(PACKET* p); +static int check_header(PACKET *p); +static int check_data(PACKET *p); +static void dump_hex( const unsigned char* ptr, size_t len); -static atransport transport_list = { - .next = &transport_list, - .prev = &transport_list, -}; +LIST_NODE* transport_list = NULL; SDB_MUTEX_DEFINE( transport_lock ); +SDB_MUTEX_DEFINE( wakeup_select_lock ); #ifdef _WIN32 /* FIXME : move to sysdeps.h later */ int asprintf( char **, char *, ... ); @@ -60,183 +74,123 @@ int asprintf( char **sptr, char *fmt, ... ) } #endif -#if SDB_TRACE -#define MAX_DUMP_HEX_LEN 16 -static void dump_hex( const unsigned char* ptr, size_t len ) +#define MAX_DUMP_HEX_LEN 30 +//#define MAX_DUMP_HEX_LEN 4096 +static void dump_hex( const unsigned char* ptr, size_t len) { - int nn, len2 = len; - // Build a string instead of logging each character. - // MAX chars in 2 digit hex, one space, MAX chars, one '\0'. - char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer; + if(SDB_TRACING) { + char hex_str[]= "0123456789abcdef"; - if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN; + if(len > MAX_DUMP_HEX_LEN) { + len = MAX_DUMP_HEX_LEN; + } - for (nn = 0; nn < len2; nn++) { - sprintf(pb, "%02x", ptr[nn]); - pb += 2; - } - sprintf(pb++, " "); + int i; + char hex[len*2 + 1]; + for (i = 0; i < len; i++) { + hex[i*2 + 0] = hex_str[ptr[i] >> 4]; + hex[i*2 + 1] = hex_str[ptr[i] & 0x0F]; + } + hex[len*2] = '\0'; - for (nn = 0; nn < len2; nn++) { - int c = ptr[nn]; - if (c < 32 || c > 127) - c = '.'; - *pb++ = c; + char asci[len + 1]; + for (i = 0; i < len; i++) { + if ((int)ptr[i] >= 32 && (int)ptr[i] <= 127) { + asci[i] = ptr[i]; + } + else { + asci[i] = '.'; + } + } + asci[len] = '\0'; + + DR("HEX:'%s', ASCI:'%s'\n", hex, asci); +// LOG_HEX(hex, asci); } - *pb++ = '\0'; - DR("%s\n", buffer); } -#endif void -kick_transport(atransport* t) +kick_transport(TRANSPORT* t) { if (t && !t->kicked) { int kicked; - sdb_mutex_lock(&transport_lock); + sdb_mutex_lock(&transport_lock, "transport kick_transport"); kicked = t->kicked; if (!kicked) t->kicked = 1; - sdb_mutex_unlock(&transport_lock); + sdb_mutex_unlock(&transport_lock, "transport kick_transport"); if (!kicked) t->kick(t); } } -void -run_transport_disconnects(atransport* t) +static void run_transport_close(TRANSPORT* t) { - adisconnect* dis = t->disconnects.next; + D("T(%s)\n", t->serial); + LIST_NODE* curptr = listener_list; - D("%s: run_transport_disconnects\n", t->serial); - while (dis != &t->disconnects) { - adisconnect* next = dis->next; - dis->func( dis->opaque, t ); - dis = next; - } -} + while(curptr != NULL) { + LISTENER* l = curptr->data; + curptr = curptr->next_ptr; -#if SDB_TRACE -static void -dump_packet(const char* name, const char* func, apacket* p) -{ - unsigned command = p->msg.command; - int len = p->msg.data_length; - char cmd[9]; - char arg0[12], arg1[12]; - int n; - - for (n = 0; n < 4; n++) { - int b = (command >> (n*8)) & 255; - if (b < 32 || b >= 127) - break; - cmd[n] = (char)b; - } - if (n == 4) { - cmd[4] = 0; - } else { - /* There is some non-ASCII name in the command, so dump - * the hexadecimal value instead */ - snprintf(cmd, sizeof cmd, "%08x", command); + if(l->transport == t) { + D("LN(%s) being closed by T(%s)\n", l->local_name, t->serial); + remove_node(&listener_list, l->node, free_listener); + } } - if (p->msg.arg0 < 256U) - snprintf(arg0, sizeof arg0, "%d", p->msg.arg0); - else - snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0); + curptr = local_socket_list; + while(curptr != NULL) { + SDB_SOCKET* s = curptr->data; + curptr = curptr->next_ptr; - if (p->msg.arg1 < 256U) - snprintf(arg1, sizeof arg1, "%d", p->msg.arg1); - else - snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1); - - D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", - name, func, cmd, arg0, arg1, len); - dump_hex(p->data, len); -} -#endif /* SDB_TRACE */ - -static int -read_packet(int fd, const char* name, apacket** ppacket) -{ - char *p = (char*)ppacket; /* really read a packet address */ - int r; - int len = sizeof(*ppacket); - char buff[8]; - if (!name) { - snprintf(buff, sizeof buff, "fd=%d", fd); - name = buff; - } - while(len > 0) { - r = sdb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; - return -1; + if(s->transport == t) { + D("LS(%X) FD(%d) being closed by T(%s)\n", s->local_id, s->fd, t->serial); + local_socket_close(s); } } - -#if SDB_TRACE - if (SDB_TRACING) { - dump_packet(name, "from remote", *ppacket); - } -#endif - return 0; } -static int -write_packet(int fd, const char* name, apacket** ppacket) + +void dump_packet(const char* name, const char* func, PACKET* p) { - char *p = (char*) ppacket; /* we really write the packet address */ - int r, len = sizeof(ppacket); - char buff[8]; - if (!name) { - snprintf(buff, sizeof buff, "fd=%d", fd); - name = buff; - } + if(SDB_TRACING) { + unsigned cmd = p->msg.command; + char command[9]; -#if SDB_TRACE - if (SDB_TRACING) { - dump_packet(name, "to remote", *ppacket); - } -#endif - len = sizeof(ppacket); - while(len > 0) { - r = sdb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; - return -1; + if(cmd == A_CLSE) { + snprintf(command, sizeof command, "%s", "A_CLSE"); } - } - return 0; -} - -static void transport_socket_events(int fd, unsigned events, void *_t) -{ - atransport *t = _t; - D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); - if(events & FDE_READ){ - apacket *p = 0; - if(read_packet(fd, t->serial, &p)){ - D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd); - } else { - handle_packet(p, (atransport *) _t); + else if(cmd == A_CNXN) { + snprintf(command, sizeof command, "%s", "A_CNXN"); + } + else if(cmd == A_OPEN) { + snprintf(command, sizeof command, "%s", "A_OPEN"); + } + else if(cmd == A_OKAY) { + snprintf(command, sizeof command, "%s", "A_OKAY"); } + else if(cmd == A_WRTE) { + snprintf(command, sizeof command, "%s", "A_WRTE"); + } + else if(cmd == A_TCLS) { + snprintf(command, sizeof command, "%s", "A_TCLS"); + } + else { + //unrecongnized command dump the hexadecimal value. + snprintf(command, sizeof command, "%08x", cmd); + } + + D("T(%s) %s: [%s] arg0=%X arg1=%X (len=%d) (total_msg_len=%d)\n", + name, func, command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->len); + dump_hex(p->data, p->msg.data_length); } } -void send_packet(apacket *p, atransport *t) -{ +static void encoding_packet(PACKET* p) { unsigned char *x; unsigned sum; unsigned count; @@ -250,147 +204,114 @@ void send_packet(apacket *p, atransport *t) sum += *x++; } p->msg.data_check = sum; +} - print_packet("send", p); +void send_packet(PACKET *p, TRANSPORT *t) +{ + if(t != NULL && t->connection_state != CS_OFFLINE) { + encoding_packet(p); - if (t == NULL) { - D("Transport is null \n"); - // Zap errno because print_packet() and other stuff have errno effect. - errno = 0; - fatal_errno("Transport is null"); + D("%s: transport got packet, sending to remote\n", t->serial); + t->write_to_remote(p, t); } - - if(write_packet(t->transport_socket, t->serial, &p)){ - fatal_errno("cannot enqueue packet on transport socket"); + else { + if (t == NULL) { + D("Transport is null \n"); + errno = 0; + LOG_FATAL("Transport is null\n"); + } + else { + D("%s: transport ignoring packet while offline\n", t->serial); + } } } -/* The transport is opened by transport_register_func before -** the input and output threads are started. -** -** The output thread issues a SYNC(1, token) message to let -** the input thread know to start things up. In the event -** of transport IO failure, the output thread will post a -** SYNC(0,0) message to ensure shutdown. -** -** The transport will not actually be closed until both -** threads exit, but the input thread will kick the transport -** on its way out to disconnect the underlying device. -*/ - -static void *output_thread(void *_t) -{ - atransport *t = _t; - apacket *p; - - D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", - t->serial, t->fd, t->sync_token + 1); - p = get_apacket(); - p->msg.command = A_SYNC; - p->msg.arg0 = 1; - p->msg.arg1 = ++(t->sync_token); - p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, t->serial, &p)) { - put_apacket(p); - D("%s: failed to write SYNC packet\n", t->serial); - goto oops; - } +static __inline__ void wakeup_select(T_PACKET* t_packet) { + sdb_mutex_lock(&wakeup_select_lock, "wakeup_select"); + writex(fdevent_wakeup_send, &t_packet, sizeof(t_packet)); + sdb_mutex_unlock(&wakeup_select_lock, "wakeup_select"); +} - D("%s: data pump started\n", t->serial); - for(;;) { - p = get_apacket(); +static void handle_packet(PACKET *p, TRANSPORT *t) +{ + unsigned int cmd = p->msg.command; + T_PACKET* t_packet = malloc(sizeof(T_PACKET)); + t_packet->t = t; + t_packet->p = NULL; - if(t->read_from_remote(p, t) == 0){ - D("%s: received remote packet, sending to transport\n", - t->serial); - if(write_packet(t->fd, t->serial, &p)){ - put_apacket(p); - D("%s: failed to write apacket to transport\n", t->serial); - goto oops; - } - } else { - D("%s: remote read failed for transport\n", t->serial); - put_apacket(p); - break; - } + //below commands should be done in main thread. packet is used in wakeup_select_func. Do not put a packet + if(cmd == A_WRTE || cmd == A_CLSE || cmd == A_CNXN || cmd == A_OKAY || cmd == A_STAT) { + ++(t->req); + t_packet->p = p; + wakeup_select(t_packet); + return; } - - D("%s: SYNC offline for transport\n", t->serial); - p = get_apacket(); - p->msg.command = A_SYNC; - p->msg.arg0 = 0; - p->msg.arg1 = 0; - p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, t->serial, &p)) { - put_apacket(p); - D("%s: failed to write SYNC apacket to transport", t->serial); + else if(cmd == A_OPEN) { + LOG_FATAL("server does not handle A_OPEN\n"); + exit(1); } - -oops: - D("%s: transport output thread is exiting\n", t->serial); - kick_transport(t); - transport_unref(t); - return 0; + D("Unknown packet command %08x\n", p->msg.command); + put_apacket(p); + free(t_packet); } -static void *input_thread(void *_t) +#define CNXN_DATA_MAX_TOKENS 3 +static void parse_banner(char *data, TRANSPORT *t) { - atransport *t = _t; - apacket *p; - int active = 0; + char *banner = s_strdup(data); + char *end = NULL; - D("%s: starting transport input thread, reading from fd %d\n", - t->serial, t->fd); + end = strchr(banner, ':'); + if(end) { + *end = '\0'; + } + const char* target_banner = STATE_HOST; + if(!strcmp(banner, STATE_DEVICE)) { + t->connection_state = CS_DEVICE; + target_banner = STATE_DEVICE; + } + else if(!strcmp(banner, STATE_BOOTLOADER)){ + t->connection_state = CS_BOOTLOADER; + target_banner = STATE_BOOTLOADER; + } + else if(!strcmp(banner, STATE_RECOVERY)) { + t->connection_state = CS_RECOVERY; + target_banner = STATE_RECOVERY; + } + else if(!strcmp(banner, STATE_SIDELOAD)) { + t->connection_state = CS_SIDELOAD; + target_banner = STATE_SIDELOAD; + } + else { + t->connection_state = CS_HOST; + } + s_free(banner); + // since version 2 + char *tokens[CNXN_DATA_MAX_TOKENS]; + size_t cnt = tokenize(data, "::", tokens, CNXN_DATA_MAX_TOKENS); - for(;;){ - if(read_packet(t->fd, t->serial, &p)) { - D("%s: failed to read apacket from transport on fd %d\n", - t->serial, t->fd ); - break; - } - if(p->msg.command == A_SYNC){ - if(p->msg.arg0 == 0) { - D("%s: transport SYNC offline\n", t->serial); - put_apacket(p); - break; - } else { - if(p->msg.arg1 == t->sync_token) { - D("%s: transport SYNC online\n", t->serial); - active = 1; - } else { - D("%s: transport ignoring SYNC %d != %d\n", - t->serial, p->msg.arg1, t->sync_token); - } - } - } else { - if(active) { - D("%s: transport got packet, sending to remote\n", t->serial); - t->write_to_remote(p, t); - } else { - D("%s: transport ignoring packet while offline\n", t->serial); - } + if (cnt == 3) { + // update device_name except usb device but it should be changed soon. + if (strcmp(STATE_UNKNOWN, tokens[1])) { + t->device_name = strdup(tokens[1]); } - put_apacket(p); + if (!strcmp(tokens[2], "1")) { + t->connection_state = CS_PWLOCK; + target_banner = STATE_LOCKED; + } } - // this is necessary to avoid a race condition that occured when a transport closes - // while a client socket is still active. - close_all_sockets(t); + if (cnt) { + free_strings(tokens, cnt); + } - D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); - kick_transport(t); - transport_unref(t); - return 0; + D("setting connection_state to '%s'\n", target_banner); + update_transports(); + return; } - -static int transport_registration_send = -1; -static int transport_registration_recv = -1; -static fdevent transport_registration_fde; - - -static int list_transports_msg(char* buffer, size_t bufferlen) +int list_transports_msg(char* buffer, size_t bufferlen) { char head[5]; int len; @@ -402,519 +323,226 @@ static int list_transports_msg(char* buffer, size_t bufferlen) return len; } -/* this adds support required by the 'track-devices' service. - * this is used to send the content of "list_transport" to any - * number of client connections that want it through a single - * live TCP connection - */ -typedef struct device_tracker device_tracker; -struct device_tracker { - asocket socket; - int update_needed; - device_tracker* next; -}; - -/* linked list of all device trackers */ -static device_tracker* device_tracker_list; - -static void -device_tracker_remove( device_tracker* tracker ) +static void update_transports(void) { - device_tracker** pnode = &device_tracker_list; - device_tracker* node = *pnode; + D("update transports\n"); + char buffer[1024]; + int len; - sdb_mutex_lock( &transport_lock ); - while (node) { - if (node == tracker) { - *pnode = node->next; - break; - } - pnode = &node->next; - node = *pnode; - } - sdb_mutex_unlock( &transport_lock ); -} + len = list_transports_msg(buffer, sizeof(buffer)); -static void -device_tracker_close( asocket* socket ) -{ - device_tracker* tracker = (device_tracker*) socket; - asocket* peer = socket->peer; - D( "device tracker %p removed\n", tracker); - if (peer) { - peer->peer = NULL; - peer->close(peer); + LIST_NODE* curptr = local_socket_list; + while(curptr != NULL) { + SDB_SOCKET *s = curptr->data; + curptr = curptr->next_ptr; + if (HAS_SOCKET_STATUS(s, DEVICE_TRACKER)) { + device_tracker_send(s, buffer, len); + } } - device_tracker_remove(tracker); - free(tracker); -} - -static int -device_tracker_enqueue( asocket* socket, apacket* p ) -{ - /* you can't read from a device tracker, close immediately */ - put_apacket(p); - device_tracker_close(socket); - return -1; } -static int -device_tracker_send( device_tracker* tracker, - const char* buffer, - int len ) -{ - apacket* p = get_apacket(); - asocket* peer = tracker->socket.peer; - - memcpy(p->data, buffer, len); - p->len = len; - return peer->enqueue( peer, p ); -} - - -static void -device_tracker_ready( asocket* socket ) -{ - device_tracker* tracker = (device_tracker*) socket; - - /* we want to send the device list when the tracker connects - * for the first time, even if no update occured */ - if (tracker->update_needed > 0) { - char buffer[1024]; - int len; - - tracker->update_needed = 0; +void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t) { + PACKET *p = get_apacket(); + p->msg.arg0 = arg0; + p->msg.arg1 = arg1; + p->msg.command = cmd; - len = list_transports_msg(buffer, sizeof(buffer)); - device_tracker_send(tracker, buffer, len); + if(data != NULL) { + snprintf((char*)p->data, sizeof(p->data), "%s", data); + p->msg.data_length = strlen((char*)p->data) + 1; } -} - - -asocket* -create_device_tracker(void) -{ - device_tracker* tracker = calloc(1,sizeof(*tracker)); - - if(tracker == 0) fatal("cannot allocate device tracker"); - - D( "device tracker %p created\n", tracker); - - tracker->socket.enqueue = device_tracker_enqueue; - tracker->socket.ready = device_tracker_ready; - tracker->socket.close = device_tracker_close; - tracker->update_needed = 1; - - tracker->next = device_tracker_list; - device_tracker_list = tracker; - return &tracker->socket; + send_packet(p, t); + put_apacket(p); } - -/* call this function each time the transport list has changed */ -void update_transports(void) +static void *transport_thread(void *_t) { - char buffer[1024]; - int len; - device_tracker* tracker; + TRANSPORT *t = _t; + PACKET *p; - len = list_transports_msg(buffer, sizeof(buffer)); + D("T(%s), FD(%d)\n", t->serial, t->sfd); + t->connection_state = CS_WAITCNXN; + send_cmd(A_VERSION, MAX_PAYLOAD, A_CNXN, "host::", t); + t->connection_state = CS_OFFLINE; + // allow the device some time to respond to the connect message + sdb_sleep_ms(1000); - tracker = device_tracker_list; - while (tracker != NULL) { - device_tracker* next = tracker->next; - /* note: this may destroy the tracker if the connection is closed */ - device_tracker_send(tracker, buffer, len); - tracker = next; - } -} - -typedef struct tmsg tmsg; -struct tmsg -{ - atransport *transport; - int action; -}; - -static int -transport_read_action(int fd, struct tmsg* m) -{ - char *p = (char*)m; - int len = sizeof(*m); - int r; + D("%s: data dump started\n", t->serial); + while(1) { + p = get_apacket(); + LOG_INFO("T(%s) remote read start\n", t->serial); - while(len > 0) { - r = sdb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if((r < 0) && (errno == EINTR)) continue; - D("transport_read_action: on fd %d, error %d: %s\n", - fd, errno, strerror(errno)); - return -1; + if(t->read_from_remote(t, &p->msg, sizeof(MESSAGE))) { + break; } - } - return 0; -} - -static int -transport_write_action(int fd, struct tmsg* m) -{ - char *p = (char*)m; - int len = sizeof(*m); - int r; - - while(len > 0) { - r = sdb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if((r < 0) && (errno == EINTR)) continue; - D("transport_write_action: on fd %d, error %d: %s\n", - fd, errno, strerror(errno)); - return -1; + if(check_header(p)) { + break; + } + if(p->msg.data_length) { + if(t->read_from_remote(t, p->data, p->msg.data_length)){ + break; + } + } + if(check_data(p)) { + break; + } + dump_packet(t->serial, "remote_read", p); + D("%s: received remote packet, sending to transport\n", + t->serial); + handle_packet(p, t); + } + LOG_INFO("T(%s) remote read fail. terminate transport\n", t->serial); + put_apacket(p); + + t->connection_state = CS_OFFLINE; + do { + if(t->req == t->res) { + p = get_apacket(); + p->msg.command = A_TCLS; + T_PACKET* t_packet = malloc(sizeof(T_PACKET)); + t_packet->t = t; + t_packet->p = p; + wakeup_select(t_packet); + break; + } + else { + //TODO this should be changed to wait later. + sdb_sleep_ms(1000); } } + while(1); return 0; } -static sdb_cond_t cond;// = PTHREAD_COND_INITIALIZER; - -static void transport_registration_func(int _fd, unsigned ev, void *data) +void register_transport(TRANSPORT *t) { - tmsg m; - sdb_thread_t output_thread_ptr; - sdb_thread_t input_thread_ptr; - int s[2]; - atransport *t; - - if(!(ev & FDE_READ)) { - return; - } - - if(transport_read_action(_fd, &m)) { - fatal_errno("cannot read transport registration socket"); - } - - t = m.transport; + D("T(%s), device name: '%s'\n", t->serial, t->device_name); + sdb_thread_t transport_thread_ptr; - if(m.action == 0){ - D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); - - /* IMPORTANT: the remove closes one half of the - ** socket pair. The close closes the other half. - */ - fdevent_remove(&(t->transport_fde)); - sdb_close(t->fd); - - sdb_mutex_lock(&transport_lock); - t->next->prev = t->prev; - t->prev->next = t->next; - - sdb_cond_broadcast(&cond); - sdb_mutex_unlock(&transport_lock); - - run_transport_disconnects(t); - - if (t->product) - free(t->product); - if (t->serial) - free(t->serial); - if (t->device_name) - free(t->device_name); - - memset(t,0xee,sizeof(atransport)); - free(t); - - update_transports(); - return; - } - - /* don't create transport threads for inaccessible devices */ - if (t->connection_state != CS_NOPERM) { - /* initial references are the two threads */ - t->ref_count = 2; - - if(sdb_socketpair(s)) { - fatal_errno("cannot open transport socketpair"); - } - - D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); - - t->transport_socket = s[0]; - t->fd = s[1]; - - fdevent_install(&(t->transport_fde), - t->transport_socket, - transport_socket_events, - t); - - fdevent_set(&(t->transport_fde), FDE_READ); - - if(sdb_thread_create(&input_thread_ptr, input_thread, t)){ - fatal_errno("cannot create input thread"); - } - - if(sdb_thread_create(&output_thread_ptr, output_thread, t)){ - fatal_errno("cannot create output thread"); - } + //transport is updated by transport_thread, we do not have to update here. + if(sdb_thread_create(&transport_thread_ptr, transport_thread, t)){ + LOG_FATAL("cannot create output thread\n"); } /* put us on the master device list */ - sdb_mutex_lock(&transport_lock); - t->next = &transport_list; - t->prev = transport_list.prev; - t->next->prev = t; - t->prev->next = t; - - sdb_cond_broadcast(&cond); - sdb_mutex_unlock(&transport_lock); - - t->disconnects.next = t->disconnects.prev = &t->disconnects; - - update_transports(); + sdb_mutex_lock(&transport_lock, "transport register_transport"); + t->node = prepend(&transport_list, t); + sdb_mutex_unlock(&transport_lock, "transport register_transport"); } -void init_transport_registration(void) +//lock is done by transport_unref +static void remove_transport(TRANSPORT *t) { - int s[2]; + D("transport removed. T(%s), device name: %s\n", t->serial, t->device_name); - sdb_cond_init(&cond, NULL); - if(sdb_socketpair(s)){ - fatal_errno("cannot open transport registration socketpair"); - } + remove_node(&transport_list, t->node, no_free); - transport_registration_send = s[0]; - transport_registration_recv = s[1]; + //In Windows, handle is not removed from sdb_handle_map, yet. +#ifdef OS_WINDOWS + sdb_close(t->sfd); +#endif - fdevent_install(&transport_registration_fde, - transport_registration_recv, - transport_registration_func, - 0); + run_transport_close(t); - fdevent_set(&transport_registration_fde, FDE_READ); + if (t->serial) + free(t->serial); + if (t->device_name) + free(t->device_name); + + free(t); } -/* the fdevent select pump is single threaded */ -static void register_transport(atransport *transport) + +static void transport_unref(TRANSPORT *t) { - tmsg m; - m.transport = transport; - m.action = 1; - D("transport: %s registered\n", transport->serial); - if(transport_write_action(transport_registration_send, &m)) { - fatal_errno("cannot write transport registration socket\n"); + if (t == NULL) { + return; } -} -static void remove_transport(atransport *transport) -{ - tmsg m; - m.transport = transport; - m.action = 0; - D("transport: %s removed\n", transport->serial); - if(transport_write_action(transport_registration_send, &m)) { - fatal_errno("cannot write transport registration socket\n"); + sdb_mutex_lock(&transport_lock, "transport_unref transport"); + int nr; + + D("transport: %s unref (kicking and closing)\n", t->serial); + if (!t->kicked) { + t->kicked = 1; + t->kick(t); } -} + t->close(t); + remove_transport(t); + LIST_NODE* curptr = transport_list; -static void transport_unref_locked(atransport *t) -{ - atransport *tmp; - int nr; - t->ref_count--; - if (t->ref_count == 0) { - D("transport: %s unref (kicking and closing)\n", t->serial); - if (!t->kicked) { - t->kicked = 1; - t->kick(t); - } - t->close(t); - remove_transport(t); - - /* update tizen specific device name */ - for (tmp = t->next; tmp && tmp != &transport_list; tmp = tmp->next) { - if (tmp->type == kTransportUsb) { - D("update tizen specific device name: %s\n", tmp->device_name); - if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) { - free(tmp->device_name); - asprintf(&tmp->device_name, "device-%d", nr - 1); - } + while(curptr != NULL) { + TRANSPORT* tmp = curptr->data; + curptr = curptr->next_ptr; + if (tmp->type == kTransportUsb) { + if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) { + free(tmp->device_name); + asprintf(&tmp->device_name, "device-%d", nr - 1); } } - } else { - D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); } -} -static void transport_unref(atransport *t) -{ - if (t) { - sdb_mutex_lock(&transport_lock); - transport_unref_locked(t); - sdb_mutex_unlock(&transport_lock); - } + sdb_mutex_unlock(&transport_lock, "transport_unref transport"); + update_transports(); } -void add_transport_disconnect(atransport* t, adisconnect* dis) +TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char** error_out) { - sdb_mutex_lock(&transport_lock); - dis->next = &t->disconnects; - dis->prev = dis->next->prev; - dis->prev->next = dis; - dis->next->prev = dis; - sdb_mutex_unlock(&transport_lock); -} + TRANSPORT *result = NULL; + char* null_str = NULL; -void remove_transport_disconnect(atransport* t, adisconnect* dis) -{ - dis->prev->next = dis->next; - dis->next->prev = dis->prev; - dis->next = dis->prev = dis; -} + if(error_out == NULL) { + error_out = &null_str; + } + sdb_mutex_lock(&transport_lock, "transport acquire_one_transport"); -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) -{ - atransport *t; - atransport *result = NULL; - int ambiguous = 0; - -retry: - if (error_out) - *error_out = "device not found"; - - sdb_mutex_lock(&transport_lock); - for (t = transport_list.next; t != &transport_list; t = t->next) { - if (t->connection_state == CS_NOPERM) { - if (error_out) - *error_out = "insufficient permissions for device"; - continue; - } + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* transport_ = curptr->data; + curptr = curptr->next_ptr; /* check for matching serial number */ if (serial) { - if (t->serial && !strcmp(serial, t->serial)) { - result = t; + if (transport_->serial && !strcmp(serial, transport_->serial)) { + result = transport_; break; } } else { - if (ttype == kTransportUsb && t->type == kTransportUsb) { - if (result) { - if (error_out) - *error_out = "more than one device"; - ambiguous = 1; - result = NULL; - break; - } - result = t; - } else if (ttype == kTransportLocal && t->type == kTransportLocal) { + if(ttype == kTransportAny) { if (result) { - if (error_out) - *error_out = "more than one emulator"; - ambiguous = 1; + *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_TARGET; result = NULL; break; } - result = t; - } else if (ttype == kTransportAny) { + result = transport_; + } + if (ttype == transport_->type) { if (result) { - if (error_out) - *error_out = "more than one device and emulator"; - ambiguous = 1; + if(ttype == kTransportUsb) { + *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_DEV; + } + else if(ttype == kTransportLocal) { + *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_EMUL; + } result = NULL; break; } - result = t; + result = transport_; } } } - sdb_mutex_unlock(&transport_lock); - - if (result) { - /* offline devices are ignored -- they are either being born or dying */ - if (result && result->connection_state == CS_OFFLINE) { - if (error_out) - *error_out = "device offline"; - result = NULL; - } - /* check for required connection state */ - if (result && state != CS_ANY && result->connection_state != state) { - if (error_out) - *error_out = "invalid device state"; - result = NULL; - } - } - - if (result) { - /* found one that we can take */ - if (error_out) - *error_out = NULL; - } else if (state != CS_ANY && (serial || !ambiguous)) { - sdb_sleep_ms(1000); - goto retry; - } - return result; -} + sdb_mutex_unlock(&transport_lock, "transport acquire_one_transport"); -static const char *statename(atransport *t) -{ - switch(t->connection_state){ - case CS_OFFLINE: return "offline"; - case CS_BOOTLOADER: return "bootloader"; - case CS_DEVICE: return "device"; - case CS_HOST: return "host"; - case CS_RECOVERY: return "recovery"; - case CS_SIDELOAD: return "sideload"; - case CS_NOPERM: return "no permissions"; - default: return "unknown"; - } -} - -/* - * find number of devices which serial match with the prefix - */ -int find_transports(char **serial_out, const char *prefix) -{ - int nr = 0; // not found - char *match = NULL; - atransport *t; - - if (!serial_out || !prefix) - return -1; - - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - char* serial = t->serial; - if (!serial || !serial[0]) - continue; - if (!strncmp(prefix, serial, strlen(prefix))) { - match = serial; - nr++; - } - - if (nr > 1) { - match = NULL; - break; - } - } - sdb_mutex_unlock(&transport_lock); - - if (nr == 1 && match) { - *serial_out = strdup(match); - } else if (nr == 0) { - asprintf(serial_out, "device not found"); - } else if (nr > 1) { - asprintf(serial_out, "more than one device and emulator"); + if (result == NULL ) { + *error_out = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND; } - return nr; + return result; } int list_transports(char *buf, size_t bufsize) @@ -922,16 +550,20 @@ int list_transports(char *buf, size_t bufsize) char* p = buf; char* end = buf + bufsize; int len; - atransport *t; /* XXX OVERRUN PROBLEMS XXX */ - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { + sdb_mutex_lock(&transport_lock, "transport list_transports"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; const char* serial = t->serial; const char* devicename = (t->device_name == NULL) ? DEFAULT_DEVICENAME : t->device_name; /* tizen specific */ if (!serial || !serial[0]) serial = "????????????"; - len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, statename(t), devicename); + // FIXME: what if each string length is longger than static length? + len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, connection_state_name(t), devicename); if (p + len >= end) { /* discard last line if buffer is too short */ @@ -939,168 +571,48 @@ int list_transports(char *buf, size_t bufsize) } p += len; } + p[0] = 0; - sdb_mutex_unlock(&transport_lock); + sdb_mutex_unlock(&transport_lock, "transport list_transports"); return p - buf; } +int register_device_con_transport(int s, const char *serial) { -/* hack for osx */ -void close_usb_devices() -{ - atransport *t; - - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if ( !t->kicked ) { - t->kicked = 1; - t->kick(t); - } + //TODO REMOTE_DEVICE_CONNECT complete device connect after resolving security issue +#if 0 + if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) { + LOG_ERROR("Too many tcp connection\n"); + return -1; } - sdb_mutex_unlock(&transport_lock); -} -void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name) -{ - atransport *t = calloc(1, sizeof(atransport)); + TRANSPORT *t = calloc(1, sizeof(TRANSPORT)); char buff[32]; if (!serial) { snprintf(buff, sizeof buff, "T-%p", t); - serial = buff; } - D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name); - if ( init_socket_transport(t, s, port, local) < 0 ) { - sdb_close(s); - free(t); - atransport *old_t = find_transport(serial); - if (old_t) { - unregister_transport(old_t); - } else { - D("No such device %s", serial); - } - return; - } - if(serial) { - t->serial = strdup(serial); + else { + snprintf(buff, sizeof buff, "T-%s", serial); } + serial = buff; - if (device_name) {/* tizen specific */ - t->device_name = strdup(device_name); - } else { // device_name could be null when sdb server was forked before qemu has sent the connect message. - char device_name[DEVICENAME_MAX]; - if (get_devicename_from_shdmem(port, device_name) == 0) { - t->device_name = strdup(device_name); - } + init_socket_transport(t, s, 0); + t->remote_cnxn_socket = NULL; + t->serial = strdup(buff); + t->device_name = strdup("unknown"); + t->type = kTransportRemoteDevCon; + TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL); + if(old_t != NULL) { + D("old transport '%s' is found. Unregister it\n", old_t->serial); + kick_transport(old_t); } + ++current_local_transports; register_transport(t); -} - -atransport *find_transport(const char *serial) -{ - atransport *t; - - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (t->serial && !strcmp(serial, t->serial)) { - break; - } - } - sdb_mutex_unlock(&transport_lock); - - if (t != &transport_list) - return t; - else - return 0; -} - -void unregister_transport(atransport *t) -{ - sdb_mutex_lock(&transport_lock); - t->next->prev = t->prev; - t->prev->next = t->next; - sdb_mutex_unlock(&transport_lock); - - kick_transport(t); - transport_unref(t); -} - -// unregisters all non-emulator TCP transports -void unregister_all_tcp_transports() -{ - atransport *t, *next; - sdb_mutex_lock(&transport_lock); - for (t = transport_list.next; t != &transport_list; t = next) { - next = t->next; - if (t->type == kTransportLocal && t->sdb_port == 0) { - t->next->prev = t->prev; - t->prev->next = next; - // we cannot call kick_transport when holding transport_lock - if (!t->kicked) - { - t->kicked = 1; - t->kick(t); - } - transport_unref_locked(t); - } - } - - sdb_mutex_unlock(&transport_lock); -} - -static int get_connected_device_count(transport_type type) -{ - int cnt = 0; - atransport *t; - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (type == t->type) - cnt++; - } - - sdb_mutex_unlock(&transport_lock); - D("connected device count:%d\n",cnt); - return cnt; -} - -void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) -{ - atransport *t = calloc(1, sizeof(atransport)); - char device_name[256]; - - D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, - serial ? serial : ""); - init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); - if(serial) { - t->serial = strdup(serial); - } - /* - * send register request to server thread and wait it finished - */ - sdb_mutex_lock(&transport_lock); - register_transport(t); - - sdb_cond_wait(&cond, &transport_lock); - sdb_mutex_unlock(&transport_lock); - /* tizen specific */ - sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb)); - t->device_name = strdup(device_name); -} - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb) -{ - atransport *t; - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (t->usb == usb && t->connection_state == CS_NOPERM) { - t->next->prev = t->prev; - t->prev->next = t->next; - break; - } - } - sdb_mutex_unlock(&transport_lock); + return 0; +#endif + return -1; } #undef TRACE_TAG @@ -1109,79 +621,67 @@ void unregister_usb_transport(usb_handle *usb) int readx(int fd, void *ptr, size_t len) { char *p = ptr; - int r; -#if SDB_TRACE - int len0 = len; -#endif - D("readx: fd=%d wanted=%d\n", fd, (int)len); + D("FD(%d) wanted=%d\n", fd, (int)len); while(len > 0) { - r = sdb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("readx: fd=%d disconnected\n", fd); + int r = sdb_read(fd, p, len); + if(r < 0) { + if(errno == EINTR) { + continue; } + LOG_ERROR("FD(%d) error %d: %s\n", fd, errno, strerror(errno)); + return -1; + } + if( r == 0) { + D("FD(%d) disconnected\n", fd); return -1; } + len -= r; + p += r; } - -#if SDB_TRACE - D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len); - dump_hex( ptr, len0 ); -#endif return 0; } int writex(int fd, const void *ptr, size_t len) { - char *p = (char*) ptr; - int r; + char *p = (char *)ptr; -#if SDB_TRACE - D("writex: fd=%d len=%d: ", fd, (int)len); - dump_hex( ptr, len ); -#endif - while(len > 0) { - r = sdb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("writex: fd=%d disconnected\n", fd); + while( len > 0) { + int r = sdb_write(fd, p, len); + if(r < 0) { + if (errno == EINTR) { + continue; } + D("fd=%d error %d: %s\n", fd, errno, strerror(errno)); + return -1; + } + if( r == 0) { + D("fd=%d disconnected\n", fd); return -1; } + + len -= r; + p += r; } return 0; } -int check_header(apacket *p) +static int check_header(PACKET *p) { if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { - D("check_header(): invalid magic\n"); + LOG_ERROR("check_header(): invalid magic\n"); return -1; } if(p->msg.data_length > MAX_PAYLOAD) { - D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); + LOG_ERROR("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); return -1; } + LOG_INFO("success to check header\n"); return 0; } -int check_data(apacket *p) +static int check_data(PACKET *p) { unsigned count, sum; unsigned char *x; @@ -1199,3 +699,178 @@ int check_data(apacket *p) return 0; } } + +static unsigned int decoding_to_remote_ls_id(unsigned int encoded_ls_id) { + unsigned int remote_ls_id = encoded_ls_id & ~15; + return remote_ls_id; +} + +static unsigned int decoding_to_local_ls_id(unsigned encoded_ls_id) { + unsigned int local_ls_id = encoded_ls_id & 15; + local_ls_id |= remote_con_flag; + return local_ls_id; +} + +void wakeup_select_func(int _fd, unsigned ev, void *data) { + T_PACKET* t_packet = NULL; + + readx(_fd, &t_packet, sizeof(t_packet)); + + TRANSPORT* t= t_packet->t; + D("T(%s)\n", t->serial); + PACKET* p = t_packet->p; + free(t_packet); + + if(p == NULL) { + D("T(%S) packet NULL\n", t->serial); + return; + } + + int c_state = t->connection_state; + unsigned int cmd = p->msg.command; + unsigned int local_id = p->msg.arg1; + unsigned int remote_id = p->msg.arg0; + SDB_SOCKET* sock = NULL; + //CNXN cannot be distinguished using remote_con_flag + if(t->remote_cnxn_socket != NULL && cmd == A_CNXN) { + dump_packet("remote_con", "wakeup_select_func", p); + sock = t->remote_cnxn_socket->data; + if(sock != NULL) { + remove_first(&(t->remote_cnxn_socket), no_free); + LOG_INFO("LS_L(%X)\n", sock->local_id); + p->ptr = (void*)(&p->msg); + p->len = sizeof(MESSAGE) + p->msg.data_length; + local_socket_enqueue(sock, p); + } + goto endup; + } + //If transport is remote device, packet should not have to be decoded. + if((local_id & remote_con_flag) && t->type != kTransportRemoteDevCon) { + LOG_INFO("LS_L(%X), LS_R(%X), LS_E(%X)\n", decoding_to_local_ls_id(local_id), + decoding_to_remote_ls_id(local_id), local_id); + sock = find_local_socket(decoding_to_local_ls_id(local_id)); + p->msg.arg1 = decoding_to_remote_ls_id(local_id); + p->ptr = (void*)(&p->msg); + p->len = sizeof(MESSAGE) + p->msg.data_length; + local_socket_enqueue(sock, p); + goto endup; + } + sock = find_local_socket(local_id); + + if(c_state != CS_OFFLINE && sock != NULL) { + //packet is used by local_socket_enqueue do not put a packet. + if(cmd == A_WRTE) { + D("T(%s) write packet from RS(%d) to LS(%X)\n", t->serial, remote_id, local_id); + p->len = p->msg.data_length; + p->ptr = p->data; + if(local_socket_enqueue(sock, p) == 0) { + send_cmd(local_id, remote_id, A_OKAY, NULL, t); + } + goto endup; + } + else if(cmd == A_OKAY) { + if(!HAS_SOCKET_STATUS(sock, REMOTE_SOCKET)) { + SET_SOCKET_STATUS(sock, REMOTE_SOCKET); + D("remote socket attached LS(%X), RS(%d)\n", sock->local_id, sock->remote_id); + sock->remote_id = remote_id; + sock->transport = t; + } + //TODO HOT PATCH FOR 2048. + if(sock->check_2048 == 1) { + sock->check_2048 = 0; + PACKET *__p = get_apacket(); + __p->msg.command = A_WRTE; + __p->msg.arg0 = sock->local_id; + __p->msg.arg1 = sock->remote_id; + __p->data[0] = sock->char_2048; + __p->msg.data_length = 1; + send_packet(__p, sock->transport); + } + else { + local_socket_ready(sock); + } + } + } + if(cmd == A_CLSE) { + if(sock != NULL) { + D("T(%s) close LS(%X)\n", t->serial, local_id); + local_socket_close(sock); + } + } + else if(cmd == A_CNXN) { + D("T(%s) gets CNXN\n", t->serial); + if(t->connection_state != CS_OFFLINE) { + t->connection_state = CS_OFFLINE; + run_transport_close(t); + } + parse_banner((char*) p->data, t); + } + else if(cmd == A_STAT) { + D("T(%s) gets A_STAT:%d\n", t->serial, p->msg.arg0); + if (t->connection_state != CS_OFFLINE) { + t->connection_state = CS_OFFLINE; + } + if (p->msg.arg0 == 1) { + t->connection_state = CS_PWLOCK; + } else { + t->connection_state = CS_DEVICE; + } + update_transports(); + } + else if(cmd == A_TCLS) { + //transport thread is finished + transport_unref(t); + return; + } + put_apacket(p); + +endup: + //request is done. res increases 1. + ++(t->res); +} + +const char *connection_state_name(TRANSPORT *t) +{ + if(t != NULL) { + int state = t->connection_state; + + if(state == CS_OFFLINE) { + return STATE_OFFLINE; + } + if(state == CS_BOOTLOADER) { + return STATE_BOOTLOADER; + } + if(state == CS_DEVICE) { + return STATE_DEVICE; + } + if(state == CS_HOST) { + return STATE_HOST; + } + if(state == CS_RECOVERY) { + return STATE_RECOVERY; + } + if(state == CS_SIDELOAD) { + return STATE_SIDELOAD; + } + if (state == CS_PWLOCK) { + return STATE_LOCKED; + } + } + return STATE_UNKNOWN; +} + +PACKET *get_apacket(void) +{ + PACKET *p = malloc(sizeof(PACKET)); + if(p == 0) { + LOG_FATAL("failed to allocate an apacket\n"); + } + memset(p, 0, sizeof(PACKET) - MAX_PAYLOAD); + return p; +} + +void put_apacket(void *p) +{ + PACKET* packet = p; + free(packet); +} diff --git a/src/transport.h b/src/transport.h old mode 100644 new mode 100755 index 511b37e..d7c18af --- a/src/transport.h +++ b/src/transport.h @@ -17,10 +17,55 @@ #ifndef __TRANSPORT_H #define __TRANSPORT_H -/* convenience wrappers around read/write that will retry on -** EINTR and/or short read/write. Returns 0 on success, -1 -** on error or EOF. -*/ -int readx(int fd, void *ptr, size_t len); -int writex(int fd, const void *ptr, size_t len); +#include "common_modules.h" + +#define LOCAL_CLIENT_PREFIX "emulator-" + +#define A_CNXN 0x4e584e43 +#define A_OPEN 0x4e45504f +#define A_OKAY 0x59414b4f +#define A_CLSE 0x45534c43 +#define A_WRTE 0x45545257 +#define A_TCLS 0x534C4354 +#define A_STAT 0x54415453 + +#define CS_NONE -10000 +#define CS_ANY -1 +#define CS_OFFLINE 0 +#define CS_BOOTLOADER 1 +#define CS_DEVICE 2 +#define CS_HOST 3 +#define CS_RECOVERY 4 +#define CS_SIDELOAD 6 +#define CS_WAITCNXN 7 +#define CS_PWLOCK 10 + +#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 +#define SDB_LOCAL_TRANSPORT_MAX 15 + +extern LIST_NODE* transport_list; +extern int current_local_transports; + +#ifdef _WIN32 /* FIXME : move to sysdeps.h later */ +int asprintf( char **, char *, ... ); +int vasprintf( char **, char *, va_list ); +#endif + +void wakeup_select_func(int _fd, unsigned ev, void *data); +void dump_packet(const char* name, const char* func, PACKET* p); +void send_packet(PACKET *p, TRANSPORT *t); +const char *connection_state_name(TRANSPORT *t); +PACKET *get_apacket(void); +void put_apacket(void *p); +void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name); +void register_usb_transport(usb_handle *usb, const char *serial); +int register_device_con_transport(int s, const char *serial); +void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t); +void close_usb_devices(); +int list_transports_msg(char* buffer, size_t bufferlen); +int list_transports(char *buf, size_t bufsize); +int local_connect(int port, const char *device_name); +TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char **error_out); +void kick_transport( TRANSPORT* t ); +void register_transport(TRANSPORT *t); #endif /* __TRANSPORT_H */ diff --git a/src/transport_local.c b/src/transport_local.c old mode 100644 new mode 100755 index 8fca32d..a58542a --- a/src/transport_local.c +++ b/src/transport_local.c @@ -18,8 +18,6 @@ #include #include #include -#include "fdevent.h" -#include "utils.h" #include #ifndef OS_WINDOWS @@ -29,106 +27,91 @@ #endif #define TRACE_TAG TRACE_TRANSPORT -#include "sdb.h" - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -#else -#define fix_endians(p) do {} while (0) -#endif +#include "strutils.h" +#include "log.h" +#include "common_modules.h" +#include "fdevent.h" +#include "utils.h" +#include "transport.h" /* we keep a list of opened transports. The atransport struct knows to which * local transport it is connected. The list is used to detect when we're * trying to connect twice to a given local transport. */ -#define SDB_LOCAL_TRANSPORT_MAX 16 -SDB_MUTEX_DEFINE( local_transports_lock ); +int current_local_transports = 0; -static atransport* local_transports[ SDB_LOCAL_TRANSPORT_MAX ]; +static int get_devicename_from_shdmem(int port, char *device_name); -static int remote_read(apacket *p, atransport *t) -{ - if(readx(t->sfd, &p->msg, sizeof(amessage))){ - D("remote local: read terminated (message)\n"); +static int remote_read(TRANSPORT* t, void* data, int len) { + return readx(t->sfd, data, len); +} + +static int remote_write(PACKET *p, TRANSPORT *t) { + dump_packet(t->serial, "remote_write_local", p); + if(writex(t->sfd, &p->msg, sizeof(MESSAGE) + p->msg.data_length)) { + LOG_ERROR("remote local: write terminated\n"); return -1; } + return 0; +} - fix_endians(p); +static int notify_sensord(int sdb_port) { -#if 0 && defined HAVE_BIG_ENDIAN - D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif - if(check_header(p)) { - D("bad header: terminated (data)\n"); - return -1; - } + int fd = -1; + int sensord_port = sdb_port + 2; - if(readx(t->sfd, p->data, p->msg.data_length)){ - D("remote local: terminated (data)\n"); - return -1; - } + fd = sdb_host_connect("127.0.0.1", sensord_port, SOCK_DGRAM); - if(check_data(p)) { - D("bad data: terminated (data)\n"); + if (fd < 0) { + LOG_ERROR("failed to create socket to localhost(%d)\n", sensord_port); return -1; } - return 0; -} - -static int remote_write(apacket *p, atransport *t) -{ - int length = p->msg.data_length; - - fix_endians(p); + char request[16]; + snprintf(request, sizeof request, "2\n"); -#if 0 && defined HAVE_BIG_ENDIAN - D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif - if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) { - D("remote local: write terminated\n"); - return -1; + // send to sensord with udp + if (sdb_write(fd, request, strlen(request)) < 0) { + LOG_ERROR("could not send sensord request\n"); } + sdb_close(fd); return 0; } +int local_connect(int sdb_port, const char *device_name) { -int local_connect(int port, const char *device_name) { - return local_connect_arbitrary_ports(port-1, port, device_name); -} - -int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name) -{ char buf[64]; - int fd = -1; - fd = socket_loopback_client(sdb_port, SOCK_STREAM); + // in case of windows, it takes a long time to connect localhost compare to linux +#if defined(OS_WINDOWS) + char devname[DEVICENAME_MAX]={0,}; + if (get_devicename_from_shdmem(sdb_port, devname) == -1) { + return -1; + } +#endif + + int fd = sdb_host_connect("127.0.0.1", sdb_port, SOCK_STREAM); if (fd >= 0) { - D("client: connected on remote on fd %d\n", fd); + D("connected on remote on fd '%d', port '%d'\n", fd, sdb_port); close_on_exec(fd); disable_tcp_nagle(fd); - snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port); + + + snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, sdb_port); register_socket_transport(fd, buf, sdb_port, 1, device_name); + + // noti to sensord port to enable shell context menu on + notify_sensord(sdb_port); return 0; } + D("failed to connect on port '%d'\n", sdb_port); return -1; } -int get_devicename_from_shdmem(int port, char *device_name) +static int get_devicename_from_shdmem(int port, char *device_name) { char *vms = NULL; #ifndef OS_WINDOWS @@ -136,8 +119,10 @@ int get_devicename_from_shdmem(int port, char *device_name) void *shared_memory = (void *)0; shm_id = shmget( (key_t)port-1, 0, 0); - if (shm_id == -1) + if (shm_id == -1) { + D("failed to get shm from key:(%d)\n", port-1); return -1; + } shared_memory = shmat(shm_id, (void *)0, SHM_RDONLY); @@ -147,10 +132,12 @@ int get_devicename_from_shdmem(int port, char *device_name) return -1; } vms = strstr((char*)shared_memory, VMS_PATH); - if (vms != NULL) - strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); - else - strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); + if (vms != NULL) { + s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); + } else { + D("failed to get vm name from(%s)\n", shared_memory); + return -1; + } #else /* _WIN32*/ HANDLE hMapFile; @@ -161,7 +148,7 @@ int get_devicename_from_shdmem(int port, char *device_name) hMapFile = OpenFileMapping(FILE_MAP_READ, TRUE, s_port); if(hMapFile == NULL) { - D("faild to get shdmem key (%ld) : %s\n", port, GetLastError() ); + D("faild to get shdmem key from port (%d) : (%ld)\n", port, GetLastError() ); return -1; } pBuf = (char*)MapViewOfFile(hMapFile, @@ -176,158 +163,105 @@ int get_devicename_from_shdmem(int port, char *device_name) } vms = strstr((char*)pBuf, VMS_PATH); - if (vms != NULL) - strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); - else - strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); + if (vms != NULL) { + s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); + } else { + D("failed to get vm name from(%s)\n", pBuf); + CloseHandle(hMapFile); + return -1; + } CloseHandle(hMapFile); #endif - // apply for new vms path policy from Jan 23 2013 // vms path should be: ~/tizen-sdk-data/emulator-vms/vms/{name}/emulimg-em1.~~ vms = strtok(device_name, OS_PATH_SEPARATOR_STR); if (vms != NULL) { - strncpy(device_name, vms, DEVICENAME_MAX); + s_strncpy(device_name, vms, DEVICENAME_MAX); + } else { + D("failed to get vm name from(%s)\n", device_name); + return -1; } D("init device name %s on port %d\n", device_name, port); return 0; } -static void *register_local_connections(void *x) -{ - int port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT; - int count = SDB_LOCAL_TRANSPORT_MAX; - - D("transport: client_socket_thread() starting\n"); - - /* try to connect to any number of running emulator instances */ - /* this is only done when SDB starts up. later, each new emulator */ - /* will send a message to SDB to indicate that is is starting up */ - for ( ; count > 0; count--, port += 10 ) { - (void) local_connect(port, NULL); - } - - return 0; -} - -/** - * register local connections - */ -void local_init(int port) -{ - sdb_thread_t thr; - void* (*func)(void *); - - func = register_local_connections; - - if(sdb_thread_create(&thr, func, (void *)port)) { - fatal_errno("cannot create local socket %s thread", - HOST ? "client" : "server"); - } -} - -static void remote_kick(atransport *t) +static void remote_kick(TRANSPORT *t) { int fd = t->sfd; - int nn; +//In Unix, another socket fd can be created while transport thread still uses it +#ifndef OS_WINDOWS t->sfd = -1; +#endif sdb_shutdown(fd); - sdb_close(fd); - - sdb_mutex_lock( &local_transports_lock ); - for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) { - if (local_transports[nn] == t) { - local_transports[nn] = NULL; - break; - } - } - - sdb_mutex_unlock( &local_transports_lock ); -} - -static void remote_close(atransport *t) -{ - sdb_close(t->fd); -} - - -/* Only call this function if you already hold local_transports_lock. */ -atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port) -{ - int i; - for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) { - if (local_transports[i] && local_transports[i]->sdb_port == sdb_port) { - return local_transports[i]; - } - } - return NULL; -} + sdb_transport_close(fd); -atransport* find_emulator_transport_by_sdb_port(int sdb_port) -{ - sdb_mutex_lock( &local_transports_lock ); - atransport* result = find_emulator_transport_by_sdb_port_locked(sdb_port); - sdb_mutex_unlock( &local_transports_lock ); - return result; + --current_local_transports; } -/* Only call this function if you already hold local_transports_lock. */ -int get_available_local_transport_index_locked() +static void remote_close(TRANSPORT *t) { - int i; - for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) { - if (local_transports[i] == NULL) { - return i; - } - } - return -1; -} - -int get_available_local_transport_index() -{ - sdb_mutex_lock( &local_transports_lock ); - int result = get_available_local_transport_index_locked(); - sdb_mutex_unlock( &local_transports_lock ); - return result; + //nothing to close + D("close remote socket. T(%s), device name: '%s'\n", t->serial, t->device_name); } -int init_socket_transport(atransport *t, int s, int sdb_port, int local) +static void init_socket_transport(TRANSPORT *t, int s, int sdb_port) { - int fail = 0; - t->kick = remote_kick; t->close = remote_close; t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sfd = s; - t->sync_token = 1; t->connection_state = CS_OFFLINE; t->type = kTransportLocal; - t->sdb_port = 0; - - if (HOST && local) { - sdb_mutex_lock( &local_transports_lock ); - { - t->sdb_port = sdb_port; - atransport* existing_transport = - find_emulator_transport_by_sdb_port_locked(sdb_port); - int index = get_available_local_transport_index_locked(); - if (existing_transport != NULL) { - D("local transport for port %d already registered (%p)?\n", - sdb_port, existing_transport); - fail = -1; - } else if (index < 0) { - // Too many emulators. - D("cannot register more emulators. Maximum is %d\n", - SDB_LOCAL_TRANSPORT_MAX); - fail = -1; - } else { - local_transports[index] = t; - } - } - sdb_mutex_unlock( &local_transports_lock ); + t->node = NULL; + t->req = 0; + t->res = 0; + t->sdb_port = sdb_port; +} + +void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name) +{ + if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) { + D("Too many emulators\n"); + sdb_close(s); + return; + } + + TRANSPORT *t = calloc(1, sizeof(TRANSPORT)); + char buff[32]; + + if (!serial) { + snprintf(buff, sizeof buff, "T-%p", t); + serial = buff; + } + D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name); + int _port = port; + if(!local) { + _port = 0; + } + init_socket_transport(t, s, _port); + TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL); + if(old_t != NULL) { + D("old transport '%s' is found. Unregister it\n", old_t->serial); + kick_transport(old_t); + } + + t->remote_cnxn_socket = NULL; + if(serial) { + t->serial = strdup(serial); + } + + if (device_name) { + t->device_name = strdup(device_name); + } else { + // device_name could be null when sdb server was forked before qemu has sent the connect message. + t->device_name = (char*) malloc(DEVICENAME_MAX+1); + if (get_devicename_from_shdmem(port, t->device_name) == -1) { + s_strncpy(t->device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); + } } - return fail; + ++current_local_transports; + register_transport(t); } diff --git a/src/transport_usb.c b/src/transport_usb.c old mode 100644 new mode 100755 index b0e557b..270bddd --- a/src/transport_usb.c +++ b/src/transport_usb.c @@ -18,107 +18,100 @@ #include #include +#include "log.h" #include "fdevent.h" #include "utils.h" #define TRACE_TAG TRACE_TRANSPORT -#include "sdb.h" #include "sdb_usb.h" +#include "transport.h" -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -unsigned host_to_le32(unsigned n) -{ - return H4(n); -} -#else -#define fix_endians(p) do {} while (0) -unsigned host_to_le32(unsigned n) -{ - return n; -} -#endif +static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state); -static int remote_read(apacket *p, atransport *t) +static int remote_read(TRANSPORT* t, void* data, int len) { - if(sdb_usb_read(t->usb, &p->msg, sizeof(amessage))){ - D("remote usb: read terminated (message)\n"); - return -1; - } - - fix_endians(p); - - if(check_header(p)) { - D("remote usb: check_header failed\n"); - return -1; - } - - if(p->msg.data_length) { - if(sdb_usb_read(t->usb, p->data, p->msg.data_length)){ - D("remote usb: terminated (data)\n"); - return -1; - } - } - - if(check_data(p)) { - D("remote usb: check_data failed\n"); - return -1; - } - - return 0; + return sdb_usb_read(t->usb, data, len); } -static int remote_write(apacket *p, atransport *t) +static int remote_write(PACKET *p, TRANSPORT *t) { - unsigned size = p->msg.data_length; - - fix_endians(p); - - if(sdb_usb_write(t->usb, &p->msg, sizeof(amessage))) { - D("remote usb: 1 - write terminated\n"); + dump_packet(t->serial, "remote_write_usb", p); + if(sdb_usb_write(t->usb, &p->msg, sizeof(MESSAGE))) { + LOG_ERROR("mesage write error\n"); return -1; } - if(p->msg.data_length == 0) return 0; - if(sdb_usb_write(t->usb, &p->data, size)) { - D("remote usb: 2 - write terminated\n"); - return -1; + + if(p->msg.data_length != 0) { + if(sdb_usb_write(t->usb, &p->data, p->msg.data_length)) { + D("remote usb: 2 - write terminated\n"); + return -1; + } } return 0; } -static void remote_close(atransport *t) +static void remote_close(TRANSPORT *t) { sdb_usb_close(t->usb); t->usb = 0; } -static void remote_kick(atransport *t) +static void remote_kick(TRANSPORT *t) { sdb_usb_kick(t->usb); } -void init_usb_transport(atransport *t, usb_handle *h, int state) +static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state) { D("transport: usb\n"); t->close = remote_close; t->kick = remote_kick; t->read_from_remote = remote_read; t->write_to_remote = remote_write; - t->sync_token = 1; t->connection_state = state; t->type = kTransportUsb; t->usb = h; + t->sdb_port = -1; + t->req = 0; + t->res = 0; +} + +static int get_connected_device_count(transport_type type) +{ + int cnt = 0; + sdb_mutex_lock(&transport_lock, "transport get_connected_device_count"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT *t = curptr->data; + curptr = curptr->next_ptr; + if (type == t->type) { + cnt++; + } + } + + sdb_mutex_unlock(&transport_lock, "transport get_connected_device_count"); + D("connected device count:%d\n",cnt); + return cnt; +} - HOST = 1; +void register_usb_transport(usb_handle *usb, const char *serial) +{ + TRANSPORT *t = calloc(1, sizeof(TRANSPORT)); + char device_name[256]; + + D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, + serial ? serial : ""); + init_usb_transport(t, usb, CS_OFFLINE); + if(serial) { + t->serial = strdup(serial); + } + t->remote_cnxn_socket = NULL; + register_transport(t); + + /* tizen specific */ + sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb)); + t->device_name = strdup(device_name); } int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_protocol) @@ -133,3 +126,20 @@ int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_pro return 0; } + +void close_usb_devices() +{ + sdb_mutex_lock(&transport_lock, "transport close_usb_devices"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; + if ( !t->kicked ) { + t->kicked = 1; + t->kick(t); + } + } + + sdb_mutex_unlock(&transport_lock, "transport close_usb_devices"); +} diff --git a/src/usb_darwin.c b/src/usb_darwin.c new file mode 100755 index 0000000..03c16e0 --- /dev/null +++ b/src/usb_darwin.c @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * documents from https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/USBBook/USBOverview/USBOverview.html + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "fdevent.h" +#include "strutils.h" +#include "memutils.h" +#include "sdb_usb.h" +#include "device_vendors.h" +#include "log.h" +#include "utils.h" +#include "linkedlist.h" +#include "transport.h" + +#define kUSBLanguageEnglish 0x409 + +static IONotificationPortRef gNotifyPort; +static io_iterator_t* gAddedIter; +static CFRunLoopRef gRunLoop; + +static pthread_mutex_t usb_init_lock; +static pthread_cond_t usb_init_cond; + +struct usb_handle { + UInt8 end_point[2]; // 0:in, 1:out + IOUSBInterfaceInterface **interface; + io_object_t usbNotification; + unsigned int zero_mask; +}; + +static void usb_unplugged(usb_handle *handle) { + LOG_INFO("clean interface resources\n"); + if (!handle) + return; + + if (handle->interface) { + (*handle->interface)->USBInterfaceClose(handle->interface); + (*handle->interface)->Release(handle->interface); + handle->interface = 0; + } +} + +void DeviceNotification(void * refCon, io_service_t service, natural_t messageType, + void * messageArgument) { + + kern_return_t kr; + usb_handle *handle = (usb_handle *) refCon; + + if (messageType == kIOMessageServiceIsTerminated) { + LOG_DEBUG("Device 0x%08x removed.\n", service); + + kr = IOObjectRelease(handle->usbNotification); + sdb_usb_kick(handle); + } + +} + +/** + * Authors: Vipul Gupta, Pete St. Pierre + **/ +static void UsbCharactersToHostCharacters(UniChar *p, UInt16 len) { + for (; len > 0; --len, ++p) + *p = USBToHostWord(*p); +} + +kern_return_t getUSBSerial(IOUSBDeviceInterface182 **dev, UInt8 string_id, char *spotSerial) { + UInt8 buffer[256]; + UInt16 result_length; + CFStringRef result; + kern_return_t kr = -1; + IOUSBDevRequest request; + + memset(buffer, 0, sizeof(buffer)); + if (string_id != 0) { + result_length = sizeof(buffer); + request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); + request.bRequest = kUSBRqGetDescriptor; + request.wValue = (kUSBStringDesc << 8) | string_id; + request.wIndex = kUSBLanguageEnglish; + request.wLength = result_length; + request.pData = buffer; + kr = (*dev)->DeviceRequest(dev, &request); + + if ((kIOReturnSuccess == kr) && (request.wLength > 0) + && (request.wLength <= sizeof(buffer))) { + result_length = buffer[0]; + if ((0 < result_length) && (result_length <= sizeof(buffer))) { + /* + * Convert USB string (always little-endian) to host-endian but + * leave the descriptor type byte and the length alone. + */ + UsbCharactersToHostCharacters(((UniChar *) buffer) + 1, ((result_length - 2) >> 1)); + + /* Recreate a string from the buffer of unicode characters */ + result = CFStringCreateWithCharacters(kCFAllocatorDefault, ((UniChar *) buffer) + 1, + ((result_length - 2) >> 1)); + + /* Copy the character contents to a local C string */ + CFStringGetCString(result, spotSerial, MAX_SERIAL_NAME, kCFStringEncodingASCII); + } + } + } + + return kr; +} + +static IOReturn FindInterfaces(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product, + usb_handle *handle) { + IOReturn kr; + UInt8 intfClass; + UInt8 intfSubClass; + UInt8 intfProtocol; + UInt8 intfNumEndpoints; + int pipeRef; + + // open the interface. This will cause the pipes to be instantiated that are + // associated with the endpoints defined in the interface descriptor. + kr = (*interface)->USBInterfaceOpen(interface); + if (kIOReturnSuccess != kr) { + LOG_DEBUG("unable to open interface (%08x)\n", kr); + return kr; + } + + kr = (*interface)->GetNumEndpoints(interface, &intfNumEndpoints); + if (kIOReturnSuccess != kr) { + LOG_DEBUG("unable to get number of endpoints (%08x)\n", kr); + (void) (*interface)->USBInterfaceClose(interface); + return kr; + } + + kr = (*interface)->GetInterfaceClass(interface, &intfClass); + kr = (*interface)->GetInterfaceSubClass(interface, &intfSubClass); + kr = (*interface)->GetInterfaceProtocol(interface, &intfProtocol); + + LOG_DEBUG("interface class %0x, subclass %0x, protocol: %0x\n", intfClass, intfSubClass, + intfProtocol); + + if (!is_sdb_interface(vendor, intfClass, intfSubClass, intfProtocol)) { + LOG_DEBUG("it is not sdb interface\n"); + (void) (*interface)->USBInterfaceClose(interface); + return kIOReturnError; + } + + for (pipeRef = 0; pipeRef <= intfNumEndpoints; pipeRef++) { + UInt8 direction; + UInt8 number; + UInt8 transferType; + UInt16 maxPacketSize; + UInt8 interval; + char *message; + + kr = (*interface)->GetPipeProperties(interface, pipeRef, &direction, &number, &transferType, + &maxPacketSize, &interval); + if (kIOReturnSuccess != kr) + LOG_DEBUG("unable to get properties of pipe %d (%08x)\n", pipeRef, kr); + else { + LOG_DEBUG("++ pipeRef:%d: ++\n ", pipeRef); + + switch (transferType) { + case kUSBControl: + message = "control"; + break; + case kUSBIsoc: + message = "isoc"; + break; + case kUSBBulk: + message = "bulk"; + break; + case kUSBInterrupt: + message = "interrupt"; + break; + case kUSBAnyType: + message = "any"; + break; + default: + message = "???"; + } + LOG_DEBUG("transfer type:%s, maxPacketSize:%d\n", message, maxPacketSize); + if (kUSBBulk != transferType) { + continue; + } + handle->zero_mask = maxPacketSize - 1; + + switch (direction) { + case kUSBOut: + message = "out"; + handle->end_point[1] = pipeRef; + break; + case kUSBIn: + message = "in"; + handle->end_point[0] = pipeRef; + break; + case kUSBNone: + message = "none"; + break; + case kUSBAnyDirn: + message = "any"; + break; + default: + message = "???"; + } + LOG_DEBUG("direction:%0x(%s)\n", pipeRef, message); + kr = kIOReturnSuccess; + } + } + handle->interface = interface; + + return kr; +} + +void DeviceAdded(void *refCon, io_iterator_t iterator) { + kern_return_t kr; + io_service_t usbDevice; + io_service_t usbInterface; + IOCFPlugInInterface **ioDev = NULL; + IOUSBDeviceInterface182 **intf = NULL; + IOUSBInterfaceInterface220 **interface = NULL; + SInt32 score; + HRESULT res; + UInt16 usbVendor; + UInt16 usbProduct; + UInt8 serialIndex; + char serial[256]; + + while ((usbInterface = IOIteratorNext(iterator))) { + // Create an intermediate plug-in + kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, &ioDev, &score); + IOObjectRelease(usbInterface); + + if ((kIOReturnSuccess != kr) || !ioDev) { + LOG_DEBUG("couldn't create a device interface plugin, find next...\n"); + continue; + } + res = (*ioDev)->QueryInterface(ioDev, + CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) & interface); + (*ioDev)->Release(ioDev); + + if (res || !interface) { + LOG_DEBUG("couldn't create an IOUSBInterfaceInterface, find next... \n"); + continue; + } + + kr = (*interface)->GetDevice(interface, &usbDevice); + if (kIOReturnSuccess != kr || !usbDevice) { + LOG_DEBUG("couldn't get device from interface, find next...\n"); + continue; + } + + kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &ioDev, &score); + // Release the usbDevice object after getting the plug-in + IOObjectRelease(usbDevice); + + if ((kIOReturnSuccess != kr) || !ioDev) { + LOG_DEBUG("unable to create a device plugin, find next...\n"); + continue; + } + + // I have the device plugin, I need the device interface + // + res = (*ioDev)->QueryInterface(ioDev, + CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&intf); + (*ioDev)->Release(ioDev); + + if (res || !intf) { + LOG_DEBUG("couldn't create a usb interface, find next...\n"); + continue; + } + // Get vendor, product and serial index + kr = (*intf)->GetDeviceVendor(intf, &usbVendor); + if (kIOReturnSuccess != kr) { + LOG_ERROR("couldn't get usb vendor name\n"); + } + kr = (*intf)->GetDeviceProduct(intf, &usbProduct); + if (kIOReturnSuccess != kr) { + LOG_ERROR("couldn't get usb product name\n"); + } + kr = (*intf)->USBGetSerialNumberStringIndex(intf, &serialIndex); + if (kIOReturnSuccess != kr) { + LOG_ERROR("couldn't get usb serial index\n"); + } + kr = getUSBSerial(intf, serialIndex, serial); + (*intf)->Release(intf); + + usb_handle* handle = calloc(1, sizeof(usb_handle)); + if (handle == NULL) { + LOG_FATAL("could't alloc mememroy\n"); + } + + kr = FindInterfaces((IOUSBInterfaceInterface**) interface, usbVendor, usbProduct, handle); + if (kIOReturnSuccess != kr) { + free(handle); + handle = NULL; + (*interface)->Release(interface); + continue; + } + + LOG_DEBUG("found tizen device and register usb transport.........\n"); + register_usb_transport(handle, serial); + + // Register for an interest notification for this device. Pass the reference to our + // private data as the refCon for the notification. + // + kr = IOServiceAddInterestNotification(gNotifyPort, // notifyPort + usbInterface, // service + kIOGeneralInterest, // interestType + DeviceNotification, // callback + handle, // refCon + &(handle->usbNotification) // notification + ); + + if (kIOReturnSuccess != kr) { + LOG_DEBUG("IOServiceAddInterestNotification returned 0x%08x\n", kr); + } + + } + LOG_DEBUG("signal to wake up main thread\n"); + sdb_mutex_lock(&usb_init_lock, "++usb locking++"); + sdb_cond_signal(&usb_init_cond); + sdb_mutex_unlock(&usb_init_lock, "--usb unlocking--"); +} + +static int cleanup_flag = 0; +static void sig_handler(int sigraised) { + int i = 0; + + LOG_DEBUG("Interrupted!\n"); + + if (cleanup_flag == 1) { + return; + } + + // Clean up + for (i = 0; i < vendor_total_cnt; i++) { + IOObjectRelease(gAddedIter[i]); + } + gAddedIter = NULL; + + IONotificationPortDestroy(gNotifyPort); + gRunLoop = 0; + + if (gAddedIter != NULL) { + s_free(gAddedIter); + gAddedIter = NULL; + } + + LOG_DEBUG("RunLoopThread done\n"); + if (gRunLoop) { + CFRunLoopStop(gRunLoop); + } + cleanup_flag = 1; +} + +void do_lsusb(void) { + mach_port_t masterPort; + CFMutableDictionaryRef matchingDict; + CFRunLoopSourceRef runLoopSource; + CFNumberRef numberRef; + kern_return_t kr; + SInt32 usbVendor, subClass, protocol; + sig_t oldHandler; + int i = 0; + + // Set up a signal handler so we can clean up when we're interrupted from the command line + // Otherwise we stay in our run loop forever. + // + oldHandler = signal(SIGINT, sig_handler); + if (oldHandler == SIG_ERR) { + LOG_DEBUG("Could not establish new signal handler\n"); + } + + // first create a master_port for my task + // + kr = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (kr || !masterPort) { + LOG_DEBUG("ERR: Couldn't create a master IOKit Port(%08x)\n", kr); + return; + } + + // Create a notification port and add its run loop event source to our run loop + // This is how async notifications get set up. + // + gNotifyPort = IONotificationPortCreate(masterPort); + runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort); + + gRunLoop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode); + + for (i = 0; tizen_device_vendors[i].vendor != NULL; i++) { + // Set up the matching criteria for the devices we're interested in. The matching criteria needs to follow + // the same rules as kernel drivers: mainly it needs to follow the USB Common Class Specification, pp. 6-7. + // See also http://developer.apple.com/qa/qa2001/qa1076.html + // One exception is that you can use the matching dictionary "as is", i.e. without adding any matching criteria + // to it and it will match every IOUSBDevice in the system. IOServiceAddMatchingNotification will consume this + // dictionary reference, so there is no need to release it later on. + // + matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); // Interested in instances of class + // IOUSBInterface and its subclasses + if (!matchingDict) { + LOG_DEBUG("Can't create a USB matching dictionary\n"); + mach_port_deallocate(mach_task_self(), masterPort); + return; + } + usbVendor = tizen_device_vendors[i].id; + subClass = SDB_INTERFACE_SUBCLASS; + protocol = SDB_INTERFACE_PROTOCOL; + + LOG_DEBUG( + "Looking for devices matching vendor ID=%0x(%0x, %0x)\n", usbVendor, subClass, protocol); + + // We are interested in all USB Devices (as opposed to USB interfaces). The Common Class Specification + // tells us that we need to specify the idVendor, idProduct, and bcdDevice fields, or, if we're not interested + // in particular bcdDevices, just the idVendor and idProduct. Note that if we were trying to match an IOUSBInterface, + // we would need to set more values in the matching dictionary (e.g. idVendor, idProduct, bInterfaceNumber and + // bConfigurationValue. + // + + // Create a CFNumber for the idVendor, interface subclass and protocol and set the value in the dictionary + // + numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor); + CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef); + CFRelease(numberRef); + + numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &subClass); + CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), numberRef); + CFRelease(numberRef); + + numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &protocol); + CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), numberRef); + CFRelease(numberRef); + + numberRef = 0; + + // Now set up a notification to be called when a device is first matched by I/O Kit. + // Note that this will not catch any devices that were already plugged in so we take + // care of those later. + // + kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort + kIOFirstMatchNotification, // notificationType + matchingDict, // matching + DeviceAdded, // callback + NULL, // refCon + &gAddedIter[i] // notification + ); + + // Iterate once to get already-present devices and arm the notification + // + DeviceAdded(NULL, gAddedIter[i]); + } + + // Now done with the master_port + mach_port_deallocate(mach_task_self(), masterPort); + masterPort = 0; + + // Start the run loop. Now we'll receive notifications. + // + LOG_DEBUG("Starting run loop.\n"); + CFRunLoopRun(); + + // We should never get here + // + LOG_DEBUG("Unexpectedly back from CFRunLoopRun()!\n"); +} + +void* usb_poll_thread(void* sleep_msec) { + LOG_DEBUG("created usb detecting thread\n"); + do_lsusb(); + return NULL; +} + +void sdb_usb_init() { + sdb_thread_t tid; + + init_device_vendors(); + gAddedIter = (io_iterator_t*) s_malloc(vendor_total_cnt * sizeof(io_iterator_t)); + if (gAddedIter == NULL) { + LOG_FATAL("Cound not alloc memory\n"); + return; + } + + sdb_mutex_init(&usb_init_lock, NULL); + sdb_cond_init(&usb_init_cond, NULL); + + if (sdb_thread_create(&tid, usb_poll_thread, NULL)) { + LOG_FATAL("cannot create usb poll thread\n"); + } + sdb_mutex_lock(&usb_init_lock, "++usb locking++"); + + LOG_DEBUG("waiting until to finish to initilize....\n"); + // wait til finish to initialize some setting for usb detection + sdb_cond_wait(&usb_init_cond, &usb_init_lock); + + LOG_DEBUG("woke up done....\n"); + sdb_mutex_unlock(&usb_init_lock, "--usb unlocking--"); + sdb_mutex_destroy(&usb_init_lock); + sdb_cond_destroy(&usb_init_cond); +} + +void sdb_usb_cleanup() { + // called when server stop or interrupted + close_usb_devices(); + sig_handler(0); +} + +int sdb_usb_write(usb_handle *h, const void *data, int len) { + IOReturn kr; + + kr = (*h->interface)->WritePipe(h->interface, h->end_point[1], (void *) data, len); + if (kr == kIOReturnSuccess) { + if (h->zero_mask && !(h->zero_mask & len)) { + (*h->interface)->WritePipe(h->interface, h->end_point[1], (void *) data, 0); + } + return 0; + } + + LOG_DEBUG("Unable to perform bulk write (%08x)\n", kr); + return -1; +} + +int sdb_usb_read(usb_handle *h, void *data, int len) { + IOReturn kr; + UInt32 size = len; + + kr = (*h->interface)->ReadPipe(h->interface, h->end_point[0], data, &size); + + if (kIOReturnSuccess != kr) { + LOG_DEBUG("Unable to perform bulk read (%08x)\n", kr); + return -1; + } + + return 0; +} + +int sdb_usb_close(usb_handle *h) { + return 0; +} + +void sdb_usb_kick(usb_handle *h) { + usb_unplugged(h); +} diff --git a/src/usb_linux.c b/src/usb_linux.c old mode 100755 new mode 100644 index 499b0c3..6a73663 --- a/src/usb_linux.c +++ b/src/usb_linux.c @@ -13,433 +13,467 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include #include #include #include - -#include -#include -#include -#include -#include #include -#include - -#include -#include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) +#include +#include #include -#else -#include -#endif -#include - +#include +#include +#include -#include "fdevent.h" #include "utils.h" +#include "fdevent.h" +#include "strutils.h" +#include "sdb_usb.h" +#include "log.h" +#include "transport.h" + #define TRACE_TAG TRACE_USB -#include "sdb.h" +#define URB_TRANSFER_TIMEOUT 0 +SDB_MUTEX_DEFINE( usb_lock); +LIST_NODE* usb_list = NULL; -/* usb scan debugging is waaaay too verbose */ -#define DBGX(x...) +struct usb_handle { + LIST_NODE* node; -SDB_MUTEX_DEFINE( usb_lock ); + char unique_node_path[PATH_MAX + 1]; + int node_fd; + unsigned char end_point[2]; // 0:in, 1:out + int interface; +}; -struct usb_handle -{ - usb_handle *prev; - usb_handle *next; +int register_device(const char* node, const char* serial) { + int fd; + unsigned char device_desc[4096]; + unsigned char* desc_current_ptr = NULL; - char fname[64]; - int desc; - unsigned char ep_in; - unsigned char ep_out; + if (node == NULL) { + return -1; + } + if (is_device_registered(node)) { + LOG_DEBUG("already registered device: %s\n", node); + return -1; + } + if ((fd = open(node, O_RDWR)) < 0) { + LOG_DEBUG("failed to open usb node %s (%s)\n", node, strerror(errno)); + return -1; + } - unsigned zero_mask; - unsigned writeable; + if (read(fd, device_desc, sizeof(device_desc)) < 0) { + LOG_DEBUG("failed to read usb node %s (%s)\n", node, strerror(errno)); + close(fd); + return -1; + } + desc_current_ptr = device_desc; - struct usbdevfs_urb urb_in; - struct usbdevfs_urb urb_out; + // get device descriptor from head first + struct usb_device_descriptor* usb_dev = + (struct usb_device_descriptor*) desc_current_ptr; - int urb_in_busy; - int urb_out_busy; - int dead; + if (USB_DT_DEVICE_SIZE != usb_dev->bLength) { + LOG_DEBUG("failed to get usb device descriptor\n"); + return -1; + } - sdb_cond_t notify; - sdb_mutex_t lock; + // move to get device config + desc_current_ptr += usb_dev->bLength; - // for garbage collecting disconnected devices - int mark; + // enumerate all available configuration descriptors + int i = 0; + for (i = 0; i < usb_dev->bNumConfigurations; i++) { + struct usb_config_descriptor* usb_config = + (struct usb_config_descriptor *) desc_current_ptr; + if (USB_DT_CONFIG_SIZE != usb_config->bLength) { + LOG_DEBUG("failed to get usb config descriptor\n"); + break; + } + desc_current_ptr += usb_config->bLength; - // ID of thread currently in REAPURB - pthread_t reaper_thread; -}; + unsigned int wTotalLength = usb_config->wTotalLength; + unsigned int wSumLength = usb_config->bLength; -static usb_handle handle_list = { - .prev = &handle_list, - .next = &handle_list, -}; + if (usb_config->bNumInterfaces < 1) { + LOG_DEBUG("there is no interfaces\n"); + break; + } + + while (wSumLength < wTotalLength) { + int bLength = desc_current_ptr[0]; + int bType = desc_current_ptr[1]; + + struct usb_interface_descriptor* usb_interface = + (struct usb_interface_descriptor *) desc_current_ptr; + + if (is_sdb_interface(usb_dev->idVendor, + usb_interface->bInterfaceClass, + usb_interface->bInterfaceSubClass, + usb_interface->bInterfaceProtocol) + && (USB_DT_INTERFACE_SIZE == bLength + && USB_DT_INTERFACE == bType + && 2 == usb_interface->bNumEndpoints)) { + desc_current_ptr += usb_interface->bLength; + wSumLength += usb_interface->bLength; + struct usb_endpoint_descriptor *endpoint1 = + (struct usb_endpoint_descriptor *) desc_current_ptr; + desc_current_ptr += endpoint1->bLength; + wSumLength += endpoint1->bLength; + struct usb_endpoint_descriptor *endpoint2 = + (struct usb_endpoint_descriptor *) desc_current_ptr; + unsigned char endpoint_in; + unsigned char endpoint_out; + unsigned char interface = usb_interface->bInterfaceNumber; + // TODO: removed! + { + int bConfigurationValue = 2; + int n = ioctl(fd, USBDEVFS_RESET); + if (n != 0) { + LOG_DEBUG("usb reset failed\n"); + } + n = ioctl(fd, USBDEVFS_SETCONFIGURATION, + &bConfigurationValue); + if (n != 0) { + LOG_DEBUG("check kernel is supporting %dth configuration\n", bConfigurationValue); + } + + n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface); + if (n != 0) { + LOG_DEBUG("usb claim failed\n"); + } + } + + // find in/out endpoint address + if ((endpoint1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) { + endpoint_in = endpoint1->bEndpointAddress; + endpoint_out = endpoint2->bEndpointAddress; + } else { + endpoint_out = endpoint1->bEndpointAddress; + endpoint_in = endpoint2->bEndpointAddress; + } + // for now i can agree to register usb + { + usb_handle* usb = NULL; + usb = calloc(1, sizeof(usb_handle)); + + if (usb == NULL) { + break; + } + usb->node_fd = fd; + usb->interface = usb_interface->bInterfaceNumber; + usb->end_point[0] = endpoint_in; + usb->end_point[1] = endpoint_out; + + char usb_serial[MAX_SERIAL_NAME] = { 0, }; + + if (serial != NULL) { + s_strncpy(usb_serial, serial, sizeof(usb_serial)); + } else { + strcpy(usb_serial, "unknown"); + } + s_strncpy(usb->unique_node_path, node, + sizeof(usb->unique_node_path)); + + sdb_mutex_lock(&usb_lock, "usb register locked"); + usb->node = prepend(&usb_list, usb); + LOG_DEBUG("-register new device (in: %04x, out: %04x) from %s\n", usb->end_point[0], usb->end_point[1], node); -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; + register_usb_transport(usb, usb_serial); + sdb_mutex_unlock(&usb_lock, "usb register unlocked"); + } + desc_current_ptr += endpoint2->bLength; + wSumLength += endpoint2->bLength; + + } else { + wSumLength += usb_interface->bLength; + desc_current_ptr += usb_interface->bLength; + } } } - sdb_mutex_unlock(&usb_lock); return 0; } -static void linux_kick_disconnected_devices() -{ - usb_handle *usb; - - sdb_mutex_lock(&usb_lock); - // kick any devices in the device list that were not found in the device scan - for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ - if (usb->mark == 0) { - sdb_usb_kick(usb); - } else { - usb->mark = 0; - } +static void usb_plugged(struct udev_device *dev) { + if (udev_device_get_devnode(dev) != NULL) { + register_device(udev_device_get_devnode(dev), + udev_device_get_sysattr_value(dev, "serial")); } - sdb_mutex_unlock(&usb_lock); +} +static void usb_unplugged(struct udev_device *dev) { + LOG_INFO("check device is removed from the list\n"); } -static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out, - int ifc, int serial_index, unsigned zero_mask); +int usb_register_callback(int msec) { + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; -static inline int badname(const char *name) -{ - while(*name) { - if(!isdigit(*name++)) return 1; + struct udev_monitor *mon; + int fd; + + // Create the udev object + udev = udev_new(); + if (!udev) { + LOG_DEBUG("Can't create udev\n"); + exit(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; - } + // 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); -// DBGX("[ scanning %s ]\n", devname); - if((fd = unix_open(devname, O_RDONLY)) < 0) { - continue; - } + // Get the file descriptor (fd) for the monitor. This fd will get passed to select() + fd = udev_monitor_get_fd(mon); - desclength = sdb_read(fd, devdesc, sizeof(devdesc)); - bufend = bufptr + desclength; + // Create a list of the devices in the 'usb' subsystem. + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "usb"); + udev_enumerate_scan_devices(enumerate); - // 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; - } + devices = udev_enumerate_get_list_entry(enumerate); - device = (struct usb_device_descriptor*)bufptr; - bufptr += USB_DT_DEVICE_SIZE; + LOG_DEBUG("doing lsusb to find tizen devices\n"); + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path; - if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) { - sdb_close(fd); - continue; + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + usb_plugged(dev); + udev_device_unref(dev); + + } + // Free the enumerator object + udev_enumerate_unref(enumerate); + LOG_DEBUG("done lsusb to find tizen devices\n"); + while (1) { + fd_set fds; + struct timeval tv; + int ret; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + ret = select(fd + 1, &fds, NULL, NULL, &tv); + + if (ret > 0 && FD_ISSET(fd, &fds)) { + dev = udev_monitor_receive_device(mon); + if (dev) { + if (!strcmp("add", udev_device_get_action(dev))) { + usb_plugged(dev); + } else { + usb_unplugged(dev); + } + udev_device_unref(dev); + } else { + LOG_DEBUG("failed to get noti from udev monitor\n"); } + } + usleep(msec); + } + udev_unref(udev); - vid = device->idVendor; - pid = device->idProduct; - DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid); + return 0; +} - // should have config descriptor next - config = (struct usb_config_descriptor *)bufptr; +int is_device_registered(const char *unique_node_path) { + int r = 0; + sdb_mutex_lock(&usb_lock, "usb registering locked"); - /* tizen specific */ - if (device->bNumConfigurations > 1) { - bufptr += config->wTotalLength; - config = (struct usb_config_descriptor *)bufptr; - bufend = bufptr + config->wTotalLength; - } + LIST_NODE* curptr = usb_list; + while (curptr != NULL) { + usb_handle *usb = curptr->data; + if (!strcmp(usb->unique_node_path, unique_node_path)) { + r = 1; + break; + } + curptr = curptr->next_ptr; + } - 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; - } + sdb_mutex_unlock(&usb_lock, "usb registering unlocked"); + return r; +} - // loop through all the descriptors and look for the SDB interface - while (bufptr < bufend) { - unsigned char length = bufptr[0]; - unsigned char type = bufptr[1]; +void* usb_callback_thread(void* sleep_msec) { + LOG_DEBUG("created usb callback thread\n"); + int mseconds = (int) sleep_msec; - if (type == USB_DT_INTERFACE) { - interface = (struct usb_interface_descriptor *)bufptr; - bufptr += length; + usb_register_callback(mseconds); - if (length != USB_DT_INTERFACE_SIZE) { - D("interface descriptor has wrong size\n"); - break; - } + return NULL; +} - DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d," - "bInterfaceProtocol: %d, bNumEndpoints: %d\n", - interface->bInterfaceClass, interface->bInterfaceSubClass, - interface->bInterfaceProtocol, interface->bNumEndpoints); - - if (interface->bNumEndpoints == 2 && - is_sdb_interface(vid, interface->bInterfaceClass, - interface->bInterfaceSubClass, interface->bInterfaceProtocol)) { - - D("looking for bulk endpoints\n"); - // looks like SDB... - ep1 = (struct usb_endpoint_descriptor *)bufptr; - bufptr += USB_DT_ENDPOINT_SIZE; - ep2 = (struct usb_endpoint_descriptor *)bufptr; - bufptr += USB_DT_ENDPOINT_SIZE; - - if (bufptr > devdesc + desclength || - ep1->bLength != USB_DT_ENDPOINT_SIZE || - ep1->bDescriptorType != USB_DT_ENDPOINT || - ep2->bLength != USB_DT_ENDPOINT_SIZE || - ep2->bDescriptorType != USB_DT_ENDPOINT) { - D("endpoints not found\n"); - break; - } - - // both endpoints should be bulk - if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK || - ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) { - D("bulk endpoints not found\n"); - continue; - } - /* aproto 01 needs 0 termination */ - if(interface->bInterfaceProtocol == 0x01) { - zero_mask = ep1->wMaxPacketSize - 1; - } - - // we have a match. now we just need to figure out which is in and which is out. - if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { - local_ep_in = ep1->bEndpointAddress; - local_ep_out = ep2->bEndpointAddress; - } else { - local_ep_in = ep2->bEndpointAddress; - local_ep_out = ep1->bEndpointAddress; - } - - register_device_callback(devname, local_ep_in, local_ep_out, - interface->bInterfaceNumber, device->iSerialNumber, zero_mask); - break; - } - } else { - bufptr += length; - } - } // end of while +void sdb_usb_init(void) { + sdb_thread_t tid; - sdb_close(fd); - } // end of devdir while - closedir(devdir); - } //end of busdir while - closedir(busdir); + if (sdb_thread_create(&tid, usb_callback_thread, (void*) (250 * 1000))) { + LOG_FATAL("cannot create input thread\n"); + } } -void sdb_usb_cleanup() -{ +void sdb_usb_cleanup() { + close_usb_devices(); } -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; +#define URB_USERCONTEXT_COOKIE ((void *)0x1) + +static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size, + int timeout) { + struct usbdevfs_urb urb; + int bytesdone = 0, requested; + struct timeval tv, tv_ref, tv_now; + struct usbdevfs_urb *context; + int ret, waiting; + + struct timeval tv_cur; + /* + * HACK: The use of urb.usercontext is a hack to get threaded applications + * sort of working again. Threaded support is still not recommended, but + * this should allow applications to work in the common cases. Basically, + * if we get the completion for an URB we're not waiting for, then we update + * the usercontext pointer to 1 for the other threads URB and it will see + * the change after it wakes up from the the timeout. Ugly, but it works. + */ + + /* + * Get actual time, and add the timeout value. The result is the absolute + * time where we have to quit waiting for an message. + */ + if (gettimeofday(&tv_cur, NULL) != 0) { + LOG_DEBUG("failed to read clock\n"); + return -1; } - do { - res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb); - } while((res < 0) && (errno == EINTR)); + tv_cur.tv_sec = tv_cur.tv_sec + timeout / 1000; + tv_cur.tv_usec = tv_cur.tv_usec + (timeout % 1000) * 1000; - if(res < 0) { - goto fail; + if (tv_cur.tv_usec > 1000000) { + tv_cur.tv_usec -= 1000000; + tv_cur.tv_sec++; } - 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; + do { + fd_set writefds; + + requested = size - bytesdone; + if (requested > MAX_READ_WRITE) { + requested = MAX_READ_WRITE; + LOG_DEBUG("requested bytes over than %d\n", MAX_READ_WRITE); } - if(h->urb_out_busy == 0) { - if(urb->status == 0) { - res = urb->actual_length; - } - break; + + urb.type = USBDEVFS_URB_TYPE_BULK; + urb.endpoint = ep; + urb.flags = 0; + urb.buffer = bytes + bytesdone; + urb.buffer_length = requested; + urb.signr = 0; + urb.actual_length = 0; + urb.number_of_packets = 0; /* don't do isochronous yet */ + urb.usercontext = NULL; + + ret = ioctl(h->node_fd, USBDEVFS_SUBMITURB, &urb); + if (ret < 0) { + LOG_DEBUG("failed to submit urb: %s\n", strerror(errno)); + return -1; } - } -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; + FD_ZERO(&writefds); + FD_SET(h->node_fd, &writefds); + + restart: waiting = 1; + context = NULL; + for (;;) { + ret = ioctl(h->node_fd, USBDEVFS_REAPURBNDELAY, &context); + int saved_errno = errno; + if (!urb.usercontext && (ret == -1) && waiting) { + // continue but, + if (saved_errno == ENODEV) { + LOG_DEBUG("device may be unplugged: %s\n", strerror(saved_errno)); + break; + } + } else { + break; + } - 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; + tv.tv_sec = 0; + tv.tv_usec = 1000; // 1 msec + select(h->node_fd + 1, NULL, &writefds, NULL, &tv); //sub second wait - 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; - } + if (timeout) { + /* compare with actual time, as the select timeout is not that precise */ + gettimeofday(&tv_now, NULL); - 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; + if ((tv_now.tv_sec > tv_cur.tv_sec) + || ((tv_now.tv_sec == tv_cur.tv_sec) + && (tv_now.tv_usec >= tv_ref.tv_usec))) { + waiting = 0; + } } - break; } - if(out == &h->urb_out) { - D("[ reap urb - OUT compelete ]\n"); - h->urb_out_busy = 0; - sdb_cond_broadcast(&h->notify); + + if (context && context != &urb) { + context->usercontext = URB_USERCONTEXT_COOKIE; + /* We need to restart since we got a successful URB, but not ours */ + goto restart; } + + /* + * If there was an error, that wasn't EAGAIN (no completion), then + * something happened during the reaping and we should return that + * error now + */ + if (ret < 0 && !urb.usercontext && errno != EAGAIN) + LOG_DEBUG("error reaping URB: %s\n", strerror(errno)); + + bytesdone += urb.actual_length; + } while ((ret == 0 || urb.usercontext) && bytesdone < size + && urb.actual_length == requested); + + /* If the URB didn't complete in success or error, then let's unlink it */ + if (ret < 0 && !urb.usercontext) { + int rc; + if (!waiting) + rc = -ETIMEDOUT; + else + rc = urb.status; + + ret = ioctl(h->node_fd, USBDEVFS_DISCARDURB, &urb); + if (ret < 0 && errno != EINVAL) + LOG_DEBUG("error discarding URB: %s\n", strerror(errno)); + + /* + * When the URB is unlinked, it gets moved to the completed list and + * then we need to reap it or else the next time we call this function, + * we'll get the previous completion and exit early + */ + ioctl(h->node_fd, USBDEVFS_REAPURB, &context); + + return rc; } -fail: - sdb_mutex_unlock(&h->lock); - return res; + + return bytesdone; } +int sdb_usb_write(usb_handle *h, const void *_data, int len) { + char *data = (char*) _data; + int n = 0; -int sdb_usb_write(usb_handle *h, const void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; - int n; - int need_zero = 0; - - if(h->zero_mask) { - /* if we need 0-markers and our transfer - ** is an even multiple of the packet size, - ** we make note of it - */ - if(!(len & h->zero_mask)) { - need_zero = 1; - } - } + LOG_DEBUG("+sdb_usb_write\n"); - while(len > 0) { - int xfer = (len > 4096) ? 4096 : len; + while (len > 0) { + int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len; - n = usb_bulk_write(h, data, xfer); - if(n != xfer) { - D("ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); + n = usb_urb_transfer(h, h->end_point[1], data, xfer, URB_TRANSFER_TIMEOUT); + if (n != xfer) { + LOG_DEBUG("fail to usb write: n = %d, errno = %d (%s)\n", n, errno, strerror(errno)); return -1; } @@ -447,37 +481,31 @@ int sdb_usb_write(usb_handle *h, const void *_data, int len) data += xfer; } - if(need_zero){ - n = usb_bulk_write(h, _data, 0); - return n; - } + LOG_DEBUG("-usb_write\n"); return 0; } -int sdb_usb_read(usb_handle *h, void *_data, int len) -{ - unsigned char *data = (unsigned char*) _data; +int sdb_usb_read(usb_handle *h, void *_data, int len) { + char *data = (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){ + LOG_DEBUG("+sdb_usb_read\n"); + + while (len > 0) { + int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len; + + n = usb_urb_transfer(h, h->end_point[0], data, xfer, URB_TRANSFER_TIMEOUT); + if (n != xfer) { + if ((errno == ETIMEDOUT)) { + LOG_DEBUG("usb bulk read timeout\n"); + if (n > 0) { data += n; len -= n; } continue; } - D("ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); + LOG_DEBUG("fail to usb read: n = %d, errno = %d (%s)\n", n, errno, strerror(errno)); return -1; } @@ -485,230 +513,28 @@ int sdb_usb_read(usb_handle *h, void *_data, int len) data += xfer; } - D("-- usb_read --\n"); - return 0; -} - -void sdb_usb_kick(usb_handle *h) -{ - D("[ kicking %p (fd = %d) ]\n", h, h->desc); - sdb_mutex_lock(&h->lock); - if(h->dead == 0) { - h->dead = 1; - - if (h->writeable) { - /* HACK ALERT! - ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB). - ** This is a workaround for that problem. - */ - if (h->reaper_thread) { - pthread_kill(h->reaper_thread, SIGALRM); - } - - /* cancel any pending transactions - ** these will quietly fail if the txns are not active, - ** but this ensures that a reader blocked on REAPURB - ** will get unblocked - */ - ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in); - ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out); - h->urb_in.status = -ENODEV; - h->urb_out.status = -ENODEV; - h->urb_in_busy = 0; - h->urb_out_busy = 0; - sdb_cond_broadcast(&h->notify); - } else { - unregister_usb_transport(h); - } - } - sdb_mutex_unlock(&h->lock); -} - -int sdb_usb_close(usb_handle *h) -{ - D("[ usb close ... ]\n"); - sdb_mutex_lock(&usb_lock); - h->next->prev = h->prev; - h->prev->next = h->next; - h->prev = 0; - h->next = 0; - - sdb_close(h->desc); - D("[ usb closed %p (fd = %d) ]\n", h, h->desc); - sdb_mutex_unlock(&usb_lock); + LOG_DEBUG("-sdb_usb_read\n"); - 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); - // TODO: verify reset is really needed! - n = ioctl(usb->desc, USBDEVFS_RESET); - if(n != 0) { - D("[ usb reset failed %s fd = %d]\n", usb->fname, usb->desc); - } - n = ioctl(usb->desc, USBDEVFS_SETCONFIGURATION, &bConfigurationValue); - if (n != 0) { - D("[ usb set %d configuration failed %s fd = %d]\n", bConfigurationValue, usb->fname, usb->desc); - D("check kernel is supporting %dth configuration\n", bConfigurationValue); - } - - n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); - if(n != 0) { - D("[ usb claim failed %s fd = %d]\n", usb->fname, usb->desc); - } - } - - /* 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 sdb_usb_kick(usb_handle *h) { + LOG_DEBUG("+kicking\n"); + LOG_DEBUG("-kicking\n"); } -void* device_poll_thread(void* unused) -{ - D("Created device thread\n"); - for(;;) { - /* XXX use inotify */ - find_usb_device("/dev/bus/usb", register_device); - linux_kick_disconnected_devices(); - sleep(1); - } - return NULL; -} +int sdb_usb_close(usb_handle *h) { + LOG_DEBUG("+usb close\n"); -static void sigalrm_handler(int signo) -{ - // don't need to do anything here -} - -void sdb_usb_init() -{ - sdb_thread_t tid; - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = sigalrm_handler; - sigaction(SIGALRM,& actions, NULL); - - if(sdb_thread_create(&tid, device_poll_thread, NULL)){ - fatal_errno("cannot create input thread"); + if (h != NULL) { + sdb_mutex_lock(&usb_lock, "usb close locked"); + remove_node(&usb_list, h->node, no_free); + sdb_close(h->node_fd); + free(h); + h = NULL; + sdb_mutex_unlock(&usb_lock, "usb close unlocked"); } + LOG_DEBUG("-usb close\n"); + return 0; } + diff --git a/src/usb_windows.c b/src/usb_windows.c new file mode 100644 index 0000000..a07aeef --- /dev/null +++ b/src/usb_windows.c @@ -0,0 +1,603 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include "fdevent.h" +#include "utils.h" +#include "strutils.h" +#include "linkedlist.h" + +#define TRACE_TAG TRACE_USB +#include "sdb.h" +#include "sdb_usb.h" +#include "ddk/usb100.h" +#include "ddk/usbioctl.h" + +// The USBD_PIPE_TYPE enumerator indicates the type of pipe. +typedef enum _USBD_PIPE_TYPE { + UsbdPipeTypeControl = 0, //Indicates that the pipe is a control pipe. + UsbdPipeTypeIsochronous = 1, //Indicates that the pipe is an isochronous transfer pipe. + UsbdPipeTypeBulk = 2, //Indicates that the pipe is a bulk transfer pipe. + UsbdPipeTypeInterrupt = 3 //Indicates that the pipe is a interrupt pipe. +} USBD_PIPE_TYPE; + +// from Winusbio.h +typedef struct _WINUSB_PIPE_INFORMATION { + USBD_PIPE_TYPE PipeType; //A USBD_PIPE_TYPE-type enumeration value that specifies the pipe type. + UCHAR PipeId; //The pipe identifier (ID). + USHORT MaximumPacketSize; //The maximum size, in bytes, of the packets that are transmitted on the pipe. + UCHAR Interval; //The pipe interval. +} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; + +// from Winusb.h +#pragma pack(1) +typedef struct _WINUSB_SETUP_PACKET { + UCHAR RequestType; //The request type. The values that are assigned to this member are defined in Table 9.2 of section 9.3 of the Universal Serial Bus (USB) specification (www.usb.org). + UCHAR Request; //The device request. The values that are assigned to this member are defined in Table 9.3 of section 9.4 of the Universal Serial Bus (USB) specification. + USHORT Value; //The meaning of this member varies according to the request. For an explanation of this member, see the Universal Serial Bus (USB) specification. + USHORT Index; //The meaning of this member varies according to the request. For an explanation of this member, see the Universal Serial Bus (USB) specification. + USHORT Length; //The number of bytes to transfer. +} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; +#pragma pack() + +typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; + +#define PIPE_TRANSFER_TIMEOUT 0x03 // Waits for a time-out interval before canceling the request +struct usb_handle { + LIST_NODE* node; + + HANDLE hnd; + WINUSB_INTERFACE_HANDLE fd; + char unique_node_path[PATH_MAX+1]; //MAX_DEVICE_ID_LEN \ + UCHAR end_point[2]; + unsigned int zero_mask; +}; +usb_handle *usb_open(const char *device_path); +int win_usb_close(usb_handle *dev); +int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen); +void *device_poll_thread(void* unused); +int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout); +void do_lsusb(void); + +// Class ID assigned to the device by aNdrOiduSb.sys +static const GUID TIZEN_CLASSID = {0x9ca29f37, 0xdd62, 0x4aad, {0x82, 0x65, 0xcf, 0xf7, 0x88, 0xc8, 0xba, 0x89}}; + +static LIST_NODE* handle_list = NULL; + +SDB_MUTEX_DEFINE( usb_lock ); + +HMODULE g_h = NULL; + +#define TYPEDEF_SYMBOL(name, args) \ + typedef BOOL (WINAPI * _##name##_)args; \ + static _##name##_ name + +#define LOAD_FUNCPTR(name) \ + do { \ + if((name = (_##name##_)GetProcAddress(g_h, #name))) \ + break; \ + } while(0) + +// declare all symbols exported by winusb dll +TYPEDEF_SYMBOL(WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); +TYPEDEF_SYMBOL(WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); +TYPEDEF_SYMBOL(WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); +TYPEDEF_SYMBOL(WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); +TYPEDEF_SYMBOL(WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); +TYPEDEF_SYMBOL(WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); +TYPEDEF_SYMBOL(WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); +TYPEDEF_SYMBOL(WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); +TYPEDEF_SYMBOL(WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); +TYPEDEF_SYMBOL(WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +TYPEDEF_SYMBOL(WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +TYPEDEF_SYMBOL(WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +TYPEDEF_SYMBOL(WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +TYPEDEF_SYMBOL(WinUsb_GetOverlappedResult, (WINUSB_INTERFACE_HANDLE, LPOVERLAPPED, LPDWORD, BOOL)); + +void win_usb_init(void) { + // Initialize DLL functions + if (g_h == NULL) { + g_h = GetModuleHandle("winusb.dll"); + if(g_h == NULL) { + g_h = LoadLibrary("winusb.dll"); + } + if(g_h == NULL) { + LOG_DEBUG("cannot load winusb dll\n"); + } + + LOAD_FUNCPTR(WinUsb_Initialize); + LOAD_FUNCPTR(WinUsb_Free); + LOAD_FUNCPTR(WinUsb_GetDescriptor); + LOAD_FUNCPTR(WinUsb_QueryInterfaceSettings); + LOAD_FUNCPTR(WinUsb_SetCurrentAlternateSetting); + LOAD_FUNCPTR(WinUsb_GetCurrentAlternateSetting); + LOAD_FUNCPTR(WinUsb_QueryPipe); + LOAD_FUNCPTR(WinUsb_SetPipePolicy); + LOAD_FUNCPTR(WinUsb_GetPipePolicy); + LOAD_FUNCPTR(WinUsb_ReadPipe); + LOAD_FUNCPTR(WinUsb_WritePipe); + LOAD_FUNCPTR(WinUsb_ControlTransfer); + LOAD_FUNCPTR(WinUsb_ResetPipe); + LOAD_FUNCPTR(WinUsb_GetOverlappedResult); + } +} + +int is_device_registered(const char *node_path) +{ + int r = 0; + sdb_mutex_lock(&usb_lock, "usb is_device_registered"); + + LIST_NODE* cur_ptr = handle_list; + while(cur_ptr != NULL) { + usb_handle* usb = cur_ptr->data; + cur_ptr = cur_ptr->next_ptr; + + if(!strcmp(usb->unique_node_path, node_path)) { + r = 1; + break; + } + } + sdb_mutex_unlock(&usb_lock, "usb is_device_registered"); + return r; +} + +usb_handle *usb_open(const char *device_path) { + // Allocate storage for handles + usb_handle* usb = calloc(1, sizeof(usb_handle)); + s_strncpy(usb->unique_node_path, device_path, sizeof(usb->unique_node_path)); + + // Open generic handle to device + HANDLE hnd = CreateFile(device_path, GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + if (INVALID_HANDLE_VALUE == hnd) { + LOG_DEBUG("fail to create device file: %s due to: %d\n", device_path, GetLastError()); + return NULL; + } + + // Initialize WinUSB for this device and get a WinUSB handle for it + WINUSB_INTERFACE_HANDLE fd; + if (!WinUsb_Initialize(hnd, &fd)) { + return NULL; + } + + // fetch USB device descriptor + USB_DEVICE_DESCRIPTOR usb_device_descriptor; + unsigned long bytes_written; + + if (!WinUsb_GetDescriptor(fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, + (PUCHAR)&usb_device_descriptor, sizeof(usb_device_descriptor), &bytes_written)) { + return NULL; + } + + USB_INTERFACE_DESCRIPTOR usb_interface_descriptor; + + // fetch usb interface descriptor + UCHAR interface_number; + if (!WinUsb_GetCurrentAlternateSetting(fd, &interface_number)) { + return NULL; + } + + if (!WinUsb_QueryInterfaceSettings(fd, interface_number, &usb_interface_descriptor)) { + return NULL; + } + + if (2 != usb_interface_descriptor.bNumEndpoints) { + LOG_DEBUG("the number of endpoint should be two\n"); + return NULL; + } + + if (!is_sdb_interface(usb_device_descriptor.idVendor, usb_interface_descriptor.bInterfaceClass, usb_interface_descriptor.bInterfaceSubClass, + usb_interface_descriptor.bInterfaceProtocol)) { + return NULL; + } + UCHAR endpoint_index = 0; + + for (endpoint_index = 0; endpoint_index < usb_interface_descriptor.bNumEndpoints; endpoint_index++) { + // fetch endpoint information + WINUSB_PIPE_INFORMATION pipe_info; + if (!WinUsb_QueryPipe(fd, interface_number, endpoint_index, &pipe_info)) { + return NULL; + } + + if(usb_interface_descriptor.bInterfaceProtocol == 0x01) { + if (endpoint_index == 0) { + usb->zero_mask = pipe_info.MaximumPacketSize - 1; + } + } + // only interested in bulk type + if (UsbdPipeTypeBulk == pipe_info.PipeType) { + if (USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) { + LOG_DEBUG("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)) { + LOG_DEBUG("builk out endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId); + usb->end_point[1] = pipe_info.PipeId; + } + + } + } + usb->hnd = hnd; + usb->fd = fd; + + return usb; +} + +int register_device(usb_handle *hnd) { + if (is_device_registered(hnd->unique_node_path)) { + return 0; + } + + sdb_mutex_lock(&usb_lock, "usb register_device"); + + hnd->node = prepend(&handle_list, hnd); + + sdb_mutex_unlock(&usb_lock, "usb register_device"); + + return 1; +} + +int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen) { + unsigned char temp[MAXIMUM_USB_STRING_LENGTH]; + + ULONG actlen = 0; + //0x0409 for English (US) + if (!WinUsb_GetDescriptor(dev->fd, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409, temp, sizeof(temp), &actlen)) { + return -GetLastError(); + } + // Skip first two bytes of result (descriptor id and length), then take + // every other byte as a cheap way to convert Unicode to ASCII + unsigned int i, j; + for (i = 2, j = 0; i < actlen && j < (buflen - 1); i += 2, ++j) + buf[j] = temp[i]; + buf[j] = '\0'; + + return strlen(buf); +} + +static int get_serial_number(usb_handle *dev, char *buf, int buflen) { + USB_DEVICE_DESCRIPTOR usb_device_descriptor; + ULONG actlen = 0; + + if (!WinUsb_GetDescriptor(dev->fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (unsigned char*) &usb_device_descriptor, + sizeof(usb_device_descriptor), &actlen)) { + return 0; + } + + return usb_get_string_simple(dev, usb_device_descriptor.iSerialNumber, buf, buflen); +} + +int usb_find_devices(GUID deviceClassID) { + SP_DEVINFO_DATA deviceInfoData; + char devicePath[PATH_MAX + 1]; + BOOL bResult = TRUE; + PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL; + int index = 0; + + // from http://msdn.microsoft.com/en-us/library/windows/hardware/ff540174(v=vs.85).aspx + // Get information about all the installed devices for the specified device interface class. + HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&deviceClassID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (hDeviceInfo == INVALID_HANDLE_VALUE) { + LOG_DEBUG("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) + { + LOG_DEBUG("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) { + LOG_DEBUG("fail to allocate memory\n"); + break; + } + } else { + LOG_DEBUG("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) { + LOG_DEBUG("fail to setdup get device interface detail: %d\n", GetLastError()); + if (detailData != NULL) { + free(detailData); + } + break; + } + + //copy device path + s_strncpy(devicePath, detailData->DevicePath, sizeof(devicePath)); + + if (detailData != NULL) { + free(detailData); + } + + if (!is_device_registered(devicePath)) { + struct usb_handle *hnd = usb_open(devicePath); + if (hnd != NULL) { + char serial[MAX_SERIAL_NAME]={0,}; + if (get_serial_number(hnd, serial, sizeof(serial)) > 0) { + LOG_DEBUG("register usb for: %s\n", serial); + if (register_device(hnd)) { + register_usb_transport(hnd, serial); + } else { + LOG_DEBUG("fail to register usb\n"); + win_usb_close(hnd); + free(hnd); + } + } else { + LOG_DEBUG("fail to get usb serial name: kick? close?\n"); + win_usb_close(hnd); + free(hnd); + } + } + } + } + // Cleanup + bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo); + + return bResult; +} + +void* device_poll_thread(void* sleep_msec) { + LOG_DEBUG("Created device thread\n"); + + int mseconds = (int) sleep_msec; + while (1) { + do_lsusb(); + sdb_sleep_ms(mseconds); + } + + return NULL; +} + +void sdb_usb_init() { + sdb_thread_t tid; + + win_usb_init(); + if (sdb_thread_create(&tid, device_poll_thread, (void*)3000)) { + LOG_FATAL("cannot create input thread\n"); + } +} + +void sdb_usb_cleanup() { + LOG_DEBUG("+all clean resources+\n"); + + if (g_h != NULL) { + FreeLibrary(g_h); + } +} + +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) { + LOG_DEBUG("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)) { + LOG_DEBUG("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); + } + LOG_DEBUG("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; + + LOG_DEBUG("+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(); + LOG_DEBUG("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 { + LOG_DEBUG("usb_write NULL handle\n"); + SetLastError(ERROR_INVALID_HANDLE); + } + + LOG_DEBUG("-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; + + LOG_DEBUG("+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(); + LOG_DEBUG("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 { + LOG_DEBUG("sdb_usb_read NULL handle\n"); + SetLastError(ERROR_INVALID_HANDLE); + } + + LOG_DEBUG("-sdb_usb_read failed: %d\n", errno); + + return -1; +} + +int win_usb_close(usb_handle *handle) { + LOG_DEBUG("+usb win_usb_close\n"); + if (NULL != handle) { + if (NULL != handle->fd) { + WinUsb_Free(handle->fd); + handle->fd = NULL; + } + if (NULL != handle->hnd) { + CloseHandle(handle->hnd); + handle->hnd = NULL; + } + handle = NULL; + } + LOG_DEBUG("-usb win_usb_close\n"); + return 0; +} + +void sdb_usb_kick(usb_handle* handle) { + LOG_DEBUG("+sdb_usb_kick: %p\n", handle); + // called from transport remote kick if already registered + // so only clean for win usb handle resources + sdb_mutex_lock(&usb_lock, "usb sdb_usb_kick"); + win_usb_close(handle); + sdb_mutex_unlock(&usb_lock , "usb sdb_usb_kick"); + LOG_DEBUG("-sdb_usb_kick: %p\n", handle); +} + +int sdb_usb_close(usb_handle* handle) { + LOG_DEBUG("+sdb_usb_close: %p\n", handle); + if (NULL != handle) { + sdb_mutex_lock(&usb_lock, "usb sdb_usb_close"); + remove_node(&handle_list, handle->node, NULL); + sdb_mutex_unlock(&usb_lock, "usb sdb_usb_close"); + } + LOG_DEBUG("-sdb_usb_close: %p\n", handle); + return 0; +} + +void do_lsusb() { + usb_find_devices(TIZEN_CLASSID); +} diff --git a/src/utils.c b/src/utils.c old mode 100644 new mode 100755 index aab3afb..baa2245 --- a/src/utils.c +++ b/src/utils.c @@ -21,10 +21,12 @@ #include "utils.h" #include "utils_backend.h" +#include "log.h" #include "fdevent.h" #include "sdb_constants.h" -#include "sdb.h" + +#define TRACE_TAG TRACE_SDB #if defined(OS_WINDOWS) const struct utils_os_backend* utils_backend = &utils_windows_backend; @@ -174,8 +176,8 @@ void dup_quote(char* result_string, const char *source, int max_len) /**************************************************/ /*** OS dependent helpers ***/ /**************************************************/ -int launch_server(int server_port) { - return utils_backend->launch_server(server_port); +int launch_server(void) { + return utils_backend->launch_server(); } void start_logging(void) { @@ -187,18 +189,23 @@ char* ansi_to_utf8(const char *str) { } int sdb_open(const char* path, int options) { + LOG_INFO("path %s, options %d\n", path, options); return utils_backend->sdb_open(path, options); } -int sdb_open_mode(const char* pathname, int options, int mode) { - return utils_backend->sdb_open_mode(pathname, options, mode); -} - int unix_open(const char* path, int options, ...) { - return utils_backend->unix_open(path, options); + int mode; + va_list args; + + va_start( args, options); + mode = va_arg( args, int ); + va_end( args); + + return open(path, options, mode); } int sdb_creat(const char* path, int mode) { + LOG_INFO("path %s mode %d\n", path, mode); return utils_backend->sdb_creat(path, mode); } @@ -210,20 +217,29 @@ 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); } +//In Windows, just close the socket and not free the SDB_HANDLE because it may be used in transport_thread +int sdb_transport_close(int fd) { + return utils_backend->sdb_transport_close(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 unix_unlink(const char* path) { + int rc = unlink(path); + + if (rc == -1 && errno == EACCES) { + rc = chmod(path, S_IREAD | S_IWRITE); + if (rc == 0) { + rc = unlink(path); + } + } + return rc; } int sdb_mkdir(const char* path, int mode) { @@ -234,11 +250,13 @@ void close_on_exec(int fd) { return utils_backend->close_on_exec(fd); } -int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { - return utils_backend->sdb_socket_accept(serverfd, addr, addrlen); +int sdb_socket_accept(int serverfd) { + LOG_INFO("FD(%d)\n"); + return utils_backend->sdb_socket_accept(serverfd); } int sdb_socketpair(int sv[2]) { + LOG_INFO("\n"); return utils_backend->sdb_socketpair(sv); } @@ -266,11 +284,17 @@ int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg) return utils_backend->sdb_thread_create(pthread, start, arg); } -int sdb_mutex_lock(sdb_mutex_t *mutex) { +int sdb_mutex_lock(sdb_mutex_t *mutex, char* name) { + if(name != NULL) { + D("lock %s\n", name); + } return utils_backend->sdb_mutex_lock(mutex); } -int sdb_mutex_unlock(sdb_mutex_t *mutex) { +int sdb_mutex_unlock(sdb_mutex_t *mutex, char *name) { + if(name != NULL) { + D("unlock %s\n", name); + } return utils_backend->sdb_mutex_unlock(mutex); } @@ -290,18 +314,13 @@ void sdb_sysdeps_init(void) { return utils_backend->sdb_sysdeps_init(); } -int socket_loopback_client(int port, int type) { - return utils_backend->socket_loopback_client(port, type); -} - -int socket_network_client(const char *host, int port, int type) { - return utils_backend->socket_network_client(host, port, type); +int sdb_host_connect(const char *host, int port, int type) { + LOG_INFO("host %s, port %d\n", host, port); + return utils_backend->sdb_host_connect(host, port, type); } -int socket_loopback_server(int port, int type) { - return utils_backend->socket_loopback_server(port, type); +int sdb_port_listen(uint32_t inet, int port, int type) { + LOG_INFO("port %d, type %d\n", port, type); + return utils_backend->sdb_port_listen(inet, port, type); } -int socket_inaddr_any_server(int port, int type) { - return utils_backend->socket_inaddr_any_server(port, type); -} diff --git a/src/utils.h b/src/utils.h old mode 100644 new mode 100755 index 1d87666..1ee4957 --- a/src/utils.h +++ b/src/utils.h @@ -83,14 +83,17 @@ extern int unix_read(int fd, void* buf, size_t len); typedef pthread_t sdb_thread_t; typedef pthread_mutex_t sdb_mutex_t; #define sdb_cond_t pthread_cond_t -#define sdb_mutex_init pthread_mutex_init +#define sdb_mutex_init pthread_mutex_init +#define sdb_cond_signal pthread_cond_signal +#define sdb_cond_destroy pthread_cond_destroy +#define sdb_mutex_destroy pthread_mutex_destroy typedef void* (*sdb_thread_func_t)( void* arg ); void sdb_sysdeps_init(void); int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg); -int sdb_mutex_lock(sdb_mutex_t *mutex); -int sdb_mutex_unlock(sdb_mutex_t *mutex); +int sdb_mutex_lock(sdb_mutex_t *mutex, char* lock_name); +int sdb_mutex_unlock(sdb_mutex_t *mutex, char* lock_name); int sdb_cond_init(sdb_cond_t *cond, const void *unused); int sdb_cond_wait(sdb_cond_t *cond, sdb_mutex_t *mutex); int sdb_cond_broadcast(sdb_cond_t *cond); @@ -98,13 +101,12 @@ int sdb_cond_broadcast(sdb_cond_t *cond); #define SDB_MUTEX(x) sdb_mutex_t x; SDB_MUTEX(dns_lock) -SDB_MUTEX(socket_list_lock) SDB_MUTEX(transport_lock) -SDB_MUTEX(local_transports_lock) +SDB_MUTEX(wakeup_select_lock) SDB_MUTEX(usb_lock) SDB_MUTEX(D_lock) -int launch_server(int server_port); +int launch_server(); void start_logging(void); char* ansi_to_utf8(const char *str); int sdb_open(const char* path, int options); @@ -113,13 +115,13 @@ 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_transport_close(int fd); int sdb_close(int fd); -int sdb_unlink(const char* path); +int unix_unlink(const char* path); int sdb_mkdir(const char* path, int mode); void close_on_exec(int fd); -int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); +int sdb_socket_accept(int serverfd); int sdb_socketpair(int sv[2]); void sdb_sleep_ms(int mseconds); char* sdb_dirstart(const char* path); @@ -128,10 +130,10 @@ int sdb_socket_setbufsize(int fd, int bufsize); void disable_tcp_nagle(int fd); // sockets -int socket_loopback_client(int port, int type); -int socket_network_client(const char *host, int port, int type); -int socket_loopback_server(int port, int type); -int socket_inaddr_any_server(int port, int type); +#define LISTEN_BACKLOG 4 + +int sdb_host_connect(const char *host, int port, int type); +int sdb_port_listen(uint32_t inet, int port, int type); #define DEVICEMAP_SEPARATOR ":" #define DEVICENAME_MAX 256 diff --git a/src/utils_backend.h b/src/utils_backend.h old mode 100644 new mode 100755 index 39d0295..f50b298 --- a/src/utils_backend.h +++ b/src/utils_backend.h @@ -17,100 +17,37 @@ #ifndef _SDB_BACKEND_UTILS_H #define _SDB_BACKEND_UTILS_H -#if defined(OS_WINDOWS) - -typedef const struct FHClassRec_* FHClass; - -typedef struct FHRec_* FH; - -typedef struct EventHookRec_* EventHook; - -typedef struct FHClassRec_ -{ - void (*_fh_init) ( FH f ); - int (*_fh_close)( FH f ); - int (*_fh_lseek)( FH f, int pos, int origin ); - int (*_fh_read) ( FH f, void* buf, int len ); - int (*_fh_write)( FH f, const void* buf, int len ); - void (*_fh_hook) ( FH f, int events, EventHook hook ); - -} FHClassRec; +#include "linkedlist.h" +#include "sdb_map.h" -/* used to emulate unix-domain socket pairs */ -typedef struct SocketPairRec_* SocketPair; -typedef struct FHRec_ -{ - FHClass clazz; - int used; - int eof; - union { - HANDLE handle; - SOCKET socket; - SocketPair pair; - } u; +#if defined(OS_WINDOWS) - HANDLE event; - int mask; +struct sdb_handle { + union { + HANDLE file_handle; + SOCKET socket; + } u; + int fd; +}; - char name[32]; +typedef struct sdb_handle SDB_HANDLE; -} FHRec; +struct sdb_socket_handle { + SDB_HANDLE handle; + int event_location; +}; -#define fh_handle u.handle -#define fh_socket u.socket -#define fh_pair u.pair +typedef struct sdb_socket_handle SDB_SOCK_HANDLE; #define BIP_BUFFER_SIZE 4096 -#define WIN32_FH_BASE 100 -#define WIN32_MAX_FHS 128 - -typedef struct BipBufferRec_ -{ - int a_start; - int a_end; - int b_end; - int fdin; - int fdout; - int closed; - int can_write; /* boolean */ - HANDLE evt_write; /* event signaled when one can write to a buffer */ - int can_read; /* boolean */ - HANDLE evt_read; /* event signaled when one can read from a buffer */ - CRITICAL_SECTION lock; - unsigned char buff[ BIP_BUFFER_SIZE ]; - -} BipBufferRec, *BipBuffer; - -typedef struct EventLooperRec_* EventLooper; - -typedef struct EventHookRec_ -{ - EventHook next; - FH fh; - HANDLE h; - int wanted; /* wanted event flags */ - int ready; /* ready event flags */ - void* aux; - void (*prepare)( EventHook hook ); - int (*start) ( EventHook hook ); - void (*stop) ( EventHook hook ); - int (*check) ( EventHook hook ); - int (*peek) ( EventHook hook ); -} EventHookRec; - #define MAX_LOOPER_HANDLES WIN32_MAX_FHS +#define IS_SOCKET_HANDLE(handle) (handle->fd < WIN32_MAX_FHS) +#define IS_SOCKET_FD(fd) (fd < WIN32_MAX_FHS) -typedef struct EventLooperRec_ -{ - EventHook hooks; - HANDLE htab[ MAX_LOOPER_HANDLES ]; - int htab_count; - -} EventLooperRec; - -int _fh_to_int( FH f ); -FH _fh_from_int( int fd ); +SDB_HANDLE* sdb_handle_map_get(int _key); +void sdb_handle_map_put(int _key, SDB_HANDLE* value); +void sdb_handle_map_remove(int _key); #else #endif // end of unix @@ -119,22 +56,19 @@ struct utils_os_backend { // human-readable name const char *name; - int (*launch_server)(int server_port); + int (*launch_server)(void); 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_transport_close)(int fd); int (*sdb_close)(int fd); - int (*sdb_unlink)(const char* path); int (*sdb_mkdir)(const char* path, int mode); void (*close_on_exec)(int fd); - int (*sdb_socket_accept)(int serverfd, struct sockaddr* addr, socklen_t *addrlen); + int (*sdb_socket_accept)(int serverfd); int (*sdb_socketpair)(int sv[2]); void (*sdb_sleep_ms)(int mseconds); char* (*sdb_dirstart)(const char* path); @@ -156,10 +90,8 @@ struct utils_os_backend { int (*sdb_cond_broadcast)(sdb_cond_t *cond); void (*sdb_sysdeps_init)(void); // helpers for sockets - int (*socket_loopback_client)(int port, int type); - int (*socket_network_client)(const char *host, int port, int type); - int (*socket_loopback_server)(int port, int type); - int (*socket_inaddr_any_server)(int port, int type); + int (*sdb_host_connect)(const char *host, int port, int type); + int (*sdb_port_listen)(uint32_t inet, int port, int type); }; diff --git a/src/utils_unix.c b/src/utils_unix.c old mode 100644 new mode 100755 index c9227a1..90df679 --- a/src/utils_unix.c +++ b/src/utils_unix.c @@ -46,113 +46,86 @@ #include "fdevent.h" #define TRACE_TAG TRACE_SYSDEPS -#include "sdb.h" #include "utils_backend.h" +#include "log.h" -#define LISTEN_BACKLOG 4 +static int _launch_server(void) +{ + pid_t pid; -static void _close_on_exec(int fd); + switch (pid = fork()) { + case -1: + fprintf(stderr, "Couldn't fork: %s\n", strerror(errno)); + return -1; + // never reached! + case 0: { + char path[128] = {0,}; #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); -} + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + CFDictionaryRef dict; + dict = ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask); //0xffffffff + CFStringRef buf = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("CFBundleExecutable")); + CFStringGetCString(buf, path, sizeof(path), 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'; - } -} + ssize_t len = 0; + char buf[128] = {0,}; + snprintf(buf, sizeof(buf), "/proc/%d/exe", getpid()); + if ((len = readlink(buf, path, sizeof(path) - 1)) != -1) { + path[len] = '\0'; + } #endif + // before fork exec, be session leader. + setsid(); -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; + execl(path, "sdb", "fork-server", "server", NULL); + fprintf(stderr, "Couldn't exec: '%s'\n", strerror(errno)); + _exit(-1); } - - setsid(); + default: + // wait for sec due to for booting up sdb server + sdb_sleep_ms(3000); + break; } + return 0; } static void _start_logging(void) { - const char* p = getenv("SDB_TRACE"); + const char* p = getenv(DEBUG_ENV); if (p == NULL) { return; } int fd; fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - sdb_close(fd); + if (fd >= 0) { + dup2(fd, 0); + sdb_close(fd); + } + else { + sdb_close(0); + } fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); if(fd < 0) { + fprintf(stderr, "fail to open '/tmp/sdb.log' logging fails\n"); fd = unix_open("/dev/null", O_WRONLY); + if( fd < 0 ) { + fprintf(stderr, "fail to open /dev/null\n"); + fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid()); + return; + } } + dup2(fd, 1); dup2(fd, 2); sdb_close(fd); + fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid()); } @@ -169,21 +142,9 @@ static char* _ansi_to_utf8(const char *str) return utf8; } -static int _unix_open(const char* path, int options,...) +static void _close_on_exec(int fd) { - if ((options & O_CREAT) == 0) - { - return open(path, options); - } - else - { - int mode; - va_list args; - va_start( args, options ); - mode = va_arg( args, int ); - va_end( args ); - return open(path, options, mode); - } + fcntl( fd, F_SETFD, FD_CLOEXEC ); } static int _sdb_open( const char* pathname, int options ) @@ -195,15 +156,9 @@ static int _sdb_open( const char* pathname, int options ) return fd; } -static int _sdb_open_mode( const char* pathname, int options, int mode ) -{ - return open( pathname, options, mode ); -} - - static int _sdb_creat(const char* path, int mode) { - int fd = creat(path, mode); + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); if ( fd < 0 ) return -1; @@ -222,11 +177,6 @@ static int _sdb_write(int fd, const void* buf, size_t len) return write(fd, buf, len); } -static int _sdb_lseek(int fd, int pos, int where) -{ - return lseek(fd, pos, where); -} - static int _sdb_shutdown(int fd) { return shutdown(fd, SHUT_RDWR); @@ -237,26 +187,19 @@ static int _sdb_close(int fd) return close(fd); } -static void _close_on_exec(int fd) -{ - fcntl( fd, F_SETFD, FD_CLOEXEC ); -} - -static int _sdb_unlink(const char* path) -{ - return unlink(path); -} - static int _sdb_mkdir(const char* path, int mode) { return mkdir(path, mode); } -static int _sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) +static int _sdb_socket_accept(int serverfd) { int fd; + struct sockaddr addr; + socklen_t alen = sizeof(addr); + + fd = accept(serverfd, &addr, &alen); - fd = accept(serverfd, addr, addrlen); if (fd >= 0) { _close_on_exec(fd); } @@ -343,44 +286,32 @@ static void _sdb_sysdeps_init(void) { } -static int _socket_loopback_client(int port, int type) +static int _sdb_host_connect(const char *host, int port, int type) { + struct hostent *hp; struct sockaddr_in addr; int s; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - s = socket(AF_INET, type, 0); - if(s < 0) return -1; - - if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - sdb_close(s); + // FIXME: might take a long time to get information + if ((hp = gethostbyname(host)) == NULL) { + LOG_ERROR("failed to get hostname:%s(%d)\n", host, port); return -1; } - return s; - -} - -static int _socket_network_client(const char *host, int port, int type) -{ - struct hostent *hp; - struct sockaddr_in addr; - int s; - - hp = gethostbyname(host); - if(hp == 0) return -1; - memset(&addr, 0, sizeof(addr)); addr.sin_family = hp->h_addrtype; addr.sin_port = htons(port); memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - s = socket(hp->h_addrtype, type, 0); - if(s < 0) return -1; + if (type == SOCK_STREAM) { + s = socket(AF_INET, type, 0); + } else { + s = socket(AF_INET, type, IPPROTO_UDP); + } + if (s < 0) { + LOG_ERROR("failed to create socket to %s(%d)\n", host, port); + return -1; + } if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { sdb_close(s); @@ -391,61 +322,21 @@ static int _socket_network_client(const char *host, int port, int type) } -static int _socket_loopback_server(int port, int type) +static int _sdb_port_listen(uint32_t inet, int port, int type) { struct sockaddr_in addr; int s, n; - int cnt_max = 30; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(inet); addr.sin_port = htons(port); - if(cnt_max ==0) - addr.sin_addr.s_addr = htonl(INADDR_ANY); - else - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - s = socket(AF_INET, type, 0); - if(s < 0) return -1; - - n = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); - - - - if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - sdb_close(s); + if ((s = socket(AF_INET, type, 0)) < 0) { + LOG_ERROR("failed to create socket to %u(%d)\n", inet, port); return -1; } - if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - - if (ret < 0) { - sdb_close(s); - return -1; - } - } - - return s; -} - -static int _socket_inaddr_any_server(int port, int type) -{ - struct sockaddr_in addr; - int s, n; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - s = socket(AF_INET, type, 0); - if(s < 0) return -1; - n = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); @@ -454,12 +345,9 @@ static int _socket_inaddr_any_server(int port, int type) return -1; } + // only listen if tcp mode if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - - if (ret < 0) { + if (listen(s, LISTEN_BACKLOG) < 0) { sdb_close(s); return -1; } @@ -468,22 +356,20 @@ static int _socket_inaddr_any_server(int port, int type) return s; } + const struct utils_os_backend utils_unix_backend = { .name = "unix utils", .launch_server = _launch_server, .start_logging = _start_logging, .ansi_to_utf8 = _ansi_to_utf8, .sdb_open = _sdb_open, - .sdb_open_mode = _sdb_open_mode, - .unix_open = _unix_open, .sdb_creat = _sdb_creat, .sdb_read = _sdb_read, .sdb_write = _sdb_write, - .sdb_lseek = _sdb_lseek, .sdb_shutdown = _sdb_shutdown, + .sdb_transport_close = _sdb_close, .sdb_close = _sdb_close, .close_on_exec = _close_on_exec, - .sdb_unlink = _sdb_unlink, .sdb_mkdir = _sdb_mkdir, .sdb_socket_accept = _sdb_socket_accept, .sdb_socketpair = _sdb_socketpair, @@ -500,8 +386,6 @@ const struct utils_os_backend utils_unix_backend = { .sdb_cond_wait = _sdb_cond_wait, .sdb_cond_broadcast = _sdb_cond_broadcast, .sdb_sysdeps_init = _sdb_sysdeps_init, - .socket_loopback_client = _socket_loopback_client, - .socket_network_client = _socket_network_client, - .socket_loopback_server = _socket_loopback_server, - .socket_inaddr_any_server = _socket_inaddr_any_server + .sdb_host_connect = _sdb_host_connect, + .sdb_port_listen = _sdb_port_listen }; diff --git a/src/utils_windows.c b/src/utils_windows.c old mode 100644 new mode 100755 index 5b66145..f19c4b7 --- a/src/utils_windows.c +++ b/src/utils_windows.c @@ -13,22 +13,113 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include #include #include #include +#include #include "utils.h" #include "fdevent.h" #include "fdevent_backend.h" +#include "sdb_map.h" #define TRACE_TAG TRACE_SYSDEPS -#include "sdb.h" #include "utils_backend.h" +#include "log.h" + +// error mapping table between windoes & unix +// error codes are described: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx +void setBaseErrno(DWORD dwLastErrorCode); +int getBaseErrno(DWORD dwLastErrorCode); + +static int total_handle_number = 0; +static LIST_NODE* free_socket_handle_list = NULL; +//this increases 1 when one file fd is created. +static int file_handle_count = WIN32_MAX_FHS; +//this indicates total number of socket fds. +static int socket_handle_number = 0; + +struct errno_lists { + unsigned long wincode; + int posixcode; +}; + +static struct errno_lists errno_list[] = { + { 0, 0 }, /* 0 return 0 as normal operation */ + { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 Incorrect function. */ + { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 The system cannot find the file specified. */ + { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 The system cannot find the path specified. */ + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 The system cannot open the file. */ + { ERROR_ACCESS_DENIED, EACCES }, /* 5 Access is denied. */ + { ERROR_INVALID_HANDLE, EBADF }, /* 6 The handle is invalid. */ + { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 The storage control blocks were destroyed.*/ + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 Not enough storage is available to process this command. */ + { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 he storage control block address is invalid. */ + { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 The environment is incorrect. */ + { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 An attempt was made to load a program with an incorrect format. */ + { ERROR_INVALID_ACCESS, EINVAL }, /* 12 The access code is invalid. */ + { ERROR_INVALID_DATA, EINVAL }, /* 13 The data is invalid. */ + { ERROR_OUTOFMEMORY, ENOMEM }, /* 14 Not enough storage is available to complete this operation. */ + { ERROR_INVALID_DRIVE, ENOENT }, /* 15 The system cannot find the drive specified.*/ + { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */ + { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */ + { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */ + { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */ + { ERROR_BAD_NETPATH, ENOENT }, /* 53 */ + { ERROR_NETWORK_ACCESS_DENIED, EACCES },/* 65 */ + { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */ + { ERROR_FILE_EXISTS, EEXIST }, /* 80 */ + { ERROR_CANNOT_MAKE, EACCES }, /* 82 */ + { ERROR_FAIL_I24, EACCES }, /* 83 */ + { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */ + { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */ + { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */ + { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */ + { ERROR_DISK_FULL, ENOSPC }, /* 112 */ + { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */ + { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */ + { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */ + { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */ + { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */ + { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */ + { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */ + { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */ + { ERROR_NOT_LOCKED, EACCES }, /* 158 */ + { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */ + { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */ + { ERROR_LOCK_FAILED, EACCES }, /* 167 */ + { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */ + { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */ + { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */ + { ERROR_NO_DATA, EPIPE }, /* 232 */ + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }, /* 1816 */ + { WSAEINTR, EINTR }, /* 10004 Interrupted function call. */ + { WSAEWOULDBLOCK, EAGAIN } /* 10035 This error is returned from operations on nonblocking sockets that cannot be completed immediately */ +}; + +void setBaseErrno(DWORD dwLastErrorCode) +{ + errno = getBaseErrno(dwLastErrorCode); +} + +int getBaseErrno(DWORD dwLastErrorCode) +{ + int i; + + for (i = 0; i < sizeof(errno_list)/sizeof(errno_list[0]); ++i) { + if (dwLastErrorCode == errno_list[i].posixcode) { + return errno_list[i].posixcode; + } + } + LOG_FIXME("unsupport error code: %ld\n", dwLastErrorCode); + return EINVAL; +} /* * from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx */ -static int _launch_server(int server_port) { +static int _launch_server(void) { HANDLE g_hChildStd_OUT_Rd = NULL; HANDLE g_hChildStd_OUT_Wr = NULL; SECURITY_ATTRIBUTES saAttr; @@ -99,22 +190,8 @@ static int _launch_server(int server_port) { 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; - } + // wait for sec due to for booting up sdb server + sdb_sleep_ms(3000); } } return 0; @@ -122,7 +199,7 @@ static int _launch_server(int server_port) { static void _start_logging(void) { - const char* p = getenv("SDB_TRACE"); + const char* p = getenv(DEBUG_ENV); if (p == NULL) { return; } @@ -150,11 +227,6 @@ static void _start_logging(void) fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid()); } - -extern void fatal(const char *fmt, ...); - -#define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0) - /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -164,344 +236,293 @@ extern void fatal(const char *fmt, ...); /**************************************************************************/ static sdb_mutex_t _win32_lock; -static FHRec _win32_fhs[WIN32_MAX_FHS]; -static int _win32_fh_count; - -FH _fh_from_int(int fd) { - FH f; - - fd -= WIN32_FH_BASE; - - if (fd < 0 || fd >= _win32_fh_count) { - D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE); - errno = EBADF; - return NULL; - } - - f = &_win32_fhs[fd]; - - if (f->used == 0) { - D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE); - errno = EBADF; - return NULL; +static sdb_mutex_t sdb_handle_map_lock; +static sdb_mutex_t free_socket_handle_list_lock; + +static SDB_HANDLE* alloc_handle(int socket) { + + SDB_HANDLE* _h = NULL; + sdb_mutex_lock(&_win32_lock, "_fh_alloc _win32_lock"); + + if(total_handle_number < WIN32_MAX_FHS) { + total_handle_number++; + if(socket) { + if(free_socket_handle_list == NULL) { + SDB_SOCK_HANDLE* __h = malloc(sizeof(SDB_SOCK_HANDLE)); + __h->event_location = -1; + _h = (SDB_HANDLE*)__h; + _h->fd = socket_handle_number++; + LOG_INFO("no free socket. assign socket fd FD(%d)\n", _h->fd); + } + else { + sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_alloc free_socket_handle_list_lock"); + _h = free_socket_handle_list->data; + remove_first(&free_socket_handle_list, no_free); + sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_alloc free_socket_handle_list_lock"); + LOG_INFO("reuse socket fd FD(%d)\n", _h->fd); + } + _h->u.socket = INVALID_SOCKET; + } + else { + _h = malloc(sizeof(SDB_HANDLE)); + _h->fd = file_handle_count++; + _h->u.file_handle = INVALID_HANDLE_VALUE; + } + + sdb_handle_map_put(_h->fd, _h); } - - return f; -} - -int _fh_to_int(FH f) { - if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS) - return (int) (f - _win32_fhs) + WIN32_FH_BASE; - - return -1; + else { + errno = ENOMEM; + LOG_ERROR("no more space for file descriptor. max file descriptor is %d\n", WIN32_MAX_FHS); + } + + sdb_mutex_unlock(&_win32_lock, "_fh_alloc _win32_lock"); + return _h; +} + +SDB_HANDLE* sdb_handle_map_get(int _key) { + MAP_KEY key; + key.key_int = _key; + sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_get"); + SDB_HANDLE* result = map_get(&sdb_handle_map, key); + sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_get"); + return result; +} + +void sdb_handle_map_put(int _key, SDB_HANDLE* value) { + MAP_KEY key; + key.key_int = _key; + sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_put"); + map_put(&sdb_handle_map, key, value); + sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_put"); +} + +void sdb_handle_map_remove(int _key) { + MAP_KEY key; + key.key_int = _key; + sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_remove"); + map_remove(&sdb_handle_map, key); + sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_remove"); +} + +static int _fh_close(SDB_HANDLE* _h) { + if(IS_SOCKET_HANDLE(_h)) { + shutdown(_h->u.socket, SD_BOTH); + closesocket(_h->u.socket); + _h->u.socket = INVALID_SOCKET; + sdb_handle_map_remove(_h->fd); + sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_close"); + prepend(&free_socket_handle_list, _h); + sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_close"); + } + else { + CloseHandle(_h->u.file_handle); + _h->u.file_handle = INVALID_HANDLE_VALUE; + free(_h); + } + sdb_mutex_lock(&_win32_lock, "_fh_close"); + total_handle_number--; + sdb_mutex_unlock(&_win32_lock, "_fh_close"); + return 0; } -static FH _fh_alloc(FHClass clazz) { - int nn; - FH f = NULL; +static int check_socket_err(int result) { - sdb_mutex_lock(&_win32_lock); + if(result != SOCKET_ERROR) { + return result; + } - if (_win32_fh_count < WIN32_MAX_FHS) { - f = &_win32_fhs[_win32_fh_count++]; - goto Exit; - } + DWORD err = WSAGetLastError(); - for (nn = 0; nn < WIN32_MAX_FHS; nn++) { - if (_win32_fhs[nn].clazz == NULL) { - f = &_win32_fhs[nn]; - goto Exit; - } - } - D( "_fh_alloc: no more free file descriptors\n"); - Exit: if (f) { - f->clazz = clazz; - f->used = 1; - f->eof = 0; - clazz->_fh_init(f); - } - sdb_mutex_unlock(&_win32_lock); - return f; + if(err == WSAEWOULDBLOCK) { + errno = EAGAIN; + LOG_ERROR("socket error EAGAIN\n"); + } + else if(err == WSAEINTR) { + errno = EINTR; + LOG_ERROR("socket error EINTR\n"); + } + else if(err == 0) { + errno = 0; + LOG_ERROR("socket error 0\n"); + } + else { + errno = EINVAL; + LOG_ERROR("unknown error %d\n", err); + } + return -1; } -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; -} +static int check_file_err(HANDLE h) { -/* forward definitions */ -static const FHClassRec _fh_file_class; -static const FHClassRec _fh_socket_class; + if (h != INVALID_HANDLE_VALUE) { + return 1; + } -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** file-based descriptor handling *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ + _fh_close(h); + DWORD err = GetLastError(); -static void _fh_file_init(FH f) { - f->fh_handle = INVALID_HANDLE_VALUE; + if(err == ERROR_PATH_NOT_FOUND) { + LOG_ERROR("path not found\n"); + errno = ENOTDIR; + } + else if (err == ERROR_FILE_NOT_FOUND) { + LOG_ERROR("file not found\n"); + errno = ENOENT; + } + else { + LOG_ERROR("unknown erro %d\n", err); + errno = ENOENT; + } + return -1; } -static int _fh_file_close(FH f) { - CloseHandle(f->fh_handle); - f->fh_handle = INVALID_HANDLE_VALUE; - return 0; -} +static int _sdb_open(const char* path, int file_options) { -static int _fh_file_read(FH f, void* buf, int len) { - DWORD read_bytes; + DWORD access_mode = 0; + DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; - 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; + if(file_options == O_RDONLY) { + access_mode = GENERIC_READ; } - 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; + else if(file_options == O_WRONLY) { + access_mode = GENERIC_WRITE; } - 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: + else if(file_options == O_RDWR) { + access_mode = GENERIC_READ | GENERIC_WRITE; + } + else { + LOG_ERROR("invalid options (0x%0x)\n", file_options); errno = EINVAL; return -1; } - result = SetFilePointer(f->fh_handle, pos, NULL, method); - if (result == INVALID_SET_FILE_POINTER) { - errno = EIO; + SDB_HANDLE* _h; + _h = alloc_handle(0); + if (!_h) { + errno = ENOMEM; return -1; - } else { - f->eof = 0; } - return (int) result; -} -static void _fh_file_hook(FH f, int event, EventHook eventhook); /* forward */ + _h->u.file_handle = CreateFile(path, access_mode, share_mode, NULL, OPEN_EXISTING, 0, NULL); -static const FHClassRec _fh_file_class = { _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read, _fh_file_write, - _fh_file_hook }; + if(check_file_err(_h->u.file_handle) == -1) { + return -1; + } + return _h->fd; +} -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** file-based descriptor handling *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ +static int _sdb_creat(const char* path, int mode) { + SDB_HANDLE* _h = alloc_handle(0); -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; + if (!_h) { + errno = ENOMEM; return -1; } + _h->u.file_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); - f = _fh_alloc(&_fh_file_class); - if (!f) { - errno = ENOMEM; - return -1; + if(check_file_err(_h->u.file_handle) == -1) { + return -1; } + return _h->fd; +} - f->fh_handle = CreateFile(path, desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL); +static int _sdb_read(int fd, void* buffer, size_t r_length) { + SDB_HANDLE* _h = sdb_handle_map_get(fd); - 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; + if (_h == NULL) { + LOG_ERROR("FD(%d) disconnected\n", fd); + return 0; + } - case ERROR_PATH_NOT_FOUND: - D( "path not found\n"); - errno = ENOTDIR; - return -1; + if(IS_SOCKET_HANDLE(_h)) { + return check_socket_err(recv(_h->u.socket, buffer, r_length, 0)); + } + else { + DWORD r_bytes; - default: - D( "unknown error\n"); - errno = ENOENT; + if (!ReadFile(_h->u.file_handle, buffer, (DWORD) r_length, &r_bytes, NULL)) { + D( "sdb_read: could not read %d bytes from FD(%d)\n", r_length, _h->fd); + errno = EIO; return -1; } + return (int) r_bytes; } - - 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 _sdb_write(int fd, const void* buffer, size_t w_length) { + SDB_HANDLE* _h = sdb_handle_map_get(fd); -static int _unix_open(const char* path, int options, ...) { - if ((options & O_CREAT) == 0) { - return open(path, options); - } else { - int mode; - va_list args; - va_start( args, options); - mode = va_arg( args, int ); - va_end( args); - return open(path, options, mode); + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists. disconnected\n", fd); + return 0; } -} - -/* 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; + if(IS_SOCKET_HANDLE(_h)) { + return check_socket_err(send(_h->u.socket, buffer, w_length, 0)); } + else { + DWORD w_bytes; - 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; + if (!WriteFile(_h->u.file_handle, buffer, (DWORD) w_length, &w_bytes, NULL)) { + D( "sdb_file_write: could not write %d bytes from FD(%d)\n", w_length, _h->fd); + errno = EIO; return -1; } + return (int) w_bytes; } - 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; - } +static int _sdb_shutdown(int fd) { - return f->clazz->_fh_read(f, buf, len); -} + if(!IS_SOCKET_FD(fd)) { + LOG_ERROR("FD(%d) is file fd\n", fd); + return -1; + } -static int _sdb_write(int fd, const void* buf, size_t len) { - FH f = _fh_from_int(fd); + SDB_HANDLE* _h = sdb_handle_map_get(fd); - if (f == NULL) { + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists\n", fd); return -1; } - return f->clazz->_fh_write(f, buf, len); + D( "sdb_shutdown: FD(%d)\n", fd); + shutdown(_h->u.socket, SD_BOTH); + return 0; } -static int _sdb_lseek(int fd, int pos, int where) { - FH f = _fh_from_int(fd); +static int _sdb_transport_close(int fd) { - if (!f) { - return -1; - } - - return f->clazz->_fh_lseek(f, pos, where); -} + SDB_HANDLE* _h = sdb_handle_map_get(fd); -static int _sdb_shutdown(int fd) { - FH f = _fh_from_int(fd); - - if (!f) { + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists\n", fd); return -1; } - D( "sdb_shutdown: %s\n", f->name); - shutdown(f->fh_socket, SD_BOTH); + D( "sdb_close: FD(%d)\n", fd); + shutdown(_h->u.socket, SD_BOTH); + closesocket(_h->u.socket); + _h->u.socket = INVALID_SOCKET; return 0; } static int _sdb_close(int fd) { - FH f = _fh_from_int(fd); - if (!f) { + SDB_HANDLE* _h = sdb_handle_map_get(fd); + + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists\n", fd); return -1; } - D( "sdb_close: %s\n", f->name); - _fh_close(f); + D( "sdb_close: FD(%d)\n", fd); + _fh_close(_h); return 0; } -static int _sdb_unlink(const char* path) { - int rc = unlink(path); - - if (rc == -1 && errno == EACCES) { - /* unlink returns EACCES when the file is read-only, so we first */ - /* try to make it writable, then unlink again... */ - rc = chmod(path, _S_IREAD | _S_IWRITE); - if (rc == 0) - rc = unlink(path); - } - return rc; -} - static int _sdb_mkdir(const char* path, int mode) { return _mkdir(path); } @@ -555,146 +576,30 @@ static char* _sdb_dirstop(const char* path) { return p; } -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** socket-based file descriptors *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -static void _socket_set_errno(void) { - switch (WSAGetLastError()) { - case 0: - errno = 0; - break; - case WSAEWOULDBLOCK: - errno = EAGAIN; - break; - case WSAEINTR: - errno = EINTR; - break; - default: - D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError()); - errno = EINVAL; - } -} - -static void _fh_socket_init(FH f) { - f->fh_socket = INVALID_SOCKET; - f->event = WSACreateEvent(); - f->mask = 0; -} - -static int _fh_socket_close(FH f) { - /* gently tell any peer that we're closing the socket */ - shutdown(f->fh_socket, SD_BOTH); - closesocket(f->fh_socket); - f->fh_socket = INVALID_SOCKET; - CloseHandle(f->event); - f->mask = 0; - return 0; -} - -static int _fh_socket_lseek(FH f, int pos, int origin) { - errno = EPIPE; - return -1; -} - -static int _fh_socket_read(FH f, void* buf, int len) { - int result = recv(f->fh_socket, buf, len, 0); - if (result == SOCKET_ERROR) { - _socket_set_errno(); - result = -1; - } - return result; -} - -static int _fh_socket_write(FH f, const void* buf, int len) { - int result = send(f->fh_socket, buf, len, 0); - if (result == SOCKET_ERROR) { - _socket_set_errno(); - result = -1; - } - return result; -} - -static void _fh_socket_hook(FH f, int event, EventHook hook); /* forward */ - -static const FHClassRec _fh_socket_class = { _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read, - _fh_socket_write, _fh_socket_hook }; - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** replacement for libs/cutils/socket_xxxx.c *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -#include - static int _winsock_init; -static void _cleanup_winsock(void) { +static void _cleanup_winsock() { WSACleanup(); } static void _init_winsock(void) { if (!_winsock_init) { WSADATA wsaData; - int rc = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (rc != 0) { - fatal("sdb: could not initialize Winsock\n"); + if(WSAStartup(MAKEWORD(2, 2), &wsaData)) { + LOG_FATAL("sdb: could not initialize Winsock\n"); } - atexit(_cleanup_winsock); _winsock_init = 1; + atexit(_cleanup_winsock); } } -static int _socket_loopback_client(int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); - struct sockaddr_in addr; - SOCKET s; - - if (!f) - return -1; - - if (!_winsock_init) - _init_winsock(); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - s = socket(AF_INET, type, 0); - if (s == INVALID_SOCKET) { - D("socket_loopback_client: could not create socket\n"); - _fh_close(f); - return -1; - } - - f->fh_socket = s; - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port); - _fh_close(f); - return -1; - } - snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); -} - -#define LISTEN_BACKLOG 4 - -static int _socket_loopback_server(int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); +static int _sdb_port_listen(uint32_t inet, int port, int type) { + SDB_HANDLE* _h = alloc_handle(1); struct sockaddr_in addr; SOCKET s; int n; - if (!f) { + if (_h == NULL) { return -1; } @@ -703,51 +608,51 @@ static int _socket_loopback_server(int port, int type) { memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(inet); addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - s = socket(AF_INET, type, 0); - if (s == INVALID_SOCKET) + if ((s = socket(AF_INET, type, 0)) == INVALID_SOCKET) { + LOG_ERROR("failed to create socket to %u(%d)\n", inet, port); return -1; + } - f->fh_socket = s; + _h->u.socket = s; n = 1; setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n)); if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + _fh_close(_h); return -1; } + // only listen if tcp mode if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - if (ret < 0) { - _fh_close(f); + if (listen(s, LISTEN_BACKLOG) < 0) { + _fh_close(_h); return -1; } } - snprintf(f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); + + D( "sdb_port_listen: port %d type %s => FD(%d)\n", port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd); + return _h->fd; } -static int _socket_network_client(const char *host, int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); +static int _sdb_host_connect(const char *host, int port, int type) { + SDB_HANDLE* _h = alloc_handle(1); struct hostent *hp; struct sockaddr_in addr; SOCKET s; - if (!f) + if (!_h) return -1; if (!_winsock_init) _init_winsock(); - hp = gethostbyname(host); - if (hp == 0) { - _fh_close(f); + // FIXME: might take a long time to get information + if ((hp = gethostbyname(host)) == NULL) { + LOG_ERROR("failed to get hostname:%s(%d)\n", host, port); + _fh_close(_h); return -1; } @@ -756,503 +661,167 @@ static int _socket_network_client(const char *host, int port, int type) { addr.sin_port = htons(port); memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - s = socket(hp->h_addrtype, type, 0); - if (s == INVALID_SOCKET) { - _fh_close(f); + if ((s = socket(hp->h_addrtype, type, 0)) == INVALID_SOCKET) { + LOG_ERROR("failed to create socket to %s(%d)\n", host, port); + _fh_close(_h); return -1; } - f->fh_socket = s; + + _h->u.socket = s; if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + _fh_close(_h); return -1; } - snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( - "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); + D("sdb_host_connect: host '%s' port %d type %s => FD(%d)\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd); + return _h->fd; } -static int _socket_inaddr_any_server(int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); - struct sockaddr_in addr; - SOCKET s; - int n; - - if (!f) - return -1; +static int _sdb_socket_accept(int serverfd) { - if (!_winsock_init) - _init_winsock(); + if(!IS_SOCKET_FD(serverfd)) { + LOG_ERROR("FD(%d) is file fd\n", serverfd); + return -1; + } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); + SDB_HANDLE* server_h = sdb_handle_map_get(serverfd); + struct sockaddr addr; + socklen_t alen = sizeof(addr); - s = socket(AF_INET, type, 0); - if (s == INVALID_SOCKET) { - _fh_close(f); + if (!server_h) { + LOG_ERROR( "FD(%d) Invalid server fd\n", serverfd); return -1; } - f->fh_socket = s; - n = 1; - setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n)); - - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + SDB_HANDLE* _h = alloc_handle(1); + if (!_h) { return -1; } - if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - if (ret < 0) { - _fh_close(f); - return -1; - } - } - snprintf(f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); -} - -static int _sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { - FH serverfh = _fh_from_int(serverfd); - FH fh; - - if (!serverfh || serverfh->clazz != &_fh_socket_class) { - D( "sdb_socket_accept: invalid fd %d\n", serverfd); + _h->u.socket = accept(server_h->u.socket, &addr, &alen); + if (_h->u.socket == INVALID_SOCKET) { + _fh_close(_h); + LOG_ERROR( "sdb_socket_accept: accept on FD(%d) return error %ld\n", serverfd, GetLastError()); return -1; } - 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); + LOG_INFO( "sdb_socket_accept on FD(%d) returns FD(%d)\n", serverfd, _h->fd); + return _h->fd; } static void _disable_tcp_nagle(int fd) { - FH fh = _fh_from_int(fd); - int on; - - if (!fh || fh->clazz != &_fh_socket_class) - return; - - setsockopt(fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)); -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** emulated socketpairs *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -/* we implement socketpairs directly in use space for the following reasons: - * - it avoids copying data from/to the Nt kernel - * - it allows us to implement fdevent hooks easily and cheaply, something - * that is not possible with standard Win32 pipes !! - * - * basically, we use two circular buffers, each one corresponding to a given - * direction. - * - * each buffer is implemented as two regions: - * - * region A which is (a_start,a_end) - * region B which is (0, b_end) with b_end <= a_start - * - * an empty buffer has: a_start = a_end = b_end = 0 - * - * a_start is the pointer where we start reading data - * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE, - * then you start writing at b_end - * - * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE - * - * there is room when b_end < a_start || a_end < BUFER_SIZE - * - * when reading, a_start is incremented, it a_start meets a_end, then - * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on.. - */ - -#define BIP_BUFFER_SIZE 4096 -#if 0 -#include -# 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(!IS_SOCKET_FD(fd)) { + LOG_ERROR("FD(%d) is file fd\n", fd); + return; + } - 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); + SDB_HANDLE* _h = sdb_handle_map_get(fd); + if (!_h) { + return; } -} -static void bip_buffer_done(BipBuffer bip) { - BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout )); - CloseHandle(bip->evt_read); - CloseHandle(bip->evt_write); - DeleteCriticalSection(&bip->lock); + int on; + setsockopt(_h->u.socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)); } -static int bip_buffer_write(BipBuffer bip, const void* src, int len) { - int avail, count = 0; - - if (len <= 0) - return 0; - - BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len )); - BIPDUMP( src, len); - - EnterCriticalSection(&bip->lock); - - while (!bip->can_write) { - int ret; - LeaveCriticalSection(&bip->lock); - - if (bip->closed) { - errno = EPIPE; - return -1; - } - /* spinlocking here is probably unfair, but let's live with it */ - ret = WaitForSingleObject(bip->evt_write, INFINITE); - if (ret != WAIT_OBJECT_0) { /* buffer probably closed */ - D( - "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError()); - return 0; - } - if (bip->closed) { - errno = EPIPE; - return -1; - } - EnterCriticalSection(&bip->lock); - } - - BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len )); - - avail = BIP_BUFFER_SIZE - bip->a_end; - if (avail > 0) { - /* we can append to region A */ - if (avail > len) - avail = len; +static int socketpair_impl(int af, int type, int protocol, SOCKET socks[2]) +{ + struct sockaddr_in addr; + SOCKET s; - memcpy(bip->buff + bip->a_end, src, avail); - src += avail; - count += avail; - len -= avail; + LOG_INFO("+socketpair impl in\n"); - bip->a_end += avail; - if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) { - bip->can_write = 0; - ResetEvent(bip->evt_write); - goto Exit; - } + if (!_winsock_init) { + _init_winsock(); } + // Create a socket, bind it to 127.0.0.1 and a random port, and listen. + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + addr.sin_port = 0; - if (len == 0) - goto Exit; - - avail = bip->a_start - bip->b_end; - assert( avail > 0); - /* since can_write is TRUE */ - - if (avail > len) - avail = len; - - memcpy(bip->buff + bip->b_end, src, avail); - count += avail; - bip->b_end += avail; + socks[0] = socks[1] = INVALID_SOCKET; - if (bip->b_end == bip->a_start) { - bip->can_write = 0; - ResetEvent(bip->evt_write); + if ((s = socket(af, type, 0)) == INVALID_SOCKET) { + return -1; } - Exit: - assert( count > 0); - - if (!bip->can_read) { - bip->can_read = 1; - SetEvent(bip->evt_read); + if (bind(s, (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { + closesocket(s); + return -1; } - BIPD( - ( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read )); - LeaveCriticalSection(&bip->lock); - - return count; -} - -static int bip_buffer_read(BipBuffer bip, void* dst, int len) { - int avail, count = 0; - - if (len <= 0) - return 0; - - BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len )); - - EnterCriticalSection(&bip->lock); - while (!bip->can_read) { -#if 0 - LeaveCriticalSection( &bip->lock ); - errno = EAGAIN; + int addr_len = sizeof(addr); + if (getsockname(s, (struct sockaddr*) &addr, &addr_len) == SOCKET_ERROR) { + closesocket(s); return -1; -#else - int ret; - LeaveCriticalSection(&bip->lock); + } - if (bip->closed) { - errno = EPIPE; - return -1; + do + { + if (listen(s, 1) == SOCKET_ERROR) { + break; } - - ret = WaitForSingleObject(bip->evt_read, INFINITE); - if (ret != WAIT_OBJECT_0) { /* probably closed buffer */ - D( - "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError()); - return 0; + // Creates the second socket and connects it to the same address and port. + if ((socks[0] = socket(af, type, 0)) == INVALID_SOCKET) { + break; } - if (bip->closed) { - errno = EPIPE; - return -1; + if (connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { + break; } - EnterCriticalSection(&bip->lock); -#endif - } - - BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len )); - - avail = bip->a_end - bip->a_start; - assert( avail > 0); - /* since can_read is TRUE */ - - if (avail > len) - avail = len; - - memcpy(dst, bip->buff + bip->a_start, avail); - dst += avail; - count += avail; - len -= avail; - - bip->a_start += avail; - if (bip->a_start < bip->a_end) - goto Exit; - - bip->a_start = 0; - bip->a_end = bip->b_end; - bip->b_end = 0; - - avail = bip->a_end; - if (avail > 0) { - if (avail > len) - avail = len; - memcpy(dst, bip->buff, avail); - count += avail; - bip->a_start += avail; - - if (bip->a_start < bip->a_end) - goto Exit; - - bip->a_start = bip->a_end = 0; - } - - bip->can_read = 0; - ResetEvent(bip->evt_read); - - Exit: - assert( count > 0); - - if (!bip->can_write) { - bip->can_write = 1; - SetEvent(bip->evt_write); - } - - BIPDUMP( (const unsigned char*)dst - count, count); - BIPD( - ( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read )); - LeaveCriticalSection(&bip->lock); - - return count; -} - -typedef struct SocketPairRec_ { - BipBufferRec a2b_bip; - BipBufferRec b2a_bip; - FH a_fd; - int used; - -} SocketPairRec; - -void _fh_socketpair_init(FH f) { - f->fh_pair = NULL; -} - -static int _fh_socketpair_close(FH f) { - if (f->fh_pair) { - SocketPair pair = f->fh_pair; - - if (f == pair->a_fd) { - pair->a_fd = NULL; + if ((socks[1] = accept(s, NULL, NULL)) == INVALID_SOCKET) { + break; } + closesocket(s); + LOG_INFO("-socketpair impl out\n"); + return 0; - bip_buffer_close(&pair->b2a_bip); - bip_buffer_close(&pair->a2b_bip); + } while (0); - if (--pair->used == 0) { - bip_buffer_done(&pair->b2a_bip); - bip_buffer_done(&pair->a2b_bip); - free(pair); - } - f->fh_pair = NULL; - } - return 0; -} + closesocket(socks[0]); + closesocket(socks[1]); + closesocket(s); -static int _fh_socketpair_lseek(FH f, int pos, int origin) { - errno = ESPIPE; + LOG_ERROR("socketpair error: %ld\n", WSAGetLastError()); return -1; } -static int _fh_socketpair_read(FH f, void* buf, int len) { - SocketPair pair = f->fh_pair; - BipBuffer bip; +static int _sdb_socketpair(int sv[2]) { + SOCKET socks[2]; + int r = 0; - if (!pair) + r = socketpair_impl( AF_INET, SOCK_STREAM, IPPROTO_TCP, socks); + if (r < 0) { + LOG_ERROR("failed to create socket pair:(%ld)\n", GetLastError()); return -1; + } - if (f == pair->a_fd) - bip = &pair->b2a_bip; - else - bip = &pair->a2b_bip; - - return bip_buffer_read(bip, buf, len); -} - -static int _fh_socketpair_write(FH f, const void* buf, int len) { - SocketPair pair = f->fh_pair; - BipBuffer bip; + SDB_HANDLE* _ha = alloc_handle(1); + SDB_HANDLE* _hb = alloc_handle(1); - if (!pair) + if (!_ha || !_hb) { return -1; - - if (f == pair->a_fd) - bip = &pair->a2b_bip; - else - bip = &pair->b2a_bip; - - return bip_buffer_write(bip, buf, len); -} - -static void _fh_socketpair_hook(FH f, int event, EventHook hook); /* forward */ - -static const FHClassRec _fh_socketpair_class = { _fh_socketpair_init, _fh_socketpair_close, _fh_socketpair_lseek, - _fh_socketpair_read, _fh_socketpair_write, _fh_socketpair_hook }; - -static int _sdb_socketpair(int sv[2]) { - FH fa, fb; - SocketPair pair; - - fa = _fh_alloc(&_fh_socketpair_class); - fb = _fh_alloc(&_fh_socketpair_class); - - if (!fa || !fb) - goto Fail; - - pair = malloc(sizeof(*pair)); - if (pair == NULL) { - D("sdb_socketpair: not enough memory to allocate pipes\n"); - goto Fail; } - bip_buffer_init(&pair->a2b_bip); - bip_buffer_init(&pair->b2a_bip); + _ha->u.socket = socks[0]; + _hb->u.socket = socks[1]; - fa->fh_pair = pair; - fb->fh_pair = pair; - pair->used = 2; - pair->a_fd = fa; - - sv[0] = _fh_to_int(fa); - sv[1] = _fh_to_int(fb); - - pair->a2b_bip.fdin = sv[0]; - pair->a2b_bip.fdout = sv[1]; - pair->b2a_bip.fdin = sv[1]; - pair->b2a_bip.fdout = sv[0]; + if (_ha->u.socket == INVALID_SOCKET || _hb->u.socket == INVALID_SOCKET) { + _fh_close(_ha); + _fh_close(_hb); + LOG_ERROR( "failed to get socket:(%ld)\n", GetLastError()); + return -1; + } + sv[0] = _ha->fd; + sv[1] = _hb->fd; - snprintf(fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1]); - snprintf(fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0]); - D( "sdb_socketpair: returns (%d, %d)\n", sv[0], sv[1]); + D( "sdb_socketpair: returns (FD(%d), FD(%d))\n", sv[0], sv[1] ); return 0; - - Fail: _fh_close(fb); - _fh_close(fa); - return -1; } + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -1264,198 +833,18 @@ static int _sdb_socketpair(int sv[2]) { /**************************************************************************/ /**************************************************************************/ - -/** FILE EVENT HOOKS - **/ - -static void _event_file_prepare(EventHook hook) { - if (hook->wanted & (FDE_READ | FDE_WRITE)) { - /* we can always read/write */ - hook->ready |= hook->wanted & (FDE_READ | FDE_WRITE); - } -} - -static int _event_file_peek(EventHook hook) { - return (hook->wanted & (FDE_READ | FDE_WRITE)); -} - -static void _fh_file_hook(FH f, int events, EventHook hook) { - hook->h = f->fh_handle; - hook->prepare = _event_file_prepare; - hook->peek = _event_file_peek; -} - -/** SOCKET EVENT HOOKS - **/ - -static void _event_socket_verify(EventHook hook, WSANETWORKEVENTS* evts) { - if (evts->lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) { - if (hook->wanted & FDE_READ) - hook->ready |= FDE_READ; - if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR) - hook->ready |= FDE_ERROR; - } - if (evts->lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE)) { - if (hook->wanted & FDE_WRITE) - hook->ready |= FDE_WRITE; - if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR) - hook->ready |= FDE_ERROR; - } - if (evts->lNetworkEvents & FD_OOB) { - if (hook->wanted & FDE_ERROR) - hook->ready |= FDE_ERROR; - } -} - -static void _event_socket_prepare(EventHook hook) { - WSANETWORKEVENTS evts; - - /* look if some of the events we want already happened ? */ - if (!WSAEnumNetworkEvents(hook->fh->fh_socket, NULL, &evts)) - _event_socket_verify(hook, &evts); -} - -static int _socket_wanted_to_flags(int wanted) { - int flags = 0; - if (wanted & FDE_READ) - flags |= FD_READ | FD_ACCEPT | FD_CLOSE; - - if (wanted & FDE_WRITE) - flags |= FD_WRITE | FD_CONNECT | FD_CLOSE; - - if (wanted & FDE_ERROR) - flags |= FD_OOB; - - return flags; -} - -static int _event_socket_start(EventHook hook) { - /* create an event which we're going to wait for */ - FH fh = hook->fh; - long flags = _socket_wanted_to_flags(hook->wanted); - - hook->h = fh->event; - if (hook->h == INVALID_HANDLE_VALUE) { - D( "_event_socket_start: no event for %s\n", fh->name); - return 0; - } - - if (flags != fh->mask) { - D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags); - if (WSAEventSelect(fh->fh_socket, hook->h, flags)) { - D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError()); - CloseHandle(hook->h); - hook->h = INVALID_HANDLE_VALUE; - exit(1); - return 0; - } - fh->mask = flags; - } - return 1; -} - -static void _event_socket_stop(EventHook hook) { - hook->h = INVALID_HANDLE_VALUE; -} - -static int _event_socket_check(EventHook hook) { - int result = 0; - FH fh = hook->fh; - WSANETWORKEVENTS evts; - - if (!WSAEnumNetworkEvents(fh->fh_socket, hook->h, &evts)) { - _event_socket_verify(hook, &evts); - result = (hook->ready != 0); - if (result) { - ResetEvent(hook->h); - } - } - D( "_event_socket_check %s returns %d\n", fh->name, result); - return result; -} - -static int _event_socket_peek(EventHook hook) { - WSANETWORKEVENTS evts; - FH fh = hook->fh; - - /* look if some of the events we want already happened ? */ - if (!WSAEnumNetworkEvents(fh->fh_socket, NULL, &evts)) { - _event_socket_verify(hook, &evts); - if (hook->ready) - ResetEvent(hook->h); - } - - return hook->ready != 0; -} - -static void _fh_socket_hook(FH f, int events, EventHook hook) { - hook->prepare = _event_socket_prepare; - hook->start = _event_socket_start; - hook->stop = _event_socket_stop; - hook->check = _event_socket_check; - hook->peek = _event_socket_peek; - - _event_socket_start(hook); -} - -/** SOCKETPAIR EVENT HOOKS - **/ - -static void _event_socketpair_prepare(EventHook hook) { - FH fh = hook->fh; - SocketPair pair = fh->fh_pair; - BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip; - BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip; - - if (hook->wanted & FDE_READ && rbip->can_read) - hook->ready |= FDE_READ; - - if (hook->wanted & FDE_WRITE && wbip->can_write) - hook->ready |= FDE_WRITE; -} - -static int _event_socketpair_start(EventHook hook) { - FH fh = hook->fh; - SocketPair pair = fh->fh_pair; - BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip; - BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip; - - if (hook->wanted == FDE_READ) - hook->h = rbip->evt_read; - - else if (hook->wanted == FDE_WRITE) - hook->h = wbip->evt_write; - - else { - D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n"); - return 0; - } - D( "_event_socketpair_start: hook %s for %x wanted=%x\n", hook->fh->name, _fh_to_int(fh), hook->wanted); - return 1; -} - -static int _event_socketpair_peek(EventHook hook) { - _event_socketpair_prepare(hook); - return hook->ready != 0; -} - -static void _fh_socketpair_hook(FH fh, int events, EventHook hook) { - hook->prepare = _event_socketpair_prepare; - hook->start = _event_socketpair_start; - hook->peek = _event_socketpair_peek; -} - static void _sdb_sysdeps_init(void) { //re define mutex variable & initialized #undef SDB_MUTEX #define SDB_MUTEX(x) InitializeCriticalSection( & x ); SDB_MUTEX(dns_lock) - SDB_MUTEX(socket_list_lock) SDB_MUTEX(transport_lock) - SDB_MUTEX(local_transports_lock) SDB_MUTEX(usb_lock) + SDB_MUTEX(wakeup_select_lock) SDB_MUTEX(D_lock) SDB_MUTEX(_win32_lock); + SDB_MUTEX(sdb_handle_map_lock); + SDB_MUTEX(free_socket_handle_list_lock); } typedef void (*win_thread_func_t)(void* arg); @@ -1609,16 +998,13 @@ const struct utils_os_backend utils_windows_backend = { .start_logging = _start_logging, .ansi_to_utf8 = _ansi_to_utf8, .sdb_open = _sdb_open, - .sdb_open_mode = _sdb_open_mode, - .unix_open = _unix_open, .sdb_creat = _sdb_creat, .sdb_read = _sdb_read, .sdb_write = _sdb_write, - .sdb_lseek = _sdb_lseek, .sdb_shutdown = _sdb_shutdown, + .sdb_transport_close = _sdb_transport_close, .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, @@ -1635,8 +1021,6 @@ const struct utils_os_backend utils_windows_backend = { .sdb_cond_init = _pthread_cond_init, .sdb_cond_broadcast = _pthread_cond_broadcast, .sdb_sysdeps_init = _sdb_sysdeps_init, - .socket_loopback_client = _socket_loopback_client, - .socket_network_client = _socket_network_client, - .socket_loopback_server = _socket_loopback_server, - .socket_inaddr_any_server = _socket_inaddr_any_server + .sdb_host_connect = _sdb_host_connect, + .sdb_port_listen = _sdb_port_listen };