--- /dev/null
+sdb_*.tar.gz
+sdb_*_*.zip
+sdb.package.*
+
+usb-connection-for-ssh_*_*.zip
+usb-connection-for-ssh.package.*
+
+*.bak
+bin/
+prebuilt/
+src/sdbwinapi/buildfre_win7_x86.log
+src/sdbwinapi/buildfre_win7_x86.wrn
+src/sdbwinapi/objfre_win7_x86/
+src/sdbwinusbapi/buildfre_win7_x86.log
+src/sdbwinusbapi/buildfre_win7_x86.wrn
+src/sdbwinusbapi/objfre_win7_x86/
#
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
# =========================================================
ifeq ($(HOST_OS),darwin)
CC := clang
endif
-
#
ifeq ($(HOST_OS),linux)
LOCAL_USB_SRC := src/usb_linux.c
LOCAL_UTIL_SRC := src/utils_unix.c
LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c
- LOCAL_LFLAGS := -lrt -lpthread
+ LOCAL_LFLAGS := -lrt -lpthread -ludev
LOCAL_CFLAGS := -DOS_LINUX -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1 -D_FILE_OFFSET_BITS=64
+ HAS_LIBUSB := false
endif
ifeq ($(HOST_OS),darwin)
- LOCAL_USB_SRC := src/libusb/darwin.c src/sdb_usb.c src/libusb/error.c src/libusb/usb.c src/libusb/descriptors.c
+ LOCAL_USB_SRC := src/usb_darwin.c
LOCAL_UTIL_SRC := src/utils_unix.c
LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c
LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS := -DOS_DARWIN -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -mmacosx-version-min=10.4 -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1
+ HAS_LIBUSB := false
endif
ifeq ($(HOST_OS),mingw32)
- LOCAL_USB_SRC := src/libusb/windows.c
+ LOCAL_USB_SRC := deps/libusb/windows.c
LOCAL_UTIL_SRC := src/utils_windows.c
LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_windows.c
LOCAL_CFLAGS := -DOS_WINDOWS
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
SDB_LFLAGS := $(LOCAL_LFLAGS)
STATIC_LFLAGS := $(LOCAL_STATIC_LFLAGS)
-OBJDIR := bin
-
-MODULE := sdb
-
all : $(MODULE)
sdb : $(SDB_SRC_FILES)
- rm -rf $(OBJDIR)
mkdir -p $(OBJDIR)
+ifeq ($(HAS_LIBUSB),true)
+ make -C ./deps/libusb
+ make install -C ./deps/libusb
+endif
$(CC) $(SDB_CFLAGS) -o $(OBJDIR)/$(MODULE) $(SDB_SRC_FILES) $(LOCAL_IFLAGS) $(SDB_LFLAGS) $(STATIC_LFLAGS)
clean :
- rm -rf $(OBJDIR)/*
+ rm -rf $(OBJDIR)
--- /dev/null
+Daniel Drake <dsd@gentoo.org>
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
--- /dev/null
+libusb is covered by the LGPL:
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+----
+
+Alternatively, the files usb.h.in and/or usb.h may be licensed under the
+BSD license:
+
+Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
--- /dev/null
+#
+#
+# Makefile for libusb
+#
+
+#
+HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1)
+
+# =========================================================
+
+ifeq ($(HOST_OS),darwin)
+ CC := /Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/bin/llvm-gcc-4.2
+else
+ CC := gcc
+endif
+
+#
+ifeq ($(HOST_OS),linux)
+ LOCAL_USB_SRC := linux.c error.c usb.c descriptors.c
+ LOCAL_LFLAGS := -lrt -lpthread
+ LOCAL_CFLAGS := -DOS_LINUX
+endif
+
+ifeq ($(HOST_OS),darwin)
+ LOCAL_USB_SRC := darwin.c error.c usb.c descriptors.c
+ LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+ LOCAL_CFLAGS := -DOS_DARWIN -mmacosx-version-min=10.4
+endif
+
+MODULE = libusb.so
+
+all : $(MODULE)
+
+$(MODULE) : $(LOCAL_USB_SRC)
+ $(CC) -o $(MODULE) -fPIC $(LOCAL_USB_SRC) $(LOCAL_LFLAGS) $(LOCAL_CFLAGS) -shared
+
+install :
+ mkdir -p ../../bin
+ cp $(MODULE) ../../bin
+clean :
+ rm -rf $(MODULE)
+ rm -rf *.o
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Darwin/MacOS X Support
+ *
+ * (c) 2002-2007 Nathan Hjelm <hjelmn@users.sourceforge.net>
+ *
+ * (07/25/2007):
+ * - Added a fix to ignore buggy (virtual?) hubs.
+ * (06/26/2006):
+ * - Bulk functions no longer use async transfer functions.
+ * (04/17/2005):
+ * - Lots of minor fixes.
+ * - Endpoint table now made by claim_interface to fix a bug.
+ * - Merged Read/Write to make modifications easier.
+ * (03/25/2005):
+ * - Fixed a bug when using asynchronous callbacks within a multi-threaded application.
+ * (03/14/2005):
+ * - Added an endpoint table to speed up bulk transfers.
+ * 0.1.11 (02/22/2005):
+ * - Updated error checking in read/write routines to check completion codes.
+ * - Updated set_configuration so that the open interface is reclaimed before completion.
+ * - Fixed several typos.
+ * 0.1.8 (01/12/2004):
+ * - Fixed several memory leaks.
+ * - Readded 10.0 support
+ * - Added support for USB fuctions defined in 10.3 and above
+ * (01/02/2003):
+ * - Applied a patch by Philip Edelbrock <phil@edgedesign.us> that fixes a bug in usb_control_msg.
+ * (12/16/2003):
+ * - Even better error printing.
+ * - Devices that cannot be opened can have their interfaces opened.
+ * 0.1.6 (05/12/2002):
+ * - Fixed problem where libusb holds resources after program completion.
+ * - Mouse should no longer freeze up now.
+ * 0.1.2 (02/13/2002):
+ * - Bulk functions should work properly now.
+ * 0.1.1 (02/11/2002):
+ * - Fixed major bug (device and interface need to be released after use)
+ * 0.1.0 (01/06/2002):
+ * - Tested driver with gphoto (works great as long as Image Capture isn't running)
+ * 0.1d (01/04/2002):
+ * - Implimented clear_halt and resetep
+ * - Uploaded to CVS.
+ * 0.1b (01/04/2002):
+ * - Added usb_debug line to bulk read and write function.
+ * 0.1a (01/03/2002):
+ * - Driver mostly completed using the macosx driver I wrote for my rioutil software.
+ *
+ * Derived from Linux version by Richard Tobin.
+ * Also partly derived from BSD version.
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* standard includes for darwin/os10 (IOKit) */
+#include <mach/mach_port.h>
+#include <IOKit/IOCFBundle.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+
+#include "usbi.h"
+
+/* some defines */
+/* IOUSBInterfaceInferface */
+#if defined (kIOUSBInterfaceInterfaceID220)
+
+// #warning "libusb being compiled for 10.4 or later"
+#define usb_interface_t IOUSBInterfaceInterface220
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+#define InterfaceVersion 220
+
+#elif defined (kIOUSBInterfaceInterfaceID197)
+
+// #warning "libusb being compiled for 10.3 or later"
+#define usb_interface_t IOUSBInterfaceInterface197
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+#define InterfaceVersion 197
+
+#elif defined (kIOUSBInterfaceInterfaceID190)
+
+// #warning "libusb being compiled for 10.2 or later"
+#define usb_interface_t IOUSBInterfaceInterface190
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+#define InterfaceVersion 190
+
+#elif defined (kIOUSBInterfaceInterfaceID182)
+
+// #warning "libusb being compiled for 10.1 or later"
+#define usb_interface_t IOUSBInterfaceInterface182
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+#define InterfaceVersion 182
+
+#else
+
+/* No timeout functions available! Time to upgrade your os. */
+#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up"
+#define usb_interface_t IOUSBInterfaceInterface
+#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID
+#define LIBUSB_NO_TIMEOUT_INTERFACE
+#define InterfaceVersion 180
+
+#endif
+
+/* IOUSBDeviceInterface */
+#if defined (kIOUSBDeviceInterfaceID197)
+
+#define usb_device_t IOUSBDeviceInterface197
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+#define DeviceVersion 197
+
+#elif defined (kIOUSBDeviceInterfaceID187)
+
+#define usb_device_t IOUSBDeviceInterface187
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+#define DeviceVersion 187
+
+#elif defined (kIOUSBDeviceInterfaceID182)
+
+#define usb_device_t IOUSBDeviceInterface182
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+#define DeviceVersion 182
+
+#else
+
+#define usb_device_t IOUSBDeviceInterface
+#define DeviceInterfaceID kIOUSBDeviceInterfaceID
+#define LIBUSB_NO_TIMEOUT_DEVICE
+#define LIBUSB_NO_SEIZE_DEVICE
+#define DeviceVersion 180
+
+#endif
+
+typedef IOReturn io_return_t;
+typedef IOCFPlugInInterface *io_cf_plugin_ref_t;
+typedef SInt32 s_int32_t;
+typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+ IOAsyncCallback1 callback, void *refcon);
+typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size,
+ UInt32 noDataTimeout, UInt32 completionTimeout,
+ IOAsyncCallback1 callback, void *refcon);
+
+#if !defined(IO_OBJECT_NULL)
+#define IO_OBJECT_NULL ((io_object_t)0)
+#endif
+
+struct darwin_dev_handle {
+ usb_device_t **device;
+ usb_interface_t **interface;
+ int open;
+
+ /* stored translation table for pipes to endpoints */
+ int num_endpoints;
+ unsigned char *endpoint_addrs;
+};
+
+static IONotificationPortRef gNotifyPort;
+static mach_port_t masterPort = MACH_PORT_NULL;
+
+static void darwin_cleanup (void)
+{
+ IONotificationPortDestroy(gNotifyPort);
+ mach_port_deallocate(mach_task_self(), masterPort);
+}
+
+static char *darwin_error_str (int result) {
+ switch (result) {
+ case kIOReturnSuccess:
+ return "no error";
+ case kIOReturnNotOpen:
+ return "device not opened for exclusive access";
+ case kIOReturnNoDevice:
+ return "no connection to an IOService";
+ case kIOUSBNoAsyncPortErr:
+ return "no async port has been opened for interface";
+ case kIOReturnExclusiveAccess:
+ return "another process has device opened for exclusive access";
+ case kIOUSBPipeStalled:
+ return "pipe is stalled";
+ case kIOReturnError:
+ return "could not establish a connection to the Darwin kernel";
+ case kIOUSBTransactionTimeout:
+ return "transaction timed out";
+ case kIOReturnBadArgument:
+ return "invalid argument";
+ case kIOReturnAborted:
+ return "transaction aborted";
+ case kIOReturnNotResponding:
+ return "device not responding";
+ default:
+ return "unknown error";
+ }
+}
+
+/* not a valid errorno outside darwin.c */
+#define LUSBDARWINSTALL (ELAST+1)
+
+static int darwin_to_errno (int result) {
+ switch (result) {
+ case kIOReturnSuccess:
+ return 0;
+ case kIOReturnNotOpen:
+ return EBADF;
+ case kIOReturnNoDevice:
+ case kIOUSBNoAsyncPortErr:
+ return ENXIO;
+ case kIOReturnExclusiveAccess:
+ return EBUSY;
+ case kIOUSBPipeStalled:
+ return LUSBDARWINSTALL;
+ case kIOReturnBadArgument:
+ return EINVAL;
+ case kIOUSBTransactionTimeout:
+ return ETIMEDOUT;
+ case kIOReturnNotResponding:
+ return EIO;
+ case kIOReturnError:
+ default:
+ return 1;
+ }
+}
+
+static int usb_setup_iterator (io_iterator_t *deviceIterator)
+{
+ int result;
+ CFMutableDictionaryRef matchingDict;
+
+ /* set up the matching dictionary for class IOUSBDevice and its subclasses.
+ It will be consumed by the IOServiceGetMatchingServices call */
+ if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
+ darwin_cleanup ();
+
+ USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n");
+ }
+
+ result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator);
+ matchingDict = NULL;
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n",
+ darwin_error_str(result));
+
+ return 0;
+}
+
+static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp)
+{
+ io_cf_plugin_ref_t *plugInInterface = NULL;
+ usb_device_t **device;
+ io_service_t usbDevice;
+ long result, score;
+
+ if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator)))
+ return NULL;
+
+ result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &plugInInterface,
+ &score);
+
+ result = IOObjectRelease(usbDevice);
+ if (result || !plugInInterface)
+ return NULL;
+
+ (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
+ (LPVOID)&device);
+
+ (*plugInInterface)->Stop(plugInInterface);
+ IODestroyPlugInInterface (plugInInterface);
+ plugInInterface = NULL;
+
+ (*(device))->GetLocationID(device, locationp);
+
+ return device;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result;
+ io_iterator_t deviceIterator;
+
+ usb_device_t **darwin_device;
+
+ UInt32 location = *((UInt32 *)dev->device->dev);
+ UInt32 dlocation;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if (masterPort == MACH_PORT_NULL)
+ USB_ERROR(-EINVAL);
+
+ device = calloc(1, sizeof(struct darwin_dev_handle));
+ if (!device)
+ USB_ERROR(-ENOMEM);
+
+ if (usb_debug > 3)
+ fprintf(stderr, "usb_os_open: %04x:%04x\n",
+ dev->device->descriptor.idVendor,
+ dev->device->descriptor.idProduct);
+
+ if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+ return result;
+
+ /* This port of libusb uses locations to keep track of devices. */
+ while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) {
+ if (dlocation == location)
+ break;
+
+ (*darwin_device)->Release(darwin_device);
+ }
+
+ IOObjectRelease(deviceIterator);
+ device->device = darwin_device;
+
+ if (device->device == NULL)
+ USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!");
+
+#if !defined (LIBUSB_NO_SEIZE_DEVICE)
+ result = (*(device->device))->USBDeviceOpenSeize (device->device);
+#else
+ /* No Seize in OS X 10.0 (Darwin 1.4) */
+ result = (*(device->device))->USBDeviceOpen (device->device);
+#endif
+
+ if (result != kIOReturnSuccess) {
+ switch (result) {
+ case kIOReturnExclusiveAccess:
+ if (usb_debug > 0)
+ fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result));
+ break;
+ default:
+ (*(device->device))->Release (device->device);
+ USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s",
+ darwin_error_str(result));
+ }
+
+ device->open = 0;
+ } else
+ device->open = 1;
+
+ dev->impl_info = device;
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ device->num_endpoints = 0;
+ device->endpoint_addrs = NULL;
+
+ return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ usb_release_interface(dev, dev->interface);
+
+ if (usb_debug > 3)
+ fprintf(stderr, "usb_os_close: %04x:%04x\n",
+ dev->device->descriptor.idVendor,
+ dev->device->descriptor.idProduct);
+
+ if (device->open == 1)
+ result = (*(device->device))->USBDeviceClose(device->device);
+ else
+ result = kIOReturnSuccess;
+
+ /* device may not need to be released, but if it has to... */
+ (*(device->device))->Release(device->device);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result));
+
+ free (device);
+
+ return 0;
+}
+
+static int get_endpoints (struct darwin_dev_handle *device)
+{
+ io_return_t ret;
+
+ u_int8_t numep, direction, number;
+ u_int8_t dont_care1, dont_care3;
+ u_int16_t dont_care2;
+
+ int i;
+
+ if (device == NULL || device->interface == NULL)
+ return -EINVAL;
+
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n");
+
+ /* retrieve the total number of endpoints on this interface */
+ ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep);
+ if ( ret ) {
+ if ( usb_debug > 1 )
+ fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface );
+
+ USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" );
+ }
+
+ free (device->endpoint_addrs);
+ device->endpoint_addrs = calloc (sizeof (unsigned char), numep);
+
+ /* iterate through pipe references */
+ for (i = 1 ; i <= numep ; i++) {
+ ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number,
+ &dont_care1, &dont_care2, &dont_care3);
+
+ if (ret != kIOReturnSuccess) {
+ fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n",
+ i );
+ USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret));
+ }
+
+ if (usb_debug > 1)
+ fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number);
+
+ device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) |
+ (number & USB_ENDPOINT_ADDRESS_MASK));
+ }
+
+ device->num_endpoints = numep;
+
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n");
+
+ return 0;
+}
+
+static int claim_interface (usb_dev_handle *dev, int interface)
+{
+ io_iterator_t interface_iterator;
+ io_service_t usbInterface = IO_OBJECT_NULL;
+ io_return_t result;
+ io_cf_plugin_ref_t *plugInInterface = NULL;
+
+ IOUSBFindInterfaceRequest request;
+
+ struct darwin_dev_handle *device;
+ long score;
+ int current_interface;
+
+ device = dev->impl_info;
+
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+ darwin_error_str(result));
+
+ for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) {
+ usbInterface = IOIteratorNext(interface_iterator);
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "Interface %d of device is 0x%08x\n",
+ current_interface, usbInterface );
+ }
+
+ current_interface--;
+
+ /* the interface iterator is no longer needed, release it */
+ IOObjectRelease(interface_iterator);
+
+ if (!usbInterface) {
+ u_int8_t nConfig; /* Index of configuration to use */
+ IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */
+ /* Only a composite class device with no vendor-specific driver will
+ be configured. Otherwise, we need to do it ourselves, or there
+ will be no interfaces for the device. */
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" );
+
+ result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig );
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s",
+ darwin_error_str(result));
+
+ if (nConfig < 1)
+ USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations");
+ else if ( nConfig > 1 && usb_debug > 0 )
+ fprintf ( stderr, "claim_interface: device has more than one"
+ " configuration, using the first (warning)\n" );
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: device has %d configuration%s\n",
+ (int)nConfig, (nConfig>1?"s":"") );
+
+ /* Always use the first configuration */
+ result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc );
+ if (result != kIOReturnSuccess) {
+ if (device->open == 1) {
+ (*(device->device))->USBDeviceClose ( (device->device) );
+ (*(device->device))->Release ( (device->device) );
+ }
+
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s",
+ darwin_error_str(result));
+ } else if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: configuration value is %d\n",
+ configDesc->bConfigurationValue );
+
+ if (device->open == 1) {
+ result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue );
+
+ if (result != kIOReturnSuccess) {
+ (*(device->device))->USBDeviceClose ( (device->device) );
+ (*(device->device))->Release ( (device->device) );
+
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s",
+ darwin_error_str(result));
+ }
+
+ dev->config = configDesc->bConfigurationValue;
+ }
+
+ request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
+ request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
+ request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ /* Now go back and get the chosen interface */
+ result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator);
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s",
+ darwin_error_str(result));
+
+ for (current_interface = 0 ; current_interface <= interface ; current_interface++) {
+ usbInterface = IOIteratorNext(interface_iterator);
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n",
+ current_interface, usbInterface );
+ }
+ current_interface--;
+
+ /* the interface iterator is no longer needed, release it */
+ IOObjectRelease(interface_iterator);
+
+ if (!usbInterface)
+ USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL");
+ }
+
+ result = IOCreatePlugInInterfaceForService(usbInterface,
+ kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &plugInInterface, &score);
+ /* No longer need the usbInterface object after getting the plug-in */
+ result = IOObjectRelease(usbInterface);
+ if (result || !plugInInterface)
+ USB_ERROR(-ENOENT);
+
+ /* Now create the device interface for the interface */
+ result = (*plugInInterface)->QueryInterface(plugInInterface,
+ CFUUIDGetUUIDBytes(InterfaceInterfaceID),
+ (LPVOID) &device->interface);
+
+ /* No longer need the intermediate plug-in */
+ (*plugInInterface)->Stop(plugInInterface);
+ IODestroyPlugInInterface (plugInInterface);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s",
+ darwin_error_str(result));
+
+ if (!device->interface)
+ USB_ERROR(-EACCES);
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n",
+ current_interface, device->interface);
+
+ /* claim the interface */
+ result = (*(device->interface))->USBInterfaceOpen(device->interface);
+ if (result)
+ USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s",
+ darwin_error_str(result));
+
+ result = get_endpoints (device);
+
+ if (result) {
+ /* this should not happen */
+ usb_release_interface (dev, interface);
+ USB_ERROR_STR ( result, "claim_interface: could not build endpoint table");
+ }
+
+ return 0;
+}
+
+int usb_set_configuration (usb_dev_handle *dev, int configuration)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+ int interface;
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration );
+
+ if (!dev)
+ USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" );
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" );
+
+ /* Setting configuration will invalidate the interface, so we need
+ to reclaim it. First, dispose of existing interface, if any. */
+ interface = dev->interface;
+
+ if ( device->interface )
+ usb_release_interface(dev, dev->interface);
+
+ result = (*(device->device))->SetConfiguration(device->device, configuration);
+
+ if (result)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s",
+ darwin_error_str(result));
+
+ /* Reclaim interface */
+ if (interface != -1)
+ result = usb_claim_interface (dev, interface);
+
+ dev->config = configuration;
+
+ return result;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+ struct darwin_dev_handle *device = dev->impl_info;
+
+ io_return_t result;
+
+ if ( usb_debug > 3 )
+ fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface );
+
+ if (!device)
+ USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" );
+
+ if (!(device->device))
+ USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" );
+
+ /* If we have already claimed an interface, release it */
+ if ( device->interface )
+ usb_release_interface(dev, dev->interface);
+
+ result = claim_interface ( dev, interface );
+ if ( result )
+ USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" );
+
+ dev->interface = interface;
+
+ /* interface is claimed and async IO is set up: return 0 */
+ return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ return 0;
+
+ result = (*(device->interface))->USBInterfaceClose(device->interface);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s",
+ darwin_error_str(result));
+
+ result = (*(device->interface))->Release(device->interface);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s",
+ darwin_error_str(result));
+
+ device->interface = NULL;
+
+ free (device->endpoint_addrs);
+
+ device->num_endpoints = 0;
+ device->endpoint_addrs = NULL;
+
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+ struct darwin_dev_handle *device;
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed");
+
+ result = (*(device->interface))->SetAlternateInterface(device->interface, alternate);
+
+ if (result)
+ USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface");
+
+ dev->altsetting = alternate;
+
+ result = get_endpoints (device);
+ if (result) {
+ /* this should not happen */
+ USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table");
+ }
+
+ return 0;
+}
+
+/* simple function that figures out what pipeRef is associated with an endpoint */
+static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep)
+{
+ int i;
+
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n");
+
+ for (i = 0 ; i < device->num_endpoints ; i++)
+ if (device->endpoint_addrs[i] == ep)
+ return i + 1;
+
+ /* No pipe found with the correct endpoint address */
+ if (usb_debug > 1)
+ fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep);
+
+ return -1;
+}
+
+static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ int pipeRef;
+
+ u_int8_t transferType, direction, number, interval;
+ u_int16_t maxPacketSize;
+
+ if (!dev)
+ USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" );
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" );
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened");
+
+
+ /* Set up transfer */
+ if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+ USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" );
+
+ (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+ &transferType, &maxPacketSize, &interval);
+ /* Transfer set up complete */
+
+ if (usb_debug > 0)
+ fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep);
+
+ /* Do bulk transfer */
+ if (transferType == kUSBInterrupt && usb_debug > 3)
+ fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE)
+ if ( transferType != kUSBInterrupt) {
+ if (usb_bt_read != 0)
+ result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout);
+ else
+ result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout);
+
+ /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */
+ if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled)
+ usb_clear_halt (dev, ep);
+ } else
+#endif
+ {
+ if (usb_bt_read != 0)
+ result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size);
+ else
+ result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size);
+ }
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result));
+
+ return size;
+}
+
+#if 0
+/* NOT USED */
+/* argument to handle multiple parameters to rw_completed */
+struct rw_complete_arg {
+ UInt32 io_size;
+ IOReturn result;
+ CFRunLoopRef cf_loop;
+};
+
+static void rw_completed(void *refcon, io_return_t result, void *io_size)
+{
+ struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon;
+
+ if (usb_debug > 2)
+ fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result),
+ (UInt32)io_size, result);
+
+ rw_arg->io_size = (UInt32)io_size;
+ rw_arg->result = result;
+
+ CFRunLoopStop(rw_arg->cf_loop);
+}
+
+static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout,
+ rw_async_func_t rw_async, rw_async_to_func_t rw_async_to)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ CFRunLoopSourceRef cfSource;
+ int pipeRef;
+
+ struct rw_complete_arg rw_arg;
+
+ u_int8_t transferType;
+
+ /* None of the values below are used in libusb for bulk transfers */
+ u_int8_t direction, number, interval;
+ u_int16_t maxPacketSize;
+
+ if (!dev)
+ USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" );
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" );
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened");
+
+
+ /* Set up transfer */
+ if ((pipeRef = ep_to_pipeRef(device, ep)) < 0)
+ USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" );
+
+ (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number,
+ &transferType, &maxPacketSize, &interval);
+
+ bzero((void *)&rw_arg, sizeof(struct rw_complete_arg));
+ rw_arg.cf_loop = CFRunLoopGetCurrent();
+ CFRetain (rw_arg.cf_loop);
+
+ (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource);
+ CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
+ /* Transfer set up complete */
+
+ if (usb_debug > 0)
+ fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n",
+ size, ep);
+
+ /* Bulk transfer */
+ if (transferType == kUSBInterrupt && usb_debug > 3)
+ fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n");
+
+ if ( transferType != kUSBInterrupt && rw_async_to != NULL)
+
+ result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout,
+ (IOAsyncCallback1)rw_completed, (void *)&rw_arg);
+ else
+ result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed,
+ (void *)&rw_arg);
+
+ if (result == kIOReturnSuccess) {
+ /* wait for write to complete */
+ if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) {
+ (*(device->interface))->AbortPipe(device->interface, pipeRef);
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */
+ if (usb_debug)
+ fprintf(stderr, "usb_bulk_transfer: timed out\n");
+ }
+ }
+
+ CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode);
+ CFRelease (rw_arg.cf_loop);
+
+ /* Check the return code of both the write and completion functions. */
+ if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess &&
+ rw_arg.result != kIOReturnAborted) ) {
+ int error_code;
+ char *error_str;
+
+ if (result == kIOReturnSuccess) {
+ error_code = darwin_to_errno (rw_arg.result);
+ error_str = darwin_error_str (rw_arg.result);
+ } else {
+ error_code = darwin_to_errno(result);
+ error_str = darwin_error_str (result);
+ }
+
+ if (transferType != kUSBInterrupt && rw_async_to != NULL)
+ USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str);
+ else
+ USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str);
+ }
+
+ return rw_arg.io_size;
+}
+#endif
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+ int result;
+
+ if (dev == NULL || dev->impl_info == NULL)
+ return -EINVAL;
+
+ if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0)
+ USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)");
+
+ return result;
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+{
+ int result;
+
+ if (dev == NULL || dev->impl_info == NULL)
+ return -EINVAL;
+
+ ep |= 0x80;
+
+ if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0)
+ USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)");
+
+ return result;
+}
+
+/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ return usb_bulk_write (dev, ep, bytes, size, timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ return usb_bulk_read (dev, ep, bytes, size, timeout);
+}
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout)
+{
+ struct darwin_dev_handle *device = dev->impl_info;
+
+ io_return_t result;
+
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+ IOUSBDevRequestTO urequest;
+#else
+ IOUSBDevRequest urequest;
+#endif
+
+ if (usb_debug >= 3)
+ fprintf(stderr, "libusb/darwin.c usb_control_msg (device: %s): %d %d %d %d %p %d %d\n",
+ dev->device->filename, requesttype, request, value, index, bytes, size, timeout);
+
+ bzero(&urequest, sizeof(urequest));
+
+ urequest.bmRequestType = requesttype;
+ urequest.bRequest = request;
+ urequest.wValue = value;
+ urequest.wIndex = index;
+ urequest.wLength = size;
+ urequest.pData = bytes;
+#if !defined (LIBUSB_NO_TIMEOUT_DEVICE)
+ urequest.completionTimeout = timeout;
+ urequest.noDataTimeout = timeout;
+
+ result = (*(device->device))->DeviceRequestTO(device->device, &urequest);
+#else
+ result = (*(device->device))->DeviceRequest(device->device, &urequest);
+#endif
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "libusb/darwin.c usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result));
+
+ /* Bytes transfered is stored in the wLenDone field*/
+ return urequest.wLenDone;
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+ struct usb_bus *fbus = NULL;
+
+ io_iterator_t deviceIterator;
+ io_return_t result;
+
+ usb_device_t **device;
+
+ UInt32 location;
+
+ char buf[20];
+ int i = 1;
+
+ /* Create a master port for communication with IOKit (this should
+ have been created if the user called usb_init() )*/
+ if (masterPort == MACH_PORT_NULL) {
+ usb_init ();
+
+ if (masterPort == MACH_PORT_NULL)
+ USB_ERROR(-ENOENT);
+ }
+
+ if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+ return result;
+
+ while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+ struct usb_bus *bus;
+
+ if (location & 0x00ffffff)
+ continue;
+
+ bus = calloc(1, sizeof(struct usb_bus));
+ if (bus == NULL)
+ USB_ERROR(-ENOMEM);
+
+ sprintf(buf, "%03i", i++);
+ bus->location = location;
+
+ strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1);
+ bus->dirname[sizeof(bus->dirname) - 1] = 0;
+
+ LIST_ADD(fbus, bus);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+
+ (*(device))->Release(device);
+ }
+
+ IOObjectRelease(deviceIterator);
+
+ *busses = fbus;
+
+ return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+ struct usb_device *fdev = NULL;
+
+ io_iterator_t deviceIterator;
+ io_return_t result;
+
+ usb_device_t **device;
+
+ u_int16_t address;
+ UInt32 location;
+ UInt32 bus_loc = bus->location;
+ int devnum;
+
+ /* for use in retrieving device description */
+ IOUSBDevRequest req;
+
+ /* a master port should have been created by usb_os_init */
+ if (masterPort == MACH_PORT_NULL)
+ USB_ERROR(-ENOENT);
+
+ if ((result = usb_setup_iterator (&deviceIterator)) < 0)
+ return result;
+
+ /* Set up request for device descriptor */
+ req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = kUSBDeviceDesc << 8;
+ req.wIndex = 0;
+ req.wLength = sizeof(IOUSBDeviceDescriptor);
+
+ devnum = 0;
+
+ while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) {
+ unsigned char device_desc[DEVICE_DESC_LENGTH];
+ UInt8 bDeviceClass, bDeviceSubClass;
+ UInt16 idVendor, idProduct;
+
+ result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address);
+
+ if (result == kIOReturnSuccess) {
+ (*(device))->GetDeviceClass (device, &bDeviceClass);
+ (*(device))->GetDeviceSubClass (device, &bDeviceSubClass);
+ (*(device))->GetDeviceProduct (device, &idProduct);
+ (*(device))->GetDeviceVendor (device, &idVendor);
+
+ if ((location >> 24) == (bus_loc >> 24)) {
+ struct usb_device *dev;
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found USB device on bus 0x%08lx: 0x%08lx\n",
+ bus_loc, location);
+
+ dev = calloc(1, sizeof(struct usb_device));
+ if (dev == NULL)
+ USB_ERROR(-ENOMEM);
+
+ dev->bus = bus;
+
+ /* retrieve device descriptor */
+ req.pData = device_desc;
+ result = (*(device))->DeviceRequest(device, &req);
+
+ if (result != kIOReturnSuccess) {
+ free (dev);
+
+ if (usb_debug)
+ fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device descriptor: %s. Skipping device.\n",
+ darwin_error_str(result));
+
+ /* release the device now */
+ (*(device))->Release(device);
+ continue; /* can't continue without a descriptor */
+ }
+
+ usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor);
+
+ /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices */
+ if (dev->descriptor.idProduct != idProduct) {
+ free (dev);
+
+ if (usb_debug)
+ fprintf (stderr, "libusb/darwin.c usb_os_find_devices: idProduct from iokit does not match idProduct in descriptor. Skipping device\n");
+
+ /* release the device now */
+ (*(device))->Release(device);
+ continue; /* can't continue without a descriptor */
+ }
+
+ dev->devnum = devnum++;
+
+ sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass);
+
+ dev->dev = (USBDeviceAddress *) calloc (1, 4);
+ if (dev->dev == NULL)
+ USB_ERROR(-ENOMEM);
+
+ memcpy(dev->dev, &location, 4);
+
+ LIST_ADD(fdev, dev);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found %s on %s at location 0x%08lx\n",
+ dev->filename, bus->dirname, location);
+ }
+ } else if (usb_debug)
+ fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device address: %s\n",
+ darwin_error_str(result));
+
+ /* release the device now */
+ (*(device))->Release(device);
+ }
+
+ IOObjectRelease(deviceIterator);
+
+ *devices = fdev;
+
+ if (usb_debug)
+ fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Complete\n");
+
+ return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+ /* Nothing yet */
+ return 0;
+}
+
+void usb_os_init(void)
+{
+ if (masterPort == MACH_PORT_NULL) {
+ IOMasterPort(masterPort, &masterPort);
+
+ gNotifyPort = IONotificationPortCreate(masterPort);
+ }
+}
+
+void usb_os_cleanup (void)
+{
+ if (masterPort != MACH_PORT_NULL)
+ darwin_cleanup ();
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ int pipeRef;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed");
+
+ if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+ USB_ERROR(-EINVAL);
+
+ result = (*(device->interface))->ResetPipe(device->interface, pipeRef);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result));
+
+ return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result = -1;
+
+ int pipeRef;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ /* interface is not open */
+ if (!device->interface)
+ USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed");
+
+ if ((pipeRef = ep_to_pipeRef(device, ep)) == -1)
+ USB_ERROR(-EINVAL);
+
+#if (InterfaceVersion < 190)
+ result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef);
+#else
+ /* newer versions of darwin support clearing additional bits on the device's endpoint */
+ result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef);
+#endif
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result));
+
+ return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+ struct darwin_dev_handle *device;
+
+ io_return_t result;
+
+ if (!dev)
+ USB_ERROR(-ENXIO);
+
+ if ((device = dev->impl_info) == NULL)
+ USB_ERROR(-ENOENT);
+
+ if (!device->device)
+ USB_ERROR_STR(-ENOENT, "usb_reset: no such device");
+
+ result = (*(device->device))->ResetDevice(device->device);
+
+ if (result != kIOReturnSuccess)
+ USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result));
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Parses descriptors
+ *
+ * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "usbi.h"
+
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+ unsigned char type, unsigned char index, void *buf, int size)
+{
+ memset(buf, 0, size);
+
+ return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+ unsigned char index, void *buf, int size)
+{
+ memset(buf, 0, size);
+
+ return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (type << 8) + index, 0, buf, size, 1000);
+}
+
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest)
+{
+ unsigned char *sp = source, *dp = dest;
+ uint16_t w;
+ uint32_t d;
+ char *cp;
+
+ for (cp = description; *cp; cp++) {
+ switch (*cp) {
+ case 'b': /* 8-bit byte */
+ *dp++ = *sp++;
+ break;
+ case 'w': /* 16-bit word, convert from little endian to CPU */
+ w = (sp[1] << 8) | sp[0]; sp += 2;
+ dp += ((unsigned long)dp & 1); /* Align to word boundary */
+ *((uint16_t *)dp) = w; dp += 2;
+ break;
+ case 'd': /* 32-bit dword, convert from little endian to CPU */
+ d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4;
+ dp += ((unsigned long)dp & 2); /* Align to dword boundary */
+ *((uint32_t *)dp) = d; dp += 4;
+ break;
+ /* These two characters are undocumented and just a hack for Linux */
+ case 'W': /* 16-bit word, keep CPU endianess */
+ dp += ((unsigned long)dp & 1); /* Align to word boundary */
+ memcpy(dp, sp, 2); sp += 2; dp += 2;
+ break;
+ case 'D': /* 32-bit dword, keep CPU endianess */
+ dp += ((unsigned long)dp & 2); /* Align to dword boundary */
+ memcpy(dp, sp, 4); sp += 4; dp += 4;
+ break;
+ }
+ }
+
+ return sp - source;
+}
+
+/*
+ * This code looks surprisingly similar to the code I wrote for the Linux
+ * kernel. It's not a coincidence :)
+ */
+
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
+{
+ struct usb_descriptor_header header;
+ unsigned char *begin;
+ int parsed = 0, len, numskipped;
+
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ /* Everything should be fine being passed into here, but we sanity */
+ /* check JIC */
+ if (header.bLength > size) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "ran out of descriptors parsing\n");
+ return -1;
+ }
+
+ if (header.bDescriptorType != USB_DT_ENDPOINT) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n",
+ header.bDescriptorType, USB_DT_ENDPOINT);
+ return parsed;
+ }
+
+ if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH)
+ usb_parse_descriptor(buffer, "bbbbwbbb", endpoint);
+ else if (header.bLength >= ENDPOINT_DESC_LENGTH)
+ usb_parse_descriptor(buffer, "bbbbwb", endpoint);
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ parsed += header.bLength;
+
+ /* Skip over the rest of the Class Specific or Vendor Specific */
+ /* descriptors */
+ begin = buffer;
+ numskipped = 0;
+ while (size >= DESC_HEADER_LENGTH) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if (header.bLength < 2) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+ (header.bDescriptorType == USB_DT_INTERFACE) ||
+ (header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ if (usb_debug >= 1)
+ fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+ numskipped++;
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ parsed += header.bLength;
+ }
+
+ if (numskipped && usb_debug >= 2)
+ fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for drivers */
+ /* to later parse */
+ len = (int)(buffer - begin);
+ if (!len) {
+ endpoint->extra = NULL;
+ endpoint->extralen = 0;
+ return parsed;
+ }
+
+ endpoint->extra = malloc(len);
+ if (!endpoint->extra) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n");
+ endpoint->extralen = 0;
+ return parsed;
+ }
+
+ memcpy(endpoint->extra, begin, len);
+ endpoint->extralen = len;
+
+ return parsed;
+}
+
+static int usb_parse_interface(struct usb_interface *interface,
+ unsigned char *buffer, int size)
+{
+ int i, len, numskipped, retval, parsed = 0;
+ struct usb_descriptor_header header;
+ struct usb_interface_descriptor *ifp;
+ unsigned char *begin;
+
+ interface->num_altsetting = 0;
+
+ while (size >= INTERFACE_DESC_LENGTH) {
+ interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1));
+ if (!interface->altsetting) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't malloc interface->altsetting\n");
+ return -1;
+ }
+
+ ifp = interface->altsetting + interface->num_altsetting;
+ interface->num_altsetting++;
+
+ usb_parse_descriptor(buffer, "bbbbbbbbb", ifp);
+
+ /* Skip over the interface */
+ buffer += ifp->bLength;
+ parsed += ifp->bLength;
+ size -= ifp->bLength;
+
+ begin = buffer;
+ numskipped = 0;
+
+ /* Skip over any interface, class or vendor descriptors */
+ while (size >= DESC_HEADER_LENGTH) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if (header.bLength < 2) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == USB_DT_INTERFACE) ||
+ (header.bDescriptorType == USB_DT_ENDPOINT) ||
+ (header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ numskipped++;
+
+ buffer += header.bLength;
+ parsed += header.bLength;
+ size -= header.bLength;
+ }
+
+ if (numskipped && usb_debug >= 2)
+ fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (!len) {
+ ifp->extra = NULL;
+ ifp->extralen = 0;
+ } else {
+ ifp->extra = malloc(len);
+ if (!ifp->extra) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n");
+ ifp->extralen = 0;
+ return -1;
+ }
+ memcpy(ifp->extra, begin, len);
+ ifp->extralen = len;
+ }
+
+ /* Did we hit an unexpected descriptor? */
+ usb_parse_descriptor(buffer, "bb", &header);
+ if ((size >= DESC_HEADER_LENGTH) &&
+ ((header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE)))
+ return parsed;
+
+ if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "too many endpoints\n");
+ return -1;
+ }
+
+ if (ifp->bNumEndpoints > 0) {
+ ifp->endpoint = (struct usb_endpoint_descriptor *)
+ malloc(ifp->bNumEndpoints *
+ sizeof(struct usb_endpoint_descriptor));
+ if (!ifp->endpoint) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n");
+ return -1;
+ }
+
+ memset(ifp->endpoint, 0, ifp->bNumEndpoints *
+ sizeof(struct usb_endpoint_descriptor));
+
+ for (i = 0; i < ifp->bNumEndpoints; i++) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if (header.bLength > size) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "ran out of descriptors parsing\n");
+ return -1;
+ }
+
+ retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
+ if (retval < 0)
+ return retval;
+
+ buffer += retval;
+ parsed += retval;
+ size -= retval;
+ }
+ } else
+ ifp->endpoint = NULL;
+
+ /* We check to see if it's an alternate to this one */
+ ifp = (struct usb_interface_descriptor *)buffer;
+ if (size < USB_DT_INTERFACE_SIZE ||
+ ifp->bDescriptorType != USB_DT_INTERFACE ||
+ !ifp->bAlternateSetting)
+ return parsed;
+ }
+
+ return parsed;
+}
+
+int usb_parse_configuration(struct usb_config_descriptor *config,
+ unsigned char *buffer)
+{
+ int i, retval, size;
+ struct usb_descriptor_header header;
+
+ usb_parse_descriptor(buffer, "bbwbbbbb", config);
+ size = config->wTotalLength;
+
+ if (config->bNumInterfaces > USB_MAXINTERFACES) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "too many interfaces\n");
+ return -1;
+ }
+
+ config->interface = (struct usb_interface *)
+ malloc(config->bNumInterfaces *
+ sizeof(struct usb_interface));
+ if (!config->interface) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+
+ memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface));
+
+ buffer += config->bLength;
+ size -= config->bLength;
+
+ config->extra = NULL;
+ config->extralen = 0;
+
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ int numskipped, len;
+ unsigned char *begin;
+
+ /* Skip over the rest of the Class Specific or Vendor */
+ /* Specific descriptors */
+ begin = buffer;
+ numskipped = 0;
+ while (size >= DESC_HEADER_LENGTH) {
+ usb_parse_descriptor(buffer, "bb", &header);
+
+ if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "invalid descriptor length of %d\n", header.bLength);
+ return -1;
+ }
+
+ /* If we find another "proper" descriptor then we're done */
+ if ((header.bDescriptorType == USB_DT_ENDPOINT) ||
+ (header.bDescriptorType == USB_DT_INTERFACE) ||
+ (header.bDescriptorType == USB_DT_CONFIG) ||
+ (header.bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType);
+ numskipped++;
+
+ buffer += header.bLength;
+ size -= header.bLength;
+ }
+
+ if (numskipped && usb_debug >= 2)
+ fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (len) {
+ /* FIXME: We should realloc and append here */
+ if (!config->extralen) {
+ config->extra = malloc(len);
+ if (!config->extra) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "couldn't allocate memory for config extra descriptors\n");
+ config->extralen = 0;
+ return -1;
+ }
+
+ memcpy(config->extra, begin, len);
+ config->extralen = len;
+ }
+ }
+
+ retval = usb_parse_interface(config->interface + i, buffer, size);
+ if (retval < 0)
+ return retval;
+
+ buffer += retval;
+ size -= retval;
+ }
+
+ return size;
+}
+
+void usb_destroy_configuration(struct usb_device *dev)
+{
+ int c, i, j, k;
+
+ if (!dev->config)
+ return;
+
+ for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+ struct usb_config_descriptor *cf = &dev->config[c];
+
+ if (!cf->interface)
+ continue;
+
+ for (i = 0; i < cf->bNumInterfaces; i++) {
+ struct usb_interface *ifp = &cf->interface[i];
+
+ if (!ifp->altsetting)
+ continue;
+
+ for (j = 0; j < ifp->num_altsetting; j++) {
+ struct usb_interface_descriptor *as = &ifp->altsetting[j];
+
+ if (as->extra)
+ free(as->extra);
+
+ if (!as->endpoint)
+ continue;
+
+ for (k = 0; k < as->bNumEndpoints; k++) {
+ if (as->endpoint[k].extra)
+ free(as->endpoint[k].extra);
+ }
+ free(as->endpoint);
+ }
+
+ free(ifp->altsetting);
+ }
+
+ free(cf->interface);
+ }
+
+ free(dev->config);
+}
+
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev)
+{
+ struct usb_device *dev = udev->device;
+ int i;
+
+ if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG);
+ return;
+ }
+
+ if (dev->descriptor.bNumConfigurations < 1) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1);
+ return;
+ }
+
+ dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+ if (!dev->config) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Unable to allocate memory for config descriptor\n");
+ return;
+ }
+
+ memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+ sizeof(struct usb_config_descriptor));
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ unsigned char buffer[8], *bigbuffer;
+ struct usb_config_descriptor config;
+ int res;
+
+ /* Get the first 8 bytes so we can figure out what the total length is */
+ res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8);
+ if (res < 8) {
+ if (usb_debug >= 1) {
+ if (res < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res);
+ }
+
+ goto err;
+ }
+
+ usb_parse_descriptor(buffer, "bbw", &config);
+
+ bigbuffer = malloc(config.wTotalLength);
+ if (!bigbuffer) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Unable to allocate memory for descriptors\n");
+ goto err;
+ }
+
+ res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength);
+ if (res < config.wTotalLength) {
+ if (usb_debug >= 1) {
+ if (res < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", res);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res);
+ }
+
+ free(bigbuffer);
+ goto err;
+ }
+
+ res = usb_parse_configuration(&dev->config[i], bigbuffer);
+ if (usb_debug >= 2) {
+ if (res > 0)
+ fprintf(stderr, "Descriptor data still left\n");
+ else if (res < 0)
+ fprintf(stderr, "Unable to parse descriptors\n");
+ }
+
+ free(bigbuffer);
+ }
+
+ return;
+
+err:
+ free(dev->config);
+
+ dev->config = NULL;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * USB Error messages
+ *
+ * Copyright (c) 2000-2001 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "usb.h"
+#include "error.h"
+
+char usb_error_str[1024] = "";
+int usb_error_errno = 0;
+usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE;
+
+char *usb_strerror(void)
+{
+ switch (usb_error_type) {
+ case USB_ERROR_TYPE_NONE:
+ return "No error";
+ case USB_ERROR_TYPE_STRING:
+ return usb_error_str;
+ case USB_ERROR_TYPE_ERRNO:
+ if (usb_error_errno > -USB_ERROR_BEGIN)
+ return strerror(usb_error_errno);
+ else
+ /* Any error we don't know falls under here */
+ return "Unknown error";
+ }
+
+ return "Unknown error";
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ERROR_H_
+#define _ERROR_H_
+
+typedef enum {
+ USB_ERROR_TYPE_NONE = 0,
+ USB_ERROR_TYPE_STRING,
+ USB_ERROR_TYPE_ERRNO,
+} usb_error_type_t;
+
+extern char usb_error_str[1024];
+extern int usb_error_errno;
+extern usb_error_type_t usb_error_type;
+
+#define USB_ERROR(x) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_ERRNO; \
+ usb_error_errno = x; \
+ return x; \
+ } while (0)
+
+#define USB_ERROR_STR(x, format, args...) \
+ do { \
+ usb_error_type = USB_ERROR_TYPE_STRING; \
+ snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \
+ if (usb_debug >= 2) \
+ fprintf(stderr, "USB error: %s\n", usb_error_str); \
+ return x; \
+ } while (0)
+
+#endif /* _ERROR_H_ */
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Linux USB support
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h> /* getenv, etc */
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <dirent.h>
+
+#include "linux.h"
+#include "usbi.h"
+
+static char usb_path[PATH_MAX + 1] = "";
+
+static int device_open(struct usb_device *dev)
+{
+ char filename[PATH_MAX + 1];
+ int fd;
+
+ snprintf(filename, sizeof(filename) - 1, "%s/%s/%s",
+ usb_path, dev->bus->dirname, dev->filename);
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ USB_ERROR_STR(-errno, "failed to open %s: %s",
+ filename, strerror(errno));
+ }
+
+ return fd;
+}
+
+int usb_os_open(usb_dev_handle *dev)
+{
+ dev->fd = device_open(dev->device);
+
+ return 0;
+}
+
+int usb_os_close(usb_dev_handle *dev)
+{
+ if (dev->fd < 0)
+ return 0;
+
+ if (close(dev->fd) == -1)
+ /* Failing trying to close a file really isn't an error, so return 0 */
+ USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_set_configuration(usb_dev_handle *dev, int configuration)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not set config %d: %s", configuration,
+ strerror(errno));
+
+ dev->config = configuration;
+
+ return 0;
+}
+
+int usb_claim_interface(usb_dev_handle *dev, int interface)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface);
+ if (ret < 0) {
+ if (errno == EBUSY && usb_debug > 0)
+ fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename);
+
+ USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface,
+ strerror(errno));
+ }
+
+ dev->interface = interface;
+
+ return 0;
+}
+
+int usb_release_interface(usb_dev_handle *dev, int interface)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not release intf %d: %s", interface,
+ strerror(errno));
+
+ dev->interface = -1;
+
+ return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle *dev, int alternate)
+{
+ int ret;
+ struct usb_setinterface setintf;
+
+ if (dev->interface < 0)
+ USB_ERROR(-EINVAL);
+
+ setintf.interface = dev->interface;
+ setintf.altsetting = alternate;
+
+ ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s",
+ dev->interface, alternate, strerror(errno));
+
+ dev->altsetting = alternate;
+
+ return 0;
+}
+
+/*
+ * Linux usbfs has a limit of one page size for synchronous bulk read/write.
+ * 4096 is the most portable maximum we can do for now.
+ * Linux usbfs has a limit of 16KB for the URB interface. We use this now
+ * to get better performance for USB 2.0 devices.
+ */
+#define MAX_READ_WRITE (16 * 1024)
+
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout)
+{
+ struct usb_ctrltransfer ctrl;
+ int ret;
+
+ ctrl.bRequestType = requesttype;
+ ctrl.bRequest = request;
+ ctrl.wValue = value;
+ ctrl.wIndex = index;
+ ctrl.wLength = size;
+
+ ctrl.data = bytes;
+ ctrl.timeout = timeout;
+
+ ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl);
+ if (ret < 0)
+ USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno));
+
+ return ret;
+}
+
+#define URB_USERCONTEXT_COOKIE ((void *)0x1)
+
+/* Reading and writing are the same except for the endpoint */
+static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype,
+ char *bytes, int size, int timeout)
+{
+ struct usb_urb urb;
+ int bytesdone = 0, requested;
+ struct timeval tv, tv_ref, tv_now;
+ struct usb_urb *context;
+ int ret, waiting;
+
+ /*
+ * HACK: The use of urb.usercontext is a hack to get threaded applications
+ * sort of working again. Threaded support is still not recommended, but
+ * this should allow applications to work in the common cases. Basically,
+ * if we get the completion for an URB we're not waiting for, then we update
+ * the usercontext pointer to 1 for the other threads URB and it will see
+ * the change after it wakes up from the the timeout. Ugly, but it works.
+ */
+
+ /*
+ * Get actual time, and add the timeout value. The result is the absolute
+ * time where we have to quit waiting for an message.
+ */
+ gettimeofday(&tv_ref, NULL);
+ tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000;
+ tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000;
+
+ if (tv_ref.tv_usec > 1000000) {
+ tv_ref.tv_usec -= 1000000;
+ tv_ref.tv_sec++;
+ }
+
+ do {
+ fd_set writefds;
+
+ requested = size - bytesdone;
+ if (requested > MAX_READ_WRITE)
+ requested = MAX_READ_WRITE;
+
+ urb.type = urbtype;
+ urb.endpoint = ep;
+ urb.flags = 0;
+ urb.buffer = bytes + bytesdone;
+ urb.buffer_length = requested;
+ urb.signr = 0;
+ urb.actual_length = 0;
+ urb.number_of_packets = 0; /* don't do isochronous yet */
+ urb.usercontext = NULL;
+
+ ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb);
+ if (ret < 0) {
+ USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno));
+ return ret;
+ }
+
+ FD_ZERO(&writefds);
+ FD_SET(dev->fd, &writefds);
+
+restart:
+ waiting = 1;
+ context = NULL;
+ while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000; // 1 msec
+ select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
+
+ if (timeout) {
+ /* compare with actual time, as the select timeout is not that precise */
+ gettimeofday(&tv_now, NULL);
+
+ if ((tv_now.tv_sec > tv_ref.tv_sec) ||
+ ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
+ waiting = 0;
+ }
+ }
+
+ if (context && context != &urb) {
+ context->usercontext = URB_USERCONTEXT_COOKIE;
+ /* We need to restart since we got a successful URB, but not ours */
+ goto restart;
+ }
+
+ /*
+ * If there was an error, that wasn't EAGAIN (no completion), then
+ * something happened during the reaping and we should return that
+ * error now
+ */
+ if (ret < 0 && !urb.usercontext && errno != EAGAIN)
+ USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno));
+
+ bytesdone += urb.actual_length;
+ } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
+
+ /* If the URB didn't complete in success or error, then let's unlink it */
+ if (ret < 0 && !urb.usercontext) {
+ int rc;
+
+ if (!waiting)
+ rc = -ETIMEDOUT;
+ else
+ rc = urb.status;
+
+ ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb);
+ if (ret < 0 && errno != EINVAL && usb_debug >= 1)
+ fprintf(stderr, "error discarding URB: %s", strerror(errno));
+
+ /*
+ * When the URB is unlinked, it gets moved to the completed list and
+ * then we need to reap it or else the next time we call this function,
+ * we'll get the previous completion and exit early
+ */
+ ioctl(dev->fd, IOCTL_USB_REAPURB, &context);
+
+ return rc;
+ }
+
+ return bytesdone;
+}
+
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
+ timeout);
+}
+
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ ep |= USB_ENDPOINT_IN;
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size,
+ timeout);
+}
+
+/*
+ * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked
+ * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need
+ * to lookup the endpoint packet size and packetize appropriately here.
+ */
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
+ timeout);
+}
+
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout)
+{
+ /* Ensure the endpoint address is correct */
+ ep |= USB_ENDPOINT_IN;
+ return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size,
+ timeout);
+}
+
+int usb_os_find_busses(struct usb_bus **busses)
+{
+ struct usb_bus *fbus = NULL;
+ DIR *dir;
+ struct dirent *entry;
+
+ dir = opendir(usb_path);
+ if (!dir)
+ USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path,
+ strerror(errno));
+
+ while ((entry = readdir(dir)) != NULL) {
+ struct usb_bus *bus;
+
+ /* Skip anything starting with a . */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n",
+ entry->d_name);
+ continue;
+ }
+
+ bus = malloc(sizeof(*bus));
+ if (!bus)
+ USB_ERROR(-ENOMEM);
+
+ memset((void *)bus, 0, sizeof(*bus));
+
+ strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1);
+ bus->dirname[sizeof(bus->dirname) - 1] = 0;
+
+ LIST_ADD(fbus, bus);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname);
+ }
+
+ closedir(dir);
+
+ *busses = fbus;
+
+ return 0;
+}
+
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
+{
+ struct usb_device *fdev = NULL;
+ DIR *dir;
+ struct dirent *entry;
+ char dirpath[PATH_MAX + 1];
+
+ snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname);
+
+ dir = opendir(dirpath);
+ if (!dir)
+ USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath,
+ strerror(errno));
+
+ while ((entry = readdir(dir)) != NULL) {
+ unsigned char device_desc[DEVICE_DESC_LENGTH];
+ char filename[PATH_MAX + 1];
+ struct usb_device *dev;
+ struct usb_connectinfo connectinfo;
+ int i, fd, ret;
+
+ /* Skip anything starting with a . */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ dev = malloc(sizeof(*dev));
+ if (!dev)
+ USB_ERROR(-ENOMEM);
+
+ memset((void *)dev, 0, sizeof(*dev));
+
+ dev->bus = bus;
+
+ strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1);
+ dev->filename[sizeof(dev->filename) - 1] = 0;
+
+ snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name);
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n",
+ filename);
+
+ free(dev);
+ continue;
+ }
+ }
+
+ /* Get the device number */
+ ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo);
+ if (ret < 0) {
+ if (usb_debug)
+ fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n");
+ } else
+ dev->devnum = connectinfo.devnum;
+
+ ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH);
+ if (ret < 0) {
+ if (usb_debug)
+ fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n");
+
+ free(dev);
+
+ goto err;
+ }
+
+ /*
+ * Linux kernel converts the words in this descriptor to CPU endian, so
+ * we use the undocumented W character for usb_parse_descriptor() that
+ * doesn't convert endianess when parsing the descriptor
+ */
+ usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor);
+
+ LIST_ADD(fdev, dev);
+
+ if (usb_debug >= 2)
+ fprintf(stderr, "usb_os_find_devices: Found %s on %s\n",
+ dev->filename, bus->dirname);
+
+ /* Now try to fetch the rest of the descriptors */
+ if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
+ /* Silent since we'll try again later */
+ goto err;
+
+ if (dev->descriptor.bNumConfigurations < 1)
+ /* Silent since we'll try again later */
+ goto err;
+
+ dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor));
+ if (!dev->config)
+ /* Silent since we'll try again later */
+ goto err;
+
+ memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+ sizeof(struct usb_config_descriptor));
+
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ unsigned char buffer[8], *bigbuffer;
+ struct usb_config_descriptor config;
+
+ /* Get the first 8 bytes so we can figure out what the total length is */
+ ret = read(fd, (void *)buffer, 8);
+ if (ret < 8) {
+ if (usb_debug >= 1) {
+ if (ret < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret);
+ }
+
+ goto err;
+ }
+
+ usb_parse_descriptor(buffer, "bbw", &config);
+
+ bigbuffer = malloc(config.wTotalLength);
+ if (!bigbuffer) {
+ if (usb_debug >= 1)
+ fprintf(stderr, "Unable to allocate memory for descriptors\n");
+ goto err;
+ }
+
+ /* Read the rest of the config descriptor */
+ memcpy(bigbuffer, buffer, 8);
+
+ ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8);
+ if (ret < config.wTotalLength - 8) {
+ if (usb_debug >= 1) {
+ if (ret < 0)
+ fprintf(stderr, "Unable to get descriptor (%d)\n", ret);
+ else
+ fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret);
+ }
+
+ free(bigbuffer);
+ goto err;
+ }
+
+ ret = usb_parse_configuration(&dev->config[i], bigbuffer);
+ if (usb_debug >= 2) {
+ if (ret > 0)
+ fprintf(stderr, "Descriptor data still left\n");
+ else if (ret < 0)
+ fprintf(stderr, "Unable to parse descriptors\n");
+ }
+
+ free(bigbuffer);
+ }
+
+err:
+ close(fd);
+ }
+
+ closedir(dir);
+
+ *devices = fdev;
+
+ return 0;
+}
+
+int usb_os_determine_children(struct usb_bus *bus)
+{
+ struct usb_device *dev, *devices[256];
+ struct usb_ioctl command;
+ int ret, i, i1;
+
+ /* Create a list of devices first */
+ memset(devices, 0, sizeof(devices));
+ for (dev = bus->devices; dev; dev = dev->next)
+ if (dev->devnum)
+ devices[dev->devnum] = dev;
+
+ /* Now fetch the children for each device */
+ for (dev = bus->devices; dev; dev = dev->next) {
+ struct usb_hub_portinfo portinfo;
+ int fd;
+
+ fd = device_open(dev);
+ if (fd < 0)
+ continue;
+
+ /* Query the hub driver for the children of this device */
+ if (dev->config && dev->config->interface && dev->config->interface->altsetting)
+ command.ifno = dev->config->interface->altsetting->bInterfaceNumber;
+ else
+ command.ifno = 0;
+ command.ioctl_code = IOCTL_USB_HUB_PORTINFO;
+ command.data = &portinfo;
+ ret = ioctl(fd, IOCTL_USB_IOCTL, &command);
+ if (ret < 0) {
+ /* errno == ENOSYS means the device probably wasn't a hub */
+ if (errno != ENOSYS && usb_debug > 1)
+ fprintf(stderr, "error obtaining child information: %s\n",
+ strerror(errno));
+
+ close(fd);
+ continue;
+ }
+
+ dev->num_children = 0;
+ for (i = 0; i < portinfo.numports; i++)
+ if (portinfo.port[i])
+ dev->num_children++;
+
+ /* Free any old children first */
+ free(dev->children);
+
+ dev->children = malloc(sizeof(struct usb_device *) * dev->num_children);
+ if (!dev->children) {
+ if (usb_debug > 1)
+ fprintf(stderr, "error allocating %zu bytes memory for dev->children\n",
+ sizeof(struct usb_device *) * dev->num_children);
+
+ dev->num_children = 0;
+ close(fd);
+ continue;
+ }
+
+ for (i = 0, i1 = 0; i < portinfo.numports; i++) {
+ if (!portinfo.port[i])
+ continue;
+
+ dev->children[i1++] = devices[portinfo.port[i]];
+
+ devices[portinfo.port[i]] = NULL;
+ }
+
+ close(fd);
+ }
+
+ /*
+ * There should be one device left in the devices list and that should be
+ * the root device
+ */
+ for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+ if (devices[i])
+ bus->root_dev = devices[i];
+ }
+
+ return 0;
+}
+
+static int check_usb_vfs(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int found = 0;
+
+ dir = opendir(dirname);
+ if (!dir)
+ return 0;
+
+ while ((entry = readdir(dir)) != NULL) {
+ /* Skip anything starting with a . */
+ if (entry->d_name[0] == '.')
+ continue;
+
+ /* We assume if we find any files that it must be the right place */
+ found = 1;
+ break;
+ }
+
+ closedir(dir);
+
+ return found;
+}
+
+void usb_os_init(void)
+{
+ /* Find the path to the virtual filesystem */
+ if (getenv("USB_DEVFS_PATH")) {
+ if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) {
+ strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1);
+ usb_path[sizeof(usb_path) - 1] = 0;
+ } else if (usb_debug)
+ fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n");
+ }
+
+ if (!usb_path[0]) {
+ if (check_usb_vfs("/dev/bus/usb")) {
+ strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1);
+ usb_path[sizeof(usb_path) - 1] = 0;
+ } else if (check_usb_vfs("/proc/bus/usb")) {
+ strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1);
+ usb_path[sizeof(usb_path) - 1] = 0;
+ } else
+ usb_path[0] = 0; /* No path, no USB support */
+ }
+
+ if (usb_debug) {
+ if (usb_path[0])
+ fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path);
+ else
+ fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n");
+ }
+}
+
+int usb_resetep(usb_dev_handle *dev, unsigned int ep)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep,
+ strerror(errno));
+
+ return 0;
+}
+
+int usb_reset(usb_dev_handle *dev)
+{
+ int ret;
+
+ ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno));
+
+ return 0;
+}
+
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+ unsigned int namelen)
+{
+ struct usb_getdriver getdrv;
+ int ret;
+
+ getdrv.interface = interface;
+ ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno));
+
+ strncpy(name, getdrv.driver, namelen - 1);
+ name[namelen - 1] = 0;
+
+ return 0;
+}
+
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
+{
+ struct usb_ioctl command;
+ int ret;
+
+ command.ifno = interface;
+ command.ioctl_code = IOCTL_USB_DISCONNECT;
+ command.data = NULL;
+
+ ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command);
+ if (ret)
+ USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s",
+ interface, strerror(errno));
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __LINUX_H__
+#define __LINUX_H__
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+struct usb_ctrltransfer {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
+ u_int8_t bRequestType;
+ u_int8_t bRequest;
+ u_int16_t wValue;
+ u_int16_t wIndex;
+ u_int16_t wLength;
+
+ u_int32_t timeout; /* in milliseconds */
+
+ /* pointer to data */
+ void *data;
+};
+
+struct usb_bulktransfer {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */
+ unsigned int ep;
+ unsigned int len;
+ unsigned int timeout; /* in milliseconds */
+
+ /* pointer to data */
+ void *data;
+};
+
+struct usb_setinterface {
+ /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */
+ unsigned int interface;
+ unsigned int altsetting;
+};
+
+#define USB_MAXDRIVERNAME 255
+
+struct usb_getdriver {
+ unsigned int interface;
+ char driver[USB_MAXDRIVERNAME + 1];
+};
+
+#define USB_URB_DISABLE_SPD 1
+#define USB_URB_ISO_ASAP 2
+#define USB_URB_QUEUE_BULK 0x10
+
+#define USB_URB_TYPE_ISO 0
+#define USB_URB_TYPE_INTERRUPT 1
+#define USB_URB_TYPE_CONTROL 2
+#define USB_URB_TYPE_BULK 3
+
+struct usb_iso_packet_desc {
+ unsigned int length;
+ unsigned int actual_length;
+ unsigned int status;
+};
+
+struct usb_urb {
+ unsigned char type;
+ unsigned char endpoint;
+ int status;
+ unsigned int flags;
+ void *buffer;
+ int buffer_length;
+ int actual_length;
+ int start_frame;
+ int number_of_packets;
+ int error_count;
+ unsigned int signr; /* signal to be sent on error, -1 if none should be sent */
+ void *usercontext;
+ struct usb_iso_packet_desc iso_frame_desc[0];
+};
+
+struct usb_connectinfo {
+ unsigned int devnum;
+ unsigned char slow;
+};
+
+struct usb_ioctl {
+ int ifno; /* interface 0..N ; negative numbers reserved */
+ int ioctl_code; /* MUST encode size + direction of data so the
+ * macros in <asm/ioctl.h> give correct values */
+ void *data; /* param buffer (in, or out) */
+};
+
+struct usb_hub_portinfo {
+ unsigned char numports;
+ unsigned char port[127]; /* port to device num mapping */
+};
+
+#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer)
+#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer)
+#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int)
+#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface)
+#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int)
+#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver)
+#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb)
+#define IOCTL_USB_DISCARDURB _IO('U', 11)
+#define IOCTL_USB_REAPURB _IOW('U', 12, void *)
+#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *)
+#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int)
+#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int)
+#define IOCTL_USB_CONNECTINFO _IOW('U', 17, struct usb_connectinfo)
+#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl)
+#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct usb_hub_portinfo)
+#define IOCTL_USB_RESET _IO('U', 20)
+#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int)
+#define IOCTL_USB_DISCONNECT _IO('U', 22)
+#define IOCTL_USB_CONNECT _IO('U', 23)
+
+/*
+ * IOCTL_USB_HUB_PORTINFO, IOCTL_USB_DISCONNECT and IOCTL_USB_CONNECT
+ * all work via IOCTL_USB_IOCTL
+ */
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Main API entry point
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ */
+
+#include <stdlib.h> /* getenv */
+#include <stdio.h> /* stderr */
+#include <string.h> /* strcmp */
+#include <errno.h>
+
+#include "usbi.h"
+
+int usb_debug = 0;
+struct usb_bus *usb_busses = NULL;
+
+int usb_find_busses(void)
+{
+ struct usb_bus *busses, *bus;
+ int ret, changes = 0;
+
+ ret = usb_os_find_busses(&busses);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now walk through all of the busses we know about and compare against
+ * this new list. Any duplicates will be removed from the new list.
+ * If we don't find it in the new list, the bus was removed. Any
+ * busses still in the new list, are new to us.
+ */
+ bus = usb_busses;
+ while (bus) {
+ int found = 0;
+ struct usb_bus *nbus, *tbus = bus->next;
+
+ nbus = busses;
+ while (nbus) {
+ struct usb_bus *tnbus = nbus->next;
+
+ if (!strcmp(bus->dirname, nbus->dirname)) {
+ /* Remove it from the new busses list */
+ LIST_DEL(busses, nbus);
+
+ usb_free_bus(nbus);
+ found = 1;
+ break;
+ }
+
+ nbus = tnbus;
+ }
+
+ if (!found) {
+ /* The bus was removed from the system */
+ LIST_DEL(usb_busses, bus);
+ usb_free_bus(bus);
+ changes++;
+ }
+
+ bus = tbus;
+ }
+
+ /*
+ * Anything on the *busses list is new. So add them to usb_busses and
+ * process them like the new bus it is.
+ */
+ bus = busses;
+ while (bus) {
+ struct usb_bus *tbus = bus->next;
+
+ /*
+ * Remove it from the temporary list first and add it to the real
+ * usb_busses list.
+ */
+ LIST_DEL(busses, bus);
+
+ LIST_ADD(usb_busses, bus);
+
+ changes++;
+
+ bus = tbus;
+ }
+
+ return changes;
+}
+
+int usb_find_devices(void)
+{
+ struct usb_bus *bus;
+ int ret, changes = 0;
+
+ for (bus = usb_busses; bus; bus = bus->next) {
+ struct usb_device *devices, *dev;
+
+ /* Find all of the devices and put them into a temporary list */
+ ret = usb_os_find_devices(bus, &devices);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Now walk through all of the devices we know about and compare
+ * against this new list. Any duplicates will be removed from the new
+ * list. If we don't find it in the new list, the device was removed.
+ * Any devices still in the new list, are new to us.
+ */
+ dev = bus->devices;
+ while (dev) {
+ int found = 0;
+ struct usb_device *ndev, *tdev = dev->next;
+
+ ndev = devices;
+ while (ndev) {
+ struct usb_device *tndev = ndev->next;
+
+ if (!strcmp(dev->filename, ndev->filename)) {
+ /* Remove it from the new devices list */
+ LIST_DEL(devices, ndev);
+
+ usb_free_dev(ndev);
+ found = 1;
+ break;
+ }
+
+ ndev = tndev;
+ }
+
+ if (!found) {
+ /* The device was removed from the system */
+ LIST_DEL(bus->devices, dev);
+ usb_free_dev(dev);
+ changes++;
+ }
+
+ dev = tdev;
+ }
+
+ /*
+ * Anything on the *devices list is new. So add them to bus->devices and
+ * process them like the new device it is.
+ */
+ dev = devices;
+ while (dev) {
+ struct usb_device *tdev = dev->next;
+
+ /*
+ * Remove it from the temporary list first and add it to the real
+ * bus->devices list.
+ */
+ LIST_DEL(devices, dev);
+
+ LIST_ADD(bus->devices, dev);
+
+ /*
+ * Some ports fetch the descriptors on scanning (like Linux) so we don't
+ * need to fetch them again.
+ */
+ if (!dev->config) {
+ usb_dev_handle *udev;
+
+ udev = usb_open(dev);
+ if (udev) {
+ usb_fetch_and_parse_descriptors(udev);
+
+ usb_close(udev);
+ }
+ }
+
+ changes++;
+
+ dev = tdev;
+ }
+
+ usb_os_determine_children(bus);
+ }
+
+ return changes;
+}
+
+void usb_set_debug(int level)
+{
+ if (usb_debug || level)
+ fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
+ level, level ? "on" : "off");
+
+ usb_debug = level;
+}
+
+void usb_init(void)
+{
+ if (getenv("USB_DEBUG"))
+ usb_set_debug(atoi(getenv("USB_DEBUG")));
+
+ usb_os_init();
+}
+
+usb_dev_handle *usb_open(struct usb_device *dev)
+{
+ usb_dev_handle *udev;
+
+ udev = malloc(sizeof(*udev));
+ if (!udev)
+ return NULL;
+
+ udev->fd = -1;
+ udev->device = dev;
+ udev->bus = dev->bus;
+ udev->config = udev->interface = udev->altsetting = -1;
+
+ if (usb_os_open(udev) < 0) {
+ free(udev);
+ return NULL;
+ }
+
+ return udev;
+}
+
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+ size_t buflen)
+{
+ /*
+ * We can't use usb_get_descriptor() because it's lacking the index
+ * parameter. This will be fixed in libusb 1.0
+ */
+ return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
+}
+
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
+{
+ char tbuf[255]; /* Some devices choke on size > 255 */
+ int ret, langid, si, di;
+
+ /*
+ * Asking for the zero'th index is special - it returns a string
+ * descriptor that contains all the language IDs supported by the
+ * device. Typically there aren't many - often only one. The
+ * language IDs are 16 bit numbers, and they start at the third byte
+ * in the descriptor. See USB 2.0 specification, section 9.6.7, for
+ * more information on this. */
+ ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
+ if (ret < 0)
+ return ret;
+
+ if (ret < 4)
+ return -EIO;
+
+ langid = tbuf[2] | (tbuf[3] << 8);
+
+ ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
+ if (ret < 0)
+ return ret;
+
+ if (tbuf[1] != USB_DT_STRING)
+ return -EIO;
+
+ if (tbuf[0] > ret)
+ return -EFBIG;
+
+ for (di = 0, si = 2; si < tbuf[0]; si += 2) {
+ if (di >= (buflen - 1))
+ break;
+
+ if (tbuf[si + 1]) /* high byte */
+ buf[di++] = '?';
+ else
+ buf[di++] = tbuf[si];
+ }
+
+ buf[di] = 0;
+
+ return di;
+}
+
+int usb_close(usb_dev_handle *dev)
+{
+ int ret;
+
+ ret = usb_os_close(dev);
+ free(dev);
+
+ return ret;
+}
+
+struct usb_device *usb_device(usb_dev_handle *dev)
+{
+ return dev->device;
+}
+
+void usb_free_dev(struct usb_device *dev)
+{
+ usb_destroy_configuration(dev);
+ free(dev->children);
+ free(dev);
+}
+
+struct usb_bus *usb_get_busses(void)
+{
+ return usb_busses;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+ free(bus);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Prototypes, structure definitions and macros.
+ *
+ * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * This library is covered by the LGPL, read LICENSE for details.
+ *
+ * This file (and only this file) may alternatively be licensed under the
+ * BSD license as well, read LICENSE for details.
+ */
+#ifndef __USB_H__
+#define __USB_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <dirent.h>
+
+/*
+ * USB spec information
+ *
+ * This is all stuff grabbed from various USB specs and is pretty much
+ * not subject to change
+ */
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_PTP 6
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_DATA 10
+#define USB_CLASS_VENDOR_SPEC 0xff
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+
+#define USB_DT_HID 0x21
+#define USB_DT_REPORT 0x22
+#define USB_DT_PHYSICAL 0x23
+#define USB_DT_HUB 0x29
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE 18
+#define USB_DT_CONFIG_SIZE 9
+#define USB_DT_INTERFACE_SIZE 9
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE 7
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+};
+
+/* String descriptor */
+struct usb_string_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short wData[1];
+};
+
+/* HID descriptor */
+struct usb_hid_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short bcdHID;
+ unsigned char bCountryCode;
+ unsigned char bNumDescriptors;
+ /* unsigned char bReportDescriptorType; */
+ /* unsigned short wDescriptorLength; */
+ /* ... */
+};
+
+/* Endpoint descriptor */
+#define USB_MAXENDPOINTS 32
+struct usb_endpoint_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned char bEndpointAddress;
+ unsigned char bmAttributes;
+ unsigned short wMaxPacketSize;
+ unsigned char bInterval;
+ unsigned char bRefresh;
+ unsigned char bSynchAddress;
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;
+};
+
+#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_TYPE_CONTROL 0
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
+#define USB_ENDPOINT_TYPE_BULK 2
+#define USB_ENDPOINT_TYPE_INTERRUPT 3
+
+/* Interface descriptor */
+#define USB_MAXINTERFACES 32
+struct usb_interface_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned char bInterfaceNumber;
+ unsigned char bAlternateSetting;
+ unsigned char bNumEndpoints;
+ unsigned char bInterfaceClass;
+ unsigned char bInterfaceSubClass;
+ unsigned char bInterfaceProtocol;
+ unsigned char iInterface;
+
+ struct usb_endpoint_descriptor *endpoint;
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;
+};
+
+#define USB_MAXALTSETTING 128 /* Hard limit */
+struct usb_interface {
+ struct usb_interface_descriptor *altsetting;
+
+ int num_altsetting;
+};
+
+/* Configuration descriptor information.. */
+#define USB_MAXCONFIG 8
+struct usb_config_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short wTotalLength;
+ unsigned char bNumInterfaces;
+ unsigned char bConfigurationValue;
+ unsigned char iConfiguration;
+ unsigned char bmAttributes;
+ unsigned char MaxPower;
+
+ struct usb_interface *interface;
+
+ unsigned char *extra; /* Extra descriptors */
+ int extralen;
+};
+
+/* Device descriptor */
+struct usb_device_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short bcdUSB;
+ unsigned char bDeviceClass;
+ unsigned char bDeviceSubClass;
+ unsigned char bDeviceProtocol;
+ unsigned char bMaxPacketSize0;
+ unsigned short idVendor;
+ unsigned short idProduct;
+ unsigned short bcdDevice;
+ unsigned char iManufacturer;
+ unsigned char iProduct;
+ unsigned char iSerialNumber;
+ unsigned char bNumConfigurations;
+};
+
+struct usb_ctrl_setup {
+ unsigned char bRequestType;
+ unsigned char bRequest;
+ unsigned short wValue;
+ unsigned short wIndex;
+ unsigned short wLength;
+};
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+/* 0x02 is reserved */
+#define USB_REQ_SET_FEATURE 0x03
+/* 0x04 is reserved */
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * Various libusb API related stuff
+ */
+
+#define USB_ENDPOINT_IN 0x80
+#define USB_ENDPOINT_OUT 0x00
+
+/* Error codes */
+#define USB_ERROR_BEGIN 500000
+
+/*
+ * This is supposed to look weird. This file is generated from autoconf
+ * and I didn't want to make this too complicated.
+ */
+#if _BIGENDIAN
+#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0)
+#else
+#define USB_LE16_TO_CPU(x)
+#endif
+
+/* Data types */
+struct usb_device;
+struct usb_bus;
+
+/*
+ * To maintain compatibility with applications already built with libusb,
+ * we must only add entries to the end of this structure. NEVER delete or
+ * move members and only change types if you really know what you're doing.
+ */
+struct usb_device {
+ struct usb_device *next, *prev;
+
+ char filename[PATH_MAX + 1];
+
+ struct usb_bus *bus;
+
+ struct usb_device_descriptor descriptor;
+ struct usb_config_descriptor *config;
+
+ void *dev; /* Darwin support */
+
+ unsigned char devnum;
+
+ unsigned char num_children;
+ struct usb_device **children;
+};
+
+struct usb_bus {
+ struct usb_bus *next, *prev;
+
+ char dirname[PATH_MAX + 1];
+
+ struct usb_device *devices;
+ unsigned long location;
+
+ struct usb_device *root_dev;
+};
+
+struct usb_dev_handle;
+typedef struct usb_dev_handle usb_dev_handle;
+
+/* Variables */
+extern struct usb_bus *usb_busses;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function prototypes */
+
+/* usb.c */
+usb_dev_handle *usb_open(struct usb_device *dev);
+int usb_close(usb_dev_handle *dev);
+int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
+ size_t buflen);
+int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf,
+ size_t buflen);
+
+/* descriptors.c */
+int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
+ unsigned char type, unsigned char index, void *buf, int size);
+int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
+ unsigned char index, void *buf, int size);
+
+/* <arch>.c */
+int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
+ int timeout);
+int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
+ int value, int index, char *bytes, int size, int timeout);
+int usb_set_configuration(usb_dev_handle *dev, int configuration);
+int usb_claim_interface(usb_dev_handle *dev, int interface);
+int usb_release_interface(usb_dev_handle *dev, int interface);
+int usb_set_altinterface(usb_dev_handle *dev, int alternate);
+int usb_resetep(usb_dev_handle *dev, unsigned int ep);
+int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
+int usb_reset(usb_dev_handle *dev);
+
+#if LINUX_API
+#define LIBUSB_HAS_GET_DRIVER_NP 1
+int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name,
+ unsigned int namelen);
+#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1
+int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
+#endif
+
+char *usb_strerror(void);
+
+void usb_init(void);
+void usb_set_debug(int level);
+int usb_find_busses(void);
+int usb_find_devices(void);
+struct usb_device *usb_device(usb_dev_handle *dev);
+struct usb_bus *usb_get_busses(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USB_H__ */
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _USBI_H_
+#define _USBI_H_
+
+#include "usb.h"
+
+#include "error.h"
+
+extern int usb_debug;
+
+/* Some quick and generic macros for the simple kind of lists we use */
+#define LIST_ADD(begin, ent) \
+ do { \
+ if (begin) { \
+ ent->next = begin; \
+ ent->next->prev = ent; \
+ } else \
+ ent->next = NULL; \
+ ent->prev = NULL; \
+ begin = ent; \
+ } while(0)
+
+#define LIST_DEL(begin, ent) \
+ do { \
+ if (ent->prev) \
+ ent->prev->next = ent->next; \
+ else \
+ begin = ent->next; \
+ if (ent->next) \
+ ent->next->prev = ent->prev; \
+ ent->prev = NULL; \
+ ent->next = NULL; \
+ } while (0)
+
+#define DESC_HEADER_LENGTH 2
+#define DEVICE_DESC_LENGTH 18
+#define CONFIG_DESC_LENGTH 9
+#define INTERFACE_DESC_LENGTH 9
+#define ENDPOINT_DESC_LENGTH 7
+#define ENDPOINT_AUDIO_DESC_LENGTH 9
+
+struct usb_dev_handle {
+ int fd;
+
+ struct usb_bus *bus;
+ struct usb_device *device;
+
+ int config;
+ int interface;
+ int altsetting;
+
+ /* Added by RMT so implementations can store other per-open-device data */
+ void *impl_info;
+};
+
+/* descriptors.c */
+int usb_parse_descriptor(unsigned char *source, char *description, void *dest);
+int usb_parse_configuration(struct usb_config_descriptor *config,
+ unsigned char *buffer);
+void usb_fetch_and_parse_descriptors(usb_dev_handle *udev);
+void usb_destroy_configuration(struct usb_device *dev);
+
+/* OS specific routines */
+int usb_os_find_busses(struct usb_bus **busses);
+int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices);
+int usb_os_determine_children(struct usb_bus *bus);
+void usb_os_init(void);
+int usb_os_open(usb_dev_handle *dev);
+int usb_os_close(usb_dev_handle *dev);
+
+void usb_free_dev(struct usb_device *dev);
+void usb_free_bus(struct usb_bus *bus);
+
+#endif /* _USBI_H_ */
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <windows.h>
+#include <setupapi.h>
+#include <winerror.h>
+#include "winusb.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include "fdevent.h"
+#include "utils.h"
+#include "strutils.h"
+#include "linkedlist.h"
+
+#define TRACE_TAG TRACE_USB
+#include "sdb.h"
+#include "sdb_usb.h"
+
+struct usb_handle {
+ LIST_NODE* node;
+
+ HANDLE hnd;
+ WINUSB_INTERFACE_HANDLE fd;
+ char unique_node_path[PATH_MAX+1]; //MAX_DEVICE_ID_LEN <device-ID>\<instance-specific-ID>
+ UCHAR end_point[2];
+ unsigned int zero_mask;
+};
+usb_handle *usb_open(const char *device_path);
+int win_usb_close(usb_handle *dev);
+int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen);
+void *device_poll_thread(void* unused);
+int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout);
+void do_lsusb(void);
+
+// Class ID assigned to the device by aNdrOiduSb.sys
+static const GUID TIZEN_CLASSID = {0x9ca29f37, 0xdd62, 0x4aad, {0x82, 0x65, 0xcf, 0xf7, 0x88, 0xc8, 0xba, 0x89}};
+
+static LIST_NODE* handle_list = NULL;
+
+SDB_MUTEX_DEFINE( usb_lock );
+
+
+// winusb.dll entrypoints
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetOverlappedResult, (WINUSB_INTERFACE_HANDLE, LPOVERLAPPED, LPDWORD, BOOL));
+
+void win_usb_init(void) {
+ // Initialize DLL functions
+ if (!WinUsb_Initialize) {
+ DLL_LOAD(winusb.dll, WinUsb_Initialize);
+ DLL_LOAD(winusb.dll, WinUsb_Free);
+ DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface);
+ DLL_LOAD(winusb.dll, WinUsb_GetDescriptor);
+ DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings);
+ DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation);
+ DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting);
+ DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting);
+ DLL_LOAD(winusb.dll, WinUsb_QueryPipe);
+ DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy);
+ DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy);
+ DLL_LOAD(winusb.dll, WinUsb_ReadPipe);
+ DLL_LOAD(winusb.dll, WinUsb_WritePipe);
+ DLL_LOAD(winusb.dll, WinUsb_ControlTransfer);
+ DLL_LOAD(winusb.dll, WinUsb_ResetPipe);
+ DLL_LOAD(winusb.dll, WinUsb_AbortPipe);
+ DLL_LOAD(winusb.dll, WinUsb_FlushPipe);
+ DLL_LOAD(winusb.dll, WinUsb_GetOverlappedResult);
+ }
+}
+
+int is_device_registered(const char *node_path)
+{
+ int r = 0;
+ sdb_mutex_lock(&usb_lock, "usb is_device_registered");
+
+ LIST_NODE* cur_ptr = handle_list;
+ while(cur_ptr != NULL) {
+ usb_handle* usb = cur_ptr->data;
+ cur_ptr = cur_ptr->next_ptr;
+
+ if(!strcmp(usb->unique_node_path, node_path)) {
+ r = 1;
+ break;
+ }
+ }
+ sdb_mutex_unlock(&usb_lock, "usb is_device_registered");
+ return r;
+}
+
+usb_handle *usb_open(const char *device_path) {
+ // Allocate storage for handles
+ usb_handle* usb = calloc(1, sizeof(usb_handle));
+ s_strncpy(usb->unique_node_path, device_path, sizeof(usb->unique_node_path));
+
+ // Open generic handle to device
+ HANDLE hnd = CreateFile(device_path, GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
+
+ if (INVALID_HANDLE_VALUE == hnd) {
+ D("fail to create device file: %s due to: %d\n", device_path, GetLastError());
+ return NULL;
+ }
+
+ // Initialize WinUSB for this device and get a WinUSB handle for it
+ WINUSB_INTERFACE_HANDLE fd;
+ if (!WinUsb_Initialize(hnd, &fd)) {
+ return NULL;
+ }
+
+ // fetch USB device descriptor
+ USB_DEVICE_DESCRIPTOR usb_device_descriptor;
+ unsigned long bytes_written;
+
+ if (!WinUsb_GetDescriptor(fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0,
+ (PUCHAR)&usb_device_descriptor, sizeof(usb_device_descriptor), &bytes_written)) {
+ return NULL;
+ }
+
+ USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
+
+ // fetch usb interface descriptor
+ UCHAR interface_number;
+ if (!WinUsb_GetCurrentAlternateSetting(fd, &interface_number)) {
+ return NULL;
+ }
+
+ if (!WinUsb_QueryInterfaceSettings(fd, interface_number, &usb_interface_descriptor)) {
+ return NULL;
+ }
+
+ if (2 != usb_interface_descriptor.bNumEndpoints) {
+ D("the number of endpoint should be two\n");
+ return NULL;
+ }
+
+ if (!is_sdb_interface(usb_device_descriptor.idVendor, usb_interface_descriptor.bInterfaceClass, usb_interface_descriptor.bInterfaceSubClass,
+ usb_interface_descriptor.bInterfaceProtocol)) {
+ return NULL;
+ }
+ UCHAR endpoint_index = 0;
+
+ for (endpoint_index = 0; endpoint_index < usb_interface_descriptor.bNumEndpoints; endpoint_index++) {
+ // fetch endpoint information
+ WINUSB_PIPE_INFORMATION pipe_info;
+ if (!WinUsb_QueryPipe(fd, interface_number, endpoint_index, &pipe_info)) {
+ return NULL;
+ }
+
+ if(usb_interface_descriptor.bInterfaceProtocol == 0x01) {
+ if (endpoint_index == 0) {
+ usb->zero_mask = pipe_info.MaximumPacketSize - 1;
+ }
+ }
+ // only interested in bulk type
+ if (UsbdPipeTypeBulk == pipe_info.PipeType) {
+ if (USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) {
+ D("builk in endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId);
+ usb->end_point[0] = pipe_info.PipeId;
+ }
+
+ if (USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) {
+ D("builk out endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId);
+ usb->end_point[1] = pipe_info.PipeId;
+ }
+
+ }
+ }
+ usb->hnd = hnd;
+ usb->fd = fd;
+
+ return usb;
+}
+
+int register_device(usb_handle *hnd) {
+ if (is_device_registered(hnd->unique_node_path)) {
+ return 0;
+ }
+
+ sdb_mutex_lock(&usb_lock, "usb register_device");
+
+ hnd->node = prepend(&handle_list, hnd);
+
+ sdb_mutex_unlock(&usb_lock, "usb register_device");
+
+ return 1;
+}
+
+int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen) {
+ unsigned char temp[MAXIMUM_USB_STRING_LENGTH];
+
+ ULONG actlen = 0;
+ //0x0409 for English (US)
+ if (!WinUsb_GetDescriptor(dev->fd, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409, temp, sizeof(temp), &actlen)) {
+ return -GetLastError();
+ }
+ // Skip first two bytes of result (descriptor id and length), then take
+ // every other byte as a cheap way to convert Unicode to ASCII
+ unsigned int i, j;
+ for (i = 2, j = 0; i < actlen && j < (buflen - 1); i += 2, ++j)
+ buf[j] = temp[i];
+ buf[j] = '\0';
+
+ return strlen(buf);
+}
+
+static int get_serial_number(usb_handle *dev, char *buf, int buflen) {
+ USB_DEVICE_DESCRIPTOR usb_device_descriptor;
+ ULONG actlen = 0;
+
+ if (!WinUsb_GetDescriptor(dev->fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (unsigned char*) &usb_device_descriptor,
+ sizeof(usb_device_descriptor), &actlen)) {
+ return 0;
+ }
+
+ return usb_get_string_simple(dev, usb_device_descriptor.iSerialNumber, buf, buflen);
+}
+
+int usb_find_devices(GUID deviceClassID) {
+ SP_DEVINFO_DATA deviceInfoData;
+ char devicePath[PATH_MAX + 1];
+ BOOL bResult = TRUE;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
+ int index = 0;
+
+ // from http://msdn.microsoft.com/en-us/library/windows/hardware/ff540174(v=vs.85).aspx
+ // Get information about all the installed devices for the specified device interface class.
+ HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&deviceClassID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (hDeviceInfo == INVALID_HANDLE_VALUE) {
+ D("fail to find any device: %d\n", GetLastError());
+ return 0;
+ }
+
+ //Enumerate all the device interfaces in the device information set.
+ deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+
+ for (index = 0; ; index++) {
+
+ //Get information about the device interface.
+ SP_DEVICE_INTERFACE_DATA interfaceData;
+ interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
+
+ bResult = SetupDiEnumDeviceInterfaces(hDeviceInfo, NULL, &deviceClassID, index, &interfaceData);
+ // Check if last item
+ if (GetLastError() == ERROR_NO_MORE_ITEMS) {
+ break;
+ }
+
+ //Check for some other error
+ if (!bResult)
+ {
+ D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
+ break;
+ }
+
+ // Determine required size for interface detail data
+ ULONG requiredLength = 0;
+
+ //Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA
+ //which we need to allocate, so we have to call this function twice.
+ //First to get the size so that we know how much to allocate
+ //Second, the actual call with the allocated buffer
+ bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL);
+
+ //Check for some other error
+ if (!bResult) {
+ if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (requiredLength > 0)) {
+ // Allocate storage for interface detail data
+ detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredLength);
+
+ if (detailData == NULL) {
+ D("fail to allocate memory\n");
+ break;
+ }
+ } else {
+ D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
+ break;
+ }
+ }
+
+ // Finally, do fetch interface detail data
+ detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+ //Now call it with the correct size and allocated buffer
+ bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, detailData, requiredLength, NULL,
+ &deviceInfoData);
+
+ //Check for some other error
+ if (!bResult) {
+ D("fail to setdup get device interface detail: %d\n", GetLastError());
+ if (detailData != NULL) {
+ free(detailData);
+ }
+ break;
+ }
+
+ //copy device path
+ s_strncpy(devicePath, detailData->DevicePath, sizeof(devicePath));
+
+ if (detailData != NULL) {
+ free(detailData);
+ }
+
+ if (!is_device_registered(devicePath)) {
+ struct usb_handle *hnd = usb_open(devicePath);
+ if (hnd != NULL) {
+ char serial[256];
+ if (get_serial_number(hnd, serial, sizeof(serial)) > 0) {
+ D("register usb for: %s\n", serial);
+ if (register_device(hnd)) {
+ register_usb_transport(hnd, serial);
+ } else {
+ D("fail to register usb\n");
+ win_usb_close(hnd);
+ free(hnd);
+ }
+ } else {
+ D("fail to get usb serial name: kick? close?\n");
+ win_usb_close(hnd);
+ free(hnd);
+ }
+ }
+ }
+ }
+ // Cleanup
+ bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo);
+
+ return bResult;
+}
+
+void* device_poll_thread(void* sleep_msec) {
+ D("Created device thread\n");
+
+ int mseconds = (int) sleep_msec;
+ while (1) {
+ do_lsusb();
+ sdb_sleep_ms(mseconds);
+ }
+
+ return NULL;
+}
+
+void sdb_usb_init() {
+ sdb_thread_t tid;
+
+ win_usb_init();
+ if (sdb_thread_create(&tid, device_poll_thread, (void*)3000)) {
+ LOG_FATAL("cannot create input thread\n");
+ }
+}
+
+void sdb_usb_cleanup() {
+ D("TODO: not imple yet\n");
+}
+
+int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout) {
+ ULONG tmp = timeout;
+ UCHAR endpoint;
+
+ if (is_read) {
+ endpoint = handle->end_point[0];
+ } else {
+ endpoint = handle->end_point[1];
+ }
+ if (handle->fd == NULL) {
+ D("invalid handle\n");
+ return 0;
+ }
+
+ // do not complete within the specified time-out interval
+ if (!WinUsb_SetPipePolicy(handle->fd, endpoint, PIPE_TRANSFER_TIMEOUT, sizeof(tmp), &tmp)) {
+ D("fail to set timeout\n");
+ SetLastError(ERROR_SEM_TIMEOUT);
+ return 0;
+ }
+
+ // manual reset must be true (second param) as the reset occurs in read
+
+ OVERLAPPED overlapped;
+ ZeroMemory(&overlapped, sizeof(overlapped));
+ overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ BOOL ret = TRUE;
+ ULONG transferred = 0;
+
+ if (is_read) {
+ ret = WinUsb_ReadPipe(handle->fd, endpoint, (UCHAR*) data, length, &transferred, &overlapped);
+ } else {
+ ret = WinUsb_WritePipe(handle->fd, endpoint, (UCHAR*) data, length, &transferred, &overlapped);
+ }
+
+ if (!ret && (ERROR_IO_PENDING != GetLastError())) {
+ if (NULL != overlapped.hEvent){
+ CloseHandle(overlapped.hEvent);
+ }
+ D("pipe error: (%ld/ld) error:%d\n", length, transferred, GetLastError());
+ return 0;
+ }
+
+ // wait for the operation to be IO completed
+ ret = WinUsb_GetOverlappedResult(handle->fd, &overlapped, &transferred, TRUE);
+
+ if (ret && (NULL != actual_length)) {
+ *actual_length = transferred;
+ }
+
+ if (NULL != overlapped.hEvent) {
+ CloseHandle(overlapped.hEvent);
+ }
+
+ return ret ? 1 : 0;
+}
+
+int sdb_usb_write(usb_handle* handle, const void* data, int len) {
+ unsigned long time_out = 5000;//5000;
+ unsigned long written = 0;
+ int ret;
+
+ D("+sdb_usb_write %d\n", len);
+
+ if (NULL != handle) {
+ ret = usb_bulk_transfer(handle, FALSE, (void*)data, (unsigned long)len, &written, time_out);
+ int saved_errno = GetLastError();
+ D("sdb_usb_write got(ret:%d): %ld, expected: %d, errno: %d\n",ret, written, len, saved_errno);
+
+ if (ret) {
+ if (written == (unsigned long) len) {
+ if (handle->zero_mask && (len & handle->zero_mask) == 0) {
+ // Send a zero length packet
+ usb_bulk_transfer(handle, FALSE, (void*)data, 0, &written, time_out);
+ }
+ return 0;
+ }
+ } else {
+ // assume ERROR_INVALID_HANDLE indicates we are disconnected
+ if (saved_errno == ERROR_INVALID_HANDLE) {
+ sdb_usb_kick(handle);
+ }
+ }
+ errno = saved_errno;
+ } else {
+ D("usb_write NULL handle\n");
+ SetLastError(ERROR_INVALID_HANDLE);
+ }
+
+ D("-sdb_usb_write failed: %d\n", errno);
+
+ return -1;
+}
+
+int sdb_usb_read(usb_handle *handle, void* data, int len) {
+ unsigned long n = 0;
+ int ret;
+
+ D("+sdb_usb_read %d\n", len);
+ if (NULL != handle) {
+ while (len > 0) {
+ int xfer = (len > 4096) ? 4096 : len;
+ ret = usb_bulk_transfer(handle, TRUE, (void*)data, (unsigned long)xfer, &n, (unsigned long)0);
+ int saved_errno = GetLastError();
+ D("sdb_usb_read got(ret:%d): %ld, expected: %d, errno: %d\n", ret, n, xfer, saved_errno);
+
+ if (ret) {
+ data += n;
+ len -= n;
+
+ if (len == 0)
+ return 0;
+ } else {
+ // assume ERROR_INVALID_HANDLE indicates we are disconnected
+ if (saved_errno == ERROR_INVALID_HANDLE) {
+ sdb_usb_kick(handle);
+ }
+ break;
+ }
+ errno = saved_errno;
+ }
+ } else {
+ D("sdb_usb_read NULL handle\n");
+ SetLastError(ERROR_INVALID_HANDLE);
+ }
+
+ D("-sdb_usb_read failed: %d\n", errno);
+
+ return -1;
+}
+
+int win_usb_close(usb_handle *handle) {
+ D("+usb win_usb_close\n");
+ if (NULL != handle) {
+ if (NULL != handle->fd) {
+ WinUsb_Free(handle->fd);
+ handle->fd = NULL;
+ }
+ if (NULL != handle->hnd) {
+ CloseHandle(handle->hnd);
+ handle->hnd = NULL;
+ }
+ handle = NULL;
+ }
+ D("-usb win_usb_close\n");
+ return 0;
+}
+
+void sdb_usb_kick(usb_handle* handle) {
+ D("+sdb_usb_kick: %p\n", handle);
+ // called from transport remote kick if already registered
+ // so only clean for win usb handle resources
+ sdb_mutex_lock(&usb_lock, "usb sdb_usb_kick");
+ win_usb_close(handle);
+ sdb_mutex_unlock(&usb_lock , "usb sdb_usb_kick");
+ D("-sdb_usb_kick: %p\n", handle);
+}
+
+int sdb_usb_close(usb_handle* handle) {
+ D("+sdb_usb_close: %p\n", handle);
+ if (NULL != handle) {
+ sdb_mutex_lock(&usb_lock, "usb sdb_usb_close");
+ remove_node(&handle_list, handle->node, NULL);
+ sdb_mutex_unlock(&usb_lock, "usb sdb_usb_close");
+ }
+ D("-sdb_usb_close: %p\n", handle);
+ return 0;
+}
+
+void do_lsusb() {
+ usb_find_devices(TIZEN_CLASSID);
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __WINUSB_H
+#define __WINUSB_H
+
+#include "ddk/usb100.h"
+#include "ddk/usbioctl.h"
+
+// Windows API default is uppercase - ugh!
+#if !defined(bool)
+#define bool BOOLEAN
+#endif
+#if !defined(true)
+#define true TRUE
+#endif
+#if !defined(false)
+#define false FALSE
+#endif
+
+
+/*
+ * Some of the EX stuff is not yet in MinGW => define it
+ */
+#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX
+#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
+#endif
+
+#ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#endif
+
+#ifndef USB_NODE_CONNECTION_INFORMATION_EX
+typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
+ ULONG ConnectionIndex;
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ UCHAR CurrentConfigurationValue;
+ UCHAR Speed;
+ BOOLEAN DeviceIsHub;
+ USHORT DeviceAddress;
+ ULONG NumberOfOpenPipes;
+ USB_CONNECTION_STATUS ConnectionStatus;
+ USB_PIPE_INFO PipeList[0];
+} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
+#endif
+
+#ifndef USB_HUB_CAP_FLAGS
+typedef union _USB_HUB_CAP_FLAGS {
+ ULONG ul;
+ struct {
+ ULONG HubIsHighSpeedCapable:1;
+ ULONG HubIsHighSpeed:1;
+ ULONG HubIsMultiTtCapable:1;
+ ULONG HubIsMultiTt:1;
+ ULONG HubIsRoot:1;
+ ULONG HubIsArmedWakeOnConnect:1;
+ ULONG ReservedMBZ:26;
+ };
+} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS;
+#endif
+
+#ifndef USB_HUB_CAPABILITIES_EX
+typedef struct _USB_HUB_CAPABILITIES_EX {
+ USB_HUB_CAP_FLAGS CapabilityFlags;
+} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX;
+#endif
+
+#ifndef USB_GET_HUB_CAPABILITIES_EX
+#define USB_GET_HUB_CAPABILITIES_EX 276
+#endif
+
+#ifndef IOCTL_USB_GET_HUB_CAPABILITIES_EX
+#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \
+ CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS )
+#endif
+
+/*
+ * WinUSB macros - from libusb-win32 1.x
+ */
+
+#define DLL_DECLARE(api, ret, name, args) \
+ typedef ret (api * __dll_##name##_t)args; \
+ static __dll_##name##_t name
+
+#define DLL_LOAD(dll, name) \
+ do { \
+ HMODULE h = GetModuleHandle(#dll); \
+ if(!h) \
+ h = LoadLibrary(#dll); \
+ if(!h) \
+ break; \
+ if((name = (__dll_##name##_t)GetProcAddress(h, #name))) \
+ break; \
+ if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \
+ break; \
+ if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \
+ break; \
+ } while(0)
+
+
+/* winusb.dll interface */
+
+#define SHORT_PACKET_TERMINATE 0x01
+#define AUTO_CLEAR_STALL 0x02
+#define PIPE_TRANSFER_TIMEOUT 0x03
+#define IGNORE_SHORT_PACKETS 0x04
+#define ALLOW_PARTIAL_READS 0x05
+#define AUTO_FLUSH 0x06
+#define RAW_IO 0x07
+#define MAXIMUM_TRANSFER_SIZE 0x08
+#define AUTO_SUSPEND 0x81
+#define SUSPEND_DELAY 0x83
+#define DEVICE_SPEED 0x01
+#define LowSpeed 0x01
+#define FullSpeed 0x02
+#define HighSpeed 0x03
+
+typedef enum _USBD_PIPE_TYPE {
+ UsbdPipeTypeControl,
+ UsbdPipeTypeIsochronous,
+ UsbdPipeTypeBulk,
+ UsbdPipeTypeInterrupt
+} USBD_PIPE_TYPE;
+
+typedef struct {
+ USBD_PIPE_TYPE PipeType;
+ UCHAR PipeId;
+ USHORT MaximumPacketSize;
+ UCHAR Interval;
+} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
+
+#pragma pack(1)
+typedef struct {
+ UCHAR RequestType;
+ UCHAR Request;
+ USHORT Value;
+ USHORT Index;
+ USHORT Length;
+} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
+#pragma pack()
+
+typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
+
+#endif // __WINUSB_H
+* 2.2.20
+- fix offline bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-16 21:35
+* 2.2.19
+- fix device undetected bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-16 20:36
+* 2.2.18
+- Fix duplicated target bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-16 13:50
* 2.2.17
-- change compiler to llvm
-== yoonki.park <yoonki.park@samsung.com> 2013-07-15
+- fix pull/ push bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-14 20:06
* 2.2.16
-- fixed build script for tsudo
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-15
+- fix bugs about sdb test cases
+== ho.namkoong <ho.namkoong@samsung.com> 2013-09-01
* 2.2.15
-- give abs path to tsudo
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-12
+- version up for refactoring test
+== ho.namkoong <ho.namkoong@samsung.com> 2013-08-23
* 2.2.14
-- Change PATH_MAX in Windows 256 -> 4096
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
+- version up 2.2.14
+== ho.namkoong <ho.namkoong@samsung.com> 2013-08-07
* 2.2.13
-- echo stdout in install script
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
+- version up 2.2.13
+== ho.namkoong <ho.namkoong@samsung.com> 2013-08-05
* 2.2.12
-- use tsudo instead of gksudo
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
+- fix socket close bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-24
* 2.2.11
-- Fixed sdbd version checking without rpm query
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-08
+- fix web debugging bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-24
* 2.2.10
-- Fixed argument append util for da/oprofile command
-== kh5325.kim <kh5325.kim@samsung.com> 2013-07-08
+- fix forward bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-24
* 2.2.9
-- Fix pull/push message
-== ho.namkoong <ho.namkoong@samsung.com> 2013-07-04
+- remove setting sdb path
+== yoonki.park <yoonki.park@samsung.com> 2013-07-23
* 2.2.8
-- Fix window install bug
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-28
+- fixed to install on windows
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-22
* 2.2.7
-- rollback linux usb control
-== ho.namkoong <yoonki.park@samsung.com> 2013-06-25
+- fixed to add sdb path to windows shell
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-19
* 2.2.6
-- change lstat to stat for treating link file as regular file
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-24
+- change PATH_MAX in Windows 256 -> 4096
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
* 2.2.5
-- modify debug launchpad applied sdbd version
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-24
+- use tsudo
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
* 2.2.4
-- change sdb version in help page
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-23
+- use libusb.so
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-11
* 2.2.3
-- remove printf in lauchapp
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-23
+- fix da and oprofile arg appending bug
+== ho.namkoong <ho.namkoong@samsung.com> 2013-07-04
* 2.2.2
-- apply debug launch pad
-== ho.namkoong <ho.namkoong@samsung.com> 2013-06-23
+- sdb for tizen2.2
+== yoonki.park <yoonki.park@samsung.com> 2013-07-04
* 2.2.1
- fixed crash on Windows
== yoonki.park <yoonki.park@samsung.com> 2013-06-21
-Version:2.2.17
+Version:2.2.20
Source:sdb
Maintainer:Kangho Kim <kh5325.kim@samsung.com>, Yoonki Park<yoonki.park@samsung.com>, Hyunsik Noh<hyunsik.noh@samsung.com>, Gun Kim<gune.kim@samsung.com>, Ho Namkoong<ho.namkoong@samsung.com>, Taeyoung Son<taeyoung2.son@samsung.com>
#!/bin/bash -ex
-## Set sdb's environment path
-bashrc=${HOME}/.bashrc
-if [ -f ${bashrc} ]; then
- s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"`
-else
- s=
-fi
-
-if [ "x${s}" = "x" ]; then
-cat >> ${bashrc} << END
-## Tizen SDK configuration
-# This is generated by Tizen SDK. Please do not modify by yourself.
-# Set sdb environment path
-export PATH=\$PATH:${INSTALLED_PATH}/tools
-## End Tizen SDK configuration
-END
-fi
-
-source ${HOME}/.bashrc
-
-# set udev rules file
-
-TMP_FILE=99-samsung-device.rules
-echo "# Add a udev rules when you want to develop a Tizen application with your device." >> $TMP_FILE
-echo "# Use this format to add each vendor to the file:" >> $TMP_FILE
-echo "# SUBSYSTEM==\"usb\", ATTR{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE
-echo "# In the example, the vendor ID is for Samsung manufacture. The mode specifies read/write permissions, and group defines which Unix group owns the device node." >> $TMP_FILE
-echo "#" >> $TMP_FILE
-echo "# Contact : Kangho Kim <kh5325.kim@samsung.com>, Yoonki Park<yoonki.park@samsung.com>, Ho Namkoong <ho.namkoong@samsung.com>" >> $TMP_FILE
-echo "# See also udev(7) for an overview of rule syntax." >> $TMP_FILE
-echo "" >> $TMP_FILE
-echo "# Samsung" >> $TMP_FILE
-echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE
-echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6863\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE
-
-chmod +x $TMP_FILE
-CURRENT_DIR=`pwd`
-
-if [ -z "$TSUDO" ]; then
- if [ -f /usr/bin/gksudo ]
- then gksudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/
- else if [ -f /usr/bin/sudo ]
- then sudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/
- fi
- fi
- exit 0
-else
- $TSUDO -m "Enter your password to install sdb." mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/
- exit 0
-fi
-
exit 0
#!/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
@echo off
-
-echo "setting path..."
-setx -m PATH "%PATH%;${INSTALLED_PATH}\tools
-exit 0
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
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
@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
#include <limits.h>
#include "utils.h"
#include "fdevent.h"
-#include "sdb.h"
#include "commandline.h"
#include "command_function.h"
#include "strutils.h"
#include "file_sync_client.h"
#include "file_sync_functions.h"
+#include "common_modules.h"
+
+#include "log.h"
+#include "sdb.h"
static const char *SDK_TOOL_PATH="/home/developer/sdk_tools";
static const char *APP_PATH_PREFIX="/opt/apps";
}
}
+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];
#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);
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) {
#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);
#include <termios.h>
#endif
#include "utils.h"
-#include "sdb.h"
#include "sdb_client.h"
#include "file_sync_service.h"
-
+#include "log.h"
#include "linkedlist.h"
#include "sdb_constants.h"
fwrite(buf, 1, len, stdout);
fflush(stdout);
}
+
}
static void *stdin_read_thread(void *x)
stdin_raw_restore(INPUT_FD, tio_save);
free(tio_save);
#endif
- free(args);
exit(0);
}
}
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) {
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) {
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;
}
print_help(opt_list, cmd_list);
+ if (serial != NULL) {
+ free(serial);
+ }
return 1;
}
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);
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);
fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]);
}
}
- curptr = curptr->next_ptr;
}
-
+ free(append_str);
+ free(help_str);
}
--- /dev/null
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef COMMON_MODULES_H_
+#define COMMON_MODULES_H_
+
+#include "linkedlist.h"
+#include "fdevent.h"
+#include "sdb_usb.h"
+
+#define MAX_PAYLOAD 4096
+#define CHUNK_SIZE (64*1024)
+#define DEFAULT_SDB_PORT 26099
+
+#define A_VERSION 0x0100000
+
+#define SDB_VERSION_MAJOR 2
+#define SDB_VERSION_MINOR 2
+
+#define SDB_SERVER_VERSION 6
+
+extern MAP hex_map;
+
+typedef struct message MESSAGE;
+struct message {
+ unsigned command; /* command identifier constant */
+ unsigned arg0; /* first argument */
+ unsigned arg1; /* second argument */
+ unsigned data_length; /* length of payload (0 is allowed) */
+ unsigned data_check; /* checksum of data payload */
+ unsigned magic; /* command ^ 0xffffffff */
+};
+
+typedef struct packet PACKET;
+struct packet
+{
+ LIST_NODE* node;
+
+ unsigned len;
+ void *ptr;
+
+ MESSAGE msg;
+ unsigned char data[MAX_PAYLOAD];
+};
+
+typedef enum transport_type {
+ kTransportUsb,
+ kTransportLocal,
+ kTransportAny,
+ kTransportRemoteDevCon
+} transport_type;
+
+typedef struct transport TRANSPORT;
+struct transport
+{
+ LIST_NODE* node;
+ //list for remote sockets which wait for CNXN
+ LIST_NODE* remote_cnxn_socket;
+
+ int (*read_from_remote)(TRANSPORT* t, void* data, int len);
+ int (*write_to_remote)(PACKET *p, TRANSPORT *t);
+ void (*close)(TRANSPORT *t);
+ void (*kick)(TRANSPORT *t);
+
+ int connection_state;
+ transport_type type;
+
+ usb_handle *usb;
+ int sfd;
+
+ char *serial;
+ int sdb_port;
+ char *device_name;
+
+ int kicked;
+ unsigned req;
+ unsigned res;
+};
+
+typedef struct listener LISTENER;
+struct listener
+{
+ LIST_NODE* node;
+
+ FD_EVENT fde;
+ int fd;
+
+ const char *local_name;
+ const char *connect_to;
+ TRANSPORT *transport;
+};
+
+typedef struct t_packet T_PACKET;
+struct t_packet {
+ TRANSPORT* t;
+ PACKET* p;
+};
+
+typedef struct socket SDB_SOCKET;
+struct socket {
+ int status;
+ LIST_NODE* node;
+
+ unsigned local_id;
+ unsigned remote_id;
+
+ int closing;
+ FD_EVENT fde;
+ int fd;
+
+ LIST_NODE* pkt_list;
+ TRANSPORT *transport;
+
+ PACKET* read_packet;
+};
+
+int readx(int fd, void *ptr, size_t len);
+int writex(int fd, const void *ptr, size_t len);
+
+#endif /* SDB_TYPES_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdio.h>
+#include "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));
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __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
#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);
}
#define __FDEVENT_H
#include <stdint.h> /* for int64_t */
+#include "linkedlist.h"
+#include "sdb_map.h"
/* events that may be observed */
-#define FDE_READ 0x0001
-#define FDE_WRITE 0x0002
-#define FDE_ERROR 0x0004
-#define FDE_TIMEOUT 0x0008
+#define FDE_READ 1
+#define FDE_WRITE 2
+#define FDE_MASK 3
-#define FDE_EVENTMASK 0x00ff
-#define FDE_STATEMASK 0xff00
-
-#define FDE_ACTIVE 0x0100
-#define FDE_PENDING 0x0200
-#define FDE_CREATED 0x0400
+typedef struct fd_event FD_EVENT;
+typedef void (*fd_func)(int fd, unsigned events, void *userdata);
-/* features that may be set (via the events set/add/del interface) */
-#define FDE_DONT_CLOSE 0x0080
+struct fd_event
+{
+ LIST_NODE* node;
-typedef struct fdevent fdevent;
+ int fd;
+ unsigned events;
-typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+ fd_func func;
+ void *arg;
+};
-/* Allocate and initialize a new fdevent object
- * Note: use FD_TIMER as 'fd' to create a fd-less object
- * (used to implement timers).
-*/
-fdevent *fdevent_create(int fd, fd_func func, void *arg);
+int fdevent_wakeup_send;
+int fdevent_wakeup_recv;
-/* Uninitialize and deallocate an fdevent object that was
-** created by fdevent_create()
-*/
-void fdevent_destroy(fdevent *fde);
+FD_EVENT fdevent_wakeup_fde;
/* Initialize an fdevent object that was externally allocated
*/
-void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
+void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg);
/* Uninitialize an fdevent object that was initialized by
** fdevent_install()
*/
-void fdevent_remove(fdevent *item);
+void fdevent_remove(FD_EVENT *item);
-/* Change which events should cause notifications
-*/
-void fdevent_set(fdevent *fde, unsigned events);
-void fdevent_add(fdevent *fde, unsigned events);
-void fdevent_del(fdevent *fde, unsigned events);
+#define EVENT_MAP_SIZE 256
-void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
+extern MAP event_map;
-/* loop forever, handling events.
+FD_EVENT* fdevent_map_get(int key);
+void fdevent_map_put(int key, FD_EVENT* value);
+void fdevent_map_remove(int key);
+
+/* Change which events should cause notifications
*/
-void fdevent_loop();
-struct fdevent
-{
- fdevent *next;
- fdevent *prev;
+#define FDEVENT_SET(fde, events) \
+ fdevent_backend->fdevent_update(fde, events)
- int fd;
- int force_eof;
+#define FDEVENT_ADD(fde, _events) \
+ fdevent_backend->fdevent_update(fde, (fde)->events | _events)
- unsigned short state;
- unsigned short events;
+#define FDEVENT_DEL(fde, _events) \
+ fdevent_backend->fdevent_update(fde, (fde)->events & ~_events)
- fd_func func;
- void *arg;
+#define FDEVENT_LOOP() \
+ fdevent_backend->fdevent_loop()
+
+struct fdevent_os_backend {
+ void (*fdevent_loop)(void);
+ void (*fdevent_disconnect)(FD_EVENT *fde);
+ void (*fdevent_update)(FD_EVENT *fde, unsigned events);
};
+extern const struct fdevent_os_backend* fdevent_backend;
+#ifndef OS_WINDOWS
+extern int max_select;
+extern const struct fdevent_os_backend fdevent_unix_backend;
+#else
+extern const struct fdevent_os_backend fdevent_windows_backend;
+#endif
+
+#if defined(OS_WINDOWS)
+#include <windows.h>
+
+#define WIN32_MAX_FHS 128
+extern MAP sdb_handle_map;
+extern HANDLE socket_event_handle[];
+extern int event_location_to_fd[];
+extern int current_socket_location;
+#endif
#endif
#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
#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.
#include <sys/select.h>
+#define FD_CLR_ALL(fde) \
+ FD_CLR(fde->fd, &fds_read); \
+ FD_CLR(fde->fd, &fds_write);
-static fd_set read_fds;
-static fd_set write_fds;
-static fd_set error_fds;
+static fd_set fds_write;
+static fd_set fds_read;
-static int select_n = 0;
-
-static void _fdevent_init(void)
-{
- FD_ZERO(&read_fds);
- FD_ZERO(&write_fds);
- FD_ZERO(&error_fds);
-}
-
-static void _fdevent_connect(fdevent *fde)
-{
- if(fde->fd >= select_n) {
- select_n = fde->fd + 1;
- }
-}
-
-static void _fdevent_disconnect(fdevent *fde)
-{
- int i, n;
-
- FD_CLR(fde->fd, &read_fds);
- FD_CLR(fde->fd, &write_fds);
- FD_CLR(fde->fd, &error_fds);
-
- for(n = 0, i = 0; i < select_n; i++) {
- if(fd_table[i] != 0) n = i;
- }
- select_n = n + 1;
-}
-
-static void _fdevent_update(fdevent *fde, unsigned events)
+static void _fdevent_disconnect(FD_EVENT *fde)
{
- if(events & FDE_READ) {
- FD_SET(fde->fd, &read_fds);
- } else {
- FD_CLR(fde->fd, &read_fds);
- }
- if(events & FDE_WRITE) {
- FD_SET(fde->fd, &write_fds);
- } else {
- FD_CLR(fde->fd, &write_fds);
- }
- if(events & FDE_ERROR) {
- FD_SET(fde->fd, &error_fds);
- } else {
- FD_CLR(fde->fd, &error_fds);
- }
-
- fde->state = (fde->state & FDE_STATEMASK) | events;
-}
-
-/* Looks at fd_table[] for bad FDs and sets bit in fds.
-** Returns the number of bad FDs.
-*/
-static int fdevent_fd_check(fd_set *fds)
-{
- int i, n = 0;
- fdevent *fde;
-
- for(i = 0; i < select_n; i++) {
- fde = fd_table[i];
- if(fde == 0) continue;
- if(fcntl(i, F_GETFL, NULL) < 0) {
- FD_SET(i, fds);
- n++;
- // fde->state |= FDE_DONT_CLOSE;
-
+ FD_CLR_ALL(fde);
+ //selectn should be reset
+ int fd = fde->fd;
+ if(fd >= max_select -1) {
+ int i = fd - 1;
+ while(i > -1) {
+ if(fdevent_map_get(i) != NULL) {
+ max_select = i+1;
+ break;
+ }
+ --i;
}
}
- return n;
}
-#if !DEBUG
-static inline void dump_all_fds(const char *extra_msg) {}
-#else
-static void dump_all_fds(const char *extra_msg)
+static void _fdevent_update(FD_EVENT *fde, unsigned events)
{
-int i;
- fdevent *fde;
- // per fd: 4 digits (but really: log10(FD_SETSIZE)), 1 staus, 1 blank
- char msg_buff[FD_SETSIZE*6 + 1], *pb=msg_buff;
- size_t max_chars = FD_SETSIZE * 6 + 1;
- int printed_out;
-#define SAFE_SPRINTF(...) \
- do { \
- printed_out = snprintf(pb, max_chars, __VA_ARGS__); \
- if (printed_out <= 0) { \
- D("... snprintf failed.\n"); \
- return; \
- } \
- if (max_chars < (unsigned int)printed_out) { \
- D("... snprintf out of space.\n"); \
- return; \
- } \
- pb += printed_out; \
- max_chars -= printed_out; \
- } while(0)
-
- for(i = 0; i < select_n; i++) {
- fde = fd_table[i];
- SAFE_SPRINTF("%d", i);
- if(fde == 0) {
- SAFE_SPRINTF("? ");
- continue;
- }
- if(fcntl(i, F_GETFL, NULL) < 0) {
- SAFE_SPRINTF("b");
- }
- SAFE_SPRINTF(" ");
+ if(fde->events == events) {
+ return;
}
- D("%s fd_table[]->fd = {%s}\n", extra_msg, msg_buff);
-}
-#endif
-static int _fdevent_process()
-{
- int i, n;
- fdevent *fde;
- unsigned events;
- fd_set rfd, wfd, efd;
+ int fd = fde->fd;
+ events = events & FDE_MASK;
+ fde->events = events;
- memcpy(&rfd, &read_fds, sizeof(fd_set));
- memcpy(&wfd, &write_fds, sizeof(fd_set));
- memcpy(&efd, &error_fds, sizeof(fd_set));
-
- dump_all_fds("pre select()");
-
- n = select(select_n, &rfd, &wfd, &efd, NULL);
- int saved_errno = errno;
- D("select() returned n=%d, errno=%d\n", n, n<0?saved_errno:0);
-
- dump_all_fds("post select()");
-
- if(n < 0) {
- switch(saved_errno) {
- case EINTR: return -1;
- case EBADF:
- // Can't trust the FD sets after an error.
- FD_ZERO(&wfd);
- FD_ZERO(&efd);
- FD_ZERO(&rfd);
+ switch (events ) {
+ case FDE_READ:
+ FD_SET(fd, &fds_read);
+ FD_CLR(fd, &fds_write);
+ break;
+ case FDE_WRITE:
+ FD_SET(fd, &fds_write);
+ FD_CLR(fd, &fds_read);
+ break;
+ case 0:
+ FD_CLR(fd, &fds_read);
+ FD_CLR(fd, &fds_write);
break;
default:
- D("Unexpected select() error=%d\n", saved_errno);
- return 0;
- }
- }
- if(n <= 0) {
- // We fake a read, as the rest of the code assumes
- // that errors will be detected at that point.
- n = fdevent_fd_check(&rfd);
- }
-
- for(i = 0; (i < select_n) && (n > 0); i++) {
- events = 0;
- if(FD_ISSET(i, &rfd)) { events |= FDE_READ; n--; }
- if(FD_ISSET(i, &wfd)) { events |= FDE_WRITE; n--; }
- if(FD_ISSET(i, &efd)) { events |= FDE_ERROR; n--; }
-
- if(events) {
- fde = fd_table[i];
- if(fde == 0)
- FATAL("missing fde for fd %d\n", i);
-
- fde->events |= events;
-
- D("got events fde->fd=%d events=%04x, state=%04x\n",
- fde->fd, fde->events, fde->state);
- if(fde->state & FDE_PENDING) continue;
- fde->state |= FDE_PENDING;
- fdevent_plist_enqueue(fde);
- }
- }
-
- return 0;
-}
-
-static void fdevent_call_fdfunc(fdevent* fde)
-{
- unsigned events = fde->events;
- fde->events = 0;
- if(!(fde->state & FDE_PENDING)) return;
- fde->state &= (~FDE_PENDING);
- dump_fde(fde, "callback");
- fde->func(fde->fd, events, fde->arg);
-}
-
-static void fdevent_subproc_event_func(int fd, unsigned ev, void *userdata)
-{
-
- D("subproc handling on fd=%d ev=%04x\n", fd, ev);
-
- // Hook oneself back into the fde's suitable for select() on read.
- if((fd < 0) || (fd >= fd_table_max)) {
- FATAL("fd %d out of range for fd_table \n", fd);
- }
- fdevent *fde = fd_table[fd];
- fdevent_add(fde, FDE_READ);
-
- if(ev & FDE_READ){
- int subproc_fd;
-
- if(readx(fd, &subproc_fd, sizeof(subproc_fd))) {
- FATAL("Failed to read the subproc's fd from fd=%d\n", fd);
- }
- if((subproc_fd < 0) || (subproc_fd >= fd_table_max)) {
- D("subproc_fd %d out of range 0, fd_table_max=%d\n",
- subproc_fd, fd_table_max);
- return;
- }
- fdevent *subproc_fde = fd_table[subproc_fd];
- if(!subproc_fde) {
- D("subproc_fd %d cleared from fd_table\n", subproc_fd);
- return;
- }
- if(subproc_fde->fd != subproc_fd) {
- // Already reallocated?
- D("subproc_fd %d != fd_table[].fd %d\n", subproc_fd, subproc_fde->fd);
- return;
- }
-
- subproc_fde->force_eof = 1;
-
- int rcount = 0;
- ioctl(subproc_fd, FIONREAD, &rcount);
- D("subproc with fd=%d has rcount=%d err=%d\n",
- subproc_fd, rcount, errno);
-
- if(rcount) {
- // If there is data left, it will show up in the select().
- // This works because there is no other thread reading that
- // data when in this fd_func().
- return;
- }
-
- D("subproc_fde.state=%04x\n", subproc_fde->state);
- subproc_fde->events |= FDE_READ;
- if(subproc_fde->state & FDE_PENDING) {
- return;
- }
- subproc_fde->state |= FDE_PENDING;
- fdevent_call_fdfunc(subproc_fde);
- }
-}
-
-static void fdevent_subproc_setup()
-{
- int s[2];
-
- if(sdb_socketpair(s)) {
- FATAL("cannot create shell-exit socket-pair\n");
+ FD_SET(fd, &fds_read);
+ FD_SET(fd, &fds_write);
+ break;
}
- SHELL_EXIT_NOTIFY_FD = s[0];
- fdevent *fde;
- fde = fdevent_create(s[1], fdevent_subproc_event_func, NULL);
- if(!fde)
- FATAL("cannot create fdevent for shell-exit handler\n");
- fdevent_add(fde, FDE_READ);
}
static void _fdevent_loop()
{
- fdevent *fde;
- fdevent_subproc_setup();
+ while(1) {
+ fd_set rfd, wfd;
- for(;;) {
- D("--- ---- waiting for events\n");
+ memcpy(&rfd, &fds_read, sizeof(fd_set));
+ memcpy(&wfd, &fds_write, sizeof(fd_set));
- if (_fdevent_process() < 0) {
- return;
+ LOG_INFO("before select function, max_select %d\n", max_select);
+ int n = select(max_select, &rfd, &wfd, NULL, NULL);
+ LOG_INFO("%d events happens\n", n);
+
+ if(n < 0) {
+ LOG_ERROR("fatal error happens in select loop errno %d, strerr %s\n", errno, strerror(errno));
+ FD_ZERO(&wfd);
+ FD_ZERO(&rfd);
+ continue;
+ }
+ if(n == 0) {
+ LOG_ERROR("select returns 0\n");
+ continue;
}
- while((fde = fdevent_plist_dequeue())) {
- fdevent_call_fdfunc(fde);
+ int i = 0;
+ while( i < max_select) {
+ unsigned events = 0;
+
+ if(FD_ISSET(i, &rfd)) {
+ events |= FDE_READ;
+ }
+ if(FD_ISSET(i, &wfd)) {
+ events |= FDE_WRITE;
+ }
+
+ if(events) {
+ LOG_INFO("FD(%d) got events=%04x\n", i, events);
+ FD_EVENT* fde = fdevent_map_get(i);
+ if(fde == NULL) {
+ LOG_INFO("fdevent FD(%d) may be already closed\n", i);
+ i++;
+ continue;
+ }
+ events |= fde->events;
+ fde->func(fde->fd, events, fde->arg);
+ LOG_INFO("FD(%d) finished\n");
+ }
+ i++;
}
}
}
const struct fdevent_os_backend fdevent_unix_backend = {
- .name = "unix fdevent",
- .fdevent_init = _fdevent_init,
- .fdevent_connect = _fdevent_connect,
.fdevent_disconnect = _fdevent_disconnect,
.fdevent_update = _fdevent_update,
.fdevent_loop = _fdevent_loop
#include "utils_backend.h"
#include "fdevent_backend.h"
#include "transport.h"
+#include "log.h"
-#define D(...) ((void)0)
+static void alloc_event(SDB_SOCK_HANDLE* h) {
+ LOG_INFO("FD(%d), LOCATION(%d)\n", h->handle.fd, current_socket_location);
+ HANDLE event = WSACreateEvent();
+ socket_event_handle[current_socket_location] = event;
+ event_location_to_fd[current_socket_location] = h->handle.fd;
-static EventHook _free_hooks;
-
-static EventHook
-event_hook_alloc( FH fh )
-{
- EventHook hook = _free_hooks;
- if (hook != NULL)
- _free_hooks = hook->next;
- else {
- hook = malloc( sizeof(*hook) );
- if (hook == NULL) {
- //_fatal( "could not allocate event hook\n" );
- //TODO:
- }
- }
- hook->next = NULL;
- hook->fh = fh;
- hook->wanted = 0;
- hook->ready = 0;
- hook->h = INVALID_HANDLE_VALUE;
- hook->aux = NULL;
-
- hook->prepare = NULL;
- hook->start = NULL;
- hook->stop = NULL;
- hook->check = NULL;
- hook->peek = NULL;
-
- return hook;
+ h->event_location = current_socket_location;
+ current_socket_location++;
}
-static void
-event_hook_free( EventHook hook )
-{
- hook->fh = NULL;
- hook->wanted = 0;
- hook->ready = 0;
- hook->next = _free_hooks;
- _free_hooks = hook;
+static void free_event(SDB_SOCK_HANDLE* remove_h) {
+
+ LOG_INFO("FD(%d), LOCATION(%d), CUR_SOCKET(%d)\n", remove_h->handle.fd, remove_h->event_location, current_socket_location);
+
+ current_socket_location--;
+ int remove_location = remove_h->event_location;
+ remove_h->event_location = -1;
+ WSACloseEvent(socket_event_handle[remove_location]);
+ if(current_socket_location != remove_location) {
+ SDB_SOCK_HANDLE* replace_h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(event_location_to_fd[current_socket_location]);
+ replace_h->event_location = remove_location;
+ socket_event_handle[remove_location] = socket_event_handle[current_socket_location];
+ int replace_fd = event_location_to_fd[current_socket_location];
+ event_location_to_fd[remove_location] = replace_fd;
+ }
}
-
-static void
-event_hook_signal( EventHook hook )
-{
- FH f = hook->fh;
- int fd = _fh_to_int(f);
- fdevent* fde = fd_table[ fd - WIN32_FH_BASE ];
-
- if (fde != NULL && fde->fd == fd) {
- if ((fde->state & FDE_PENDING) == 0) {
- fde->state |= FDE_PENDING;
- fdevent_plist_enqueue( fde );
- }
- fde->events |= hook->wanted;
+static int _event_socket_verify(FD_EVENT* fde, WSANETWORKEVENTS* evts) {
+ if ((fde->events & FDE_READ) && (evts->lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))) {
+ return 1;
}
-}
-
-static EventHook*
-event_looper_find_p( EventLooper looper, FH fh )
-{
- EventHook *pnode = &looper->hooks;
- EventHook node = *pnode;
- for (;;) {
- if ( node == NULL || node->fh == fh )
- break;
- pnode = &node->next;
- node = *pnode;
+ if ((fde->events & FDE_WRITE) && (evts->lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE))) {
+ return 1;
}
- return pnode;
+ return 0;
}
-static void
-event_looper_hook( EventLooper looper, int fd, int events )
-{
- FH f = _fh_from_int(fd);
- EventHook *pnode;
- EventHook node;
+static int _socket_wanted_to_flags(int wanted) {
+ int flags = 0;
+ if (wanted & FDE_READ)
+ flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
- if (f == NULL) /* invalid arg */ {
- D("event_looper_hook: invalid fd=%d\n", fd);
- return;
- }
+ if (wanted & FDE_WRITE)
+ flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
- pnode = event_looper_find_p( looper, f );
- node = *pnode;
- if ( node == NULL ) {
- node = event_hook_alloc( f );
- node->next = *pnode;
- *pnode = node;
- }
-
- if ( (node->wanted & events) != events ) {
- /* this should update start/stop/check/peek */
- D("event_looper_hook: call hook for %d (new=%x, old=%x)\n",
- fd, node->wanted, events);
- f->clazz->_fh_hook( f, events & ~node->wanted, node );
- node->wanted |= events;
- } else {
- D("event_looper_hook: ignoring events %x for %d wanted=%x)\n",
- events, fd, node->wanted);
- }
+ return flags;
}
-static void
-event_looper_unhook( EventLooper looper, int fd, int events )
-{
- FH fh = _fh_from_int(fd);
- EventHook *pnode = event_looper_find_p( looper, fh );
- EventHook node = *pnode;
-
- if (node != NULL) {
- int events2 = events & node->wanted;
- if ( events2 == 0 ) {
- D( "event_looper_unhook: events %x not registered for fd %d\n", events, fd );
- return;
- }
- node->wanted &= ~events2;
- if (!node->wanted) {
- *pnode = node->next;
- event_hook_free( node );
- }
+static int _event_socket_start(FD_EVENT* fde) {
+ /* create an event which we're going to wait for */
+ int fd = fde->fd;
+ long flags = _socket_wanted_to_flags(fde->events);
+ SDB_SOCK_HANDLE* __h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fd);
+ LOG_INFO("FD(%d) LOCATION(%d)\n", fd, __h->event_location);
+ HANDLE event = socket_event_handle[__h->event_location];
+
+ if (event == INVALID_HANDLE_VALUE) {
+ LOG_ERROR( "no event for FD(%d)\n", fd);
+ return 0;
}
+ D( "_event_socket_start: hooking FD(%d) for %x (flags %ld)\n", fd, fde->events, flags);
+ if (WSAEventSelect(__h->handle.u.socket, event, flags)) {
+ LOG_ERROR( "_event_socket_start: WSAEventSelect() for FD(%d) failed, error %d\n", fd, WSAGetLastError());
+ exit(1);
+ return 0;
+ }
+ return 1;
}
-static EventLooperRec win32_looper;
-
-static void _fdevent_init(void)
-{
- win32_looper.htab_count = 0;
- win32_looper.hooks = NULL;
-}
-
-static void _fdevent_connect(fdevent *fde)
+static void _fdevent_disconnect(FD_EVENT *fde)
{
- EventLooper looper = &win32_looper;
- int events = fde->state & FDE_EVENTMASK;
-
- if (events != 0)
- event_looper_hook( looper, fde->fd, events );
-}
-
-static void _fdevent_disconnect(fdevent *fde)
-{
- EventLooper looper = &win32_looper;
- int events = fde->state & FDE_EVENTMASK;
-
- if (events != 0)
- event_looper_unhook( looper, fde->fd, events );
+ int events = fde->events;
+
+ if (events) {
+ SDB_SOCK_HANDLE* h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd);
+ if(h == NULL) {
+ LOG_ERROR("FDE of FD(%d) has no socket event handle\n", fde->fd);
+ return;
+ }
+ free_event(h);
+ }
}
-static void _fdevent_update(fdevent *fde, unsigned events)
+static void _fdevent_update(FD_EVENT *fde, unsigned events)
{
- EventLooper looper = &win32_looper;
- unsigned events0 = fde->state & FDE_EVENTMASK;
-
- if (events != events0) {
- int removes = events0 & ~events;
- int adds = events & ~events0;
- if (removes) {
- D("fdevent_update: remove %x from %d\n", removes, fde->fd);
- event_looper_unhook( looper, fde->fd, removes );
- }
- if (adds) {
- D("fdevent_update: add %x to %d\n", adds, fde->fd);
- event_looper_hook ( looper, fde->fd, adds );
- }
+ if(fde->events == events) {
+ return;
}
+
+ fde->events = events;
+ SDB_SOCK_HANDLE* h = (SDB_SOCK_HANDLE*)sdb_handle_map_get(fde->fd);
+ if(h == NULL) {
+ LOG_ERROR("invalid FD(%d)\n", fde->fd);
+ return;
+ }
+
+ if(h->event_location == -1) {
+ alloc_event(h);
+ }
+ _event_socket_start(fde);
}
-static void fdevent_process()
+void _fdevent_loop()
{
- EventLooper looper = &win32_looper;
- EventHook hook;
- int gotone = 0;
-
- /* if we have at least one ready hook, execute it/them */
- for (hook = looper->hooks; hook; hook = hook->next) {
- hook->ready = 0;
- if (hook->prepare) {
- hook->prepare(hook);
- if (hook->ready != 0) {
- event_hook_signal( hook );
- gotone = 1;
- }
- }
- }
-
- /* nothing's ready yet, so wait for something to happen */
- if (!gotone)
+ do
{
- looper->htab_count = 0;
-
- for (hook = looper->hooks; hook; hook = hook->next)
- {
- if (hook->start && !hook->start(hook)) {
- D( "fdevent_process: error when starting a hook\n" );
- return;
- }
- if (hook->h != INVALID_HANDLE_VALUE) {
- int nn;
-
- for (nn = 0; nn < looper->htab_count; nn++)
- {
- if ( looper->htab[nn] == hook->h )
- goto DontAdd;
- }
- looper->htab[ looper->htab_count++ ] = hook->h;
- DontAdd:
- ;
- }
+ if (current_socket_location == 0) {
+ D( "fdevent_process: nothing to wait for !!\n" );
+ continue;
+ }
+ LOG_INFO( "sdb_win32: fdevevnt loop for %d events start\n", current_socket_location );
+ if (current_socket_location > MAXIMUM_WAIT_OBJECTS) {
+ LOG_ERROR("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", current_socket_location);
+ abort();
}
+ int wait_ret = WaitForMultipleObjects( current_socket_location, socket_event_handle, FALSE, INFINITE );
- if (looper->htab_count == 0) {
- D( "fdevent_process: nothing to wait for !!\n" );
- return;
+ if(wait_ret == (int)WAIT_FAILED) {
+ LOG_ERROR( "sdb_win32: wait failed, error %ld\n", GetLastError() );
+ continue;
}
+ else {
- do
- {
- int wait_ret;
+ int _fd = event_location_to_fd[wait_ret];
+ LOG_INFO("wait success. FD(%d), LOCATION(%d)\n", _fd, wait_ret);
+ SDB_HANDLE* _h = sdb_handle_map_get(_fd);
+ WSANETWORKEVENTS evts;
- D( "sdb_win32: waiting for %d events\n", looper->htab_count );
- if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
- D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS, aborting!\n", looper->htab_count);
- abort();
- }
- wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
- if (wait_ret == (int)WAIT_FAILED) {
- D( "sdb_win32: wait failed, error %ld\n", GetLastError() );
- } else {
- D( "sdb_win32: got one (index %d)\n", wait_ret );
+ HANDLE event = socket_event_handle[wait_ret];
+ if(!WSAEnumNetworkEvents(_h->u.socket, event, &evts)) {
+ FD_EVENT* fde = fdevent_map_get(_fd);
+ if(_event_socket_verify(fde, &evts)) {
- /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
- * like mouse movements. we need to filter these with the "check" function
- */
- if ((unsigned)wait_ret < (unsigned)looper->htab_count)
- {
- for (hook = looper->hooks; hook; hook = hook->next)
- {
- if ( looper->htab[wait_ret] == hook->h &&
- (!hook->check || hook->check(hook)) )
- {
- D( "sdb_win32: signaling %s for %x\n", hook->fh->name, hook->ready );
- event_hook_signal( hook );
- gotone = 1;
- break;
- }
- }
- }
- }
- }
- while (!gotone);
- for (hook = looper->hooks; hook; hook = hook->next) {
- if (hook->stop)
- hook->stop( hook );
- }
- }
-
- for (hook = looper->hooks; hook; hook = hook->next) {
- if (hook->peek && hook->peek(hook))
- event_hook_signal( hook );
- }
-}
-
-void _fdevent_loop()
-{
- fdevent *fde;
+ if (fde != NULL && fde->fd == _fd) {
+ LOG_INFO("FD(%d) start\n", fde->fd);
+ fde->func(fde->fd, fde->events, fde->arg);
+ LOG_INFO("FD(%d) end\n", fde->fd);
+ }
+ }
+ else {
+ LOG_INFO("verify failed\n");
+ }
- for(;;) {
-#if DEBUG
- fprintf(stderr,"--- ---- waiting for events\n");
-#endif
- fdevent_process();
- while((fde = fdevent_plist_dequeue())) {
- unsigned events = fde->events;
- fde->events = 0;
- fde->state &= (~FDE_PENDING);
- dump_fde(fde, "callback");
- fde->func(fde->fd, events, fde->arg);
+ }
}
}
+ while (1);
}
const struct fdevent_os_backend fdevent_windows_backend = {
- .name = "windows fdevent",
- .fdevent_init = _fdevent_init,
- .fdevent_connect = _fdevent_connect,
.fdevent_disconnect = _fdevent_disconnect,
.fdevent_update = _fdevent_update,
.fdevent_loop = _fdevent_loop
#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);
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;
}
}
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;
}
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();
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);
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);
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;
}
/* 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) {
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++;
}
}
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;
}
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++;
}
}
}
}
- 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;
#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,
};
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,
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) {
}
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));
}
}
-//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);
}
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);
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);
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)) {
}
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);
}
}
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);
}
//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;
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)) ||
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))) {
return -1;
}
- if(msg.status.id != ID_OKAY) {
+ if(msg.status.id != sync_okay) {
char buf[256];
- if(msg.status.id == ID_FAIL) {
+ if(msg.status.id == sync_fail) {
int len = ltohl(msg.status.msglen);
if(len > 256) {
len = 255;
//-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;
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))) {
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;
}
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;
}
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)) {
}
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);
COPY_INFO* info;
create_copy_info(&info, src_full_path, dst_full_path);
- append(dirlist, info);
+ prepend(dirlist, info);
}
closedir(d);
}
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);
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;
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;
}
#define TRACE_TAG TRACE_SDB
+#include <sys/stat.h>
#include "file_sync_service.h"
#include "linkedlist.h"
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);
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_ */
#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
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;
//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.
}
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);
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);
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_ */
--- /dev/null
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "listener.h"
+#include "fdevent.h"
+#include "utils.h"
+#include "sockets.h"
+
+LIST_NODE* listener_list = NULL;
+
+static void listener_event_func(int _fd, unsigned ev, void *_l);
+static LISTENER* find_listener(const char *local_name);
+
+void free_listener(void* data)
+{
+ LISTENER* listener = data;
+ fdevent_remove(&(listener->fde));
+ free((void*)listener->local_name);
+ free((void*)listener->connect_to);
+ free(listener);
+}
+
+int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport)
+{
+ D("LN(%s)\n", local_name);
+
+ LISTENER* listener = find_listener(local_name);
+
+ if(listener != NULL) {
+ char *cto;
+
+ /* can't repurpose a smartsocket */
+ if(listener->connect_to[0] == '*') {
+ return -1;
+ }
+
+ cto = strdup(connect_to);
+ if(cto == 0) {
+ return -1;
+ }
+
+ //printf("rebinding '%s' to '%s'\n", local_name, connect_to);
+ free((void*) listener->connect_to);
+ listener->connect_to = cto;
+ if (listener->transport != transport) {
+ listener->transport = transport;
+ }
+ return 0;
+ }
+
+ if(strncmp("tcp:", local_name, 4)){
+ LOG_FATAL("LN(%s) unknown local portname\n", local_name);
+ return -2;
+ }
+
+ int port = atoi(local_name + 4);
+
+ //TODO REMOTE_DEVICE_CONNECT block remote connect until security issue is cleard
+// int fd = sdb_port_listen(INADDR_ANY, port, SOCK_STREAM);
+ int fd = sdb_port_listen(INADDR_LOOPBACK, port, SOCK_STREAM);
+
+ if(fd < 0) {
+ LOG_FATAL("LN(%s) cannot bind\n", local_name);
+ return -2;
+ }
+
+ listener = calloc(1, sizeof(LISTENER));
+ listener->local_name = strdup(local_name);
+ listener->connect_to = strdup(connect_to);
+ listener->fd = fd;
+ listener->node = prepend(&listener_list, listener);
+ listener->transport = transport;
+ close_on_exec(fd);
+ fdevent_install(&listener->fde, fd, listener_event_func, listener);
+ FDEVENT_SET(&listener->fde, FDE_READ);
+ return 0;
+}
+
+int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport)
+{
+ D("LN(%s)\n", local_name);
+ LISTENER* listener = find_listener(local_name);
+
+ if(listener != NULL &&
+ !strcmp(connect_to, listener->connect_to) &&
+ listener->transport != NULL &&
+ listener->transport == transport) {
+ remove_node(&listener_list, listener->node, free_listener);
+ D("LN(%s) removed\n", local_name);
+ return 0;
+ }
+
+ D("LN(%s) could not find\n", local_name);
+ return -1;
+}
+
+static void listener_event_func(int _fd, unsigned ev, void *_l)
+{
+ LISTENER *l = _l;
+ D("LN(%s)\n", l->local_name);
+
+ if(ev & FDE_READ) {
+ int fd = sdb_socket_accept(_fd);
+
+ if(fd < 0) {
+ D("LN(%s) fail to create\n", l->local_name);
+ return;
+ }
+
+ SDB_SOCKET *s = create_local_socket(fd);
+
+ int ss = 0;
+ if(!strcmp(l->connect_to, "*smartsocket*")) {
+ ss = 1;
+ }
+
+ if(ss) {
+ sdb_socket_setbufsize(fd, CHUNK_SIZE);
+ }
+ if(s) {
+
+ if(ss) {
+ local_socket_ready(s);
+ }
+ else {
+
+ if(l->transport->type == kTransportRemoteDevCon) {
+ if(assign_remote_connect_socket_rid(s)) {
+ local_socket_close(s);
+ return;
+ }
+ }
+
+ s->transport = l->transport;
+ connect_to_remote(s, l->connect_to);
+ }
+ return;
+ }
+
+ sdb_close(fd);
+ }
+}
+
+static LISTENER* find_listener(const char *local_name) {
+ LIST_NODE* currentptr = listener_list;
+ while(currentptr != NULL) {
+ LISTENER* l = currentptr->data;
+ currentptr = currentptr->next_ptr;
+ if(!strcmp(local_name, l->local_name)) {
+ return l;
+ }
+ }
+ return NULL;
+}
--- /dev/null
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef 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_ */
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h> // for using va_list
+#include "log.h"
+#include "utils.h"
+
+int loglevel_mask;
+
+static struct {
+ char* name;
+ LogLevel level;
+} log_levels[] = {
+ { "all", 0 },
+ { "fatal", SDBLOG_FATAL },
+ { "error", SDBLOG_ERROR },
+ { "debug", SDBLOG_DEBUG },
+ { "info", SDBLOG_INFO },
+ { "fixme", SDBLOG_FIXME },
+ { NULL, 0 }
+};
+
+void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...) {
+ char *name = NULL;
+ char mbuf[1024];
+ char fbuf[1024];
+ va_list args;
+
+ va_start(args, fmt);
+
+ switch (level) {
+ case SDBLOG_FATAL:
+ name = log_levels[SDBLOG_FATAL].name;
+ break;
+ case SDBLOG_ERROR:
+ name = log_levels[SDBLOG_ERROR].name;
+ break;
+ case SDBLOG_INFO:
+ name = log_levels[SDBLOG_INFO].name;
+ break;
+ case SDBLOG_DEBUG:
+ name = log_levels[SDBLOG_DEBUG].name;;
+ break;
+ case SDBLOG_FIXME:
+ name = log_levels[SDBLOG_FIXME].name;
+ break;
+ default:
+ name = log_levels[SDBLOG_INFO].name;
+ break;
+ }
+ snprintf(fbuf, sizeof(fbuf), "[%s][%s:%s():%d]%s", name, filename, funcname, line_number, fmt);
+ vsnprintf(mbuf, sizeof(mbuf), fbuf, args);
+ sdb_mutex_lock(&D_lock, NULL);
+ fprintf(stderr, "%s", mbuf);
+ sdb_mutex_unlock(&D_lock, NULL);
+ fflush(stderr);
+ va_end(args);
+}
+
+static void log_parse(char* args) {
+ char *level, *levels, *next;
+
+ levels = strdup(args);
+ if (levels == NULL) {
+ return;
+ }
+ int i=0;
+ for (level = levels; level; level = next) {
+ next = strchr(level, ',' );
+ if (next != NULL) {
+ *next++ = 0;
+ }
+
+ for (i = 0; log_levels[i].name != NULL; i++) {
+ if (!strcmp(level, log_levels[i].name))
+ {
+ if (!strcmp("all",log_levels[i].name)) {
+ loglevel_mask = ~0;
+ free(levels);
+ return;
+ }
+ loglevel_mask |= 1 << log_levels[i].level;
+ break;
+ }
+ }
+ }
+ free(levels);
+}
+
+void log_init(void)
+{
+ char* sdb_debug = NULL;
+
+ if ((sdb_debug = getenv(DEBUG_ENV))) {
+ log_parse(sdb_debug);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LOG_H
+#define __LOG_H
+
+#define SDB_TRACE 1
+#define DEBUG_ENV "SDB_DEBUG"
+extern int loglevel_mask;
+
+typedef enum {
+ SDBLOG_FATAL = 1,
+ SDBLOG_ERROR,
+ SDBLOG_DEBUG,
+ SDBLOG_INFO,
+ SDBLOG_FIXME
+} LogLevel;
+
+#define LOG_FATAL(args...) \
+ do { \
+ logging(SDBLOG_FATAL, __FILE__, __FUNCTION__, __LINE__, args);\
+ exit(255);} while(0)
+
+#define LOG_ASSERT(cond) do { if (!(cond)) LOG_FATAL( "assertion failed '%s'\n", #cond); } while (0)
+
+
+#define LOG_ERROR(args...) \
+ do { if ((loglevel_mask & (1 << SDBLOG_ERROR)) != 0) { \
+ logging(SDBLOG_ERROR, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+#define LOG_DEBUG(args...) \
+ do { if ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0) { \
+ logging(SDBLOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+#define LOG_INFO(args...) \
+ do { if ((loglevel_mask & (1 << SDBLOG_INFO)) != 0) { \
+ logging(SDBLOG_INFO, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+#define LOG_FIXME(args...) \
+ do { if ((loglevel_mask & (1 << SDBLOG_FIXME)) != 0) { \
+ logging(SDBLOG_FIXME, __FILE__, __FUNCTION__, __LINE__, args); } } while(0)
+
+void log_init(void);
+void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...);
+
+// define for a while for testing
+#undef D
+#define D LOG_DEBUG
+#undef DR
+#define DR LOG_DEBUG
+#define SDB_TRACING ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0)
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "log.h"
+#include "strutils.h"
+
+static size_t total_mem = 0;
+
+// added size of size_t to know how many bytes have been allocated.
+
+void *s_malloc(size_t size) {
+ void *ptr = malloc(size + sizeof(size_t));
+
+ if (ptr == NULL) {
+ LOG_FATAL("cannot allocate memory:%d bytes\n", (int ) size);
+ }
+ *(size_t*) ptr = size;
+
+ total_mem += size;
+
+ LOG_DEBUG("memory allocated:%u bytes / %u bytes\n", size, total_mem);
+
+ return ptr + sizeof(size_t);
+}
+
+void *s_realloc(void *ptr, size_t new_size) {
+ void *new_ptr;
+ size_t org_size;
+
+ if (ptr == NULL) {
+ LOG_FATAL("null argument in!!\n");
+ }
+
+ new_ptr = realloc(ptr - sizeof(size_t), new_size + sizeof(size_t));
+ if (new_ptr == NULL) {
+ LOG_FATAL("cannot allocate new memory:%d bytes\n", (int ) new_size);
+ }
+ org_size = *(size_t*) (ptr - sizeof(size_t));
+ *(size_t*) new_ptr = new_size;
+ total_mem += new_size - org_size;
+
+ LOG_DEBUG("memory allocated:%u bytes -> %u bytes / %u bytes\n", org_size, new_size, total_mem);
+
+ return new_ptr + sizeof(size_t);
+}
+
+void s_free(void *ptr) {
+ size_t size;
+
+ if (ptr == NULL) {
+ return;
+ }
+
+ size = *(size_t*) (ptr - sizeof(size_t));
+ total_mem -= size;
+
+ free(ptr - sizeof(size_t));
+
+ LOG_DEBUG("memory freed:%u bytes / %u\n", size, total_mem);
+
+}
+
+char *s_strdup(const char *str) {
+ if (str == NULL) {
+ return NULL;
+ }
+ int len = strlen(str) + 1;
+
+ char *ptr = s_malloc(len);
+
+ s_strncpy(ptr, str, len);
+ return ptr;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _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
+
#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)
}
#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.
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);
#endif
start_logging();
}
- D("Event loop starting\n");
-
- fdevent_loop();
+ LOG_INFO("Event loop starting\n");
+ FDEVENT_LOOP();
atexit(sdb_cleanup);
-
return 0;
}
-void connect_device(char* host, char* buffer, int buffer_size)
+static void local_init(int port)
{
- int port, fd;
- char* portstr = strchr(host, ':');
- char hostbuf[100];
- char serial[100];
-
- strncpy(hostbuf, host, sizeof(hostbuf) - 1);
- if (portstr) {
- if (portstr - host >= sizeof(hostbuf)) {
- snprintf(buffer, buffer_size, "bad host name %s", host);
- return;
- }
- // zero terminate the host at the point we found the colon
- hostbuf[portstr - host] = 0;
- if (sscanf(portstr + 1, "%d", &port) == 0) {
- snprintf(buffer, buffer_size, "bad port number %s", portstr);
- return;
- }
- } else {
+ if(port < 1024) {
port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
}
+ int count = SDB_LOCAL_TRANSPORT_MAX;
- snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
- if (find_transport(serial)) {
- snprintf(buffer, buffer_size, "already connected to %s", serial);
- return;
- }
-
- fd = socket_network_client(hostbuf, port, SOCK_STREAM);
- if (fd < 0) {
- snprintf(buffer, buffer_size, "unable to connect to %s", host);
- return;
+ LOG_INFO("try to connect to emulator instances when booting sdb server up\n");
+ for ( ; count > 0; count--, port += 10 ) {
+ (void) local_connect(port, NULL);
}
-
- D("client: connected on remote on fd %d\n", fd);
- close_on_exec(fd);
- disable_tcp_nagle(fd);
- register_socket_transport(fd, serial, port, 0, NULL);
- snprintf(buffer, buffer_size, "connected to %s", serial);
}
-void connect_emulator(char* port_spec, char* buffer, int buffer_size)
-{
- char* port_separator = strchr(port_spec, ',');
- if (!port_separator) {
- snprintf(buffer, buffer_size,
- "unable to parse '%s' as <console port>,<sdb port>",
- port_spec);
- return;
- }
- // Zero-terminate console port and make port_separator point to 2nd port.
- *port_separator++ = 0;
- int console_port = strtol(port_spec, NULL, 0);
- int sdb_port = strtol(port_separator, NULL, 0);
- if (!(console_port > 0 && sdb_port > 0)) {
- *(port_separator - 1) = ',';
- snprintf(buffer, buffer_size,
- "Invalid port numbers: Expected positive numbers, got '%s'",
- port_spec);
- return;
- }
+void init_wakeup_select_func() {
+ D("initialize select wakeup func\n");
+ int socket_pair[2];
- /* Check if the emulator is already known.
- * Note: There's a small but harmless race condition here: An emulator not
- * present just yet could be registered by another invocation right
- * after doing this check here. However, local_connect protects
- * against double-registration too. From here, a better error message
- * can be produced. In the case of the race condition, the very specific
- * error message won't be shown, but the data doesn't get corrupted. */
- atransport* known_emulator = find_emulator_transport_by_sdb_port(sdb_port);
- if (known_emulator != NULL) {
- snprintf(buffer, buffer_size,
- "Emulator on port %d already registered.", sdb_port);
+ if(sdb_socketpair(socket_pair)){
+ D("cannot open select wakeup socketpair\n");
return;
}
+ fdevent_wakeup_send = socket_pair[0];
+ fdevent_wakeup_recv = socket_pair[1];
- /* Check if more emulators can be registered. Similar unproblematic
- * race condition as above. */
- int candidate_slot = get_available_local_transport_index();
- if (candidate_slot < 0) {
- snprintf(buffer, buffer_size, "Cannot accept more emulators.");
- return;
- }
-
- /* Preconditions met, try to connect to the emulator. */
- if (!local_connect_arbitrary_ports(console_port, sdb_port, NULL)) {
- snprintf(buffer, buffer_size,
- "Connected to emulator on ports %d,%d", console_port, sdb_port);
- } else {
- snprintf(buffer, buffer_size,
- "Could not connect to emulator on ports %d,%d",
- console_port, sdb_port);
- }
-}
-
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
-{
- atransport *transport = NULL;
- char buf[4096];
+ fdevent_install(&fdevent_wakeup_fde,
+ fdevent_wakeup_recv,
+ wakeup_select_func,
+ 0);
- if(!strcmp(service, "kill")) {
- fprintf(stderr,"sdb server killed by remote request\n");
- fflush(stdout);
- sdb_write(reply_fd, "OKAY", 4);
- sdb_cleanup();
- exit(0);
- }
-
- // "transport:" is used for switching transport with a specified serial number
- // "transport-usb:" is used for switching transport to the only USB transport
- // "transport-local:" is used for switching transport to the only local transport
- // "transport-any:" is used for switching transport to the only transport
- if (!strncmp(service, "transport", strlen("transport"))) {
- char* error_string = "unknown failure";
- transport_type type = kTransportAny;
-
- if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
- type = kTransportUsb;
- } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
- type = kTransportLocal;
- } else if (!strncmp(service, "transport-any", strlen("transport-any"))) {
- type = kTransportAny;
- } else if (!strncmp(service, "transport:", strlen("transport:"))) {
- service += strlen("transport:");
- serial = service;
- }
-
- transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
-
- if (transport) {
- s->transport = transport;
- sdb_write(reply_fd, "OKAY", 4);
- } else {
- sendfailmsg(reply_fd, error_string);
- }
- return 1;
- }
-
- // find a device which prefix match the partial serial num
- // for example, there are two devices
- // fjldsads9uq2oeu
- // fjkuiaoejlfamck
- // to make user's life more easier, it can specify a device with
- // it's uniq prefix, in the above example, that means
- // fjl <==> fjldsads9uq2oeu
- // fjk <==> fjkuiaoejlfamck
- if (!strncmp(service, "serial-match:", 13)) {
- char *tmp = service + 13;
- char *serial = NULL;
- int ret = -1;
- D("Try to find device for: %s\n", tmp);
- ret = find_transports(&serial, tmp);
- if (ret <= 0) {
- D("No device found\n");
- snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(serial), serial);
- } else if (ret == 1) {
- D("found device: %s\n", serial);
- snprintf(buf, sizeof(buf), "OKAY%04x%s", (unsigned)strlen(serial), serial);
- } else {
- D("found more than one devices matched: %d\n", ret);
- snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(serial), serial);
- }
-
- writex(reply_fd, buf, strlen(buf));
- free(serial);
- return 0;
- }
- // return a list of all connected devices
- if (!strcmp(service, "devices")) {
- char buffer[4096];
- memset(buf, 0, sizeof(buf));
- memset(buffer, 0, sizeof(buffer));
- D("Getting device list \n");
- list_transports(buffer, sizeof(buffer));
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
- D("Wrote device list \n");
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
-
- // add a new TCP transport, device or emulator
- if (!strncmp(service, "connect:", 8)) {
- char buffer[4096];
- char* host = service + 8;
- if (!strncmp(host, "emu:", 4)) {
- connect_emulator(host + 4, buffer, sizeof(buffer));
- } else {
- connect_device(host, buffer, sizeof(buffer));
- }
- // Send response for emulator and device
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
-
- // remove TCP transport
- if (!strncmp(service, "disconnect:", 11)) {
- char buffer[4096];
- memset(buffer, 0, sizeof(buffer));
- char* serial = service + 11;
- if (serial[0] == 0) {
- // disconnect from all TCP devices
- unregister_all_tcp_transports();
- } else {
- char hostbuf[100];
- // assume port 26101 if no port is specified
- if (!strchr(serial, ':')) {
- snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:26101", serial);
- serial = hostbuf;
- }
- atransport *t = find_transport(serial);
-
- if (t) {
- unregister_transport(t);
- } else {
- snprintf(buffer, sizeof(buffer), "No such device %s", serial);
- }
- }
-
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
-
- // returns our value for SDB_SERVER_VERSION
- if (!strcmp(service, "version")) {
- char version[12];
- snprintf(version, sizeof version, "%04x", SDB_SERVER_VERSION);
- snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
-
- if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
- char *out = "unknown";
- transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
- if (transport && transport->serial) {
- out = transport->serial;
- }
- snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
- // indicates a new emulator instance has started
- if (!strncmp(service,"emulator:",9)) { /* tizen specific */
- char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR);
- int port = 0;
-
- if (tmp == NULL) {
- port = atoi(service+9);
- } else {
- port = atoi(tmp);
- tmp = strtok(NULL, DEVICEMAP_SEPARATOR);
- if (tmp != NULL) {
- local_connect(port, tmp);
- }
- }
- local_connect(port, NULL);
- return 0;
- }
-
- if(!strncmp(service,"forward:",8) || !strncmp(service,"killforward:",12)) {
- char *local, *remote, *err;
- int r;
- atransport *transport;
-
- int createForward = strncmp(service,"kill",4);
-
- local = service + (createForward ? 8 : 12);
- remote = strchr(local,';');
- if(remote == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
-
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
-
- transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
- if (!transport) {
- sendfailmsg(reply_fd, err);
- return 0;
- }
-
- if (createForward) {
- r = install_listener(local, remote, transport);
- } else {
- r = remove_listener(local, remote, transport);
- }
- if(r == 0) {
- /* 1st OKAY is connect, 2nd OKAY is status */
- writex(reply_fd, "OKAYOKAY", 8);
- return 0;
- }
-
- if (createForward) {
- sendfailmsg(reply_fd, (r == -1) ? "cannot rebind smartsocket" : "cannot bind socket");
- } else {
- sendfailmsg(reply_fd, "cannot remove listener");
- }
- return 0;
- }
-
- if(!strncmp(service,"get-state",strlen("get-state"))) {
- transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
- char *state = connection_state_name(transport);
- snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
- writex(reply_fd, buf, strlen(buf));
- return 0;
- }
- return -1;
+ FDEVENT_SET(&fdevent_wakeup_fde, FDE_READ);
}
int main(int argc, char **argv)
{
- sdb_trace_init();
+ log_init();
sdb_sysdeps_init();
+ init_map();
return process_cmdline(argc - 1, argv + 1);
}
#include <limits.h>
+#include "linkedlist.h"
#include "transport.h" /* readx(), writex() */
#include "sdb_usb.h"
-
-#define MAX_PAYLOAD 4096
-
-#define A_SYNC 0x434e5953
-#define A_CNXN 0x4e584e43
-#define A_OPEN 0x4e45504f
-#define A_OKAY 0x59414b4f
-#define A_CLSE 0x45534c43
-#define A_WRTE 0x45545257
-
-#define A_VERSION 0x01000000 // SDB protocol version
-
-#define SDB_VERSION_MAJOR 2 // Used for help/version information
-#define SDB_VERSION_MINOR 2 // Used for help/version information
-
-#define SDB_SERVER_VERSION 5 // Increment this when we want to force users to start a new sdb server
-
-typedef struct amessage amessage;
-typedef struct apacket apacket;
-typedef struct asocket asocket;
-typedef struct alistener alistener;
-typedef struct aservice aservice;
-typedef struct atransport atransport;
-typedef struct adisconnect adisconnect;
-
-struct amessage {
- unsigned command; /* command identifier constant */
- unsigned arg0; /* first argument */
- unsigned arg1; /* second argument */
- unsigned data_length; /* length of payload (0 is allowed) */
- unsigned data_check; /* checksum of data payload */
- unsigned magic; /* command ^ 0xffffffff */
-};
-
-struct apacket
-{
- apacket *next;
-
- unsigned len;
- unsigned char *ptr;
-
- amessage msg;
- unsigned char data[MAX_PAYLOAD];
-};
-
-/* An asocket represents one half of a connection between a local and
-** remote entity. A local asocket is bound to a file descriptor. A
-** remote asocket is bound to the protocol engine.
-*/
-struct asocket {
- /* chain pointers for the local/remote list of
- ** asockets that this asocket lives in
- */
- asocket *next;
- asocket *prev;
-
- /* the unique identifier for this asocket
- */
- unsigned id;
-
- /* flag: set when the socket's peer has closed
- ** but packets are still queued for delivery
- */
- int closing;
-
- /* flag: quit sdbd when both ends close the
- ** local service socket
- */
- int exit_on_close;
-
- /* the asocket we are connected to
- */
-
- asocket *peer;
-
- /* For local asockets, the fde is used to bind
- ** us to our fd event system. For remote asockets
- ** these fields are not used.
- */
- fdevent fde;
- int fd;
-
- /* queue of apackets waiting to be written
- */
- apacket *pkt_first;
- apacket *pkt_last;
-
- /* enqueue is called by our peer when it has data
- ** for us. It should return 0 if we can accept more
- ** data or 1 if not. If we return 1, we must call
- ** peer->ready() when we once again are ready to
- ** receive data.
- */
- int (*enqueue)(asocket *s, apacket *pkt);
-
- /* ready is called by the peer when it is ready for
- ** us to send data via enqueue again
- */
- void (*ready)(asocket *s);
-
- /* close is called by the peer when it has gone away.
- ** we are not allowed to make any further calls on the
- ** peer once our close method is called.
- */
- void (*close)(asocket *s);
-
- /* socket-type-specific extradata */
- void *extra;
-
- /* A socket is bound to atransport */
- atransport *transport;
-};
-
-
-/* the adisconnect structure is used to record a callback that
-** will be called whenever a transport is disconnected (e.g. by the user)
-** this should be used to cleanup objects that depend on the
-** transport (e.g. remote sockets, listeners, etc...)
-*/
-struct adisconnect
-{
- void (*func)(void* opaque, atransport* t);
- void* opaque;
- adisconnect* next;
- adisconnect* prev;
-};
-
-
-/* a transport object models the connection to a remote device or emulator
-** there is one transport per connected device/emulator. a "local transport"
-** connects through TCP (for the emulator), while a "usb transport" through
-** USB (for real devices)
-**
-** note that kTransportHost doesn't really correspond to a real transport
-** object, it's a special value used to indicate that a client wants to
-** connect to a service implemented within the SDB server itself.
-*/
-typedef enum transport_type {
- kTransportUsb,
- kTransportLocal,
- kTransportAny,
- kTransportHost,
-} transport_type;
-
-struct atransport
-{
- atransport *next;
- atransport *prev;
-
- int (*read_from_remote)(apacket *p, atransport *t);
- int (*write_to_remote)(apacket *p, atransport *t);
- void (*close)(atransport *t);
- void (*kick)(atransport *t);
-
- int fd;
- int transport_socket;
- fdevent transport_fde;
- int ref_count;
- unsigned sync_token;
- int connection_state;
- transport_type type;
-
- /* usb handle or socket fd as needed */
- usb_handle *usb;
- int sfd;
-
- /* used to identify transports for clients */
- char *serial;
- char *product;
- int sdb_port; // Use for emulators (local transport)
- char *device_name; // for connection explorer
-
- /* a list of adisconnect callbacks called when the transport is kicked */
- int kicked;
- adisconnect disconnects;
-};
-
-
-/* A listener is an entity which binds to a local port
-** and, upon receiving a connection on that port, creates
-** an asocket to connect the new local connection to a
-** specific remote service.
-**
-** TODO: some listeners read from the new connection to
-** determine what exact service to connect to on the far
-** side.
-*/
-struct alistener
-{
- alistener *next;
- alistener *prev;
-
- fdevent fde;
- int fd;
-
- const char *local_name;
- const char *connect_to;
- atransport *transport;
- adisconnect disconnect;
-};
-
-
-void print_packet(const char *label, apacket *p);
-
-asocket *find_local_socket(unsigned id);
-void install_local_socket(asocket *s);
-void remove_socket(asocket *s);
-void close_all_sockets(atransport *t);
-
-#define LOCAL_CLIENT_PREFIX "emulator-"
-
-asocket *create_local_socket(int fd);
-asocket *create_local_service_socket(const char *destination);
-
-asocket *create_remote_socket(unsigned id, atransport *t);
-void connect_to_remote(asocket *s, const char *destination);
-void connect_to_smartsocket(asocket *s);
-
-void fatal(const char *fmt, ...);
-void fatal_errno(const char *fmt, ...);
-
-void handle_packet(apacket *p, atransport *t);
-void send_packet(apacket *p, atransport *t);
+#include "log.h"
+#include "sdb_map.h"
int sdb_main(int is_daemon, int server_port);
-
-/* transports are ref-counted
-** get_device_transport does an acquire on your behalf before returning
-*/
-void init_transport_registration(void);
-int find_transports(char **serial, const char *prefix);
-int list_transports(char *buf, size_t bufsize);
-void update_transports(void);
-
-asocket* create_device_tracker(void);
-
-/* Obtain a transport from the available transports.
-** If state is != CS_ANY, only transports in that state are considered.
-** If serial is non-NULL then only the device with that serial will be chosen.
-** If no suitable transport is found, error is set.
-*/
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out);
-void add_transport_disconnect( atransport* t, adisconnect* dis );
-void remove_transport_disconnect( atransport* t, adisconnect* dis );
-void run_transport_disconnects( atransport* t );
-void kick_transport( atransport* t );
-
-/* initialize a transport object's func pointers and state */
-int get_available_local_transport_index();
-int init_socket_transport(atransport *t, int s, int port, int local);
-void init_usb_transport(atransport *t, usb_handle *usb, int state);
-void close_usb_devices();
-
-
-/* cause new transports to be init'd and added to the list */
-void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name);
-
-/* these should only be used for the "sdb disconnect" command */
-void unregister_transport(atransport *t);
-void unregister_all_tcp_transports();
-
-void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
-
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb);
-
-atransport *find_transport(const char *serial);
-atransport* find_emulator_transport_by_sdb_port(int sdb_port);
-
-int service_to_fd(const char *name);
-asocket *host_service_to_socket(const char* name, const char *serial);
-
-/* packet allocator */
-apacket *get_apacket(void);
-void put_apacket(apacket *p);
-
-int check_header(apacket *p);
-int check_data(apacket *p);
-
-/* define SDB_TRACE to 1 to enable tracing support, or 0 to disable it */
-
-#define SDB_TRACE 1
-
-/* IMPORTANT: if you change the following list, don't
- * forget to update the corresponding 'tags' table in
- * the sdb_trace_init() function implemented in sdb.c
- */
-typedef enum {
- TRACE_SDB = 0,
- TRACE_SOCKETS,
- TRACE_PACKETS,
- TRACE_TRANSPORT,
- TRACE_RWX,
- TRACE_USB,
- TRACE_SYNC,
- TRACE_SYSDEPS,
- TRACE_JDWP,
- TRACE_SERVICES,
- TRACE_PROPERTIES
-} SdbTrace;
-
-#if SDB_TRACE
-
-#define DQ(...) ((void)0)
-
-
- extern int sdb_trace_mask;
- extern unsigned char sdb_trace_output_count;
- void sdb_trace_init(void);
-
-# define SDB_TRACING ((sdb_trace_mask & (1 << TRACE_TAG)) != 0)
-
- /* you must define TRACE_TAG before using this macro */
-# define D(...) \
- do { \
- if (SDB_TRACING) { \
- int save_errno = errno; \
- sdb_mutex_lock(&D_lock); \
- fprintf(stderr, "%s::%s():", \
- __FILE__, __FUNCTION__); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__ ); \
- fflush(stderr); \
- sdb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } \
- } while (0)
-# define DR(...) \
- do { \
- if (SDB_TRACING) { \
- int save_errno = errno; \
- sdb_mutex_lock(&D_lock); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__ ); \
- fflush(stderr); \
- sdb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } \
- } while (0)
-#else
-# define D(...) ((void)0)
-# define DR(...) ((void)0)
-# define SDB_TRACING 0
-#endif
-
-
-#if !TRACE_PACKETS
-#define print_packet(tag,p) do {} while (0)
-#endif
-
-
-/* sdb and sdbd are coexisting on the target, so use 26099 for sdb
- * to avoid conflicting with sdbd's usage of 26098
- */
-#define DEFAULT_SDB_PORT 26099 /* tizen specific */
-#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 /* tizen specific */
-
-void local_init(int port);
-int local_connect(int port, const char *device_name);
-int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name);
-
-
unsigned host_to_le32(unsigned n);
int sdb_commandline(int argc, char **argv);
-int connection_state(atransport *t);
+int connection_state(TRANSPORT *t);
-#define CS_ANY -1
-#define CS_OFFLINE 0
-#define CS_BOOTLOADER 1
-#define CS_DEVICE 2
-#define CS_HOST 3
-#define CS_RECOVERY 4
-#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
-#define CS_SIDELOAD 6
-
-extern int HOST;
extern int SHELL_EXIT_NOTIFY_FD;
-#define CHUNK_SIZE (64*1024)
-
-int sendfailmsg(int fd, const char *reason);
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
+void sdb_cleanup(void);
-void register_device_name(const char *device_type, const char *device_name, int port);
-int get_devicename_from_shdmem(int port, char *device_name);
#endif
#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;
}
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;
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;
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) {
ver_num = ++null;
null = strchr(ver_num, '.');
+ if(null == NULL) {
+ goto error;
+ }
+
version = atoi(ver_num);
*null = '\0';
if(version > middle) {
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;
}
}
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;
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;
}
return fd;
}
-int __inline__ read_msg_size(int fd) {
+int read_msg_size(int fd) {
char buf[5];
if(readx(fd, buf, 4)) {
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
}
if(version != SDB_SERVER_VERSION) {
- printf("sdb server is out of date. killing...\n");
+ printf("client version: %d, server version: %d\nsdb server is out of date. killing...\n", version, SDB_SERVER_VERSION);
fd = _sdb_connect("host:kill", ext_args);
sdb_close(fd);
return -1;
}
- if(sdb_status(fd)) {
+ if(sdb_status(fd, 0)) {
sdb_close(fd);
return -1;
}
}
}
else {
- char* temp_prefix;
+ char* temp_prefix = NULL;
if(ttype == kTransportUsb) {
if(host_type == host) {
temp_prefix = (char*)PREFIX_HOST_USB;
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;
#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
** 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
const char* QUOTE_CHAR = " \"\\()";
const char* PREFIX_HOST = "host:";
+ const char* PREFIX_HOST_ANY = "host-any:";
const char* PREFIX_HOST_USB = "host-usb:";
const char* PREFIX_HOST_LOCAL = "host-local:";
const char* PREFIX_HOST_SERIAL = "host-serial:";
const int COMMANDLINE_CONNECT_MAX_ARG = 1;
const int COMMANDLINE_CONNECT_MIN_ARG = 1;
+ const char* COMMANDLINE_DEVICE_CON_NAME = "device_con";
+ const char* COMMANDLINE_DEVICE_CON_DESC[] = {
+ "connect to a remote device"
+ };
+ const int COMMANDLINE_DEVICE_CON_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DEVICE_CON_DESC, char*);
+ const char* COMMANDLINE_DEVICE_CON_ARG_DESC = "<host> <device serial-number>";
+ const int COMMANDLINE_DEVICE_CON_MAX_ARG = 2;
+ const int COMMANDLINE_DEVICE_CON_MIN_ARG = 2;
+
const char* COMMANDLINE_GSERIAL_NAME = "get-serialno";
const char* COMMANDLINE_GSERIAL_DESC[] = {
"print: <serial-number>"
const char* COMMANDLINE_GSTATE_NAME = "get-state";
const char* COMMANDLINE_GSTATE_DESC[] = {
- "print: offline | bootloader | device"
+ "print: offline | locked | device"
};
const int COMMANDLINE_GSTATE_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_GSTATE_DESC, char*);
const int COMMANDLINE_GSTATE_MAX_ARG = 0;
const int COMMANDLINE_EMULATOR_HAS_ARG = 0;
const char* COMMANDLINE_ERROR_ARG_MISSING = "argument %s is missing for command %s";
+
+ const char* STATE_OFFLINE = "offline";
+ const char* STATE_BOOTLOADER = "bootloader";
+ const char* STATE_DEVICE = "device";
+ const char* STATE_HOST = "host";
+ const char* STATE_RECOVERY = "recovery";
+ const char* STATE_SIDELOAD = "sideload";
+ const char* STATE_NOPERM = "no permissions";
+ const char* STATE_LOCKED = "locked";
+ const char* STATE_UNKNOWN = "unknown";
+
+ const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET = "more than one target";
+ const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL = "more than one emulator";
+ const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV = "more than one device";
+ const char* TRANSPORT_ERR_TARGET_OFFLINE = "target offline";
+ const char* TRANSPORT_ERR_TARGET_NOT_FOUND = "target not found";
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;
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;
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_*/
--- /dev/null
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#include <stdlib.h>
+#include "sdb_map.h"
+#include "linkedlist.h"
+
+static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key);
+static int default_hash(MAP* this, MAP_KEY key);
+static int default_equal(MAP_KEY key, MAP_KEY node_key);
+static void default_free(void* node);
+
+void initialize_map(MAP* this, int size, int(*hash)(struct map* this, MAP_KEY key),
+ int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data)) {
+
+ if(size < 1) {
+ this->size = DEFAULT_MAP_SIZE;
+ }
+ else {
+ this->size = size;
+ }
+
+ if(equal == NULL) {
+ this->equal = default_equal;
+ }
+ else {
+ this->equal = equal;
+ }
+
+ if(hash == NULL) {
+ this->hash = default_hash;
+ }
+ else {
+ this->hash = hash;
+ }
+
+ if(freedata == NULL) {
+ this->freedata = default_free;
+ }
+ else {
+ this->freedata = freedata;
+ }
+
+ this->map_node_list = (LIST_NODE**)calloc(this->size, sizeof(LIST_NODE*));
+}
+
+static void default_free(void* node) {
+ MAP_NODE* _node = node;
+ if(_node != NULL) {
+ if(_node->value != NULL ) {
+// free(_node->value);
+ }
+ free(_node);
+ }
+}
+
+static int default_hash(MAP* this, MAP_KEY key) {
+ return key.key_int%(this->size);
+}
+
+static int default_equal(MAP_KEY key, MAP_KEY node_key) {
+ if(key.key_int != node_key.key_int) {
+ return 0;
+ }
+ return 1;
+}
+
+static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key) {
+
+ while(list != NULL) {
+ MAP_NODE* node = list->data;
+ if(this->equal(key, node->key)) {
+ return list;
+ }
+ list = list->next_ptr;
+ }
+
+ return NULL;
+}
+
+void map_put(MAP* this, MAP_KEY key, void* value) {
+
+ int hash_key = this->hash(this, key);
+ LIST_NODE** hash_list = &(this->map_node_list[hash_key]);
+
+ MAP_NODE* node = malloc(sizeof(MAP_NODE));
+ node->key = key;
+ node->value = value;
+
+ LIST_NODE* list_node = find_in_list(this, *hash_list, key);
+ if(list_node == NULL) {
+ prepend(hash_list, (void*)node);
+ }
+ else {
+ this->freedata(list_node->data);
+ list_node->data = node;
+ }
+}
+
+void* map_get(MAP* this, MAP_KEY key) {
+
+ int hash_key = this->hash(this, key);
+ LIST_NODE* hash_list = this->map_node_list[hash_key];
+ LIST_NODE* result_node = find_in_list(this, hash_list, key);
+ if(result_node == NULL) {
+ return NULL;
+ }
+
+ return ((MAP_NODE*)(result_node->data))->value;
+}
+
+void map_remove(MAP* this, MAP_KEY key) {
+
+ int hash_key = this->hash(this, key);
+ LIST_NODE** hash_list = &(this->map_node_list[hash_key]);
+
+ LIST_NODE* result_node = find_in_list(this, *hash_list, key);
+ if(result_node != NULL) {
+ this->freedata(result_node->data);
+ LIST_NODE* prev = result_node->prev_ptr;
+ LIST_NODE* next = result_node->next_ptr;
+
+ if(prev == NULL && next == NULL) {
+ *hash_list = NULL;
+ }
+ else {
+ if(prev != NULL) {
+ prev->next_ptr = next;
+ }
+
+ if(next != NULL) {
+ next->prev_ptr = prev;
+ }
+ }
+
+ free(result_node);
+ }
+}
+
+void map_clear(MAP* this) {
+
+ if(this != NULL) {
+ int i =0;
+ for(; i<this->size; i++) {
+ free_list(this->map_node_list[i], this->freedata);
+ }
+
+ free(this->map_node_list);
+ }
+}
--- /dev/null
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef SDB_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_ */
#include "fdevent.h"
#include "sdb_model.h"
#include "linkedlist.h"
-#include "sdb.h"
+#include "log.h"
const COMMAND NULL_COMMAND = {
NULL,
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;
#include "utils.h"
#include "fdevent.h"
#include "sdb_constants.h"
-
-#define TRACE_TAG TRACE_SOCKETS
+#include "sdb_map.h"
+#include "sdb_client.h"
+#include "sockets.h"
+#include "transport.h"
+#include "log.h"
+#include "listener.h"
#include "sdb.h"
-SDB_MUTEX_DEFINE( socket_list_lock );
-
-static void local_socket_close_locked(asocket *s);
-
-int sendfailmsg(int fd, const char *reason)
-{
- char buf[9];
- int len;
- len = strlen(reason);
- if(len > 0xffff) len = 0xffff;
- snprintf(buf, sizeof buf, "FAIL%04x", len);
- if(writex(fd, buf, 8)) return -1;
- return writex(fd, reason, len);
-}
+#define TRACE_TAG TRACE_SOCKETS
-//extern int online;
+static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p);
+static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func);
+static int peer_enqueue(SDB_SOCKET* socket, PACKET* p);
+static void local_socket_destroy(SDB_SOCKET *s);
+static void remove_socket(void* s);
+static void destroy_socket(void* data);
+static void local_socket_event_func(int fd, unsigned ev, void *_s);
+static unsigned unhex(unsigned char*s, int len);
+static int find_transports(char **serial_out, const char *prefix);
+static void unregister_all_tcp_transports();
+static void connect_emulator(char* host, int port, char* buf, int buf_len);
+
+const unsigned int unsigned_int_bit = sizeof(unsigned int) * 8;
+const unsigned int remote_con_right_padding = ~(~0 << sizeof(unsigned int) * 4);
+const unsigned int remote_con_flag = 1 << (sizeof(unsigned int) * 8 - 1);
+unsigned int remote_con_cur_r_id = 1;
+unsigned int remote_con_cur_l_number = 0;
+const unsigned int remote_con_l_max = 16; // Ox1111
+const unsigned int remote_con_r_max = ~(~0 << (sizeof(unsigned int) * 8 - 5));
+unsigned int remote_con_l_table[16] = {0,};
static unsigned local_socket_next_id = 1;
-static asocket local_socket_list = {
- .next = &local_socket_list,
- .prev = &local_socket_list,
-};
-
-/* the the list of currently closing local sockets.
-** these have no peer anymore, but still packets to
-** write to their fd.
-*/
-static asocket local_socket_closing_list = {
- .next = &local_socket_closing_list,
- .prev = &local_socket_closing_list,
-};
-
-asocket *find_local_socket(unsigned id)
+LIST_NODE* local_socket_list = NULL;
+
+SDB_SOCKET *find_local_socket(unsigned id)
{
- asocket *s;
- asocket *result = NULL;
+ SDB_SOCKET *result = NULL;
- sdb_mutex_lock(&socket_list_lock);
- for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
- if (s->id == id) {
+
+ LIST_NODE* curptr = local_socket_list;
+ while(curptr != NULL) {
+ SDB_SOCKET* s = curptr->data;
+ curptr = curptr->next_ptr;
+ if(s->local_id == id) {
result = s;
break;
}
}
- sdb_mutex_unlock(&socket_list_lock);
return result;
}
-static void
-insert_local_socket(asocket* s, asocket* list)
+static void remove_socket(void* s)
{
- s->next = list;
- s->prev = s->next->prev;
- s->prev->next = s;
- s->next->prev = s;
+ SDB_SOCKET* socket = s;
+ socket->node = NULL;
}
-
-void install_local_socket(asocket *s)
+int local_socket_enqueue(SDB_SOCKET *s, PACKET *p)
{
- sdb_mutex_lock(&socket_list_lock);
+ D("LS(%X) local enqueue\n", s->local_id);
- s->id = local_socket_next_id++;
- insert_local_socket(s, &local_socket_list);
+ if(s->pkt_list == NULL) {
+ int r = local_enqueue(s->fd, p, s, 0);
+ if( r == 0) {
+ //enqueue done normally
+ return 0;
+ }
+ if( r < 0) {
+ //error occurred
+ return 1;
+ }
+ }
+ //wait for next round
+ append(&(s->pkt_list), p);
+ FDEVENT_ADD(&s->fde, FDE_WRITE);
- sdb_mutex_unlock(&socket_list_lock);
+ return 1;
}
-void remove_socket(asocket *s)
+void local_socket_ready(SDB_SOCKET *s)
{
- // socket_list_lock should already be held
- if (s->prev && s->next)
- {
- s->prev->next = s->next;
- s->next->prev = s->prev;
- s->next = 0;
- s->prev = 0;
- s->id = 0;
+ D("local socket ready. LS(%X)\n", s->local_id);
+ if(HAS_SOCKET_STATUS(s, NOTIFY)) {
+ D("local socket notify to the client FD(%d)\n", s->fd);
+ sdb_write(s->fd, "OKAY", 4);
+ REMOVE_SOCKET_STATUS(s, NOTIFY);
}
+ FDEVENT_ADD(&s->fde, FDE_READ);
}
-void close_all_sockets(atransport *t)
+void local_socket_close(SDB_SOCKET *s)
{
- asocket *s;
-
- /* this is a little gross, but since s->close() *will* modify
- ** the list out from under you, your options are limited.
- */
- sdb_mutex_lock(&socket_list_lock);
-restart:
- for(s = local_socket_list.next; s != &local_socket_list; s = s->next){
- if(s->transport == t || (s->peer && s->peer->transport == t)) {
- local_socket_close_locked(s);
- goto restart;
- }
+ D("LS(%X) FD(%d)\n", s->local_id, s->fd);
+ if(HAS_SOCKET_STATUS(s, NOTIFY)) {
+ D("LS(%X) fail to send notify\n", s->local_id);
+ sendfailmsg(s->fd, "closed");
+ REMOVE_SOCKET_STATUS(s, NOTIFY);
}
- sdb_mutex_unlock(&socket_list_lock);
-}
-
-static int local_socket_enqueue(asocket *s, apacket *p)
-{
- D("LS(%d): enqueue %d\n", s->id, p->len);
-
- p->ptr = p->data;
- /* if there is already data queue'd, we will receive
- ** events when it's time to write. just add this to
- ** the tail
- */
- if(s->pkt_first) {
- goto enqueue;
- }
- /* write as much as we can, until we
- ** would block or there is an error/eof
- */
- while(p->len > 0) {
- int r = sdb_write(s->fd, p->ptr, p->len);
- if(r > 0) {
- p->len -= r;
- p->ptr += r;
- continue;
- }
- if((r == 0) || (errno != EAGAIN)) {
- D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) );
- s->close(s);
- return 1; /* not ready (error) */
- } else {
- break;
- }
+ if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) {
+ send_cmd(0, s->remote_id, A_CLSE, NULL, s->transport);
}
+ int id = s->local_id;
- if(p->len == 0) {
- put_apacket(p);
- return 0; /* ready for more data */
+ if(!s->closing && s->pkt_list != NULL) {
+ s->closing = 1;
+ FDEVENT_DEL(&s->fde, FDE_READ);
+ remove_node(&local_socket_list, s->node, remove_socket);
+ D("LS(%X) pending close\n", id);
}
-
-enqueue:
- p->next = 0;
- if(s->pkt_first) {
- s->pkt_last->next = p;
- } else {
- s->pkt_first = p;
+ else {
+ local_socket_destroy(s);
+ D("LS(%X) closed\n", id);
}
- s->pkt_last = p;
-
- /* make sure we are notified when we can drain the queue */
- fdevent_add(&s->fde, FDE_WRITE);
-
- return 1; /* not ready (backlog) */
}
-static void local_socket_ready(asocket *s)
-{
- /* far side is ready for data, pay attention to
- readable events */
- fdevent_add(&s->fde, FDE_READ);
-// D("LS(%d): ready()\n", s->id);
-}
-
-static void local_socket_close(asocket *s)
-{
- sdb_mutex_lock(&socket_list_lock);
- local_socket_close_locked(s);
- sdb_mutex_unlock(&socket_list_lock);
+static void destroy_socket(void* data) {
+ SDB_SOCKET* socket = data;
+ socket->node = NULL;
+
+ if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) {
+ free(socket->read_packet);
+ unsigned int id = socket->local_id & ~remote_con_flag;
+
+ TRANSPORT* t = socket->transport;
+ if(t != NULL) {
+ LIST_NODE* node = t->remote_cnxn_socket;
+ while(node != NULL) {
+ SDB_SOCKET* s = node->data;
+ node = node->next_ptr;
+ if(s == socket) {
+ remove_node(&(t->remote_cnxn_socket), s->node, no_free);
+ break;
+ }
+ }
+ }
+ remote_con_l_table[id] = 0;
+ }
+ socket->local_id = 0;
+ free(socket);
}
// be sure to hold the socket list lock when calling this
-static void local_socket_destroy(asocket *s)
+static void local_socket_destroy(SDB_SOCKET *s)
{
- apacket *p, *n;
- int exit_on_close = s->exit_on_close;
+ D("LS(%X) FD(%d)\n", s->local_id, s->fd);
- D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd);
-
- /* IMPORTANT: the remove closes the fd
+ /* IMPORTANT: fdevent_remove closes the fd
** that belongs to this socket
*/
fdevent_remove(&s->fde);
/* dispose of any unwritten data */
- for(p = s->pkt_first; p; p = n) {
- D("LS(%d): discarding %d bytes\n", s->id, p->len);
- n = p->next;
- put_apacket(p);
+ free_list(s->pkt_list, put_apacket);
+ s->pkt_list = NULL;
+
+ if(s->node != NULL) {
+ remove_node(&local_socket_list, s->node, destroy_socket);
+ }
+ else {
+ destroy_socket(s);
+ }
+}
+
+ //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared
+#if 0
+//remote_ls_id is a socket in the remote server.
+//local_ls_id is a socket of fowarding socket
+// left half is local_ls_id and right half is remote_ls_id.
+static unsigned int encoding_ls_id(unsigned int remote_ls_id, unsigned int local_ls_id) {
+ D("LS_R(%X), LS_L(%X)\n", remote_ls_id, local_ls_id);
+ return remote_ls_id | local_ls_id;
+}
+
+static void send_remote_con_packet(SDB_SOCKET* sock, PACKET* p) {
+
+ //message and data are filled send it to the target.
+ if(p->msg.command != A_CNXN) {
+ //A_CNXN does not have to encode local socket id.
+ p->msg.arg0 = encoding_ls_id(p->msg.arg0, sock->local_id);
+ LOG_INFO("LS_L(%X) LS_E(%X) encoding done\n", sock->local_id, p->msg.arg0);
+ }
+ else {
+ //for notifying transport that it has remaning socket which wait for CNXN
+ LOG_INFO("LS_L(%X) message was CNXN\n", sock->local_id);
+ append(&sock->transport->remote_cnxn_socket, sock);
}
- remove_socket(s);
- free(s);
- if (exit_on_close) {
- D("local_socket_destroy: exiting\n");
- exit(1);
+ encoding_packet(p);
+ //send packet to the target transport
+ if(sock->transport->write_to_remote(p, sock->transport)) {
+ LOG_ERROR("fail to write packet\n");
+ dump_packet("write error", "remote_con_enqueue", p);
}
}
+static int remote_con_enqueue(SDB_SOCKET* socket, PACKET* p) {
+ LOG_INFO("LS_L(%X)\n", socket->local_id);
-static void local_socket_close_locked(asocket *s)
-{
- D("entered. LS(%d) fd=%d\n", s->id, s->fd);
- if(s->peer) {
- D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n",
- s->id, s->peer->id, s->peer->fd);
- s->peer->peer = 0;
- // tweak to avoid deadlock
- if (s->peer->close == local_socket_close) {
- local_socket_close_locked(s->peer);
- } else {
- s->peer->close(s->peer);
+ PACKET* read_p = socket->read_packet;
+
+ if(read_p->len == 0 && p->len >= sizeof(MESSAGE)) {
+ if(p->len == sizeof(MESSAGE) + p->msg.data_length) {
+ //send packet directly without memcpy.
+ if(check_header(p) || check_data(read_p)) {
+ LOG_ERROR("bad packet: terminated (data)\n");
+ dump_packet("bad packet", "remote_con_enqueue", read_p);
+ put_apacket(p);
+ return 0;
+ }
+
+ LOG_INFO("packet is complete send directly\n");
+ send_remote_con_packet(socket, p);
+ put_apacket(p);
+ return 1;
}
- s->peer = 0;
}
- /* If we are already closing, or if there are no
- ** pending packets, destroy immediately
- */
- if (s->closing || s->pkt_first == NULL) {
- int id = s->id;
- local_socket_destroy(s);
- D("LS(%d): closed\n", id);
- return;
+ while(p != NULL) {
+ //read MESSAGE
+ if(read_p->len < sizeof(MESSAGE)) {
+ int read_length = 0;
+ int msg_done = 1;
+ if(read_p->len + p->len >= sizeof(MESSAGE)) {
+ read_length = sizeof(MESSAGE) - read_p->len;
+ }
+ else {
+ read_length = p->len;
+ msg_done = 0;
+ }
+ memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length);
+ p->ptr += read_length;
+ p->len -= read_length;
+ read_p->len += read_length;
+ if(msg_done) {
+ LOG_INFO("message reading done\n");
+
+ #if 0 && defined HAVE_BIG_ENDIAN
+ D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
+ socket_p->msg.command, socket_p->msg.arg0, socket_p->msg.arg1, socket_p->msg.data_length, socket_p->msg.data_check, socket_p->msg.magic);
+ #endif
+ if(check_header(read_p)) {
+ LOG_ERROR("bad header: terminated (data)\n");
+ dump_packet("bad header", "remote_con_enqueue", read_p);
+ read_p->len = 0;
+ put_apacket(p);
+ return 0;
+ }
+ }
+ else {
+ //wait for next round
+ LOG_INFO("wait for next round while reading message\n");
+ put_apacket(p);
+ return 0;
+ }
+ }
+ //read data
+ unsigned data_length = read_p->msg.data_length + sizeof(MESSAGE);
+ int read_length = 0;
+ int data_done = 1;
+ if(read_p->len + p->len >= data_length) {
+ read_length = data_length - read_p->len;
+ }
+ else {
+ read_length = p->len;
+ data_done = 0;
+ }
+
+ memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length);
+ p->ptr += read_length;
+ p->len -= read_length;
+ read_p->len += read_length;
+
+ if(data_done) {
+ LOG_INFO("data reading done\n");
+ if(check_data(read_p)) {
+ LOG_ERROR("bad data: terminated (data)\n");
+ dump_packet("bad data", "remote_con_enqueue", read_p);
+ read_p->len = 0;
+ put_apacket(p);
+ return 0;
+ }
+
+ send_remote_con_packet(socket, read_p);
+ read_p->len = 0;
+ }
+
+ if(p->len == 0) {
+ LOG_INFO("reading all the packet is done\n");
+ put_apacket(p);
+ p = NULL;
+ }
}
- /* otherwise, put on the closing list
- */
- D("LS(%d): closing\n", s->id);
- s->closing = 1;
- fdevent_del(&s->fde, FDE_READ);
- remove_socket(s);
- D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd);
- insert_local_socket(s, &local_socket_closing_list);
+ LOG_INFO("read_p->len: %d\n", read_p->len);
+ return 1;
+}
+#endif
+
+static int peer_enqueue(SDB_SOCKET* socket, PACKET* p) {
+ if(HAS_SOCKET_STATUS(socket, REMOTE_SOCKET)) {
+ D("entered remote_socket_enqueue RS(%d) WRTE fd=%d\n",
+ socket->remote_id, socket->fd);
+ p->msg.command = A_WRTE;
+ p->msg.arg0 = socket->local_id;
+ p->msg.arg1 = socket->remote_id;
+ p->msg.data_length = p->len;
+ send_packet(p, socket->transport);
+ put_apacket(p);
+ FDEVENT_DEL(&socket->fde, FDE_READ);
+ return 1;
+ }
+
+ //TODO REMOTE_DEVICE_CONNECT block this code until security issue is resolved
+#if 0
+ if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) {
+ return remote_con_enqueue(socket, p);
+ }
+#endif
+
+ if(HAS_SOCKET_STATUS(socket, DEVICE_TRACKER)) {
+ D("close device tracker.fd: '%d', LS(%X)", socket->fd, socket->local_id);
+ put_apacket(p);
+ local_socket_close(socket);
+ return -1;
+ }
+
+ //packet can be queued, so do not free it here.
+ return smart_socket_enqueue(socket, p);
+}
+
+/**
+ * If returns 0, appending is done. packet is freed.
+ * 1, EAGAIN happens packet is put in the queue. wait for next round.
+ * -1, error happens. socket is closed. return immediately.
+ */
+static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func) {
+ D("LS(%X) FD(%d)\n", s->local_id, fd);
+ while(p->len > 0) {
+ dump_packet("0", "local_enqueue", p);
+ int r = sdb_write(fd, p->ptr, p->len);
+ if(r < 0) {
+ if(errno == EAGAIN) {
+ //packet is used next round do not free.
+ D( "LS(%X) EAGAIN pending to next round\n", s->local_id);
+ return 1;
+ }
+ //TODO if we handle EINTR when local_socket_enqueue calls this, Windows debug fails.
+ if(errno == EINTR && event_func) {
+ D( "LS(%X) EINTR continue\n", s->local_id);
+ continue;
+ }
+ }
+ if(r > 0) {
+ p->len -= r;
+ p->ptr += r;
+ continue;
+ }
+ //error happens. close the socket.
+ D( "LS(%X) error ER(%d) %s\n", s->local_id, errno, strerror(errno) );
+ put_apacket(p);
+ local_socket_close(s);
+ return -1; /* not ready (error) */
+ }
+ //append done.
+ D("LS(%X) enqueue done\n", s->local_id);
+ put_apacket(p);
+ return 0;
}
static void local_socket_event_func(int fd, unsigned ev, void *_s)
{
- asocket *s = _s;
+ SDB_SOCKET *s = _s;
- D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev);
+ D("LS(%X) FD(%d)\n", s->local_id, s->fd);
/* put the FDE_WRITE processing before the FDE_READ
** in order to simplify the code.
*/
if(ev & FDE_WRITE){
- apacket *p;
-
- while((p = s->pkt_first) != 0) {
- while(p->len > 0) {
- int r = sdb_write(fd, p->ptr, p->len);
- if(r > 0) {
- p->ptr += r;
- p->len -= r;
- continue;
- }
- if(r < 0) {
- /* returning here is ok because FDE_READ will
- ** be processed in the next iteration loop
- */
- if(errno == EAGAIN) return;
- if(errno == EINTR) continue;
- }
- D(" closing after write because r=%d and errno is %d\n", r, errno);
- s->close(s);
- return;
+ D("LS(%X) gets a write event\n", s->local_id);
+ while(s->pkt_list != NULL) {
+ PACKET* p = s->pkt_list->data;
+ int r = local_enqueue(fd, p, s, 1);
+
+ if ( r == 0) {
+ //packet enqueue done
+ remove_first(&s->pkt_list, no_free);
}
-
- if(p->len == 0) {
- s->pkt_first = p->next;
- if(s->pkt_first == 0) s->pkt_last = 0;
- put_apacket(p);
+ else {
+ //in both cases r = 1 and r = -1, return immediately.
+ return;
}
}
-
- /* if we sent the last packet of a closing socket,
- ** we can now destroy it.
- */
if (s->closing) {
- D(" closing because 'closing' is set after write\n");
- s->close(s);
+ D("LS(%X) closing because 'closing' is set after write\n", s->local_id);
+ local_socket_close(s);
return;
}
-
- /* no more packets queued, so we can ignore
- ** writable events again and tell our peer
- ** to resume writing
- */
- fdevent_del(&s->fde, FDE_WRITE);
- s->peer->ready(s->peer);
+ //all the packet in the pkt_list is enqueued. write event is done.
+ FDEVENT_DEL(&s->fde, FDE_WRITE);
+ if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) {
+ send_cmd(s->local_id, s->remote_id, A_OKAY, NULL, s->transport);
+ }
}
if(ev & FDE_READ){
- apacket *p = get_apacket();
- unsigned char *x = p->data;
+ D("LS(%X) gets a read event\n", s->local_id);
+ //packet should be freed in peer_enqueue
+ PACKET *p = get_apacket();
+
+ void *x;
+ if(HAS_SOCKET_STATUS(s, REMOTE_CON)) {
+ x = &p->msg;
+ p->ptr = &p->msg;
+ }
+ else {
+ x = p->data;
+ }
size_t avail = MAX_PAYLOAD;
- int r;
- int is_eof = 0;
+ int r = 1;
while(avail > 0) {
r = sdb_read(fd, x, avail);
- D("LS(%d): post sdb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
if(r > 0) {
avail -= r;
x += r;
continue;
}
if(r < 0) {
- if(errno == EAGAIN) break;
- if(errno == EINTR) continue;
+ if(errno == EAGAIN) {
+ D("LS(%X) EAGAIN while reading\n", s->local_id);
+ break;
+ }
+ if(errno == EINTR) {
+ continue;
+ }
+ LOG_ERROR("LS(%X) error while reading ER(%d), %s\n", s->local_id, errno, strerror(errno));
+ // r = 0 means EOF or unhandled error.
+ r = 0;
}
-
- /* r = 0 or unhandled error */
- is_eof = 1;
+ D("LS(%X) reading done\n", s->local_id);
break;
}
- D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n",
- s->id, s->fd, r, is_eof, s->fde.force_eof);
- if((avail == MAX_PAYLOAD) || (s->peer == 0)) {
+
+ if(avail == MAX_PAYLOAD) {
put_apacket(p);
} else {
p->len = MAX_PAYLOAD - avail;
-
- r = s->peer->enqueue(s->peer, p);
- D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r);
-
- if(r < 0) {
- /* error return means they closed us as a side-effect
- ** and we must return immediately.
- **
- ** note that if we still have buffered packets, the
- ** socket will be placed on the closing socket list.
- ** this handler function will be called again
- ** to process FDE_WRITE events.
- */
+ if(peer_enqueue(s, p) < 0) {
+ //local socket is already closed by peer or should not close the socket.
return;
}
-
- if(r > 0) {
- /* if the remote cannot accept further events,
- ** we disable notification of READs. They'll
- ** be enabled again when we get a call to ready()
- */
- fdevent_del(&s->fde, FDE_READ);
- }
}
- /* Don't allow a forced eof if data is still there */
- if((s->fde.force_eof && !r) || is_eof) {
- D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof);
- s->close(s);
+ if(r == 0) {
+ D("LS(%X) EOF. closing\n", s->local_id);
+ local_socket_close(s);
}
}
-
- if(ev & FDE_ERROR){
- /* this should be caught be the next read or write
- ** catching it here means we may skip the last few
- ** bytes of readable data.
- */
-// s->close(s);
- D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd);
-
- return;
- }
}
-asocket *create_local_socket(int fd)
+SDB_SOCKET *create_local_socket(int fd)
{
- asocket *s = calloc(1, sizeof(asocket));
- if (s == NULL) fatal("cannot allocate socket");
+ D("FD(%d)\n", fd);
+ SDB_SOCKET *s = calloc(1, sizeof(SDB_SOCKET));
+ if (s == NULL) {
+ LOG_FATAL("cannot allocate socket\n");
+ }
+ s->status = 0;
+ s->node = NULL;
+ s->pkt_list = NULL;
s->fd = fd;
- s->enqueue = local_socket_enqueue;
- s->ready = local_socket_ready;
- s->close = local_socket_close;
- install_local_socket(s);
+
+ s->local_id = local_socket_next_id++;
+ s->node = prepend(&local_socket_list, s);
fdevent_install(&s->fde, fd, local_socket_event_func, s);
-/* fdevent_add(&s->fde, FDE_ERROR); */
- //fprintf(stderr, "Created local socket in create_local_socket \n");
- D("LS(%d): created (fd=%d)\n", s->id, s->fd);
+ D("LS(%X) FD(%d) created\n", s->local_id, s->fd);
return s;
}
-asocket *create_local_service_socket(const char *name)
-{
- asocket *s;
- int fd;
-
- fd = service_to_fd(name);
- if(fd < 0) return 0;
-
- s = create_local_socket(fd);
- D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
-
- return s;
+void create_remote_connection_socket(SDB_SOCKET* socket) {
+ LOG_INFO("FD(%d)\n", socket->fd);
+ SET_SOCKET_STATUS(socket, REMOTE_CON);
+ socket->read_packet = malloc(sizeof(PACKET));
+ socket->read_packet->len = 0;
}
-static asocket *create_host_service_socket(const char *name, const char* serial)
+void connect_to_remote(SDB_SOCKET *s, const char *destination)
{
- asocket *s;
-
- s = host_service_to_socket(name, serial);
+ D("LS(%X)\n", s->local_id);
+ PACKET *p = get_apacket();
+ int len = strlen(destination) + 1;
- if (s != NULL) {
- D("LS(%d) bound to '%s'\n", s->id, name);
- return s;
+ if(len > (MAX_PAYLOAD-1)) {
+ LOG_FATAL("destination oversized\n");
}
- return s;
+ D("LS(%X): connect('%s')\n", s->local_id, destination);
+ p->msg.command = A_OPEN;
+ p->msg.arg0 = s->local_id;
+ p->msg.data_length = len;
+ strcpy((char*) p->data, destination);
+ send_packet(p, s->transport);
+ put_apacket(p);
}
-/* a Remote socket is used to send/receive data to/from a given transport object
-** it needs to be closed when the transport is forcibly destroyed by the user
-*/
-typedef struct aremotesocket {
- asocket socket;
- adisconnect disconnect;
-} aremotesocket;
+static unsigned unhex(unsigned char*s, int len) {
-static int remote_socket_enqueue(asocket *s, apacket *p)
-{
- D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
- s->id, s->fd, s->peer->fd);
- p->msg.command = A_WRTE;
- p->msg.arg0 = s->peer->id;
- p->msg.arg1 = s->id;
- p->msg.data_length = p->len;
- send_packet(p, s->transport);
- return 1;
+ unsigned n = 0;
+ while(len > 0) {
+ MAP_KEY key;
+ key.key_int = (int)(0 | *s++);
+ void* _c = map_get(&hex_map, key);
+ unsigned c = (unsigned)_c;
+ n = (n << 4) | c;
+ len--;
+ }
+ return n;
}
-static void remote_socket_ready(asocket *s)
-{
- D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n",
- s->id, s->fd, s->peer->fd);
- apacket *p = get_apacket();
- p->msg.command = A_OKAY;
- p->msg.arg0 = s->peer->id;
- p->msg.arg1 = s->id;
- send_packet(p, s->transport);
-}
+/**
+ * return 0 for host
+ * return 1 for transport
+ */
+static int parse_host_service(char* host_str, char** service_ptr, TRANSPORT** t, char** err_str) {
-static void remote_socket_close(asocket *s)
-{
- D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
- s->id, s->fd, s->peer?s->peer->fd:-1);
- apacket *p = get_apacket();
- p->msg.command = A_CLSE;
- if(s->peer) {
- p->msg.arg0 = s->peer->id;
- s->peer->peer = 0;
- D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n",
- s->id, s->peer->id, s->peer->fd);
- s->peer->close(s->peer);
- }
- p->msg.arg1 = s->id;
- send_packet(p, s->transport);
- D("RS(%d): closed\n", s->id);
- remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
- free(s);
+ int prefix_len = strlen(PREFIX_HOST_USB);
+ if (!strncmp(host_str, PREFIX_HOST_USB, prefix_len)) {
+ *service_ptr = host_str + prefix_len;
+ *t = acquire_one_transport(kTransportUsb, NULL, err_str);
+ return 0;
+ }
+ prefix_len = strlen(PREFIX_HOST_LOCAL);
+ if (!strncmp(host_str, PREFIX_HOST_LOCAL, prefix_len)) {
+ *service_ptr = host_str + prefix_len;
+ *t = acquire_one_transport(kTransportLocal, NULL, err_str);
+ return 0;
+ }
+ prefix_len = strlen(PREFIX_HOST);
+ if (!strncmp(host_str, PREFIX_HOST, prefix_len)) {
+ if(!strncmp(host_str, PREFIX_TRANSPORT_ANY, strlen(PREFIX_TRANSPORT_ANY))) {
+ *t = acquire_one_transport(kTransportAny, NULL, err_str);
+ return 1;
+ }
+ if(!strncmp(host_str, PREFIX_TRANSPORT_LOCAL, strlen(PREFIX_TRANSPORT_LOCAL))) {
+ *t = acquire_one_transport(kTransportLocal, NULL, err_str);
+ return 1;
+ }
+ if(!strncmp(host_str, PREFIX_TRANSPORT_USB, strlen(PREFIX_TRANSPORT_USB))) {
+ *t = acquire_one_transport(kTransportUsb, NULL, err_str);
+ return 1;
+ }
+ if(!strncmp(host_str, PREFIX_TRANSPORT_SERIAL, strlen(PREFIX_TRANSPORT_SERIAL))) {
+ *t = acquire_one_transport(kTransportAny, host_str + strlen(PREFIX_TRANSPORT_SERIAL), err_str);
+ return 1;
+ }
+ *service_ptr = host_str + prefix_len;
+ //does not have to find transport.
+ *t = NULL;
+ *err_str = NULL;
+ return 0;
+ }
+ prefix_len = strlen(PREFIX_HOST_ANY);
+ if(!strncmp(host_str, PREFIX_HOST_ANY, prefix_len)) {
+ *service_ptr = host_str + prefix_len;
+ *t = acquire_one_transport(kTransportAny, NULL, err_str);
+ return 0;
+ }
+ prefix_len = strlen(PREFIX_HOST_SERIAL);
+ if(!strncmp(host_str, PREFIX_HOST_SERIAL, prefix_len)) {
+ char* serial = host_str + prefix_len;
+ char* end = strchr(serial, ':');
+ if(end == NULL) {
+ *err_str = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND;
+ return 0;
+ }
+ *end = '\0';
+ *service_ptr = end + 1;
+ *t = acquire_one_transport(kTransportAny, serial, err_str);
+ return 0;
+ }
+ *service_ptr = NULL;
+ return 0;
}
-static void remote_socket_disconnect(void* _s, atransport* t)
-{
- asocket* s = _s;
- asocket* peer = s->peer;
+static int handle_request_with_t(SDB_SOCKET* socket, char* service, TRANSPORT* t, char* err_str) {
+ int forward = 0;
+ if(!strncmp(service,"forward:",8)) {
+ forward = 8;
+ }
+ else if (!strncmp(service,"killforward:",12)) {
+ forward = 12;
+ }
+
+ if(forward) {
+ char* forward_err = NULL;
+
+ char *local, *remote = NULL;
+ local = service + forward;
+ remote = strchr(local,';');
+
+ if (t == NULL || t->connection_state == CS_OFFLINE) {
+ if(t != NULL) {
+ forward_err = (char*)TRANSPORT_ERR_TARGET_OFFLINE;
+ }
+ else {
+ forward_err = err_str;
+ }
+ goto sendfail;
+ }
+ if(remote == 0 || remote[1] == '\0') {
+ forward_err = "malformed forward spec";
+ goto sendfail;
+ }
+ *remote++ = 0;
- D("remote_socket_disconnect RS(%d)\n", s->id);
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
+ if (forward == 8) {
+ if(!install_listener(local, remote, t)) {
+ writex(socket->fd, "OKAYOKAY", 8);
+ return 0;
+ }
+ else {
+ LOG_INFO("LS(%X) T(%s) fail to install listener\n", socket->fd, t->device_name);
+ forward_err = "cannot install listener";
+ }
+ } else {
+ if(!remove_listener(local, remote, t)) {
+ writex(socket->fd, "OKAYOKAY", 8);
+ return 0;
+ } else {
+ LOG_INFO("LS(%X) T(%s) fail to remove listener\n", socket->fd, t->device_name);
+ forward_err = "cannot remove listener";
+ }
+ }
+sendfail:
+ sendfailmsg(socket->fd, forward_err);
+ return 0;
+ }
+ else if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
+ if (t) {
+ sendokmsg(socket->fd, t->serial);
+ }
+ else {
+ sendokmsg(socket->fd, "target not exist");
+ }
+ return 0;
+ }
+ else if(!strncmp(service,"get-state",strlen("get-state"))) {
+ const char *state = connection_state_name(t);
+ sendokmsg(socket->fd, state);
+ return 0;
}
- remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
- free(s);
-}
-asocket *create_remote_socket(unsigned id, atransport *t)
-{
- asocket *s = calloc(1, sizeof(aremotesocket));
- adisconnect* dis = &((aremotesocket*)s)->disconnect;
-
- if (s == NULL) fatal("cannot allocate socket");
- s->id = id;
- s->enqueue = remote_socket_enqueue;
- s->ready = remote_socket_ready;
- s->close = remote_socket_close;
- s->transport = t;
-
- dis->func = remote_socket_disconnect;
- dis->opaque = s;
- add_transport_disconnect( t, dis );
- D("RS(%d): created\n", s->id);
- return s;
+ //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared
+#if 0
+ else if(!strncmp(service,"_dev_con",strlen("_dev_con"))) {
+ if(t == NULL) {
+ sendfailmsg(socket->fd, err_str);
+ return 0;
+ }
+ if(assign_remote_connect_socket_lid(socket)) {
+ sendfailmsg(socket->fd, "remote connect socket exceeds limit. cannot create remote socket\n");
+ local_socket_close(socket);
+ return 0;
+ }
+ socket->transport = t;
+ create_remote_connection_socket(socket);
+
+ char* buf = "OKAY";
+ writex(socket->fd, buf, strlen(buf));
+ return 0;
+ }
+#endif
+
+ return -1;
}
-void connect_to_remote(asocket *s, const char *destination)
+static int find_transports(char **serial_out, const char *prefix)
{
- D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd);
- apacket *p = get_apacket();
- int len = strlen(destination) + 1;
+ int nr = 0; // not found
+ char *match = NULL;
- if(len > (MAX_PAYLOAD-1)) {
- fatal("destination oversized");
- }
+ if (!serial_out || !prefix)
+ return -1;
- D("LS(%d): connect('%s')\n", s->id, destination);
- p->msg.command = A_OPEN;
- p->msg.arg0 = s->id;
- p->msg.data_length = len;
- strcpy((char*) p->data, destination);
- send_packet(p, s->transport);
-}
+ sdb_mutex_lock(&transport_lock, "transport find_transports");
+ LIST_NODE* curptr = transport_list;
+ while(curptr != NULL) {
+ TRANSPORT* t = curptr->data;
+ curptr = curptr->next_ptr;
+ char* serial = t->serial;
+ if (!serial || !serial[0])
+ continue;
+ if (!strncmp(prefix, serial, strlen(prefix))) {
+ match = serial;
+ nr++;
+ }
-/* this is used by magic sockets to rig local sockets to
- send the go-ahead message when they connect */
-static void local_socket_ready_notify(asocket *s)
-{
- s->ready = local_socket_ready;
- s->close = local_socket_close;
- sdb_write(s->fd, "OKAY", 4);
- s->ready(s);
+ if (nr > 1) {
+ match = NULL;
+ break;
+ }
+ }
+ sdb_mutex_unlock(&transport_lock, "transport find_transports");
+
+ if (nr == 1 && match) {
+ *serial_out = strdup(match);
+ } else if (nr == 0) {
+ asprintf(serial_out, "device not found");
+ } else if (nr > 1) {
+ asprintf(serial_out, "more than one device and emulator");
+ }
+
+ return nr;
}
-/* this is used by magic sockets to rig local sockets to
- send the failure message if they are closed before
- connected (to avoid closing them without a status message) */
-static void local_socket_close_notify(asocket *s)
+static void unregister_all_tcp_transports()
{
- s->ready = local_socket_ready;
- s->close = local_socket_close;
- sendfailmsg(s->fd, "closed");
- s->close(s);
+ sdb_mutex_lock(&transport_lock, "transport unregister_all_tcp_transports");
+
+ LIST_NODE* curptr = transport_list;
+ while(curptr != NULL) {
+ TRANSPORT* t = curptr->data;
+ curptr = curptr->next_ptr;
+ if (t->type == kTransportLocal && t->sdb_port == 0) {
+ //just kick the transport. transport is destroied by transport thread.
+ if(!t->kicked) {
+ t->kicked = 1;
+ t->kick(t);
+ }
+ }
+ }
+
+ sdb_mutex_unlock(&transport_lock, "transport unregister_all_tcp_transports");
}
-unsigned unhex(unsigned char *s, int len)
+static int handle_host_request(char *service, SDB_SOCKET* socket)
{
- unsigned n = 0, c;
-
- while(len-- > 0) {
- switch((c = *s++)) {
- case '0': case '1': case '2':
- case '3': case '4': case '5':
- case '6': case '7': case '8':
- case '9':
- c -= '0';
- break;
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f':
- c = c - 'a' + 10;
- break;
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F':
- c = c - 'A' + 10;
- break;
- default:
- return 0xffffffff;
+ LOG_INFO("LS(%X)\n", socket->fd);
+ char cmd_buf[1024];
+ int cbuf_size = sizeof cmd_buf;
+
+ if (!strncmp(service, "serial-match:", 13)) {
+ char *tmp = service + 13;
+ char *serial = NULL;
+ int ret = -1;
+ D("Try to find device for: %s\n", tmp);
+ ret = find_transports(&serial, tmp);
+ if (ret <= 0) {
+ LOG_ERROR("No device found\n");
+ sendfailmsg(socket->fd, serial);
+ } else if (ret == 1) {
+ sendokmsg(socket->fd, serial);
+ } else {
+ LOG_ERROR("found more than one devices matched: %d\n", ret);
+ sendfailmsg(socket->fd, serial);
+ }
+ free(serial);
+ return 0;
+ }
+ // return a list of all connected devices
+ if (!strcmp(service, "devices")) {
+ list_transports(cmd_buf, cbuf_size);
+ sendokmsg(socket->fd, cmd_buf);
+ return 0;
+ }
+
+ // add a new TCP transport, device or emulator
+ if (!strncmp(service, "connect:", 8)) {
+ char* host = service + 8;
+ char* portstr = strchr(host, ':');
+ int port = -1;
+
+ if(portstr) {
+ *portstr++ = 0;
+ if(!sscanf(portstr, "%d", &port)) {
+ snprintf(cmd_buf, cbuf_size, "bad port format '%s'", portstr);
+ goto connect_done;
+ }
}
+ connect_emulator(host, port, cmd_buf, cbuf_size);
- n = (n << 4) | c;
+connect_done:
+ sendokmsg(socket->fd, cmd_buf);
+ return 0;
}
- return n;
-}
+ // remove TCP transport
+ if (!strncmp(service, "disconnect:", 11)) {
+ char* serial = service + 11;
+ if (serial[0]) {
+ if (!strchr(serial, ':')) {
+ snprintf(cmd_buf, cbuf_size, "%s:26101", serial);
+ serial = cmd_buf;
+ }
+ TRANSPORT *t = acquire_one_transport(kTransportAny, serial, NULL);
-/* skip_host_serial return the position in a string
- skipping over the 'serial' parameter in the SDB protocol,
- where parameter string may be a host:port string containing
- the protocol delimiter (colon). */
-char *skip_host_serial(char *service) {
- char *first_colon, *serial_end;
+ if (t) {
+ cmd_buf[0] = '\0';
+ kick_transport(t);
+ } else {
+ snprintf(cmd_buf, cbuf_size, "No such device %s", serial);
+ }
+ } else {
+ unregister_all_tcp_transports();
+ cmd_buf[0] = '\0';
+ }
- first_colon = strchr(service, ':');
- if (!first_colon) {
- /* No colon in service string. */
- return NULL;
+ sendokmsg(socket->fd, cmd_buf);
+ return 0;
}
- serial_end = first_colon;
- if (isdigit(serial_end[1])) {
- serial_end++;
- while ((*serial_end) && isdigit(*serial_end)) {
- serial_end++;
+
+ if (!strncmp(service, "device_con:", 11)) {
+ char* _host = service + 11;
+ char host_buf[4096];
+ char target_buf[4096];
+ char full_cmd[4096];
+ char full_serial[256];
+ strncpy(host_buf, _host, sizeof(host_buf) - 1);
+ _host = host_buf;
+ char* serial = strchr(host_buf, ':');
+ *(serial) = '\0';
+ serial++;
+
+ int fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM);
+ if (fd < 0) {
+ snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host);
+ LOG_ERROR(target_buf);
+ sendfailmsg(socket->fd, target_buf);
+ return 0;
+ }
+ D("FD(%d) remote connected with host: %s\n", fd, _host);
+
+ D("FULL_CMD %s\n", full_cmd);
+ snprintf(full_cmd, sizeof(full_cmd), "host:serial-match:%s", serial);
+ if(!send_service_with_length(fd, full_cmd, socket->fd)) {
+ if(!sdb_status(fd, socket->fd)) {
+ int n = read_msg_size(fd);
+ if(n > 0 && n < 256) {
+ if(!readx(fd, full_serial, n)) {
+ full_serial[n] = 0;
+ serial = full_serial;
+ goto success;
+ }
+ }
+ snprintf(target_buf, sizeof(target_buf), "fail to read full serial of %s", serial);
+ sendfailmsg(socket->fd, target_buf);
+ }
+ }
+ sdb_close(fd);
+ return 0;
+
+success:
+ sdb_close(fd);
+ fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM);
+ if (fd < 0) {
+ snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host);
+ LOG_ERROR(target_buf);
+ sendfailmsg(socket->fd, target_buf);
+ return 0;
}
- if ((*serial_end) != ':') {
- // Something other than numbers was found, reset the end.
- serial_end = first_colon;
+ D("FD(%d) remote connected\n", fd);
+ get_host_prefix(target_buf, sizeof target_buf, kTransportAny, serial, host);
+ snprintf(full_cmd, sizeof full_cmd, "%s_dev_con",target_buf);
+
+ D("FULL_CMD: %s\n", full_cmd);
+ if(!send_service_with_length(fd, full_cmd, socket->fd)) {
+ if(!sdb_status(fd, socket->fd)) {
+ if(!register_device_con_transport(fd, serial)) {
+ snprintf(target_buf, sizeof target_buf, "success to connect with remote target '%s'\n", serial);
+ snprintf(full_cmd, sizeof(full_cmd), "OKAY%04x%s",(unsigned)strlen(target_buf), target_buf);
+ if(!writex(socket->fd, full_cmd, strlen(full_cmd))) {
+ return 0;
+ }
+ else {
+ sendfailmsg(socket->fd, "fail to write OKAY message\n");
+ }
+ }
+ else {
+ sendfailmsg(socket->fd, "fail to connect with remote device\n");
+ }
+ }
}
+ sdb_close(fd);
+ return 0;
}
- return serial_end;
+
+ // returns our value for SDB_SERVER_VERSION
+ if (!strcmp(service, "version")) {
+ snprintf(cmd_buf, cbuf_size, "%04x", SDB_SERVER_VERSION);
+ sendokmsg(socket->fd, cmd_buf);
+ return 0;
+ }
+
+ // indicates a new emulator instance has started
+ if (!strncmp(service,"emulator:",9)) { /* tizen specific */
+ D("new emulator is in\n");
+ char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR);
+ int port = 0;
+
+ if (tmp == NULL) {
+ port = atoi(service+9);
+ } else {
+ port = atoi(tmp);
+ tmp = strtok(NULL, DEVICEMAP_SEPARATOR);
+ }
+ local_connect(port, tmp);
+ return 0;
+ }
+
+ if(!strcmp(service, "kill")) {
+ LOG_INFO("sdb is being killed\n");
+ sdb_cleanup();
+ sdb_write(socket->fd, "OKAY", 4);
+ exit(0);
+ }
+
+ return -1;
}
-static int smart_socket_enqueue(asocket *s, apacket *p)
+static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p)
{
unsigned len;
- char *service = NULL;
- char* serial = NULL;
- transport_type ttype = kTransportAny;
- D("SS(%d): enqueue %d\n", s->id, p->len);
+ D("LS(%X)\n", s->local_id);
- if(s->pkt_first == 0) {
- s->pkt_first = p;
- s->pkt_last = p;
- } else {
- if((s->pkt_first->len + p->len) > MAX_PAYLOAD) {
- D("SS(%d): overflow\n", s->id);
+ if(s->pkt_list == NULL) {
+ prepend(&s->pkt_list, p);
+ }
+ else {
+ PACKET* socket_packet = s->pkt_list->data;
+ if((socket_packet->len + p->len) > MAX_PAYLOAD) {
+ D("SS(%d): overflow\n", s->local_id);
put_apacket(p);
goto fail;
}
- memcpy(s->pkt_first->data + s->pkt_first->len,
+ memcpy(socket_packet->data + socket_packet->len,
p->data, p->len);
- s->pkt_first->len += p->len;
+ socket_packet->len += p->len;
put_apacket(p);
- p = s->pkt_first;
+ p = socket_packet;
}
/* don't bother if we can't decode the length */
if(p->len < 4) return 0;
len = unhex(p->data, 4);
+
if((len < 1) || (len > 1024)) {
- D("SS(%d): bad size (%d)\n", s->id, len);
+ D("LS(%X): bad size (%d)\n", s->local_id, len);
goto fail;
}
- D("SS(%d): len is %d\n", s->id, len );
/* can't do anything until we have the full header */
if((len + 4) > p->len) {
- D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len);
+ D("LS(%X): waiting for %d more bytes in smart socket\n", s->local_id, len+4 - p->len);
return 0;
}
p->data[len + 4] = 0;
+ D("LS(%X) %s\n", s->local_id, p->data + 4);
- D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4));
-
- service = (char *)p->data + 4;
- if(!strncmp(service, PREFIX_HOST_SERIAL, strlen(PREFIX_HOST_SERIAL))) {
- char* serial_end;
- service += strlen(PREFIX_HOST_SERIAL);
-
- // serial number should follow "host:" and could be a host:port string.
- serial_end = skip_host_serial(service);
- if (serial_end) {
- *serial_end = 0; // terminate string
- serial = service;
- service = serial_end + 1;
- }
- ttype = kTransportUsb;
- } else if (!strncmp(service, PREFIX_HOST_USB, strlen(PREFIX_HOST_USB))) {
- service += strlen(PREFIX_HOST_USB);
- } else if (!strncmp(service, PREFIX_HOST_LOCAL, strlen(PREFIX_HOST_LOCAL))) {
- ttype = kTransportLocal;
- service += strlen(PREFIX_HOST_LOCAL);
- } else if (!strncmp(service, PREFIX_HOST, strlen(PREFIX_HOST))) {
- ttype = kTransportAny;
- service += strlen(PREFIX_HOST);
- } else {
- service = NULL;
+ char* host_str = (char *)p->data + 4;
+ char *service = NULL;
+ char* err_str = NULL;
+ TRANSPORT* t = NULL;
+
+ if(parse_host_service(host_str, &service, &t, &err_str) == 1) {
+ if (t && t->connection_state != CS_OFFLINE) {
+ s->transport = t;
+ sdb_write(s->fd, "OKAY", 4);
+ D("LS(%X) get transport T(%s)", s->local_id, t->device_name);
+ } else {
+ if(t != NULL) {
+ err_str = (char*)TRANSPORT_ERR_TARGET_OFFLINE;
+ }
+ LOG_ERROR("LS(%X) get no transport", s->local_id);
+ sendfailmsg(s->fd, err_str);
+ }
+ p->len = 0;
+ return 0;
}
if (service) {
- asocket *s2;
-
- /* some requests are handled immediately -- in that
- ** case the handle_host_request() routine has sent
- ** the OKAY or FAIL message and all we have to do
- ** is clean up.
- */
- if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
+ if(handle_request_with_t(s, service, t, err_str) == 0) {
+ D( "LS(%X): handled host service with '%s'\n", s->local_id, service );
+ goto fail;
+ }
+
+ if(handle_host_request(service, s) == 0) {
/* XXX fail message? */
- D( "SS(%d): handled host service '%s'\n", s->id, service );
+ D( "LS(%X): handled host service '%s'\n", s->local_id, service );
goto fail;
}
- if (!strncmp(service, "transport", strlen("transport"))) {
- D( "SS(%d): okay transport\n", s->id );
- p->len = 0;
+
+ if (!strcmp(service,"track-devices")) {
+ free_list(s->pkt_list, put_apacket);
+ s->pkt_list = NULL;
+ D("LS(%X): OKAY\n", s->local_id);
+ SET_SOCKET_STATUS(s, DEVICE_TRACKER);
+ sdb_write(s->fd, "OKAY", 4);
+
+ D( "LS(%X) fd: '%d' for device tracking\n", s->local_id, s->fd );
+ char buffer[1024];
+ int len;
+ len = list_transports_msg(buffer, sizeof(buffer));
+ device_tracker_send(s, buffer, len);
return 0;
}
-
- /* try to find a local service with this name.
- ** if no such service exists, we'll fail out
- ** and tear down here.
- */
- s2 = create_host_service_socket(service, serial);
- if(s2 == 0) {
- D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
- sendfailmsg(s->peer->fd, "unknown host service");
+ else {
+ D( "LS(%X): couldn't create host service '%s'\n", s->local_id, service );
+ sendfailmsg(s->fd, "unknown host service");
goto fail;
}
-
- /* we've connected to a local host service,
- ** so we make our peer back into a regular
- ** local socket and bind it to the new local
- ** service socket, acknowledge the successful
- ** connection, and close this smart socket now
- ** that its work is done.
- */
- sdb_write(s->peer->fd, "OKAY", 4);
-
- s->peer->ready = local_socket_ready;
- s->peer->close = local_socket_close;
- s->peer->peer = s2;
- s2->peer = s->peer;
- s->peer = 0;
- D( "SS(%d): okay\n", s->id );
- s->close(s);
-
- /* initial state is "ready" */
- s2->ready(s2);
- return 0;
}
if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
- /* if there's no remote we fail the connection
- ** right here and terminate it
- */
- sendfailmsg(s->peer->fd, "device offline (x)");
+ sendfailmsg(s->fd, "device offline (x)");
goto fail;
}
+ if (!(s->transport) || (s->transport->connection_state == CS_PWLOCK)) {
+ sendfailmsg(s->fd, "device locked");
+ goto fail;
+ }
- /* instrument our peer to pass the success or fail
- ** message back once it connects or closes, then
- ** detach from it, request the connection, and
- ** tear down
- */
- s->peer->ready = local_socket_ready_notify;
- s->peer->close = local_socket_close_notify;
- s->peer->peer = 0;
- /* give him our transport and upref it */
- s->peer->transport = s->transport;
-
- connect_to_remote(s->peer, (char*) (p->data + 4));
- s->peer = 0;
- s->close(s);
- return 1;
+ if(s->transport->type == kTransportRemoteDevCon) {
+ if(assign_remote_connect_socket_rid(s)) {
+ sendfailmsg(s->fd, "remote connect socket exceeds limit. cannot create remote socket\n");
+ local_socket_close(s);
+ return -1;
+ }
+ }
+
+ SET_SOCKET_STATUS(s, NOTIFY);
+ connect_to_remote(s, (char*) (p->data + 4));
+ free_list(s->pkt_list, put_apacket);
+ s->pkt_list = NULL;
+ FDEVENT_DEL(&s->fde, FDE_READ);
+ return 0;
fail:
- /* we're going to close our peer as a side-effect, so
- ** return -1 to signal that state to the local socket
- ** who is enqueueing against us
- */
- s->close(s);
+
+ free_list(s->pkt_list, put_apacket);
+ s->pkt_list = NULL;
+ if(!HAS_SOCKET_STATUS(s, REMOTE_CON)) {
+ //do not close socket if it is remote connected socket
+ local_socket_close(s);
+ }
return -1;
}
-static void smart_socket_ready(asocket *s)
-{
- D("SS(%d): ready\n", s->id);
+int assign_remote_connect_socket_rid (SDB_SOCKET* s) {
+ if(remote_con_cur_r_id > remote_con_r_max) {
+ LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd);
+ return -1;
+ }
+ int remote_id = (remote_con_cur_r_id << 4) | remote_con_flag;
+ LOG_INFO("LS(%X) -> LS_R(%X)\n", s->local_id, remote_id);
+ s->local_id = remote_id;
+ remote_con_cur_r_id++;
+ return 0;
}
-static void smart_socket_close(asocket *s)
-{
- D("SS(%d): closed\n", s->id);
- if(s->pkt_first){
- put_apacket(s->pkt_first);
+int assign_remote_connect_socket_lid (SDB_SOCKET* s) {
+ if(remote_con_cur_l_number >= remote_con_l_max) {
+ LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd);
+ return -1;
}
- if(s->peer) {
- s->peer->peer = 0;
- s->peer->close(s->peer);
- s->peer = 0;
+ int i = 0;
+ for(i = 0; i< remote_con_l_max; i++) {
+ if(remote_con_l_table[i] == 0) {
+ unsigned int remote_id = i | remote_con_flag;
+ remote_con_cur_l_number++;
+ LOG_INFO("LS(%X) -> LS_L(%X)\n", s->local_id, remote_id);
+ s->local_id = remote_id;
+ remote_con_l_table[i] = 1;
+ return 0;
+ }
}
- free(s);
+ LOG_ERROR("not enough space in remote_con_l_table\n");
+ return -1;
}
-asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act))
+int
+device_tracker_send( SDB_SOCKET* local_socket,
+ const char* buffer,
+ int len )
{
- D("Creating smart socket \n");
- asocket *s = calloc(1, sizeof(asocket));
- if (s == NULL) fatal("cannot allocate socket");
- s->enqueue = smart_socket_enqueue;
- s->ready = smart_socket_ready;
- s->close = smart_socket_close;
- s->extra = action_cb;
-
- D("SS(%d): created %p\n", s->id, action_cb);
- return s;
+ D("device tracker send to the socket. LS(%X), fd: '%d'\n", local_socket->local_id, local_socket->fd);
+ PACKET* p = get_apacket();
+
+ memcpy(p->data, buffer, len);
+ p->len = len;
+ p->ptr = p->data;
+ //packet should not be freed after local_socket_enqueue because it can be still used in local socket packet queue.
+ return local_socket_enqueue( local_socket, p );
}
-void smart_socket_action(asocket *s, const char *act)
-{
+static void connect_emulator(char* host, int port, char* buf, int buf_len) {
+ if(port < 0) {
+ port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
+ }
+ LOG_INFO("connecting ip: '%s', port: '%d'\n", host, port);
-}
+ int fd = sdb_host_connect(host, port, SOCK_STREAM);
+ if (fd < 0) {
+ snprintf(buf, buf_len, "fail to connect to %s", host);
+ return;
+ }
-void connect_to_smartsocket(asocket *s)
-{
- D("Connecting to smart socket \n");
- asocket *ss = create_smart_socket(smart_socket_action);
- s->peer = ss;
- ss->peer = s;
- s->ready(s);
+ LOG_INFO("FD(%d) connected\n", fd);
+ close_on_exec(fd);
+ disable_tcp_nagle(fd);
+ char serial[100];
+ snprintf(serial, sizeof(serial), "%s:%d", host, port);
+ register_socket_transport(fd, serial, port, 0, NULL);
+ snprintf(buf, buf_len, "connected to %s", serial);
}
--- /dev/null
+/*
+* SDB - Smart Development Bridge
+*
+* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* Contact:
+* Ho Namkoong <ho.namkoong@samsung.com>
+* Yoonki Park <yoonki.park@samsung.com>
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* Contributors:
+* - S-Core Co., Ltd
+*
+*/
+
+#ifndef 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_ */
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;
}
*dest++ = *source++;
}
+ *dest = '\0';
}
- *dest = '\0';
return start;
}
#include <errno.h>
#include "fdevent.h"
#include "utils.h"
+#include "transport.h"
+#include "sockets.h"
+#include "sdb_constants.h"
+#include "strutils.h"
+#include "memutils.h"
+#include "listener.h"
+#include "log.h"
+
#define TRACE_TAG TRACE_TRANSPORT
-#include "sdb.h"
-static void transport_unref(atransport *t);
+static void transport_unref(TRANSPORT *t);
+static void handle_packet(PACKET *p, TRANSPORT *t);
+static void parse_banner(char *banner, TRANSPORT *t);
+static void wakeup_select(T_PACKET* t_packet);
+static void update_transports(void);
+static void run_transport_close(TRANSPORT* t);
+static void encoding_packet(PACKET* p);
+static int check_header(PACKET *p);
+static int check_data(PACKET *p);
+static void dump_hex( const unsigned char* ptr, size_t len);
-static atransport transport_list = {
- .next = &transport_list,
- .prev = &transport_list,
-};
+LIST_NODE* transport_list = NULL;
SDB_MUTEX_DEFINE( transport_lock );
+SDB_MUTEX_DEFINE( wakeup_select_lock );
#ifdef _WIN32 /* FIXME : move to sysdeps.h later */
int asprintf( char **, char *, ... );
}
#endif
-#if SDB_TRACE
-#define MAX_DUMP_HEX_LEN 16
-static void dump_hex( const unsigned char* ptr, size_t len )
+#define MAX_DUMP_HEX_LEN 30
+static void dump_hex( const unsigned char* ptr, size_t len)
{
- int nn, len2 = len;
- // Build a string instead of logging each character.
- // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
- char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
+ if(SDB_TRACING) {
+ char hex_str[]= "0123456789abcdef";
- if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
+ if(len > MAX_DUMP_HEX_LEN) {
+ len = MAX_DUMP_HEX_LEN;
+ }
- for (nn = 0; nn < len2; nn++) {
- sprintf(pb, "%02x", ptr[nn]);
- pb += 2;
- }
- sprintf(pb++, " ");
+ int i;
+ char hex[len*2 + 1];
+ for (i = 0; i < len; i++) {
+ hex[i*2 + 0] = hex_str[ptr[i] >> 4];
+ hex[i*2 + 1] = hex_str[ptr[i] & 0x0F];
+ }
+ hex[len*2] = '\0';
- for (nn = 0; nn < len2; nn++) {
- int c = ptr[nn];
- if (c < 32 || c > 127)
- c = '.';
- *pb++ = c;
+ char asci[len + 1];
+ for (i = 0; i < len; i++) {
+ if ((int)ptr[i] >= 32 && (int)ptr[i] <= 127) {
+ asci[i] = ptr[i];
+ }
+ else {
+ asci[i] = '.';
+ }
+ }
+ asci[len] = '\0';
+
+ DR("HEX:'%s', ASCI:'%s'\n", hex, asci);
}
- *pb++ = '\0';
- DR("%s\n", buffer);
}
-#endif
void
-kick_transport(atransport* t)
+kick_transport(TRANSPORT* t)
{
if (t && !t->kicked)
{
int kicked;
- sdb_mutex_lock(&transport_lock);
+ sdb_mutex_lock(&transport_lock, "transport kick_transport");
kicked = t->kicked;
if (!kicked)
t->kicked = 1;
- sdb_mutex_unlock(&transport_lock);
+ sdb_mutex_unlock(&transport_lock, "transport kick_transport");
if (!kicked)
t->kick(t);
}
}
-void
-run_transport_disconnects(atransport* t)
+static void run_transport_close(TRANSPORT* t)
{
- adisconnect* dis = t->disconnects.next;
+ D("T(%s)\n", t->serial);
+ LIST_NODE* curptr = listener_list;
- D("%s: run_transport_disconnects\n", t->serial);
- while (dis != &t->disconnects) {
- adisconnect* next = dis->next;
- dis->func( dis->opaque, t );
- dis = next;
- }
-}
+ while(curptr != NULL) {
+ LISTENER* l = curptr->data;
+ curptr = curptr->next_ptr;
-#if SDB_TRACE
-static void
-dump_packet(const char* name, const char* func, apacket* p)
-{
- unsigned command = p->msg.command;
- int len = p->msg.data_length;
- char cmd[9];
- char arg0[12], arg1[12];
- int n;
-
- for (n = 0; n < 4; n++) {
- int b = (command >> (n*8)) & 255;
- if (b < 32 || b >= 127)
- break;
- cmd[n] = (char)b;
- }
- if (n == 4) {
- cmd[4] = 0;
- } else {
- /* There is some non-ASCII name in the command, so dump
- * the hexadecimal value instead */
- snprintf(cmd, sizeof cmd, "%08x", command);
+ if(l->transport == t) {
+ D("LN(%s) being closed by T(%s)\n", l->local_name, t->serial);
+ remove_node(&listener_list, l->node, free_listener);
+ }
}
- if (p->msg.arg0 < 256U)
- snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
- else
- snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
+ curptr = local_socket_list;
+ while(curptr != NULL) {
+ SDB_SOCKET* s = curptr->data;
+ curptr = curptr->next_ptr;
- if (p->msg.arg1 < 256U)
- snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
- else
- snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
-
- D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ",
- name, func, cmd, arg0, arg1, len);
- dump_hex(p->data, len);
-}
-#endif /* SDB_TRACE */
-
-static int
-read_packet(int fd, const char* name, apacket** ppacket)
-{
- char *p = (char*)ppacket; /* really read a packet address */
- int r;
- int len = sizeof(*ppacket);
- char buff[8];
- if (!name) {
- snprintf(buff, sizeof buff, "fd=%d", fd);
- name = buff;
- }
- while(len > 0) {
- r = sdb_read(fd, p, len);
- if(r > 0) {
- len -= r;
- p += r;
- } else {
- D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
- if((r < 0) && (errno == EINTR)) continue;
- return -1;
+ if(s->transport == t) {
+ D("LS(%X) FD(%d) being closed by T(%s)\n", s->local_id, s->fd, t->serial);
+ local_socket_close(s);
}
}
-
-#if SDB_TRACE
- if (SDB_TRACING) {
- dump_packet(name, "from remote", *ppacket);
- }
-#endif
- return 0;
}
-static int
-write_packet(int fd, const char* name, apacket** ppacket)
+
+void dump_packet(const char* name, const char* func, PACKET* p)
{
- char *p = (char*) ppacket; /* we really write the packet address */
- int r, len = sizeof(ppacket);
- char buff[8];
- if (!name) {
- snprintf(buff, sizeof buff, "fd=%d", fd);
- name = buff;
- }
+ if(SDB_TRACING) {
+ unsigned cmd = p->msg.command;
+ char command[9];
-#if SDB_TRACE
- if (SDB_TRACING) {
- dump_packet(name, "to remote", *ppacket);
- }
-#endif
- len = sizeof(ppacket);
- while(len > 0) {
- r = sdb_write(fd, p, len);
- if(r > 0) {
- len -= r;
- p += r;
- } else {
- D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
- if((r < 0) && (errno == EINTR)) continue;
- return -1;
+ if(cmd == A_CLSE) {
+ snprintf(command, sizeof command, "%s", "A_CLSE");
}
- }
- return 0;
-}
-
-static void transport_socket_events(int fd, unsigned events, void *_t)
-{
- atransport *t = _t;
- D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events);
- if(events & FDE_READ){
- apacket *p = 0;
- if(read_packet(fd, t->serial, &p)){
- D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd);
- } else {
- handle_packet(p, (atransport *) _t);
+ else if(cmd == A_CNXN) {
+ snprintf(command, sizeof command, "%s", "A_CNXN");
+ }
+ else if(cmd == A_OPEN) {
+ snprintf(command, sizeof command, "%s", "A_OPEN");
}
+ else if(cmd == A_OKAY) {
+ snprintf(command, sizeof command, "%s", "A_OKAY");
+ }
+ else if(cmd == A_WRTE) {
+ snprintf(command, sizeof command, "%s", "A_WRTE");
+ }
+ else if(cmd == A_TCLS) {
+ snprintf(command, sizeof command, "%s", "A_TCLS");
+ }
+ else {
+ //unrecongnized command dump the hexadecimal value.
+ snprintf(command, sizeof command, "%08x", cmd);
+ }
+
+ D("T(%s) %s: [%s] arg0=%X arg1=%X (len=%d) (total_msg_len=%d)\n",
+ name, func, command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->len);
+ dump_hex(p->data, p->msg.data_length);
}
}
-void send_packet(apacket *p, atransport *t)
-{
+static void encoding_packet(PACKET* p) {
unsigned char *x;
unsigned sum;
unsigned count;
sum += *x++;
}
p->msg.data_check = sum;
+}
- print_packet("send", p);
+void send_packet(PACKET *p, TRANSPORT *t)
+{
+ if(t != NULL && t->connection_state != CS_OFFLINE) {
+ encoding_packet(p);
- if (t == NULL) {
- D("Transport is null \n");
- // Zap errno because print_packet() and other stuff have errno effect.
- errno = 0;
- fatal_errno("Transport is null");
+ D("%s: transport got packet, sending to remote\n", t->serial);
+ t->write_to_remote(p, t);
}
-
- if(write_packet(t->transport_socket, t->serial, &p)){
- fatal_errno("cannot enqueue packet on transport socket");
+ else {
+ if (t == NULL) {
+ D("Transport is null \n");
+ errno = 0;
+ LOG_FATAL("Transport is null\n");
+ }
+ else {
+ D("%s: transport ignoring packet while offline\n", t->serial);
+ }
}
}
-/* The transport is opened by transport_register_func before
-** the input and output threads are started.
-**
-** The output thread issues a SYNC(1, token) message to let
-** the input thread know to start things up. In the event
-** of transport IO failure, the output thread will post a
-** SYNC(0,0) message to ensure shutdown.
-**
-** The transport will not actually be closed until both
-** threads exit, but the input thread will kick the transport
-** on its way out to disconnect the underlying device.
-*/
-
-static void *output_thread(void *_t)
-{
- atransport *t = _t;
- apacket *p;
-
- D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
- t->serial, t->fd, t->sync_token + 1);
- p = get_apacket();
- p->msg.command = A_SYNC;
- p->msg.arg0 = 1;
- p->msg.arg1 = ++(t->sync_token);
- p->msg.magic = A_SYNC ^ 0xffffffff;
- if(write_packet(t->fd, t->serial, &p)) {
- put_apacket(p);
- D("%s: failed to write SYNC packet\n", t->serial);
- goto oops;
- }
+static __inline__ void wakeup_select(T_PACKET* t_packet) {
+ sdb_mutex_lock(&wakeup_select_lock, "wakeup_select");
+ writex(fdevent_wakeup_send, &t_packet, sizeof(t_packet));
+ sdb_mutex_unlock(&wakeup_select_lock, "wakeup_select");
+}
- D("%s: data pump started\n", t->serial);
- for(;;) {
- p = get_apacket();
+static void handle_packet(PACKET *p, TRANSPORT *t)
+{
+ unsigned int cmd = p->msg.command;
+ T_PACKET* t_packet = malloc(sizeof(T_PACKET));
+ t_packet->t = t;
+ t_packet->p = NULL;
- if(t->read_from_remote(p, t) == 0){
- D("%s: received remote packet, sending to transport\n",
- t->serial);
- if(write_packet(t->fd, t->serial, &p)){
- put_apacket(p);
- D("%s: failed to write apacket to transport\n", t->serial);
- goto oops;
- }
- } else {
- D("%s: remote read failed for transport\n", t->serial);
- put_apacket(p);
- break;
- }
+ //below commands should be done in main thread. packet is used in wakeup_select_func. Do not put a packet
+ if(cmd == A_WRTE || cmd == A_CLSE || cmd == A_CNXN || cmd == A_OKAY || cmd == A_STAT) {
+ ++(t->req);
+ t_packet->p = p;
+ wakeup_select(t_packet);
+ return;
}
-
- D("%s: SYNC offline for transport\n", t->serial);
- p = get_apacket();
- p->msg.command = A_SYNC;
- p->msg.arg0 = 0;
- p->msg.arg1 = 0;
- p->msg.magic = A_SYNC ^ 0xffffffff;
- if(write_packet(t->fd, t->serial, &p)) {
- put_apacket(p);
- D("%s: failed to write SYNC apacket to transport", t->serial);
+ else if(cmd == A_OPEN) {
+ LOG_FATAL("server does not handle A_OPEN\n");
+ exit(1);
}
-
-oops:
- D("%s: transport output thread is exiting\n", t->serial);
- kick_transport(t);
- transport_unref(t);
- return 0;
+ D("Unknown packet command %08x\n", p->msg.command);
+ put_apacket(p);
+ free(t_packet);
}
-static void *input_thread(void *_t)
+#define CNXN_DATA_MAX_TOKENS 3
+static void parse_banner(char *data, TRANSPORT *t)
{
- atransport *t = _t;
- apacket *p;
- int active = 0;
+ char *banner = s_strdup(data);
+ char *end = NULL;
- D("%s: starting transport input thread, reading from fd %d\n",
- t->serial, t->fd);
+ end = strchr(banner, ':');
+ if(end) {
+ *end = '\0';
+ }
+ const char* target_banner = STATE_HOST;
+ if(!strcmp(banner, STATE_DEVICE)) {
+ t->connection_state = CS_DEVICE;
+ target_banner = STATE_DEVICE;
+ }
+ else if(!strcmp(banner, STATE_BOOTLOADER)){
+ t->connection_state = CS_BOOTLOADER;
+ target_banner = STATE_BOOTLOADER;
+ }
+ else if(!strcmp(banner, STATE_RECOVERY)) {
+ t->connection_state = CS_RECOVERY;
+ target_banner = STATE_RECOVERY;
+ }
+ else if(!strcmp(banner, STATE_SIDELOAD)) {
+ t->connection_state = CS_SIDELOAD;
+ target_banner = STATE_SIDELOAD;
+ }
+ else {
+ t->connection_state = CS_HOST;
+ }
+ if (banner != NULL) {
+ s_free(banner);
+ }
+ // since version 2
+ char *tokens[CNXN_DATA_MAX_TOKENS];
+ size_t cnt = tokenize(data, "::", tokens, CNXN_DATA_MAX_TOKENS);
- for(;;){
- if(read_packet(t->fd, t->serial, &p)) {
- D("%s: failed to read apacket from transport on fd %d\n",
- t->serial, t->fd );
- break;
- }
- if(p->msg.command == A_SYNC){
- if(p->msg.arg0 == 0) {
- D("%s: transport SYNC offline\n", t->serial);
- put_apacket(p);
- break;
- } else {
- if(p->msg.arg1 == t->sync_token) {
- D("%s: transport SYNC online\n", t->serial);
- active = 1;
- } else {
- D("%s: transport ignoring SYNC %d != %d\n",
- t->serial, p->msg.arg1, t->sync_token);
- }
- }
- } else {
- if(active) {
- D("%s: transport got packet, sending to remote\n", t->serial);
- t->write_to_remote(p, t);
- } else {
- D("%s: transport ignoring packet while offline\n", t->serial);
- }
+ if (cnt == 3) {
+ // update device_name except usb device but it should be changed soon.
+ if (strcmp(STATE_UNKNOWN, tokens[1])) {
+ t->device_name = strdup(tokens[1]);
}
- put_apacket(p);
+ if (!strcmp(tokens[2], "1")) {
+ t->connection_state = CS_PWLOCK;
+ target_banner = STATE_LOCKED;
+ }
}
- // this is necessary to avoid a race condition that occured when a transport closes
- // while a client socket is still active.
- close_all_sockets(t);
+ if (cnt) {
+ free_strings(tokens, cnt);
+ }
- D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
- kick_transport(t);
- transport_unref(t);
- return 0;
+ D("setting connection_state to '%s'\n", target_banner);
+ update_transports();
+ return;
}
-
-static int transport_registration_send = -1;
-static int transport_registration_recv = -1;
-static fdevent transport_registration_fde;
-
-
-static int list_transports_msg(char* buffer, size_t bufferlen)
+int list_transports_msg(char* buffer, size_t bufferlen)
{
char head[5];
int len;
return len;
}
-/* this adds support required by the 'track-devices' service.
- * this is used to send the content of "list_transport" to any
- * number of client connections that want it through a single
- * live TCP connection
- */
-typedef struct device_tracker device_tracker;
-struct device_tracker {
- asocket socket;
- int update_needed;
- device_tracker* next;
-};
-
-/* linked list of all device trackers */
-static device_tracker* device_tracker_list;
-
-static void
-device_tracker_remove( device_tracker* tracker )
+static void update_transports(void)
{
- device_tracker** pnode = &device_tracker_list;
- device_tracker* node = *pnode;
+ D("update transports\n");
+ char buffer[1024];
+ int len;
- sdb_mutex_lock( &transport_lock );
- while (node) {
- if (node == tracker) {
- *pnode = node->next;
- break;
- }
- pnode = &node->next;
- node = *pnode;
- }
- sdb_mutex_unlock( &transport_lock );
-}
+ len = list_transports_msg(buffer, sizeof(buffer));
-static void
-device_tracker_close( asocket* socket )
-{
- device_tracker* tracker = (device_tracker*) socket;
- asocket* peer = socket->peer;
- D( "device tracker %p removed\n", tracker);
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
+ LIST_NODE* curptr = local_socket_list;
+ while(curptr != NULL) {
+ SDB_SOCKET *s = curptr->data;
+ curptr = curptr->next_ptr;
+ if (HAS_SOCKET_STATUS(s, DEVICE_TRACKER)) {
+ device_tracker_send(s, buffer, len);
+ }
}
- device_tracker_remove(tracker);
- free(tracker);
}
-static int
-device_tracker_enqueue( asocket* socket, apacket* p )
-{
- /* you can't read from a device tracker, close immediately */
- put_apacket(p);
- device_tracker_close(socket);
- return -1;
-}
-
-static int
-device_tracker_send( device_tracker* tracker,
- const char* buffer,
- int len )
-{
- apacket* p = get_apacket();
- asocket* peer = tracker->socket.peer;
-
- memcpy(p->data, buffer, len);
- p->len = len;
- return peer->enqueue( peer, p );
-}
+void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t) {
+ PACKET *p = get_apacket();
+ p->msg.arg0 = arg0;
+ p->msg.arg1 = arg1;
+ p->msg.command = cmd;
-
-static void
-device_tracker_ready( asocket* socket )
-{
- device_tracker* tracker = (device_tracker*) socket;
-
- /* we want to send the device list when the tracker connects
- * for the first time, even if no update occured */
- if (tracker->update_needed > 0) {
- char buffer[1024];
- int len;
-
- tracker->update_needed = 0;
-
- len = list_transports_msg(buffer, sizeof(buffer));
- device_tracker_send(tracker, buffer, len);
+ if(data != NULL) {
+ snprintf((char*)p->data, sizeof(p->data), "%s", data);
+ p->msg.data_length = strlen((char*)p->data) + 1;
}
-}
-
-
-asocket*
-create_device_tracker(void)
-{
- device_tracker* tracker = calloc(1,sizeof(*tracker));
-
- if(tracker == 0) fatal("cannot allocate device tracker");
-
- D( "device tracker %p created\n", tracker);
- tracker->socket.enqueue = device_tracker_enqueue;
- tracker->socket.ready = device_tracker_ready;
- tracker->socket.close = device_tracker_close;
- tracker->update_needed = 1;
-
- tracker->next = device_tracker_list;
- device_tracker_list = tracker;
-
- return &tracker->socket;
+ send_packet(p, t);
+ put_apacket(p);
}
-
-/* call this function each time the transport list has changed */
-void update_transports(void)
+static void *transport_thread(void *_t)
{
- char buffer[1024];
- int len;
- device_tracker* tracker;
-
- len = list_transports_msg(buffer, sizeof(buffer));
-
- tracker = device_tracker_list;
- while (tracker != NULL) {
- device_tracker* next = tracker->next;
- /* note: this may destroy the tracker if the connection is closed */
- device_tracker_send(tracker, buffer, len);
- tracker = next;
- }
-}
+ TRANSPORT *t = _t;
+ PACKET *p;
-typedef struct tmsg tmsg;
-struct tmsg
-{
- atransport *transport;
- int action;
-};
+ D("T(%s), FD(%d)\n", t->serial, t->sfd);
+ t->connection_state = CS_WAITCNXN;
+ send_cmd(A_VERSION, MAX_PAYLOAD, A_CNXN, "host::", t);
+ t->connection_state = CS_OFFLINE;
+ // allow the device some time to respond to the connect message
+ sdb_sleep_ms(1000);
-static int
-transport_read_action(int fd, struct tmsg* m)
-{
- char *p = (char*)m;
- int len = sizeof(*m);
- int r;
+ D("%s: data dump started\n", t->serial);
+ while(1) {
+ p = get_apacket();
+ LOG_INFO("T(%s) remote read start\n", t->serial);
- while(len > 0) {
- r = sdb_read(fd, p, len);
- if(r > 0) {
- len -= r;
- p += r;
- } else {
- if((r < 0) && (errno == EINTR)) continue;
- D("transport_read_action: on fd %d, error %d: %s\n",
- fd, errno, strerror(errno));
- return -1;
+ if(t->read_from_remote(t, &p->msg, sizeof(MESSAGE))) {
+ break;
}
- }
- return 0;
-}
-
-static int
-transport_write_action(int fd, struct tmsg* m)
-{
- char *p = (char*)m;
- int len = sizeof(*m);
- int r;
-
- while(len > 0) {
- r = sdb_write(fd, p, len);
- if(r > 0) {
- len -= r;
- p += r;
- } else {
- if((r < 0) && (errno == EINTR)) continue;
- D("transport_write_action: on fd %d, error %d: %s\n",
- fd, errno, strerror(errno));
- return -1;
+ if(check_header(p)) {
+ break;
+ }
+ if(p->msg.data_length) {
+ if(t->read_from_remote(t, p->data, p->msg.data_length)){
+ break;
+ }
+ }
+ if(check_data(p)) {
+ break;
+ }
+ dump_packet(t->serial, "remote_read", p);
+ D("%s: received remote packet, sending to transport\n",
+ t->serial);
+ handle_packet(p, t);
+ }
+ LOG_INFO("T(%s) remote read fail. terminate transport\n", t->serial);
+ put_apacket(p);
+
+ t->connection_state = CS_OFFLINE;
+ do {
+ if(t->req == t->res) {
+ p = get_apacket();
+ p->msg.command = A_TCLS;
+ T_PACKET* t_packet = malloc(sizeof(T_PACKET));
+ t_packet->t = t;
+ t_packet->p = p;
+ wakeup_select(t_packet);
+ break;
+ }
+ else {
+ //TODO this should be changed to wait later.
+ sdb_sleep_ms(1000);
}
}
+ while(1);
return 0;
}
-static sdb_cond_t cond;// = PTHREAD_COND_INITIALIZER;
-
-static void transport_registration_func(int _fd, unsigned ev, void *data)
+void register_transport(TRANSPORT *t)
{
- tmsg m;
- sdb_thread_t output_thread_ptr;
- sdb_thread_t input_thread_ptr;
- int s[2];
- atransport *t;
-
- if(!(ev & FDE_READ)) {
- return;
- }
-
- if(transport_read_action(_fd, &m)) {
- fatal_errno("cannot read transport registration socket");
- }
-
- t = m.transport;
-
- if(m.action == 0){
- D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket);
-
- /* IMPORTANT: the remove closes one half of the
- ** socket pair. The close closes the other half.
- */
- fdevent_remove(&(t->transport_fde));
- sdb_close(t->fd);
-
- sdb_mutex_lock(&transport_lock);
- t->next->prev = t->prev;
- t->prev->next = t->next;
-
- sdb_cond_broadcast(&cond);
- sdb_mutex_unlock(&transport_lock);
-
- run_transport_disconnects(t);
-
- if (t->product)
- free(t->product);
- if (t->serial)
- free(t->serial);
- if (t->device_name)
- free(t->device_name);
-
- memset(t,0xee,sizeof(atransport));
- free(t);
-
- update_transports();
- return;
- }
-
- /* don't create transport threads for inaccessible devices */
- if (t->connection_state != CS_NOPERM) {
- /* initial references are the two threads */
- t->ref_count = 2;
-
- if(sdb_socketpair(s)) {
- fatal_errno("cannot open transport socketpair");
- }
-
- D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]);
-
- t->transport_socket = s[0];
- t->fd = s[1];
-
- fdevent_install(&(t->transport_fde),
- t->transport_socket,
- transport_socket_events,
- t);
-
- fdevent_set(&(t->transport_fde), FDE_READ);
+ D("T(%s), device name: '%s'\n", t->serial, t->device_name);
+ sdb_thread_t transport_thread_ptr;
- if(sdb_thread_create(&input_thread_ptr, input_thread, t)){
- fatal_errno("cannot create input thread");
- }
-
- if(sdb_thread_create(&output_thread_ptr, output_thread, t)){
- fatal_errno("cannot create output thread");
- }
+ //transport is updated by transport_thread, we do not have to update here.
+ if(sdb_thread_create(&transport_thread_ptr, transport_thread, t)){
+ LOG_FATAL("cannot create output thread\n");
}
/* put us on the master device list */
- sdb_mutex_lock(&transport_lock);
- t->next = &transport_list;
- t->prev = transport_list.prev;
- t->next->prev = t;
- t->prev->next = t;
-
- sdb_cond_broadcast(&cond);
- sdb_mutex_unlock(&transport_lock);
-
- t->disconnects.next = t->disconnects.prev = &t->disconnects;
-
- update_transports();
+ sdb_mutex_lock(&transport_lock, "transport register_transport");
+ t->node = prepend(&transport_list, t);
+ sdb_mutex_unlock(&transport_lock, "transport register_transport");
}
-void init_transport_registration(void)
+//lock is done by transport_unref
+static void remove_transport(TRANSPORT *t)
{
- int s[2];
+ D("transport removed. serial: %s, device name: %s\n", t->serial, t->device_name);
- sdb_cond_init(&cond, NULL);
- if(sdb_socketpair(s)){
- fatal_errno("cannot open transport registration socketpair");
- }
+ remove_node(&transport_list, t->node, no_free);
- transport_registration_send = s[0];
- transport_registration_recv = s[1];
+ run_transport_close(t);
- fdevent_install(&transport_registration_fde,
- transport_registration_recv,
- transport_registration_func,
- 0);
+ if (t->serial)
+ free(t->serial);
+ if (t->device_name)
+ free(t->device_name);
- fdevent_set(&transport_registration_fde, FDE_READ);
+ free(t);
}
-/* the fdevent select pump is single threaded */
-static void register_transport(atransport *transport)
+
+static void transport_unref(TRANSPORT *t)
{
- tmsg m;
- m.transport = transport;
- m.action = 1;
- D("transport: %s registered\n", transport->serial);
- if(transport_write_action(transport_registration_send, &m)) {
- fatal_errno("cannot write transport registration socket\n");
+ if (t == NULL) {
+ return;
}
-}
-static void remove_transport(atransport *transport)
-{
- tmsg m;
- m.transport = transport;
- m.action = 0;
- D("transport: %s removed\n", transport->serial);
- if(transport_write_action(transport_registration_send, &m)) {
- fatal_errno("cannot write transport registration socket\n");
+ sdb_mutex_lock(&transport_lock, "transport_unref transport");
+ int nr;
+
+ D("transport: %s unref (kicking and closing)\n", t->serial);
+ if (!t->kicked) {
+ t->kicked = 1;
+ t->kick(t);
}
-}
+ t->close(t);
+ remove_transport(t);
+ LIST_NODE* curptr = transport_list;
-static void transport_unref_locked(atransport *t)
-{
- atransport *tmp;
- int nr;
- t->ref_count--;
- if (t->ref_count == 0) {
- D("transport: %s unref (kicking and closing)\n", t->serial);
- if (!t->kicked) {
- t->kicked = 1;
- t->kick(t);
- }
- t->close(t);
- remove_transport(t);
-
- /* update tizen specific device name */
- for (tmp = t->next; tmp && tmp != &transport_list; tmp = tmp->next) {
- if (tmp->type == kTransportUsb) {
- D("update tizen specific device name: %s\n", tmp->device_name);
- if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) {
- free(tmp->device_name);
- asprintf(&tmp->device_name, "device-%d", nr - 1);
- }
+ while(curptr != NULL) {
+ TRANSPORT* tmp = curptr->data;
+ curptr = curptr->next_ptr;
+ if (tmp->type == kTransportUsb) {
+ if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) {
+ free(tmp->device_name);
+ asprintf(&tmp->device_name, "device-%d", nr - 1);
}
}
- } else {
- D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
}
-}
-static void transport_unref(atransport *t)
-{
- if (t) {
- sdb_mutex_lock(&transport_lock);
- transport_unref_locked(t);
- sdb_mutex_unlock(&transport_lock);
- }
+ sdb_mutex_unlock(&transport_lock, "transport_unref transport");
+ update_transports();
}
-void add_transport_disconnect(atransport* t, adisconnect* dis)
+TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char** error_out)
{
- sdb_mutex_lock(&transport_lock);
- dis->next = &t->disconnects;
- dis->prev = dis->next->prev;
- dis->prev->next = dis;
- dis->next->prev = dis;
- sdb_mutex_unlock(&transport_lock);
-}
+ TRANSPORT *result = NULL;
+ char* null_str = NULL;
-void remove_transport_disconnect(atransport* t, adisconnect* dis)
-{
- dis->prev->next = dis->next;
- dis->next->prev = dis->prev;
- dis->next = dis->prev = dis;
-}
+ if(error_out == NULL) {
+ error_out = &null_str;
+ }
+ sdb_mutex_lock(&transport_lock, "transport acquire_one_transport");
-atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out)
-{
- atransport *t;
- atransport *result = NULL;
- int ambiguous = 0;
-
-retry:
- if (error_out)
- *error_out = "device not found";
-
- sdb_mutex_lock(&transport_lock);
- for (t = transport_list.next; t != &transport_list; t = t->next) {
- if (t->connection_state == CS_NOPERM) {
- if (error_out)
- *error_out = "insufficient permissions for device";
- continue;
- }
+ LIST_NODE* curptr = transport_list;
+ while(curptr != NULL) {
+ TRANSPORT* transport_ = curptr->data;
+ curptr = curptr->next_ptr;
/* check for matching serial number */
if (serial) {
- if (t->serial && !strcmp(serial, t->serial)) {
- result = t;
+ if (transport_->serial && !strcmp(serial, transport_->serial)) {
+ result = transport_;
break;
}
} else {
- if (ttype == kTransportUsb && t->type == kTransportUsb) {
+ if(ttype == kTransportAny) {
if (result) {
- if (error_out)
- *error_out = "more than one device";
- ambiguous = 1;
+ *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_TARGET;
result = NULL;
break;
}
- result = t;
- } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
- if (result) {
- if (error_out)
- *error_out = "more than one emulator";
- ambiguous = 1;
- result = NULL;
- break;
- }
- result = t;
- } else if (ttype == kTransportAny) {
+ result = transport_;
+ }
+ if (ttype == transport_->type) {
if (result) {
- if (error_out)
- *error_out = "more than one device and emulator";
- ambiguous = 1;
+ if(ttype == kTransportUsb) {
+ *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_DEV;
+ }
+ else if(ttype == kTransportLocal) {
+ *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_EMUL;
+ }
result = NULL;
break;
}
- result = t;
+ result = transport_;
}
}
}
- sdb_mutex_unlock(&transport_lock);
-
- if (result) {
- /* offline devices are ignored -- they are either being born or dying */
- if (result && result->connection_state == CS_OFFLINE) {
- if (error_out)
- *error_out = "device offline";
- result = NULL;
- }
- /* check for required connection state */
- if (result && state != CS_ANY && result->connection_state != state) {
- if (error_out)
- *error_out = "invalid device state";
- result = NULL;
- }
- }
-
- if (result) {
- /* found one that we can take */
- if (error_out)
- *error_out = NULL;
- } else if (state != CS_ANY && (serial || !ambiguous)) {
- sdb_sleep_ms(1000);
- goto retry;
- }
- return result;
-}
-
-static const char *statename(atransport *t)
-{
- switch(t->connection_state){
- case CS_OFFLINE: return "offline";
- case CS_BOOTLOADER: return "bootloader";
- case CS_DEVICE: return "device";
- case CS_HOST: return "host";
- case CS_RECOVERY: return "recovery";
- case CS_SIDELOAD: return "sideload";
- case CS_NOPERM: return "no permissions";
- default: return "unknown";
- }
-}
-
-/*
- * find number of devices which serial match with the prefix
- */
-int find_transports(char **serial_out, const char *prefix)
-{
- int nr = 0; // not found
- char *match = NULL;
- atransport *t;
-
- if (!serial_out || !prefix)
- return -1;
-
- sdb_mutex_lock(&transport_lock);
- for(t = transport_list.next; t != &transport_list; t = t->next) {
- char* serial = t->serial;
- if (!serial || !serial[0])
- continue;
- if (!strncmp(prefix, serial, strlen(prefix))) {
- match = serial;
- nr++;
- }
+ sdb_mutex_unlock(&transport_lock, "transport acquire_one_transport");
- if (nr > 1) {
- match = NULL;
- break;
- }
- }
- sdb_mutex_unlock(&transport_lock);
-
- if (nr == 1 && match) {
- *serial_out = strdup(match);
- } else if (nr == 0) {
- asprintf(serial_out, "device not found");
- } else if (nr > 1) {
- asprintf(serial_out, "more than one device and emulator");
+ if (result == NULL ) {
+ *error_out = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND;
}
- return nr;
+ return result;
}
int list_transports(char *buf, size_t bufsize)
char* p = buf;
char* end = buf + bufsize;
int len;
- atransport *t;
/* XXX OVERRUN PROBLEMS XXX */
- sdb_mutex_lock(&transport_lock);
- for(t = transport_list.next; t != &transport_list; t = t->next) {
+ sdb_mutex_lock(&transport_lock, "transport list_transports");
+
+ LIST_NODE* curptr = transport_list;
+ while(curptr != NULL) {
+ TRANSPORT* t = curptr->data;
+ curptr = curptr->next_ptr;
const char* serial = t->serial;
const char* devicename = (t->device_name == NULL) ? DEFAULT_DEVICENAME : t->device_name; /* tizen specific */
if (!serial || !serial[0])
serial = "????????????";
- len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, statename(t), devicename);
+ // FIXME: what if each string length is longger than static length?
+ len = snprintf(p, end - p, "%-20s\t%-10s\t%s\n", serial, connection_state_name(t), devicename);
if (p + len >= end) {
/* discard last line if buffer is too short */
}
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
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;
return 0;
}
}
+
+static unsigned int decoding_to_remote_ls_id(unsigned int encoded_ls_id) {
+ unsigned int remote_ls_id = encoded_ls_id & ~15;
+ return remote_ls_id;
+}
+
+static unsigned int decoding_to_local_ls_id(unsigned encoded_ls_id) {
+ unsigned int local_ls_id = encoded_ls_id & 15;
+ local_ls_id |= remote_con_flag;
+ return local_ls_id;
+}
+
+void wakeup_select_func(int _fd, unsigned ev, void *data) {
+ T_PACKET* t_packet = NULL;
+
+ readx(_fd, &t_packet, sizeof(t_packet));
+
+ TRANSPORT* t= t_packet->t;
+ D("T(%s)\n", t->serial);
+ PACKET* p = t_packet->p;
+ free(t_packet);
+
+ if(p == NULL) {
+ D("T(%S) packet NULL\n", t->serial);
+ return;
+ }
+
+ int c_state = t->connection_state;
+ unsigned int cmd = p->msg.command;
+ unsigned int local_id = p->msg.arg1;
+ unsigned int remote_id = p->msg.arg0;
+ SDB_SOCKET* sock = NULL;
+ //CNXN cannot be distinguished using remote_con_flag
+ if(t->remote_cnxn_socket != NULL && cmd == A_CNXN) {
+ dump_packet("remote_con", "wakeup_select_func", p);
+ sock = t->remote_cnxn_socket->data;
+ if(sock != NULL) {
+ remove_first(&(t->remote_cnxn_socket), no_free);
+ LOG_INFO("LS_L(%X)\n", sock->local_id);
+ p->ptr = (void*)(&p->msg);
+ p->len = sizeof(MESSAGE) + p->msg.data_length;
+ local_socket_enqueue(sock, p);
+ }
+ goto endup;
+ }
+ //If transport is remote device, packet should not have to be decoded.
+ if((local_id & remote_con_flag) && t->type != kTransportRemoteDevCon) {
+ LOG_INFO("LS_L(%X), LS_R(%X), LS_E(%X)\n", decoding_to_local_ls_id(local_id),
+ decoding_to_remote_ls_id(local_id), local_id);
+ sock = find_local_socket(decoding_to_local_ls_id(local_id));
+ p->msg.arg1 = decoding_to_remote_ls_id(local_id);
+ p->ptr = (void*)(&p->msg);
+ p->len = sizeof(MESSAGE) + p->msg.data_length;
+ local_socket_enqueue(sock, p);
+ goto endup;
+ }
+ sock = find_local_socket(local_id);
+
+ if(c_state != CS_OFFLINE && sock != NULL) {
+ //packet is used by local_socket_enqueue do not put a packet.
+ if(cmd == A_WRTE) {
+ D("T(%s) write packet from RS(%d) to LS(%X)\n", t->serial, remote_id, local_id);
+ p->len = p->msg.data_length;
+ p->ptr = p->data;
+ if(local_socket_enqueue(sock, p) == 0) {
+ send_cmd(local_id, remote_id, A_OKAY, NULL, t);
+ }
+ goto endup;
+ }
+ else if(cmd == A_OKAY) {
+ if(!HAS_SOCKET_STATUS(sock, REMOTE_SOCKET)) {
+ SET_SOCKET_STATUS(sock, REMOTE_SOCKET);
+ D("remote socket attached LS(%X), RS(%d)\n", sock->local_id, sock->remote_id);
+ sock->remote_id = remote_id;
+ sock->transport = t;
+ }
+ local_socket_ready(sock);
+ }
+ }
+ if(cmd == A_CLSE) {
+ if(sock != NULL) {
+ D("T(%s) close LS(%X)\n", t->serial, local_id);
+ local_socket_close(sock);
+ }
+ }
+ else if(cmd == A_CNXN) {
+ D("T(%s) gets CNXN\n", t->serial);
+ if(t->connection_state != CS_OFFLINE) {
+ t->connection_state = CS_OFFLINE;
+ run_transport_close(t);
+ }
+ parse_banner((char*) p->data, t);
+ }
+ else if(cmd == A_STAT) {
+ D("T(%s) gets A_STAT:%d\n", t->serial, p->msg.arg0);
+ if (t->connection_state != CS_OFFLINE) {
+ t->connection_state = CS_OFFLINE;
+ }
+ if (p->msg.arg0 == 1) {
+ t->connection_state = CS_PWLOCK;
+ } else {
+ t->connection_state = CS_DEVICE;
+ }
+ update_transports();
+ }
+ else if(cmd == A_TCLS) {
+ //transport thread is finished
+ transport_unref(t);
+ return;
+ }
+ put_apacket(p);
+
+endup:
+ //request is done. res increases 1.
+ ++(t->res);
+}
+
+const char *connection_state_name(TRANSPORT *t)
+{
+ if(t != NULL) {
+ int state = t->connection_state;
+
+ if(state == CS_OFFLINE) {
+ return STATE_OFFLINE;
+ }
+ if(state == CS_BOOTLOADER) {
+ return STATE_BOOTLOADER;
+ }
+ if(state == CS_DEVICE) {
+ return STATE_DEVICE;
+ }
+ if(state == CS_HOST) {
+ return STATE_HOST;
+ }
+ if(state == CS_RECOVERY) {
+ return STATE_RECOVERY;
+ }
+ if(state == CS_SIDELOAD) {
+ return STATE_SIDELOAD;
+ }
+ if (state == CS_PWLOCK) {
+ return STATE_LOCKED;
+ }
+ }
+ return STATE_UNKNOWN;
+}
+
+PACKET *get_apacket(void)
+{
+ PACKET *p = malloc(sizeof(PACKET));
+ if(p == 0) {
+ LOG_FATAL("failed to allocate an apacket\n");
+ }
+ memset(p, 0, sizeof(PACKET) - MAX_PAYLOAD);
+ return p;
+}
+
+void put_apacket(void *p)
+{
+ PACKET* packet = p;
+ free(packet);
+}
#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 */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include "fdevent.h"
-#include "utils.h"
#include <sys/types.h>
#ifndef OS_WINDOWS
#endif
#define TRACE_TAG TRACE_TRANSPORT
-#include "sdb.h"
-
-#ifdef HAVE_BIG_ENDIAN
-#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
-static inline void fix_endians(apacket *p)
-{
- p->msg.command = H4(p->msg.command);
- p->msg.arg0 = H4(p->msg.arg0);
- p->msg.arg1 = H4(p->msg.arg1);
- p->msg.data_length = H4(p->msg.data_length);
- p->msg.data_check = H4(p->msg.data_check);
- p->msg.magic = H4(p->msg.magic);
-}
-#else
-#define fix_endians(p) do {} while (0)
-#endif
+#include "strutils.h"
+#include "log.h"
+#include "common_modules.h"
+#include "fdevent.h"
+#include "utils.h"
+#include "transport.h"
/* we keep a list of opened transports. The atransport struct knows to which
* local transport it is connected. The list is used to detect when we're
* trying to connect twice to a given local transport.
*/
-#define SDB_LOCAL_TRANSPORT_MAX 16
-SDB_MUTEX_DEFINE( local_transports_lock );
+int current_local_transports = 0;
-static atransport* local_transports[ SDB_LOCAL_TRANSPORT_MAX ];
+static int get_devicename_from_shdmem(int port, char *device_name);
-static int remote_read(apacket *p, atransport *t)
-{
- if(readx(t->sfd, &p->msg, sizeof(amessage))){
- D("remote local: read terminated (message)\n");
+static int remote_read(TRANSPORT* t, void* data, int len) {
+ return readx(t->sfd, data, len);
+}
+
+static int remote_write(PACKET *p, TRANSPORT *t) {
+ dump_packet(t->serial, "remote_write_local", p);
+ if(writex(t->sfd, &p->msg, sizeof(MESSAGE) + p->msg.data_length)) {
+ LOG_ERROR("remote local: write terminated\n");
return -1;
}
+ return 0;
+}
- fix_endians(p);
+static int notify_sensord(int sdb_port) {
-#if 0 && defined HAVE_BIG_ENDIAN
- D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
- p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
-#endif
- if(check_header(p)) {
- D("bad header: terminated (data)\n");
- return -1;
- }
+ int fd = -1;
+ int sensord_port = sdb_port + 2;
- if(readx(t->sfd, p->data, p->msg.data_length)){
- D("remote local: terminated (data)\n");
- return -1;
- }
+ fd = sdb_host_connect("127.0.0.1", sensord_port, SOCK_DGRAM);
- if(check_data(p)) {
- D("bad data: terminated (data)\n");
+ if (fd < 0) {
+ LOG_ERROR("failed to create socket to localhost(%d)\n", sensord_port);
return -1;
}
- return 0;
-}
-
-static int remote_write(apacket *p, atransport *t)
-{
- int length = p->msg.data_length;
-
- fix_endians(p);
+ char request[16];
+ snprintf(request, sizeof request, "2\n");
-#if 0 && defined HAVE_BIG_ENDIAN
- D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n",
- p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic);
-#endif
- if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) {
- D("remote local: write terminated\n");
- return -1;
+ // send to sensord with udp
+ if (sdb_write(fd, request, strlen(request)) < 0) {
+ LOG_ERROR("could not send sensord request\n");
}
+ sdb_close(fd);
return 0;
}
+int local_connect(int sdb_port, const char *device_name) {
-int local_connect(int port, const char *device_name) {
- return local_connect_arbitrary_ports(port-1, port, device_name);
-}
-
-int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name)
-{
char buf[64];
- int fd = -1;
- fd = socket_loopback_client(sdb_port, SOCK_STREAM);
+ // in case of windows, it takes a long time to connect localhost compare to linux
+#if defined(OS_WINDOWS)
+ char devname[DEVICENAME_MAX]={0,};
+ if (get_devicename_from_shdmem(sdb_port, devname) == -1) {
+ return -1;
+ }
+#endif
+
+ int fd = sdb_host_connect("127.0.0.1", sdb_port, SOCK_STREAM);
if (fd >= 0) {
- D("client: connected on remote on fd %d\n", fd);
+ D("connected on remote on fd '%d', port '%d'\n", fd, sdb_port);
close_on_exec(fd);
disable_tcp_nagle(fd);
- snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
+
+
+ snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, sdb_port);
register_socket_transport(fd, buf, sdb_port, 1, device_name);
+
+ // noti to sensord port to enable shell context menu on
+ notify_sensord(sdb_port);
return 0;
}
+ D("failed to connect on port '%d'\n", sdb_port);
return -1;
}
-int get_devicename_from_shdmem(int port, char *device_name)
+static int get_devicename_from_shdmem(int port, char *device_name)
{
char *vms = NULL;
#ifndef OS_WINDOWS
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);
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;
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,
}
vms = strstr((char*)pBuf, VMS_PATH);
- if (vms != NULL)
- strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
- else
- strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
+ if (vms != NULL) {
+ s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX);
+ } else {
+ D("failed to get vm name from(%s)\n", pBuf);
+ CloseHandle(hMapFile);
+ return -1;
+ }
CloseHandle(hMapFile);
#endif
- // apply for new vms path policy from Jan 23 2013
// vms path should be: ~/tizen-sdk-data/emulator-vms/vms/{name}/emulimg-em1.~~
vms = strtok(device_name, OS_PATH_SEPARATOR_STR);
if (vms != NULL) {
- strncpy(device_name, vms, DEVICENAME_MAX);
+ s_strncpy(device_name, vms, DEVICENAME_MAX);
+ } else {
+ D("failed to get vm name from(%s)\n", device_name);
+ return -1;
}
D("init device name %s on port %d\n", device_name, port);
return 0;
}
-static void *register_local_connections(void *x)
-{
- int port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT;
- int count = SDB_LOCAL_TRANSPORT_MAX;
-
- D("transport: client_socket_thread() starting\n");
-
- /* try to connect to any number of running emulator instances */
- /* this is only done when SDB starts up. later, each new emulator */
- /* will send a message to SDB to indicate that is is starting up */
- for ( ; count > 0; count--, port += 10 ) {
- (void) local_connect(port, NULL);
- }
-
- return 0;
-}
-
-/**
- * register local connections
- */
-void local_init(int port)
-{
- sdb_thread_t thr;
- void* (*func)(void *);
-
- func = register_local_connections;
-
- if(sdb_thread_create(&thr, func, (void *)port)) {
- fatal_errno("cannot create local socket %s thread",
- HOST ? "client" : "server");
- }
-}
-
-static void remote_kick(atransport *t)
+static void remote_kick(TRANSPORT *t)
{
int fd = t->sfd;
- int nn;
t->sfd = -1;
sdb_shutdown(fd);
sdb_close(fd);
- sdb_mutex_lock( &local_transports_lock );
- for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) {
- if (local_transports[nn] == t) {
- local_transports[nn] = NULL;
- break;
- }
- }
-
- sdb_mutex_unlock( &local_transports_lock );
-}
-
-static void remote_close(atransport *t)
-{
- sdb_close(t->fd);
-}
-
-
-/* Only call this function if you already hold local_transports_lock. */
-atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port)
-{
- int i;
- for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
- if (local_transports[i] && local_transports[i]->sdb_port == sdb_port) {
- return local_transports[i];
- }
- }
- return NULL;
-}
-
-atransport* find_emulator_transport_by_sdb_port(int sdb_port)
-{
- sdb_mutex_lock( &local_transports_lock );
- atransport* result = find_emulator_transport_by_sdb_port_locked(sdb_port);
- sdb_mutex_unlock( &local_transports_lock );
- return result;
-}
-
-/* Only call this function if you already hold local_transports_lock. */
-int get_available_local_transport_index_locked()
-{
- int i;
- for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) {
- if (local_transports[i] == NULL) {
- return i;
- }
- }
- return -1;
+ --current_local_transports;
}
-int get_available_local_transport_index()
+static void remote_close(TRANSPORT *t)
{
- sdb_mutex_lock( &local_transports_lock );
- int result = get_available_local_transport_index_locked();
- sdb_mutex_unlock( &local_transports_lock );
- return result;
+ //nothing to close
+ D("close remote socket. serial: '%s', device name: '%s'\n", t->serial, t->device_name);
}
-int init_socket_transport(atransport *t, int s, int sdb_port, int local)
+static void init_socket_transport(TRANSPORT *t, int s, int sdb_port)
{
- int fail = 0;
-
t->kick = remote_kick;
t->close = remote_close;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sfd = s;
- t->sync_token = 1;
t->connection_state = CS_OFFLINE;
t->type = kTransportLocal;
- t->sdb_port = 0;
-
- if (HOST && local) {
- sdb_mutex_lock( &local_transports_lock );
- {
- t->sdb_port = sdb_port;
- atransport* existing_transport =
- find_emulator_transport_by_sdb_port_locked(sdb_port);
- int index = get_available_local_transport_index_locked();
- if (existing_transport != NULL) {
- D("local transport for port %d already registered (%p)?\n",
- sdb_port, existing_transport);
- fail = -1;
- } else if (index < 0) {
- // Too many emulators.
- D("cannot register more emulators. Maximum is %d\n",
- SDB_LOCAL_TRANSPORT_MAX);
- fail = -1;
- } else {
- local_transports[index] = t;
- }
- }
- sdb_mutex_unlock( &local_transports_lock );
+ t->node = NULL;
+ t->req = 0;
+ t->res = 0;
+ t->sdb_port = sdb_port;
+}
+
+void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name)
+{
+ if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) {
+ D("Too many emulators\n");
+ sdb_close(s);
+ return;
+ }
+
+ TRANSPORT *t = calloc(1, sizeof(TRANSPORT));
+ char buff[32];
+
+ if (!serial) {
+ snprintf(buff, sizeof buff, "T-%p", t);
+ serial = buff;
+ }
+ D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name);
+ int _port = port;
+ if(!local) {
+ _port = 0;
+ }
+ init_socket_transport(t, s, _port);
+ TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL);
+ if(old_t != NULL) {
+ D("old transport '%s' is found. Unregister it\n", old_t->serial);
+ kick_transport(old_t);
+ }
+
+ t->remote_cnxn_socket = NULL;
+ if(serial) {
+ t->serial = strdup(serial);
+ }
+
+ if (device_name) {
+ t->device_name = strdup(device_name);
+ } else {
+ // device_name could be null when sdb server was forked before qemu has sent the connect message.
+ t->device_name = (char*) malloc(DEVICENAME_MAX+1);
+ if (get_devicename_from_shdmem(port, t->device_name) == -1) {
+ s_strncpy(t->device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX);
+ }
}
- return fail;
+ ++current_local_transports;
+ register_transport(t);
}
#include <stdlib.h>
#include <string.h>
+#include "log.h"
#include "fdevent.h"
#include "utils.h"
#define TRACE_TAG TRACE_TRANSPORT
-#include "sdb.h"
#include "sdb_usb.h"
+#include "transport.h"
-#ifdef HAVE_BIG_ENDIAN
-#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24)
-static inline void fix_endians(apacket *p)
-{
- p->msg.command = H4(p->msg.command);
- p->msg.arg0 = H4(p->msg.arg0);
- p->msg.arg1 = H4(p->msg.arg1);
- p->msg.data_length = H4(p->msg.data_length);
- p->msg.data_check = H4(p->msg.data_check);
- p->msg.magic = H4(p->msg.magic);
-}
-unsigned host_to_le32(unsigned n)
-{
- return H4(n);
-}
-#else
-#define fix_endians(p) do {} while (0)
-unsigned host_to_le32(unsigned n)
-{
- return n;
-}
-#endif
+static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state);
-static int remote_read(apacket *p, atransport *t)
+static int remote_read(TRANSPORT* t, void* data, int len)
{
- if(sdb_usb_read(t->usb, &p->msg, sizeof(amessage))){
- D("remote usb: read terminated (message)\n");
- return -1;
- }
-
- fix_endians(p);
-
- if(check_header(p)) {
- D("remote usb: check_header failed\n");
- return -1;
- }
-
- if(p->msg.data_length) {
- if(sdb_usb_read(t->usb, p->data, p->msg.data_length)){
- D("remote usb: terminated (data)\n");
- return -1;
- }
- }
-
- if(check_data(p)) {
- D("remote usb: check_data failed\n");
- return -1;
- }
-
- return 0;
+ return sdb_usb_read(t->usb, data, len);
}
-static int remote_write(apacket *p, atransport *t)
+static int remote_write(PACKET *p, TRANSPORT *t)
{
- unsigned size = p->msg.data_length;
-
- fix_endians(p);
-
- if(sdb_usb_write(t->usb, &p->msg, sizeof(amessage))) {
- D("remote usb: 1 - write terminated\n");
+ dump_packet(t->serial, "remote_write_usb", p);
+ if(sdb_usb_write(t->usb, &p->msg, sizeof(MESSAGE))) {
+ LOG_ERROR("mesage write error\n");
return -1;
}
- if(p->msg.data_length == 0) return 0;
- if(sdb_usb_write(t->usb, &p->data, size)) {
- D("remote usb: 2 - write terminated\n");
- return -1;
+
+ if(p->msg.data_length != 0) {
+ if(sdb_usb_write(t->usb, &p->data, p->msg.data_length)) {
+ D("remote usb: 2 - write terminated\n");
+ return -1;
+ }
}
return 0;
}
-static void remote_close(atransport *t)
+static void remote_close(TRANSPORT *t)
{
sdb_usb_close(t->usb);
t->usb = 0;
}
-static void remote_kick(atransport *t)
+static void remote_kick(TRANSPORT *t)
{
sdb_usb_kick(t->usb);
}
-void init_usb_transport(atransport *t, usb_handle *h, int state)
+static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state)
{
D("transport: usb\n");
t->close = remote_close;
t->kick = remote_kick;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
- t->sync_token = 1;
t->connection_state = state;
t->type = kTransportUsb;
t->usb = h;
+ t->sdb_port = -1;
+ t->req = 0;
+ t->res = 0;
+}
+
+static int get_connected_device_count(transport_type type)
+{
+ int cnt = 0;
+ sdb_mutex_lock(&transport_lock, "transport get_connected_device_count");
+
+ LIST_NODE* curptr = transport_list;
+ while(curptr != NULL) {
+ TRANSPORT *t = curptr->data;
+ curptr = curptr->next_ptr;
+ if (type == t->type) {
+ cnt++;
+ }
+ }
+
+ sdb_mutex_unlock(&transport_lock, "transport get_connected_device_count");
+ D("connected device count:%d\n",cnt);
+ return cnt;
+}
- HOST = 1;
+void register_usb_transport(usb_handle *usb, const char *serial)
+{
+ TRANSPORT *t = calloc(1, sizeof(TRANSPORT));
+ char device_name[256];
+
+ D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
+ serial ? serial : "");
+ init_usb_transport(t, usb, CS_OFFLINE);
+ if(serial) {
+ t->serial = strdup(serial);
+ }
+ t->remote_cnxn_socket = NULL;
+ register_transport(t);
+
+ /* tizen specific */
+ sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb));
+ t->device_name = strdup(device_name);
}
int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_protocol)
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");
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * documents from https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/USBBook/USBOverview/USBOverview.html
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <mach/mach.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+
+#include "fdevent.h"
+#include "strutils.h"
+#include "memutils.h"
+#include "sdb_usb.h"
+#include "device_vendors.h"
+#include "log.h"
+#include "utils.h"
+#include "linkedlist.h"
+#include "transport.h"
+
+#define MAX_C_STRLEN 128
+#define kUSBLanguageEnglish 0x409
+
+static IONotificationPortRef gNotifyPort;
+static io_iterator_t* gAddedIter;
+static CFRunLoopRef gRunLoop;
+
+static pthread_mutex_t usb_init_lock;
+static pthread_cond_t usb_init_cond;
+
+struct usb_handle {
+ UInt8 end_point[2]; // 0:in, 1:out
+ IOUSBInterfaceInterface **interface;
+ io_object_t usbNotification;
+ unsigned int zero_mask;
+};
+
+static void usb_unplugged(usb_handle *handle) {
+ LOG_INFO("clean interface resources\n");
+ if (!handle)
+ return;
+
+ if (handle->interface) {
+ (*handle->interface)->USBInterfaceClose(handle->interface);
+ (*handle->interface)->Release(handle->interface);
+ handle->interface = 0;
+ }
+}
+
+void DeviceNotification(void * refCon, io_service_t service, natural_t messageType,
+ void * messageArgument) {
+
+ kern_return_t kr;
+ usb_handle *handle = (usb_handle *) refCon;
+
+ if (messageType == kIOMessageServiceIsTerminated) {
+ LOG_DEBUG("Device 0x%08x removed.\n", service);
+
+ kr = IOObjectRelease(handle->usbNotification);
+ sdb_usb_kick(handle);
+ }
+
+}
+
+/**
+ * Authors: Vipul Gupta, Pete St. Pierre
+ **/
+static void UsbCharactersToHostCharacters(UniChar *p, UInt16 len) {
+ for (; len > 0; --len, ++p)
+ *p = USBToHostWord(*p);
+}
+
+kern_return_t getUSBSerial(IOUSBDeviceInterface182 **dev, UInt8 string_id, char *spotSerial) {
+ UInt8 buffer[256];
+ UInt16 result_length;
+ CFStringRef result;
+ kern_return_t kr = -1;
+ IOUSBDevRequest request;
+
+ memset(buffer, 0, sizeof(buffer));
+ if (string_id != 0) {
+ result_length = sizeof(buffer);
+ request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ request.bRequest = kUSBRqGetDescriptor;
+ request.wValue = (kUSBStringDesc << 8) | string_id;
+ request.wIndex = kUSBLanguageEnglish;
+ request.wLength = result_length;
+ request.pData = buffer;
+ kr = (*dev)->DeviceRequest(dev, &request);
+
+ if ((kIOReturnSuccess == kr) && (request.wLength > 0)
+ && (request.wLength <= sizeof(buffer))) {
+ result_length = buffer[0];
+ if ((0 < result_length) && (result_length <= sizeof(buffer))) {
+ /*
+ * Convert USB string (always little-endian) to host-endian but
+ * leave the descriptor type byte and the length alone.
+ */
+ UsbCharactersToHostCharacters(((UniChar *) buffer) + 1, ((result_length - 2) >> 1));
+
+ /* Recreate a string from the buffer of unicode characters */
+ result = CFStringCreateWithCharacters(kCFAllocatorDefault, ((UniChar *) buffer) + 1,
+ ((result_length - 2) >> 1));
+
+ /* Copy the character contents to a local C string */
+ CFStringGetCString(result, spotSerial, MAX_C_STRLEN, kCFStringEncodingASCII);
+ }
+ }
+ }
+
+ return kr;
+}
+
+static IOReturn FindInterfaces(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 product,
+ usb_handle *handle) {
+ IOReturn kr;
+ UInt8 intfClass;
+ UInt8 intfSubClass;
+ UInt8 intfProtocol;
+ UInt8 intfNumEndpoints;
+ int pipeRef;
+
+ // open the interface. This will cause the pipes to be instantiated that are
+ // associated with the endpoints defined in the interface descriptor.
+ kr = (*interface)->USBInterfaceOpen(interface);
+ if (kIOReturnSuccess != kr) {
+ LOG_DEBUG("unable to open interface (%08x)\n", kr);
+ return kr;
+ }
+
+ kr = (*interface)->GetNumEndpoints(interface, &intfNumEndpoints);
+ if (kIOReturnSuccess != kr) {
+ LOG_DEBUG("unable to get number of endpoints (%08x)\n", kr);
+ (void) (*interface)->USBInterfaceClose(interface);
+ return kr;
+ }
+
+ kr = (*interface)->GetInterfaceClass(interface, &intfClass);
+ kr = (*interface)->GetInterfaceSubClass(interface, &intfSubClass);
+ kr = (*interface)->GetInterfaceProtocol(interface, &intfProtocol);
+
+ LOG_DEBUG("interface class %0x, subclass %0x, protocol: %0x\n", intfClass, intfSubClass,
+ intfProtocol);
+
+ if (!is_sdb_interface(vendor, intfClass, intfSubClass, intfProtocol)) {
+ LOG_DEBUG("it is not sdb interface\n");
+ (void) (*interface)->USBInterfaceClose(interface);
+ return kIOReturnError;
+ }
+
+ for (pipeRef = 0; pipeRef <= intfNumEndpoints; pipeRef++) {
+ UInt8 direction;
+ UInt8 number;
+ UInt8 transferType;
+ UInt16 maxPacketSize;
+ UInt8 interval;
+ char *message;
+
+ kr = (*interface)->GetPipeProperties(interface, pipeRef, &direction, &number, &transferType,
+ &maxPacketSize, &interval);
+ if (kIOReturnSuccess != kr)
+ LOG_DEBUG("unable to get properties of pipe %d (%08x)\n", pipeRef, kr);
+ else {
+ LOG_DEBUG("++ pipeRef:%d: ++\n ", pipeRef);
+
+ switch (transferType) {
+ case kUSBControl:
+ message = "control";
+ break;
+ case kUSBIsoc:
+ message = "isoc";
+ break;
+ case kUSBBulk:
+ message = "bulk";
+ break;
+ case kUSBInterrupt:
+ message = "interrupt";
+ break;
+ case kUSBAnyType:
+ message = "any";
+ break;
+ default:
+ message = "???";
+ }
+ LOG_DEBUG("transfer type:%s, maxPacketSize:%d\n", message, maxPacketSize);
+ if (kUSBBulk != transferType) {
+ continue;
+ }
+ handle->zero_mask = maxPacketSize - 1;
+
+ switch (direction) {
+ case kUSBOut:
+ message = "out";
+ handle->end_point[1] = pipeRef;
+ break;
+ case kUSBIn:
+ message = "in";
+ handle->end_point[0] = pipeRef;
+ break;
+ case kUSBNone:
+ message = "none";
+ break;
+ case kUSBAnyDirn:
+ message = "any";
+ break;
+ default:
+ message = "???";
+ }
+ LOG_DEBUG("direction:%0x(%s)\n", pipeRef, message);
+ kr = kIOReturnSuccess;
+ }
+ }
+ handle->interface = interface;
+
+ return kr;
+}
+
+void DeviceAdded(void *refCon, io_iterator_t iterator) {
+ kern_return_t kr;
+ io_service_t usbDevice;
+ io_service_t usbInterface;
+ IOCFPlugInInterface **ioDev = NULL;
+ IOUSBDeviceInterface182 **intf = NULL;
+ IOUSBInterfaceInterface220 **interface = NULL;
+ SInt32 score;
+ HRESULT res;
+ UInt16 usbVendor;
+ UInt16 usbProduct;
+ UInt8 serialIndex;
+ char serial[256];
+
+ while ((usbInterface = IOIteratorNext(iterator))) {
+ // Create an intermediate plug-in
+ kr = IOCreatePlugInInterfaceForService(usbInterface, kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &ioDev, &score);
+ IOObjectRelease(usbInterface);
+
+ if ((kIOReturnSuccess != kr) || !ioDev) {
+ LOG_DEBUG("couldn't create a device interface plugin, find next...\n");
+ continue;
+ }
+ res = (*ioDev)->QueryInterface(ioDev,
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID) & interface);
+ (*ioDev)->Release(ioDev);
+
+ if (res || !interface) {
+ LOG_DEBUG("couldn't create an IOUSBInterfaceInterface, find next... \n");
+ continue;
+ }
+
+ kr = (*interface)->GetDevice(interface, &usbDevice);
+ if (kIOReturnSuccess != kr || !usbDevice) {
+ LOG_DEBUG("couldn't get device from interface, find next...\n");
+ continue;
+ }
+
+ kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &ioDev, &score);
+ // Release the usbDevice object after getting the plug-in
+ IOObjectRelease(usbDevice);
+
+ if ((kIOReturnSuccess != kr) || !ioDev) {
+ LOG_DEBUG("unable to create a device plugin, find next...\n");
+ continue;
+ }
+
+ // I have the device plugin, I need the device interface
+ //
+ res = (*ioDev)->QueryInterface(ioDev,
+ CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&intf);
+ (*ioDev)->Release(ioDev);
+
+ if (res || !intf) {
+ LOG_DEBUG("couldn't create a usb interface, find next...\n");
+ continue;
+ }
+ // Get vendor, product and serial index
+ kr = (*intf)->GetDeviceVendor(intf, &usbVendor);
+ if (kIOReturnSuccess != kr) {
+ LOG_ERROR("couldn't get usb vendor name\n");
+ }
+ kr = (*intf)->GetDeviceProduct(intf, &usbProduct);
+ if (kIOReturnSuccess != kr) {
+ LOG_ERROR("couldn't get usb product name\n");
+ }
+ kr = (*intf)->USBGetSerialNumberStringIndex(intf, &serialIndex);
+ if (kIOReturnSuccess != kr) {
+ LOG_ERROR("couldn't get usb serial index\n");
+ }
+ kr = getUSBSerial(intf, serialIndex, serial);
+ (*intf)->Release(intf);
+
+ usb_handle* handle = calloc(1, sizeof(usb_handle));
+ if (handle == NULL) {
+ LOG_FATAL("could't alloc mememroy\n");
+ }
+
+ kr = FindInterfaces((IOUSBInterfaceInterface**) interface, usbVendor, usbProduct, handle);
+ if (kIOReturnSuccess != kr) {
+ free(handle);
+ handle = NULL;
+ (*interface)->Release(interface);
+ continue;
+ }
+
+ LOG_DEBUG("found tizen device and register usb transport.........\n");
+ register_usb_transport(handle, serial);
+
+ // Register for an interest notification for this device. Pass the reference to our
+ // private data as the refCon for the notification.
+ //
+ kr = IOServiceAddInterestNotification(gNotifyPort, // notifyPort
+ usbInterface, // service
+ kIOGeneralInterest, // interestType
+ DeviceNotification, // callback
+ handle, // refCon
+ &(handle->usbNotification) // notification
+ );
+
+ if (kIOReturnSuccess != kr) {
+ LOG_DEBUG("IOServiceAddInterestNotification returned 0x%08x\n", kr);
+ }
+
+ }
+ LOG_DEBUG("signal to wake up main thread\n");
+ sdb_mutex_lock(&usb_init_lock, "++usb locking++");
+ sdb_cond_signal(&usb_init_cond);
+ sdb_mutex_unlock(&usb_init_lock, "--usb unlocking--");
+}
+
+static int cleanup_flag = 0;
+static void sig_handler(int sigraised) {
+ int i = 0;
+
+ LOG_DEBUG("Interrupted!\n");
+
+ if (cleanup_flag == 1) {
+ return;
+ }
+
+ // Clean up
+ for (i = 0; i < vendor_total_cnt; i++) {
+ IOObjectRelease(gAddedIter[i]);
+ }
+ gAddedIter = NULL;
+
+ IONotificationPortDestroy(gNotifyPort);
+ gRunLoop = 0;
+
+ if (gAddedIter != NULL) {
+ s_free(gAddedIter);
+ gAddedIter = NULL;
+ }
+
+ LOG_DEBUG("RunLoopThread done\n");
+ if (gRunLoop) {
+ CFRunLoopStop(gRunLoop);
+ }
+ cleanup_flag = 1;
+}
+
+void do_lsusb(void) {
+ mach_port_t masterPort;
+ CFMutableDictionaryRef matchingDict;
+ CFRunLoopSourceRef runLoopSource;
+ CFNumberRef numberRef;
+ kern_return_t kr;
+ SInt32 usbVendor, subClass, protocol;
+ sig_t oldHandler;
+ int i = 0;
+
+ // Set up a signal handler so we can clean up when we're interrupted from the command line
+ // Otherwise we stay in our run loop forever.
+ //
+ oldHandler = signal(SIGINT, sig_handler);
+ if (oldHandler == SIG_ERR) {
+ LOG_DEBUG("Could not establish new signal handler\n");
+ }
+
+ // first create a master_port for my task
+ //
+ kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
+ if (kr || !masterPort) {
+ LOG_DEBUG("ERR: Couldn't create a master IOKit Port(%08x)\n", kr);
+ return;
+ }
+
+ // Create a notification port and add its run loop event source to our run loop
+ // This is how async notifications get set up.
+ //
+ gNotifyPort = IONotificationPortCreate(masterPort);
+ runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
+
+ gRunLoop = CFRunLoopGetCurrent();
+ CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode);
+
+ for (i = 0; tizen_device_vendors[i].vendor != NULL; i++) {
+ // Set up the matching criteria for the devices we're interested in. The matching criteria needs to follow
+ // the same rules as kernel drivers: mainly it needs to follow the USB Common Class Specification, pp. 6-7.
+ // See also http://developer.apple.com/qa/qa2001/qa1076.html
+ // One exception is that you can use the matching dictionary "as is", i.e. without adding any matching criteria
+ // to it and it will match every IOUSBDevice in the system. IOServiceAddMatchingNotification will consume this
+ // dictionary reference, so there is no need to release it later on.
+ //
+ matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); // Interested in instances of class
+ // IOUSBInterface and its subclasses
+ if (!matchingDict) {
+ LOG_DEBUG("Can't create a USB matching dictionary\n");
+ mach_port_deallocate(mach_task_self(), masterPort);
+ return;
+ }
+ usbVendor = tizen_device_vendors[i].id;
+ subClass = SDB_INTERFACE_SUBCLASS;
+ protocol = SDB_INTERFACE_PROTOCOL;
+
+ LOG_DEBUG(
+ "Looking for devices matching vendor ID=%0x(%0x, %0x)\n", usbVendor, subClass, protocol);
+
+ // We are interested in all USB Devices (as opposed to USB interfaces). The Common Class Specification
+ // tells us that we need to specify the idVendor, idProduct, and bcdDevice fields, or, if we're not interested
+ // in particular bcdDevices, just the idVendor and idProduct. Note that if we were trying to match an IOUSBInterface,
+ // we would need to set more values in the matching dictionary (e.g. idVendor, idProduct, bInterfaceNumber and
+ // bConfigurationValue.
+ //
+
+ // Create a CFNumber for the idVendor, interface subclass and protocol and set the value in the dictionary
+ //
+ numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
+ CFRelease(numberRef);
+
+ numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &subClass);
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), numberRef);
+ CFRelease(numberRef);
+
+ numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &protocol);
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), numberRef);
+ CFRelease(numberRef);
+
+ numberRef = 0;
+
+ // Now set up a notification to be called when a device is first matched by I/O Kit.
+ // Note that this will not catch any devices that were already plugged in so we take
+ // care of those later.
+ //
+ kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
+ kIOFirstMatchNotification, // notificationType
+ matchingDict, // matching
+ DeviceAdded, // callback
+ NULL, // refCon
+ &gAddedIter[i] // notification
+ );
+
+ // Iterate once to get already-present devices and arm the notification
+ //
+ DeviceAdded(NULL, gAddedIter[i]);
+ }
+
+ // Now done with the master_port
+ mach_port_deallocate(mach_task_self(), masterPort);
+ masterPort = 0;
+
+ // Start the run loop. Now we'll receive notifications.
+ //
+ LOG_DEBUG("Starting run loop.\n");
+ CFRunLoopRun();
+
+ // We should never get here
+ //
+ LOG_DEBUG("Unexpectedly back from CFRunLoopRun()!\n");
+}
+
+void* usb_poll_thread(void* sleep_msec) {
+ LOG_DEBUG("created usb detecting thread\n");
+ do_lsusb();
+ return NULL;
+}
+
+void sdb_usb_init() {
+ sdb_thread_t tid;
+
+ init_device_vendors();
+ gAddedIter = (io_iterator_t*) s_malloc(vendor_total_cnt * sizeof(io_iterator_t));
+ if (gAddedIter == NULL) {
+ LOG_FATAL("Cound not alloc memory\n");
+ return;
+ }
+
+ sdb_mutex_init(&usb_init_lock, NULL);
+ sdb_cond_init(&usb_init_cond, NULL);
+
+ if (sdb_thread_create(&tid, usb_poll_thread, NULL)) {
+ LOG_FATAL("cannot create usb poll thread\n");
+ }
+ sdb_mutex_lock(&usb_init_lock, "++usb locking++");
+
+ LOG_DEBUG("waiting until to finish to initilize....\n");
+ // wait til finish to initialize some setting for usb detection
+ sdb_cond_wait(&usb_init_cond, &usb_init_lock);
+
+ LOG_DEBUG("woke up done....\n");
+ sdb_mutex_unlock(&usb_init_lock, "--usb unlocking--");
+ sdb_mutex_destroy(&usb_init_lock);
+ sdb_cond_destroy(&usb_init_cond);
+}
+
+void sdb_usb_cleanup() {
+ // called when server stop or interrupted
+ close_usb_devices();
+ sig_handler(0);
+}
+
+int sdb_usb_write(usb_handle *h, const void *data, int len) {
+ IOReturn kr;
+
+ kr = (*h->interface)->WritePipe(h->interface, h->end_point[1], (void *) data, len);
+ if (kr == kIOReturnSuccess) {
+ if (h->zero_mask && !(h->zero_mask & len)) {
+ (*h->interface)->WritePipe(h->interface, h->end_point[1], (void *) data, 0);
+ }
+ return 0;
+ }
+
+ LOG_DEBUG("Unable to perform bulk write (%08x)\n", kr);
+ return -1;
+}
+
+int sdb_usb_read(usb_handle *h, void *data, int len) {
+ IOReturn kr;
+ UInt32 size = len;
+
+ kr = (*h->interface)->ReadPipe(h->interface, h->end_point[0], data, &size);
+
+ if (kIOReturnSuccess != kr) {
+ LOG_DEBUG("Unable to perform bulk read (%08x)\n", kr);
+ return -1;
+ }
+
+ return 0;
+}
+
+int sdb_usb_close(usb_handle *h) {
+ return 0;
+}
+
+void sdb_usb_kick(usb_handle *h) {
+ usb_unplugged(h);
+}
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <fcntl.h>
#include <errno.h>
-#include <ctype.h>
-
-#include <linux/usbdevice_fs.h>
-#include <linux/version.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <libudev.h>
+#include <locale.h>
#include <linux/usb/ch9.h>
-#else
-#include <linux/usb_ch9.h>
-#endif
-#include <asm/byteorder.h>
-
+#include <linux/usbdevice_fs.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
-#include "fdevent.h"
#include "utils.h"
-#define TRACE_TAG TRACE_USB
-#include "sdb.h"
-
+#include "fdevent.h"
+#include "strutils.h"
+#include "sdb_usb.h"
+#include "log.h"
+#include "transport.h"
-/* usb scan debugging is waaaay too verbose */
-#define DBGX(x...)
+#define TRACE_TAG TRACE_USB
SDB_MUTEX_DEFINE( usb_lock );
+LIST_NODE* usb_list = NULL;
+
struct usb_handle
{
- usb_handle *prev;
- usb_handle *next;
+ LIST_NODE* node;
- char fname[64];
- int desc;
- unsigned char ep_in;
- unsigned char ep_out;
-
- unsigned zero_mask;
- unsigned writeable;
+ char unique_node_path[PATH_MAX+1];
+ int node_fd;
+ unsigned char end_point[2]; // 0:in, 1:out
+ int interface;
+};
- struct usbdevfs_urb urb_in;
- struct usbdevfs_urb urb_out;
+int register_device(const char* node, const char* serial) {
+ int fd;
+ unsigned char device_desc[4096];
+ unsigned char* desc_current_ptr = NULL;
- int urb_in_busy;
- int urb_out_busy;
- int dead;
+ if (node == NULL) {
+ return -1;
+ }
+ if (is_device_registered(node)) {
+ D("already registered device: %s\n", node);
+ return -1;
+ }
+ if ((fd = open(node, O_RDWR)) < 0) {
+ D ("failed to open usb node %s (%s)\n", node, strerror(errno));
+ return -1;
+ }
- sdb_cond_t notify;
- sdb_mutex_t lock;
+ if (read(fd, device_desc, sizeof(device_desc)) < 0) {
+ D ("failed to read usb node %s (%s)\n", node, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ desc_current_ptr = device_desc;
- // for garbage collecting disconnected devices
- int mark;
+ // get device descriptor from head first
+ struct usb_device_descriptor* usb_dev = (struct usb_device_descriptor*)desc_current_ptr;
- // ID of thread currently in REAPURB
- pthread_t reaper_thread;
-};
+ if (USB_DT_DEVICE_SIZE != usb_dev->bLength) {
+ D("failed to get usb device descriptor\n");
+ return -1;
+ }
-static usb_handle handle_list = {
- .prev = &handle_list,
- .next = &handle_list,
-};
+ // move to get device config
+ desc_current_ptr += usb_dev->bLength;
-static int known_device(const char *dev_name)
-{
- usb_handle *usb;
-
- sdb_mutex_lock(&usb_lock);
- for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
- if(!strcmp(usb->fname, dev_name)) {
- // set mark flag to indicate this device is still alive
- usb->mark = 1;
- sdb_mutex_unlock(&usb_lock);
- return 1;
+ // enumerate all available configuration descriptors
+ int i = 0;
+ for (i = 0; i < usb_dev->bNumConfigurations; i++) {
+ struct usb_config_descriptor* usb_config = (struct usb_config_descriptor *) desc_current_ptr;
+ if (USB_DT_CONFIG_SIZE != usb_config->bLength) {
+ D("failed to get usb config descriptor\n");
+ break;
}
- }
- sdb_mutex_unlock(&usb_lock);
- return 0;
-}
+ desc_current_ptr += usb_config->bLength;
-static void linux_kick_disconnected_devices()
-{
- usb_handle *usb;
-
- sdb_mutex_lock(&usb_lock);
- // kick any devices in the device list that were not found in the device scan
- for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
- if (usb->mark == 0) {
- sdb_usb_kick(usb);
- } else {
- usb->mark = 0;
+ unsigned int wTotalLength = usb_config->wTotalLength;
+ unsigned int wSumLength = usb_config->bLength;
+
+ if (usb_config->bNumInterfaces < 1) {
+ D("there is no interfaces\n");
+ break;
}
- }
- sdb_mutex_unlock(&usb_lock);
-}
+ while (wSumLength < wTotalLength)
+ {
+ int bLength = desc_current_ptr[0];
+ int bType = desc_current_ptr[1];
+
+ struct usb_interface_descriptor* usb_interface = (struct usb_interface_descriptor *)desc_current_ptr;
+
+ if (is_sdb_interface(usb_dev->idVendor, usb_interface->bInterfaceClass, usb_interface->bInterfaceSubClass,
+ usb_interface->bInterfaceProtocol) &&
+ (USB_DT_INTERFACE_SIZE == bLength && USB_DT_INTERFACE == bType && 2 == usb_interface->bNumEndpoints)) {
+ desc_current_ptr += usb_interface->bLength;
+ wSumLength += usb_interface->bLength;
+ struct usb_endpoint_descriptor *endpoint1 = (struct usb_endpoint_descriptor *) desc_current_ptr;
+ desc_current_ptr += endpoint1->bLength;
+ wSumLength += endpoint1->bLength;
+ struct usb_endpoint_descriptor *endpoint2 = (struct usb_endpoint_descriptor *) desc_current_ptr;
+ unsigned char endpoint_in;
+ unsigned char endpoint_out;
+ unsigned char interface = usb_interface->bInterfaceNumber;
+ // TODO: removed!
+ {
+ int bConfigurationValue = 2;
+ int n = ioctl(fd, USBDEVFS_RESET);
+ if (n != 0) {
+ D("usb reset failed\n");
+ }
+ n = ioctl(fd, USBDEVFS_SETCONFIGURATION, &bConfigurationValue);
+ if (n != 0) {
+ D("check kernel is supporting %dth configuration\n", bConfigurationValue);
+ }
-static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
- int ifc, int serial_index, unsigned zero_mask);
+ n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
+ if (n != 0) {
+ D("usb claim failed\n");
+ }
+ }
-static inline int badname(const char *name)
-{
- while(*name) {
- if(!isdigit(*name++)) return 1;
- }
- return 0;
-}
+ // find in/out endpoint address
+ if ((endpoint1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ endpoint_in = endpoint1->bEndpointAddress;
+ endpoint_out = endpoint2->bEndpointAddress;
+ } else {
+ endpoint_out = endpoint1->bEndpointAddress;
+ endpoint_in = endpoint2->bEndpointAddress;
+ }
+ // for now i can agree to register usb
+ {
+ usb_handle* usb = NULL;
+ usb = calloc(1, sizeof(usb_handle));
-static void find_usb_device(const char *base,
- void (*register_device_callback)
- (const char *, unsigned char, unsigned char, int, int, unsigned))
-{
- char busname[32], devname[32];
- unsigned char local_ep_in, local_ep_out;
- DIR *busdir , *devdir ;
- struct dirent *de;
- int fd ;
-
- busdir = opendir(base);
- if(busdir == 0) return;
-
- while((de = readdir(busdir)) != 0) {
- if(badname(de->d_name)) continue;
-
- snprintf(busname, sizeof busname, "%s/%s", base, de->d_name);
- devdir = opendir(busname);
- if(devdir == 0) continue;
-
-// DBGX("[ scanning %s ]\n", busname);
- while((de = readdir(devdir))) {
- unsigned char devdesc[4096];
- unsigned char* bufptr = devdesc;
- unsigned char* bufend;
- struct usb_device_descriptor* device;
- struct usb_config_descriptor* config;
- struct usb_interface_descriptor* interface;
- struct usb_endpoint_descriptor *ep1, *ep2;
- unsigned zero_mask = 0;
- unsigned vid, pid;
- unsigned int desclength;
-
- if(badname(de->d_name)) continue;
- snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
-
- if(known_device(devname)) {
- DBGX("skipping %s\n", devname);
- continue;
- }
+ if (usb == NULL) {
+ break;
+ }
+ usb->node_fd = fd;
+ usb->interface = usb_interface->bInterfaceNumber;
+ usb->end_point[0] = endpoint_in;
+ usb->end_point[1] = endpoint_out;
-// DBGX("[ scanning %s ]\n", devname);
- if((fd = unix_open(devname, O_RDONLY)) < 0) {
- continue;
- }
+ char usb_serial[256] = {0,};
- desclength = sdb_read(fd, devdesc, sizeof(devdesc));
- bufend = bufptr + desclength;
+ if (serial != NULL) {
+ s_strncpy(usb_serial, serial, sizeof(usb_serial));
+ } else {
+ strcpy(usb_serial, "unknown");
+ }
+ s_strncpy(usb->unique_node_path, node, sizeof(usb->unique_node_path));
- // should have device and configuration descriptors, and atleast two endpoints
- if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
- D("desclength %d is too small\n", desclength);
- sdb_close(fd);
- continue;
- }
+ sdb_mutex_lock(&usb_lock, "usb register locked");
+ usb->node = prepend(&usb_list, usb);
+ D("-register new device (in: %04x, out: %04x) from %s\n", usb->end_point[0], usb->end_point[1], node);
- device = (struct usb_device_descriptor*)bufptr;
- bufptr += USB_DT_DEVICE_SIZE;
+ register_usb_transport(usb, usb_serial);
+ sdb_mutex_unlock(&usb_lock, "usb register unlocked");
+ }
+ desc_current_ptr += endpoint2->bLength;
+ wSumLength += endpoint2->bLength;
- if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
- sdb_close(fd);
- continue;
+ } else {
+ wSumLength += usb_interface->bLength;
+ desc_current_ptr += usb_interface->bLength;
}
+ }
+ }
+ return 0;
+}
+
+static void usb_plugged(struct udev_device *dev) {
+ if (udev_device_get_devnode(dev) != NULL) {
+ register_device(udev_device_get_devnode(dev), udev_device_get_sysattr_value(dev, "serial"));
+ }
+}
- vid = device->idVendor;
- pid = device->idProduct;
- DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid);
+static void usb_unplugged(struct udev_device *dev) {
+ LOG_INFO("check device is removed from the list\n");
+}
- // should have config descriptor next
- config = (struct usb_config_descriptor *)bufptr;
+int usb_register_callback(int msec)
+{
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev;
+
+ struct udev_monitor *mon;
+ int fd;
+
+ // Create the udev object
+ udev = udev_new();
+ if (!udev) {
+ D("Can't create udev\n");
+ exit(1);
+ }
- /* tizen specific */
- if (device->bNumConfigurations > 1) {
- bufptr += config->wTotalLength;
- config = (struct usb_config_descriptor *)bufptr;
- bufend = bufptr + config->wTotalLength;
- }
+ // Set up a monitor to monitor hidraw devices
+ mon = udev_monitor_new_from_netlink(udev, "udev");
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device");
+ udev_monitor_enable_receiving(mon);
- bufptr += USB_DT_CONFIG_SIZE;
- if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
- D("usb_config_descriptor not found\n");
- sdb_close(fd);
- continue;
- }
+ // Get the file descriptor (fd) for the monitor. This fd will get passed to select()
+ fd = udev_monitor_get_fd(mon);
- // loop through all the descriptors and look for the SDB interface
- while (bufptr < bufend) {
- unsigned char length = bufptr[0];
- unsigned char type = bufptr[1];
+ // Create a list of the devices in the 'usb' subsystem.
+ enumerate = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(enumerate, "usb");
+ udev_enumerate_scan_devices(enumerate);
- if (type == USB_DT_INTERFACE) {
- interface = (struct usb_interface_descriptor *)bufptr;
- bufptr += length;
+ devices = udev_enumerate_get_list_entry(enumerate);
- if (length != USB_DT_INTERFACE_SIZE) {
- D("interface descriptor has wrong size\n");
- break;
- }
+ D("doing lsusb to find tizen devices\n");
+ udev_list_entry_foreach(dev_list_entry, devices) {
+ const char *path;
- DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d,"
- "bInterfaceProtocol: %d, bNumEndpoints: %d\n",
- interface->bInterfaceClass, interface->bInterfaceSubClass,
- interface->bInterfaceProtocol, interface->bNumEndpoints);
-
- if (interface->bNumEndpoints == 2 &&
- is_sdb_interface(vid, interface->bInterfaceClass,
- interface->bInterfaceSubClass, interface->bInterfaceProtocol)) {
-
- D("looking for bulk endpoints\n");
- // looks like SDB...
- ep1 = (struct usb_endpoint_descriptor *)bufptr;
- bufptr += USB_DT_ENDPOINT_SIZE;
- ep2 = (struct usb_endpoint_descriptor *)bufptr;
- bufptr += USB_DT_ENDPOINT_SIZE;
-
- if (bufptr > devdesc + desclength ||
- ep1->bLength != USB_DT_ENDPOINT_SIZE ||
- ep1->bDescriptorType != USB_DT_ENDPOINT ||
- ep2->bLength != USB_DT_ENDPOINT_SIZE ||
- ep2->bDescriptorType != USB_DT_ENDPOINT) {
- D("endpoints not found\n");
- break;
- }
-
- // both endpoints should be bulk
- if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK ||
- ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) {
- D("bulk endpoints not found\n");
- continue;
- }
- /* aproto 01 needs 0 termination */
- if(interface->bInterfaceProtocol == 0x01) {
- zero_mask = ep1->wMaxPacketSize - 1;
- }
-
- // we have a match. now we just need to figure out which is in and which is out.
- if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
- local_ep_in = ep1->bEndpointAddress;
- local_ep_out = ep2->bEndpointAddress;
- } else {
- local_ep_in = ep2->bEndpointAddress;
- local_ep_out = ep1->bEndpointAddress;
- }
-
- register_device_callback(devname, local_ep_in, local_ep_out,
- interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
- break;
- }
+ path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(udev, path);
+ usb_plugged(dev);
+ udev_device_unref(dev);
+
+ }
+ // Free the enumerator object
+ udev_enumerate_unref(enumerate);
+ D("done lsusb to find tizen devices\n");
+ while (1) {
+ fd_set fds;
+ struct timeval tv;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ ret = select(fd+1, &fds, NULL, NULL, &tv);
+
+ if (ret > 0 && FD_ISSET(fd, &fds)) {
+ dev = udev_monitor_receive_device(mon);
+ if (dev) {
+ if (!strcmp("add", udev_device_get_action(dev))) {
+ usb_plugged(dev);
} else {
- bufptr += length;
+ usb_unplugged(dev);
}
- } // end of while
+ udev_device_unref(dev);
+ } else {
+ D("failed to get noti from udev monitor\n");
+ }
+ }
+ usleep(msec);
+ }
+ udev_unref(udev);
- sdb_close(fd);
- } // end of devdir while
- closedir(devdir);
- } //end of busdir while
- closedir(busdir);
+ return 0;
}
-void sdb_usb_cleanup()
+int is_device_registered(const char *unique_node_path)
{
+ int r = 0;
+ sdb_mutex_lock(&usb_lock, "usb registering locked");
+
+ LIST_NODE* curptr = usb_list;
+ while(curptr != NULL) {
+ usb_handle *usb = curptr->data;
+ if (!strcmp(usb->unique_node_path, unique_node_path)) {
+ r = 1;
+ break;
+ }
+ curptr = curptr->next_ptr;
+ }
+
+ sdb_mutex_unlock(&usb_lock, "usb registering unlocked");
+ return r;
}
-static int usb_bulk_write(usb_handle *h, const void *data, int len)
+void* usb_callback_thread(void* sleep_msec)
{
- struct usbdevfs_urb *urb = &h->urb_out;
- int res;
- struct timeval tv;
- struct timespec ts;
-
- memset(urb, 0, sizeof(*urb));
- urb->type = USBDEVFS_URB_TYPE_BULK;
- urb->endpoint = h->ep_out;
- urb->status = -1;
- urb->buffer = (void*) data;
- urb->buffer_length = len;
-
- D("++ write ++\n");
-
- sdb_mutex_lock(&h->lock);
- if(h->dead) {
- res = -1;
- goto fail;
- }
- do {
- res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
- } while((res < 0) && (errno == EINTR));
+ D("created usb callback thread\n");
+ int mseconds = (int) sleep_msec;
- if(res < 0) {
- goto fail;
- }
+ usb_register_callback(mseconds);
- res = -1;
- h->urb_out_busy = 1;
- for(;;) {
- /* time out after five seconds */
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec + 5;
- ts.tv_nsec = tv.tv_usec * 1000L;
- res = pthread_cond_timedwait(&h->notify, &h->lock, &ts);
- if(res < 0 || h->dead) {
- break;
- }
- if(h->urb_out_busy == 0) {
- if(urb->status == 0) {
- res = urb->actual_length;
- }
- break;
- }
+ return NULL;
+}
+
+void sdb_usb_init(void)
+{
+ sdb_thread_t tid;
+
+ if(sdb_thread_create(&tid, usb_callback_thread, (void*)(250*1000))){
+ LOG_FATAL("cannot create input thread\n");
}
-fail:
- sdb_mutex_unlock(&h->lock);
- D("-- write --\n");
- return res;
}
-static int usb_bulk_read(usb_handle *h, void *data, int len)
+void sdb_usb_cleanup()
{
- struct usbdevfs_urb *urb = &h->urb_in;
- struct usbdevfs_urb *out = NULL;
- int res;
-
- memset(urb, 0, sizeof(*urb));
- urb->type = USBDEVFS_URB_TYPE_BULK;
- urb->endpoint = h->ep_in;
- urb->status = -1;
- urb->buffer = data;
- urb->buffer_length = len;
-
-
- sdb_mutex_lock(&h->lock);
- if(h->dead) {
- res = -1;
- goto fail;
+ close_usb_devices();
+}
+
+#define URB_USERCONTEXT_COOKIE ((void *)0x1)
+
+static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size, int timeout) {
+ struct usbdevfs_urb urb;
+ int bytesdone = 0, requested;
+ struct timeval tv, tv_ref, tv_now;
+ struct usbdevfs_urb *context;
+ int ret, waiting;
+
+ struct timeval tv_cur;
+ /*
+ * HACK: The use of urb.usercontext is a hack to get threaded applications
+ * sort of working again. Threaded support is still not recommended, but
+ * this should allow applications to work in the common cases. Basically,
+ * if we get the completion for an URB we're not waiting for, then we update
+ * the usercontext pointer to 1 for the other threads URB and it will see
+ * the change after it wakes up from the the timeout. Ugly, but it works.
+ */
+
+ /*
+ * Get actual time, and add the timeout value. The result is the absolute
+ * time where we have to quit waiting for an message.
+ */
+ if (gettimeofday(&tv_cur, NULL) != 0) {
+ D("failed to read clock\n");
+ return -1;
}
- do {
- res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb);
- } while((res < 0) && (errno == EINTR));
+ tv_cur.tv_sec = tv_cur.tv_sec + timeout / 1000;
+ tv_cur.tv_usec = tv_cur.tv_usec + (timeout % 1000) * 1000;
- if(res < 0) {
- goto fail;
+ if (tv_cur.tv_usec > 1000000) {
+ tv_cur.tv_usec -= 1000000;
+ tv_cur.tv_sec++;
}
- h->urb_in_busy = 1;
- for(;;) {
- D("[ reap urb - wait ]\n");
- h->reaper_thread = pthread_self();
- sdb_mutex_unlock(&h->lock);
- res = ioctl(h->desc, USBDEVFS_REAPURB, &out);
- int saved_errno = errno;
- sdb_mutex_lock(&h->lock);
- h->reaper_thread = 0;
- if(h->dead) {
- res = -1;
- break;
- }
- if(res < 0) {
- if(saved_errno == EINTR) {
- continue;
- }
- D("[ reap urb - error ]\n");
- break;
+ do {
+ fd_set writefds;
+
+ requested = size - bytesdone;
+ if (requested > MAX_READ_WRITE)
+ requested = MAX_READ_WRITE;
+
+ urb.type = USBDEVFS_URB_TYPE_BULK;
+ urb.endpoint = ep;
+ urb.flags = 0;
+ urb.buffer = bytes + bytesdone;
+ urb.buffer_length = requested;
+ urb.signr = 0;
+ urb.actual_length = 0;
+ urb.number_of_packets = 0; /* don't do isochronous yet */
+ urb.usercontext = NULL;
+
+ ret = ioctl(h->node_fd, USBDEVFS_SUBMITURB, &urb);
+ if (ret < 0) {
+ D("failed to submit urb: %s\n", strerror(errno));
+ return -1;
}
- D("[ urb @%p status = %d, actual = %d ]\n",
- out, out->status, out->actual_length);
-
- if(out == &h->urb_in) {
- D("[ reap urb - IN complete ]\n");
- h->urb_in_busy = 0;
- if(urb->status == 0) {
- res = urb->actual_length;
- } else {
- res = -1;
+
+ FD_ZERO(&writefds);
+ FD_SET(h->node_fd, &writefds);
+
+restart: waiting = 1;
+ context = NULL;
+ while (!urb.usercontext && ((ret = ioctl(h->node_fd, USBDEVFS_REAPURBNDELAY, &context)) == -1) && waiting) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000; // 1 msec
+
+ select(h->node_fd + 1, NULL, &writefds, NULL, &tv); //sub second wait
+
+ if (timeout) {
+ /* compare with actual time, as the select timeout is not that precise */
+ gettimeofday(&tv_now, NULL);
+
+ if ((tv_now.tv_sec > tv_cur.tv_sec)
+ || ((tv_now.tv_sec == tv_cur.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec)))
+ waiting = 0;
}
- break;
}
- if(out == &h->urb_out) {
- D("[ reap urb - OUT compelete ]\n");
- h->urb_out_busy = 0;
- sdb_cond_broadcast(&h->notify);
+
+ if (context && context != &urb) {
+ context->usercontext = URB_USERCONTEXT_COOKIE;
+ /* We need to restart since we got a successful URB, but not ours */
+ goto restart;
}
+
+ /*
+ * If there was an error, that wasn't EAGAIN (no completion), then
+ * something happened during the reaping and we should return that
+ * error now
+ */
+ if (ret < 0 && !urb.usercontext && errno != EAGAIN)
+ D("error reaping URB: %s\n", strerror(errno));
+
+ bytesdone += urb.actual_length;
+ } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested);
+
+ /* If the URB didn't complete in success or error, then let's unlink it */
+ if (ret < 0 && !urb.usercontext) {
+ int rc;
+ if (!waiting)
+ rc = -ETIMEDOUT;
+ else
+ rc = urb.status;
+
+ ret = ioctl(h->node_fd, USBDEVFS_DISCARDURB, &urb);
+ if (ret < 0 && errno != EINVAL)
+ D("error discarding URB: %s\n", strerror(errno));
+
+ /*
+ * When the URB is unlinked, it gets moved to the completed list and
+ * then we need to reap it or else the next time we call this function,
+ * we'll get the previous completion and exit early
+ */
+ ioctl(h->node_fd, USBDEVFS_REAPURB, &context);
+
+ return rc;
}
-fail:
- sdb_mutex_unlock(&h->lock);
- return res;
-}
+ return bytesdone;
+}
int sdb_usb_write(usb_handle *h, const void *_data, int len)
{
- unsigned char *data = (unsigned char*) _data;
- int n;
- int need_zero = 0;
-
- if(h->zero_mask) {
- /* if we need 0-markers and our transfer
- ** is an even multiple of the packet size,
- ** we make note of it
- */
- if(!(len & h->zero_mask)) {
- need_zero = 1;
- }
- }
+ char *data = (char*) _data;
+ int n = 0;
+
+ D("+sdb_usb_write\n");
while(len > 0) {
- int xfer = (len > 4096) ? 4096 : len;
+ int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
- n = usb_bulk_write(h, data, xfer);
+ n = usb_urb_transfer(h, h->end_point[1], data, xfer, 0);
if(n != xfer) {
- D("ERROR: n = %d, errno = %d (%s)\n",
- n, errno, strerror(errno));
+ D("fail to usb write: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
return -1;
}
data += xfer;
}
- if(need_zero){
- n = usb_bulk_write(h, _data, 0);
- return n;
- }
+ D("-usb_write\n");
return 0;
}
int sdb_usb_read(usb_handle *h, void *_data, int len)
{
- unsigned char *data = (unsigned char*) _data;
+ char *data = (char*) _data;
int n;
- D("++ usb_read ++\n");
+ D("+sdb_usb_read\n");
+
while(len > 0) {
- int xfer = (len > 4096) ? 4096 : len;
+ int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
- D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname);
- n = usb_bulk_read(h, data, xfer);
- D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname);
+ n = usb_urb_transfer(h, h->end_point[0], data, xfer, 0);
if(n != xfer) {
- if((errno == ETIMEDOUT) && (h->desc != -1)) {
- D("[ timeout ]\n");
+ if((errno == ETIMEDOUT)) {
+ D("usb bulk read timeout\n");
if(n > 0){
data += n;
len -= n;
}
continue;
}
- D("ERROR: n = %d, errno = %d (%s)\n",
- n, errno, strerror(errno));
+ D("fail to usb read: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
return -1;
}
data += xfer;
}
- D("-- usb_read --\n");
+ D("-sdb_usb_read\n");
+
return 0;
}
void sdb_usb_kick(usb_handle *h)
{
- D("[ kicking %p (fd = %d) ]\n", h, h->desc);
- sdb_mutex_lock(&h->lock);
- if(h->dead == 0) {
- h->dead = 1;
-
- if (h->writeable) {
- /* HACK ALERT!
- ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
- ** This is a workaround for that problem.
- */
- if (h->reaper_thread) {
- pthread_kill(h->reaper_thread, SIGALRM);
- }
-
- /* cancel any pending transactions
- ** these will quietly fail if the txns are not active,
- ** but this ensures that a reader blocked on REAPURB
- ** will get unblocked
- */
- ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
- ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
- h->urb_in.status = -ENODEV;
- h->urb_out.status = -ENODEV;
- h->urb_in_busy = 0;
- h->urb_out_busy = 0;
- sdb_cond_broadcast(&h->notify);
- } else {
- unregister_usb_transport(h);
- }
- }
- sdb_mutex_unlock(&h->lock);
+ D("+kicking\n");
+ D("-kicking\n");
}
int sdb_usb_close(usb_handle *h)
{
- D("[ usb close ... ]\n");
- sdb_mutex_lock(&usb_lock);
- h->next->prev = h->prev;
- h->prev->next = h->next;
- h->prev = 0;
- h->next = 0;
-
- sdb_close(h->desc);
- D("[ usb closed %p (fd = %d) ]\n", h, h->desc);
- sdb_mutex_unlock(&usb_lock);
-
- free(h);
- return 0;
-}
+ D("+usb close\n");
-static void register_device(const char *dev_name,
- unsigned char ep_in, unsigned char ep_out,
- int interface, int serial_index, unsigned zero_mask)
-{
- usb_handle* usb = 0;
- int n = 0;
- char serial[256];
- int bConfigurationValue = 2; /* tizen specific : sdb needs 2nd configruation */
-
- /* Since Linux will not reassign the device ID (and dev_name)
- ** as long as the device is open, we can add to the list here
- ** once we open it and remove from the list when we're finally
- ** closed and everything will work out fine.
- **
- ** If we have a usb_handle on the list 'o handles with a matching
- ** name, we have no further work to do.
- */
- sdb_mutex_lock(&usb_lock);
- for(usb = handle_list.next; usb != &handle_list; usb = usb->next){
- if(!strcmp(usb->fname, dev_name)) {
- sdb_mutex_unlock(&usb_lock);
- return;
- }
- }
- sdb_mutex_unlock(&usb_lock);
-
- D("[ usb located new device %s (%d/%d/%d) ]\n",
- dev_name, ep_in, ep_out, interface);
- usb = calloc(1, sizeof(usb_handle));
- strcpy(usb->fname, dev_name);
- usb->ep_in = ep_in;
- usb->ep_out = ep_out;
- usb->zero_mask = zero_mask;
- usb->writeable = 1;
-
- sdb_cond_init(&usb->notify, 0);
- sdb_mutex_init(&usb->lock, 0);
- /* initialize mark to 1 so we don't get garbage collected after the device scan */
- usb->mark = 1;
- usb->reaper_thread = 0;
-
- usb->desc = unix_open(usb->fname, O_RDWR);
- if(usb->desc < 0) {
- /* if we fail, see if have read-only access */
- usb->desc = unix_open(usb->fname, O_RDONLY);
- if(usb->desc < 0) goto fail;
- usb->writeable = 0;
- D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
- } else {
- D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
- // TODO: verify reset is really needed!
- n = ioctl(usb->desc, USBDEVFS_RESET);
- if(n != 0) {
- D("[ usb reset failed %s fd = %d]\n", usb->fname, usb->desc);
- }
- n = ioctl(usb->desc, USBDEVFS_SETCONFIGURATION, &bConfigurationValue);
- if (n != 0) {
- D("[ usb set %d configuration failed %s fd = %d]\n", bConfigurationValue, usb->fname, usb->desc);
- D("check kernel is supporting %dth configuration\n", bConfigurationValue);
- }
-
- n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
- if(n != 0) {
- D("[ usb claim failed %s fd = %d]\n", usb->fname, usb->desc);
- }
+ if (h != NULL) {
+ remove_node(&usb_list, h->node, no_free);
+ sdb_close(h->node_fd);
+ free(h);
+ h = NULL;
}
-
- /* read the device's serial number */
- serial[0] = 0;
- memset(serial, 0, sizeof(serial));
- if (serial_index) {
- struct usbdevfs_ctrltransfer ctrl;
- __u16 buffer[128];
- __u16 languages[128];
- int i, result;
- int languageCount = 0;
-
- memset(languages, 0, sizeof(languages));
- memset(&ctrl, 0, sizeof(ctrl));
-
- // read list of supported languages
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | 0;
- ctrl.wIndex = 0;
- ctrl.wLength = sizeof(languages);
- ctrl.data = languages;
- ctrl.timeout = 1000;
-
- result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
- if (result > 0)
- languageCount = (result - 2) / 2;
-
- for (i = 1; i <= languageCount; i++) {
- memset(buffer, 0, sizeof(buffer));
- memset(&ctrl, 0, sizeof(ctrl));
-
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
- ctrl.wIndex = __le16_to_cpu(languages[i]);
- ctrl.wLength = sizeof(buffer);
- ctrl.data = buffer;
- ctrl.timeout = 1000;
-
- result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
- if (result > 0) {
- int j;
- // skip first word, and copy the rest to the serial string, changing shorts to bytes.
- result /= 2;
- for (j = 1; j < result; j++) {
- serial[j - 1] = __le16_to_cpu(buffer[j]);
- }
- serial[j - 1] = 0;
- break;
- }
- }
- }
-
- /* add to the end of the active handles */
- sdb_mutex_lock(&usb_lock);
- usb->next = &handle_list;
- usb->prev = handle_list.prev;
- usb->prev->next = usb;
- usb->next->prev = usb;
- sdb_mutex_unlock(&usb_lock);
-
- register_usb_transport(usb, serial, usb->writeable);
- return;
-
-fail:
- D("[ usb open %s error=%d, err_str = %s]\n",
- usb->fname, errno, strerror(errno));
- if(usb->desc >= 0) {
- sdb_close(usb->desc);
- }
- free(usb);
-}
-
-void* device_poll_thread(void* unused)
-{
- D("Created device thread\n");
- for(;;) {
- /* XXX use inotify */
- find_usb_device("/dev/bus/usb", register_device);
- linux_kick_disconnected_devices();
- sleep(1);
- }
- return NULL;
-}
-
-static void sigalrm_handler(int signo)
-{
- // don't need to do anything here
+ D("-usb close\n");
+ return 0;
}
-void sdb_usb_init()
-{
- sdb_thread_t tid;
- struct sigaction actions;
-
- memset(&actions, 0, sizeof(actions));
- sigemptyset(&actions.sa_mask);
- actions.sa_flags = 0;
- actions.sa_handler = sigalrm_handler;
- sigaction(SIGALRM,& actions, NULL);
-
- if(sdb_thread_create(&tid, device_poll_thread, NULL)){
- fatal_errno("cannot create input thread");
- }
-}
#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;
}
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);
}
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);
}
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) {
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);
}
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);
}
return utils_backend->sdb_sysdeps_init();
}
-int socket_loopback_client(int port, int type) {
- return utils_backend->socket_loopback_client(port, type);
+int sdb_host_connect(const char *host, int port, int type) {
+ LOG_INFO("host %s, port %d\n", host, port);
+ return utils_backend->sdb_host_connect(host, port, type);
}
-int socket_network_client(const char *host, int port, int type) {
- return utils_backend->socket_network_client(host, port, type);
+int sdb_port_listen(uint32_t inet, int port, int type) {
+ LOG_INFO("port %d, type %d\n", port, type);
+ return utils_backend->sdb_port_listen(inet, port, type);
}
-int socket_loopback_server(int port, int type) {
- return utils_backend->socket_loopback_server(port, type);
-}
-
-int socket_inaddr_any_server(int port, int type) {
- return utils_backend->socket_inaddr_any_server(port, type);
-}
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);
#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 sdb_creat(const char* path, int mode);
int sdb_read(int fd, void* buf, size_t len);
int sdb_write(int fd, const void* buf, size_t len);
-int sdb_lseek(int fd, int pos, int where);
int sdb_shutdown(int fd);
int sdb_close(int fd);
-int sdb_unlink(const char* path);
+int unix_unlink(const char* path);
int sdb_mkdir(const char* path, int mode);
void close_on_exec(int fd);
-int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
+int sdb_socket_accept(int serverfd);
int sdb_socketpair(int sv[2]);
void sdb_sleep_ms(int mseconds);
char* sdb_dirstart(const char* path);
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
#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
void (*start_logging)(void);
char* (*ansi_to_utf8)(const char *str);
int (*sdb_open)(const char* path, int options);
- int (*sdb_open_mode)(const char* path, int options, int mode);
- int (*unix_open)(const char* path, int options, ...);
int (*sdb_creat)(const char* path, int mode);
int (*sdb_read)(int fd, void* buf, size_t len);
int (*sdb_write)(int fd, const void* buf, size_t len);
- int (*sdb_lseek)(int fd, int pos, int where);
int (*sdb_shutdown)(int fd);
int (*sdb_close)(int fd);
- int (*sdb_unlink)(const char* path);
int (*sdb_mkdir)(const char* path, int mode);
void (*close_on_exec)(int fd);
- int (*sdb_socket_accept)(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
+ int (*sdb_socket_accept)(int serverfd);
int (*sdb_socketpair)(int sv[2]);
void (*sdb_sleep_ms)(int mseconds);
char* (*sdb_dirstart)(const char* path);
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);
};
#include "fdevent.h"
#define TRACE_TAG TRACE_SYSDEPS
-#include "sdb.h"
#include "utils_backend.h"
-
-#define LISTEN_BACKLOG 4
-
-static void _close_on_exec(int fd);
+#include "log.h"
#if defined(OS_DARWIN)
dup2(fd[1], STDERR_FILENO);
sdb_close(fd[1]);
+ sdb_close(STDOUT_FILENO);
+
// child process
int result = execl(path, "sdb", "fork-server", "server", NULL);
// this should not return
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;
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());
}
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 )
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;
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);
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);
}
{
}
-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);
}
-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));
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;
}
return s;
}
+
const struct utils_os_backend utils_unix_backend = {
.name = "unix utils",
.launch_server = _launch_server,
.start_logging = _start_logging,
.ansi_to_utf8 = _ansi_to_utf8,
.sdb_open = _sdb_open,
- .sdb_open_mode = _sdb_open_mode,
- .unix_open = _unix_open,
.sdb_creat = _sdb_creat,
.sdb_read = _sdb_read,
.sdb_write = _sdb_write,
- .sdb_lseek = _sdb_lseek,
.sdb_shutdown = _sdb_shutdown,
.sdb_close = _sdb_close,
.close_on_exec = _close_on_exec,
- .sdb_unlink = _sdb_unlink,
.sdb_mkdir = _sdb_mkdir,
.sdb_socket_accept = _sdb_socket_accept,
.sdb_socketpair = _sdb_socketpair,
.sdb_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
};
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <errno.h>
+#include <limits.h>
#include "utils.h"
#include "fdevent.h"
#include "fdevent_backend.h"
+#include "sdb_map.h"
#define TRACE_TAG TRACE_SYSDEPS
-#include "sdb.h"
#include "utils_backend.h"
+#include "log.h"
+
+// error mapping table between windoes & unix
+// error codes are described: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx
+void setBaseErrno(DWORD dwLastErrorCode);
+int getBaseErrno(DWORD dwLastErrorCode);
+
+static int total_handle_number = 0;
+static LIST_NODE* free_socket_handle_list = NULL;
+//this increases 1 when one file fd is created.
+static int file_handle_count = WIN32_MAX_FHS;
+//this indicates total number of socket fds.
+static int socket_handle_number = 0;
+
+struct errno_lists {
+ unsigned long wincode;
+ int posixcode;
+};
+
+static struct errno_lists errno_list[] = {
+ { 0, 0 }, /* 0 return 0 as normal operation */
+ { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 Incorrect function. */
+ { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 The system cannot find the file specified. */
+ { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 The system cannot find the path specified. */
+ { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 The system cannot open the file. */
+ { ERROR_ACCESS_DENIED, EACCES }, /* 5 Access is denied. */
+ { ERROR_INVALID_HANDLE, EBADF }, /* 6 The handle is invalid. */
+ { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 The storage control blocks were destroyed.*/
+ { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 Not enough storage is available to process this command. */
+ { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 he storage control block address is invalid. */
+ { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 The environment is incorrect. */
+ { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 An attempt was made to load a program with an incorrect format. */
+ { ERROR_INVALID_ACCESS, EINVAL }, /* 12 The access code is invalid. */
+ { ERROR_INVALID_DATA, EINVAL }, /* 13 The data is invalid. */
+ { ERROR_OUTOFMEMORY, ENOMEM }, /* 14 Not enough storage is available to complete this operation. */
+ { ERROR_INVALID_DRIVE, ENOENT }, /* 15 The system cannot find the drive specified.*/
+ { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
+ { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
+ { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
+ { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
+ { ERROR_BAD_NETPATH, ENOENT }, /* 53 */
+ { ERROR_NETWORK_ACCESS_DENIED, EACCES },/* 65 */
+ { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
+ { ERROR_FILE_EXISTS, EEXIST }, /* 80 */
+ { ERROR_CANNOT_MAKE, EACCES }, /* 82 */
+ { ERROR_FAIL_I24, EACCES }, /* 83 */
+ { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
+ { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
+ { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
+ { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
+ { ERROR_DISK_FULL, ENOSPC }, /* 112 */
+ { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
+ { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
+ { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
+ { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
+ { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
+ { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
+ { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
+ { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
+ { ERROR_NOT_LOCKED, EACCES }, /* 158 */
+ { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
+ { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
+ { ERROR_LOCK_FAILED, EACCES }, /* 167 */
+ { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
+ { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
+ { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
+ { ERROR_NO_DATA, EPIPE }, /* 232 */
+ { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }, /* 1816 */
+ { WSAEINTR, EINTR }, /* 10004 Interrupted function call. */
+ { WSAEWOULDBLOCK, EAGAIN } /* 10035 This error is returned from operations on nonblocking sockets that cannot be completed immediately */
+};
+
+void setBaseErrno(DWORD dwLastErrorCode)
+{
+ errno = getBaseErrno(dwLastErrorCode);
+}
+
+int getBaseErrno(DWORD dwLastErrorCode)
+{
+ int i;
+
+ for (i = 0; i < sizeof(errno_list)/sizeof(errno_list[0]); ++i) {
+ if (dwLastErrorCode == errno_list[i].posixcode) {
+ return errno_list[i].posixcode;
+ }
+ }
+ LOG_FIXME("unsupport error code: %ld\n", dwLastErrorCode);
+ return EINVAL;
+}
/*
* from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
static void _start_logging(void)
{
- const char* p = getenv("SDB_TRACE");
+ const char* p = getenv(DEBUG_ENV);
if (p == NULL) {
return;
}
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)
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
/**************************************************************************/
static sdb_mutex_t _win32_lock;
-static FHRec _win32_fhs[WIN32_MAX_FHS];
-static int _win32_fh_count;
-
-FH _fh_from_int(int fd) {
- FH f;
-
- fd -= WIN32_FH_BASE;
-
- if (fd < 0 || fd >= _win32_fh_count) {
- D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE);
- errno = EBADF;
- return NULL;
+static sdb_mutex_t sdb_handle_map_lock;
+static sdb_mutex_t free_socket_handle_list_lock;
+
+static SDB_HANDLE* alloc_handle(int socket) {
+
+ SDB_HANDLE* _h = NULL;
+ sdb_mutex_lock(&_win32_lock, "_fh_alloc");
+
+ if(total_handle_number < WIN32_MAX_FHS) {
+ total_handle_number++;
+ if(socket) {
+ if(free_socket_handle_list == NULL) {
+ SDB_SOCK_HANDLE* __h = malloc(sizeof(SDB_SOCK_HANDLE));
+ __h->event_location = -1;
+ _h = (SDB_HANDLE*)__h;
+ _h->fd = socket_handle_number++;
+ LOG_INFO("no free socket. assign socket fd FD(%d)\n", _h->fd);
+ }
+ else {
+ sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_alloc");
+ _h = free_socket_handle_list->data;
+ remove_first(&free_socket_handle_list, no_free);
+ sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_alloc");
+ LOG_INFO("reuse socket fd FD(%d)\n", _h->fd);
+ }
+ _h->u.socket = INVALID_SOCKET;
+ }
+ else {
+ _h = malloc(sizeof(SDB_HANDLE));
+ _h->fd = file_handle_count++;
+ _h->u.file_handle = INVALID_HANDLE_VALUE;
+ }
+
+ sdb_handle_map_put(_h->fd, _h);
}
-
- f = &_win32_fhs[fd];
-
- if (f->used == 0) {
- D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE);
- errno = EBADF;
- return NULL;
- }
-
- return f;
-}
-
-int _fh_to_int(FH f) {
- if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
- return (int) (f - _win32_fhs) + WIN32_FH_BASE;
-
- return -1;
+ else {
+ errno = ENOMEM;
+ LOG_ERROR("no more space for file descriptor. max file descriptor is %d\n", WIN32_MAX_FHS);
+ }
+
+ sdb_mutex_unlock(&_win32_lock, "_fh_alloc");
+ return _h;
+}
+
+SDB_HANDLE* sdb_handle_map_get(int _key) {
+ MAP_KEY key;
+ key.key_int = _key;
+ sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_get");
+ SDB_HANDLE* result = map_get(&sdb_handle_map, key);
+ sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_get");
+ return result;
+}
+
+void sdb_handle_map_put(int _key, SDB_HANDLE* value) {
+ MAP_KEY key;
+ key.key_int = _key;
+ sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_put");
+ map_put(&sdb_handle_map, key, value);
+ sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_put");
+}
+
+void sdb_handle_map_remove(int _key) {
+ MAP_KEY key;
+ key.key_int = _key;
+ sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_remove");
+ map_remove(&sdb_handle_map, key);
+ sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_remove");
+}
+
+static int _fh_close(SDB_HANDLE* _h) {
+ if(IS_SOCKET_HANDLE(_h)) {
+ shutdown(_h->u.socket, SD_BOTH);
+ closesocket(_h->u.socket);
+ _h->u.socket = INVALID_SOCKET;
+ sdb_handle_map_remove(_h->fd);
+ sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_close");
+ prepend(&free_socket_handle_list, _h);
+ sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_close");
+ }
+ else {
+ CloseHandle(_h->u.file_handle);
+ _h->u.file_handle = INVALID_HANDLE_VALUE;
+ free(_h);
+ }
+ total_handle_number--;
+ return 0;
}
-static FH _fh_alloc(FHClass clazz) {
- int nn;
- FH f = NULL;
+static int check_socket_err(int result) {
- sdb_mutex_lock(&_win32_lock);
+ if(result != SOCKET_ERROR) {
+ return result;
+ }
- if (_win32_fh_count < WIN32_MAX_FHS) {
- f = &_win32_fhs[_win32_fh_count++];
- goto Exit;
- }
+ DWORD err = WSAGetLastError();
- for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
- if (_win32_fhs[nn].clazz == NULL) {
- f = &_win32_fhs[nn];
- goto Exit;
- }
- }
- D( "_fh_alloc: no more free file descriptors\n");
- Exit: if (f) {
- f->clazz = clazz;
- f->used = 1;
- f->eof = 0;
- clazz->_fh_init(f);
- }
- sdb_mutex_unlock(&_win32_lock);
- return f;
-}
-
-static int _fh_close(FH f) {
- if (f->used) {
- f->clazz->_fh_close(f);
- f->used = 0;
- f->eof = 0;
- f->clazz = NULL;
- }
- return 0;
+ if(err == WSAEWOULDBLOCK) {
+ errno = EAGAIN;
+ LOG_ERROR("socket error EAGAIN\n");
+ }
+ else if(err == WSAEINTR) {
+ errno = EINTR;
+ LOG_ERROR("socket error EINTR\n");
+ }
+ else if(err == 0) {
+ errno = 0;
+ LOG_ERROR("socket error 0\n");
+ }
+ else {
+ errno = EINVAL;
+ LOG_ERROR("unknown error %d\n", err);
+ }
+ return -1;
}
-/* forward definitions */
-static const FHClassRec _fh_file_class;
-static const FHClassRec _fh_socket_class;
+static int check_file_err(HANDLE h) {
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** file-based descriptor handling *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
+ if (h != INVALID_HANDLE_VALUE) {
+ return 1;
+ }
-static void _fh_file_init(FH f) {
- f->fh_handle = INVALID_HANDLE_VALUE;
-}
+ _fh_close(h);
+ DWORD err = GetLastError();
-static int _fh_file_close(FH f) {
- CloseHandle(f->fh_handle);
- f->fh_handle = INVALID_HANDLE_VALUE;
- return 0;
+ if(err == ERROR_PATH_NOT_FOUND) {
+ LOG_ERROR("path not found\n");
+ errno = ENOTDIR;
+ }
+ else if (err == ERROR_FILE_NOT_FOUND) {
+ LOG_ERROR("file not found\n");
+ errno = ENOENT;
+ }
+ else {
+ LOG_ERROR("unknown erro %d\n", err);
+ errno = ENOENT;
+ }
+ return -1;
}
-static int _fh_file_read(FH f, void* buf, int len) {
- DWORD read_bytes;
-
- if (!ReadFile(f->fh_handle, buf, (DWORD) len, &read_bytes, NULL)) {
- D( "sdb_read: could not read %d bytes from %s\n", len, f->name);
- errno = EIO;
- return -1;
- } else if (read_bytes < (DWORD) len) {
- f->eof = 1;
- }
- return (int) read_bytes;
-}
+static int _sdb_open(const char* path, int file_options) {
-static int _fh_file_write(FH f, const void* buf, int len) {
- DWORD wrote_bytes;
+ DWORD access_mode = 0;
+ DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
- if (!WriteFile(f->fh_handle, buf, (DWORD) len, &wrote_bytes, NULL)) {
- D( "sdb_file_write: could not write %d bytes from %s\n", len, f->name);
- errno = EIO;
- return -1;
- } else if (wrote_bytes < (DWORD) len) {
- f->eof = 1;
+ if(file_options == O_RDONLY) {
+ access_mode = GENERIC_READ;
}
- return (int) wrote_bytes;
-}
-
-static int _fh_file_lseek(FH f, int pos, int origin) {
- DWORD method;
- DWORD result;
-
- switch (origin) {
- case SEEK_SET:
- method = FILE_BEGIN;
- break;
- case SEEK_CUR:
- method = FILE_CURRENT;
- break;
- case SEEK_END:
- method = FILE_END;
- break;
- default:
- errno = EINVAL;
- return -1;
+ else if(file_options == O_WRONLY) {
+ access_mode = GENERIC_WRITE;
}
-
- result = SetFilePointer(f->fh_handle, pos, NULL, method);
- if (result == INVALID_SET_FILE_POINTER) {
- errno = EIO;
- return -1;
- } else {
- f->eof = 0;
+ else if(file_options == O_RDWR) {
+ access_mode = GENERIC_READ | GENERIC_WRITE;
}
- return (int) result;
-}
-
-static void _fh_file_hook(FH f, int event, EventHook eventhook); /* forward */
-
-static const FHClassRec _fh_file_class = { _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read, _fh_file_write,
- _fh_file_hook };
-
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** file-based descriptor handling *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static int _sdb_open(const char* path, int options) {
- FH f;
-
- DWORD desiredAccess = 0;
- DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-
- switch (options) {
- case O_RDONLY:
- desiredAccess = GENERIC_READ;
- break;
- case O_WRONLY:
- desiredAccess = GENERIC_WRITE;
- break;
- case O_RDWR:
- desiredAccess = GENERIC_READ | GENERIC_WRITE;
- break;
- default:
- D("sdb_open: invalid options (0x%0x)\n", options);
+ else {
+ LOG_ERROR("invalid options (0x%0x)\n", file_options);
errno = EINVAL;
return -1;
}
- f = _fh_alloc(&_fh_file_class);
- if (!f) {
+ SDB_HANDLE* _h;
+ _h = alloc_handle(0);
+ if (!_h) {
errno = ENOMEM;
return -1;
}
- f->fh_handle = CreateFile(path, desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL);
-
- if (f->fh_handle == INVALID_HANDLE_VALUE) {
- _fh_close(f);
- D( "sdb_open: could not open '%s':", path);
- switch (GetLastError()) {
- case ERROR_FILE_NOT_FOUND:
- D( "file not found\n");
- errno = ENOENT;
- return -1;
-
- case ERROR_PATH_NOT_FOUND:
- D( "path not found\n");
- errno = ENOTDIR;
- return -1;
-
- default:
- D( "unknown error\n");
- errno = ENOENT;
- return -1;
- }
- }
-
- snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
- D( "sdb_open: '%s' => fd %d\n", path, _fh_to_int(f));
- return _fh_to_int(f);
-}
-
-static int _sdb_open_mode(const char* path, int options, int mode) {
- return sdb_open(path, options);
-}
+ _h->u.file_handle = CreateFile(path, access_mode, share_mode, NULL, OPEN_EXISTING, 0, NULL);
-static int _unix_open(const char* path, int options, ...) {
- if ((options & O_CREAT) == 0) {
- return open(path, options);
- } else {
- int mode;
- va_list args;
- va_start( args, options);
- mode = va_arg( args, int );
- va_end( args);
- return open(path, options, mode);
+ if(check_file_err(_h->u.file_handle) == -1) {
+ return -1;
}
+ return _h->fd;
}
-/* ignore mode on Win32 */
static int _sdb_creat(const char* path, int mode) {
- FH f;
+ SDB_HANDLE* _h = alloc_handle(0);
- f = _fh_alloc(&_fh_file_class);
- if (!f) {
- errno = ENOMEM;
+ if (!_h) {
+ errno = ENOMEM;
return -1;
}
-
- f->fh_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
+ _h->u.file_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
- if (f->fh_handle == INVALID_HANDLE_VALUE) {
- _fh_close(f);
- D( "sdb_creat: could not open '%s':", path);
- switch (GetLastError()) {
- case ERROR_FILE_NOT_FOUND:
- D( "file not found\n");
- errno = ENOENT;
- return -1;
-
- case ERROR_PATH_NOT_FOUND:
- D( "path not found\n");
- errno = ENOTDIR;
- return -1;
-
- default:
- D( "unknown error\n");
- errno = ENOENT;
- return -1;
- }
+ if(check_file_err(_h->u.file_handle) == -1) {
+ return -1;
}
- snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path);
- D( "sdb_creat: '%s' => fd %d\n", path, _fh_to_int(f));
- return _fh_to_int(f);
+ return _h->fd;
}
-static int _sdb_read(int fd, void* buf, size_t len) {
- FH f = _fh_from_int(fd);
+static int _sdb_read(int fd, void* buffer, size_t r_length) {
+ SDB_HANDLE* _h = sdb_handle_map_get(fd);
- if (f == NULL) {
- return -1;
+ if (_h == NULL) {
+ LOG_ERROR("FD(%d) disconnected\n", fd);
+ return 0;
}
- return f->clazz->_fh_read(f, buf, len);
-}
-
-static int _sdb_write(int fd, const void* buf, size_t len) {
- FH f = _fh_from_int(fd);
-
- if (f == NULL) {
- return -1;
+ if(IS_SOCKET_HANDLE(_h)) {
+ return check_socket_err(recv(_h->u.socket, buffer, r_length, 0));
}
+ else {
+ DWORD r_bytes;
- return f->clazz->_fh_write(f, buf, len);
+ if (!ReadFile(_h->u.file_handle, buffer, (DWORD) r_length, &r_bytes, NULL)) {
+ D( "sdb_read: could not read %d bytes from FD(%d)\n", r_length, _h->fd);
+ errno = EIO;
+ return -1;
+ }
+ return (int) r_bytes;
+ }
}
-static int _sdb_lseek(int fd, int pos, int where) {
- FH f = _fh_from_int(fd);
+static int _sdb_write(int fd, const void* buffer, size_t w_length) {
+ SDB_HANDLE* _h = sdb_handle_map_get(fd);
- if (!f) {
- return -1;
+ if (_h == NULL) {
+ LOG_ERROR("FD(%d) not exists. disconnected\n", fd);
+ return 0;
}
- return f->clazz->_fh_lseek(f, pos, where);
+ if(IS_SOCKET_HANDLE(_h)) {
+ return check_socket_err(send(_h->u.socket, buffer, w_length, 0));
+ }
+ else {
+ DWORD w_bytes;
+
+ if (!WriteFile(_h->u.file_handle, buffer, (DWORD) w_length, &w_bytes, NULL)) {
+ D( "sdb_file_write: could not write %d bytes from FD(%d)\n", w_length, _h->fd);
+ errno = EIO;
+ return -1;
+ }
+ return (int) w_bytes;
+ }
}
static int _sdb_shutdown(int fd) {
- FH f = _fh_from_int(fd);
- if (!f) {
+ if(!IS_SOCKET_FD(fd)) {
+ LOG_ERROR("FD(%d) is file fd\n", fd);
+ return -1;
+ }
+
+ SDB_HANDLE* _h = sdb_handle_map_get(fd);
+
+ if (_h == NULL) {
+ LOG_ERROR("FD(%d) not exists\n", fd);
return -1;
}
- D( "sdb_shutdown: %s\n", f->name);
- shutdown(f->fh_socket, SD_BOTH);
+ D( "sdb_shutdown: FD(%d)\n", fd);
+ shutdown(_h->u.socket, SD_BOTH);
return 0;
}
static int _sdb_close(int fd) {
- FH f = _fh_from_int(fd);
- if (!f) {
+ SDB_HANDLE* _h = sdb_handle_map_get(fd);
+
+ if (_h == NULL) {
+ LOG_ERROR("FD(%d) not exists\n", fd);
return -1;
}
- D( "sdb_close: %s\n", f->name);
- _fh_close(f);
+ D( "sdb_close: FD(%d)\n", fd);
+ _fh_close(_h);
return 0;
}
-static int _sdb_unlink(const char* path) {
- int rc = unlink(path);
-
- if (rc == -1 && errno == EACCES) {
- /* unlink returns EACCES when the file is read-only, so we first */
- /* try to make it writable, then unlink again... */
- rc = chmod(path, _S_IREAD | _S_IWRITE);
- if (rc == 0)
- rc = unlink(path);
- }
- return rc;
-}
-
static int _sdb_mkdir(const char* path, int mode) {
return _mkdir(path);
}
return p;
}
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** socket-based file descriptors *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
-
-static void _socket_set_errno(void) {
- switch (WSAGetLastError()) {
- case 0:
- errno = 0;
- break;
- case WSAEWOULDBLOCK:
- errno = EAGAIN;
- break;
- case WSAEINTR:
- errno = EINTR;
- break;
- default:
- D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError());
- errno = EINVAL;
- }
-}
-
-static void _fh_socket_init(FH f) {
- f->fh_socket = INVALID_SOCKET;
- f->event = WSACreateEvent();
- f->mask = 0;
-}
-
-static int _fh_socket_close(FH f) {
- /* gently tell any peer that we're closing the socket */
- shutdown(f->fh_socket, SD_BOTH);
- closesocket(f->fh_socket);
- f->fh_socket = INVALID_SOCKET;
- CloseHandle(f->event);
- f->mask = 0;
- return 0;
-}
-
-static int _fh_socket_lseek(FH f, int pos, int origin) {
- errno = EPIPE;
- return -1;
-}
-
-static int _fh_socket_read(FH f, void* buf, int len) {
- int result = recv(f->fh_socket, buf, len, 0);
- if (result == SOCKET_ERROR) {
- _socket_set_errno();
- result = -1;
- }
- return result;
-}
-
-static int _fh_socket_write(FH f, const void* buf, int len) {
- int result = send(f->fh_socket, buf, len, 0);
- if (result == SOCKET_ERROR) {
- _socket_set_errno();
- result = -1;
- }
- return result;
-}
-
-static void _fh_socket_hook(FH f, int event, EventHook hook); /* forward */
-
-static const FHClassRec _fh_socket_class = { _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read,
- _fh_socket_write, _fh_socket_hook };
-
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** replacement for libs/cutils/socket_xxxx.c *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
-
-#include <winsock2.h>
-
static int _winsock_init;
-static void _cleanup_winsock(void) {
+static void _cleanup_winsock() {
WSACleanup();
}
static void _init_winsock(void) {
if (!_winsock_init) {
WSADATA wsaData;
- int rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (rc != 0) {
- fatal("sdb: could not initialize Winsock\n");
+ if(WSAStartup(MAKEWORD(2, 2), &wsaData)) {
+ LOG_FATAL("sdb: could not initialize Winsock\n");
}
- atexit(_cleanup_winsock);
_winsock_init = 1;
+ atexit(_cleanup_winsock);
}
}
-static int _socket_loopback_client(int port, int type) {
- FH f = _fh_alloc(&_fh_socket_class);
- struct sockaddr_in addr;
- SOCKET s;
-
- if (!f)
- return -1;
-
- if (!_winsock_init)
- _init_winsock();
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- s = socket(AF_INET, type, 0);
- if (s == INVALID_SOCKET) {
- D("socket_loopback_client: could not create socket\n");
- _fh_close(f);
- return -1;
- }
-
- f->fh_socket = s;
- if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port);
- _fh_close(f);
- return -1;
- }
- snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
- D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
- return _fh_to_int(f);
-}
-
-#define LISTEN_BACKLOG 4
-
-static int _socket_loopback_server(int port, int type) {
- FH f = _fh_alloc(&_fh_socket_class);
+static int _sdb_port_listen(uint32_t inet, int port, int type) {
+ SDB_HANDLE* _h = alloc_handle(1);
struct sockaddr_in addr;
SOCKET s;
int n;
- if (!f) {
+ if (_h == NULL) {
return -1;
}
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;
}
addr.sin_port = htons(port);
memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
- s = socket(hp->h_addrtype, type, 0);
- if (s == INVALID_SOCKET) {
- _fh_close(f);
+ if ((s = socket(hp->h_addrtype, type, 0)) == INVALID_SOCKET) {
+ LOG_ERROR("failed to create socket to %s(%d)\n", host, port);
+ _fh_close(_h);
return -1;
}
- f->fh_socket = s;
+
+ _h->u.socket = s;
if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- _fh_close(f);
+ _fh_close(_h);
return -1;
}
- snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
- D(
- "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
- return _fh_to_int(f);
+ D("sdb_host_connect: host '%s' port %d type %s => FD(%d)\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd);
+ return _h->fd;
}
-static int _socket_inaddr_any_server(int port, int type) {
- FH f = _fh_alloc(&_fh_socket_class);
- struct sockaddr_in addr;
- SOCKET s;
- int n;
+static int _sdb_socket_accept(int serverfd) {
- if (!f)
- return -1;
+ if(!IS_SOCKET_FD(serverfd)) {
+ LOG_ERROR("FD(%d) is file fd\n", serverfd);
+ return -1;
+ }
- if (!_winsock_init)
- _init_winsock();
+ SDB_HANDLE* server_h = sdb_handle_map_get(serverfd);
+ struct sockaddr addr;
+ socklen_t alen = sizeof(addr);
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
- s = socket(AF_INET, type, 0);
- if (s == INVALID_SOCKET) {
- _fh_close(f);
+ if (!server_h) {
+ LOG_ERROR( "FD(%d) Invalid server fd\n", serverfd);
return -1;
}
- f->fh_socket = s;
- n = 1;
- setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n));
-
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- _fh_close(f);
+ SDB_HANDLE* _h = alloc_handle(1);
+ if (!_h) {
return -1;
}
- if (type == SOCK_STREAM) {
- int ret;
-
- ret = listen(s, LISTEN_BACKLOG);
- if (ret < 0) {
- _fh_close(f);
- return -1;
- }
- }
- snprintf(f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port);
- D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f));
- return _fh_to_int(f);
-}
-
-static int _sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) {
- FH serverfh = _fh_from_int(serverfd);
- FH fh;
-
- if (!serverfh || serverfh->clazz != &_fh_socket_class) {
- D( "sdb_socket_accept: invalid fd %d\n", serverfd);
- return -1;
- }
-
- fh = _fh_alloc(&_fh_socket_class);
- if (!fh) {
- D( "sdb_socket_accept: not enough memory to allocate accepted socket descriptor\n");
- return -1;
- }
-
- fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
- if (fh->fh_socket == INVALID_SOCKET) {
- _fh_close(fh);
- D( "sdb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError());
+ _h->u.socket = accept(server_h->u.socket, &addr, &alen);
+ if (_h->u.socket == INVALID_SOCKET) {
+ _fh_close(_h);
+ LOG_ERROR( "sdb_socket_accept: accept on FD(%d) return error %ld\n", serverfd, GetLastError());
return -1;
}
- snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name);
- D( "sdb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh));
- return _fh_to_int(fh);
+ LOG_INFO( "sdb_socket_accept on FD(%d) returns FD(%d)\n", serverfd, _h->fd);
+ return _h->fd;
}
static void _disable_tcp_nagle(int fd) {
- FH fh = _fh_from_int(fd);
- int on;
-
- if (!fh || fh->clazz != &_fh_socket_class)
- return;
-
- setsockopt(fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on));
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** emulated socketpairs *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
-
-/* we implement socketpairs directly in use space for the following reasons:
- * - it avoids copying data from/to the Nt kernel
- * - it allows us to implement fdevent hooks easily and cheaply, something
- * that is not possible with standard Win32 pipes !!
- *
- * basically, we use two circular buffers, each one corresponding to a given
- * direction.
- *
- * each buffer is implemented as two regions:
- *
- * region A which is (a_start,a_end)
- * region B which is (0, b_end) with b_end <= a_start
- *
- * an empty buffer has: a_start = a_end = b_end = 0
- *
- * a_start is the pointer where we start reading data
- * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
- * then you start writing at b_end
- *
- * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE
- *
- * there is room when b_end < a_start || a_end < BUFER_SIZE
- *
- * when reading, a_start is incremented, it a_start meets a_end, then
- * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on..
- */
-
-#define BIP_BUFFER_SIZE 4096
-
-#if 0
-#include <stdio.h>
-# define BIPD(x) D x
-# define BIPDUMP bip_dump_hex
-static void bip_dump_hex( const unsigned char* ptr, size_t len )
-{
- int nn, len2 = len;
-
- if (len2 > 8) len2 = 8;
-
- for (nn = 0; nn < len2; nn++)
- printf("%02x", ptr[nn]);
- printf(" ");
-
- for (nn = 0; nn < len2; nn++) {
- int c = ptr[nn];
- if (c < 32 || c > 127)
- c = '.';
- printf("%c", c);
- }
- printf("\n");
- fflush(stdout);
-}
+ if(!IS_SOCKET_FD(fd)) {
+ LOG_ERROR("FD(%d) is file fd\n", fd);
+ return;
+ }
-#else
-# define BIPD(x) do {} while (0)
-# define BIPDUMP(p,l) BIPD(p)
-#endif
-
-
-static void bip_buffer_init(BipBuffer buffer) {
- D( "bit_buffer_init %p\n", buffer);
- buffer->a_start = 0;
- buffer->a_end = 0;
- buffer->b_end = 0;
- buffer->can_write = 1;
- buffer->can_read = 0;
- buffer->fdin = 0;
- buffer->fdout = 0;
- buffer->closed = 0;
- buffer->evt_write = CreateEvent(NULL, TRUE, TRUE, NULL);
- buffer->evt_read = CreateEvent(NULL, TRUE, FALSE, NULL);
- InitializeCriticalSection(&buffer->lock);
-}
-
-static void bip_buffer_close(BipBuffer bip) {
- bip->closed = 1;
-
- if (!bip->can_read) {
- SetEvent(bip->evt_read);
- }
- if (!bip->can_write) {
- SetEvent(bip->evt_write);
+ SDB_HANDLE* _h = sdb_handle_map_get(fd);
+ if (!_h) {
+ return;
}
-}
-static void bip_buffer_done(BipBuffer bip) {
- BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout ));
- CloseHandle(bip->evt_read);
- CloseHandle(bip->evt_write);
- DeleteCriticalSection(&bip->lock);
+ int on;
+ setsockopt(_h->u.socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on));
}
-static int bip_buffer_write(BipBuffer bip, const void* src, int len) {
- int avail, count = 0;
-
- if (len <= 0)
- return 0;
-
- BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
- BIPDUMP( src, len);
-
- EnterCriticalSection(&bip->lock);
-
- while (!bip->can_write) {
- int ret;
- LeaveCriticalSection(&bip->lock);
-
- if (bip->closed) {
- errno = EPIPE;
- return -1;
- }
- /* spinlocking here is probably unfair, but let's live with it */
- ret = WaitForSingleObject(bip->evt_write, INFINITE);
- if (ret != WAIT_OBJECT_0) { /* buffer probably closed */
- D(
- "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
- return 0;
- }
- if (bip->closed) {
- errno = EPIPE;
- return -1;
- }
- EnterCriticalSection(&bip->lock);
- }
-
- BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
- avail = BIP_BUFFER_SIZE - bip->a_end;
- if (avail > 0) {
- /* we can append to region A */
- if (avail > len)
- avail = len;
+static int socketpair_impl(int af, int type, int protocol, SOCKET socks[2])
+{
+ struct sockaddr_in addr;
+ SOCKET s;
- memcpy(bip->buff + bip->a_end, src, avail);
- src += avail;
- count += avail;
- len -= avail;
+ LOG_INFO("+socketpair impl in\n");
- bip->a_end += avail;
- if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
- bip->can_write = 0;
- ResetEvent(bip->evt_write);
- goto Exit;
- }
+ if (!_winsock_init) {
+ _init_winsock();
}
+ // Create a socket, bind it to 127.0.0.1 and a random port, and listen.
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ addr.sin_port = 0;
- if (len == 0)
- goto Exit;
-
- avail = bip->a_start - bip->b_end;
- assert( avail > 0);
- /* since can_write is TRUE */
-
- if (avail > len)
- avail = len;
-
- memcpy(bip->buff + bip->b_end, src, avail);
- count += avail;
- bip->b_end += avail;
+ socks[0] = socks[1] = INVALID_SOCKET;
- if (bip->b_end == bip->a_start) {
- bip->can_write = 0;
- ResetEvent(bip->evt_write);
+ if ((s = socket(af, type, 0)) == INVALID_SOCKET) {
+ return -1;
}
- Exit:
- assert( count > 0);
-
- if (!bip->can_read) {
- bip->can_read = 1;
- SetEvent(bip->evt_read);
+ if (bind(s, (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) {
+ closesocket(s);
+ return -1;
}
- BIPD(
- ( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
- LeaveCriticalSection(&bip->lock);
-
- return count;
-}
-
-static int bip_buffer_read(BipBuffer bip, void* dst, int len) {
- int avail, count = 0;
-
- if (len <= 0)
- return 0;
-
- BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
- EnterCriticalSection(&bip->lock);
- while (!bip->can_read) {
-#if 0
- LeaveCriticalSection( &bip->lock );
- errno = EAGAIN;
+ int addr_len = sizeof(addr);
+ if (getsockname(s, (struct sockaddr*) &addr, &addr_len) == SOCKET_ERROR) {
+ closesocket(s);
return -1;
-#else
- int ret;
- LeaveCriticalSection(&bip->lock);
+ }
- if (bip->closed) {
- errno = EPIPE;
- return -1;
+ do
+ {
+ if (listen(s, 1) == SOCKET_ERROR) {
+ break;
}
-
- ret = WaitForSingleObject(bip->evt_read, INFINITE);
- if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
- D(
- "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError());
- return 0;
+ // Creates the second socket and connects it to the same address and port.
+ if ((socks[0] = socket(af, type, 0)) == INVALID_SOCKET) {
+ break;
}
- if (bip->closed) {
- errno = EPIPE;
- return -1;
+ if (connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) {
+ break;
}
- EnterCriticalSection(&bip->lock);
-#endif
- }
-
- BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len ));
-
- avail = bip->a_end - bip->a_start;
- assert( avail > 0);
- /* since can_read is TRUE */
-
- if (avail > len)
- avail = len;
-
- memcpy(dst, bip->buff + bip->a_start, avail);
- dst += avail;
- count += avail;
- len -= avail;
-
- bip->a_start += avail;
- if (bip->a_start < bip->a_end)
- goto Exit;
-
- bip->a_start = 0;
- bip->a_end = bip->b_end;
- bip->b_end = 0;
-
- avail = bip->a_end;
- if (avail > 0) {
- if (avail > len)
- avail = len;
- memcpy(dst, bip->buff, avail);
- count += avail;
- bip->a_start += avail;
-
- if (bip->a_start < bip->a_end)
- goto Exit;
-
- bip->a_start = bip->a_end = 0;
- }
-
- bip->can_read = 0;
- ResetEvent(bip->evt_read);
-
- Exit:
- assert( count > 0);
-
- if (!bip->can_write) {
- bip->can_write = 1;
- SetEvent(bip->evt_write);
- }
-
- BIPDUMP( (const unsigned char*)dst - count, count);
- BIPD(
- ( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
- LeaveCriticalSection(&bip->lock);
-
- return count;
-}
-
-typedef struct SocketPairRec_ {
- BipBufferRec a2b_bip;
- BipBufferRec b2a_bip;
- FH a_fd;
- int used;
-
-} SocketPairRec;
-
-void _fh_socketpair_init(FH f) {
- f->fh_pair = NULL;
-}
-
-static int _fh_socketpair_close(FH f) {
- if (f->fh_pair) {
- SocketPair pair = f->fh_pair;
-
- if (f == pair->a_fd) {
- pair->a_fd = NULL;
+ if ((socks[1] = accept(s, NULL, NULL)) == INVALID_SOCKET) {
+ break;
}
+ closesocket(s);
+ LOG_INFO("-socketpair impl out\n");
+ return 0;
- bip_buffer_close(&pair->b2a_bip);
- bip_buffer_close(&pair->a2b_bip);
+ } while (0);
- if (--pair->used == 0) {
- bip_buffer_done(&pair->b2a_bip);
- bip_buffer_done(&pair->a2b_bip);
- free(pair);
- }
- f->fh_pair = NULL;
- }
- return 0;
-}
+ closesocket(socks[0]);
+ closesocket(socks[1]);
+ closesocket(s);
-static int _fh_socketpair_lseek(FH f, int pos, int origin) {
- errno = ESPIPE;
+ LOG_ERROR("socketpair error: %ld\n", WSAGetLastError());
return -1;
}
-static int _fh_socketpair_read(FH f, void* buf, int len) {
- SocketPair pair = f->fh_pair;
- BipBuffer bip;
+static int _sdb_socketpair(int sv[2]) {
+ SOCKET socks[2];
+ int r = 0;
- if (!pair)
+ r = socketpair_impl( AF_INET, SOCK_STREAM, IPPROTO_TCP, socks);
+ if (r < 0) {
+ LOG_ERROR("failed to create socket pair:(%ld)\n", GetLastError());
return -1;
+ }
- if (f == pair->a_fd)
- bip = &pair->b2a_bip;
- else
- bip = &pair->a2b_bip;
-
- return bip_buffer_read(bip, buf, len);
-}
-
-static int _fh_socketpair_write(FH f, const void* buf, int len) {
- SocketPair pair = f->fh_pair;
- BipBuffer bip;
+ SDB_HANDLE* _ha = alloc_handle(1);
+ SDB_HANDLE* _hb = alloc_handle(1);
- if (!pair)
+ if (!_ha || !_hb) {
return -1;
-
- if (f == pair->a_fd)
- bip = &pair->a2b_bip;
- else
- bip = &pair->b2a_bip;
-
- return bip_buffer_write(bip, buf, len);
-}
-
-static void _fh_socketpair_hook(FH f, int event, EventHook hook); /* forward */
-
-static const FHClassRec _fh_socketpair_class = { _fh_socketpair_init, _fh_socketpair_close, _fh_socketpair_lseek,
- _fh_socketpair_read, _fh_socketpair_write, _fh_socketpair_hook };
-
-static int _sdb_socketpair(int sv[2]) {
- FH fa, fb;
- SocketPair pair;
-
- fa = _fh_alloc(&_fh_socketpair_class);
- fb = _fh_alloc(&_fh_socketpair_class);
-
- if (!fa || !fb)
- goto Fail;
-
- pair = malloc(sizeof(*pair));
- if (pair == NULL) {
- D("sdb_socketpair: not enough memory to allocate pipes\n");
- goto Fail;
}
- bip_buffer_init(&pair->a2b_bip);
- bip_buffer_init(&pair->b2a_bip);
+ _ha->u.socket = socks[0];
+ _hb->u.socket = socks[1];
- fa->fh_pair = pair;
- fb->fh_pair = pair;
- pair->used = 2;
- pair->a_fd = fa;
-
- sv[0] = _fh_to_int(fa);
- sv[1] = _fh_to_int(fb);
-
- pair->a2b_bip.fdin = sv[0];
- pair->a2b_bip.fdout = sv[1];
- pair->b2a_bip.fdin = sv[1];
- pair->b2a_bip.fdout = sv[0];
+ if (_ha->u.socket == INVALID_SOCKET || _hb->u.socket == INVALID_SOCKET) {
+ _fh_close(_ha);
+ _fh_close(_hb);
+ LOG_ERROR( "failed to get socket:(%ld)\n", GetLastError());
+ return -1;
+ }
+ sv[0] = _ha->fd;
+ sv[1] = _hb->fd;
- snprintf(fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1]);
- snprintf(fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0]);
- D( "sdb_socketpair: returns (%d, %d)\n", sv[0], sv[1]);
+ D( "sdb_socketpair: returns (FD(%d), FD(%d))\n", sv[0], sv[1] );
return 0;
-
- Fail: _fh_close(fb);
- _fh_close(fa);
- return -1;
}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
/**************************************************************************/
/**************************************************************************/
-
-/** 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);
.start_logging = _start_logging,
.ansi_to_utf8 = _ansi_to_utf8,
.sdb_open = _sdb_open,
- .sdb_open_mode = _sdb_open_mode,
- .unix_open = _unix_open,
.sdb_creat = _sdb_creat,
.sdb_read = _sdb_read,
.sdb_write = _sdb_write,
- .sdb_lseek = _sdb_lseek,
.sdb_shutdown = _sdb_shutdown,
.sdb_close = _sdb_close,
.close_on_exec = _close_on_exec,
- .sdb_unlink = _sdb_unlink,
.sdb_mkdir = _sdb_mkdir,
.sdb_socket_accept = _sdb_socket_accept,
.sdb_socketpair = _sdb_socketpair,
.sdb_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
};