From: kh5325.kim Date: Tue, 22 Oct 2013 05:25:26 +0000 (+0900) Subject: merged from dev to tizen X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=320dfff22e8d0af76b454202a7e16c33741a4b72;p=sdk%2Ftools%2Fsdb.git merged from dev to tizen Change-Id: I883731a41b81baf46b2a60cb893896a3930e0e58 Signed-off-by: kh5325.kim --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71f1d5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +sdb_*.tar.gz +sdb_*_*.zip +sdb.package.* + +usb-connection-for-ssh_*_*.zip +usb-connection-for-ssh.package.* + +*.bak +bin/ +prebuilt/ +src/sdbwinapi/buildfre_win7_x86.log +src/sdbwinapi/buildfre_win7_x86.wrn +src/sdbwinapi/objfre_win7_x86/ +src/sdbwinusbapi/buildfre_win7_x86.log +src/sdbwinusbapi/buildfre_win7_x86.wrn +src/sdbwinusbapi/objfre_win7_x86/ diff --git a/Makefile b/Makefile index 4a0f5fc..fc83b05 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ # HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1) +LBITS := $(shell getconf LONG_BIT) +OBJDIR := bin +MODULE := sdb # sdb host tool # ========================================================= @@ -12,26 +15,27 @@ HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1) ifeq ($(HOST_OS),darwin) CC := clang endif - # ifeq ($(HOST_OS),linux) LOCAL_USB_SRC := src/usb_linux.c LOCAL_UTIL_SRC := src/utils_unix.c LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c - LOCAL_LFLAGS := -lrt -lpthread + LOCAL_LFLAGS := -lrt -lpthread -ludev LOCAL_CFLAGS := -DOS_LINUX -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1 -D_FILE_OFFSET_BITS=64 + HAS_LIBUSB := false endif ifeq ($(HOST_OS),darwin) - LOCAL_USB_SRC := src/libusb/darwin.c src/sdb_usb.c src/libusb/error.c src/libusb/usb.c src/libusb/descriptors.c + LOCAL_USB_SRC := src/usb_darwin.c LOCAL_UTIL_SRC := src/utils_unix.c LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_unix.c LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon LOCAL_CFLAGS := -DOS_DARWIN -DHAVE_FORKEXEC -DHAVE_TERMIO_H -DHAVE_SYMLINKS -mmacosx-version-min=10.4 -DSDB_HOST=1 -DSDB_HOST_ON_TARGET=1 + HAS_LIBUSB := false endif ifeq ($(HOST_OS),mingw32) - LOCAL_USB_SRC := src/libusb/windows.c + LOCAL_USB_SRC := deps/libusb/windows.c LOCAL_UTIL_SRC := src/utils_windows.c LOCAL_OTHER_SRC := src/fdevent.c src/fdevent_windows.c LOCAL_CFLAGS := -DOS_WINDOWS @@ -49,18 +53,22 @@ SDB_SRC_FILES := \ src/commandline.c \ src/sdb_client.c \ src/sockets.c \ - src/services.c \ src/file_sync_client.c \ $(LOCAL_USB_SRC) \ + src/device_vendors.c \ $(LOCAL_UTIL_SRC) \ $(LOCAL_OTHER_SRC) \ src/utils.c \ src/strutils.c \ + src/memutils.c \ src/linkedlist.c \ src/sdb_model.c \ src/sdb_constants.c \ src/file_sync_functions.c \ - src/command_function.c + src/command_function.c \ + src/log.c \ + src/listener.c \ + src/sdb_map.c SDB_CFLAGS := -O2 -g -Wall -Wno-unused-parameter SDB_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE @@ -69,16 +77,15 @@ SDB_CFLAGS += $(LOCAL_CFLAGS) SDB_LFLAGS := $(LOCAL_LFLAGS) STATIC_LFLAGS := $(LOCAL_STATIC_LFLAGS) -OBJDIR := bin - -MODULE := sdb - all : $(MODULE) sdb : $(SDB_SRC_FILES) - rm -rf $(OBJDIR) mkdir -p $(OBJDIR) +ifeq ($(HAS_LIBUSB),true) + make -C ./deps/libusb + make install -C ./deps/libusb +endif $(CC) $(SDB_CFLAGS) -o $(OBJDIR)/$(MODULE) $(SDB_SRC_FILES) $(LOCAL_IFLAGS) $(SDB_LFLAGS) $(STATIC_LFLAGS) clean : - rm -rf $(OBJDIR)/* + rm -rf $(OBJDIR) diff --git a/deps/libusb/AUTHORS b/deps/libusb/AUTHORS new file mode 100644 index 0000000..d2beff9 --- /dev/null +++ b/deps/libusb/AUTHORS @@ -0,0 +1,2 @@ +Daniel Drake + diff --git a/deps/libusb/COPYING b/deps/libusb/COPYING new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/deps/libusb/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/deps/libusb/LICENSE b/deps/libusb/LICENSE new file mode 100644 index 0000000..f98680a --- /dev/null +++ b/deps/libusb/LICENSE @@ -0,0 +1,47 @@ +libusb is covered by the LGPL: + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +---- + +Alternatively, the files usb.h.in and/or usb.h may be licensed under the +BSD license: + +Copyright (c) 2000-2003 Johannes Erdfelt +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/deps/libusb/Makefile b/deps/libusb/Makefile new file mode 100644 index 0000000..bb6054f --- /dev/null +++ b/deps/libusb/Makefile @@ -0,0 +1,42 @@ +# +# +# Makefile for libusb +# + +# +HOST_OS := $(shell uname -s | tr A-Z a-z | cut -d'_' -f1) + +# ========================================================= + +ifeq ($(HOST_OS),darwin) + CC := /Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/bin/llvm-gcc-4.2 +else + CC := gcc +endif + +# +ifeq ($(HOST_OS),linux) + LOCAL_USB_SRC := linux.c error.c usb.c descriptors.c + LOCAL_LFLAGS := -lrt -lpthread + LOCAL_CFLAGS := -DOS_LINUX +endif + +ifeq ($(HOST_OS),darwin) + LOCAL_USB_SRC := darwin.c error.c usb.c descriptors.c + LOCAL_LFLAGS := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon + LOCAL_CFLAGS := -DOS_DARWIN -mmacosx-version-min=10.4 +endif + +MODULE = libusb.so + +all : $(MODULE) + +$(MODULE) : $(LOCAL_USB_SRC) + $(CC) -o $(MODULE) -fPIC $(LOCAL_USB_SRC) $(LOCAL_LFLAGS) $(LOCAL_CFLAGS) -shared + +install : + mkdir -p ../../bin + cp $(MODULE) ../../bin +clean : + rm -rf $(MODULE) + rm -rf *.o diff --git a/deps/libusb/darwin.c b/deps/libusb/darwin.c new file mode 100644 index 0000000..c330eb0 --- /dev/null +++ b/deps/libusb/darwin.c @@ -0,0 +1,1329 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Darwin/MacOS X Support + * + * (c) 2002-2007 Nathan Hjelm + * + * (07/25/2007): + * - Added a fix to ignore buggy (virtual?) hubs. + * (06/26/2006): + * - Bulk functions no longer use async transfer functions. + * (04/17/2005): + * - Lots of minor fixes. + * - Endpoint table now made by claim_interface to fix a bug. + * - Merged Read/Write to make modifications easier. + * (03/25/2005): + * - Fixed a bug when using asynchronous callbacks within a multi-threaded application. + * (03/14/2005): + * - Added an endpoint table to speed up bulk transfers. + * 0.1.11 (02/22/2005): + * - Updated error checking in read/write routines to check completion codes. + * - Updated set_configuration so that the open interface is reclaimed before completion. + * - Fixed several typos. + * 0.1.8 (01/12/2004): + * - Fixed several memory leaks. + * - Readded 10.0 support + * - Added support for USB fuctions defined in 10.3 and above + * (01/02/2003): + * - Applied a patch by Philip Edelbrock that fixes a bug in usb_control_msg. + * (12/16/2003): + * - Even better error printing. + * - Devices that cannot be opened can have their interfaces opened. + * 0.1.6 (05/12/2002): + * - Fixed problem where libusb holds resources after program completion. + * - Mouse should no longer freeze up now. + * 0.1.2 (02/13/2002): + * - Bulk functions should work properly now. + * 0.1.1 (02/11/2002): + * - Fixed major bug (device and interface need to be released after use) + * 0.1.0 (01/06/2002): + * - Tested driver with gphoto (works great as long as Image Capture isn't running) + * 0.1d (01/04/2002): + * - Implimented clear_halt and resetep + * - Uploaded to CVS. + * 0.1b (01/04/2002): + * - Added usb_debug line to bulk read and write function. + * 0.1a (01/03/2002): + * - Driver mostly completed using the macosx driver I wrote for my rioutil software. + * + * Derived from Linux version by Richard Tobin. + * Also partly derived from BSD version. + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +/* standard includes for darwin/os10 (IOKit) */ +#include +#include +#include +#include + +#include "usbi.h" + +/* some defines */ +/* IOUSBInterfaceInferface */ +#if defined (kIOUSBInterfaceInterfaceID220) + +// #warning "libusb being compiled for 10.4 or later" +#define usb_interface_t IOUSBInterfaceInterface220 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 +#define InterfaceVersion 220 + +#elif defined (kIOUSBInterfaceInterfaceID197) + +// #warning "libusb being compiled for 10.3 or later" +#define usb_interface_t IOUSBInterfaceInterface197 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 +#define InterfaceVersion 197 + +#elif defined (kIOUSBInterfaceInterfaceID190) + +// #warning "libusb being compiled for 10.2 or later" +#define usb_interface_t IOUSBInterfaceInterface190 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 +#define InterfaceVersion 190 + +#elif defined (kIOUSBInterfaceInterfaceID182) + +// #warning "libusb being compiled for 10.1 or later" +#define usb_interface_t IOUSBInterfaceInterface182 +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 +#define InterfaceVersion 182 + +#else + +/* No timeout functions available! Time to upgrade your os. */ +#warning "libusb being compiled without support for timeout bulk functions! 10.0 and up" +#define usb_interface_t IOUSBInterfaceInterface +#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID +#define LIBUSB_NO_TIMEOUT_INTERFACE +#define InterfaceVersion 180 + +#endif + +/* IOUSBDeviceInterface */ +#if defined (kIOUSBDeviceInterfaceID197) + +#define usb_device_t IOUSBDeviceInterface197 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 +#define DeviceVersion 197 + +#elif defined (kIOUSBDeviceInterfaceID187) + +#define usb_device_t IOUSBDeviceInterface187 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 +#define DeviceVersion 187 + +#elif defined (kIOUSBDeviceInterfaceID182) + +#define usb_device_t IOUSBDeviceInterface182 +#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 +#define DeviceVersion 182 + +#else + +#define usb_device_t IOUSBDeviceInterface +#define DeviceInterfaceID kIOUSBDeviceInterfaceID +#define LIBUSB_NO_TIMEOUT_DEVICE +#define LIBUSB_NO_SEIZE_DEVICE +#define DeviceVersion 180 + +#endif + +typedef IOReturn io_return_t; +typedef IOCFPlugInInterface *io_cf_plugin_ref_t; +typedef SInt32 s_int32_t; +typedef IOReturn (*rw_async_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size, + IOAsyncCallback1 callback, void *refcon); +typedef IOReturn (*rw_async_to_func_t)(void *self, UInt8 pipeRef, void *buf, UInt32 size, + UInt32 noDataTimeout, UInt32 completionTimeout, + IOAsyncCallback1 callback, void *refcon); + +#if !defined(IO_OBJECT_NULL) +#define IO_OBJECT_NULL ((io_object_t)0) +#endif + +struct darwin_dev_handle { + usb_device_t **device; + usb_interface_t **interface; + int open; + + /* stored translation table for pipes to endpoints */ + int num_endpoints; + unsigned char *endpoint_addrs; +}; + +static IONotificationPortRef gNotifyPort; +static mach_port_t masterPort = MACH_PORT_NULL; + +static void darwin_cleanup (void) +{ + IONotificationPortDestroy(gNotifyPort); + mach_port_deallocate(mach_task_self(), masterPort); +} + +static char *darwin_error_str (int result) { + switch (result) { + case kIOReturnSuccess: + return "no error"; + case kIOReturnNotOpen: + return "device not opened for exclusive access"; + case kIOReturnNoDevice: + return "no connection to an IOService"; + case kIOUSBNoAsyncPortErr: + return "no async port has been opened for interface"; + case kIOReturnExclusiveAccess: + return "another process has device opened for exclusive access"; + case kIOUSBPipeStalled: + return "pipe is stalled"; + case kIOReturnError: + return "could not establish a connection to the Darwin kernel"; + case kIOUSBTransactionTimeout: + return "transaction timed out"; + case kIOReturnBadArgument: + return "invalid argument"; + case kIOReturnAborted: + return "transaction aborted"; + case kIOReturnNotResponding: + return "device not responding"; + default: + return "unknown error"; + } +} + +/* not a valid errorno outside darwin.c */ +#define LUSBDARWINSTALL (ELAST+1) + +static int darwin_to_errno (int result) { + switch (result) { + case kIOReturnSuccess: + return 0; + case kIOReturnNotOpen: + return EBADF; + case kIOReturnNoDevice: + case kIOUSBNoAsyncPortErr: + return ENXIO; + case kIOReturnExclusiveAccess: + return EBUSY; + case kIOUSBPipeStalled: + return LUSBDARWINSTALL; + case kIOReturnBadArgument: + return EINVAL; + case kIOUSBTransactionTimeout: + return ETIMEDOUT; + case kIOReturnNotResponding: + return EIO; + case kIOReturnError: + default: + return 1; + } +} + +static int usb_setup_iterator (io_iterator_t *deviceIterator) +{ + int result; + CFMutableDictionaryRef matchingDict; + + /* set up the matching dictionary for class IOUSBDevice and its subclasses. + It will be consumed by the IOServiceGetMatchingServices call */ + if ((matchingDict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) { + darwin_cleanup (); + + USB_ERROR_STR(-1, "libusb/darwin.c usb_setup_iterator: Could not create a matching dictionary.\n"); + } + + result = IOServiceGetMatchingServices(masterPort, matchingDict, deviceIterator); + matchingDict = NULL; + + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_setup_iterator: IOServiceGetMatchingServices: %s\n", + darwin_error_str(result)); + + return 0; +} + +static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) +{ + io_cf_plugin_ref_t *plugInInterface = NULL; + usb_device_t **device; + io_service_t usbDevice; + long result, score; + + if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator))) + return NULL; + + result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &plugInInterface, + &score); + + result = IOObjectRelease(usbDevice); + if (result || !plugInInterface) + return NULL; + + (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), + (LPVOID)&device); + + (*plugInInterface)->Stop(plugInInterface); + IODestroyPlugInInterface (plugInInterface); + plugInInterface = NULL; + + (*(device))->GetLocationID(device, locationp); + + return device; +} + +int usb_os_open(usb_dev_handle *dev) +{ + struct darwin_dev_handle *device; + + io_return_t result; + io_iterator_t deviceIterator; + + usb_device_t **darwin_device; + + UInt32 location = *((UInt32 *)dev->device->dev); + UInt32 dlocation; + + if (!dev) + USB_ERROR(-ENXIO); + + if (masterPort == MACH_PORT_NULL) + USB_ERROR(-EINVAL); + + device = calloc(1, sizeof(struct darwin_dev_handle)); + if (!device) + USB_ERROR(-ENOMEM); + + if (usb_debug > 3) + fprintf(stderr, "usb_os_open: %04x:%04x\n", + dev->device->descriptor.idVendor, + dev->device->descriptor.idProduct); + + if ((result = usb_setup_iterator (&deviceIterator)) < 0) + return result; + + /* This port of libusb uses locations to keep track of devices. */ + while ((darwin_device = usb_get_next_device (deviceIterator, &dlocation)) != NULL) { + if (dlocation == location) + break; + + (*darwin_device)->Release(darwin_device); + } + + IOObjectRelease(deviceIterator); + device->device = darwin_device; + + if (device->device == NULL) + USB_ERROR_STR (-ENOENT, "usb_os_open: %s\n", "Device not found!"); + +#if !defined (LIBUSB_NO_SEIZE_DEVICE) + result = (*(device->device))->USBDeviceOpenSeize (device->device); +#else + /* No Seize in OS X 10.0 (Darwin 1.4) */ + result = (*(device->device))->USBDeviceOpen (device->device); +#endif + + if (result != kIOReturnSuccess) { + switch (result) { + case kIOReturnExclusiveAccess: + if (usb_debug > 0) + fprintf (stderr, "usb_os_open(USBDeviceOpenSeize): %s\n", darwin_error_str(result)); + break; + default: + (*(device->device))->Release (device->device); + USB_ERROR_STR(-darwin_to_errno (result), "usb_os_open(USBDeviceOpenSeize): %s", + darwin_error_str(result)); + } + + device->open = 0; + } else + device->open = 1; + + dev->impl_info = device; + dev->interface = -1; + dev->altsetting = -1; + + device->num_endpoints = 0; + device->endpoint_addrs = NULL; + + return 0; +} + +int usb_os_close(usb_dev_handle *dev) +{ + struct darwin_dev_handle *device; + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + usb_release_interface(dev, dev->interface); + + if (usb_debug > 3) + fprintf(stderr, "usb_os_close: %04x:%04x\n", + dev->device->descriptor.idVendor, + dev->device->descriptor.idProduct); + + if (device->open == 1) + result = (*(device->device))->USBDeviceClose(device->device); + else + result = kIOReturnSuccess; + + /* device may not need to be released, but if it has to... */ + (*(device->device))->Release(device->device); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_os_close(USBDeviceClose): %s", darwin_error_str(result)); + + free (device); + + return 0; +} + +static int get_endpoints (struct darwin_dev_handle *device) +{ + io_return_t ret; + + u_int8_t numep, direction, number; + u_int8_t dont_care1, dont_care3; + u_int16_t dont_care2; + + int i; + + if (device == NULL || device->interface == NULL) + return -EINVAL; + + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c get_endpoints: building table of endpoints.\n"); + + /* retrieve the total number of endpoints on this interface */ + ret = (*(device->interface))->GetNumEndpoints(device->interface, &numep); + if ( ret ) { + if ( usb_debug > 1 ) + fprintf ( stderr, "get_endpoints: interface is %p\n", device->interface ); + + USB_ERROR_STR ( -ret, "get_endpoints: can't get number of endpoints for interface" ); + } + + free (device->endpoint_addrs); + device->endpoint_addrs = calloc (sizeof (unsigned char), numep); + + /* iterate through pipe references */ + for (i = 1 ; i <= numep ; i++) { + ret = (*(device->interface))->GetPipeProperties(device->interface, i, &direction, &number, + &dont_care1, &dont_care2, &dont_care3); + + if (ret != kIOReturnSuccess) { + fprintf (stderr, "get_endpoints: an error occurred getting pipe information on pipe %d\n", + i ); + USB_ERROR_STR(-darwin_to_errno(ret), "get_endpoints(GetPipeProperties): %s", darwin_error_str(ret)); + } + + if (usb_debug > 1) + fprintf (stderr, "get_endpoints: Pipe %i: DIR: %i number: %i\n", i, direction, number); + + device->endpoint_addrs[i - 1] = ((direction << 7 & USB_ENDPOINT_DIR_MASK) | + (number & USB_ENDPOINT_ADDRESS_MASK)); + } + + device->num_endpoints = numep; + + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c get_endpoints: complete.\n"); + + return 0; +} + +static int claim_interface (usb_dev_handle *dev, int interface) +{ + io_iterator_t interface_iterator; + io_service_t usbInterface = IO_OBJECT_NULL; + io_return_t result; + io_cf_plugin_ref_t *plugInInterface = NULL; + + IOUSBFindInterfaceRequest request; + + struct darwin_dev_handle *device; + long score; + int current_interface; + + device = dev->impl_info; + + request.bInterfaceClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + request.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator); + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s", + darwin_error_str(result)); + + for ( current_interface=0 ; current_interface <= interface ; current_interface++ ) { + usbInterface = IOIteratorNext(interface_iterator); + if ( usb_debug > 3 ) + fprintf ( stderr, "Interface %d of device is 0x%08x\n", + current_interface, usbInterface ); + } + + current_interface--; + + /* the interface iterator is no longer needed, release it */ + IOObjectRelease(interface_iterator); + + if (!usbInterface) { + u_int8_t nConfig; /* Index of configuration to use */ + IOUSBConfigurationDescriptorPtr configDesc; /* to describe which configuration to select */ + /* Only a composite class device with no vendor-specific driver will + be configured. Otherwise, we need to do it ourselves, or there + will be no interfaces for the device. */ + + if ( usb_debug > 3 ) + fprintf ( stderr,"claim_interface: No interface found; selecting configuration\n" ); + + result = (*(device->device))->GetNumberOfConfigurations ( device->device, &nConfig ); + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetNumberOfConfigurations): %s", + darwin_error_str(result)); + + if (nConfig < 1) + USB_ERROR_STR(-ENXIO ,"claim_interface(GetNumberOfConfigurations): no configurations"); + else if ( nConfig > 1 && usb_debug > 0 ) + fprintf ( stderr, "claim_interface: device has more than one" + " configuration, using the first (warning)\n" ); + + if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: device has %d configuration%s\n", + (int)nConfig, (nConfig>1?"s":"") ); + + /* Always use the first configuration */ + result = (*(device->device))->GetConfigurationDescriptorPtr ( (device->device), 0, &configDesc ); + if (result != kIOReturnSuccess) { + if (device->open == 1) { + (*(device->device))->USBDeviceClose ( (device->device) ); + (*(device->device))->Release ( (device->device) ); + } + + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(GetConfigurationDescriptorPtr): %s", + darwin_error_str(result)); + } else if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: configuration value is %d\n", + configDesc->bConfigurationValue ); + + if (device->open == 1) { + result = (*(device->device))->SetConfiguration ( (device->device), configDesc->bConfigurationValue ); + + if (result != kIOReturnSuccess) { + (*(device->device))->USBDeviceClose ( (device->device) ); + (*(device->device))->Release ( (device->device) ); + + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(SetConfiguration): %s", + darwin_error_str(result)); + } + + dev->config = configDesc->bConfigurationValue; + } + + request.bInterfaceClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + request.bAlternateSetting = kIOUSBFindInterfaceDontCare; + + /* Now go back and get the chosen interface */ + result = (*(device->device))->CreateInterfaceIterator(device->device, &request, &interface_iterator); + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno(result), "claim_interface(CreateInterfaceIterator): %s", + darwin_error_str(result)); + + for (current_interface = 0 ; current_interface <= interface ; current_interface++) { + usbInterface = IOIteratorNext(interface_iterator); + + if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: Interface %d of device is 0x%08x\n", + current_interface, usbInterface ); + } + current_interface--; + + /* the interface iterator is no longer needed, release it */ + IOObjectRelease(interface_iterator); + + if (!usbInterface) + USB_ERROR_STR (-ENOENT, "claim_interface: interface iterator returned NULL"); + } + + result = IOCreatePlugInInterfaceForService(usbInterface, + kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugInInterface, &score); + /* No longer need the usbInterface object after getting the plug-in */ + result = IOObjectRelease(usbInterface); + if (result || !plugInInterface) + USB_ERROR(-ENOENT); + + /* Now create the device interface for the interface */ + result = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(InterfaceInterfaceID), + (LPVOID) &device->interface); + + /* No longer need the intermediate plug-in */ + (*plugInInterface)->Stop(plugInInterface); + IODestroyPlugInInterface (plugInInterface); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(QueryInterface): %s", + darwin_error_str(result)); + + if (!device->interface) + USB_ERROR(-EACCES); + + if ( usb_debug > 3 ) + fprintf ( stderr, "claim_interface: Interface %d of device from QueryInterface is %p\n", + current_interface, device->interface); + + /* claim the interface */ + result = (*(device->interface))->USBInterfaceOpen(device->interface); + if (result) + USB_ERROR_STR(-darwin_to_errno(result), "claim_interface(USBInterfaceOpen): %s", + darwin_error_str(result)); + + result = get_endpoints (device); + + if (result) { + /* this should not happen */ + usb_release_interface (dev, interface); + USB_ERROR_STR ( result, "claim_interface: could not build endpoint table"); + } + + return 0; +} + +int usb_set_configuration (usb_dev_handle *dev, int configuration) +{ + struct darwin_dev_handle *device; + io_return_t result; + int interface; + + if ( usb_debug > 3 ) + fprintf ( stderr, "usb_set_configuration: called for config %x\n", configuration ); + + if (!dev) + USB_ERROR_STR ( -ENXIO, "usb_set_configuration: called with null device\n" ); + + if ((device = dev->impl_info) == NULL) + USB_ERROR_STR ( -ENOENT, "usb_set_configuration: device not properly initialized" ); + + /* Setting configuration will invalidate the interface, so we need + to reclaim it. First, dispose of existing interface, if any. */ + interface = dev->interface; + + if ( device->interface ) + usb_release_interface(dev, dev->interface); + + result = (*(device->device))->SetConfiguration(device->device, configuration); + + if (result) + USB_ERROR_STR(-darwin_to_errno(result), "usb_set_configuration(SetConfiguration): %s", + darwin_error_str(result)); + + /* Reclaim interface */ + if (interface != -1) + result = usb_claim_interface (dev, interface); + + dev->config = configuration; + + return result; +} + +int usb_claim_interface(usb_dev_handle *dev, int interface) +{ + struct darwin_dev_handle *device = dev->impl_info; + + io_return_t result; + + if ( usb_debug > 3 ) + fprintf ( stderr, "usb_claim_interface: called for interface %d\n", interface ); + + if (!device) + USB_ERROR_STR ( -ENOENT, "usb_claim_interface: device is NULL" ); + + if (!(device->device)) + USB_ERROR_STR ( -EINVAL, "usb_claim_interface: device->device is NULL" ); + + /* If we have already claimed an interface, release it */ + if ( device->interface ) + usb_release_interface(dev, dev->interface); + + result = claim_interface ( dev, interface ); + if ( result ) + USB_ERROR_STR ( result, "usb_claim_interface: couldn't claim interface" ); + + dev->interface = interface; + + /* interface is claimed and async IO is set up: return 0 */ + return 0; +} + +int usb_release_interface(usb_dev_handle *dev, int interface) +{ + struct darwin_dev_handle *device; + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + return 0; + + result = (*(device->interface))->USBInterfaceClose(device->interface); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(USBInterfaceClose): %s", + darwin_error_str(result)); + + result = (*(device->interface))->Release(device->interface); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_release_interface(Release): %s", + darwin_error_str(result)); + + device->interface = NULL; + + free (device->endpoint_addrs); + + device->num_endpoints = 0; + device->endpoint_addrs = NULL; + + dev->interface = -1; + dev->altsetting = -1; + + return 0; +} + +int usb_set_altinterface(usb_dev_handle *dev, int alternate) +{ + struct darwin_dev_handle *device; + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_set_altinterface: interface used without being claimed"); + + result = (*(device->interface))->SetAlternateInterface(device->interface, alternate); + + if (result) + USB_ERROR_STR(result, "usb_set_altinterface: could not set alternate interface"); + + dev->altsetting = alternate; + + result = get_endpoints (device); + if (result) { + /* this should not happen */ + USB_ERROR_STR ( result, "usb_set_altinterface: could not build endpoint table"); + } + + return 0; +} + +/* simple function that figures out what pipeRef is associated with an endpoint */ +static int ep_to_pipeRef (struct darwin_dev_handle *device, int ep) +{ + int i; + + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: Converting ep address to pipeRef.\n"); + + for (i = 0 ; i < device->num_endpoints ; i++) + if (device->endpoint_addrs[i] == ep) + return i + 1; + + /* No pipe found with the correct endpoint address */ + if (usb_debug > 1) + fprintf(stderr, "libusb/darwin.c ep_to_pipeRef: No pipeRef found with endpoint address 0x%02x.\n", ep); + + return -1; +} + +static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, u_int32_t size, int timeout, int usb_bt_read) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + int pipeRef; + + u_int8_t transferType, direction, number, interval; + u_int16_t maxPacketSize; + + if (!dev) + USB_ERROR_STR ( -ENXIO, "libusb/darwin.c usb_bulk_transfer: Called with NULL device" ); + + if ((device = dev->impl_info) == NULL) + USB_ERROR_STR ( -ENOENT, "libusb/darwin.c usb_bulk_transfer: Device not open" ); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "libusb/darwin.c usb_bulk_transfer: Interface used before it was opened"); + + + /* Set up transfer */ + if ((pipeRef = ep_to_pipeRef(device, ep)) < 0) + USB_ERROR_STR ( -EINVAL, "libusb/darwin.c usb_bulk_transfer: Invalid pipe reference" ); + + (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, + &transferType, &maxPacketSize, &interval); + /* Transfer set up complete */ + + if (usb_debug > 0) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", size, ep); + + /* Do bulk transfer */ + if (transferType == kUSBInterrupt && usb_debug > 3) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); + +#if !defined(LIBUSB_NO_TIMEOUT_INTERFACE) + if ( transferType != kUSBInterrupt) { + if (usb_bt_read != 0) + result = (*(device->interface))->ReadPipeTO (device->interface, pipeRef, bytes, (UInt32 *)&size, timeout, timeout); + else + result = (*(device->interface))->WritePipeTO (device->interface, pipeRef, bytes, size, timeout, timeout); + + /* pipe bits may need to be cleared after a timeout. should this be done here or in user code? */ + if (result == kIOUSBTransactionTimeout && (*(device->interface))->GetPipeStatus (device->interface, pipeRef) == kIOUSBPipeStalled) + usb_clear_halt (dev, ep); + } else +#endif + { + if (usb_bt_read != 0) + result = (*(device->interface))->ReadPipe (device->interface, pipeRef, bytes, (UInt32 *)&size); + else + result = (*(device->interface))->WritePipe (device->interface, pipeRef, bytes, size); + } + + if (result != kIOReturnSuccess) + USB_ERROR_STR (-darwin_to_errno (result), "libusb/darwin.c usb_bulk_transfer: %s", darwin_error_str (result)); + + return size; +} + +#if 0 +/* NOT USED */ +/* argument to handle multiple parameters to rw_completed */ +struct rw_complete_arg { + UInt32 io_size; + IOReturn result; + CFRunLoopRef cf_loop; +}; + +static void rw_completed(void *refcon, io_return_t result, void *io_size) +{ + struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon; + + if (usb_debug > 2) + fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result), + (UInt32)io_size, result); + + rw_arg->io_size = (UInt32)io_size; + rw_arg->result = result; + + CFRunLoopStop(rw_arg->cf_loop); +} + +static int usb_bulk_transfer_async (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout, + rw_async_func_t rw_async, rw_async_to_func_t rw_async_to) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + CFRunLoopSourceRef cfSource; + int pipeRef; + + struct rw_complete_arg rw_arg; + + u_int8_t transferType; + + /* None of the values below are used in libusb for bulk transfers */ + u_int8_t direction, number, interval; + u_int16_t maxPacketSize; + + if (!dev) + USB_ERROR_STR ( -ENXIO, "usb_bulk_transfer: Called with NULL device" ); + + if ((device = dev->impl_info) == NULL) + USB_ERROR_STR ( -ENOENT, "usb_bulk_transfer: Device not open" ); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_bulk_transfer: Interface used before it was opened"); + + + /* Set up transfer */ + if ((pipeRef = ep_to_pipeRef(device, ep)) < 0) + USB_ERROR_STR ( -EINVAL, "usb_bulk_transfer: Invalid pipe reference" ); + + (*(device->interface))->GetPipeProperties (device->interface, pipeRef, &direction, &number, + &transferType, &maxPacketSize, &interval); + + bzero((void *)&rw_arg, sizeof(struct rw_complete_arg)); + rw_arg.cf_loop = CFRunLoopGetCurrent(); + CFRetain (rw_arg.cf_loop); + + (*(device->interface))->CreateInterfaceAsyncEventSource(device->interface, &cfSource); + CFRunLoopAddSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); + /* Transfer set up complete */ + + if (usb_debug > 0) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: Transfering %i bytes of data on endpoint 0x%02x\n", + size, ep); + + /* Bulk transfer */ + if (transferType == kUSBInterrupt && usb_debug > 3) + fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); + + if ( transferType != kUSBInterrupt && rw_async_to != NULL) + + result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout, + (IOAsyncCallback1)rw_completed, (void *)&rw_arg); + else + result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed, + (void *)&rw_arg); + + if (result == kIOReturnSuccess) { + /* wait for write to complete */ + if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) { + (*(device->interface))->AbortPipe(device->interface, pipeRef); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */ + if (usb_debug) + fprintf(stderr, "usb_bulk_transfer: timed out\n"); + } + } + + CFRunLoopRemoveSource(rw_arg.cf_loop, cfSource, kCFRunLoopDefaultMode); + CFRelease (rw_arg.cf_loop); + + /* Check the return code of both the write and completion functions. */ + if (result != kIOReturnSuccess || (rw_arg.result != kIOReturnSuccess && + rw_arg.result != kIOReturnAborted) ) { + int error_code; + char *error_str; + + if (result == kIOReturnSuccess) { + error_code = darwin_to_errno (rw_arg.result); + error_str = darwin_error_str (rw_arg.result); + } else { + error_code = darwin_to_errno(result); + error_str = darwin_error_str (result); + } + + if (transferType != kUSBInterrupt && rw_async_to != NULL) + USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str); + else + USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str); + } + + return rw_arg.io_size; +} +#endif + +int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) +{ + int result; + + if (dev == NULL || dev->impl_info == NULL) + return -EINVAL; + + if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 0)) < 0) + USB_ERROR_STR (result, "usb_bulk_write: An error occured during write (see messages above)"); + + return result; +} + +int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) +{ + int result; + + if (dev == NULL || dev->impl_info == NULL) + return -EINVAL; + + ep |= 0x80; + + if ((result = usb_bulk_transfer (dev, ep, bytes, size, timeout, 1)) < 0) + USB_ERROR_STR (result, "usb_bulk_read: An error occured during read (see messages above)"); + + return result; +} + +/* interrupt endpoints appear to be treated the same as non-interrupt endpoints under OSX/Darwin */ +int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + return usb_bulk_write (dev, ep, bytes, size, timeout); +} + +int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + return usb_bulk_read (dev, ep, bytes, size, timeout); +} + +int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, int timeout) +{ + struct darwin_dev_handle *device = dev->impl_info; + + io_return_t result; + +#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) + IOUSBDevRequestTO urequest; +#else + IOUSBDevRequest urequest; +#endif + + if (usb_debug >= 3) + fprintf(stderr, "libusb/darwin.c usb_control_msg (device: %s): %d %d %d %d %p %d %d\n", + dev->device->filename, requesttype, request, value, index, bytes, size, timeout); + + bzero(&urequest, sizeof(urequest)); + + urequest.bmRequestType = requesttype; + urequest.bRequest = request; + urequest.wValue = value; + urequest.wIndex = index; + urequest.wLength = size; + urequest.pData = bytes; +#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) + urequest.completionTimeout = timeout; + urequest.noDataTimeout = timeout; + + result = (*(device->device))->DeviceRequestTO(device->device, &urequest); +#else + result = (*(device->device))->DeviceRequest(device->device, &urequest); +#endif + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "libusb/darwin.c usb_control_msg(DeviceRequestTO): %s", darwin_error_str(result)); + + /* Bytes transfered is stored in the wLenDone field*/ + return urequest.wLenDone; +} + +int usb_os_find_busses(struct usb_bus **busses) +{ + struct usb_bus *fbus = NULL; + + io_iterator_t deviceIterator; + io_return_t result; + + usb_device_t **device; + + UInt32 location; + + char buf[20]; + int i = 1; + + /* Create a master port for communication with IOKit (this should + have been created if the user called usb_init() )*/ + if (masterPort == MACH_PORT_NULL) { + usb_init (); + + if (masterPort == MACH_PORT_NULL) + USB_ERROR(-ENOENT); + } + + if ((result = usb_setup_iterator (&deviceIterator)) < 0) + return result; + + while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { + struct usb_bus *bus; + + if (location & 0x00ffffff) + continue; + + bus = calloc(1, sizeof(struct usb_bus)); + if (bus == NULL) + USB_ERROR(-ENOMEM); + + sprintf(buf, "%03i", i++); + bus->location = location; + + strncpy(bus->dirname, buf, sizeof(bus->dirname) - 1); + bus->dirname[sizeof(bus->dirname) - 1] = 0; + + LIST_ADD(fbus, bus); + + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname); + + (*(device))->Release(device); + } + + IOObjectRelease(deviceIterator); + + *busses = fbus; + + return 0; +} + +int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) +{ + struct usb_device *fdev = NULL; + + io_iterator_t deviceIterator; + io_return_t result; + + usb_device_t **device; + + u_int16_t address; + UInt32 location; + UInt32 bus_loc = bus->location; + int devnum; + + /* for use in retrieving device description */ + IOUSBDevRequest req; + + /* a master port should have been created by usb_os_init */ + if (masterPort == MACH_PORT_NULL) + USB_ERROR(-ENOENT); + + if ((result = usb_setup_iterator (&deviceIterator)) < 0) + return result; + + /* Set up request for device descriptor */ + req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); + req.bRequest = kUSBRqGetDescriptor; + req.wValue = kUSBDeviceDesc << 8; + req.wIndex = 0; + req.wLength = sizeof(IOUSBDeviceDescriptor); + + devnum = 0; + + while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { + unsigned char device_desc[DEVICE_DESC_LENGTH]; + UInt8 bDeviceClass, bDeviceSubClass; + UInt16 idVendor, idProduct; + + result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address); + + if (result == kIOReturnSuccess) { + (*(device))->GetDeviceClass (device, &bDeviceClass); + (*(device))->GetDeviceSubClass (device, &bDeviceSubClass); + (*(device))->GetDeviceProduct (device, &idProduct); + (*(device))->GetDeviceVendor (device, &idVendor); + + if ((location >> 24) == (bus_loc >> 24)) { + struct usb_device *dev; + + if (usb_debug >= 2) + fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found USB device on bus 0x%08lx: 0x%08lx\n", + bus_loc, location); + + dev = calloc(1, sizeof(struct usb_device)); + if (dev == NULL) + USB_ERROR(-ENOMEM); + + dev->bus = bus; + + /* retrieve device descriptor */ + req.pData = device_desc; + result = (*(device))->DeviceRequest(device, &req); + + if (result != kIOReturnSuccess) { + free (dev); + + if (usb_debug) + fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device descriptor: %s. Skipping device.\n", + darwin_error_str(result)); + + /* release the device now */ + (*(device))->Release(device); + continue; /* can't continue without a descriptor */ + } + + usb_parse_descriptor(device_desc, "bbwbbbbwwwbbbb", &dev->descriptor); + + /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices */ + if (dev->descriptor.idProduct != idProduct) { + free (dev); + + if (usb_debug) + fprintf (stderr, "libusb/darwin.c usb_os_find_devices: idProduct from iokit does not match idProduct in descriptor. Skipping device\n"); + + /* release the device now */ + (*(device))->Release(device); + continue; /* can't continue without a descriptor */ + } + + dev->devnum = devnum++; + + sprintf(dev->filename, "%03i-%04x-%04x-%02x-%02x", address, idVendor, idProduct, bDeviceClass, bDeviceSubClass); + + dev->dev = (USBDeviceAddress *) calloc (1, 4); + if (dev->dev == NULL) + USB_ERROR(-ENOMEM); + + memcpy(dev->dev, &location, 4); + + LIST_ADD(fdev, dev); + + if (usb_debug >= 2) + fprintf(stderr, "libusb/darwin.c usb_os_find_devices: Found %s on %s at location 0x%08lx\n", + dev->filename, bus->dirname, location); + } + } else if (usb_debug) + fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Could not retrieve device address: %s\n", + darwin_error_str(result)); + + /* release the device now */ + (*(device))->Release(device); + } + + IOObjectRelease(deviceIterator); + + *devices = fdev; + + if (usb_debug) + fprintf (stderr, "libusb/darwin.c usb_os_find_devices: Complete\n"); + + return 0; +} + +int usb_os_determine_children(struct usb_bus *bus) +{ + /* Nothing yet */ + return 0; +} + +void usb_os_init(void) +{ + if (masterPort == MACH_PORT_NULL) { + IOMasterPort(masterPort, &masterPort); + + gNotifyPort = IONotificationPortCreate(masterPort); + } +} + +void usb_os_cleanup (void) +{ + if (masterPort != MACH_PORT_NULL) + darwin_cleanup (); +} + +int usb_resetep(usb_dev_handle *dev, unsigned int ep) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + int pipeRef; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_resetep: interface used without being claimed"); + + if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) + USB_ERROR(-EINVAL); + + result = (*(device->interface))->ResetPipe(device->interface, pipeRef); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_resetep(ResetPipe): %s", darwin_error_str(result)); + + return 0; +} + +int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) +{ + struct darwin_dev_handle *device; + + io_return_t result = -1; + + int pipeRef; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + /* interface is not open */ + if (!device->interface) + USB_ERROR_STR(-EACCES, "usb_clear_halt: interface used without being claimed"); + + if ((pipeRef = ep_to_pipeRef(device, ep)) == -1) + USB_ERROR(-EINVAL); + +#if (InterfaceVersion < 190) + result = (*(device->interface))->ClearPipeStall(device->interface, pipeRef); +#else + /* newer versions of darwin support clearing additional bits on the device's endpoint */ + result = (*(device->interface))->ClearPipeStallBothEnds(device->interface, pipeRef); +#endif + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_clear_halt(ClearPipeStall): %s", darwin_error_str(result)); + + return 0; +} + +int usb_reset(usb_dev_handle *dev) +{ + struct darwin_dev_handle *device; + + io_return_t result; + + if (!dev) + USB_ERROR(-ENXIO); + + if ((device = dev->impl_info) == NULL) + USB_ERROR(-ENOENT); + + if (!device->device) + USB_ERROR_STR(-ENOENT, "usb_reset: no such device"); + + result = (*(device->device))->ResetDevice(device->device); + + if (result != kIOReturnSuccess) + USB_ERROR_STR(-darwin_to_errno(result), "usb_reset(ResetDevice): %s", darwin_error_str(result)); + + return 0; +} diff --git a/deps/libusb/descriptors.c b/deps/libusb/descriptors.c new file mode 100644 index 0000000..f7fc784 --- /dev/null +++ b/deps/libusb/descriptors.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Parses descriptors + * + * Copyright (c) 2001 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include +#include +#include +#include "usbi.h" + +int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, + unsigned char type, unsigned char index, void *buf, int size) +{ + memset(buf, 0, size); + + return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (type << 8) + index, 0, buf, size, 1000); +} + +int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size) +{ + memset(buf, 0, size); + + return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (type << 8) + index, 0, buf, size, 1000); +} + +int usb_parse_descriptor(unsigned char *source, char *description, void *dest) +{ + unsigned char *sp = source, *dp = dest; + uint16_t w; + uint32_t d; + char *cp; + + for (cp = description; *cp; cp++) { + switch (*cp) { + case 'b': /* 8-bit byte */ + *dp++ = *sp++; + break; + case 'w': /* 16-bit word, convert from little endian to CPU */ + w = (sp[1] << 8) | sp[0]; sp += 2; + dp += ((unsigned long)dp & 1); /* Align to word boundary */ + *((uint16_t *)dp) = w; dp += 2; + break; + case 'd': /* 32-bit dword, convert from little endian to CPU */ + d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4; + dp += ((unsigned long)dp & 2); /* Align to dword boundary */ + *((uint32_t *)dp) = d; dp += 4; + break; + /* These two characters are undocumented and just a hack for Linux */ + case 'W': /* 16-bit word, keep CPU endianess */ + dp += ((unsigned long)dp & 1); /* Align to word boundary */ + memcpy(dp, sp, 2); sp += 2; dp += 2; + break; + case 'D': /* 32-bit dword, keep CPU endianess */ + dp += ((unsigned long)dp & 2); /* Align to dword boundary */ + memcpy(dp, sp, 4); sp += 4; dp += 4; + break; + } + } + + return sp - source; +} + +/* + * This code looks surprisingly similar to the code I wrote for the Linux + * kernel. It's not a coincidence :) + */ + +static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) +{ + struct usb_descriptor_header header; + unsigned char *begin; + int parsed = 0, len, numskipped; + + usb_parse_descriptor(buffer, "bb", &header); + + /* Everything should be fine being passed into here, but we sanity */ + /* check JIC */ + if (header.bLength > size) { + if (usb_debug >= 1) + fprintf(stderr, "ran out of descriptors parsing\n"); + return -1; + } + + if (header.bDescriptorType != USB_DT_ENDPOINT) { + if (usb_debug >= 2) + fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n", + header.bDescriptorType, USB_DT_ENDPOINT); + return parsed; + } + + if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) + usb_parse_descriptor(buffer, "bbbbwbbb", endpoint); + else if (header.bLength >= ENDPOINT_DESC_LENGTH) + usb_parse_descriptor(buffer, "bbbbwb", endpoint); + + buffer += header.bLength; + size -= header.bLength; + parsed += header.bLength; + + /* Skip over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + begin = buffer; + numskipped = 0; + while (size >= DESC_HEADER_LENGTH) { + usb_parse_descriptor(buffer, "bb", &header); + + if (header.bLength < 2) { + if (usb_debug >= 1) + fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header.bDescriptorType == USB_DT_ENDPOINT) || + (header.bDescriptorType == USB_DT_INTERFACE) || + (header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE)) + break; + + if (usb_debug >= 1) + fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); + numskipped++; + + buffer += header.bLength; + size -= header.bLength; + parsed += header.bLength; + } + + if (numskipped && usb_debug >= 2) + fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for drivers */ + /* to later parse */ + len = (int)(buffer - begin); + if (!len) { + endpoint->extra = NULL; + endpoint->extralen = 0; + return parsed; + } + + endpoint->extra = malloc(len); + if (!endpoint->extra) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n"); + endpoint->extralen = 0; + return parsed; + } + + memcpy(endpoint->extra, begin, len); + endpoint->extralen = len; + + return parsed; +} + +static int usb_parse_interface(struct usb_interface *interface, + unsigned char *buffer, int size) +{ + int i, len, numskipped, retval, parsed = 0; + struct usb_descriptor_header header; + struct usb_interface_descriptor *ifp; + unsigned char *begin; + + interface->num_altsetting = 0; + + while (size >= INTERFACE_DESC_LENGTH) { + interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1)); + if (!interface->altsetting) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't malloc interface->altsetting\n"); + return -1; + } + + ifp = interface->altsetting + interface->num_altsetting; + interface->num_altsetting++; + + usb_parse_descriptor(buffer, "bbbbbbbbb", ifp); + + /* Skip over the interface */ + buffer += ifp->bLength; + parsed += ifp->bLength; + size -= ifp->bLength; + + begin = buffer; + numskipped = 0; + + /* Skip over any interface, class or vendor descriptors */ + while (size >= DESC_HEADER_LENGTH) { + usb_parse_descriptor(buffer, "bb", &header); + + if (header.bLength < 2) { + if (usb_debug >= 1) + fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header.bDescriptorType == USB_DT_INTERFACE) || + (header.bDescriptorType == USB_DT_ENDPOINT) || + (header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE)) + break; + + numskipped++; + + buffer += header.bLength; + parsed += header.bLength; + size -= header.bLength; + } + + if (numskipped && usb_debug >= 2) + fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (!len) { + ifp->extra = NULL; + ifp->extralen = 0; + } else { + ifp->extra = malloc(len); + if (!ifp->extra) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n"); + ifp->extralen = 0; + return -1; + } + memcpy(ifp->extra, begin, len); + ifp->extralen = len; + } + + /* Did we hit an unexpected descriptor? */ + usb_parse_descriptor(buffer, "bb", &header); + if ((size >= DESC_HEADER_LENGTH) && + ((header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE))) + return parsed; + + if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { + if (usb_debug >= 1) + fprintf(stderr, "too many endpoints\n"); + return -1; + } + + if (ifp->bNumEndpoints > 0) { + ifp->endpoint = (struct usb_endpoint_descriptor *) + malloc(ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); + if (!ifp->endpoint) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n"); + return -1; + } + + memset(ifp->endpoint, 0, ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); + + for (i = 0; i < ifp->bNumEndpoints; i++) { + usb_parse_descriptor(buffer, "bb", &header); + + if (header.bLength > size) { + if (usb_debug >= 1) + fprintf(stderr, "ran out of descriptors parsing\n"); + return -1; + } + + retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } + } else + ifp->endpoint = NULL; + + /* We check to see if it's an alternate to this one */ + ifp = (struct usb_interface_descriptor *)buffer; + if (size < USB_DT_INTERFACE_SIZE || + ifp->bDescriptorType != USB_DT_INTERFACE || + !ifp->bAlternateSetting) + return parsed; + } + + return parsed; +} + +int usb_parse_configuration(struct usb_config_descriptor *config, + unsigned char *buffer) +{ + int i, retval, size; + struct usb_descriptor_header header; + + usb_parse_descriptor(buffer, "bbwbbbbb", config); + size = config->wTotalLength; + + if (config->bNumInterfaces > USB_MAXINTERFACES) { + if (usb_debug >= 1) + fprintf(stderr, "too many interfaces\n"); + return -1; + } + + config->interface = (struct usb_interface *) + malloc(config->bNumInterfaces * + sizeof(struct usb_interface)); + if (!config->interface) { + if (usb_debug >= 1) + fprintf(stderr, "out of memory\n"); + return -1; + } + + memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface)); + + buffer += config->bLength; + size -= config->bLength; + + config->extra = NULL; + config->extralen = 0; + + for (i = 0; i < config->bNumInterfaces; i++) { + int numskipped, len; + unsigned char *begin; + + /* Skip over the rest of the Class Specific or Vendor */ + /* Specific descriptors */ + begin = buffer; + numskipped = 0; + while (size >= DESC_HEADER_LENGTH) { + usb_parse_descriptor(buffer, "bb", &header); + + if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { + if (usb_debug >= 1) + fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); + return -1; + } + + /* If we find another "proper" descriptor then we're done */ + if ((header.bDescriptorType == USB_DT_ENDPOINT) || + (header.bDescriptorType == USB_DT_INTERFACE) || + (header.bDescriptorType == USB_DT_CONFIG) || + (header.bDescriptorType == USB_DT_DEVICE)) + break; + + if (usb_debug >= 2) + fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); + numskipped++; + + buffer += header.bLength; + size -= header.bLength; + } + + if (numskipped && usb_debug >= 2) + fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); + + /* Copy any unknown descriptors into a storage area for */ + /* drivers to later parse */ + len = (int)(buffer - begin); + if (len) { + /* FIXME: We should realloc and append here */ + if (!config->extralen) { + config->extra = malloc(len); + if (!config->extra) { + if (usb_debug >= 1) + fprintf(stderr, "couldn't allocate memory for config extra descriptors\n"); + config->extralen = 0; + return -1; + } + + memcpy(config->extra, begin, len); + config->extralen = len; + } + } + + retval = usb_parse_interface(config->interface + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + size -= retval; + } + + return size; +} + +void usb_destroy_configuration(struct usb_device *dev) +{ + int c, i, j, k; + + if (!dev->config) + return; + + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + struct usb_config_descriptor *cf = &dev->config[c]; + + if (!cf->interface) + continue; + + for (i = 0; i < cf->bNumInterfaces; i++) { + struct usb_interface *ifp = &cf->interface[i]; + + if (!ifp->altsetting) + continue; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = &ifp->altsetting[j]; + + if (as->extra) + free(as->extra); + + if (!as->endpoint) + continue; + + for (k = 0; k < as->bNumEndpoints; k++) { + if (as->endpoint[k].extra) + free(as->endpoint[k].extra); + } + free(as->endpoint); + } + + free(ifp->altsetting); + } + + free(cf->interface); + } + + free(dev->config); +} + +void usb_fetch_and_parse_descriptors(usb_dev_handle *udev) +{ + struct usb_device *dev = udev->device; + int i; + + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { + if (usb_debug >= 1) + fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG); + return; + } + + if (dev->descriptor.bNumConfigurations < 1) { + if (usb_debug >= 1) + fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1); + return; + } + + dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); + if (!dev->config) { + if (usb_debug >= 1) + fprintf(stderr, "Unable to allocate memory for config descriptor\n"); + return; + } + + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor)); + + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + unsigned char buffer[8], *bigbuffer; + struct usb_config_descriptor config; + int res; + + /* Get the first 8 bytes so we can figure out what the total length is */ + res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8); + if (res < 8) { + if (usb_debug >= 1) { + if (res < 0) + fprintf(stderr, "Unable to get descriptor (%d)\n", res); + else + fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res); + } + + goto err; + } + + usb_parse_descriptor(buffer, "bbw", &config); + + bigbuffer = malloc(config.wTotalLength); + if (!bigbuffer) { + if (usb_debug >= 1) + fprintf(stderr, "Unable to allocate memory for descriptors\n"); + goto err; + } + + res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength); + if (res < config.wTotalLength) { + if (usb_debug >= 1) { + if (res < 0) + fprintf(stderr, "Unable to get descriptor (%d)\n", res); + else + fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res); + } + + free(bigbuffer); + goto err; + } + + res = usb_parse_configuration(&dev->config[i], bigbuffer); + if (usb_debug >= 2) { + if (res > 0) + fprintf(stderr, "Descriptor data still left\n"); + else if (res < 0) + fprintf(stderr, "Unable to parse descriptors\n"); + } + + free(bigbuffer); + } + + return; + +err: + free(dev->config); + + dev->config = NULL; +} + diff --git a/deps/libusb/error.c b/deps/libusb/error.c new file mode 100644 index 0000000..9212e86 --- /dev/null +++ b/deps/libusb/error.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * USB Error messages + * + * Copyright (c) 2000-2001 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include +#include + +#include "usb.h" +#include "error.h" + +char usb_error_str[1024] = ""; +int usb_error_errno = 0; +usb_error_type_t usb_error_type = USB_ERROR_TYPE_NONE; + +char *usb_strerror(void) +{ + switch (usb_error_type) { + case USB_ERROR_TYPE_NONE: + return "No error"; + case USB_ERROR_TYPE_STRING: + return usb_error_str; + case USB_ERROR_TYPE_ERRNO: + if (usb_error_errno > -USB_ERROR_BEGIN) + return strerror(usb_error_errno); + else + /* Any error we don't know falls under here */ + return "Unknown error"; + } + + return "Unknown error"; +} + diff --git a/deps/libusb/error.h b/deps/libusb/error.h new file mode 100644 index 0000000..c980e22 --- /dev/null +++ b/deps/libusb/error.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _ERROR_H_ +#define _ERROR_H_ + +typedef enum { + USB_ERROR_TYPE_NONE = 0, + USB_ERROR_TYPE_STRING, + USB_ERROR_TYPE_ERRNO, +} usb_error_type_t; + +extern char usb_error_str[1024]; +extern int usb_error_errno; +extern usb_error_type_t usb_error_type; + +#define USB_ERROR(x) \ + do { \ + usb_error_type = USB_ERROR_TYPE_ERRNO; \ + usb_error_errno = x; \ + return x; \ + } while (0) + +#define USB_ERROR_STR(x, format, args...) \ + do { \ + usb_error_type = USB_ERROR_TYPE_STRING; \ + snprintf(usb_error_str, sizeof(usb_error_str) - 1, format, ## args); \ + if (usb_debug >= 2) \ + fprintf(stderr, "USB error: %s\n", usb_error_str); \ + return x; \ + } while (0) + +#endif /* _ERROR_H_ */ + diff --git a/deps/libusb/linux.c b/deps/libusb/linux.c new file mode 100644 index 0000000..6b13afb --- /dev/null +++ b/deps/libusb/linux.c @@ -0,0 +1,748 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Linux USB support + * + * Copyright (c) 2000-2003 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include /* getenv, etc */ +#include +#include +#include +#include +#include +#include +#include + +#include "linux.h" +#include "usbi.h" + +static char usb_path[PATH_MAX + 1] = ""; + +static int device_open(struct usb_device *dev) +{ + char filename[PATH_MAX + 1]; + int fd; + + snprintf(filename, sizeof(filename) - 1, "%s/%s/%s", + usb_path, dev->bus->dirname, dev->filename); + + fd = open(filename, O_RDWR); + if (fd < 0) { + fd = open(filename, O_RDONLY); + if (fd < 0) + USB_ERROR_STR(-errno, "failed to open %s: %s", + filename, strerror(errno)); + } + + return fd; +} + +int usb_os_open(usb_dev_handle *dev) +{ + dev->fd = device_open(dev->device); + + return 0; +} + +int usb_os_close(usb_dev_handle *dev) +{ + if (dev->fd < 0) + return 0; + + if (close(dev->fd) == -1) + /* Failing trying to close a file really isn't an error, so return 0 */ + USB_ERROR_STR(0, "tried to close device fd %d: %s", dev->fd, + strerror(errno)); + + return 0; +} + +int usb_set_configuration(usb_dev_handle *dev, int configuration) +{ + int ret; + + ret = ioctl(dev->fd, IOCTL_USB_SETCONFIG, &configuration); + if (ret < 0) + USB_ERROR_STR(-errno, "could not set config %d: %s", configuration, + strerror(errno)); + + dev->config = configuration; + + return 0; +} + +int usb_claim_interface(usb_dev_handle *dev, int interface) +{ + int ret; + + ret = ioctl(dev->fd, IOCTL_USB_CLAIMINTF, &interface); + if (ret < 0) { + if (errno == EBUSY && usb_debug > 0) + fprintf(stderr, "Check that you have permissions to write to %s/%s and, if you don't, that you set up hotplug (http://linux-hotplug.sourceforge.net/) correctly.\n", dev->bus->dirname, dev->device->filename); + + USB_ERROR_STR(-errno, "could not claim interface %d: %s", interface, + strerror(errno)); + } + + dev->interface = interface; + + return 0; +} + +int usb_release_interface(usb_dev_handle *dev, int interface) +{ + int ret; + + ret = ioctl(dev->fd, IOCTL_USB_RELEASEINTF, &interface); + if (ret < 0) + USB_ERROR_STR(-errno, "could not release intf %d: %s", interface, + strerror(errno)); + + dev->interface = -1; + + return 0; +} + +int usb_set_altinterface(usb_dev_handle *dev, int alternate) +{ + int ret; + struct usb_setinterface setintf; + + if (dev->interface < 0) + USB_ERROR(-EINVAL); + + setintf.interface = dev->interface; + setintf.altsetting = alternate; + + ret = ioctl(dev->fd, IOCTL_USB_SETINTF, &setintf); + if (ret < 0) + USB_ERROR_STR(-errno, "could not set alt intf %d/%d: %s", + dev->interface, alternate, strerror(errno)); + + dev->altsetting = alternate; + + return 0; +} + +/* + * Linux usbfs has a limit of one page size for synchronous bulk read/write. + * 4096 is the most portable maximum we can do for now. + * Linux usbfs has a limit of 16KB for the URB interface. We use this now + * to get better performance for USB 2.0 devices. + */ +#define MAX_READ_WRITE (16 * 1024) + +int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, int timeout) +{ + struct usb_ctrltransfer ctrl; + int ret; + + ctrl.bRequestType = requesttype; + ctrl.bRequest = request; + ctrl.wValue = value; + ctrl.wIndex = index; + ctrl.wLength = size; + + ctrl.data = bytes; + ctrl.timeout = timeout; + + ret = ioctl(dev->fd, IOCTL_USB_CONTROL, &ctrl); + if (ret < 0) + USB_ERROR_STR(-errno, "error sending control message: %s", strerror(errno)); + + return ret; +} + +#define URB_USERCONTEXT_COOKIE ((void *)0x1) + +/* Reading and writing are the same except for the endpoint */ +static int usb_urb_transfer(usb_dev_handle *dev, int ep, int urbtype, + char *bytes, int size, int timeout) +{ + struct usb_urb urb; + int bytesdone = 0, requested; + struct timeval tv, tv_ref, tv_now; + struct usb_urb *context; + int ret, waiting; + + /* + * HACK: The use of urb.usercontext is a hack to get threaded applications + * sort of working again. Threaded support is still not recommended, but + * this should allow applications to work in the common cases. Basically, + * if we get the completion for an URB we're not waiting for, then we update + * the usercontext pointer to 1 for the other threads URB and it will see + * the change after it wakes up from the the timeout. Ugly, but it works. + */ + + /* + * Get actual time, and add the timeout value. The result is the absolute + * time where we have to quit waiting for an message. + */ + gettimeofday(&tv_ref, NULL); + tv_ref.tv_sec = tv_ref.tv_sec + timeout / 1000; + tv_ref.tv_usec = tv_ref.tv_usec + (timeout % 1000) * 1000; + + if (tv_ref.tv_usec > 1000000) { + tv_ref.tv_usec -= 1000000; + tv_ref.tv_sec++; + } + + do { + fd_set writefds; + + requested = size - bytesdone; + if (requested > MAX_READ_WRITE) + requested = MAX_READ_WRITE; + + urb.type = urbtype; + urb.endpoint = ep; + urb.flags = 0; + urb.buffer = bytes + bytesdone; + urb.buffer_length = requested; + urb.signr = 0; + urb.actual_length = 0; + urb.number_of_packets = 0; /* don't do isochronous yet */ + urb.usercontext = NULL; + + ret = ioctl(dev->fd, IOCTL_USB_SUBMITURB, &urb); + if (ret < 0) { + USB_ERROR_STR(-errno, "error submitting URB: %s", strerror(errno)); + return ret; + } + + FD_ZERO(&writefds); + FD_SET(dev->fd, &writefds); + +restart: + waiting = 1; + context = NULL; + while (!urb.usercontext && ((ret = ioctl(dev->fd, IOCTL_USB_REAPURBNDELAY, &context)) == -1) && waiting) { + tv.tv_sec = 0; + tv.tv_usec = 1000; // 1 msec + select(dev->fd + 1, NULL, &writefds, NULL, &tv); //sub second wait + + if (timeout) { + /* compare with actual time, as the select timeout is not that precise */ + gettimeofday(&tv_now, NULL); + + if ((tv_now.tv_sec > tv_ref.tv_sec) || + ((tv_now.tv_sec == tv_ref.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec))) + waiting = 0; + } + } + + if (context && context != &urb) { + context->usercontext = URB_USERCONTEXT_COOKIE; + /* We need to restart since we got a successful URB, but not ours */ + goto restart; + } + + /* + * If there was an error, that wasn't EAGAIN (no completion), then + * something happened during the reaping and we should return that + * error now + */ + if (ret < 0 && !urb.usercontext && errno != EAGAIN) + USB_ERROR_STR(-errno, "error reaping URB: %s", strerror(errno)); + + bytesdone += urb.actual_length; + } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested); + + /* If the URB didn't complete in success or error, then let's unlink it */ + if (ret < 0 && !urb.usercontext) { + int rc; + + if (!waiting) + rc = -ETIMEDOUT; + else + rc = urb.status; + + ret = ioctl(dev->fd, IOCTL_USB_DISCARDURB, &urb); + if (ret < 0 && errno != EINVAL && usb_debug >= 1) + fprintf(stderr, "error discarding URB: %s", strerror(errno)); + + /* + * When the URB is unlinked, it gets moved to the completed list and + * then we need to reap it or else the next time we call this function, + * we'll get the previous completion and exit early + */ + ioctl(dev->fd, IOCTL_USB_REAPURB, &context); + + return rc; + } + + return bytesdone; +} + +int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + /* Ensure the endpoint address is correct */ + return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size, + timeout); +} + +int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + /* Ensure the endpoint address is correct */ + ep |= USB_ENDPOINT_IN; + return usb_urb_transfer(dev, ep, USB_URB_TYPE_BULK, bytes, size, + timeout); +} + +/* + * FIXME: Packetize large buffers here. 2.4 HCDs (atleast, haven't checked + * 2.5 HCDs yet) don't handle multi-packet Interrupt transfers. So we need + * to lookup the endpoint packet size and packetize appropriately here. + */ +int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + /* Ensure the endpoint address is correct */ + return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size, + timeout); +} + +int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + /* Ensure the endpoint address is correct */ + ep |= USB_ENDPOINT_IN; + return usb_urb_transfer(dev, ep, USB_URB_TYPE_INTERRUPT, bytes, size, + timeout); +} + +int usb_os_find_busses(struct usb_bus **busses) +{ + struct usb_bus *fbus = NULL; + DIR *dir; + struct dirent *entry; + + dir = opendir(usb_path); + if (!dir) + USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", usb_path, + strerror(errno)); + + while ((entry = readdir(dir)) != NULL) { + struct usb_bus *bus; + + /* Skip anything starting with a . */ + if (entry->d_name[0] == '.') + continue; + + if (!strchr("0123456789", entry->d_name[strlen(entry->d_name) - 1])) { + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_busses: Skipping non bus directory %s\n", + entry->d_name); + continue; + } + + bus = malloc(sizeof(*bus)); + if (!bus) + USB_ERROR(-ENOMEM); + + memset((void *)bus, 0, sizeof(*bus)); + + strncpy(bus->dirname, entry->d_name, sizeof(bus->dirname) - 1); + bus->dirname[sizeof(bus->dirname) - 1] = 0; + + LIST_ADD(fbus, bus); + + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_busses: Found %s\n", bus->dirname); + } + + closedir(dir); + + *busses = fbus; + + return 0; +} + +int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices) +{ + struct usb_device *fdev = NULL; + DIR *dir; + struct dirent *entry; + char dirpath[PATH_MAX + 1]; + + snprintf(dirpath, PATH_MAX, "%s/%s", usb_path, bus->dirname); + + dir = opendir(dirpath); + if (!dir) + USB_ERROR_STR(-errno, "couldn't opendir(%s): %s", dirpath, + strerror(errno)); + + while ((entry = readdir(dir)) != NULL) { + unsigned char device_desc[DEVICE_DESC_LENGTH]; + char filename[PATH_MAX + 1]; + struct usb_device *dev; + struct usb_connectinfo connectinfo; + int i, fd, ret; + + /* Skip anything starting with a . */ + if (entry->d_name[0] == '.') + continue; + + dev = malloc(sizeof(*dev)); + if (!dev) + USB_ERROR(-ENOMEM); + + memset((void *)dev, 0, sizeof(*dev)); + + dev->bus = bus; + + strncpy(dev->filename, entry->d_name, sizeof(dev->filename) - 1); + dev->filename[sizeof(dev->filename) - 1] = 0; + + snprintf(filename, sizeof(filename) - 1, "%s/%s", dirpath, entry->d_name); + fd = open(filename, O_RDWR); + if (fd < 0) { + fd = open(filename, O_RDONLY); + if (fd < 0) { + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_devices: Couldn't open %s\n", + filename); + + free(dev); + continue; + } + } + + /* Get the device number */ + ret = ioctl(fd, IOCTL_USB_CONNECTINFO, &connectinfo); + if (ret < 0) { + if (usb_debug) + fprintf(stderr, "usb_os_find_devices: couldn't get connect info\n"); + } else + dev->devnum = connectinfo.devnum; + + ret = read(fd, (void *)device_desc, DEVICE_DESC_LENGTH); + if (ret < 0) { + if (usb_debug) + fprintf(stderr, "usb_os_find_devices: Couldn't read descriptor\n"); + + free(dev); + + goto err; + } + + /* + * Linux kernel converts the words in this descriptor to CPU endian, so + * we use the undocumented W character for usb_parse_descriptor() that + * doesn't convert endianess when parsing the descriptor + */ + usb_parse_descriptor(device_desc, "bbWbbbbWWWbbbb", &dev->descriptor); + + LIST_ADD(fdev, dev); + + if (usb_debug >= 2) + fprintf(stderr, "usb_os_find_devices: Found %s on %s\n", + dev->filename, bus->dirname); + + /* Now try to fetch the rest of the descriptors */ + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) + /* Silent since we'll try again later */ + goto err; + + if (dev->descriptor.bNumConfigurations < 1) + /* Silent since we'll try again later */ + goto err; + + dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); + if (!dev->config) + /* Silent since we'll try again later */ + goto err; + + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor)); + + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + unsigned char buffer[8], *bigbuffer; + struct usb_config_descriptor config; + + /* Get the first 8 bytes so we can figure out what the total length is */ + ret = read(fd, (void *)buffer, 8); + if (ret < 8) { + if (usb_debug >= 1) { + if (ret < 0) + fprintf(stderr, "Unable to get descriptor (%d)\n", ret); + else + fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, ret); + } + + goto err; + } + + usb_parse_descriptor(buffer, "bbw", &config); + + bigbuffer = malloc(config.wTotalLength); + if (!bigbuffer) { + if (usb_debug >= 1) + fprintf(stderr, "Unable to allocate memory for descriptors\n"); + goto err; + } + + /* Read the rest of the config descriptor */ + memcpy(bigbuffer, buffer, 8); + + ret = read(fd, (void *)(bigbuffer + 8), config.wTotalLength - 8); + if (ret < config.wTotalLength - 8) { + if (usb_debug >= 1) { + if (ret < 0) + fprintf(stderr, "Unable to get descriptor (%d)\n", ret); + else + fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, ret); + } + + free(bigbuffer); + goto err; + } + + ret = usb_parse_configuration(&dev->config[i], bigbuffer); + if (usb_debug >= 2) { + if (ret > 0) + fprintf(stderr, "Descriptor data still left\n"); + else if (ret < 0) + fprintf(stderr, "Unable to parse descriptors\n"); + } + + free(bigbuffer); + } + +err: + close(fd); + } + + closedir(dir); + + *devices = fdev; + + return 0; +} + +int usb_os_determine_children(struct usb_bus *bus) +{ + struct usb_device *dev, *devices[256]; + struct usb_ioctl command; + int ret, i, i1; + + /* Create a list of devices first */ + memset(devices, 0, sizeof(devices)); + for (dev = bus->devices; dev; dev = dev->next) + if (dev->devnum) + devices[dev->devnum] = dev; + + /* Now fetch the children for each device */ + for (dev = bus->devices; dev; dev = dev->next) { + struct usb_hub_portinfo portinfo; + int fd; + + fd = device_open(dev); + if (fd < 0) + continue; + + /* Query the hub driver for the children of this device */ + if (dev->config && dev->config->interface && dev->config->interface->altsetting) + command.ifno = dev->config->interface->altsetting->bInterfaceNumber; + else + command.ifno = 0; + command.ioctl_code = IOCTL_USB_HUB_PORTINFO; + command.data = &portinfo; + ret = ioctl(fd, IOCTL_USB_IOCTL, &command); + if (ret < 0) { + /* errno == ENOSYS means the device probably wasn't a hub */ + if (errno != ENOSYS && usb_debug > 1) + fprintf(stderr, "error obtaining child information: %s\n", + strerror(errno)); + + close(fd); + continue; + } + + dev->num_children = 0; + for (i = 0; i < portinfo.numports; i++) + if (portinfo.port[i]) + dev->num_children++; + + /* Free any old children first */ + free(dev->children); + + dev->children = malloc(sizeof(struct usb_device *) * dev->num_children); + if (!dev->children) { + if (usb_debug > 1) + fprintf(stderr, "error allocating %zu bytes memory for dev->children\n", + sizeof(struct usb_device *) * dev->num_children); + + dev->num_children = 0; + close(fd); + continue; + } + + for (i = 0, i1 = 0; i < portinfo.numports; i++) { + if (!portinfo.port[i]) + continue; + + dev->children[i1++] = devices[portinfo.port[i]]; + + devices[portinfo.port[i]] = NULL; + } + + close(fd); + } + + /* + * There should be one device left in the devices list and that should be + * the root device + */ + for (i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) { + if (devices[i]) + bus->root_dev = devices[i]; + } + + return 0; +} + +static int check_usb_vfs(const char *dirname) +{ + DIR *dir; + struct dirent *entry; + int found = 0; + + dir = opendir(dirname); + if (!dir) + return 0; + + while ((entry = readdir(dir)) != NULL) { + /* Skip anything starting with a . */ + if (entry->d_name[0] == '.') + continue; + + /* We assume if we find any files that it must be the right place */ + found = 1; + break; + } + + closedir(dir); + + return found; +} + +void usb_os_init(void) +{ + /* Find the path to the virtual filesystem */ + if (getenv("USB_DEVFS_PATH")) { + if (check_usb_vfs(getenv("USB_DEVFS_PATH"))) { + strncpy(usb_path, getenv("USB_DEVFS_PATH"), sizeof(usb_path) - 1); + usb_path[sizeof(usb_path) - 1] = 0; + } else if (usb_debug) + fprintf(stderr, "usb_os_init: couldn't find USB VFS in USB_DEVFS_PATH\n"); + } + + if (!usb_path[0]) { + if (check_usb_vfs("/dev/bus/usb")) { + strncpy(usb_path, "/dev/bus/usb", sizeof(usb_path) - 1); + usb_path[sizeof(usb_path) - 1] = 0; + } else if (check_usb_vfs("/proc/bus/usb")) { + strncpy(usb_path, "/proc/bus/usb", sizeof(usb_path) - 1); + usb_path[sizeof(usb_path) - 1] = 0; + } else + usb_path[0] = 0; /* No path, no USB support */ + } + + if (usb_debug) { + if (usb_path[0]) + fprintf(stderr, "usb_os_init: Found USB VFS at %s\n", usb_path); + else + fprintf(stderr, "usb_os_init: No USB VFS found, is it mounted?\n"); + } +} + +int usb_resetep(usb_dev_handle *dev, unsigned int ep) +{ + int ret; + + ret = ioctl(dev->fd, IOCTL_USB_RESETEP, &ep); + if (ret) + USB_ERROR_STR(-errno, "could not reset ep %d: %s", ep, + strerror(errno)); + + return 0; +} + +int usb_clear_halt(usb_dev_handle *dev, unsigned int ep) +{ + int ret; + + ret = ioctl(dev->fd, IOCTL_USB_CLEAR_HALT, &ep); + if (ret) + USB_ERROR_STR(-errno, "could not clear/halt ep %d: %s", ep, + strerror(errno)); + + return 0; +} + +int usb_reset(usb_dev_handle *dev) +{ + int ret; + + ret = ioctl(dev->fd, IOCTL_USB_RESET, NULL); + if (ret) + USB_ERROR_STR(-errno, "could not reset: %s", strerror(errno)); + + return 0; +} + +int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, + unsigned int namelen) +{ + struct usb_getdriver getdrv; + int ret; + + getdrv.interface = interface; + ret = ioctl(dev->fd, IOCTL_USB_GETDRIVER, &getdrv); + if (ret) + USB_ERROR_STR(-errno, "could not get bound driver: %s", strerror(errno)); + + strncpy(name, getdrv.driver, namelen - 1); + name[namelen - 1] = 0; + + return 0; +} + +int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface) +{ + struct usb_ioctl command; + int ret; + + command.ifno = interface; + command.ioctl_code = IOCTL_USB_DISCONNECT; + command.data = NULL; + + ret = ioctl(dev->fd, IOCTL_USB_IOCTL, &command); + if (ret) + USB_ERROR_STR(-errno, "could not detach kernel driver from interface %d: %s", + interface, strerror(errno)); + + return 0; +} + diff --git a/deps/libusb/linux.h b/deps/libusb/linux.h new file mode 100644 index 0000000..e544c09 --- /dev/null +++ b/deps/libusb/linux.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __LINUX_H__ +#define __LINUX_H__ + +#include +#include +#include + +struct usb_ctrltransfer { + /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ + u_int8_t bRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; + + u_int32_t timeout; /* in milliseconds */ + + /* pointer to data */ + void *data; +}; + +struct usb_bulktransfer { + /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ + unsigned int ep; + unsigned int len; + unsigned int timeout; /* in milliseconds */ + + /* pointer to data */ + void *data; +}; + +struct usb_setinterface { + /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */ + unsigned int interface; + unsigned int altsetting; +}; + +#define USB_MAXDRIVERNAME 255 + +struct usb_getdriver { + unsigned int interface; + char driver[USB_MAXDRIVERNAME + 1]; +}; + +#define USB_URB_DISABLE_SPD 1 +#define USB_URB_ISO_ASAP 2 +#define USB_URB_QUEUE_BULK 0x10 + +#define USB_URB_TYPE_ISO 0 +#define USB_URB_TYPE_INTERRUPT 1 +#define USB_URB_TYPE_CONTROL 2 +#define USB_URB_TYPE_BULK 3 + +struct usb_iso_packet_desc { + unsigned int length; + unsigned int actual_length; + unsigned int status; +}; + +struct usb_urb { + unsigned char type; + unsigned char endpoint; + int status; + unsigned int flags; + void *buffer; + int buffer_length; + int actual_length; + int start_frame; + int number_of_packets; + int error_count; + unsigned int signr; /* signal to be sent on error, -1 if none should be sent */ + void *usercontext; + struct usb_iso_packet_desc iso_frame_desc[0]; +}; + +struct usb_connectinfo { + unsigned int devnum; + unsigned char slow; +}; + +struct usb_ioctl { + int ifno; /* interface 0..N ; negative numbers reserved */ + int ioctl_code; /* MUST encode size + direction of data so the + * macros in give correct values */ + void *data; /* param buffer (in, or out) */ +}; + +struct usb_hub_portinfo { + unsigned char numports; + unsigned char port[127]; /* port to device num mapping */ +}; + +#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer) +#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer) +#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int) +#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface) +#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int) +#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver) +#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb) +#define IOCTL_USB_DISCARDURB _IO('U', 11) +#define IOCTL_USB_REAPURB _IOW('U', 12, void *) +#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *) +#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int) +#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int) +#define IOCTL_USB_CONNECTINFO _IOW('U', 17, struct usb_connectinfo) +#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl) +#define IOCTL_USB_HUB_PORTINFO _IOR('U', 19, struct usb_hub_portinfo) +#define IOCTL_USB_RESET _IO('U', 20) +#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int) +#define IOCTL_USB_DISCONNECT _IO('U', 22) +#define IOCTL_USB_CONNECT _IO('U', 23) + +/* + * IOCTL_USB_HUB_PORTINFO, IOCTL_USB_DISCONNECT and IOCTL_USB_CONNECT + * all work via IOCTL_USB_IOCTL + */ + +#endif + diff --git a/deps/libusb/usb.c b/deps/libusb/usb.c new file mode 100644 index 0000000..ea4b375 --- /dev/null +++ b/deps/libusb/usb.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Main API entry point + * + * Copyright (c) 2000-2003 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + */ + +#include /* getenv */ +#include /* stderr */ +#include /* strcmp */ +#include + +#include "usbi.h" + +int usb_debug = 0; +struct usb_bus *usb_busses = NULL; + +int usb_find_busses(void) +{ + struct usb_bus *busses, *bus; + int ret, changes = 0; + + ret = usb_os_find_busses(&busses); + if (ret < 0) + return ret; + + /* + * Now walk through all of the busses we know about and compare against + * this new list. Any duplicates will be removed from the new list. + * If we don't find it in the new list, the bus was removed. Any + * busses still in the new list, are new to us. + */ + bus = usb_busses; + while (bus) { + int found = 0; + struct usb_bus *nbus, *tbus = bus->next; + + nbus = busses; + while (nbus) { + struct usb_bus *tnbus = nbus->next; + + if (!strcmp(bus->dirname, nbus->dirname)) { + /* Remove it from the new busses list */ + LIST_DEL(busses, nbus); + + usb_free_bus(nbus); + found = 1; + break; + } + + nbus = tnbus; + } + + if (!found) { + /* The bus was removed from the system */ + LIST_DEL(usb_busses, bus); + usb_free_bus(bus); + changes++; + } + + bus = tbus; + } + + /* + * Anything on the *busses list is new. So add them to usb_busses and + * process them like the new bus it is. + */ + bus = busses; + while (bus) { + struct usb_bus *tbus = bus->next; + + /* + * Remove it from the temporary list first and add it to the real + * usb_busses list. + */ + LIST_DEL(busses, bus); + + LIST_ADD(usb_busses, bus); + + changes++; + + bus = tbus; + } + + return changes; +} + +int usb_find_devices(void) +{ + struct usb_bus *bus; + int ret, changes = 0; + + for (bus = usb_busses; bus; bus = bus->next) { + struct usb_device *devices, *dev; + + /* Find all of the devices and put them into a temporary list */ + ret = usb_os_find_devices(bus, &devices); + if (ret < 0) + return ret; + + /* + * Now walk through all of the devices we know about and compare + * against this new list. Any duplicates will be removed from the new + * list. If we don't find it in the new list, the device was removed. + * Any devices still in the new list, are new to us. + */ + dev = bus->devices; + while (dev) { + int found = 0; + struct usb_device *ndev, *tdev = dev->next; + + ndev = devices; + while (ndev) { + struct usb_device *tndev = ndev->next; + + if (!strcmp(dev->filename, ndev->filename)) { + /* Remove it from the new devices list */ + LIST_DEL(devices, ndev); + + usb_free_dev(ndev); + found = 1; + break; + } + + ndev = tndev; + } + + if (!found) { + /* The device was removed from the system */ + LIST_DEL(bus->devices, dev); + usb_free_dev(dev); + changes++; + } + + dev = tdev; + } + + /* + * Anything on the *devices list is new. So add them to bus->devices and + * process them like the new device it is. + */ + dev = devices; + while (dev) { + struct usb_device *tdev = dev->next; + + /* + * Remove it from the temporary list first and add it to the real + * bus->devices list. + */ + LIST_DEL(devices, dev); + + LIST_ADD(bus->devices, dev); + + /* + * Some ports fetch the descriptors on scanning (like Linux) so we don't + * need to fetch them again. + */ + if (!dev->config) { + usb_dev_handle *udev; + + udev = usb_open(dev); + if (udev) { + usb_fetch_and_parse_descriptors(udev); + + usb_close(udev); + } + } + + changes++; + + dev = tdev; + } + + usb_os_determine_children(bus); + } + + return changes; +} + +void usb_set_debug(int level) +{ + if (usb_debug || level) + fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n", + level, level ? "on" : "off"); + + usb_debug = level; +} + +void usb_init(void) +{ + if (getenv("USB_DEBUG")) + usb_set_debug(atoi(getenv("USB_DEBUG"))); + + usb_os_init(); +} + +usb_dev_handle *usb_open(struct usb_device *dev) +{ + usb_dev_handle *udev; + + udev = malloc(sizeof(*udev)); + if (!udev) + return NULL; + + udev->fd = -1; + udev->device = dev; + udev->bus = dev->bus; + udev->config = udev->interface = udev->altsetting = -1; + + if (usb_os_open(udev) < 0) { + free(udev); + return NULL; + } + + return udev; +} + +int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, + size_t buflen) +{ + /* + * We can't use usb_get_descriptor() because it's lacking the index + * parameter. This will be fixed in libusb 1.0 + */ + return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000); +} + +int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen) +{ + char tbuf[255]; /* Some devices choke on size > 255 */ + int ret, langid, si, di; + + /* + * Asking for the zero'th index is special - it returns a string + * descriptor that contains all the language IDs supported by the + * device. Typically there aren't many - often only one. The + * language IDs are 16 bit numbers, and they start at the third byte + * in the descriptor. See USB 2.0 specification, section 9.6.7, for + * more information on this. */ + ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf)); + if (ret < 0) + return ret; + + if (ret < 4) + return -EIO; + + langid = tbuf[2] | (tbuf[3] << 8); + + ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf)); + if (ret < 0) + return ret; + + if (tbuf[1] != USB_DT_STRING) + return -EIO; + + if (tbuf[0] > ret) + return -EFBIG; + + for (di = 0, si = 2; si < tbuf[0]; si += 2) { + if (di >= (buflen - 1)) + break; + + if (tbuf[si + 1]) /* high byte */ + buf[di++] = '?'; + else + buf[di++] = tbuf[si]; + } + + buf[di] = 0; + + return di; +} + +int usb_close(usb_dev_handle *dev) +{ + int ret; + + ret = usb_os_close(dev); + free(dev); + + return ret; +} + +struct usb_device *usb_device(usb_dev_handle *dev) +{ + return dev->device; +} + +void usb_free_dev(struct usb_device *dev) +{ + usb_destroy_configuration(dev); + free(dev->children); + free(dev); +} + +struct usb_bus *usb_get_busses(void) +{ + return usb_busses; +} + +void usb_free_bus(struct usb_bus *bus) +{ + free(bus); +} + diff --git a/deps/libusb/usb.h b/deps/libusb/usb.h new file mode 100644 index 0000000..35955b7 --- /dev/null +++ b/deps/libusb/usb.h @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Prototypes, structure definitions and macros. + * + * Copyright (c) 2000-2003 Johannes Erdfelt + * + * This library is covered by the LGPL, read LICENSE for details. + * + * This file (and only this file) may alternatively be licensed under the + * BSD license as well, read LICENSE for details. + */ +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include +#include + +#include + +/* + * USB spec information + * + * This is all stuff grabbed from various USB specs and is pretty much + * not subject to change + */ + +/* + * Device and/or Interface Class codes + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_PTP 6 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 +#define USB_CLASS_VENDOR_SPEC 0xff + +/* + * Descriptor types + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 +#define USB_DT_HUB 0x29 + +/* + * Descriptor sizes per descriptor type + */ +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ +#define USB_DT_HUB_NONVAR_SIZE 7 + +/* All standard descriptors have these 2 fields in common */ +struct usb_descriptor_header { + unsigned char bLength; + unsigned char bDescriptorType; +}; + +/* String descriptor */ +struct usb_string_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short wData[1]; +}; + +/* HID descriptor */ +struct usb_hid_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short bcdHID; + unsigned char bCountryCode; + unsigned char bNumDescriptors; + /* unsigned char bReportDescriptorType; */ + /* unsigned short wDescriptorLength; */ + /* ... */ +}; + +/* Endpoint descriptor */ +#define USB_MAXENDPOINTS 32 +struct usb_endpoint_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bEndpointAddress; + unsigned char bmAttributes; + unsigned short wMaxPacketSize; + unsigned char bInterval; + unsigned char bRefresh; + unsigned char bSynchAddress; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_TYPE_CONTROL 0 +#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1 +#define USB_ENDPOINT_TYPE_BULK 2 +#define USB_ENDPOINT_TYPE_INTERRUPT 3 + +/* Interface descriptor */ +#define USB_MAXINTERFACES 32 +struct usb_interface_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bInterfaceNumber; + unsigned char bAlternateSetting; + unsigned char bNumEndpoints; + unsigned char bInterfaceClass; + unsigned char bInterfaceSubClass; + unsigned char bInterfaceProtocol; + unsigned char iInterface; + + struct usb_endpoint_descriptor *endpoint; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +#define USB_MAXALTSETTING 128 /* Hard limit */ +struct usb_interface { + struct usb_interface_descriptor *altsetting; + + int num_altsetting; +}; + +/* Configuration descriptor information.. */ +#define USB_MAXCONFIG 8 +struct usb_config_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short wTotalLength; + unsigned char bNumInterfaces; + unsigned char bConfigurationValue; + unsigned char iConfiguration; + unsigned char bmAttributes; + unsigned char MaxPower; + + struct usb_interface *interface; + + unsigned char *extra; /* Extra descriptors */ + int extralen; +}; + +/* Device descriptor */ +struct usb_device_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short bcdUSB; + unsigned char bDeviceClass; + unsigned char bDeviceSubClass; + unsigned char bDeviceProtocol; + unsigned char bMaxPacketSize0; + unsigned short idVendor; + unsigned short idProduct; + unsigned short bcdDevice; + unsigned char iManufacturer; + unsigned char iProduct; + unsigned char iSerialNumber; + unsigned char bNumConfigurations; +}; + +struct usb_ctrl_setup { + unsigned char bRequestType; + unsigned char bRequest; + unsigned short wValue; + unsigned short wIndex; + unsigned short wLength; +}; + +/* + * Standard requests + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +/* 0x02 is reserved */ +#define USB_REQ_SET_FEATURE 0x03 +/* 0x04 is reserved */ +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Various libusb API related stuff + */ + +#define USB_ENDPOINT_IN 0x80 +#define USB_ENDPOINT_OUT 0x00 + +/* Error codes */ +#define USB_ERROR_BEGIN 500000 + +/* + * This is supposed to look weird. This file is generated from autoconf + * and I didn't want to make this too complicated. + */ +#if _BIGENDIAN +#define USB_LE16_TO_CPU(x) do { x = ((x & 0xff) << 8) | ((x & 0xff00) >> 8); } while(0) +#else +#define USB_LE16_TO_CPU(x) +#endif + +/* Data types */ +struct usb_device; +struct usb_bus; + +/* + * To maintain compatibility with applications already built with libusb, + * we must only add entries to the end of this structure. NEVER delete or + * move members and only change types if you really know what you're doing. + */ +struct usb_device { + struct usb_device *next, *prev; + + char filename[PATH_MAX + 1]; + + struct usb_bus *bus; + + struct usb_device_descriptor descriptor; + struct usb_config_descriptor *config; + + void *dev; /* Darwin support */ + + unsigned char devnum; + + unsigned char num_children; + struct usb_device **children; +}; + +struct usb_bus { + struct usb_bus *next, *prev; + + char dirname[PATH_MAX + 1]; + + struct usb_device *devices; + unsigned long location; + + struct usb_device *root_dev; +}; + +struct usb_dev_handle; +typedef struct usb_dev_handle usb_dev_handle; + +/* Variables */ +extern struct usb_bus *usb_busses; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Function prototypes */ + +/* usb.c */ +usb_dev_handle *usb_open(struct usb_device *dev); +int usb_close(usb_dev_handle *dev); +int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf, + size_t buflen); +int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, + size_t buflen); + +/* descriptors.c */ +int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, + unsigned char type, unsigned char index, void *buf, int size); +int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, + unsigned char index, void *buf, int size); + +/* .c */ +int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, + int value, int index, char *bytes, int size, int timeout); +int usb_set_configuration(usb_dev_handle *dev, int configuration); +int usb_claim_interface(usb_dev_handle *dev, int interface); +int usb_release_interface(usb_dev_handle *dev, int interface); +int usb_set_altinterface(usb_dev_handle *dev, int alternate); +int usb_resetep(usb_dev_handle *dev, unsigned int ep); +int usb_clear_halt(usb_dev_handle *dev, unsigned int ep); +int usb_reset(usb_dev_handle *dev); + +#if LINUX_API +#define LIBUSB_HAS_GET_DRIVER_NP 1 +int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, + unsigned int namelen); +#define LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 1 +int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface); +#endif + +char *usb_strerror(void); + +void usb_init(void); +void usb_set_debug(int level); +int usb_find_busses(void); +int usb_find_devices(void); +struct usb_device *usb_device(usb_dev_handle *dev); +struct usb_bus *usb_get_busses(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __USB_H__ */ + diff --git a/deps/libusb/usbi.h b/deps/libusb/usbi.h new file mode 100644 index 0000000..d71b5c4 --- /dev/null +++ b/deps/libusb/usbi.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _USBI_H_ +#define _USBI_H_ + +#include "usb.h" + +#include "error.h" + +extern int usb_debug; + +/* Some quick and generic macros for the simple kind of lists we use */ +#define LIST_ADD(begin, ent) \ + do { \ + if (begin) { \ + ent->next = begin; \ + ent->next->prev = ent; \ + } else \ + ent->next = NULL; \ + ent->prev = NULL; \ + begin = ent; \ + } while(0) + +#define LIST_DEL(begin, ent) \ + do { \ + if (ent->prev) \ + ent->prev->next = ent->next; \ + else \ + begin = ent->next; \ + if (ent->next) \ + ent->next->prev = ent->prev; \ + ent->prev = NULL; \ + ent->next = NULL; \ + } while (0) + +#define DESC_HEADER_LENGTH 2 +#define DEVICE_DESC_LENGTH 18 +#define CONFIG_DESC_LENGTH 9 +#define INTERFACE_DESC_LENGTH 9 +#define ENDPOINT_DESC_LENGTH 7 +#define ENDPOINT_AUDIO_DESC_LENGTH 9 + +struct usb_dev_handle { + int fd; + + struct usb_bus *bus; + struct usb_device *device; + + int config; + int interface; + int altsetting; + + /* Added by RMT so implementations can store other per-open-device data */ + void *impl_info; +}; + +/* descriptors.c */ +int usb_parse_descriptor(unsigned char *source, char *description, void *dest); +int usb_parse_configuration(struct usb_config_descriptor *config, + unsigned char *buffer); +void usb_fetch_and_parse_descriptors(usb_dev_handle *udev); +void usb_destroy_configuration(struct usb_device *dev); + +/* OS specific routines */ +int usb_os_find_busses(struct usb_bus **busses); +int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices); +int usb_os_determine_children(struct usb_bus *bus); +void usb_os_init(void); +int usb_os_open(usb_dev_handle *dev); +int usb_os_close(usb_dev_handle *dev); + +void usb_free_dev(struct usb_device *dev); +void usb_free_bus(struct usb_bus *bus); + +#endif /* _USBI_H_ */ + diff --git a/deps/libusb/windows.c b/deps/libusb/windows.c new file mode 100755 index 0000000..0afbef9 --- /dev/null +++ b/deps/libusb/windows.c @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "winusb.h" + +#include +#include +#include +#include "fdevent.h" +#include "utils.h" +#include "strutils.h" +#include "linkedlist.h" + +#define TRACE_TAG TRACE_USB +#include "sdb.h" +#include "sdb_usb.h" + +struct usb_handle { + LIST_NODE* node; + + HANDLE hnd; + WINUSB_INTERFACE_HANDLE fd; + char unique_node_path[PATH_MAX+1]; //MAX_DEVICE_ID_LEN \ + UCHAR end_point[2]; + unsigned int zero_mask; +}; +usb_handle *usb_open(const char *device_path); +int win_usb_close(usb_handle *dev); +int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen); +void *device_poll_thread(void* unused); +int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout); +void do_lsusb(void); + +// Class ID assigned to the device by aNdrOiduSb.sys +static const GUID TIZEN_CLASSID = {0x9ca29f37, 0xdd62, 0x4aad, {0x82, 0x65, 0xcf, 0xf7, 0x88, 0xc8, 0xba, 0x89}}; + +static LIST_NODE* handle_list = NULL; + +SDB_MUTEX_DEFINE( usb_lock ); + + +// winusb.dll entrypoints +DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); +DLL_DECLARE(WINAPI, BOOL, WinUsb_GetOverlappedResult, (WINUSB_INTERFACE_HANDLE, LPOVERLAPPED, LPDWORD, BOOL)); + +void win_usb_init(void) { + // Initialize DLL functions + if (!WinUsb_Initialize) { + DLL_LOAD(winusb.dll, WinUsb_Initialize); + DLL_LOAD(winusb.dll, WinUsb_Free); + DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface); + DLL_LOAD(winusb.dll, WinUsb_GetDescriptor); + DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings); + DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation); + DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting); + DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting); + DLL_LOAD(winusb.dll, WinUsb_QueryPipe); + DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy); + DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy); + DLL_LOAD(winusb.dll, WinUsb_ReadPipe); + DLL_LOAD(winusb.dll, WinUsb_WritePipe); + DLL_LOAD(winusb.dll, WinUsb_ControlTransfer); + DLL_LOAD(winusb.dll, WinUsb_ResetPipe); + DLL_LOAD(winusb.dll, WinUsb_AbortPipe); + DLL_LOAD(winusb.dll, WinUsb_FlushPipe); + DLL_LOAD(winusb.dll, WinUsb_GetOverlappedResult); + } +} + +int is_device_registered(const char *node_path) +{ + int r = 0; + sdb_mutex_lock(&usb_lock, "usb is_device_registered"); + + LIST_NODE* cur_ptr = handle_list; + while(cur_ptr != NULL) { + usb_handle* usb = cur_ptr->data; + cur_ptr = cur_ptr->next_ptr; + + if(!strcmp(usb->unique_node_path, node_path)) { + r = 1; + break; + } + } + sdb_mutex_unlock(&usb_lock, "usb is_device_registered"); + return r; +} + +usb_handle *usb_open(const char *device_path) { + // Allocate storage for handles + usb_handle* usb = calloc(1, sizeof(usb_handle)); + s_strncpy(usb->unique_node_path, device_path, sizeof(usb->unique_node_path)); + + // Open generic handle to device + HANDLE hnd = CreateFile(device_path, GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, NULL); + + if (INVALID_HANDLE_VALUE == hnd) { + D("fail to create device file: %s due to: %d\n", device_path, GetLastError()); + return NULL; + } + + // Initialize WinUSB for this device and get a WinUSB handle for it + WINUSB_INTERFACE_HANDLE fd; + if (!WinUsb_Initialize(hnd, &fd)) { + return NULL; + } + + // fetch USB device descriptor + USB_DEVICE_DESCRIPTOR usb_device_descriptor; + unsigned long bytes_written; + + if (!WinUsb_GetDescriptor(fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, + (PUCHAR)&usb_device_descriptor, sizeof(usb_device_descriptor), &bytes_written)) { + return NULL; + } + + USB_INTERFACE_DESCRIPTOR usb_interface_descriptor; + + // fetch usb interface descriptor + UCHAR interface_number; + if (!WinUsb_GetCurrentAlternateSetting(fd, &interface_number)) { + return NULL; + } + + if (!WinUsb_QueryInterfaceSettings(fd, interface_number, &usb_interface_descriptor)) { + return NULL; + } + + if (2 != usb_interface_descriptor.bNumEndpoints) { + D("the number of endpoint should be two\n"); + return NULL; + } + + if (!is_sdb_interface(usb_device_descriptor.idVendor, usb_interface_descriptor.bInterfaceClass, usb_interface_descriptor.bInterfaceSubClass, + usb_interface_descriptor.bInterfaceProtocol)) { + return NULL; + } + UCHAR endpoint_index = 0; + + for (endpoint_index = 0; endpoint_index < usb_interface_descriptor.bNumEndpoints; endpoint_index++) { + // fetch endpoint information + WINUSB_PIPE_INFORMATION pipe_info; + if (!WinUsb_QueryPipe(fd, interface_number, endpoint_index, &pipe_info)) { + return NULL; + } + + if(usb_interface_descriptor.bInterfaceProtocol == 0x01) { + if (endpoint_index == 0) { + usb->zero_mask = pipe_info.MaximumPacketSize - 1; + } + } + // only interested in bulk type + if (UsbdPipeTypeBulk == pipe_info.PipeType) { + if (USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) { + D("builk in endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId); + usb->end_point[0] = pipe_info.PipeId; + } + + if (USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) { + D("builk out endpoint index: %d, id: %04x\n", endpoint_index, pipe_info.PipeId); + usb->end_point[1] = pipe_info.PipeId; + } + + } + } + usb->hnd = hnd; + usb->fd = fd; + + return usb; +} + +int register_device(usb_handle *hnd) { + if (is_device_registered(hnd->unique_node_path)) { + return 0; + } + + sdb_mutex_lock(&usb_lock, "usb register_device"); + + hnd->node = prepend(&handle_list, hnd); + + sdb_mutex_unlock(&usb_lock, "usb register_device"); + + return 1; +} + +int usb_get_string_simple(usb_handle *dev, int index, char *buf, size_t buflen) { + unsigned char temp[MAXIMUM_USB_STRING_LENGTH]; + + ULONG actlen = 0; + //0x0409 for English (US) + if (!WinUsb_GetDescriptor(dev->fd, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409, temp, sizeof(temp), &actlen)) { + return -GetLastError(); + } + // Skip first two bytes of result (descriptor id and length), then take + // every other byte as a cheap way to convert Unicode to ASCII + unsigned int i, j; + for (i = 2, j = 0; i < actlen && j < (buflen - 1); i += 2, ++j) + buf[j] = temp[i]; + buf[j] = '\0'; + + return strlen(buf); +} + +static int get_serial_number(usb_handle *dev, char *buf, int buflen) { + USB_DEVICE_DESCRIPTOR usb_device_descriptor; + ULONG actlen = 0; + + if (!WinUsb_GetDescriptor(dev->fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (unsigned char*) &usb_device_descriptor, + sizeof(usb_device_descriptor), &actlen)) { + return 0; + } + + return usb_get_string_simple(dev, usb_device_descriptor.iSerialNumber, buf, buflen); +} + +int usb_find_devices(GUID deviceClassID) { + SP_DEVINFO_DATA deviceInfoData; + char devicePath[PATH_MAX + 1]; + BOOL bResult = TRUE; + PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL; + int index = 0; + + // from http://msdn.microsoft.com/en-us/library/windows/hardware/ff540174(v=vs.85).aspx + // Get information about all the installed devices for the specified device interface class. + HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&deviceClassID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (hDeviceInfo == INVALID_HANDLE_VALUE) { + D("fail to find any device: %d\n", GetLastError()); + return 0; + } + + //Enumerate all the device interfaces in the device information set. + deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + for (index = 0; ; index++) { + + //Get information about the device interface. + SP_DEVICE_INTERFACE_DATA interfaceData; + interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); + + bResult = SetupDiEnumDeviceInterfaces(hDeviceInfo, NULL, &deviceClassID, index, &interfaceData); + // Check if last item + if (GetLastError() == ERROR_NO_MORE_ITEMS) { + break; + } + + //Check for some other error + if (!bResult) + { + D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); + break; + } + + // Determine required size for interface detail data + ULONG requiredLength = 0; + + //Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA + //which we need to allocate, so we have to call this function twice. + //First to get the size so that we know how much to allocate + //Second, the actual call with the allocated buffer + bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL); + + //Check for some other error + if (!bResult) { + if ((ERROR_INSUFFICIENT_BUFFER == GetLastError()) && (requiredLength > 0)) { + // Allocate storage for interface detail data + detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredLength); + + if (detailData == NULL) { + D("fail to allocate memory\n"); + break; + } + } else { + D("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError()); + break; + } + } + + // Finally, do fetch interface detail data + detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + //Now call it with the correct size and allocated buffer + bResult = SetupDiGetDeviceInterfaceDetail(hDeviceInfo, &interfaceData, detailData, requiredLength, NULL, + &deviceInfoData); + + //Check for some other error + if (!bResult) { + D("fail to setdup get device interface detail: %d\n", GetLastError()); + if (detailData != NULL) { + free(detailData); + } + break; + } + + //copy device path + s_strncpy(devicePath, detailData->DevicePath, sizeof(devicePath)); + + if (detailData != NULL) { + free(detailData); + } + + if (!is_device_registered(devicePath)) { + struct usb_handle *hnd = usb_open(devicePath); + if (hnd != NULL) { + char serial[256]; + if (get_serial_number(hnd, serial, sizeof(serial)) > 0) { + D("register usb for: %s\n", serial); + if (register_device(hnd)) { + register_usb_transport(hnd, serial); + } else { + D("fail to register usb\n"); + win_usb_close(hnd); + free(hnd); + } + } else { + D("fail to get usb serial name: kick? close?\n"); + win_usb_close(hnd); + free(hnd); + } + } + } + } + // Cleanup + bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo); + + return bResult; +} + +void* device_poll_thread(void* sleep_msec) { + D("Created device thread\n"); + + int mseconds = (int) sleep_msec; + while (1) { + do_lsusb(); + sdb_sleep_ms(mseconds); + } + + return NULL; +} + +void sdb_usb_init() { + sdb_thread_t tid; + + win_usb_init(); + if (sdb_thread_create(&tid, device_poll_thread, (void*)3000)) { + LOG_FATAL("cannot create input thread\n"); + } +} + +void sdb_usb_cleanup() { + D("TODO: not imple yet\n"); +} + +int usb_bulk_transfer(usb_handle* handle, BOOL is_read, const void *data, unsigned long length, unsigned long *actual_length, unsigned long timeout) { + ULONG tmp = timeout; + UCHAR endpoint; + + if (is_read) { + endpoint = handle->end_point[0]; + } else { + endpoint = handle->end_point[1]; + } + if (handle->fd == NULL) { + D("invalid handle\n"); + return 0; + } + + // do not complete within the specified time-out interval + if (!WinUsb_SetPipePolicy(handle->fd, endpoint, PIPE_TRANSFER_TIMEOUT, sizeof(tmp), &tmp)) { + D("fail to set timeout\n"); + SetLastError(ERROR_SEM_TIMEOUT); + return 0; + } + + // manual reset must be true (second param) as the reset occurs in read + + OVERLAPPED overlapped; + ZeroMemory(&overlapped, sizeof(overlapped)); + overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + BOOL ret = TRUE; + ULONG transferred = 0; + + if (is_read) { + ret = WinUsb_ReadPipe(handle->fd, endpoint, (UCHAR*) data, length, &transferred, &overlapped); + } else { + ret = WinUsb_WritePipe(handle->fd, endpoint, (UCHAR*) data, length, &transferred, &overlapped); + } + + if (!ret && (ERROR_IO_PENDING != GetLastError())) { + if (NULL != overlapped.hEvent){ + CloseHandle(overlapped.hEvent); + } + D("pipe error: (%ld/ld) error:%d\n", length, transferred, GetLastError()); + return 0; + } + + // wait for the operation to be IO completed + ret = WinUsb_GetOverlappedResult(handle->fd, &overlapped, &transferred, TRUE); + + if (ret && (NULL != actual_length)) { + *actual_length = transferred; + } + + if (NULL != overlapped.hEvent) { + CloseHandle(overlapped.hEvent); + } + + return ret ? 1 : 0; +} + +int sdb_usb_write(usb_handle* handle, const void* data, int len) { + unsigned long time_out = 5000;//5000; + unsigned long written = 0; + int ret; + + D("+sdb_usb_write %d\n", len); + + if (NULL != handle) { + ret = usb_bulk_transfer(handle, FALSE, (void*)data, (unsigned long)len, &written, time_out); + int saved_errno = GetLastError(); + D("sdb_usb_write got(ret:%d): %ld, expected: %d, errno: %d\n",ret, written, len, saved_errno); + + if (ret) { + if (written == (unsigned long) len) { + if (handle->zero_mask && (len & handle->zero_mask) == 0) { + // Send a zero length packet + usb_bulk_transfer(handle, FALSE, (void*)data, 0, &written, time_out); + } + return 0; + } + } else { + // assume ERROR_INVALID_HANDLE indicates we are disconnected + if (saved_errno == ERROR_INVALID_HANDLE) { + sdb_usb_kick(handle); + } + } + errno = saved_errno; + } else { + D("usb_write NULL handle\n"); + SetLastError(ERROR_INVALID_HANDLE); + } + + D("-sdb_usb_write failed: %d\n", errno); + + return -1; +} + +int sdb_usb_read(usb_handle *handle, void* data, int len) { + unsigned long n = 0; + int ret; + + D("+sdb_usb_read %d\n", len); + if (NULL != handle) { + while (len > 0) { + int xfer = (len > 4096) ? 4096 : len; + ret = usb_bulk_transfer(handle, TRUE, (void*)data, (unsigned long)xfer, &n, (unsigned long)0); + int saved_errno = GetLastError(); + D("sdb_usb_read got(ret:%d): %ld, expected: %d, errno: %d\n", ret, n, xfer, saved_errno); + + if (ret) { + data += n; + len -= n; + + if (len == 0) + return 0; + } else { + // assume ERROR_INVALID_HANDLE indicates we are disconnected + if (saved_errno == ERROR_INVALID_HANDLE) { + sdb_usb_kick(handle); + } + break; + } + errno = saved_errno; + } + } else { + D("sdb_usb_read NULL handle\n"); + SetLastError(ERROR_INVALID_HANDLE); + } + + D("-sdb_usb_read failed: %d\n", errno); + + return -1; +} + +int win_usb_close(usb_handle *handle) { + D("+usb win_usb_close\n"); + if (NULL != handle) { + if (NULL != handle->fd) { + WinUsb_Free(handle->fd); + handle->fd = NULL; + } + if (NULL != handle->hnd) { + CloseHandle(handle->hnd); + handle->hnd = NULL; + } + handle = NULL; + } + D("-usb win_usb_close\n"); + return 0; +} + +void sdb_usb_kick(usb_handle* handle) { + D("+sdb_usb_kick: %p\n", handle); + // called from transport remote kick if already registered + // so only clean for win usb handle resources + sdb_mutex_lock(&usb_lock, "usb sdb_usb_kick"); + win_usb_close(handle); + sdb_mutex_unlock(&usb_lock , "usb sdb_usb_kick"); + D("-sdb_usb_kick: %p\n", handle); +} + +int sdb_usb_close(usb_handle* handle) { + D("+sdb_usb_close: %p\n", handle); + if (NULL != handle) { + sdb_mutex_lock(&usb_lock, "usb sdb_usb_close"); + remove_node(&handle_list, handle->node, NULL); + sdb_mutex_unlock(&usb_lock, "usb sdb_usb_close"); + } + D("-sdb_usb_close: %p\n", handle); + return 0; +} + +void do_lsusb() { + usb_find_devices(TIZEN_CLASSID); +} diff --git a/deps/libusb/winusb.h b/deps/libusb/winusb.h new file mode 100755 index 0000000..8e5cf8a --- /dev/null +++ b/deps/libusb/winusb.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __WINUSB_H +#define __WINUSB_H + +#include "ddk/usb100.h" +#include "ddk/usbioctl.h" + +// Windows API default is uppercase - ugh! +#if !defined(bool) +#define bool BOOLEAN +#endif +#if !defined(true) +#define true TRUE +#endif +#if !defined(false) +#define false FALSE +#endif + + +/* + * Some of the EX stuff is not yet in MinGW => define it + */ +#ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX +#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 +#endif + +#ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX +#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ + CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + +#ifndef USB_NODE_CONNECTION_INFORMATION_EX +typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { + ULONG ConnectionIndex; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + UCHAR CurrentConfigurationValue; + UCHAR Speed; + BOOLEAN DeviceIsHub; + USHORT DeviceAddress; + ULONG NumberOfOpenPipes; + USB_CONNECTION_STATUS ConnectionStatus; + USB_PIPE_INFO PipeList[0]; +} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; +#endif + +#ifndef USB_HUB_CAP_FLAGS +typedef union _USB_HUB_CAP_FLAGS { + ULONG ul; + struct { + ULONG HubIsHighSpeedCapable:1; + ULONG HubIsHighSpeed:1; + ULONG HubIsMultiTtCapable:1; + ULONG HubIsMultiTt:1; + ULONG HubIsRoot:1; + ULONG HubIsArmedWakeOnConnect:1; + ULONG ReservedMBZ:26; + }; +} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; +#endif + +#ifndef USB_HUB_CAPABILITIES_EX +typedef struct _USB_HUB_CAPABILITIES_EX { + USB_HUB_CAP_FLAGS CapabilityFlags; +} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; +#endif + +#ifndef USB_GET_HUB_CAPABILITIES_EX +#define USB_GET_HUB_CAPABILITIES_EX 276 +#endif + +#ifndef IOCTL_USB_GET_HUB_CAPABILITIES_EX +#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ + CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, \ + METHOD_BUFFERED, FILE_ANY_ACCESS ) +#endif + +/* + * WinUSB macros - from libusb-win32 1.x + */ + +#define DLL_DECLARE(api, ret, name, args) \ + typedef ret (api * __dll_##name##_t)args; \ + static __dll_##name##_t name + +#define DLL_LOAD(dll, name) \ + do { \ + HMODULE h = GetModuleHandle(#dll); \ + if(!h) \ + h = LoadLibrary(#dll); \ + if(!h) \ + break; \ + if((name = (__dll_##name##_t)GetProcAddress(h, #name))) \ + break; \ + if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \ + break; \ + if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \ + break; \ + } while(0) + + +/* winusb.dll interface */ + +#define SHORT_PACKET_TERMINATE 0x01 +#define AUTO_CLEAR_STALL 0x02 +#define PIPE_TRANSFER_TIMEOUT 0x03 +#define IGNORE_SHORT_PACKETS 0x04 +#define ALLOW_PARTIAL_READS 0x05 +#define AUTO_FLUSH 0x06 +#define RAW_IO 0x07 +#define MAXIMUM_TRANSFER_SIZE 0x08 +#define AUTO_SUSPEND 0x81 +#define SUSPEND_DELAY 0x83 +#define DEVICE_SPEED 0x01 +#define LowSpeed 0x01 +#define FullSpeed 0x02 +#define HighSpeed 0x03 + +typedef enum _USBD_PIPE_TYPE { + UsbdPipeTypeControl, + UsbdPipeTypeIsochronous, + UsbdPipeTypeBulk, + UsbdPipeTypeInterrupt +} USBD_PIPE_TYPE; + +typedef struct { + USBD_PIPE_TYPE PipeType; + UCHAR PipeId; + USHORT MaximumPacketSize; + UCHAR Interval; +} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; + +#pragma pack(1) +typedef struct { + UCHAR RequestType; + UCHAR Request; + USHORT Value; + USHORT Index; + USHORT Length; +} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; +#pragma pack() + +typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; + +#endif // __WINUSB_H diff --git a/package/changelog b/package/changelog index 2549397..164ccd9 100644 --- a/package/changelog +++ b/package/changelog @@ -1,51 +1,60 @@ +* 2.2.20 +- fix offline bug +== ho.namkoong 2013-09-16 21:35 +* 2.2.19 +- fix device undetected bug +== ho.namkoong 2013-09-16 20:36 +* 2.2.18 +- Fix duplicated target bug +== ho.namkoong 2013-09-16 13:50 * 2.2.17 -- change compiler to llvm -== yoonki.park 2013-07-15 +- fix pull/ push bug +== ho.namkoong 2013-09-14 20:06 * 2.2.16 -- fixed build script for tsudo -== ho.namkoong 2013-07-15 +- fix bugs about sdb test cases +== ho.namkoong 2013-09-01 * 2.2.15 -- give abs path to tsudo -== ho.namkoong 2013-07-12 +- version up for refactoring test +== ho.namkoong 2013-08-23 * 2.2.14 -- Change PATH_MAX in Windows 256 -> 4096 -== ho.namkoong 2013-07-11 +- version up 2.2.14 +== ho.namkoong 2013-08-07 * 2.2.13 -- echo stdout in install script -== ho.namkoong 2013-07-11 +- version up 2.2.13 +== ho.namkoong 2013-08-05 * 2.2.12 -- use tsudo instead of gksudo -== ho.namkoong 2013-07-11 +- fix socket close bug +== ho.namkoong 2013-07-24 * 2.2.11 -- Fixed sdbd version checking without rpm query -== ho.namkoong 2013-07-08 +- fix web debugging bug +== ho.namkoong 2013-07-24 * 2.2.10 -- Fixed argument append util for da/oprofile command -== kh5325.kim 2013-07-08 +- fix forward bug +== ho.namkoong 2013-07-24 * 2.2.9 -- Fix pull/push message -== ho.namkoong 2013-07-04 +- remove setting sdb path +== yoonki.park 2013-07-23 * 2.2.8 -- Fix window install bug -== ho.namkoong 2013-06-28 +- fixed to install on windows +== ho.namkoong 2013-07-22 * 2.2.7 -- rollback linux usb control -== ho.namkoong 2013-06-25 +- fixed to add sdb path to windows shell +== ho.namkoong 2013-07-19 * 2.2.6 -- change lstat to stat for treating link file as regular file -== ho.namkoong 2013-06-24 +- change PATH_MAX in Windows 256 -> 4096 +== ho.namkoong 2013-07-11 * 2.2.5 -- modify debug launchpad applied sdbd version -== ho.namkoong 2013-06-24 +- use tsudo +== ho.namkoong 2013-07-11 * 2.2.4 -- change sdb version in help page -== ho.namkoong 2013-06-23 +- use libusb.so +== ho.namkoong 2013-07-11 * 2.2.3 -- remove printf in lauchapp -== ho.namkoong 2013-06-23 +- fix da and oprofile arg appending bug +== ho.namkoong 2013-07-04 * 2.2.2 -- apply debug launch pad -== ho.namkoong 2013-06-23 +- sdb for tizen2.2 +== yoonki.park 2013-07-04 * 2.2.1 - fixed crash on Windows == yoonki.park 2013-06-21 diff --git a/package/pkginfo.manifest b/package/pkginfo.manifest index 7ce81c8..edea43b 100644 --- a/package/pkginfo.manifest +++ b/package/pkginfo.manifest @@ -1,4 +1,4 @@ -Version:2.2.17 +Version:2.2.20 Source:sdb Maintainer:Kangho Kim , Yoonki Park, Hyunsik Noh, Gun Kim, Ho Namkoong, Taeyoung Son diff --git a/package/sdb.install.linux b/package/sdb.install.linux index 456cba7..256b648 100755 --- a/package/sdb.install.linux +++ b/package/sdb.install.linux @@ -1,54 +1,3 @@ #!/bin/bash -ex -## Set sdb's environment path -bashrc=${HOME}/.bashrc -if [ -f ${bashrc} ]; then - s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` -else - s= -fi - -if [ "x${s}" = "x" ]; then -cat >> ${bashrc} << END -## Tizen SDK configuration -# This is generated by Tizen SDK. Please do not modify by yourself. -# Set sdb environment path -export PATH=\$PATH:${INSTALLED_PATH}/tools -## End Tizen SDK configuration -END -fi - -source ${HOME}/.bashrc - -# set udev rules file - -TMP_FILE=99-samsung-device.rules -echo "# Add a udev rules when you want to develop a Tizen application with your device." >> $TMP_FILE -echo "# Use this format to add each vendor to the file:" >> $TMP_FILE -echo "# SUBSYSTEM==\"usb\", ATTR{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE -echo "# In the example, the vendor ID is for Samsung manufacture. The mode specifies read/write permissions, and group defines which Unix group owns the device node." >> $TMP_FILE -echo "#" >> $TMP_FILE -echo "# Contact : Kangho Kim , Yoonki Park, Ho Namkoong " >> $TMP_FILE -echo "# See also udev(7) for an overview of rule syntax." >> $TMP_FILE -echo "" >> $TMP_FILE -echo "# Samsung" >> $TMP_FILE -echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6864\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE -echo "SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"04e8\", ATTRS{idProduct}==\"6863\", MODE=\"0666\", GROUP=\"plugdev\"" >> $TMP_FILE - -chmod +x $TMP_FILE -CURRENT_DIR=`pwd` - -if [ -z "$TSUDO" ]; then - if [ -f /usr/bin/gksudo ] - then gksudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/ - else if [ -f /usr/bin/sudo ] - then sudo mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/ - fi - fi - exit 0 -else - $TSUDO -m "Enter your password to install sdb." mv ${CURRENT_DIR}/${TMP_FILE} /etc/udev/rules.d/ - exit 0 -fi - exit 0 diff --git a/package/sdb.install.macos-64 b/package/sdb.install.macos-64 index 08a8365..256b648 100755 --- a/package/sdb.install.macos-64 +++ b/package/sdb.install.macos-64 @@ -1,24 +1,3 @@ #!/bin/bash -ex -## Set sdb's environment path - -bashrc=${HOME}/.bashrc -if [ -f ${bashrc} ]; then - s=`cat ${bashrc} | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` -else - s= -fi - -if [ "x${s}" = "x" ]; then -cat >> ${bashrc} << END -## Tizen SDK configuration -# This is generated by Tizen SDK. Please do not modify by yourself. -# Set sdb environment path -export PATH=\$PATH:${INSTALLED_PATH}/tools -## End Tizen SDK configuration -END -fi - -source ${HOME}/.bashrc - exit 0 diff --git a/package/sdb.install.windows b/package/sdb.install.windows index 02753b7..83cb140 100644 --- a/package/sdb.install.windows +++ b/package/sdb.install.windows @@ -1,5 +1 @@ @echo off - -echo "setting path..." -setx -m PATH "%PATH%;${INSTALLED_PATH}\tools -exit 0 diff --git a/package/sdb.remove.linux b/package/sdb.remove.linux index b849590..8f3cbf8 100755 --- a/package/sdb.remove.linux +++ b/package/sdb.remove.linux @@ -2,35 +2,23 @@ SDB_PATH=tools/sdb ${INSTALLED_PATH}/${SDB_PATH} kill-server rm -rf ${INSTALLED_PATH}/${SDB_PATH} -## remove sdb environment path -s=`cat ${HOME}/.bashrc | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` -if [ "x${s}" = "x" ] ; then - exit 0 -fi +UDEV_RULE=/etc/udev/rules.d/99-samsung-device.rules -if [ ${s} -ge 0 ] ; then - e=`cat ${HOME}/.bashrc | grep -n "## End Tizen SDK configuration" | cut -f1 -d":"` - if [ $e -ge $s ] ; then - cp ${HOME}/.bashrc ${HOME}/.bashrc.tizen - sed "${s},${e}d" ${HOME}/.bashrc > ${HOME}/.bashrc.swap - mv ${HOME}/.bashrc.swap ${HOME}/.bashrc - source ${HOME}/.bashrc - fi +if [ ! -f ${UDEV_RULE} ]; then + exit 0 fi - ## remove udev rule file - if [ -z "$TSUDO" ]; then if [ -f /usr/bin/gksudo ] - then gksudo rm -rf /etc/udev/rules.d/99-samsung-device.rules + then gksudo rm -rf ${UDEV_RULE} else if [ -f /usr/bin/sudo ] - then sudo rm -rf /etc/udev/rules.d/99-samsung-device.rules + then sudo rm -rf ${UDEV_RULE} fi fi exit 0 else - $TSUDO -m "Enter your password to uninstall sdb." rm -rf /etc/udev/rules.d/99-samsung-device.rules + $TSUDO -m "Enter your password to uninstall sdb." rm -rf ${UDEV_RULE} exit 0 fi diff --git a/package/sdb.remove.macos-64 b/package/sdb.remove.macos-64 index 7632317..10a8dda 100755 --- a/package/sdb.remove.macos-64 +++ b/package/sdb.remove.macos-64 @@ -2,21 +2,5 @@ SDB_PATH=tools/sdb ${INSTALLED_PATH}/${SDB_PATH} kill-server rm -rf ${INSTALLED_PATH}/${SDB_PATH} -## remove sdb environment path -s=`cat ${HOME}/.bashrc | grep -n "## Tizen SDK configuration" | cut -f1 -d":"` - -if [ "x${s}" = "x" ] ; then - exit 1 -fi - -if [ ${s} -ge 0 ] ; then - e=`cat ${HOME}/.bashrc | grep -n "## End Tizen SDK configuration" | cut -f1 -d":"` - if [ $e -ge $s ] ; then - cp ${HOME}/.bashrc ${HOME}/.bashrc.tizen - sed "${s},${e}d" ${HOME}/.bashrc > ${HOME}/.bashrc.swap - mv ${HOME}/.bashrc.swap ${HOME}/.bashrc - source ${HOME}/.bashrc - fi -fi exit 0 diff --git a/package/sdb.remove.windows b/package/sdb.remove.windows index 1c3c664..1d845d3 100644 --- a/package/sdb.remove.windows +++ b/package/sdb.remove.windows @@ -1,8 +1,18 @@ @echo off -set execute_path=tools -%INSTALLED_PATH%\%execute_path%\sdb.exe kill-server -del %INSTALLED_PATH%\%execute_path%\sdb.exe -del %INSTALLED_PATH%\%execute_path%\ansicon.exe -del %INSTALLED_PATH%\%execute_path%\ANSI32.dll -exit 0 +set SDB_PATH=%INSTALLED_PATH%\tools + +%SDB_PATH%\sdb.exe kill-server +del %SDB_PATH%\sdb.exe +del %SDB_PATH%\ansicon.exe +del %SDB_PATH%\ANSI32.dll + +::echo "removing sdb path..." + +::set replace= +::set search=%SDB_PATH% +::set subject=%PATH% +:: update path +::call set subject=%%subject:%search%=%replace%%% +::setx -m PATH "%subject%" +exit 0 \ No newline at end of file diff --git a/src/command_function.c b/src/command_function.c index 47f3eb1..f170516 100644 --- a/src/command_function.c +++ b/src/command_function.c @@ -28,7 +28,6 @@ #include #include "utils.h" #include "fdevent.h" -#include "sdb.h" #include "commandline.h" #include "command_function.h" @@ -39,6 +38,10 @@ #include "strutils.h" #include "file_sync_client.h" #include "file_sync_functions.h" +#include "common_modules.h" + +#include "log.h" +#include "sdb.h" static const char *SDK_TOOL_PATH="/home/developer/sdk_tools"; static const char *APP_PATH_PREFIX="/opt/apps"; @@ -295,6 +298,23 @@ int __connect(int argc, char ** argv, void** extargv) { } } +int device_con(int argc, char ** argv, void** extargv) { + + char *tmp; + char full_cmd[PATH_MAX]; + + snprintf(full_cmd, sizeof full_cmd, "host:device_con:%s:%s", argv[1], argv[2]); + D(COMMANDLINE_MSG_FULL_CMD, argv[0], full_cmd); + tmp = sdb_query(full_cmd, extargv); + + if(tmp != NULL) { + printf("%s", tmp); + return 0; + } + + return 1; +} + int get_state_serialno(int argc, char ** argv, void** extargv) { char* serial = (char *)extargv[0]; transport_type* ttype = (transport_type*)extargv[1]; @@ -340,8 +360,11 @@ int status_window(int argc, char ** argv, void** extargv) { #else int fd; fd = unix_open("/dev/null", O_WRONLY); - dup2(fd, 2); - sdb_close(fd); + + if(fd >= 0) { + dup2(fd, 2); + sdb_close(fd); + } #endif format_host_command(full_cmd, sizeof full_cmd, "get-state", *ttype, serial); @@ -487,23 +510,20 @@ int shell(int argc, char ** argv, void** extargv) { strcat(buf, "\""); } - for(;;) { - D("interactive shell loop. buff=%s\n", buf); - fd = sdb_connect(buf, extargv); - if(fd >= 0) { - D("about to read_and_dump(fd=%d)\n", fd); - read_and_dump(fd); - D("read_and_dump() done.\n"); - sdb_close(fd); - r = 0; - } else { - r = 1; - } - - D("interactive shell loop. return r=%d\n", r); - return r; + D("interactive shell loop. buff=%s\n", buf); + fd = sdb_connect(buf, extargv); + if(fd >= 0) { + D("about to read_and_dump(fd=%d)\n", fd); + read_and_dump(fd); + D("read_and_dump() done.\n"); + sdb_close(fd); + r = 0; + } else { + r = 1; } - return 1; + + D("interactive shell loop. return r=%d\n", r); + return r; } int forkserver(int argc, char** argv, void** extargv) { diff --git a/src/command_function.h b/src/command_function.h index f9c6801..42816ee 100644 --- a/src/command_function.h +++ b/src/command_function.h @@ -30,16 +30,17 @@ #define TRACE_TAG TRACE_SDB #ifdef OS_WINDOWS +#undef PATH_MAX #define PATH_MAX 4096 #endif - int da(int argc, char ** argv, void** extargv); int oprofile(int argc, char ** argv, void** extargv); int launch(int argc, char ** argv, void** extargv); int devices(int argc, char ** argv, void** extargv); int __disconnect(int argc, char ** argv, void** extargv); int __connect(int argc, char ** argv, void** extargv); +int device_con(int argc, char ** argv, void** extargv); int get_state_serialno(int argc, char ** argv, void** extargv); int root(int argc, char ** argv, void** extargv); int status_window(int argc, char ** argv, void** extargv); diff --git a/src/commandline.c b/src/commandline.c index 6f0d9fb..a761805 100755 --- a/src/commandline.c +++ b/src/commandline.c @@ -35,10 +35,9 @@ #include #endif #include "utils.h" -#include "sdb.h" #include "sdb_client.h" #include "file_sync_service.h" - +#include "log.h" #include "linkedlist.h" #include "sdb_constants.h" @@ -100,6 +99,7 @@ void read_and_dump(int fd) fwrite(buf, 1, len, stdout); fflush(stdout); } + } static void *stdin_read_thread(void *x) @@ -135,7 +135,6 @@ static void *stdin_read_thread(void *x) stdin_raw_restore(INPUT_FD, tio_save); free(tio_save); #endif - free(args); exit(0); } } @@ -272,17 +271,17 @@ static void create_opt_list(LIST_NODE** opt_list) { OPTION* serial = NULL; create_option(&serial, COMMANDLINE_SERIAL_LONG_OPT, COMMANDLINE_SERIAL_SHORT_OPT, COMMANDLINE_SERIAL_DESC, COMMANDLINE_SERIAL_DESC_SIZE, COMMANDLINE_SERIAL_ARG_DESC, COMMANDLINE_SERIAL_HAS_ARG); - append(opt_list, serial); + prepend(opt_list, serial); OPTION* device = NULL; create_option(&device, COMMANDLINE_DEVICE_LONG_OPT, COMMANDLINE_DEVICE_SHORT_OPT, COMMANDLINE_DEVICE_DESC, COMMANDLINE_DEVICES_DESC_SIZE, EMPTY_STRING, COMMANDLINE_DEVICE_HAS_ARG); - append(opt_list, device); + prepend(opt_list, device); OPTION* emulator = NULL; create_option(&emulator, COMMANDLINE_EMULATOR_LONG_OPT, COMMANDLINE_EMULATOR_SHORT_OPT, COMMANDLINE_EMULATOR_DESC, COMMANDLINE_EMULATOR_DESC_SIZE, EMPTY_STRING, COMMANDLINE_EMULATOR_HAS_ARG); - append(opt_list, emulator); + prepend(opt_list, emulator); } static void create_cmd_list(LIST_NODE** cmd_list) { @@ -290,112 +289,119 @@ static void create_cmd_list(LIST_NODE** cmd_list) { COMMAND* devices_cmd = NULL; create_command(&devices_cmd, COMMANDLINE_DEVICES_NAME, COMMANDLINE_DEVICES_DESC, COMMANDLINE_DEVICES_DESC_SIZE, EMPTY_STRING, devices, COMMANDLINE_DEVICES_MAX_ARG, COMMANDLINE_DEVICES_MIN_ARG); - append(cmd_list, devices_cmd); + prepend(cmd_list, devices_cmd); COMMAND* connect_cmd = NULL; create_command(&connect_cmd, COMMANDLINE_CONNECT_NAME, COMMANDLINE_CONNECT_DESC, COMMANDLINE_CONNECT_DESC_SIZE, COMMANDLINE_CONNECT_ARG_DESC, __connect, COMMANDLINE_CONNECT_MAX_ARG, COMMANDLINE_CONNECT_MIN_ARG); - append(cmd_list, connect_cmd); + prepend(cmd_list, connect_cmd); + //TODO REMOTE_DEVICE_CONNECT security issue should be resolved first +#if 0 + COMMAND* device_con_cmd = NULL; + create_command(&device_con_cmd, COMMANDLINE_DEVICE_CON_NAME, COMMANDLINE_DEVICE_CON_DESC, + COMMANDLINE_DEVICE_CON_DESC_SIZE, COMMANDLINE_DEVICE_CON_ARG_DESC, device_con, COMMANDLINE_DEVICE_CON_MAX_ARG, COMMANDLINE_DEVICE_CON_MIN_ARG); + prepend(cmd_list, device_con_cmd); +#endif COMMAND* disconnect_cmd = NULL; create_command(&disconnect_cmd, COMMANDLINE_DISCONNECT_NAME, COMMANDLINE_DISCONNECT_DESC, COMMANDLINE_DISCONNECT_DESC_SIZE, COMMANDLINE_DISCONNECT_ARG_DESC, __disconnect, COMMANDLINE_DISCONNECT_MAX_ARG, COMMANDLINE_DISCONNECT_MIN_ARG); - append(cmd_list, disconnect_cmd); + prepend(cmd_list, disconnect_cmd); COMMAND* push_cmd = NULL; create_command(&push_cmd, COMMANDLINE_PUSH_NAME, COMMANDLINE_PUSH_DESC, COMMANDLINE_PUSH_DESC_SIZE, COMMANDLINE_PUSH_ARG_DESC, push, COMMANDLINE_PUSH_MAX_ARG, COMMANDLINE_PUSH_MIN_ARG); - append(cmd_list, push_cmd); + prepend(cmd_list, push_cmd); COMMAND* pull_cmd = NULL; create_command(&pull_cmd, COMMANDLINE_PULL_NAME, COMMANDLINE_PULL_DESC, COMMANDLINE_PULL_DESC_SIZE, COMMANDLINE_PULL_ARG_DESC, pull, COMMANDLINE_PULL_MAX_ARG, COMMANDLINE_PULL_MIN_ARG); - append(cmd_list, pull_cmd); + prepend(cmd_list, pull_cmd); COMMAND* shell_cmd = NULL; create_command(&shell_cmd, COMMANDLINE_SHELL_NAME, COMMANDLINE_SHELL_DESC, COMMANDLINE_SHELL_DESC_SIZE, COMMANDLINE_SHELL_ARG_DESC, shell, COMMANDLINE_SHELL_MAX_ARG, COMMANDLINE_SHELL_MIN_ARG); - append(cmd_list, shell_cmd); + prepend(cmd_list, shell_cmd); COMMAND* dlog_cmd = NULL; create_command(&dlog_cmd, COMMANDLINE_DLOG_NAME, COMMANDLINE_DLOG_DESC, COMMANDLINE_DLOG_DESC_SIZE, COMMANDLINE_DLOG_ARG_DESC, dlog, COMMANDLINE_DLOG_MAX_ARG, COMMANDLINE_DLOG_MIN_ARG); - append(cmd_list, dlog_cmd); + prepend(cmd_list, dlog_cmd); COMMAND* install_cmd = NULL; create_command(&install_cmd, COMMANDLINE_INSTALL_NAME, COMMANDLINE_INSTALL_DESC, COMMANDLINE_INSTALL_DESC_SIZE, COMMANDLINE_INSTALL_ARG_DESC, install, COMMANDLINE_INSTALL_MAX_ARG, COMMANDLINE_INSTALL_MIN_ARG); - append(cmd_list, install_cmd); + prepend(cmd_list, install_cmd); COMMAND* uninstall_cmd = NULL; create_command(&uninstall_cmd, COMMANDLINE_UNINSTALL_NAME, COMMANDLINE_UNINSTALL_DESC, COMMANDLINE_UNINSTALL_DESC_SIZE, COMMANDLINE_UNINSTALL_ARG_DESC, uninstall, COMMANDLINE_UNINSTALL_MAX_ARG, COMMANDLINE_UNINSTALL_MIN_ARG); - append(cmd_list, uninstall_cmd); + prepend(cmd_list, uninstall_cmd); COMMAND* forward_cmd = NULL; create_command(&forward_cmd, COMMANDLINE_FORWARD_NAME, COMMANDLINE_FORWARD_DESC, COMMANDLINE_FORWARD_DESC_SIZE, COMMANDLINE_FORWARD_ARG_DESC, forward, COMMANDLINE_FORWARD_MAX_ARG, COMMANDLINE_FORWARD_MIN_ARG); - append(cmd_list, forward_cmd); + prepend(cmd_list, forward_cmd); COMMAND* help_cmd = NULL; create_command(&help_cmd, COMMANDLINE_HELP_NAME, COMMANDLINE_HELP_DESC, COMMANDLINE_HELP_DESC_SIZE, EMPTY_STRING, NULL, 0, 0); - append(cmd_list, help_cmd); + prepend(cmd_list, help_cmd); COMMAND* version_cmd = NULL; create_command(&version_cmd, COMMANDLINE_VERSION_NAME, COMMANDLINE_VERSION_DESC, COMMANDLINE_VERSION_DESC_SIZE, EMPTY_STRING, version, COMMANDLINE_VERSION_MAX_ARG, COMMANDLINE_VERSION_MIN_ARG); - append(cmd_list, version_cmd); + prepend(cmd_list, version_cmd); COMMAND* sserver_cmd = NULL; create_command(&sserver_cmd, COMMANDLINE_SSERVER_NAME, COMMANDLINE_SSERVER_DESC, COMMANDLINE_SSERVER_DESC_SIZE, EMPTY_STRING, start_server, COMMANDLINE_SSERVER_MAX_ARG, COMMANDLINE_SSERVER_MIN_ARG); - append(cmd_list, sserver_cmd); + prepend(cmd_list, sserver_cmd); COMMAND* kserver_cmd = NULL; create_command(&kserver_cmd, COMMANDLINE_KSERVER_NAME, COMMANDLINE_KSERVER_DESC, COMMANDLINE_KSERVER_DESC_SIZE, EMPTY_STRING, kill_server, COMMANDLINE_KSERVER_MAX_ARG, COMMANDLINE_KSERVER_MIN_ARG); - append(cmd_list, kserver_cmd); + prepend(cmd_list, kserver_cmd); COMMAND* gstate_cmd = NULL; create_command(&gstate_cmd, COMMANDLINE_GSTATE_NAME, COMMANDLINE_GSTATE_DESC, COMMANDLINE_GSTATE_DESC_SIZE, EMPTY_STRING, get_state_serialno, COMMANDLINE_GSTATE_MAX_ARG, COMMANDLINE_GSTATE_MIN_ARG); - append(cmd_list, gstate_cmd); + prepend(cmd_list, gstate_cmd); COMMAND* gserial_cmd = NULL; create_command(&gserial_cmd, COMMANDLINE_GSERIAL_NAME, COMMANDLINE_GSERIAL_DESC, COMMANDLINE_GSERIAL_DESC_SIZE, EMPTY_STRING, get_state_serialno, COMMANDLINE_GSERIAL_MAX_ARG, COMMANDLINE_GSERIAL_MIN_ARG); - append(cmd_list, gserial_cmd); + prepend(cmd_list, gserial_cmd); COMMAND* swindow_cmd = NULL; create_command(&swindow_cmd, COMMANDLINE_SWINDOW_NAME, COMMANDLINE_SWINDOW_DESC, COMMANDLINE_SWINDOW_DESC_SIZE, EMPTY_STRING, status_window, COMMANDLINE_SWINDOW_MAX_ARG, COMMANDLINE_SWINDOW_MIN_ARG); - append(cmd_list, swindow_cmd); + prepend(cmd_list, swindow_cmd); COMMAND* root_cmd = NULL; create_command(&root_cmd, COMMANDLINE_ROOT_NAME, COMMANDLINE_ROOT_DESC, COMMANDLINE_ROOT_DESC_SIZE, COMMANDLINE_ROOT_ARG_DESC, root, COMMANDLINE_ROOT_MAX_ARG, COMMANDLINE_ROOT_MIN_ARG); - append(cmd_list, root_cmd); + prepend(cmd_list, root_cmd); COMMAND* launch_cmd = NULL; create_command(&launch_cmd, COMMANDLINE_LAUNCH_NAME, NULL, 0, EMPTY_STRING, launch, COMMANDLINE_LAUNCH_MAX_ARG, COMMANDLINE_LAUNCH_MIN_ARG); - append(cmd_list, launch_cmd); + prepend(cmd_list, launch_cmd); COMMAND* forkserver_cmd = NULL; create_command(&forkserver_cmd, COMMANDLINE_FORKSERVER_NAME, NULL, 0, EMPTY_STRING, forkserver, COMMANDLINE_FORKSERVER_MAX_ARG, COMMANDLINE_FORKSERVER_MIN_ARG); - append(cmd_list, forkserver_cmd); + prepend(cmd_list, forkserver_cmd); COMMAND* oprofile_cmd = NULL; create_command(&oprofile_cmd, COMMANDLINE_OPROFILE_NAME, NULL, 0, EMPTY_STRING, oprofile, COMMANDLINE_OPROFILE_MAX_ARG, COMMANDLINE_OPROFILE_MIN_ARG); - append(cmd_list, oprofile_cmd); + prepend(cmd_list, oprofile_cmd); COMMAND* da_cmd = NULL; create_command(&da_cmd , COMMANDLINE_DA_NAME, NULL, 0, EMPTY_STRING, da, COMMANDLINE_DA_MAX_ARG, COMMANDLINE_DA_MIN_ARG); - append(cmd_list, da_cmd ); + prepend(cmd_list, da_cmd ); } int process_cmdline(int argc, char** argv) { @@ -469,10 +475,16 @@ int process_cmdline(int argc, char** argv) { if(argc < minargs + 1) { fprintf(stderr, "%s command has following args: %s, and it requires at least %d arguments\n", argv[0], command->argdesc, minargs); + if (serial != NULL) { + free(serial); + } return 1; } if(argc > maxargs + 1 && maxargs > -1) { fprintf(stderr, "command %s require at most %d arguments\n", argv[0], maxargs); + if (serial != NULL) { + free(serial); + } return 1; } extraarg[0] = serial; @@ -485,6 +497,9 @@ int process_cmdline(int argc, char** argv) { } print_help(opt_list, cmd_list); + if (serial != NULL) { + free(serial); + } return 1; } @@ -501,6 +516,7 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) { char* help_str = (char*)malloc(sizeof(char)*append_len*3); while(curptr != NULL) { OPTION* opt = (OPTION*)curptr->data; + curptr = curptr->next_ptr; const char** des = opt->desc; if(des != NULL) { snprintf(help_str, append_len*3, " -%s, --%s %s", opt->shortopt, opt->longopt, opt->argdesc); @@ -512,21 +528,20 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) { snprintf(append_str, append_len - opt_len + 1, "%s", HELP_APPEND_STR); fprintf(stderr, "%s%s", help_str, append_str); } + int array_len = opt->desc_size; + fprintf(stderr, "- %s\n", des[0]); + int i = 1; + for(; i< array_len; i++) { + fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]); + } } - - int array_len = opt->desc_size; - fprintf(stderr, "- %s\n", des[0]); - int i = 1; - for(; i< array_len; i++) { - fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]); - } - curptr = curptr->next_ptr; } fprintf(stderr, "\n commands:\n"); curptr = cmdlist; while(curptr != NULL) { COMMAND* cmd = (COMMAND*)curptr ->data; + curptr = curptr->next_ptr; const char** des = cmd->desc; if(des != NULL) { snprintf(help_str, append_len*3, " sdb %s %s", cmd->name, cmd->argdesc); @@ -545,10 +560,10 @@ static void print_help(LIST_NODE* optlist, LIST_NODE* cmdlist) { fprintf(stderr, "%s %s\n", HELP_APPEND_STR, des[i]); } } - curptr = curptr->next_ptr; } - + free(append_str); + free(help_str); } diff --git a/src/common_modules.h b/src/common_modules.h new file mode 100644 index 0000000..260cb4f --- /dev/null +++ b/src/common_modules.h @@ -0,0 +1,143 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef COMMON_MODULES_H_ +#define COMMON_MODULES_H_ + +#include "linkedlist.h" +#include "fdevent.h" +#include "sdb_usb.h" + +#define MAX_PAYLOAD 4096 +#define CHUNK_SIZE (64*1024) +#define DEFAULT_SDB_PORT 26099 + +#define A_VERSION 0x0100000 + +#define SDB_VERSION_MAJOR 2 +#define SDB_VERSION_MINOR 2 + +#define SDB_SERVER_VERSION 6 + +extern MAP hex_map; + +typedef struct message MESSAGE; +struct message { + unsigned command; /* command identifier constant */ + unsigned arg0; /* first argument */ + unsigned arg1; /* second argument */ + unsigned data_length; /* length of payload (0 is allowed) */ + unsigned data_check; /* checksum of data payload */ + unsigned magic; /* command ^ 0xffffffff */ +}; + +typedef struct packet PACKET; +struct packet +{ + LIST_NODE* node; + + unsigned len; + void *ptr; + + MESSAGE msg; + unsigned char data[MAX_PAYLOAD]; +}; + +typedef enum transport_type { + kTransportUsb, + kTransportLocal, + kTransportAny, + kTransportRemoteDevCon +} transport_type; + +typedef struct transport TRANSPORT; +struct transport +{ + LIST_NODE* node; + //list for remote sockets which wait for CNXN + LIST_NODE* remote_cnxn_socket; + + int (*read_from_remote)(TRANSPORT* t, void* data, int len); + int (*write_to_remote)(PACKET *p, TRANSPORT *t); + void (*close)(TRANSPORT *t); + void (*kick)(TRANSPORT *t); + + int connection_state; + transport_type type; + + usb_handle *usb; + int sfd; + + char *serial; + int sdb_port; + char *device_name; + + int kicked; + unsigned req; + unsigned res; +}; + +typedef struct listener LISTENER; +struct listener +{ + LIST_NODE* node; + + FD_EVENT fde; + int fd; + + const char *local_name; + const char *connect_to; + TRANSPORT *transport; +}; + +typedef struct t_packet T_PACKET; +struct t_packet { + TRANSPORT* t; + PACKET* p; +}; + +typedef struct socket SDB_SOCKET; +struct socket { + int status; + LIST_NODE* node; + + unsigned local_id; + unsigned remote_id; + + int closing; + FD_EVENT fde; + int fd; + + LIST_NODE* pkt_list; + TRANSPORT *transport; + + PACKET* read_packet; +}; + +int readx(int fd, void *ptr, size_t len); +int writex(int fd, const void *ptr, size_t len); + +#endif /* SDB_TYPES_H_ */ diff --git a/src/device_vendors.c b/src/device_vendors.c new file mode 100644 index 0000000..5faa95e --- /dev/null +++ b/src/device_vendors.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "device_vendors.h" +#include "log.h" + + +VENDOR tizen_device_vendors[] = { + {"samsung", 0x04e8} //1256 +}; + + +void init_device_vendors(void) +{ + LOG_FIXME("should implement later\n"); + vendor_total_cnt = (sizeof(tizen_device_vendors)/sizeof(VENDOR)); +} diff --git a/src/device_vendors.h b/src/device_vendors.h new file mode 100644 index 0000000..476198b --- /dev/null +++ b/src/device_vendors.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DEVICE_VENDORS_H +#define __DEVICE_VENDORS_H + +#define VENDOR_COUNT_MAX 64 + +typedef struct +{ + const char *vendor; + int id; +} VENDOR; + +VENDOR tizen_device_vendors[VENDOR_COUNT_MAX]; + +unsigned vendor_total_cnt; + +void init_device_vendors(void); + +#endif diff --git a/src/fdevent.c b/src/fdevent.c old mode 100644 new mode 100755 index 32dd05f..826cb8f --- a/src/fdevent.c +++ b/src/fdevent.c @@ -28,214 +28,98 @@ #include "fdevent_backend.h" #include "transport.h" #include "utils.h" +#include "fdevent.h" +#include "log.h" -#if defined(OS_LINUX) -const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend; -#elif defined(OS_DARWIN) +#ifndef OS_WINDOWS +int max_select = 0; const struct fdevent_os_backend* fdevent_backend = &fdevent_unix_backend; -#elif defined(OS_WINDOWS) -const struct fdevent_os_backend* fdevent_backend = &fdevent_windows_backend; -#define WIN32_FH_BASE 100 #else -#error "unsupported OS" +const struct fdevent_os_backend* fdevent_backend = &fdevent_windows_backend; #endif -fdevent list_pending = { - .next = &list_pending, - .prev = &list_pending, -}; +#define TRACE_TAG TRACE_SDB -fdevent **fd_table = 0; -int fd_table_max = 0; - -void _fatal(const char *fn, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:", fn); - vfprintf(stderr, fmt, ap); - va_end(ap); - abort(); -} +MAP event_map; -void fdevent_register(fdevent *fde) -{ #if defined(OS_WINDOWS) - int fd = fde->fd - WIN32_FH_BASE; -#else - int fd = fde->fd; +MAP sdb_handle_map; +HANDLE socket_event_handle[WIN32_MAX_FHS]; +int event_location_to_fd[WIN32_MAX_FHS]; +int current_socket_location = 0; #endif +void fdevent_register(FD_EVENT *fde) +{ + int fd = fde->fd; + if(fd < 0) { - FATAL("bogus negative fd (%d)\n", fde->fd); + LOG_FATAL("bogus negative fd (%d)\n", fd); } - if(fd >= fd_table_max) { - int oldmax = fd_table_max; - if(fde->fd > 32000) { - FATAL("bogus huuuuge fd (%d)\n", fde->fd); - } - if(fd_table_max == 0) { - fdevent_backend->fdevent_init(); - fd_table_max = 256; - } - while(fd_table_max <= fd) { - fd_table_max *= 2; - } - fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max); - if(fd_table == 0) { - FATAL("could not expand fd_table to %d entries\n", fd_table_max); - } - memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax)); + if(fd > 32000) { + LOG_FATAL("bogus huuuuge FD(%d)\n", fd); + } + else { + fdevent_map_put(fd, fde); } - - fd_table[fd] = fde; } -void fdevent_unregister(fdevent *fde) +void fdevent_unregister(FD_EVENT *fde) { -#if defined(OS_WINDOWS) - int fd = fde->fd - WIN32_FH_BASE; -#else - int fd = fde->fd; -#endif - if((fd < 0) || (fd >= fd_table_max)) { - FATAL("fd out of range (%d)\n", fde->fd); - } + int fd = fde->fd; - if(fd_table[fd] != fde) { - FATAL("fd_table out of sync"); + if((fd < 0)) { + LOG_FATAL("fdevent out of range FD(%d)\n", fd); } - - fd_table[fd] = 0; - - if(!(fde->state & FDE_DONT_CLOSE)) { - dump_fde(fde, "close"); - sdb_close(fde->fd); + else if(fdevent_map_get(fd) != fde) { + LOG_FATAL("fd event out of sync"); } -} - -void fdevent_plist_enqueue(fdevent *node) -{ - fdevent *list = &list_pending; - - node->next = list; - node->prev = list->prev; - node->prev->next = node; - list->prev = node; -} - -void fdevent_plist_remove(fdevent *node) -{ - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; -} - -fdevent *fdevent_plist_dequeue(void) -{ - fdevent *list = &list_pending; - fdevent *node = list->next; - - if(node == list) return 0; - - list->next = node->next; - list->next->prev = list; - node->next = 0; - node->prev = 0; - - return node; -} - -fdevent *fdevent_create(int fd, fd_func func, void *arg) -{ - fdevent *fde = (fdevent*) malloc(sizeof(fdevent)); - if(fde == 0) return 0; - fdevent_install(fde, fd, func, arg); - fde->state |= FDE_CREATED; - return fde; -} - -void fdevent_destroy(fdevent *fde) -{ - if(fde == 0) return; - if(!(fde->state & FDE_CREATED)) { - FATAL("fde %p not created by fdevent_create()\n", fde); + else { + fdevent_map_remove(fd); + sdb_close(fde->fd); } - fdevent_remove(fde); } -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) +void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg) { - memset(fde, 0, sizeof(fdevent)); - fde->state = FDE_ACTIVE; + D("FD(%d)\n", fd); + memset(fde, 0, sizeof(FD_EVENT)); fde->fd = fd; - fde->force_eof = 0; fde->func = func; fde->arg = arg; + fde->events = 0; #ifndef OS_WINDOWS fcntl(fd, F_SETFL, O_NONBLOCK); + if(fd >= max_select) { + max_select = fd + 1; + } #endif fdevent_register(fde); - dump_fde(fde, "connect"); - fdevent_backend->fdevent_connect(fde); - fde->state |= FDE_ACTIVE; } -void fdevent_remove(fdevent *fde) +void fdevent_remove(FD_EVENT *fde) { - if(fde->state & FDE_PENDING) { - fdevent_plist_remove(fde); - } - - if(fde->state & FDE_ACTIVE) { - fdevent_backend->fdevent_disconnect(fde); - dump_fde(fde, "disconnect"); - fdevent_unregister(fde); - } - - fde->state = 0; + fdevent_backend->fdevent_disconnect(fde); + fdevent_unregister(fde); fde->events = 0; } - -void fdevent_set(fdevent *fde, unsigned events) -{ - events &= FDE_EVENTMASK; - - if((fde->state & FDE_EVENTMASK) == events) return; - - if(fde->state & FDE_ACTIVE) { - fdevent_backend->fdevent_update(fde, events); - dump_fde(fde, "update"); - } - - fde->state = (fde->state & FDE_STATEMASK) | events; - - if(fde->state & FDE_PENDING) { - /* if we're pending, make sure - ** we don't signal an event that - ** is no longer wanted. - */ - fde->events &= (~events); - if(fde->events == 0) { - fdevent_plist_remove(fde); - fde->state &= (~FDE_PENDING); - } - } -} - -void fdevent_add(fdevent *fde, unsigned events) { - fdevent_set(fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK)); +FD_EVENT* fdevent_map_get(int _key) { + MAP_KEY key; + key.key_int = _key; + return map_get(&event_map, key); } -void fdevent_del(fdevent *fde, unsigned events) { - fdevent_set(fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK))); +void fdevent_map_put(int _key, FD_EVENT* _value) { + MAP_KEY key; + key.key_int = _key; + map_put(&event_map, key, _value); } -void fdevent_loop() -{ - fdevent_backend->fdevent_loop(); +void fdevent_map_remove(int _key) { + MAP_KEY key; + key.key_int = _key; + map_remove(&event_map, key); } diff --git a/src/fdevent.h b/src/fdevent.h old mode 100644 new mode 100755 index 6bb2d4b..2e876be --- a/src/fdevent.h +++ b/src/fdevent.h @@ -18,74 +18,88 @@ #define __FDEVENT_H #include /* for int64_t */ +#include "linkedlist.h" +#include "sdb_map.h" /* events that may be observed */ -#define FDE_READ 0x0001 -#define FDE_WRITE 0x0002 -#define FDE_ERROR 0x0004 -#define FDE_TIMEOUT 0x0008 +#define FDE_READ 1 +#define FDE_WRITE 2 +#define FDE_MASK 3 -#define FDE_EVENTMASK 0x00ff -#define FDE_STATEMASK 0xff00 - -#define FDE_ACTIVE 0x0100 -#define FDE_PENDING 0x0200 -#define FDE_CREATED 0x0400 +typedef struct fd_event FD_EVENT; +typedef void (*fd_func)(int fd, unsigned events, void *userdata); -/* features that may be set (via the events set/add/del interface) */ -#define FDE_DONT_CLOSE 0x0080 +struct fd_event +{ + LIST_NODE* node; -typedef struct fdevent fdevent; + int fd; + unsigned events; -typedef void (*fd_func)(int fd, unsigned events, void *userdata); + fd_func func; + void *arg; +}; -/* Allocate and initialize a new fdevent object - * Note: use FD_TIMER as 'fd' to create a fd-less object - * (used to implement timers). -*/ -fdevent *fdevent_create(int fd, fd_func func, void *arg); +int fdevent_wakeup_send; +int fdevent_wakeup_recv; -/* Uninitialize and deallocate an fdevent object that was -** created by fdevent_create() -*/ -void fdevent_destroy(fdevent *fde); +FD_EVENT fdevent_wakeup_fde; /* Initialize an fdevent object that was externally allocated */ -void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg); +void fdevent_install(FD_EVENT *fde, int fd, fd_func func, void *arg); /* Uninitialize an fdevent object that was initialized by ** fdevent_install() */ -void fdevent_remove(fdevent *item); +void fdevent_remove(FD_EVENT *item); -/* Change which events should cause notifications -*/ -void fdevent_set(fdevent *fde, unsigned events); -void fdevent_add(fdevent *fde, unsigned events); -void fdevent_del(fdevent *fde, unsigned events); +#define EVENT_MAP_SIZE 256 -void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms); +extern MAP event_map; -/* loop forever, handling events. +FD_EVENT* fdevent_map_get(int key); +void fdevent_map_put(int key, FD_EVENT* value); +void fdevent_map_remove(int key); + +/* Change which events should cause notifications */ -void fdevent_loop(); -struct fdevent -{ - fdevent *next; - fdevent *prev; +#define FDEVENT_SET(fde, events) \ + fdevent_backend->fdevent_update(fde, events) - int fd; - int force_eof; +#define FDEVENT_ADD(fde, _events) \ + fdevent_backend->fdevent_update(fde, (fde)->events | _events) - unsigned short state; - unsigned short events; +#define FDEVENT_DEL(fde, _events) \ + fdevent_backend->fdevent_update(fde, (fde)->events & ~_events) - fd_func func; - void *arg; +#define FDEVENT_LOOP() \ + fdevent_backend->fdevent_loop() + +struct fdevent_os_backend { + void (*fdevent_loop)(void); + void (*fdevent_disconnect)(FD_EVENT *fde); + void (*fdevent_update)(FD_EVENT *fde, unsigned events); }; +extern const struct fdevent_os_backend* fdevent_backend; +#ifndef OS_WINDOWS +extern int max_select; +extern const struct fdevent_os_backend fdevent_unix_backend; +#else +extern const struct fdevent_os_backend fdevent_windows_backend; +#endif + +#if defined(OS_WINDOWS) +#include + +#define WIN32_MAX_FHS 128 +extern MAP sdb_handle_map; +extern HANDLE socket_event_handle[]; +extern int event_location_to_fd[]; +extern int current_socket_location; +#endif #endif diff --git a/src/fdevent_backend.h b/src/fdevent_backend.h old mode 100644 new mode 100755 index 3213f58..851243b --- a/src/fdevent_backend.h +++ b/src/fdevent_backend.h @@ -17,45 +17,11 @@ #define __FDEVENT_I_H #include "fdevent.h" - -extern fdevent list_pending; -extern fdevent **fd_table; +extern FD_EVENT **fd_table; extern int fd_table_max; -void fdevent_plist_enqueue(fdevent *node); -void fdevent_plist_remove(fdevent *node); -fdevent *fdevent_plist_dequeue(void); -void fdevent_register(fdevent *fde); -void fdevent_unregister(fdevent *fde); - -void _fatal(const char *fn, const char *fmt, ...); -#define FATAL(x...) _fatal(__FUNCTION__, x) - -#if DEBUG -void dump_fde(fdevent *fde, const char *info) -{ - fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd, - fde->state & FDE_READ ? 'R' : ' ', - fde->state & FDE_WRITE ? 'W' : ' ', - fde->state & FDE_ERROR ? 'E' : ' ', - info); -} -#else -#define dump_fde(fde, info) do { } while(0) -#endif - -struct fdevent_os_backend { - // human-readable name - const char *name; - void (*fdevent_loop)(void); - void (*fdevent_init)(void); - void (*fdevent_connect)(fdevent *fde); - void (*fdevent_disconnect)(fdevent *fde); - void (*fdevent_update)(fdevent *fde, unsigned events); -}; - -extern const struct fdevent_os_backend* fdevent_backend; -extern const struct fdevent_os_backend fdevent_unix_backend; -extern const struct fdevent_os_backend fdevent_windows_backend; +FD_EVENT *fdevent_plist_dequeue(void); +void fdevent_register(FD_EVENT *fde); +void fdevent_unregister(FD_EVENT *fde); #endif diff --git a/src/fdevent_unix.c b/src/fdevent_unix.c old mode 100644 new mode 100755 index d5b6807..01f5baa --- a/src/fdevent_unix.c +++ b/src/fdevent_unix.c @@ -30,8 +30,8 @@ #include "fdevent_backend.h" #include "transport.h" #include "utils.h" +#include "log.h" -#define D(...) ((void)0) // This socket is used when a subproc shell service exists. // It wakes up the fdevent_loop() and cause the correct handling // of the shell's pseudo-tty master. I.e. force close it. @@ -39,293 +39,112 @@ int SHELL_EXIT_NOTIFY_FD = -1; #include +#define FD_CLR_ALL(fde) \ + FD_CLR(fde->fd, &fds_read); \ + FD_CLR(fde->fd, &fds_write); -static fd_set read_fds; -static fd_set write_fds; -static fd_set error_fds; +static fd_set fds_write; +static fd_set fds_read; -static int select_n = 0; - -static void _fdevent_init(void) -{ - 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 diff --git a/src/fdevent_windows.c b/src/fdevent_windows.c old mode 100644 new mode 100755 index 5f750a4..60ee720 --- a/src/fdevent_windows.c +++ b/src/fdevent_windows.c @@ -31,300 +31,161 @@ #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 diff --git a/src/file_sync_client.c b/src/file_sync_client.c index e2c9d8f..dcd199a 100644 --- a/src/file_sync_client.c +++ b/src/file_sync_client.c @@ -34,7 +34,7 @@ #include "utils.h" #include "strutils.h" #include "fdevent.h" -#include "sdb.h" +#include "log.h" static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC* dstF); @@ -49,36 +49,35 @@ static __inline__ void finalize(int srcfd, int dstfd, FILE_FUNC* srcF, FILE_FUNC dstF->finalize(dstfd); } -static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes) { +static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, unsigned* total_bytes, struct stat* src_stat, char* copy_flag) { D("file is copied from 'fd:%d' '%s' to 'fd:%d' '%s'\n", src_fd, srcp, dst_fd, dstp); - void* srcstat; - if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) { - return -1; - } - src_fd = srcF->readopen(src_fd, srcp, srcstat); + unsigned file_byte = src_stat->st_size; + unsigned written_byte = 0; + + src_fd = srcF->readopen(src_fd, srcp, src_stat); if(src_fd < 0) { return -1; } - dst_fd = dstF->writeopen(dst_fd, dstp, srcstat); + dst_fd = dstF->writeopen(dst_fd, dstp, src_stat); if(dst_fd < 0) { return -1; } FILE_BUFFER srcbuf; - srcbuf.id = ID_DATA; + srcbuf.id = sync_data; while(1) { - int ret = srcF->readfile(src_fd, srcp, srcstat, &srcbuf); + int ret = srcF->readfile(src_fd, srcp, src_stat, &srcbuf); if(ret == 0) { break; } else if(ret == 1) { - ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes); + ret = dstF->writefile(dst_fd, dstp, &srcbuf, &written_byte); if(ret < 0) { srcF->readclose(src_fd); - dstF->writeclose(dst_fd, dstp, srcstat); + dstF->writeclose(dst_fd, dstp, src_stat); return -1; } } @@ -86,27 +85,31 @@ static int file_copy(int src_fd, int dst_fd, char* srcp, char* dstp, FILE_FUNC* continue; } else if(ret == 3) { - ret = dstF->writefile(dst_fd, dstp, &srcbuf, total_bytes); + ret = dstF->writefile(dst_fd, dstp, &srcbuf, &written_byte); if(ret < 0) { srcF->readclose(src_fd); - dstF->writeclose(dst_fd, dstp, srcstat); + dstF->writeclose(dst_fd, dstp, src_stat); return -1; } break; } else { srcF->readclose(src_fd); - dstF->writeclose(dst_fd, dstp, srcstat); + dstF->writeclose(dst_fd, dstp, src_stat); if(ret == 4) { return 0; } return -1; } + //TODO pull / push progress bar + //fprintf(stderr,"%s [%u / %u]: %s -> %s \r", copy_flag, written_byte, file_byte, srcp, dstp); } - if(srcF->readclose(src_fd) < 0 || dstF->writeclose(dst_fd, dstp, srcstat) < 0) { + if(srcF->readclose(src_fd) < 0 || dstF->writeclose(dst_fd, dstp, src_stat) < 0) { return -1; } - free(srcstat); + + fprintf(stderr,"%s: %s -> %s \n", copy_flag, srcp, dstp); + *total_bytes = *total_bytes + written_byte; return 1; } @@ -115,16 +118,27 @@ static void free_copyinfo(void* data) { if(info != NULL) { if(info->src != NULL) { free(info->src); + info->src = NULL; } if(info->dst != NULL) { free(info->dst); + info->dst = NULL; } free(info); + info = NULL; } } int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int is_utf8, void** ext_argv) { + char copy_flag[7]; + if(srcF->local) { + snprintf(copy_flag, sizeof(copy_flag), "%s", "pushed"); + } + else { + snprintf(copy_flag, sizeof(copy_flag), "%s", "pulled"); + } + D("copy %s to the %s\n", srcp, dstp); unsigned total_bytes = 0; long long start_time = NOW(); @@ -132,8 +146,6 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i int src_fd = 0; int dst_fd = 0; - void* srcstat = NULL; - void* dststat = NULL; int pushed = 0; int skiped = 0; src_fd = srcF->initialize(srcp, ext_argv); @@ -141,15 +153,19 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i if(src_fd < 0 || dst_fd < 0) { return 1; } - if(srcF->_stat(src_fd, srcp, &srcstat, 1) < 0) { + + struct stat src_stat; + struct stat dst_stat; + + if(srcF->_stat(src_fd, srcp, &src_stat, 1) < 0) { finalize(src_fd, dst_fd, srcF, dstF); return 1; } - int src_dir = srcF->is_dir(srcp, srcstat, 1); + int src_dir = srcF->is_dir(srcp, &src_stat, 1); int dst_dir = 0; - if(dstF->_stat(dst_fd, dstp, &dststat, 0) >= 0) { - dst_dir = dstF->is_dir(dstp, dststat, 0); + if(dstF->_stat(dst_fd, dstp, &dst_stat, 0) >= 0) { + dst_dir = dstF->is_dir(dstp, &dst_stat, 0); } else { int dst_len = strlen(dstp); @@ -157,9 +173,9 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i dst_dir = 1; } } - free(dststat); - free(srcstat); + if(src_dir == -1 || dst_dir == -1) { + LOG_ERROR("src_dir: %d, dst_dir %d\n", src_dir, dst_dir); finalize(src_fd, dst_fd, srcF, dstF); return 1; } @@ -167,9 +183,9 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i /* if we're copying a local file to a remote directory, ** we *really* want to copy to remotedir + "/" + localfilename */ + char full_dstpath[PATH_MAX]; if(dst_dir == 1) { char* src_filename = get_filename(srcp); - char full_dstpath[PATH_MAX]; append_file(full_dstpath, dstp, src_filename); if(is_utf8 != 0) { @@ -179,12 +195,13 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i dstp = full_dstpath; } } - int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes); + int result = file_copy(src_fd, dst_fd, srcp, dstp, srcF, dstF, &total_bytes, &src_stat, copy_flag); if(result == 1) { pushed++; } else { + fprintf(stderr,"skipped: %s -> %s\n", srcp, dstp); skiped++; } } @@ -221,13 +238,12 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i char* src_p = (char*)info->src; char* dst_p = (char*)info->dst; - if(srcF->_stat(src_fd, src_p, &srcstat, 1) < 0) { + if(srcF->_stat(src_fd, src_p, &src_stat, 1) < 0) { finalize(src_fd, dst_fd, srcF, dstF); return 1; } - src_dir = srcF->is_dir(src_p, srcstat, 1); - free(srcstat); + src_dir = srcF->is_dir(src_p, &src_stat, 1); if(src_dir < 0) { finalize(src_fd, dst_fd, srcF, dstF); return 1; @@ -237,13 +253,13 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i } else { if(src_dir == 0) { - fprintf(stderr,"push: %s -> %s\n", src_p, dst_p); - int result = file_copy(src_fd, dst_fd, src_p, dst_p, srcF, dstF, &total_bytes); + int result = file_copy(src_fd, dst_fd, src_p, dst_p, srcF, dstF, &total_bytes, &src_stat, copy_flag); if(result == 1) { pushed++; } else { + fprintf(stderr,"skipped: %s -> %s\n", src_p, dst_p); skiped++; } } @@ -261,14 +277,8 @@ int do_sync_copy(char* srcp, char* dstp, FILE_FUNC* srcF, FILE_FUNC* dstF, int i } } - if(srcF == &REMOTE_FILE_FUNC) { - fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n", - pushed, "pulled", skiped); - } - else { - fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n", - pushed, "pushed", skiped); - } + fprintf(stderr,"%d file(s) %s. %d file(s) skipped.\n", + pushed, copy_flag, skiped); long long end_time = NOW() - start_time; diff --git a/src/file_sync_functions.c b/src/file_sync_functions.c index baceb3b..d4013e6 100644 --- a/src/file_sync_functions.c +++ b/src/file_sync_functions.c @@ -34,12 +34,25 @@ #include "linkedlist.h" #include "strutils.h" #include "file_sync_client.h" +#include "log.h" + +const unsigned sync_stat = MKSYNC('S','T','A','T'); +const unsigned sync_list = MKSYNC('L','I','S','T'); +const unsigned sync_send = MKSYNC('S','E','N','D'); +const unsigned sync_recv = MKSYNC('R','E','C','V'); +const unsigned sync_dent = MKSYNC('D','E','N','T'); +const unsigned sync_done = MKSYNC('D','O','N','E'); +const unsigned sync_data = MKSYNC('D','A','T','A'); +const unsigned sync_okay = MKSYNC('O','K','A','Y'); +const unsigned sync_fail = MKSYNC('F','A','I','L'); +const unsigned sync_quit = MKSYNC('Q','U','I','T'); const FILE_FUNC LOCAL_FILE_FUNC = { + 1, initialize_local, finalize_local, _stat_local, - is_directory_local, + is_directory_common, readopen_local, readclose_local, writeopen_local, @@ -50,10 +63,11 @@ const FILE_FUNC LOCAL_FILE_FUNC = { }; const FILE_FUNC REMOTE_FILE_FUNC = { + 0, initialize_remote, finalize_remote, _stat_remote, - is_directory_remote, + is_directory_common, readopen_remote, readclose_remote, writeopen_remote, @@ -63,18 +77,18 @@ const FILE_FUNC REMOTE_FILE_FUNC = { getdirlist_remote, }; -static int sync_readmode(int fd, const char *path, unsigned *mode); +static int sync_readstat(int fd, const char *path, struct stat* st); //return > 0 fd, = 0 success, < 0 fail. int initialize_local(char* path, void** extargv) { - D("initialize local file '%s'", path); + D("initialize local file '%s'\n", path); return 0; } //return fd int initialize_remote(char* path, void** extargv) { - D("initialize remote file '%s'", path); + D("initialize remote file '%s'\n", path); int fd = sdb_connect("sync:", extargv); if(fd < 0) { @@ -86,14 +100,14 @@ int initialize_remote(char* path, void** extargv) { } void finalize_local(int fd) { - D("finalize local fd '%d'", fd); + D("finalize local fd '%d'\n", fd); } void finalize_remote(int fd) { - D("finalize remote fd '%d'", fd); - syncmsg msg; + D("finalize remote fd '%d'\n", fd); + SYNC_MSG msg; - msg.req.id = ID_QUIT; + msg.req.id = sync_quit; msg.req.namelen = 0; writex(fd, &msg.req, sizeof(msg.req)); @@ -103,40 +117,36 @@ void finalize_remote(int fd) { } } -//TODO stat should be freed. -int _stat_local(int fd, char* path, void** _stat, int show_error) { - D("stat local file 'fd:%d' '%s'", fd, path); - struct stat* st = (struct stat*)malloc(sizeof(struct stat)); +int _stat_local(int fd, char* path, struct stat* st, int show_error) { + + D("stat local file 'fd:%d' '%s'\n", fd, path); if(stat(path, st)) { if(show_error) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); } + st->st_mode = 0; return -1; } - *_stat = st; return 1; } -int _stat_remote(int fd, char* path, void** stat, int show_error) { +int _stat_remote(int fd, char* path, struct stat* st, int show_error) { - D("stat remote file 'fd:%d' '%s'", fd, path); - unsigned* mode = (unsigned*)malloc(sizeof(unsigned)); - if(sync_readmode(fd, path, mode)) { + D("stat remote file 'fd:%d' '%s'\n", fd, path); + if(sync_readstat(fd, path, st)) { if(show_error) { fprintf(stderr,"cannot read mode '%s': %s\n", path, strerror(errno)); } + st->st_mode = 0; return -1; } - *stat = mode; return 1; } -int is_directory_local(char* path, void* stat, int show_error) { - struct stat* st = (struct stat*)stat; - - if(st == NULL) { +int is_directory_common(char* path, struct stat* st, int show_error) { + if(st->st_mode == 0) { if(show_error) { fprintf(stderr,"'%s': No such file or directory\n", path); } @@ -153,29 +163,10 @@ int is_directory_local(char* path, void* stat, int show_error) { return 2; } -int is_directory_remote(char* path, void* stat, int show_error) { - int* mode = (int*)stat; - - if(mode == NULL) { - if(show_error) { - fprintf(stderr,"'%s': No such file or directory\n", path); - } - return -1; - } - if(S_ISREG(*mode) || S_ISLNK(*mode)) { - return 0; - } - if(S_ISDIR(*mode)) { - return 1; - } - return 2; -} - //return fd. -int readopen_local(int fd, char* srcp, void* srcstat) { +int readopen_local(int fd, char* srcp, struct stat* st) { - D("read open local file 'fd:%d' '%s'", fd, srcp); - struct stat* st = srcstat; + D("read open local file 'fd:%d' '%s'\n", fd, srcp); if(S_ISREG(st->st_mode)) { fd = sdb_open(srcp, O_RDONLY); @@ -190,9 +181,9 @@ int readopen_local(int fd, char* srcp, void* srcstat) { return fd; } -int readopen_remote(int fd, char* srcp, void* srcstat) { - D("read open remote file 'fd:%d' '%s'", fd, srcp); - syncmsg msg; +int readopen_remote(int fd, char* srcp, struct stat* st) { + D("read open remote file 'fd:%d' '%s'\n", fd, srcp); + SYNC_MSG msg; int len; len = strlen(srcp); @@ -201,7 +192,7 @@ int readopen_remote(int fd, char* srcp, void* srcstat) { return -1; } - msg.req.id = ID_RECV; + msg.req.id = sync_recv; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, srcp, len)) { @@ -212,7 +203,7 @@ int readopen_remote(int fd, char* srcp, void* srcstat) { } int readclose_local(int lfd) { - D("read close local file 'fd:%d'", lfd); + D("read close local file 'fd:%d'\n", lfd); if(lfd > 0) { sdb_close(lfd); } @@ -220,13 +211,13 @@ int readclose_local(int lfd) { } int readclose_remote(int fd) { - D("read close remote file 'fd:%d'", fd); + D("read close remote file 'fd:%d'\n", fd); return fd; } -int writeopen_local(int fd, char* dstp, void* stat) { - D("write open local file 'fd:%d' '%s'", fd, dstp); - sdb_unlink(dstp); +int writeopen_local(int fd, char* dstp, struct stat* st) { + D("write open local file 'fd:%d' '%s'\n", fd, dstp); + unix_unlink(dstp); mkdirs(dstp); fd = sdb_creat(dstp, 0644); @@ -239,10 +230,9 @@ int writeopen_local(int fd, char* dstp, void* stat) { } //return fd. -int writeopen_remote(int fd, char* dstp, void* stat) { - D("write open remote file 'fd:%d' '%s'", fd, dstp); - syncmsg msg; - struct stat* st = (struct stat*)stat; +int writeopen_remote(int fd, char* dstp, struct stat* st) { + D("write open remote file 'fd:%d' '%s'\n", fd, dstp); + SYNC_MSG msg; int len, r; int total_len; @@ -258,7 +248,7 @@ int writeopen_remote(int fd, char* dstp, void* stat) { return -1; } - msg.req.id = ID_SEND; + msg.req.id = sync_send; msg.req.namelen = htoll(total_len); if(writex(fd, &msg.req, sizeof(msg.req)) || @@ -271,19 +261,18 @@ int writeopen_remote(int fd, char* dstp, void* stat) { return fd; } -int writeclose_local(int fd, char*dstp, void* stat) { - D("write close local file 'fd:%d' '%s'", fd, dstp); +int writeclose_local(int fd, char*dstp, struct stat* st) { + D("write close local file 'fd:%d' '%s'\n", fd, dstp); if(fd > 0) { sdb_close(fd); } return fd; } -int writeclose_remote(int fd, char* dstp, void* stat) { - D("write close remote file 'fd:%d' '%s'", fd, dstp); - struct stat* st = (struct stat*)stat; - syncmsg msg; - msg.data.id = ID_DONE; +int writeclose_remote(int fd, char* dstp, struct stat* st) { + D("write close remote file 'fd:%d' '%s'\n", fd, dstp); + SYNC_MSG msg; + msg.data.id = sync_done; msg.data.size = htoll(st->st_mtime); if(writex(fd, &msg.data, sizeof(msg.data))) { @@ -296,9 +285,9 @@ int writeclose_remote(int fd, char* dstp, void* stat) { return -1; } - if(msg.status.id != ID_OKAY) { + if(msg.status.id != sync_okay) { char buf[256]; - if(msg.status.id == ID_FAIL) { + if(msg.status.id == sync_fail) { int len = ltohl(msg.status.msglen); if(len > 256) { len = 255; @@ -325,9 +314,8 @@ int writeclose_remote(int fd, char* dstp, void* stat) { //-1:fail //1: write and continue load //3: write and stop -int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) { - D("read local file 'fd:%d' '%s'", lfd, srcpath); - struct stat* st = (struct stat*)stat; +int readfile_local(int lfd, char* srcpath, struct stat* st, FILE_BUFFER* sbuf) { + D("read local file 'fd:%d' '%s'\n", lfd, srcpath); if (S_ISREG(st->st_mode)) { int ret; @@ -375,9 +363,9 @@ int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf) { return -1; } -int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) { - D("read remote file 'fd:%d' '%s'", fd, srcpath); - syncmsg msg; +int readfile_remote(int fd, char* srcpath, struct stat* st, FILE_BUFFER* buffer) { + D("read remote file 'fd:%d' '%s'\n", fd, srcpath); + SYNC_MSG msg; unsigned id; if(readx(fd, &(msg.data), sizeof(msg.data))) { @@ -387,14 +375,14 @@ int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) { id = msg.data.id; buffer->size = ltohl(msg.data.size); - if(id == ID_DONE) { + if(id == sync_done) { //Finish normally. return 0; } //fail - if(id != ID_DATA) { - int len; - if(id == ID_FAIL) { + if(id != sync_data) { + int len = 0; + if(id == sync_fail) { int len = buffer->size; if(len > 256) { len = 255; @@ -430,7 +418,7 @@ int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer) { } int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) { - D("write local file 'fd:%d' '%s'", fd, dstp); + D("write local file 'fd:%d' '%s'\n", fd, dstp); char* data = sbuf->data; unsigned len = sbuf->size; @@ -444,7 +432,7 @@ int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes } int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes) { - D("write remote file 'fd:%d' '%s'", fd, dstp); + D("write remote file 'fd:%d' '%s'\n", fd, dstp); int size = ltohl(sbuf->size); if(writex(fd, sbuf, sizeof(unsigned)*2 + size)) { @@ -457,7 +445,7 @@ int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_byte } int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) { - D("get list of local file 'fd:%d' '%s'", fd, src_dir); + D("get list of local file 'fd:%d' '%s'\n", fd, src_dir); DIR* d; d = opendir(src_dir); @@ -488,7 +476,7 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) COPY_INFO* info; create_copy_info(&info, src_full_path, dst_full_path); - append(dirlist, info); + prepend(dirlist, info); } closedir(d); @@ -496,8 +484,8 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) } int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) { - D("get list of remote file 'fd:%d' '%s'", fd, src_dir); - syncmsg msg; + D("get list of remote file 'fd:%d' '%s'\n", fd, src_dir); + SYNC_MSG msg; int len; len = strlen(src_dir); @@ -507,36 +495,36 @@ int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) return -1; } - msg.req.id = ID_LIST; + msg.req.id = sync_list; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, src_dir, len)) { - fprintf(stderr,"cannot request directory entry: '%s'", src_dir); + fprintf(stderr,"cannot request directory entry: '%s'\n", src_dir); return -1; } while(1) { if(readx(fd, &msg.dent, sizeof(msg.dent))) { - fprintf(stderr,"cannot read dirlist: '%s'", src_dir); + fprintf(stderr,"cannot read dirlist: '%s'\n", src_dir); return -1; } - if(msg.dent.id == ID_DONE) { + if(msg.dent.id == sync_done) { return fd; } - if(msg.dent.id != ID_DENT) { - fprintf(stderr,"received dent msg '%d' is not DENT", msg.dent.id); + if(msg.dent.id != sync_dent) { + fprintf(stderr,"received dent msg '%d' is not DENT\n", msg.dent.id); return -1; } len = ltohl(msg.dent.namelen); if(len > 256) { - fprintf(stderr,"some file in the remote '%s' exceeds 256", src_dir); + fprintf(stderr,"some file in the remote '%s' exceeds 256\n", src_dir); return -1; } char file_name[257]; if(readx(fd, file_name, len)) { - fprintf(stderr,"cannot read file in the remote directory '%s'", src_dir); + fprintf(stderr,"cannot read file in the remote directory '%s'\n", src_dir); return -1; } file_name[len] = 0; @@ -558,27 +546,39 @@ int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist) COPY_INFO* info; create_copy_info(&info, src_full_path, dst_full_path); - append(dirlist, info); + prepend(dirlist, info); + D("!!!!!!!!!!!!!!!!!!!\n"); } + D("getting list of remote file 'fd:%d' '%s' is done\n", fd, src_dir); return fd; } -static int sync_readmode(int fd, const char *path, unsigned *mode) { - syncmsg msg; +static int sync_readstat(int fd, const char *path, struct stat* st) { + SYNC_MSG msg; int len = strlen(path); - msg.req.id = ID_STAT; + msg.req.id = sync_stat; msg.req.namelen = htoll(len); if(writex(fd, &msg.req, sizeof(msg.req)) || writex(fd, path, len)) { + LOG_ERROR("fail to send request ID_STAT with name length %d\n", len); return -1; } + if(readx(fd, &msg.stat, sizeof(msg.stat))) { + LOG_ERROR("fail to read response of ID_STAT with name length %d\n", len); return -1; } - if(msg.stat.id != ID_STAT) { + if(msg.stat.id != sync_stat) { + return -1; + } + st->st_mode = ltohl(msg.stat.mode); + + if(!st->st_mode) { + LOG_ERROR("fail to stat remote file: '%s'", path); return -1; } - *mode = ltohl(msg.stat.mode); + st->st_size = ltohl(msg.stat.size); + D("remote stat: mode %u, size %u\n", st->st_mode, st->st_size); return 0; } diff --git a/src/file_sync_functions.h b/src/file_sync_functions.h index ddba671..6897c90 100644 --- a/src/file_sync_functions.h +++ b/src/file_sync_functions.h @@ -29,6 +29,7 @@ #define TRACE_TAG TRACE_SDB +#include #include "file_sync_service.h" #include "linkedlist.h" @@ -51,26 +52,25 @@ int initialize_remote(char* path, void** extargv); void finalize_local(int fd); void finalize_remote(int fd); -int _stat_local(int fd, char* path, void** _stat, int show_error); -int _stat_remote(int fd, char* path, void** stat, int show_error); +int _stat_local(int fd, char* path, struct stat* st, int show_error); +int _stat_remote(int fd, char* path, struct stat* st, int show_error); -int is_directory_local(char* path, void* stat, int show_error); -int is_directory_remote(char* path, void* stat, int show_error); +int is_directory_common(char* path, struct stat* st, int show_error); -int readopen_local(int fd, char* srcp, void* srcstat); -int readopen_remote(int fd, char* srcp, void* srcstat); +int readopen_local(int fd, char* srcp, struct stat* st); +int readopen_remote(int fd, char* srcp, struct stat* st); int readclose_local(int lfd); int readclose_remote(int fd); -int writeopen_local(int fd, char* dstp, void* stat); -int writeopen_remote(int fd, char* dstp, void* stat); +int writeopen_local(int fd, char* dstp, struct stat* st); +int writeopen_remote(int fd, char* dstp, struct stat* st); -int writeclose_local(int fd, char*dstp, void* stat); -int writeclose_remote(int fd, char* dstp, void* stat); +int writeclose_local(int fd, char*dstp, struct stat* st); +int writeclose_remote(int fd, char* dstp, struct stat* st); -int readfile_local(int lfd, char* srcpath, void* stat, FILE_BUFFER* sbuf); -int readfile_remote(int fd, char* srcpath, void* stat, FILE_BUFFER* buffer); +int readfile_local(int lfd, char* srcpath, struct stat* st, FILE_BUFFER* sbuf); +int readfile_remote(int fd, char* srcpath, struct stat* st, FILE_BUFFER* buffer); int writefile_local(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes); int writefile_remote(int fd, char* dstp, FILE_BUFFER* sbuf, unsigned* total_bytes); @@ -79,21 +79,22 @@ int getdirlist_local(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist); int getdirlist_remote(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist); struct file_function { + int local; int(*initialize)(char* path, void** extargv); void(*finalize)(int fd); - int(*_stat)(int fd, char* path, void** stat, int show_error); - int(*is_dir)(char* path, void* stat, int show_error); - int(*readopen)(int fd, char* dstp, void* stat); + int(*_stat)(int fd, char* path, struct stat* st, int show_error); + int(*is_dir)(char* path, struct stat* st, int show_error); + int(*readopen)(int fd, char* dstp, struct stat* st); int(*readclose)(int fd); - int(*writeopen)(int fd, char* dstp, void* stat); - int(*writeclose)(int fd, char* dstp, void* stat); - int(*readfile)(int fd, char* path, void* stat, FILE_BUFFER* buf); + int(*writeopen)(int fd, char* dstp, struct stat* st); + int(*writeclose)(int fd, char* dstp, struct stat* st); + int(*readfile)(int fd, char* path, struct stat* st, FILE_BUFFER* buf); int(*writefile)(int fd, char* path, FILE_BUFFER* buf, unsigned* total_bytes); int(*get_dirlist)(int fd, char* src_dir, char* dst_dir, LIST_NODE** dirlist); }; typedef struct file_function FILE_FUNC; -const FILE_FUNC LOCAL_FILE_FUNC; -const FILE_FUNC REMOTE_FILE_FUNC; +extern const FILE_FUNC LOCAL_FILE_FUNC; +extern const FILE_FUNC REMOTE_FILE_FUNC; #endif /* FILE_SYNC_FUNCTIONS_H_ */ diff --git a/src/file_sync_service.h b/src/file_sync_service.h old mode 100644 new mode 100755 index 6f01979..50de665 --- a/src/file_sync_service.h +++ b/src/file_sync_service.h @@ -17,70 +17,64 @@ #ifndef _FILE_SYNC_SERVICE_H_ #define _FILE_SYNC_SERVICE_H_ -#ifdef HAVE_BIG_ENDIAN -static inline unsigned __swap_uint32(unsigned x) -{ - return (((x) & 0xFF000000) >> 24) - | (((x) & 0x00FF0000) >> 8) - | (((x) & 0x0000FF00) << 8) - | (((x) & 0x000000FF) << 24); -} -#define htoll(x) __swap_uint32(x) -#define ltohl(x) __swap_uint32(x) -#define MKID(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((a) << 24)) -#else #define htoll(x) (x) #define ltohl(x) (x) -#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) -#endif +#define MKSYNC(a,b,c,d) ( (d << 24) | (c << 16) | (b << 8) | a ) + +extern const unsigned sync_stat; +extern const unsigned sync_list; +extern const unsigned sync_send; +extern const unsigned sync_recv; +extern const unsigned sync_dent; +extern const unsigned sync_done; +extern const unsigned sync_data; +extern const unsigned sync_okay; +extern const unsigned sync_fail; +extern const unsigned sync_quit; + +typedef struct req REQ; +struct req { + unsigned id; + unsigned namelen; +}; -#define ID_STAT MKID('S','T','A','T') -#define ID_LIST MKID('L','I','S','T') -#define ID_ULNK MKID('U','L','N','K') -#define ID_SEND MKID('S','E','N','D') -#define ID_RECV MKID('R','E','C','V') -#define ID_DENT MKID('D','E','N','T') -#define ID_DONE MKID('D','O','N','E') -#define ID_DATA MKID('D','A','T','A') -#define ID_OKAY MKID('O','K','A','Y') -#define ID_FAIL MKID('F','A','I','L') -#define ID_QUIT MKID('Q','U','I','T') +typedef struct sdb_stat SDB_STAT; +struct sdb_stat { + unsigned id; + unsigned mode; + unsigned size; + unsigned time; +}; + +typedef struct dent DENT; +struct dent { + unsigned id; + unsigned mode; + unsigned size; + unsigned time; + unsigned namelen; +}; -typedef union { +typedef struct data DATA; +struct data { unsigned id; - struct { - unsigned id; - unsigned namelen; - } req; - struct { - unsigned id; - unsigned mode; - unsigned size; - unsigned time; - } stat; - struct { - unsigned id; - unsigned mode; - unsigned size; - unsigned time; - unsigned namelen; - } dent; - struct { - unsigned id; - unsigned size; - } data; - struct { - unsigned id; - unsigned msglen; - } status; -} syncmsg; + unsigned size; +}; +typedef struct status STATUS; +struct status { + unsigned id; + unsigned msglen; +}; -void file_sync_service(int fd, void *cookie); -int do_sync_ls(const char *path); -int do_sync_push(const char *lpath, const char *rpath, int isUtf8); -int do_sync_sync(const char *lpath, const char *rpath, int listonly); -int do_sync_pull(const char *rpath, const char *lpath); +typedef union syncmsg SYNC_MSG; +union syncmsg { + REQ req; + SDB_STAT stat; + DENT dent; + DATA data; + STATUS status; +}; #define SYNC_DATA_MAX (64*1024) #define SYNC_CHAR_MAX 1024 diff --git a/src/linkedlist.c b/src/linkedlist.c index 93aa7bb..4c6beb4 100644 --- a/src/linkedlist.c +++ b/src/linkedlist.c @@ -31,7 +31,7 @@ static void default_free(void* data); -void append(LIST_NODE** listptr, void* value) { +LIST_NODE* append(LIST_NODE** listptr, void* value) { LIST_NODE* prev_ptr = NULL; LIST_NODE* current_ptr = *listptr; @@ -47,14 +47,34 @@ void append(LIST_NODE** listptr, void* value) { //listptr is empty. if(prev_ptr == NULL) { + new_ptr->prev_ptr = NULL; *listptr = new_ptr; } else { prev_ptr->next_ptr = new_ptr; + new_ptr->prev_ptr = prev_ptr; } + + return new_ptr; +} + +LIST_NODE* prepend(LIST_NODE** listptr, void* value) { + + LIST_NODE* new_ptr = (LIST_NODE*)malloc(sizeof(LIST_NODE)); + new_ptr->data = value; + new_ptr->next_ptr = *listptr; + new_ptr->prev_ptr = NULL; + + if(*listptr != NULL) { + (*listptr)->prev_ptr = new_ptr; + } + + *listptr = new_ptr; + + return new_ptr; } -void no_free() { +void no_free(void* data) { //do nothing. } @@ -64,17 +84,39 @@ void free_list(LIST_NODE* listptr, void(free_func)(void*)) { free_func = default_free; } - LIST_NODE* nextptr = NULL; LIST_NODE* currentptr = listptr; while(currentptr != NULL) { - nextptr = currentptr->next_ptr; - free_func(currentptr->data); - free(currentptr); - currentptr = nextptr; + LIST_NODE* prev = currentptr; + currentptr = currentptr->next_ptr; + free_func(prev->data); + free(prev); } } +void remove_node(LIST_NODE** listptr, LIST_NODE* remove_node, void(free_func)(void*)) { + + if(free_func == NULL) { + free_func = default_free; + } + LIST_NODE* next = remove_node->next_ptr; + LIST_NODE* prev = remove_node->prev_ptr; + + if(*listptr == remove_node) { + *listptr = next; + } + else { + //if remove_node is not listptr, prev is always not NULL. + prev->next_ptr = next; + } + if (next != NULL) { + next->prev_ptr = prev; + } + + free_func(remove_node->data); + free(remove_node); +} + static void default_free(void* data) { if(data != NULL) { free(data); @@ -89,6 +131,9 @@ void remove_first(LIST_NODE** listptr, void(free_func)(void*)) { if(*listptr != NULL) { LIST_NODE* curptr = (*listptr)->next_ptr; + if(curptr != NULL) { + curptr->prev_ptr = NULL; + } LIST_NODE* removeptr = *listptr; *listptr = curptr; free_func(removeptr->data); diff --git a/src/linkedlist.h b/src/linkedlist.h index b88a5de..11d7aed 100644 --- a/src/linkedlist.h +++ b/src/linkedlist.h @@ -30,13 +30,16 @@ struct list_node { void* data; struct list_node* next_ptr; + struct list_node* prev_ptr; }; typedef struct list_node LIST_NODE; -void no_free(); -void append( LIST_NODE** listptr, void* value); -void free_list(LIST_NODE* listptr, void(free_func)(void*)); -void remove_first(LIST_NODE** listptr, void(free_func)(void*)); +void no_free(void* data); +LIST_NODE* append( LIST_NODE** listptr, void* value); +LIST_NODE* prepend(LIST_NODE** listptr, void* value); +void free_list(LIST_NODE* listptr, void(free_func)(void* data)); +void remove_first(LIST_NODE** listptr, void(free_func)(void* data)); +void remove_node(LIST_NODE** listptr, LIST_NODE* remove_node, void(free_func)(void* data)); #endif /* LINKEDLIST_H_ */ diff --git a/src/listener.c b/src/listener.c new file mode 100644 index 0000000..c66ec70 --- /dev/null +++ b/src/listener.c @@ -0,0 +1,182 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#include +#include +#include + +#include "log.h" +#include "listener.h" +#include "fdevent.h" +#include "utils.h" +#include "sockets.h" + +LIST_NODE* listener_list = NULL; + +static void listener_event_func(int _fd, unsigned ev, void *_l); +static LISTENER* find_listener(const char *local_name); + +void free_listener(void* data) +{ + LISTENER* listener = data; + fdevent_remove(&(listener->fde)); + free((void*)listener->local_name); + free((void*)listener->connect_to); + free(listener); +} + +int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport) +{ + D("LN(%s)\n", local_name); + + LISTENER* listener = find_listener(local_name); + + if(listener != NULL) { + char *cto; + + /* can't repurpose a smartsocket */ + if(listener->connect_to[0] == '*') { + return -1; + } + + cto = strdup(connect_to); + if(cto == 0) { + return -1; + } + + //printf("rebinding '%s' to '%s'\n", local_name, connect_to); + free((void*) listener->connect_to); + listener->connect_to = cto; + if (listener->transport != transport) { + listener->transport = transport; + } + return 0; + } + + if(strncmp("tcp:", local_name, 4)){ + LOG_FATAL("LN(%s) unknown local portname\n", local_name); + return -2; + } + + int port = atoi(local_name + 4); + + //TODO REMOTE_DEVICE_CONNECT block remote connect until security issue is cleard +// int fd = sdb_port_listen(INADDR_ANY, port, SOCK_STREAM); + int fd = sdb_port_listen(INADDR_LOOPBACK, port, SOCK_STREAM); + + if(fd < 0) { + LOG_FATAL("LN(%s) cannot bind\n", local_name); + return -2; + } + + listener = calloc(1, sizeof(LISTENER)); + listener->local_name = strdup(local_name); + listener->connect_to = strdup(connect_to); + listener->fd = fd; + listener->node = prepend(&listener_list, listener); + listener->transport = transport; + close_on_exec(fd); + fdevent_install(&listener->fde, fd, listener_event_func, listener); + FDEVENT_SET(&listener->fde, FDE_READ); + return 0; +} + +int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport) +{ + D("LN(%s)\n", local_name); + LISTENER* listener = find_listener(local_name); + + if(listener != NULL && + !strcmp(connect_to, listener->connect_to) && + listener->transport != NULL && + listener->transport == transport) { + remove_node(&listener_list, listener->node, free_listener); + D("LN(%s) removed\n", local_name); + return 0; + } + + D("LN(%s) could not find\n", local_name); + return -1; +} + +static void listener_event_func(int _fd, unsigned ev, void *_l) +{ + LISTENER *l = _l; + D("LN(%s)\n", l->local_name); + + if(ev & FDE_READ) { + int fd = sdb_socket_accept(_fd); + + if(fd < 0) { + D("LN(%s) fail to create\n", l->local_name); + return; + } + + SDB_SOCKET *s = create_local_socket(fd); + + int ss = 0; + if(!strcmp(l->connect_to, "*smartsocket*")) { + ss = 1; + } + + if(ss) { + sdb_socket_setbufsize(fd, CHUNK_SIZE); + } + if(s) { + + if(ss) { + local_socket_ready(s); + } + else { + + if(l->transport->type == kTransportRemoteDevCon) { + if(assign_remote_connect_socket_rid(s)) { + local_socket_close(s); + return; + } + } + + s->transport = l->transport; + connect_to_remote(s, l->connect_to); + } + return; + } + + sdb_close(fd); + } +} + +static LISTENER* find_listener(const char *local_name) { + LIST_NODE* currentptr = listener_list; + while(currentptr != NULL) { + LISTENER* l = currentptr->data; + currentptr = currentptr->next_ptr; + if(!strcmp(local_name, l->local_name)) { + return l; + } + } + return NULL; +} diff --git a/src/listener.h b/src/listener.h new file mode 100644 index 0000000..b2850cc --- /dev/null +++ b/src/listener.h @@ -0,0 +1,37 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef LISTENER_H_ +#define LISTENER_H_ + +#include "common_modules.h" +extern LIST_NODE* listener_list; + +int remove_listener(const char *local_name, const char *connect_to, TRANSPORT* transport); +int install_listener(const char *local_name, const char *connect_to, TRANSPORT* transport); +void free_listener(void* data); + +#endif /* LISTENER_H_ */ diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..41477f3 --- /dev/null +++ b/src/log.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include // for using va_list +#include "log.h" +#include "utils.h" + +int loglevel_mask; + +static struct { + char* name; + LogLevel level; +} log_levels[] = { + { "all", 0 }, + { "fatal", SDBLOG_FATAL }, + { "error", SDBLOG_ERROR }, + { "debug", SDBLOG_DEBUG }, + { "info", SDBLOG_INFO }, + { "fixme", SDBLOG_FIXME }, + { NULL, 0 } +}; + +void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...) { + char *name = NULL; + char mbuf[1024]; + char fbuf[1024]; + va_list args; + + va_start(args, fmt); + + switch (level) { + case SDBLOG_FATAL: + name = log_levels[SDBLOG_FATAL].name; + break; + case SDBLOG_ERROR: + name = log_levels[SDBLOG_ERROR].name; + break; + case SDBLOG_INFO: + name = log_levels[SDBLOG_INFO].name; + break; + case SDBLOG_DEBUG: + name = log_levels[SDBLOG_DEBUG].name;; + break; + case SDBLOG_FIXME: + name = log_levels[SDBLOG_FIXME].name; + break; + default: + name = log_levels[SDBLOG_INFO].name; + break; + } + snprintf(fbuf, sizeof(fbuf), "[%s][%s:%s():%d]%s", name, filename, funcname, line_number, fmt); + vsnprintf(mbuf, sizeof(mbuf), fbuf, args); + sdb_mutex_lock(&D_lock, NULL); + fprintf(stderr, "%s", mbuf); + sdb_mutex_unlock(&D_lock, NULL); + fflush(stderr); + va_end(args); +} + +static void log_parse(char* args) { + char *level, *levels, *next; + + levels = strdup(args); + if (levels == NULL) { + return; + } + int i=0; + for (level = levels; level; level = next) { + next = strchr(level, ',' ); + if (next != NULL) { + *next++ = 0; + } + + for (i = 0; log_levels[i].name != NULL; i++) { + if (!strcmp(level, log_levels[i].name)) + { + if (!strcmp("all",log_levels[i].name)) { + loglevel_mask = ~0; + free(levels); + return; + } + loglevel_mask |= 1 << log_levels[i].level; + break; + } + } + } + free(levels); +} + +void log_init(void) +{ + char* sdb_debug = NULL; + + if ((sdb_debug = getenv(DEBUG_ENV))) { + log_parse(sdb_debug); + } +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..d6e85ac --- /dev/null +++ b/src/log.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LOG_H +#define __LOG_H + +#define SDB_TRACE 1 +#define DEBUG_ENV "SDB_DEBUG" +extern int loglevel_mask; + +typedef enum { + SDBLOG_FATAL = 1, + SDBLOG_ERROR, + SDBLOG_DEBUG, + SDBLOG_INFO, + SDBLOG_FIXME +} LogLevel; + +#define LOG_FATAL(args...) \ + do { \ + logging(SDBLOG_FATAL, __FILE__, __FUNCTION__, __LINE__, args);\ + exit(255);} while(0) + +#define LOG_ASSERT(cond) do { if (!(cond)) LOG_FATAL( "assertion failed '%s'\n", #cond); } while (0) + + +#define LOG_ERROR(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_ERROR)) != 0) { \ + logging(SDBLOG_ERROR, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_DEBUG(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0) { \ + logging(SDBLOG_DEBUG, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_INFO(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_INFO)) != 0) { \ + logging(SDBLOG_INFO, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +#define LOG_FIXME(args...) \ + do { if ((loglevel_mask & (1 << SDBLOG_FIXME)) != 0) { \ + logging(SDBLOG_FIXME, __FILE__, __FUNCTION__, __LINE__, args); } } while(0) + +void log_init(void); +void logging(LogLevel level, const char *filename, const char *funcname, int line_number, const char *fmt, ...); + +// define for a while for testing +#undef D +#define D LOG_DEBUG +#undef DR +#define DR LOG_DEBUG +#define SDB_TRACING ((loglevel_mask & (1 << SDBLOG_DEBUG)) != 0) + +#endif diff --git a/src/memutils.c b/src/memutils.c new file mode 100644 index 0000000..4fdd686 --- /dev/null +++ b/src/memutils.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "log.h" +#include "strutils.h" + +static size_t total_mem = 0; + +// added size of size_t to know how many bytes have been allocated. + +void *s_malloc(size_t size) { + void *ptr = malloc(size + sizeof(size_t)); + + if (ptr == NULL) { + LOG_FATAL("cannot allocate memory:%d bytes\n", (int ) size); + } + *(size_t*) ptr = size; + + total_mem += size; + + LOG_DEBUG("memory allocated:%u bytes / %u bytes\n", size, total_mem); + + return ptr + sizeof(size_t); +} + +void *s_realloc(void *ptr, size_t new_size) { + void *new_ptr; + size_t org_size; + + if (ptr == NULL) { + LOG_FATAL("null argument in!!\n"); + } + + new_ptr = realloc(ptr - sizeof(size_t), new_size + sizeof(size_t)); + if (new_ptr == NULL) { + LOG_FATAL("cannot allocate new memory:%d bytes\n", (int ) new_size); + } + org_size = *(size_t*) (ptr - sizeof(size_t)); + *(size_t*) new_ptr = new_size; + total_mem += new_size - org_size; + + LOG_DEBUG("memory allocated:%u bytes -> %u bytes / %u bytes\n", org_size, new_size, total_mem); + + return new_ptr + sizeof(size_t); +} + +void s_free(void *ptr) { + size_t size; + + if (ptr == NULL) { + return; + } + + size = *(size_t*) (ptr - sizeof(size_t)); + total_mem -= size; + + free(ptr - sizeof(size_t)); + + LOG_DEBUG("memory freed:%u bytes / %u\n", size, total_mem); + +} + +char *s_strdup(const char *str) { + if (str == NULL) { + return NULL; + } + int len = strlen(str) + 1; + + char *ptr = s_malloc(len); + + s_strncpy(ptr, str, len); + return ptr; +} diff --git a/src/memutils.h b/src/memutils.h new file mode 100644 index 0000000..082bf59 --- /dev/null +++ b/src/memutils.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _MEMUTILS_H_ +#define _MEMUTILS_H_ + +void *s_malloc(size_t size); +void *s_realloc(void *ptr, size_t new_size); +void s_free(void *ptr); +char *s_strdup(const char *str); + +#endif + diff --git a/src/sdb.c b/src/sdb.c index d33b6b8..9471e56 100755 --- a/src/sdb.c +++ b/src/sdb.c @@ -30,561 +30,17 @@ #include "fdevent.h" #include "sdb.h" #include "commandline.h" +#include "sdb_constants.h" +#include "listener.h" #if SDB_TRACE SDB_MUTEX_DEFINE( D_lock ); #endif -int HOST = 0; +MAP hex_map; -static const char *sdb_device_banner = "device"; - -void fatal(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(-1); -} - -void fatal_errno(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "error: %s: ", strerror(errno)); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - exit(-1); -} - -int sdb_trace_mask; - -/* read a comma/space/colum/semi-column separated list of tags - * from the SDB_TRACE environment variable and build the trace - * mask from it. note that '1' and 'all' are special cases to - * enable all tracing - */ -void sdb_trace_init(void) -{ - const char* p = getenv("SDB_TRACE"); - const char* q; - - static const struct { - const char* tag; - int flag; - } tags[] = { - { "1", 0 }, - { "all", 0 }, - { "sdb", TRACE_SDB }, - { "sockets", TRACE_SOCKETS }, - { "packets", TRACE_PACKETS }, - { "rwx", TRACE_RWX }, - { "usb", TRACE_USB }, - { "sync", TRACE_SYNC }, - { "sysdeps", TRACE_SYSDEPS }, - { "transport", TRACE_TRANSPORT }, - { "jdwp", TRACE_JDWP }, - { "services", TRACE_SERVICES }, - { "properties", TRACE_PROPERTIES }, - { NULL, 0 } - }; - - if (p == NULL) - return; - - /* use a comma/column/semi-colum/space separated list */ - while (*p) { - int len, tagn; - - q = strpbrk(p, " ,:;"); - if (q == NULL) { - q = p + strlen(p); - } - len = q - p; - - for (tagn = 0; tags[tagn].tag != NULL; tagn++) - { - int taglen = strlen(tags[tagn].tag); - - if (len == taglen && !memcmp(tags[tagn].tag, p, len) ) - { - int flag = tags[tagn].flag; - if (flag == 0) { - sdb_trace_mask = ~0; - return; - } - sdb_trace_mask |= (1 << flag); - break; - } - } - p = q; - if (*p) - p++; - } -} - -apacket *get_apacket(void) -{ - apacket *p = malloc(sizeof(apacket)); - if(p == 0) fatal("failed to allocate an apacket"); - memset(p, 0, sizeof(apacket) - MAX_PAYLOAD); - return p; -} - -void put_apacket(apacket *p) -{ - free(p); -} - -void handle_online(void) -{ - D("sdb: online\n"); -} - -void handle_offline(atransport *t) -{ - D("sdb: offline\n"); - //Close the associated usb - run_transport_disconnects(t); -} - -#if TRACE_PACKETS -#define DUMPMAX 32 -void print_packet(const char *label, apacket *p) -{ - char *tag; - char *x; - unsigned count; - - switch(p->msg.command){ - case A_SYNC: tag = "SYNC"; break; - case A_CNXN: tag = "CNXN" ; break; - case A_OPEN: tag = "OPEN"; break; - case A_OKAY: tag = "OKAY"; break; - case A_CLSE: tag = "CLSE"; break; - case A_WRTE: tag = "WRTE"; break; - default: tag = "????"; break; - } - - fprintf(stderr, "%s: %s %08x %08x %04x \"", - label, tag, p->msg.arg0, p->msg.arg1, p->msg.data_length); - count = p->msg.data_length; - x = (char*) p->data; - if(count > DUMPMAX) { - count = DUMPMAX; - tag = "\n"; - } else { - tag = "\"\n"; - } - while(count-- > 0){ - if((*x >= ' ') && (*x < 127)) { - fputc(*x, stderr); - } else { - fputc('.', stderr); - } - x++; - } - fprintf(stderr, tag); -} -#endif - -static void send_ready(unsigned local, unsigned remote, atransport *t) -{ - D("Calling send_ready \n"); - apacket *p = get_apacket(); - p->msg.command = A_OKAY; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -static void send_close(unsigned local, unsigned remote, atransport *t) -{ - D("Calling send_close \n"); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - p->msg.arg0 = local; - p->msg.arg1 = remote; - send_packet(p, t); -} - -static void send_connect(atransport *t) -{ - D("Calling send_connect \n"); - apacket *cp = get_apacket(); - cp->msg.command = A_CNXN; - cp->msg.arg0 = A_VERSION; - cp->msg.arg1 = MAX_PAYLOAD; - snprintf((char*) cp->data, sizeof cp->data, "%s::", - HOST ? "host" : sdb_device_banner); - cp->msg.data_length = strlen((char*) cp->data) + 1; - send_packet(cp, t); - - /* XXX why sleep here? */ - // allow the device some time to respond to the connect message - sdb_sleep_ms(1000); - -} - -static char *connection_state_name(atransport *t) -{ - if (t == NULL) { - return "unknown"; - } - - switch(t->connection_state) { - case CS_BOOTLOADER: - return "bootloader"; - case CS_DEVICE: - return "device"; - case CS_OFFLINE: - return "offline"; - default: - return "unknown"; - } -} - -void parse_banner(char *banner, atransport *t) -{ - char *type, *product, *end; - - D("parse_banner: %s\n", banner); - type = banner; - product = strchr(type, ':'); - if(product) { - *product++ = 0; - } else { - product = ""; - } - - /* remove trailing ':' */ - end = strchr(product, ':'); - if(end) *end = 0; - - /* save product name in device structure */ - if (t->product == NULL) { - t->product = strdup(product); - } else if (strcmp(product, t->product) != 0) { - free(t->product); - t->product = strdup(product); - } - - if(!strcmp(type, "bootloader")){ - D("setting connection_state to CS_BOOTLOADER\n"); - t->connection_state = CS_BOOTLOADER; - update_transports(); - return; - } - - if(!strcmp(type, "device")) { - D("setting connection_state to CS_DEVICE\n"); - t->connection_state = CS_DEVICE; - update_transports(); - return; - } - - if(!strcmp(type, "recovery")) { - D("setting connection_state to CS_RECOVERY\n"); - t->connection_state = CS_RECOVERY; - update_transports(); - return; - } - - if(!strcmp(type, "sideload")) { - D("setting connection_state to CS_SIDELOAD\n"); - t->connection_state = CS_SIDELOAD; - update_transports(); - return; - } - - t->connection_state = CS_HOST; -} - -void handle_packet(apacket *p, atransport *t) -{ - asocket *s; - - D("handle_packet() %c%c%c%c\n", ((char*) (&(p->msg.command)))[0], - ((char*) (&(p->msg.command)))[1], - ((char*) (&(p->msg.command)))[2], - ((char*) (&(p->msg.command)))[3]); - - print_packet("recv", p); - - switch(p->msg.command){ - case A_SYNC: - if(p->msg.arg0){ - send_packet(p, t); - if(HOST) send_connect(t); - } else { - t->connection_state = CS_OFFLINE; - handle_offline(t); - send_packet(p, t); - } - return; - - case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ - /* XXX verify version, etc */ - if(t->connection_state != CS_OFFLINE) { - t->connection_state = CS_OFFLINE; - handle_offline(t); - } - parse_banner((char*) p->data, t); - handle_online(); - if(!HOST) send_connect(t); - break; - - case A_OPEN: /* OPEN(local-id, 0, "destination") */ - if(t->connection_state != CS_OFFLINE) { - char *name = (char*) p->data; - name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0; - s = create_local_service_socket(name); - if(s == 0) { - send_close(0, p->msg.arg0, t); - } else { - s->peer = create_remote_socket(p->msg.arg0, t); - s->peer->peer = s; - send_ready(s->id, s->peer->id, t); - s->ready(s); - } - } - break; - - case A_OKAY: /* READY(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - if(s->peer == 0) { - s->peer = create_remote_socket(p->msg.arg0, t); - s->peer->peer = s; - } - s->ready(s); - } - } - break; - - case A_CLSE: /* CLOSE(local-id, remote-id, "") */ - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - s->close(s); - } - } - break; - - case A_WRTE: - if(t->connection_state != CS_OFFLINE) { - if((s = find_local_socket(p->msg.arg1))) { - unsigned rid = p->msg.arg0; - p->len = p->msg.data_length; - - if(s->enqueue(s, p) == 0) { - D("Enqueue the socket\n"); - send_ready(s->id, rid, t); - } - return; - } - } - break; - - default: - printf("handle_packet: what is %08x?!\n", p->msg.command); - } - - put_apacket(p); -} - -alistener listener_list = { - .next = &listener_list, - .prev = &listener_list, -}; - -static void ss_listener_event_func(int _fd, unsigned ev, void *_l) -{ - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = sdb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - sdb_socket_setbufsize(fd, CHUNK_SIZE); - - s = create_local_socket(fd); - if(s) { - connect_to_smartsocket(s); - return; - } - - sdb_close(fd); - } -} - -static void listener_event_func(int _fd, unsigned ev, void *_l) -{ - alistener *l = _l; - asocket *s; - - if(ev & FDE_READ) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = sdb_socket_accept(_fd, &addr, &alen); - if(fd < 0) return; - - s = create_local_socket(fd); - if(s) { - s->transport = l->transport; - connect_to_remote(s, l->connect_to); - return; - } - - sdb_close(fd); - } -} - -static void free_listener(alistener* l) -{ - if (l->next) { - l->next->prev = l->prev; - l->prev->next = l->next; - l->next = l->prev = l; - } - - // closes the corresponding fd - fdevent_remove(&l->fde); - - if (l->local_name) - free((char*)l->local_name); - - if (l->connect_to) - free((char*)l->connect_to); - - if (l->transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - } - free(l); -} - -static void listener_disconnect(void* _l, atransport* t) -{ - alistener* l = _l; - - free_listener(l); -} - -int local_name_to_fd(const char *name) -{ - int port; - - if(!strncmp("tcp:", name, 4)){ - int ret; - port = atoi(name + 4); - ret = socket_loopback_server(port, SOCK_STREAM); - D("add loopback listen to %d", port); - return ret; - } - - printf("unknown local portname '%s'\n", name); - return -1; -} - -static int remove_listener(const char *local_name, const char *connect_to, atransport* transport) -{ - alistener *l; - - for (l = listener_list.next; l != &listener_list; l = l->next) { - if (!strcmp(local_name, l->local_name) && - !strcmp(connect_to, l->connect_to) && - l->transport && l->transport == transport) { - - listener_disconnect(l, transport); - return 0; - } - } - - return -1; -} - -static int install_listener(const char *local_name, const char *connect_to, atransport* transport) -{ - alistener *l; - - D("install_listener('%s','%s')\n", local_name, connect_to); - - for(l = listener_list.next; l != &listener_list; l = l->next){ - if(strcmp(local_name, l->local_name) == 0) { - char *cto; - - /* can't repurpose a smartsocket */ - if(l->connect_to[0] == '*') { - return -1; - } - - cto = strdup(connect_to); - if(cto == 0) { - return -1; - } - - //printf("rebinding '%s' to '%s'\n", local_name, connect_to); - free((void*) l->connect_to); - l->connect_to = cto; - if (l->transport != transport) { - remove_transport_disconnect(l->transport, &l->disconnect); - l->transport = transport; - add_transport_disconnect(l->transport, &l->disconnect); - } - return 0; - } - } - - if((l = calloc(1, sizeof(alistener))) == 0) goto nomem; - if((l->local_name = strdup(local_name)) == 0) goto nomem; - if((l->connect_to = strdup(connect_to)) == 0) goto nomem; - - - l->fd = local_name_to_fd(local_name); - if(l->fd < 0) { - free((void*) l->local_name); - free((void*) l->connect_to); - free(l); - printf("cannot bind '%s'\n", local_name); - return -2; - } - - close_on_exec(l->fd); - if(!strcmp(l->connect_to, "*smartsocket*")) { - fdevent_install(&l->fde, l->fd, ss_listener_event_func, l); - } else { - fdevent_install(&l->fde, l->fd, listener_event_func, l); - } - fdevent_set(&l->fde, FDE_READ); - - l->next = &listener_list; - l->prev = listener_list.prev; - l->next->prev = l; - l->prev->next = l; - l->transport = transport; - - if (transport) { - l->disconnect.opaque = l; - l->disconnect.func = listener_disconnect; - add_transport_disconnect(transport, &l->disconnect); - } - return 0; - -nomem: - fatal("cannot allocate listener"); - return 0; -} +static void local_init(int port); +static void init_wakeup_select_func(); #ifdef OS_WINDOWS static BOOL WINAPI ctrlc_handler(DWORD type) @@ -594,11 +50,65 @@ static BOOL WINAPI ctrlc_handler(DWORD type) } #endif -static void sdb_cleanup(void) +void sdb_cleanup(void) { sdb_usb_cleanup(); } +static void init_map() { + initialize_map(&event_map, EVENT_MAP_SIZE, NULL, NULL, no_free); + initialize_map(&hex_map, 16, NULL, NULL, no_free); + MAP_KEY key; + key.key_int = (int)'0'; + map_put(&hex_map, key, 0); + key.key_int = (int)'1'; + map_put(&hex_map, key, (void*)('1' - '0')); + key.key_int = (int)'2'; + map_put(&hex_map, key, (void*)('2' - '0')); + key.key_int = (int)'3'; + map_put(&hex_map, key, (void*)('3' - '0')); + key.key_int = (int)'4'; + map_put(&hex_map, key, (void*)('4' - '0')); + key.key_int = (int)'5'; + map_put(&hex_map, key, (void*)('5' - '0')); + key.key_int = (int)'6'; + map_put(&hex_map, key, (void*)('6' - '0')); + key.key_int = (int)'7'; + map_put(&hex_map, key, (void*)('7' - '0')); + key.key_int = (int)'8'; + map_put(&hex_map, key, (void*)('8' - '0')); + key.key_int = (int)'9'; + map_put(&hex_map, key, (void*)('9' - '0')); + key.key_int = (int)'a'; + map_put(&hex_map, key, (void*)10); + key.key_int = (int)'b'; + map_put(&hex_map, key, (void*)(10 + 'b' - 'a')); + key.key_int = (int)'c'; + map_put(&hex_map, key, (void*)(10 + 'c' - 'a')); + key.key_int = (int)'d'; + map_put(&hex_map, key, (void*)(10 + 'd' - 'a')); + key.key_int = (int)'e'; + map_put(&hex_map, key, (void*)(10 + 'e' - 'a')); + key.key_int = (int)'f'; + map_put(&hex_map, key, (void*)(10 + 'f' - 'a')); + key.key_int = (int)'A'; + map_put(&hex_map, key, (void*)10); + key.key_int = (int)'B'; + map_put(&hex_map, key, (void*)(10 + 'B' - 'A')); + key.key_int = (int)'C'; + map_put(&hex_map, key, (void*)(10 + 'C' - 'A')); + key.key_int = (int)'D'; + map_put(&hex_map, key, (void*)(10 + 'D' - 'A')); + key.key_int = (int)'E'; + map_put(&hex_map, key, (void*)(10 + 'E' - 'A')); + key.key_int = (int)'F'; + map_put(&hex_map, key, (void*)(10 + 'F' - 'A')); + +#if defined(OS_WINDOWS) + initialize_map(&sdb_handle_map, WIN32_MAX_FHS / 2, NULL, NULL, no_free); +#endif +} + /* Constructs a local name of form tcp:port. * target_str points to the target string, it's content will be overwritten. * target_size is the capacity of the target string. @@ -618,10 +128,8 @@ int sdb_main(int is_daemon, int server_port) signal(SIGPIPE, SIG_IGN); #endif - init_transport_registration(); + init_wakeup_select_func(); - HOST = 1; -// usb_vendors_init(); sdb_usb_init(); local_init(DEFAULT_SDB_LOCAL_TRANSPORT_PORT); @@ -641,337 +149,51 @@ int sdb_main(int is_daemon, int server_port) #endif start_logging(); } - D("Event loop starting\n"); - - fdevent_loop(); + LOG_INFO("Event loop starting\n"); + FDEVENT_LOOP(); atexit(sdb_cleanup); - return 0; } -void connect_device(char* host, char* buffer, int buffer_size) +static void local_init(int port) { - int port, fd; - char* portstr = strchr(host, ':'); - char hostbuf[100]; - char serial[100]; - - strncpy(hostbuf, host, sizeof(hostbuf) - 1); - if (portstr) { - if (portstr - host >= sizeof(hostbuf)) { - snprintf(buffer, buffer_size, "bad host name %s", host); - return; - } - // zero terminate the host at the point we found the colon - hostbuf[portstr - host] = 0; - if (sscanf(portstr + 1, "%d", &port) == 0) { - snprintf(buffer, buffer_size, "bad port number %s", portstr); - return; - } - } else { + if(port < 1024) { port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT; } + int count = SDB_LOCAL_TRANSPORT_MAX; - snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port); - if (find_transport(serial)) { - snprintf(buffer, buffer_size, "already connected to %s", serial); - return; - } - - fd = socket_network_client(hostbuf, port, SOCK_STREAM); - if (fd < 0) { - snprintf(buffer, buffer_size, "unable to connect to %s", host); - return; + LOG_INFO("try to connect to emulator instances when booting sdb server up\n"); + for ( ; count > 0; count--, port += 10 ) { + (void) local_connect(port, NULL); } - - D("client: connected on remote on fd %d\n", fd); - close_on_exec(fd); - disable_tcp_nagle(fd); - register_socket_transport(fd, serial, port, 0, NULL); - snprintf(buffer, buffer_size, "connected to %s", serial); } -void connect_emulator(char* port_spec, char* buffer, int buffer_size) -{ - char* port_separator = strchr(port_spec, ','); - if (!port_separator) { - snprintf(buffer, buffer_size, - "unable to parse '%s' as ,", - 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); } diff --git a/src/sdb.h b/src/sdb.h index 16964b0..70733dc 100755 --- a/src/sdb.h +++ b/src/sdb.h @@ -19,393 +19,21 @@ #include +#include "linkedlist.h" #include "transport.h" /* readx(), writex() */ #include "sdb_usb.h" - -#define MAX_PAYLOAD 4096 - -#define A_SYNC 0x434e5953 -#define A_CNXN 0x4e584e43 -#define A_OPEN 0x4e45504f -#define A_OKAY 0x59414b4f -#define A_CLSE 0x45534c43 -#define A_WRTE 0x45545257 - -#define A_VERSION 0x01000000 // SDB protocol version - -#define SDB_VERSION_MAJOR 2 // Used for help/version information -#define SDB_VERSION_MINOR 2 // Used for help/version information - -#define SDB_SERVER_VERSION 5 // Increment this when we want to force users to start a new sdb server - -typedef struct amessage amessage; -typedef struct apacket apacket; -typedef struct asocket asocket; -typedef struct alistener alistener; -typedef struct aservice aservice; -typedef struct atransport atransport; -typedef struct adisconnect adisconnect; - -struct amessage { - unsigned command; /* command identifier constant */ - unsigned arg0; /* first argument */ - unsigned arg1; /* second argument */ - unsigned data_length; /* length of payload (0 is allowed) */ - unsigned data_check; /* checksum of data payload */ - unsigned magic; /* command ^ 0xffffffff */ -}; - -struct apacket -{ - apacket *next; - - unsigned len; - unsigned char *ptr; - - amessage msg; - unsigned char data[MAX_PAYLOAD]; -}; - -/* An asocket represents one half of a connection between a local and -** remote entity. A local asocket is bound to a file descriptor. A -** remote asocket is bound to the protocol engine. -*/ -struct asocket { - /* chain pointers for the local/remote list of - ** asockets that this asocket lives in - */ - asocket *next; - asocket *prev; - - /* the unique identifier for this asocket - */ - unsigned id; - - /* flag: set when the socket's peer has closed - ** but packets are still queued for delivery - */ - int closing; - - /* flag: quit sdbd when both ends close the - ** local service socket - */ - int exit_on_close; - - /* the asocket we are connected to - */ - - asocket *peer; - - /* For local asockets, the fde is used to bind - ** us to our fd event system. For remote asockets - ** these fields are not used. - */ - fdevent fde; - int fd; - - /* queue of apackets waiting to be written - */ - apacket *pkt_first; - apacket *pkt_last; - - /* enqueue is called by our peer when it has data - ** for us. It should return 0 if we can accept more - ** data or 1 if not. If we return 1, we must call - ** peer->ready() when we once again are ready to - ** receive data. - */ - int (*enqueue)(asocket *s, apacket *pkt); - - /* ready is called by the peer when it is ready for - ** us to send data via enqueue again - */ - void (*ready)(asocket *s); - - /* close is called by the peer when it has gone away. - ** we are not allowed to make any further calls on the - ** peer once our close method is called. - */ - void (*close)(asocket *s); - - /* socket-type-specific extradata */ - void *extra; - - /* A socket is bound to atransport */ - atransport *transport; -}; - - -/* the adisconnect structure is used to record a callback that -** will be called whenever a transport is disconnected (e.g. by the user) -** this should be used to cleanup objects that depend on the -** transport (e.g. remote sockets, listeners, etc...) -*/ -struct adisconnect -{ - void (*func)(void* opaque, atransport* t); - void* opaque; - adisconnect* next; - adisconnect* prev; -}; - - -/* a transport object models the connection to a remote device or emulator -** there is one transport per connected device/emulator. a "local transport" -** connects through TCP (for the emulator), while a "usb transport" through -** USB (for real devices) -** -** note that kTransportHost doesn't really correspond to a real transport -** object, it's a special value used to indicate that a client wants to -** connect to a service implemented within the SDB server itself. -*/ -typedef enum transport_type { - kTransportUsb, - kTransportLocal, - kTransportAny, - kTransportHost, -} transport_type; - -struct atransport -{ - atransport *next; - atransport *prev; - - int (*read_from_remote)(apacket *p, atransport *t); - int (*write_to_remote)(apacket *p, atransport *t); - void (*close)(atransport *t); - void (*kick)(atransport *t); - - int fd; - int transport_socket; - fdevent transport_fde; - int ref_count; - unsigned sync_token; - int connection_state; - transport_type type; - - /* usb handle or socket fd as needed */ - usb_handle *usb; - int sfd; - - /* used to identify transports for clients */ - char *serial; - char *product; - int sdb_port; // Use for emulators (local transport) - char *device_name; // for connection explorer - - /* a list of adisconnect callbacks called when the transport is kicked */ - int kicked; - adisconnect disconnects; -}; - - -/* A listener is an entity which binds to a local port -** and, upon receiving a connection on that port, creates -** an asocket to connect the new local connection to a -** specific remote service. -** -** TODO: some listeners read from the new connection to -** determine what exact service to connect to on the far -** side. -*/ -struct alistener -{ - alistener *next; - alistener *prev; - - fdevent fde; - int fd; - - const char *local_name; - const char *connect_to; - atransport *transport; - adisconnect disconnect; -}; - - -void print_packet(const char *label, apacket *p); - -asocket *find_local_socket(unsigned id); -void install_local_socket(asocket *s); -void remove_socket(asocket *s); -void close_all_sockets(atransport *t); - -#define LOCAL_CLIENT_PREFIX "emulator-" - -asocket *create_local_socket(int fd); -asocket *create_local_service_socket(const char *destination); - -asocket *create_remote_socket(unsigned id, atransport *t); -void connect_to_remote(asocket *s, const char *destination); -void connect_to_smartsocket(asocket *s); - -void fatal(const char *fmt, ...); -void fatal_errno(const char *fmt, ...); - -void handle_packet(apacket *p, atransport *t); -void send_packet(apacket *p, atransport *t); +#include "log.h" +#include "sdb_map.h" int sdb_main(int is_daemon, int server_port); - -/* transports are ref-counted -** get_device_transport does an acquire on your behalf before returning -*/ -void init_transport_registration(void); -int find_transports(char **serial, const char *prefix); -int list_transports(char *buf, size_t bufsize); -void update_transports(void); - -asocket* create_device_tracker(void); - -/* Obtain a transport from the available transports. -** If state is != CS_ANY, only transports in that state are considered. -** If serial is non-NULL then only the device with that serial will be chosen. -** If no suitable transport is found, error is set. -*/ -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char **error_out); -void add_transport_disconnect( atransport* t, adisconnect* dis ); -void remove_transport_disconnect( atransport* t, adisconnect* dis ); -void run_transport_disconnects( atransport* t ); -void kick_transport( atransport* t ); - -/* initialize a transport object's func pointers and state */ -int get_available_local_transport_index(); -int init_socket_transport(atransport *t, int s, int port, int local); -void init_usb_transport(atransport *t, usb_handle *usb, int state); -void close_usb_devices(); - - -/* cause new transports to be init'd and added to the list */ -void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name); - -/* these should only be used for the "sdb disconnect" command */ -void unregister_transport(atransport *t); -void unregister_all_tcp_transports(); - -void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable); - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb); - -atransport *find_transport(const char *serial); -atransport* find_emulator_transport_by_sdb_port(int sdb_port); - -int service_to_fd(const char *name); -asocket *host_service_to_socket(const char* name, const char *serial); - -/* packet allocator */ -apacket *get_apacket(void); -void put_apacket(apacket *p); - -int check_header(apacket *p); -int check_data(apacket *p); - -/* define SDB_TRACE to 1 to enable tracing support, or 0 to disable it */ - -#define SDB_TRACE 1 - -/* IMPORTANT: if you change the following list, don't - * forget to update the corresponding 'tags' table in - * the sdb_trace_init() function implemented in sdb.c - */ -typedef enum { - TRACE_SDB = 0, - TRACE_SOCKETS, - TRACE_PACKETS, - TRACE_TRANSPORT, - TRACE_RWX, - TRACE_USB, - TRACE_SYNC, - TRACE_SYSDEPS, - TRACE_JDWP, - TRACE_SERVICES, - TRACE_PROPERTIES -} SdbTrace; - -#if SDB_TRACE - -#define DQ(...) ((void)0) - - - extern int sdb_trace_mask; - extern unsigned char sdb_trace_output_count; - void sdb_trace_init(void); - -# define SDB_TRACING ((sdb_trace_mask & (1 << TRACE_TAG)) != 0) - - /* you must define TRACE_TAG before using this macro */ -# define D(...) \ - do { \ - if (SDB_TRACING) { \ - int save_errno = errno; \ - sdb_mutex_lock(&D_lock); \ - fprintf(stderr, "%s::%s():", \ - __FILE__, __FUNCTION__); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - sdb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -# define DR(...) \ - do { \ - if (SDB_TRACING) { \ - int save_errno = errno; \ - sdb_mutex_lock(&D_lock); \ - errno = save_errno; \ - fprintf(stderr, __VA_ARGS__ ); \ - fflush(stderr); \ - sdb_mutex_unlock(&D_lock); \ - errno = save_errno; \ - } \ - } while (0) -#else -# define D(...) ((void)0) -# define DR(...) ((void)0) -# define SDB_TRACING 0 -#endif - - -#if !TRACE_PACKETS -#define print_packet(tag,p) do {} while (0) -#endif - - -/* sdb and sdbd are coexisting on the target, so use 26099 for sdb - * to avoid conflicting with sdbd's usage of 26098 - */ -#define DEFAULT_SDB_PORT 26099 /* tizen specific */ -#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 /* tizen specific */ - -void local_init(int port); -int local_connect(int port, const char *device_name); -int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name); - - unsigned host_to_le32(unsigned n); int sdb_commandline(int argc, char **argv); -int connection_state(atransport *t); +int connection_state(TRANSPORT *t); -#define CS_ANY -1 -#define CS_OFFLINE 0 -#define CS_BOOTLOADER 1 -#define CS_DEVICE 2 -#define CS_HOST 3 -#define CS_RECOVERY 4 -#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ -#define CS_SIDELOAD 6 - -extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; -#define CHUNK_SIZE (64*1024) - -int sendfailmsg(int fd, const char *reason); -int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s); +void sdb_cleanup(void); -void register_device_name(const char *device_type, const char *device_name, int port); -int get_devicename_from_shdmem(int port, char *device_name); #endif diff --git a/src/sdb_client.c b/src/sdb_client.c index 62dadc3..1aa4910 100644 --- a/src/sdb_client.c +++ b/src/sdb_client.c @@ -28,31 +28,65 @@ #define TRACE_TAG TRACE_SDB #include "sdb_client.h" +#include "log.h" static int switch_socket_transport(int fd, void** extra_args); -static int send_service_with_length(int fd, const char* service); -static int sdb_status(int fd); +static int __inline__ write_msg_size(int fd, int size, int host_fd); -static int send_service_with_length(int fd, const char* service) { +void sendokmsg(int fd, const char *msg) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "OKAY%04x%s", (unsigned)strlen(msg), msg); + writex(fd, buf, strlen(buf)); +} + +void sendfailmsg(int fd, const char *reason) +{ + char buf[1024]; + snprintf(buf, sizeof(buf), "FAIL%04x%s", (unsigned)strlen(reason), reason); + writex(fd, buf, strlen(buf)); +} + +int send_service_with_length(int fd, const char* service, int host_fd) { int len; len = strlen(service); if(len < 1) { - fprintf(stderr,"error: service name is empty\n"); + if(host_fd == 0) { + fprintf(stderr,"error: service name is empty\n"); + } + else { + sendfailmsg(host_fd, "error: service name is empty\n"); + } return -1; } else if (len > 1024) { - fprintf(stderr,"error: service name too long\n"); + if(host_fd == 0) { + fprintf(stderr,"error: service name too long\n"); + } + else { + sendfailmsg(host_fd, "error: service name too long\n"); + } return -1; } - if(write_msg_size(fd, len) < 0) { + if(write_msg_size(fd, len, host_fd) < 0) { + D("fail to write msg size\n"); + if(host_fd != 0) { + sendfailmsg(host_fd, "fail to write msg size\n"); + } return -1; } if(writex(fd, service, len)) { - fprintf(stderr,"error: write failure during connection\n"); + D("error: write failure during connection\n"); + if(host_fd == 0) { + fprintf(stderr,"error: write failure during connection\n"); + } + else { + sendfailmsg(host_fd, "error: write failure during connection\n"); + } return -1; } @@ -68,19 +102,14 @@ static int switch_socket_transport(int fd, void** extra_args) get_host_prefix(service, sizeof service, ttype, serial, transport); - if(!strcmp(service, PREFIX_HOST)) { - // no switch necessary - return 0; - } - - if(send_service_with_length(fd, service) < 0) { + if(send_service_with_length(fd, service, 0) < 0) { sdb_close(fd); return -1; } D("Switch transport in progress\n"); - if(sdb_status(fd)) { + if(sdb_status(fd, 0)) { sdb_close(fd); D("Switch transport failed\n"); return -1; @@ -123,7 +152,7 @@ int sdk_launch_exist(void* extargv) { const char* expected_result = "/usr/sbin/sdk_launch"; - if(!strncmp(expected_result, query_result, sizeof(expected_result))) { + if(!strncmp(expected_result, query_result, strlen(expected_result))) { return 1; } return 0; @@ -172,14 +201,17 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) { null = strchr(ver_num, '-'); if(null == NULL) { - fprintf(stderr, "error: cannot parse sdbd version\n"); - return -1; + goto error; } *null = '\0'; D("sdbd version: %s\n", ver_num); null = strchr(ver_num, '.'); + if(null == NULL) { + goto error; + } + *null = '\0'; version = atoi(ver_num); if(version > first) { @@ -191,6 +223,10 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) { ver_num = ++null; null = strchr(ver_num, '.'); + if(null == NULL) { + goto error; + } + version = atoi(ver_num); *null = '\0'; if(version > middle) { @@ -206,14 +242,23 @@ int sdb_higher_ver(int first, int middle, int last, void* extargv) { return 1; } return 0; + +error: + LOG_ERROR("wrong version format %s", ver); + return -1; } -static int sdb_status(int fd) +int sdb_status(int fd, int host_fd) { unsigned char buf[5]; if(readx(fd, buf, 4)) { - fprintf(stderr,"error: protocol fault (no status)\n"); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (no status)\n"); + } + else { + sendfailmsg(host_fd, "error: protocol fault (no status)\n"); + } return -1; } @@ -222,29 +267,59 @@ static int sdb_status(int fd) } if(memcmp(buf, "FAIL", 4)) { - fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n", - buf[0], buf[1], buf[2], buf[3]); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (status %02x %02x %02x %02x?!)\n", + buf[0], buf[1], buf[2], buf[3]); + } + else { + char err_msg[255]; + snprintf(err_msg, sizeof(err_msg), "error: protocol fault (status %02x %02x %02x %02x?!)\n", + buf[0], buf[1], buf[2], buf[3]); + sendfailmsg(host_fd, err_msg); + } return -1; } int len = read_msg_size(fd); if(len < 0) { - fprintf(stderr,"error: protocol fault (status len)\n"); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (status len)\n"); + } + else { + sendfailmsg(host_fd, "error: protocol fault (status len)\n"); + } return -1; } - if(len > 255) len = 255; + if(len > 254) len = 254; char error[255]; if(readx(fd, error, len)) { - fprintf(stderr,"error: protocol fault (status read)\n"); + if(host_fd == 0) { + fprintf(stderr,"error: protocol fault (status read)\n"); + } + else { + sendfailmsg(host_fd, "error: protocol fault (status read)\n"); + } return -1; } error[len] = '\0'; - fprintf(stderr,"error: %s\n", error); + if(host_fd == 0) { + fprintf(stderr,"error msg: %s\n", error); + } + else { + char err_msg[255]; + snprintf(err_msg, sizeof(err_msg), "error msg: %s\n", error); + sendfailmsg(host_fd, err_msg); + } return -1; } +/** + * First check whether host service or transport service, + * If transport service, send transport prefix. Then, do the service. + * If host service, do the service. does not have to get transport. + */ int _sdb_connect(const char *service, void** ext_args) { int fd; @@ -253,22 +328,23 @@ int _sdb_connect(const char *service, void** ext_args) int server_port = *(int*)ext_args[2]; - fd = socket_loopback_client(server_port, SOCK_STREAM); + fd = sdb_host_connect("127.0.0.1", server_port, SOCK_STREAM); if(fd < 0) { D("error: cannot connect to daemon\n"); return -2; } + //If service is not host, send transport_prefix if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd, ext_args)) { return -1; } - if(send_service_with_length(fd, service) < 0) { + if(send_service_with_length(fd, service, 0) < 0) { sdb_close(fd); return -1; } - if(sdb_status(fd)) { + if(sdb_status(fd, 0)) { sdb_close(fd); return -1; } @@ -277,7 +353,7 @@ int _sdb_connect(const char *service, void** ext_args) return fd; } -int __inline__ read_msg_size(int fd) { +int read_msg_size(int fd) { char buf[5]; if(readx(fd, buf, 4)) { @@ -288,17 +364,27 @@ int __inline__ read_msg_size(int fd) { return strtoul(buf, NULL, 16); } -int __inline__ write_msg_size(int fd, int size) { +static int __inline__ write_msg_size(int fd, int size, int host_fd) { char tmp[5]; snprintf(tmp, sizeof tmp, "%04x", size); if(writex(fd, tmp, 4)) { - fprintf(stderr,"error: write msg size failure\n"); + D("error: write msg size failure\n"); + if(host_fd == 0) { + fprintf(stderr,"error: write msg size failure\n"); + } + else { + sendfailmsg(host_fd, "error: write msg size failure\n"); + } return -1; } return 1; } +/** + * First, check the host version. + * Then, send the service using _sdb_connect + */ int sdb_connect(const char *service, void** ext_args) { // first query the sdb server's version @@ -336,7 +422,7 @@ int sdb_connect(const char *service, void** ext_args) } if(version != SDB_SERVER_VERSION) { - printf("sdb server is out of date. killing...\n"); + printf("client version: %d, server version: %d\nsdb server is out of date. killing...\n", version, SDB_SERVER_VERSION); fd = _sdb_connect("host:kill", ext_args); sdb_close(fd); @@ -370,7 +456,7 @@ int sdb_command(const char *service, void** extra_args) return -1; } - if(sdb_status(fd)) { + if(sdb_status(fd, 0)) { sdb_close(fd); return -1; } @@ -418,7 +504,7 @@ void get_host_prefix(char* prefix, int size, transport_type ttype, const char* s } } else { - char* temp_prefix; + char* temp_prefix = NULL; if(ttype == kTransportUsb) { if(host_type == host) { temp_prefix = (char*)PREFIX_HOST_USB; @@ -435,12 +521,9 @@ void get_host_prefix(char* prefix, int size, transport_type ttype, const char* s temp_prefix = (char*)PREFIX_TRANSPORT_LOCAL; } } - else if(ttype == kTransportHost) { - temp_prefix = (char*)PREFIX_HOST; - } else if(ttype == kTransportAny) { if(host_type == host) { - temp_prefix = (char*)PREFIX_HOST; + temp_prefix = (char*)PREFIX_HOST_ANY; } else if(host_type == transport) { temp_prefix = (char*)PREFIX_TRANSPORT_ANY; diff --git a/src/sdb_client.h b/src/sdb_client.h index 04d9da2..31be98e 100644 --- a/src/sdb_client.h +++ b/src/sdb_client.h @@ -17,12 +17,15 @@ #ifndef _SDB_CLIENT_H_ #define _SDB_CLIENT_H_ -#include "sdb.h" #include "sdb_constants.h" +#include "common_modules.h" // debug launch pad is applied after sdbd 2.2.3 #define SDB_HIGHER_THAN_2_2_3(extargv) sdk_launch_exist(extargv) +int send_service_with_length(int fd, const char* service, int host_fd); +int sdb_status(int fd, int host_fd); + /* connect to sdb, connect to the named service, and return ** a valid fd for interacting with that service upon success ** or a negative number on failure @@ -64,8 +67,10 @@ int sdk_launch_exist(void* extargv); ** return 0 in the event of OKAY, -1 in the event of FAIL ** or protocol error */ -int __inline__ read_msg_size(int fd); -int __inline__ write_msg_size(int fd, int size); +int read_msg_size(int fd); + +void sendokmsg(int fd, const char *msg); +void sendfailmsg(int fd, const char *reason); void get_host_prefix(char* prefix, int size, transport_type ttype, const char* serial, HOST_TYPE host_type); #endif diff --git a/src/sdb_constants.c b/src/sdb_constants.c index 0c4acc9..57a9e63 100644 --- a/src/sdb_constants.c +++ b/src/sdb_constants.c @@ -35,6 +35,7 @@ const char* QUOTE_CHAR = " \"\\()"; const char* PREFIX_HOST = "host:"; + const char* PREFIX_HOST_ANY = "host-any:"; const char* PREFIX_HOST_USB = "host-usb:"; const char* PREFIX_HOST_LOCAL = "host-local:"; const char* PREFIX_HOST_SERIAL = "host-serial:"; @@ -87,6 +88,15 @@ const int COMMANDLINE_CONNECT_MAX_ARG = 1; const int COMMANDLINE_CONNECT_MIN_ARG = 1; + const char* COMMANDLINE_DEVICE_CON_NAME = "device_con"; + const char* COMMANDLINE_DEVICE_CON_DESC[] = { + "connect to a remote device" + }; + const int COMMANDLINE_DEVICE_CON_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_DEVICE_CON_DESC, char*); + const char* COMMANDLINE_DEVICE_CON_ARG_DESC = " "; + const int COMMANDLINE_DEVICE_CON_MAX_ARG = 2; + const int COMMANDLINE_DEVICE_CON_MIN_ARG = 2; + const char* COMMANDLINE_GSERIAL_NAME = "get-serialno"; const char* COMMANDLINE_GSERIAL_DESC[] = { "print: " @@ -97,7 +107,7 @@ const char* COMMANDLINE_GSTATE_NAME = "get-state"; const char* COMMANDLINE_GSTATE_DESC[] = { - "print: offline | bootloader | device" + "print: offline | locked | device" }; const int COMMANDLINE_GSTATE_DESC_SIZE = GET_ARRAY_SIZE(COMMANDLINE_GSTATE_DESC, char*); const int COMMANDLINE_GSTATE_MAX_ARG = 0; @@ -249,3 +259,19 @@ const int COMMANDLINE_EMULATOR_HAS_ARG = 0; const char* COMMANDLINE_ERROR_ARG_MISSING = "argument %s is missing for command %s"; + + const char* STATE_OFFLINE = "offline"; + const char* STATE_BOOTLOADER = "bootloader"; + const char* STATE_DEVICE = "device"; + const char* STATE_HOST = "host"; + const char* STATE_RECOVERY = "recovery"; + const char* STATE_SIDELOAD = "sideload"; + const char* STATE_NOPERM = "no permissions"; + const char* STATE_LOCKED = "locked"; + const char* STATE_UNKNOWN = "unknown"; + + const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET = "more than one target"; + const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL = "more than one emulator"; + const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV = "more than one device"; + const char* TRANSPORT_ERR_TARGET_OFFLINE = "target offline"; + const char* TRANSPORT_ERR_TARGET_NOT_FOUND = "target not found"; diff --git a/src/sdb_constants.h b/src/sdb_constants.h index caa88da..d0dda55 100644 --- a/src/sdb_constants.h +++ b/src/sdb_constants.h @@ -46,6 +46,7 @@ typedef enum host_type HOST_TYPE; extern const char* QUOTE_CHAR; extern const char* PREFIX_HOST; + extern const char* PREFIX_HOST_ANY; extern const char* PREFIX_HOST_USB; extern const char* PREFIX_HOST_LOCAL; extern const char* PREFIX_HOST_SERIAL; @@ -89,6 +90,13 @@ typedef enum host_type HOST_TYPE; extern const int COMMANDLINE_CONNECT_MAX_ARG; extern const int COMMANDLINE_CONNECT_MIN_ARG; + extern const char* COMMANDLINE_DEVICE_CON_NAME; + extern const char* COMMANDLINE_DEVICE_CON_DESC[]; + extern const int COMMANDLINE_DEVICE_CON_DESC_SIZE; + extern const char* COMMANDLINE_DEVICE_CON_ARG_DESC; + extern const int COMMANDLINE_DEVICE_CON_MAX_ARG; + extern const int COMMANDLINE_DEVICE_CON_MIN_ARG; + extern const char* COMMANDLINE_GSERIAL_NAME; extern const char* COMMANDLINE_GSERIAL_DESC[]; extern const int COMMANDLINE_GSERIAL_DESC_SIZE; @@ -210,4 +218,20 @@ typedef enum host_type HOST_TYPE; extern const char* COMMANDLINE_ERROR_ARG_MISSING; + extern const char* STATE_OFFLINE; + extern const char* STATE_BOOTLOADER; + extern const char* STATE_DEVICE; + extern const char* STATE_HOST; + extern const char* STATE_RECOVERY; + extern const char* STATE_SIDELOAD; + extern const char* STATE_NOPERM; + extern const char* STATE_LOCKED; + extern const char* STATE_UNKNOWN; + + extern const char* TRANSPORT_ERR_MORE_THAN_ONE_TARGET; + extern const char* TRANSPORT_ERR_MORE_THAN_ONE_EMUL; + extern const char* TRANSPORT_ERR_MORE_THAN_ONE_DEV; + extern const char* TRANSPORT_ERR_TARGET_OFFLINE; + extern const char* TRANSPORT_ERR_TARGET_NOT_FOUND; + #endif /* SDB_CONSTANTS_H_*/ diff --git a/src/sdb_map.c b/src/sdb_map.c new file mode 100644 index 0000000..470429f --- /dev/null +++ b/src/sdb_map.c @@ -0,0 +1,173 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#include +#include "sdb_map.h" +#include "linkedlist.h" + +static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key); +static int default_hash(MAP* this, MAP_KEY key); +static int default_equal(MAP_KEY key, MAP_KEY node_key); +static void default_free(void* node); + +void initialize_map(MAP* this, int size, int(*hash)(struct map* this, MAP_KEY key), + int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data)) { + + if(size < 1) { + this->size = DEFAULT_MAP_SIZE; + } + else { + this->size = size; + } + + if(equal == NULL) { + this->equal = default_equal; + } + else { + this->equal = equal; + } + + if(hash == NULL) { + this->hash = default_hash; + } + else { + this->hash = hash; + } + + if(freedata == NULL) { + this->freedata = default_free; + } + else { + this->freedata = freedata; + } + + this->map_node_list = (LIST_NODE**)calloc(this->size, sizeof(LIST_NODE*)); +} + +static void default_free(void* node) { + MAP_NODE* _node = node; + if(_node != NULL) { + if(_node->value != NULL ) { +// free(_node->value); + } + free(_node); + } +} + +static int default_hash(MAP* this, MAP_KEY key) { + return key.key_int%(this->size); +} + +static int default_equal(MAP_KEY key, MAP_KEY node_key) { + if(key.key_int != node_key.key_int) { + return 0; + } + return 1; +} + +static LIST_NODE* find_in_list(MAP* this, LIST_NODE* list, MAP_KEY key) { + + while(list != NULL) { + MAP_NODE* node = list->data; + if(this->equal(key, node->key)) { + return list; + } + list = list->next_ptr; + } + + return NULL; +} + +void map_put(MAP* this, MAP_KEY key, void* value) { + + int hash_key = this->hash(this, key); + LIST_NODE** hash_list = &(this->map_node_list[hash_key]); + + MAP_NODE* node = malloc(sizeof(MAP_NODE)); + node->key = key; + node->value = value; + + LIST_NODE* list_node = find_in_list(this, *hash_list, key); + if(list_node == NULL) { + prepend(hash_list, (void*)node); + } + else { + this->freedata(list_node->data); + list_node->data = node; + } +} + +void* map_get(MAP* this, MAP_KEY key) { + + int hash_key = this->hash(this, key); + LIST_NODE* hash_list = this->map_node_list[hash_key]; + LIST_NODE* result_node = find_in_list(this, hash_list, key); + if(result_node == NULL) { + return NULL; + } + + return ((MAP_NODE*)(result_node->data))->value; +} + +void map_remove(MAP* this, MAP_KEY key) { + + int hash_key = this->hash(this, key); + LIST_NODE** hash_list = &(this->map_node_list[hash_key]); + + LIST_NODE* result_node = find_in_list(this, *hash_list, key); + 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(; isize; i++) { + free_list(this->map_node_list[i], this->freedata); + } + + free(this->map_node_list); + } +} diff --git a/src/sdb_map.h b/src/sdb_map.h new file mode 100644 index 0000000..4af7bb9 --- /dev/null +++ b/src/sdb_map.h @@ -0,0 +1,62 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef SDB_MAP_H_ +#define SDB_MAP_H_ + +#include "linkedlist.h" + +#define DEFAULT_MAP_SIZE 30 + +union map_key { + int key_int; + void* key_void; +}; + +typedef union map_key MAP_KEY; + +struct map_node { + MAP_KEY key; + void* value; +}; +typedef struct map_node MAP_NODE; + +struct map { + int size; + int(*hash)(struct map* this, MAP_KEY key); + int(*equal)(MAP_KEY key, MAP_KEY node_key); + void(*freedata)(void* data); + LIST_NODE** map_node_list; +}; +typedef struct map MAP; + +void initialize_map(MAP* map, int size, int(*hash)(struct map* this, MAP_KEY key), + int(*equal)(MAP_KEY key, MAP_KEY node_key), void(*freedata)(void* data)); +void map_put(MAP* map, MAP_KEY key, void* value); +void* map_get(MAP* map, MAP_KEY key); +void map_remove(MAP* this, MAP_KEY key); + +#endif /* SDB_MAP_H_ */ diff --git a/src/sdb_model.c b/src/sdb_model.c index 8b6162c..203def1 100644 --- a/src/sdb_model.c +++ b/src/sdb_model.c @@ -31,7 +31,7 @@ #include "fdevent.h" #include "sdb_model.h" #include "linkedlist.h" -#include "sdb.h" +#include "log.h" const COMMAND NULL_COMMAND = { NULL, @@ -157,7 +157,7 @@ int parse_opt(int argc, char** argv, LIST_NODE* opt_list, LIST_NODE** result_lis INPUT_OPTION* input = (INPUT_OPTION*)malloc(sizeof(INPUT_OPTION)); input->option = option; input->value = value; - append(result_list, input); + prepend(result_list, input); argv = argv + local_pass_arg; argc = argc - local_pass_arg; diff --git a/src/sockets.c b/src/sockets.c old mode 100644 new mode 100755 index b4e27e8..4a02c6a --- a/src/sockets.c +++ b/src/sockets.c @@ -23,800 +23,1130 @@ #include "utils.h" #include "fdevent.h" #include "sdb_constants.h" - -#define TRACE_TAG TRACE_SOCKETS +#include "sdb_map.h" +#include "sdb_client.h" +#include "sockets.h" +#include "transport.h" +#include "log.h" +#include "listener.h" #include "sdb.h" -SDB_MUTEX_DEFINE( socket_list_lock ); - -static void local_socket_close_locked(asocket *s); - -int sendfailmsg(int fd, const char *reason) -{ - char buf[9]; - int len; - len = strlen(reason); - if(len > 0xffff) len = 0xffff; - snprintf(buf, sizeof buf, "FAIL%04x", len); - if(writex(fd, buf, 8)) return -1; - return writex(fd, reason, len); -} +#define TRACE_TAG TRACE_SOCKETS -//extern int online; +static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p); +static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func); +static int peer_enqueue(SDB_SOCKET* socket, PACKET* p); +static void local_socket_destroy(SDB_SOCKET *s); +static void remove_socket(void* s); +static void destroy_socket(void* data); +static void local_socket_event_func(int fd, unsigned ev, void *_s); +static unsigned unhex(unsigned char*s, int len); +static int find_transports(char **serial_out, const char *prefix); +static void unregister_all_tcp_transports(); +static void connect_emulator(char* host, int port, char* buf, int buf_len); + +const unsigned int unsigned_int_bit = sizeof(unsigned int) * 8; +const unsigned int remote_con_right_padding = ~(~0 << sizeof(unsigned int) * 4); +const unsigned int remote_con_flag = 1 << (sizeof(unsigned int) * 8 - 1); +unsigned int remote_con_cur_r_id = 1; +unsigned int remote_con_cur_l_number = 0; +const unsigned int remote_con_l_max = 16; // Ox1111 +const unsigned int remote_con_r_max = ~(~0 << (sizeof(unsigned int) * 8 - 5)); +unsigned int remote_con_l_table[16] = {0,}; static unsigned local_socket_next_id = 1; -static asocket local_socket_list = { - .next = &local_socket_list, - .prev = &local_socket_list, -}; - -/* the the list of currently closing local sockets. -** these have no peer anymore, but still packets to -** write to their fd. -*/ -static asocket local_socket_closing_list = { - .next = &local_socket_closing_list, - .prev = &local_socket_closing_list, -}; - -asocket *find_local_socket(unsigned id) +LIST_NODE* local_socket_list = NULL; + +SDB_SOCKET *find_local_socket(unsigned id) { - asocket *s; - asocket *result = NULL; + SDB_SOCKET *result = NULL; - sdb_mutex_lock(&socket_list_lock); - for (s = local_socket_list.next; s != &local_socket_list; s = s->next) { - if (s->id == id) { + + LIST_NODE* curptr = local_socket_list; + while(curptr != NULL) { + SDB_SOCKET* s = curptr->data; + curptr = curptr->next_ptr; + if(s->local_id == id) { result = s; break; } } - sdb_mutex_unlock(&socket_list_lock); return result; } -static void -insert_local_socket(asocket* s, asocket* list) +static void remove_socket(void* s) { - s->next = list; - s->prev = s->next->prev; - s->prev->next = s; - s->next->prev = s; + SDB_SOCKET* socket = s; + socket->node = NULL; } - -void install_local_socket(asocket *s) +int local_socket_enqueue(SDB_SOCKET *s, PACKET *p) { - sdb_mutex_lock(&socket_list_lock); + D("LS(%X) local enqueue\n", s->local_id); - s->id = local_socket_next_id++; - insert_local_socket(s, &local_socket_list); + if(s->pkt_list == NULL) { + int r = local_enqueue(s->fd, p, s, 0); + if( r == 0) { + //enqueue done normally + return 0; + } + if( r < 0) { + //error occurred + return 1; + } + } + //wait for next round + append(&(s->pkt_list), p); + FDEVENT_ADD(&s->fde, FDE_WRITE); - sdb_mutex_unlock(&socket_list_lock); + return 1; } -void remove_socket(asocket *s) +void local_socket_ready(SDB_SOCKET *s) { - // socket_list_lock should already be held - if (s->prev && s->next) - { - s->prev->next = s->next; - s->next->prev = s->prev; - s->next = 0; - s->prev = 0; - s->id = 0; + D("local socket ready. LS(%X)\n", s->local_id); + if(HAS_SOCKET_STATUS(s, NOTIFY)) { + D("local socket notify to the client FD(%d)\n", s->fd); + sdb_write(s->fd, "OKAY", 4); + REMOVE_SOCKET_STATUS(s, NOTIFY); } + FDEVENT_ADD(&s->fde, FDE_READ); } -void close_all_sockets(atransport *t) +void local_socket_close(SDB_SOCKET *s) { - asocket *s; - - /* this is a little gross, but since s->close() *will* modify - ** the list out from under you, your options are limited. - */ - sdb_mutex_lock(&socket_list_lock); -restart: - for(s = local_socket_list.next; s != &local_socket_list; s = s->next){ - if(s->transport == t || (s->peer && s->peer->transport == t)) { - local_socket_close_locked(s); - goto restart; - } + D("LS(%X) FD(%d)\n", s->local_id, s->fd); + if(HAS_SOCKET_STATUS(s, NOTIFY)) { + D("LS(%X) fail to send notify\n", s->local_id); + sendfailmsg(s->fd, "closed"); + REMOVE_SOCKET_STATUS(s, NOTIFY); } - sdb_mutex_unlock(&socket_list_lock); -} - -static int local_socket_enqueue(asocket *s, apacket *p) -{ - D("LS(%d): enqueue %d\n", s->id, p->len); - - p->ptr = p->data; - /* if there is already data queue'd, we will receive - ** events when it's time to write. just add this to - ** the tail - */ - if(s->pkt_first) { - goto enqueue; - } - /* write as much as we can, until we - ** would block or there is an error/eof - */ - while(p->len > 0) { - int r = sdb_write(s->fd, p->ptr, p->len); - if(r > 0) { - p->len -= r; - p->ptr += r; - continue; - } - if((r == 0) || (errno != EAGAIN)) { - D( "LS(%d): not ready, errno=%d: %s\n", s->id, errno, strerror(errno) ); - s->close(s); - return 1; /* not ready (error) */ - } else { - break; - } + if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) { + send_cmd(0, s->remote_id, A_CLSE, NULL, s->transport); } + int id = s->local_id; - if(p->len == 0) { - put_apacket(p); - return 0; /* ready for more data */ + if(!s->closing && s->pkt_list != NULL) { + s->closing = 1; + FDEVENT_DEL(&s->fde, FDE_READ); + remove_node(&local_socket_list, s->node, remove_socket); + D("LS(%X) pending close\n", id); } - -enqueue: - p->next = 0; - if(s->pkt_first) { - s->pkt_last->next = p; - } else { - s->pkt_first = p; + else { + local_socket_destroy(s); + D("LS(%X) closed\n", id); } - s->pkt_last = p; - - /* make sure we are notified when we can drain the queue */ - fdevent_add(&s->fde, FDE_WRITE); - - return 1; /* not ready (backlog) */ } -static void local_socket_ready(asocket *s) -{ - /* far side is ready for data, pay attention to - readable events */ - fdevent_add(&s->fde, FDE_READ); -// D("LS(%d): ready()\n", s->id); -} - -static void local_socket_close(asocket *s) -{ - sdb_mutex_lock(&socket_list_lock); - local_socket_close_locked(s); - sdb_mutex_unlock(&socket_list_lock); +static void destroy_socket(void* data) { + SDB_SOCKET* socket = data; + socket->node = NULL; + + if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) { + free(socket->read_packet); + unsigned int id = socket->local_id & ~remote_con_flag; + + TRANSPORT* t = socket->transport; + if(t != NULL) { + LIST_NODE* node = t->remote_cnxn_socket; + while(node != NULL) { + SDB_SOCKET* s = node->data; + node = node->next_ptr; + if(s == socket) { + remove_node(&(t->remote_cnxn_socket), s->node, no_free); + break; + } + } + } + remote_con_l_table[id] = 0; + } + socket->local_id = 0; + free(socket); } // be sure to hold the socket list lock when calling this -static void local_socket_destroy(asocket *s) +static void local_socket_destroy(SDB_SOCKET *s) { - apacket *p, *n; - int exit_on_close = s->exit_on_close; + D("LS(%X) FD(%d)\n", s->local_id, s->fd); - D("LS(%d): destroying fde.fd=%d\n", s->id, s->fde.fd); - - /* IMPORTANT: the remove closes the fd + /* IMPORTANT: fdevent_remove closes the fd ** that belongs to this socket */ fdevent_remove(&s->fde); /* dispose of any unwritten data */ - for(p = s->pkt_first; p; p = n) { - D("LS(%d): discarding %d bytes\n", s->id, p->len); - n = p->next; - put_apacket(p); + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + + if(s->node != NULL) { + remove_node(&local_socket_list, s->node, destroy_socket); + } + else { + destroy_socket(s); + } +} + + //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared +#if 0 +//remote_ls_id is a socket in the remote server. +//local_ls_id is a socket of fowarding socket +// left half is local_ls_id and right half is remote_ls_id. +static unsigned int encoding_ls_id(unsigned int remote_ls_id, unsigned int local_ls_id) { + D("LS_R(%X), LS_L(%X)\n", remote_ls_id, local_ls_id); + return remote_ls_id | local_ls_id; +} + +static void send_remote_con_packet(SDB_SOCKET* sock, PACKET* p) { + + //message and data are filled send it to the target. + if(p->msg.command != A_CNXN) { + //A_CNXN does not have to encode local socket id. + p->msg.arg0 = encoding_ls_id(p->msg.arg0, sock->local_id); + LOG_INFO("LS_L(%X) LS_E(%X) encoding done\n", sock->local_id, p->msg.arg0); + } + else { + //for notifying transport that it has remaning socket which wait for CNXN + LOG_INFO("LS_L(%X) message was CNXN\n", sock->local_id); + append(&sock->transport->remote_cnxn_socket, sock); } - remove_socket(s); - free(s); - if (exit_on_close) { - D("local_socket_destroy: exiting\n"); - exit(1); + encoding_packet(p); + //send packet to the target transport + if(sock->transport->write_to_remote(p, sock->transport)) { + LOG_ERROR("fail to write packet\n"); + dump_packet("write error", "remote_con_enqueue", p); } } +static int remote_con_enqueue(SDB_SOCKET* socket, PACKET* p) { + LOG_INFO("LS_L(%X)\n", socket->local_id); -static void local_socket_close_locked(asocket *s) -{ - D("entered. LS(%d) fd=%d\n", s->id, s->fd); - if(s->peer) { - D("LS(%d): closing peer. peer->id=%d peer->fd=%d\n", - s->id, s->peer->id, s->peer->fd); - s->peer->peer = 0; - // tweak to avoid deadlock - if (s->peer->close == local_socket_close) { - local_socket_close_locked(s->peer); - } else { - s->peer->close(s->peer); + PACKET* read_p = socket->read_packet; + + if(read_p->len == 0 && p->len >= sizeof(MESSAGE)) { + if(p->len == sizeof(MESSAGE) + p->msg.data_length) { + //send packet directly without memcpy. + if(check_header(p) || check_data(read_p)) { + LOG_ERROR("bad packet: terminated (data)\n"); + dump_packet("bad packet", "remote_con_enqueue", read_p); + put_apacket(p); + return 0; + } + + LOG_INFO("packet is complete send directly\n"); + send_remote_con_packet(socket, p); + put_apacket(p); + return 1; } - s->peer = 0; } - /* If we are already closing, or if there are no - ** pending packets, destroy immediately - */ - if (s->closing || s->pkt_first == NULL) { - int id = s->id; - local_socket_destroy(s); - D("LS(%d): closed\n", id); - return; + while(p != NULL) { + //read MESSAGE + if(read_p->len < sizeof(MESSAGE)) { + int read_length = 0; + int msg_done = 1; + if(read_p->len + p->len >= sizeof(MESSAGE)) { + read_length = sizeof(MESSAGE) - read_p->len; + } + else { + read_length = p->len; + msg_done = 0; + } + memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length); + p->ptr += read_length; + p->len -= read_length; + read_p->len += read_length; + if(msg_done) { + LOG_INFO("message reading done\n"); + + #if 0 && defined HAVE_BIG_ENDIAN + D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", + socket_p->msg.command, socket_p->msg.arg0, socket_p->msg.arg1, socket_p->msg.data_length, socket_p->msg.data_check, socket_p->msg.magic); + #endif + if(check_header(read_p)) { + LOG_ERROR("bad header: terminated (data)\n"); + dump_packet("bad header", "remote_con_enqueue", read_p); + read_p->len = 0; + put_apacket(p); + return 0; + } + } + else { + //wait for next round + LOG_INFO("wait for next round while reading message\n"); + put_apacket(p); + return 0; + } + } + //read data + unsigned data_length = read_p->msg.data_length + sizeof(MESSAGE); + int read_length = 0; + int data_done = 1; + if(read_p->len + p->len >= data_length) { + read_length = data_length - read_p->len; + } + else { + read_length = p->len; + data_done = 0; + } + + memcpy((void*)&(read_p->msg) + read_p->len, p->ptr, read_length); + p->ptr += read_length; + p->len -= read_length; + read_p->len += read_length; + + if(data_done) { + LOG_INFO("data reading done\n"); + if(check_data(read_p)) { + LOG_ERROR("bad data: terminated (data)\n"); + dump_packet("bad data", "remote_con_enqueue", read_p); + read_p->len = 0; + put_apacket(p); + return 0; + } + + send_remote_con_packet(socket, read_p); + read_p->len = 0; + } + + if(p->len == 0) { + LOG_INFO("reading all the packet is done\n"); + put_apacket(p); + p = NULL; + } } - /* otherwise, put on the closing list - */ - D("LS(%d): closing\n", s->id); - s->closing = 1; - fdevent_del(&s->fde, FDE_READ); - remove_socket(s); - D("LS(%d): put on socket_closing_list fd=%d\n", s->id, s->fd); - insert_local_socket(s, &local_socket_closing_list); + LOG_INFO("read_p->len: %d\n", read_p->len); + return 1; +} +#endif + +static int peer_enqueue(SDB_SOCKET* socket, PACKET* p) { + if(HAS_SOCKET_STATUS(socket, REMOTE_SOCKET)) { + D("entered remote_socket_enqueue RS(%d) WRTE fd=%d\n", + socket->remote_id, socket->fd); + p->msg.command = A_WRTE; + p->msg.arg0 = socket->local_id; + p->msg.arg1 = socket->remote_id; + p->msg.data_length = p->len; + send_packet(p, socket->transport); + put_apacket(p); + FDEVENT_DEL(&socket->fde, FDE_READ); + return 1; + } + + //TODO REMOTE_DEVICE_CONNECT block this code until security issue is resolved +#if 0 + if(HAS_SOCKET_STATUS(socket, REMOTE_CON)) { + return remote_con_enqueue(socket, p); + } +#endif + + if(HAS_SOCKET_STATUS(socket, DEVICE_TRACKER)) { + D("close device tracker.fd: '%d', LS(%X)", socket->fd, socket->local_id); + put_apacket(p); + local_socket_close(socket); + return -1; + } + + //packet can be queued, so do not free it here. + return smart_socket_enqueue(socket, p); +} + +/** + * If returns 0, appending is done. packet is freed. + * 1, EAGAIN happens packet is put in the queue. wait for next round. + * -1, error happens. socket is closed. return immediately. + */ +static int local_enqueue(int fd, PACKET* p, SDB_SOCKET* s, int event_func) { + D("LS(%X) FD(%d)\n", s->local_id, fd); + while(p->len > 0) { + dump_packet("0", "local_enqueue", p); + int r = sdb_write(fd, p->ptr, p->len); + if(r < 0) { + if(errno == EAGAIN) { + //packet is used next round do not free. + D( "LS(%X) EAGAIN pending to next round\n", s->local_id); + return 1; + } + //TODO if we handle EINTR when local_socket_enqueue calls this, Windows debug fails. + if(errno == EINTR && event_func) { + D( "LS(%X) EINTR continue\n", s->local_id); + continue; + } + } + if(r > 0) { + p->len -= r; + p->ptr += r; + continue; + } + //error happens. close the socket. + D( "LS(%X) error ER(%d) %s\n", s->local_id, errno, strerror(errno) ); + put_apacket(p); + local_socket_close(s); + return -1; /* not ready (error) */ + } + //append done. + D("LS(%X) enqueue done\n", s->local_id); + put_apacket(p); + return 0; } static void local_socket_event_func(int fd, unsigned ev, void *_s) { - asocket *s = _s; + SDB_SOCKET *s = _s; - D("LS(%d): event_func(fd=%d(==%d), ev=%04x)\n", s->id, s->fd, fd, ev); + D("LS(%X) FD(%d)\n", s->local_id, s->fd); /* put the FDE_WRITE processing before the FDE_READ ** in order to simplify the code. */ if(ev & FDE_WRITE){ - apacket *p; - - while((p = s->pkt_first) != 0) { - while(p->len > 0) { - int r = sdb_write(fd, p->ptr, p->len); - if(r > 0) { - p->ptr += r; - p->len -= r; - continue; - } - if(r < 0) { - /* returning here is ok because FDE_READ will - ** be processed in the next iteration loop - */ - if(errno == EAGAIN) return; - if(errno == EINTR) continue; - } - D(" closing after write because r=%d and errno is %d\n", r, errno); - s->close(s); - return; + D("LS(%X) gets a write event\n", s->local_id); + while(s->pkt_list != NULL) { + PACKET* p = s->pkt_list->data; + int r = local_enqueue(fd, p, s, 1); + + if ( r == 0) { + //packet enqueue done + remove_first(&s->pkt_list, no_free); } - - if(p->len == 0) { - s->pkt_first = p->next; - if(s->pkt_first == 0) s->pkt_last = 0; - put_apacket(p); + else { + //in both cases r = 1 and r = -1, return immediately. + return; } } - - /* if we sent the last packet of a closing socket, - ** we can now destroy it. - */ if (s->closing) { - D(" closing because 'closing' is set after write\n"); - s->close(s); + D("LS(%X) closing because 'closing' is set after write\n", s->local_id); + local_socket_close(s); return; } - - /* no more packets queued, so we can ignore - ** writable events again and tell our peer - ** to resume writing - */ - fdevent_del(&s->fde, FDE_WRITE); - s->peer->ready(s->peer); + //all the packet in the pkt_list is enqueued. write event is done. + FDEVENT_DEL(&s->fde, FDE_WRITE); + if(HAS_SOCKET_STATUS(s, REMOTE_SOCKET)) { + send_cmd(s->local_id, s->remote_id, A_OKAY, NULL, s->transport); + } } if(ev & FDE_READ){ - apacket *p = get_apacket(); - unsigned char *x = p->data; + D("LS(%X) gets a read event\n", s->local_id); + //packet should be freed in peer_enqueue + PACKET *p = get_apacket(); + + void *x; + if(HAS_SOCKET_STATUS(s, REMOTE_CON)) { + x = &p->msg; + p->ptr = &p->msg; + } + else { + x = p->data; + } size_t avail = MAX_PAYLOAD; - int r; - int is_eof = 0; + int r = 1; while(avail > 0) { r = sdb_read(fd, x, avail); - D("LS(%d): post sdb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail); if(r > 0) { avail -= r; x += r; continue; } if(r < 0) { - if(errno == EAGAIN) break; - if(errno == EINTR) continue; + if(errno == EAGAIN) { + D("LS(%X) EAGAIN while reading\n", s->local_id); + break; + } + if(errno == EINTR) { + continue; + } + LOG_ERROR("LS(%X) error while reading ER(%d), %s\n", s->local_id, errno, strerror(errno)); + // r = 0 means EOF or unhandled error. + r = 0; } - - /* r = 0 or unhandled error */ - is_eof = 1; + D("LS(%X) reading done\n", s->local_id); break; } - D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d\n", - s->id, s->fd, r, is_eof, s->fde.force_eof); - if((avail == MAX_PAYLOAD) || (s->peer == 0)) { + + if(avail == MAX_PAYLOAD) { put_apacket(p); } else { p->len = MAX_PAYLOAD - avail; - - r = s->peer->enqueue(s->peer, p); - D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd, r); - - if(r < 0) { - /* error return means they closed us as a side-effect - ** and we must return immediately. - ** - ** note that if we still have buffered packets, the - ** socket will be placed on the closing socket list. - ** this handler function will be called again - ** to process FDE_WRITE events. - */ + if(peer_enqueue(s, p) < 0) { + //local socket is already closed by peer or should not close the socket. return; } - - if(r > 0) { - /* if the remote cannot accept further events, - ** we disable notification of READs. They'll - ** be enabled again when we get a call to ready() - */ - fdevent_del(&s->fde, FDE_READ); - } } - /* Don't allow a forced eof if data is still there */ - if((s->fde.force_eof && !r) || is_eof) { - D(" closing because is_eof=%d r=%d s->fde.force_eof=%d\n", is_eof, r, s->fde.force_eof); - s->close(s); + if(r == 0) { + D("LS(%X) EOF. closing\n", s->local_id); + local_socket_close(s); } } - - if(ev & FDE_ERROR){ - /* this should be caught be the next read or write - ** catching it here means we may skip the last few - ** bytes of readable data. - */ -// s->close(s); - D("LS(%d): FDE_ERROR (fd=%d)\n", s->id, s->fd); - - return; - } } -asocket *create_local_socket(int fd) +SDB_SOCKET *create_local_socket(int fd) { - asocket *s = calloc(1, sizeof(asocket)); - if (s == NULL) fatal("cannot allocate socket"); + D("FD(%d)\n", fd); + SDB_SOCKET *s = calloc(1, sizeof(SDB_SOCKET)); + if (s == NULL) { + LOG_FATAL("cannot allocate socket\n"); + } + s->status = 0; + s->node = NULL; + s->pkt_list = NULL; s->fd = fd; - s->enqueue = local_socket_enqueue; - s->ready = local_socket_ready; - s->close = local_socket_close; - install_local_socket(s); + + s->local_id = local_socket_next_id++; + s->node = prepend(&local_socket_list, s); fdevent_install(&s->fde, fd, local_socket_event_func, s); -/* fdevent_add(&s->fde, FDE_ERROR); */ - //fprintf(stderr, "Created local socket in create_local_socket \n"); - D("LS(%d): created (fd=%d)\n", s->id, s->fd); + D("LS(%X) FD(%d) created\n", s->local_id, s->fd); return s; } -asocket *create_local_service_socket(const char *name) -{ - asocket *s; - int fd; - - fd = service_to_fd(name); - if(fd < 0) return 0; - - s = create_local_socket(fd); - D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); - - return s; +void create_remote_connection_socket(SDB_SOCKET* socket) { + LOG_INFO("FD(%d)\n", socket->fd); + SET_SOCKET_STATUS(socket, REMOTE_CON); + socket->read_packet = malloc(sizeof(PACKET)); + socket->read_packet->len = 0; } -static asocket *create_host_service_socket(const char *name, const char* serial) +void connect_to_remote(SDB_SOCKET *s, const char *destination) { - asocket *s; - - s = host_service_to_socket(name, serial); + D("LS(%X)\n", s->local_id); + PACKET *p = get_apacket(); + int len = strlen(destination) + 1; - if (s != NULL) { - D("LS(%d) bound to '%s'\n", s->id, name); - return s; + if(len > (MAX_PAYLOAD-1)) { + LOG_FATAL("destination oversized\n"); } - return s; + D("LS(%X): connect('%s')\n", s->local_id, destination); + p->msg.command = A_OPEN; + p->msg.arg0 = s->local_id; + p->msg.data_length = len; + strcpy((char*) p->data, destination); + send_packet(p, s->transport); + put_apacket(p); } -/* a Remote socket is used to send/receive data to/from a given transport object -** it needs to be closed when the transport is forcibly destroyed by the user -*/ -typedef struct aremotesocket { - asocket socket; - adisconnect disconnect; -} aremotesocket; +static unsigned unhex(unsigned char*s, int len) { -static int remote_socket_enqueue(asocket *s, apacket *p) -{ - D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n", - s->id, s->fd, s->peer->fd); - p->msg.command = A_WRTE; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - p->msg.data_length = p->len; - send_packet(p, s->transport); - return 1; + unsigned n = 0; + while(len > 0) { + MAP_KEY key; + key.key_int = (int)(0 | *s++); + void* _c = map_get(&hex_map, key); + unsigned c = (unsigned)_c; + n = (n << 4) | c; + len--; + } + return n; } -static void remote_socket_ready(asocket *s) -{ - D("entered remote_socket_ready RS(%d) OKAY fd=%d peer.fd=%d\n", - s->id, s->fd, s->peer->fd); - apacket *p = get_apacket(); - p->msg.command = A_OKAY; - p->msg.arg0 = s->peer->id; - p->msg.arg1 = s->id; - send_packet(p, s->transport); -} +/** + * return 0 for host + * return 1 for transport + */ +static int parse_host_service(char* host_str, char** service_ptr, TRANSPORT** t, char** err_str) { -static void remote_socket_close(asocket *s) -{ - D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n", - s->id, s->fd, s->peer?s->peer->fd:-1); - apacket *p = get_apacket(); - p->msg.command = A_CLSE; - if(s->peer) { - p->msg.arg0 = s->peer->id; - s->peer->peer = 0; - D("RS(%d) peer->close()ing peer->id=%d peer->fd=%d\n", - s->id, s->peer->id, s->peer->fd); - s->peer->close(s->peer); - } - p->msg.arg1 = s->id; - send_packet(p, s->transport); - D("RS(%d): closed\n", s->id); - remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); - free(s); + int prefix_len = strlen(PREFIX_HOST_USB); + if (!strncmp(host_str, PREFIX_HOST_USB, prefix_len)) { + *service_ptr = host_str + prefix_len; + *t = acquire_one_transport(kTransportUsb, NULL, err_str); + return 0; + } + prefix_len = strlen(PREFIX_HOST_LOCAL); + if (!strncmp(host_str, PREFIX_HOST_LOCAL, prefix_len)) { + *service_ptr = host_str + prefix_len; + *t = acquire_one_transport(kTransportLocal, NULL, err_str); + return 0; + } + prefix_len = strlen(PREFIX_HOST); + if (!strncmp(host_str, PREFIX_HOST, prefix_len)) { + if(!strncmp(host_str, PREFIX_TRANSPORT_ANY, strlen(PREFIX_TRANSPORT_ANY))) { + *t = acquire_one_transport(kTransportAny, NULL, err_str); + return 1; + } + if(!strncmp(host_str, PREFIX_TRANSPORT_LOCAL, strlen(PREFIX_TRANSPORT_LOCAL))) { + *t = acquire_one_transport(kTransportLocal, NULL, err_str); + return 1; + } + if(!strncmp(host_str, PREFIX_TRANSPORT_USB, strlen(PREFIX_TRANSPORT_USB))) { + *t = acquire_one_transport(kTransportUsb, NULL, err_str); + return 1; + } + if(!strncmp(host_str, PREFIX_TRANSPORT_SERIAL, strlen(PREFIX_TRANSPORT_SERIAL))) { + *t = acquire_one_transport(kTransportAny, host_str + strlen(PREFIX_TRANSPORT_SERIAL), err_str); + return 1; + } + *service_ptr = host_str + prefix_len; + //does not have to find transport. + *t = NULL; + *err_str = NULL; + return 0; + } + prefix_len = strlen(PREFIX_HOST_ANY); + if(!strncmp(host_str, PREFIX_HOST_ANY, prefix_len)) { + *service_ptr = host_str + prefix_len; + *t = acquire_one_transport(kTransportAny, NULL, err_str); + return 0; + } + prefix_len = strlen(PREFIX_HOST_SERIAL); + if(!strncmp(host_str, PREFIX_HOST_SERIAL, prefix_len)) { + char* serial = host_str + prefix_len; + char* end = strchr(serial, ':'); + if(end == NULL) { + *err_str = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND; + return 0; + } + *end = '\0'; + *service_ptr = end + 1; + *t = acquire_one_transport(kTransportAny, serial, err_str); + return 0; + } + *service_ptr = NULL; + return 0; } -static void remote_socket_disconnect(void* _s, atransport* t) -{ - asocket* s = _s; - asocket* peer = s->peer; +static int handle_request_with_t(SDB_SOCKET* socket, char* service, TRANSPORT* t, char* err_str) { + int forward = 0; + if(!strncmp(service,"forward:",8)) { + forward = 8; + } + else if (!strncmp(service,"killforward:",12)) { + forward = 12; + } + + if(forward) { + char* forward_err = NULL; + + char *local, *remote = NULL; + local = service + forward; + remote = strchr(local,';'); + + if (t == NULL || t->connection_state == CS_OFFLINE) { + if(t != NULL) { + forward_err = (char*)TRANSPORT_ERR_TARGET_OFFLINE; + } + else { + forward_err = err_str; + } + goto sendfail; + } + if(remote == 0 || remote[1] == '\0') { + forward_err = "malformed forward spec"; + goto sendfail; + } + *remote++ = 0; - D("remote_socket_disconnect RS(%d)\n", s->id); - if (peer) { - peer->peer = NULL; - peer->close(peer); + if (forward == 8) { + if(!install_listener(local, remote, t)) { + writex(socket->fd, "OKAYOKAY", 8); + return 0; + } + else { + LOG_INFO("LS(%X) T(%s) fail to install listener\n", socket->fd, t->device_name); + forward_err = "cannot install listener"; + } + } else { + if(!remove_listener(local, remote, t)) { + writex(socket->fd, "OKAYOKAY", 8); + return 0; + } else { + LOG_INFO("LS(%X) T(%s) fail to remove listener\n", socket->fd, t->device_name); + forward_err = "cannot remove listener"; + } + } +sendfail: + sendfailmsg(socket->fd, forward_err); + return 0; + } + else if(!strncmp(service,"get-serialno",strlen("get-serialno"))) { + if (t) { + sendokmsg(socket->fd, t->serial); + } + else { + sendokmsg(socket->fd, "target not exist"); + } + return 0; + } + else if(!strncmp(service,"get-state",strlen("get-state"))) { + const char *state = connection_state_name(t); + sendokmsg(socket->fd, state); + return 0; } - remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect ); - free(s); -} -asocket *create_remote_socket(unsigned id, atransport *t) -{ - asocket *s = calloc(1, sizeof(aremotesocket)); - adisconnect* dis = &((aremotesocket*)s)->disconnect; - - if (s == NULL) fatal("cannot allocate socket"); - s->id = id; - s->enqueue = remote_socket_enqueue; - s->ready = remote_socket_ready; - s->close = remote_socket_close; - s->transport = t; - - dis->func = remote_socket_disconnect; - dis->opaque = s; - add_transport_disconnect( t, dis ); - D("RS(%d): created\n", s->id); - return s; + //TODO REMOTE_DEVICE_CONNECT block this code until security issue is cleared +#if 0 + else if(!strncmp(service,"_dev_con",strlen("_dev_con"))) { + if(t == NULL) { + sendfailmsg(socket->fd, err_str); + return 0; + } + if(assign_remote_connect_socket_lid(socket)) { + sendfailmsg(socket->fd, "remote connect socket exceeds limit. cannot create remote socket\n"); + local_socket_close(socket); + return 0; + } + socket->transport = t; + create_remote_connection_socket(socket); + + char* buf = "OKAY"; + writex(socket->fd, buf, strlen(buf)); + return 0; + } +#endif + + return -1; } -void connect_to_remote(asocket *s, const char *destination) +static int find_transports(char **serial_out, const char *prefix) { - D("Connect_to_remote call RS(%d) fd=%d\n", s->id, s->fd); - apacket *p = get_apacket(); - int len = strlen(destination) + 1; + int nr = 0; // not found + char *match = NULL; - if(len > (MAX_PAYLOAD-1)) { - fatal("destination oversized"); - } + if (!serial_out || !prefix) + return -1; - D("LS(%d): connect('%s')\n", s->id, destination); - p->msg.command = A_OPEN; - p->msg.arg0 = s->id; - p->msg.data_length = len; - strcpy((char*) p->data, destination); - send_packet(p, s->transport); -} + sdb_mutex_lock(&transport_lock, "transport find_transports"); + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; + char* serial = t->serial; + if (!serial || !serial[0]) + continue; + if (!strncmp(prefix, serial, strlen(prefix))) { + match = serial; + nr++; + } -/* this is used by magic sockets to rig local sockets to - send the go-ahead message when they connect */ -static void local_socket_ready_notify(asocket *s) -{ - s->ready = local_socket_ready; - s->close = local_socket_close; - sdb_write(s->fd, "OKAY", 4); - s->ready(s); + if (nr > 1) { + match = NULL; + break; + } + } + sdb_mutex_unlock(&transport_lock, "transport find_transports"); + + if (nr == 1 && match) { + *serial_out = strdup(match); + } else if (nr == 0) { + asprintf(serial_out, "device not found"); + } else if (nr > 1) { + asprintf(serial_out, "more than one device and emulator"); + } + + return nr; } -/* this is used by magic sockets to rig local sockets to - send the failure message if they are closed before - connected (to avoid closing them without a status message) */ -static void local_socket_close_notify(asocket *s) +static void unregister_all_tcp_transports() { - s->ready = local_socket_ready; - s->close = local_socket_close; - sendfailmsg(s->fd, "closed"); - s->close(s); + sdb_mutex_lock(&transport_lock, "transport unregister_all_tcp_transports"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; + if (t->type == kTransportLocal && t->sdb_port == 0) { + //just kick the transport. transport is destroied by transport thread. + if(!t->kicked) { + t->kicked = 1; + t->kick(t); + } + } + } + + sdb_mutex_unlock(&transport_lock, "transport unregister_all_tcp_transports"); } -unsigned unhex(unsigned char *s, int len) +static int handle_host_request(char *service, SDB_SOCKET* socket) { - unsigned n = 0, c; - - while(len-- > 0) { - switch((c = *s++)) { - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': case '8': - case '9': - c -= '0'; - break; - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - c = c - 'a' + 10; - break; - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - c = c - 'A' + 10; - break; - default: - return 0xffffffff; + LOG_INFO("LS(%X)\n", socket->fd); + char cmd_buf[1024]; + int cbuf_size = sizeof cmd_buf; + + if (!strncmp(service, "serial-match:", 13)) { + char *tmp = service + 13; + char *serial = NULL; + int ret = -1; + D("Try to find device for: %s\n", tmp); + ret = find_transports(&serial, tmp); + if (ret <= 0) { + LOG_ERROR("No device found\n"); + sendfailmsg(socket->fd, serial); + } else if (ret == 1) { + sendokmsg(socket->fd, serial); + } else { + LOG_ERROR("found more than one devices matched: %d\n", ret); + sendfailmsg(socket->fd, serial); + } + free(serial); + return 0; + } + // return a list of all connected devices + if (!strcmp(service, "devices")) { + list_transports(cmd_buf, cbuf_size); + sendokmsg(socket->fd, cmd_buf); + return 0; + } + + // add a new TCP transport, device or emulator + if (!strncmp(service, "connect:", 8)) { + char* host = service + 8; + char* portstr = strchr(host, ':'); + int port = -1; + + if(portstr) { + *portstr++ = 0; + if(!sscanf(portstr, "%d", &port)) { + snprintf(cmd_buf, cbuf_size, "bad port format '%s'", portstr); + goto connect_done; + } } + connect_emulator(host, port, cmd_buf, cbuf_size); - n = (n << 4) | c; +connect_done: + sendokmsg(socket->fd, cmd_buf); + return 0; } - return n; -} + // remove TCP transport + if (!strncmp(service, "disconnect:", 11)) { + char* serial = service + 11; + if (serial[0]) { + if (!strchr(serial, ':')) { + snprintf(cmd_buf, cbuf_size, "%s:26101", serial); + serial = cmd_buf; + } + TRANSPORT *t = acquire_one_transport(kTransportAny, serial, NULL); -/* skip_host_serial return the position in a string - skipping over the 'serial' parameter in the SDB protocol, - where parameter string may be a host:port string containing - the protocol delimiter (colon). */ -char *skip_host_serial(char *service) { - char *first_colon, *serial_end; + if (t) { + cmd_buf[0] = '\0'; + kick_transport(t); + } else { + snprintf(cmd_buf, cbuf_size, "No such device %s", serial); + } + } else { + unregister_all_tcp_transports(); + cmd_buf[0] = '\0'; + } - first_colon = strchr(service, ':'); - if (!first_colon) { - /* No colon in service string. */ - return NULL; + sendokmsg(socket->fd, cmd_buf); + return 0; } - serial_end = first_colon; - if (isdigit(serial_end[1])) { - serial_end++; - while ((*serial_end) && isdigit(*serial_end)) { - serial_end++; + + if (!strncmp(service, "device_con:", 11)) { + char* _host = service + 11; + char host_buf[4096]; + char target_buf[4096]; + char full_cmd[4096]; + char full_serial[256]; + strncpy(host_buf, _host, sizeof(host_buf) - 1); + _host = host_buf; + char* serial = strchr(host_buf, ':'); + *(serial) = '\0'; + serial++; + + int fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM); + if (fd < 0) { + snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host); + LOG_ERROR(target_buf); + sendfailmsg(socket->fd, target_buf); + return 0; + } + D("FD(%d) remote connected with host: %s\n", fd, _host); + + D("FULL_CMD %s\n", full_cmd); + snprintf(full_cmd, sizeof(full_cmd), "host:serial-match:%s", serial); + if(!send_service_with_length(fd, full_cmd, socket->fd)) { + if(!sdb_status(fd, socket->fd)) { + int n = read_msg_size(fd); + if(n > 0 && n < 256) { + if(!readx(fd, full_serial, n)) { + full_serial[n] = 0; + serial = full_serial; + goto success; + } + } + snprintf(target_buf, sizeof(target_buf), "fail to read full serial of %s", serial); + sendfailmsg(socket->fd, target_buf); + } + } + sdb_close(fd); + return 0; + +success: + sdb_close(fd); + fd = sdb_host_connect(_host, DEFAULT_SDB_PORT, SOCK_STREAM); + if (fd < 0) { + snprintf(target_buf, sizeof(target_buf), "fail to connect with '%s'", _host); + LOG_ERROR(target_buf); + sendfailmsg(socket->fd, target_buf); + return 0; } - if ((*serial_end) != ':') { - // Something other than numbers was found, reset the end. - serial_end = first_colon; + D("FD(%d) remote connected\n", fd); + get_host_prefix(target_buf, sizeof target_buf, kTransportAny, serial, host); + snprintf(full_cmd, sizeof full_cmd, "%s_dev_con",target_buf); + + D("FULL_CMD: %s\n", full_cmd); + if(!send_service_with_length(fd, full_cmd, socket->fd)) { + if(!sdb_status(fd, socket->fd)) { + if(!register_device_con_transport(fd, serial)) { + snprintf(target_buf, sizeof target_buf, "success to connect with remote target '%s'\n", serial); + snprintf(full_cmd, sizeof(full_cmd), "OKAY%04x%s",(unsigned)strlen(target_buf), target_buf); + if(!writex(socket->fd, full_cmd, strlen(full_cmd))) { + return 0; + } + else { + sendfailmsg(socket->fd, "fail to write OKAY message\n"); + } + } + else { + sendfailmsg(socket->fd, "fail to connect with remote device\n"); + } + } } + sdb_close(fd); + return 0; } - return serial_end; + + // returns our value for SDB_SERVER_VERSION + if (!strcmp(service, "version")) { + snprintf(cmd_buf, cbuf_size, "%04x", SDB_SERVER_VERSION); + sendokmsg(socket->fd, cmd_buf); + return 0; + } + + // indicates a new emulator instance has started + if (!strncmp(service,"emulator:",9)) { /* tizen specific */ + D("new emulator is in\n"); + char *tmp = strtok(service+9, DEVICEMAP_SEPARATOR); + int port = 0; + + if (tmp == NULL) { + port = atoi(service+9); + } else { + port = atoi(tmp); + tmp = strtok(NULL, DEVICEMAP_SEPARATOR); + } + local_connect(port, tmp); + return 0; + } + + if(!strcmp(service, "kill")) { + LOG_INFO("sdb is being killed\n"); + sdb_cleanup(); + sdb_write(socket->fd, "OKAY", 4); + exit(0); + } + + return -1; } -static int smart_socket_enqueue(asocket *s, apacket *p) +static int smart_socket_enqueue(SDB_SOCKET *s, PACKET *p) { unsigned len; - char *service = NULL; - char* serial = NULL; - transport_type ttype = kTransportAny; - D("SS(%d): enqueue %d\n", s->id, p->len); + D("LS(%X)\n", s->local_id); - if(s->pkt_first == 0) { - s->pkt_first = p; - s->pkt_last = p; - } else { - if((s->pkt_first->len + p->len) > MAX_PAYLOAD) { - D("SS(%d): overflow\n", s->id); + if(s->pkt_list == NULL) { + prepend(&s->pkt_list, p); + } + else { + PACKET* socket_packet = s->pkt_list->data; + if((socket_packet->len + p->len) > MAX_PAYLOAD) { + D("SS(%d): overflow\n", s->local_id); put_apacket(p); goto fail; } - memcpy(s->pkt_first->data + s->pkt_first->len, + memcpy(socket_packet->data + socket_packet->len, p->data, p->len); - s->pkt_first->len += p->len; + socket_packet->len += p->len; put_apacket(p); - p = s->pkt_first; + p = socket_packet; } /* don't bother if we can't decode the length */ if(p->len < 4) return 0; len = unhex(p->data, 4); + if((len < 1) || (len > 1024)) { - D("SS(%d): bad size (%d)\n", s->id, len); + D("LS(%X): bad size (%d)\n", s->local_id, len); goto fail; } - D("SS(%d): len is %d\n", s->id, len ); /* can't do anything until we have the full header */ if((len + 4) > p->len) { - D("SS(%d): waiting for %d more bytes\n", s->id, len+4 - p->len); + D("LS(%X): waiting for %d more bytes in smart socket\n", s->local_id, len+4 - p->len); return 0; } p->data[len + 4] = 0; + D("LS(%X) %s\n", s->local_id, p->data + 4); - D("SS(%d): '%s'\n", s->id, (char*) (p->data + 4)); - - service = (char *)p->data + 4; - if(!strncmp(service, PREFIX_HOST_SERIAL, strlen(PREFIX_HOST_SERIAL))) { - char* serial_end; - service += strlen(PREFIX_HOST_SERIAL); - - // serial number should follow "host:" and could be a host:port string. - serial_end = skip_host_serial(service); - if (serial_end) { - *serial_end = 0; // terminate string - serial = service; - service = serial_end + 1; - } - ttype = kTransportUsb; - } else if (!strncmp(service, PREFIX_HOST_USB, strlen(PREFIX_HOST_USB))) { - service += strlen(PREFIX_HOST_USB); - } else if (!strncmp(service, PREFIX_HOST_LOCAL, strlen(PREFIX_HOST_LOCAL))) { - ttype = kTransportLocal; - service += strlen(PREFIX_HOST_LOCAL); - } else if (!strncmp(service, PREFIX_HOST, strlen(PREFIX_HOST))) { - ttype = kTransportAny; - service += strlen(PREFIX_HOST); - } else { - service = NULL; + char* host_str = (char *)p->data + 4; + char *service = NULL; + char* err_str = NULL; + TRANSPORT* t = NULL; + + if(parse_host_service(host_str, &service, &t, &err_str) == 1) { + if (t && t->connection_state != CS_OFFLINE) { + s->transport = t; + sdb_write(s->fd, "OKAY", 4); + D("LS(%X) get transport T(%s)", s->local_id, t->device_name); + } else { + if(t != NULL) { + err_str = (char*)TRANSPORT_ERR_TARGET_OFFLINE; + } + LOG_ERROR("LS(%X) get no transport", s->local_id); + sendfailmsg(s->fd, err_str); + } + p->len = 0; + return 0; } if (service) { - asocket *s2; - - /* some requests are handled immediately -- in that - ** case the handle_host_request() routine has sent - ** the OKAY or FAIL message and all we have to do - ** is clean up. - */ - if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) { + if(handle_request_with_t(s, service, t, err_str) == 0) { + D( "LS(%X): handled host service with '%s'\n", s->local_id, service ); + goto fail; + } + + if(handle_host_request(service, s) == 0) { /* XXX fail message? */ - D( "SS(%d): handled host service '%s'\n", s->id, service ); + D( "LS(%X): handled host service '%s'\n", s->local_id, service ); goto fail; } - if (!strncmp(service, "transport", strlen("transport"))) { - D( "SS(%d): okay transport\n", s->id ); - p->len = 0; + + if (!strcmp(service,"track-devices")) { + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + D("LS(%X): OKAY\n", s->local_id); + SET_SOCKET_STATUS(s, DEVICE_TRACKER); + sdb_write(s->fd, "OKAY", 4); + + D( "LS(%X) fd: '%d' for device tracking\n", s->local_id, s->fd ); + char buffer[1024]; + int len; + len = list_transports_msg(buffer, sizeof(buffer)); + device_tracker_send(s, buffer, len); return 0; } - - /* try to find a local service with this name. - ** if no such service exists, we'll fail out - ** and tear down here. - */ - s2 = create_host_service_socket(service, serial); - if(s2 == 0) { - D( "SS(%d): couldn't create host service '%s'\n", s->id, service ); - sendfailmsg(s->peer->fd, "unknown host service"); + else { + D( "LS(%X): couldn't create host service '%s'\n", s->local_id, service ); + sendfailmsg(s->fd, "unknown host service"); goto fail; } - - /* we've connected to a local host service, - ** so we make our peer back into a regular - ** local socket and bind it to the new local - ** service socket, acknowledge the successful - ** connection, and close this smart socket now - ** that its work is done. - */ - sdb_write(s->peer->fd, "OKAY", 4); - - s->peer->ready = local_socket_ready; - s->peer->close = local_socket_close; - s->peer->peer = s2; - s2->peer = s->peer; - s->peer = 0; - D( "SS(%d): okay\n", s->id ); - s->close(s); - - /* initial state is "ready" */ - s2->ready(s2); - return 0; } if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) { - /* if there's no remote we fail the connection - ** right here and terminate it - */ - sendfailmsg(s->peer->fd, "device offline (x)"); + sendfailmsg(s->fd, "device offline (x)"); goto fail; } + if (!(s->transport) || (s->transport->connection_state == CS_PWLOCK)) { + sendfailmsg(s->fd, "device locked"); + goto fail; + } - /* instrument our peer to pass the success or fail - ** message back once it connects or closes, then - ** detach from it, request the connection, and - ** tear down - */ - s->peer->ready = local_socket_ready_notify; - s->peer->close = local_socket_close_notify; - s->peer->peer = 0; - /* give him our transport and upref it */ - s->peer->transport = s->transport; - - connect_to_remote(s->peer, (char*) (p->data + 4)); - s->peer = 0; - s->close(s); - return 1; + if(s->transport->type == kTransportRemoteDevCon) { + if(assign_remote_connect_socket_rid(s)) { + sendfailmsg(s->fd, "remote connect socket exceeds limit. cannot create remote socket\n"); + local_socket_close(s); + return -1; + } + } + + SET_SOCKET_STATUS(s, NOTIFY); + connect_to_remote(s, (char*) (p->data + 4)); + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + FDEVENT_DEL(&s->fde, FDE_READ); + return 0; fail: - /* we're going to close our peer as a side-effect, so - ** return -1 to signal that state to the local socket - ** who is enqueueing against us - */ - s->close(s); + + free_list(s->pkt_list, put_apacket); + s->pkt_list = NULL; + if(!HAS_SOCKET_STATUS(s, REMOTE_CON)) { + //do not close socket if it is remote connected socket + local_socket_close(s); + } return -1; } -static void smart_socket_ready(asocket *s) -{ - D("SS(%d): ready\n", s->id); +int assign_remote_connect_socket_rid (SDB_SOCKET* s) { + if(remote_con_cur_r_id > remote_con_r_max) { + LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd); + return -1; + } + int remote_id = (remote_con_cur_r_id << 4) | remote_con_flag; + LOG_INFO("LS(%X) -> LS_R(%X)\n", s->local_id, remote_id); + s->local_id = remote_id; + remote_con_cur_r_id++; + return 0; } -static void smart_socket_close(asocket *s) -{ - D("SS(%d): closed\n", s->id); - if(s->pkt_first){ - put_apacket(s->pkt_first); +int assign_remote_connect_socket_lid (SDB_SOCKET* s) { + if(remote_con_cur_l_number >= remote_con_l_max) { + LOG_ERROR("remote connect socket exceeds limit. cannot create remote socket for LS(%X) FD(%d)\n", s->local_id, s->fd); + return -1; } - if(s->peer) { - s->peer->peer = 0; - s->peer->close(s->peer); - s->peer = 0; + int i = 0; + for(i = 0; i< remote_con_l_max; i++) { + if(remote_con_l_table[i] == 0) { + unsigned int remote_id = i | remote_con_flag; + remote_con_cur_l_number++; + LOG_INFO("LS(%X) -> LS_L(%X)\n", s->local_id, remote_id); + s->local_id = remote_id; + remote_con_l_table[i] = 1; + return 0; + } } - free(s); + LOG_ERROR("not enough space in remote_con_l_table\n"); + return -1; } -asocket *create_smart_socket(void (*action_cb)(asocket *s, const char *act)) +int +device_tracker_send( SDB_SOCKET* local_socket, + const char* buffer, + int len ) { - D("Creating smart socket \n"); - asocket *s = calloc(1, sizeof(asocket)); - if (s == NULL) fatal("cannot allocate socket"); - s->enqueue = smart_socket_enqueue; - s->ready = smart_socket_ready; - s->close = smart_socket_close; - s->extra = action_cb; - - D("SS(%d): created %p\n", s->id, action_cb); - return s; + D("device tracker send to the socket. LS(%X), fd: '%d'\n", local_socket->local_id, local_socket->fd); + PACKET* p = get_apacket(); + + memcpy(p->data, buffer, len); + p->len = len; + p->ptr = p->data; + //packet should not be freed after local_socket_enqueue because it can be still used in local socket packet queue. + return local_socket_enqueue( local_socket, p ); } -void smart_socket_action(asocket *s, const char *act) -{ +static void connect_emulator(char* host, int port, char* buf, int buf_len) { + if(port < 0) { + port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT; + } + LOG_INFO("connecting ip: '%s', port: '%d'\n", host, port); -} + int fd = sdb_host_connect(host, port, SOCK_STREAM); + if (fd < 0) { + snprintf(buf, buf_len, "fail to connect to %s", host); + return; + } -void connect_to_smartsocket(asocket *s) -{ - D("Connecting to smart socket \n"); - asocket *ss = create_smart_socket(smart_socket_action); - s->peer = ss; - ss->peer = s; - s->ready(s); + LOG_INFO("FD(%d) connected\n", fd); + close_on_exec(fd); + disable_tcp_nagle(fd); + char serial[100]; + snprintf(serial, sizeof(serial), "%s:%d", host, port); + register_socket_transport(fd, serial, port, 0, NULL); + snprintf(buf, buf_len, "connected to %s", serial); } diff --git a/src/sockets.h b/src/sockets.h new file mode 100644 index 0000000..51fe875 --- /dev/null +++ b/src/sockets.h @@ -0,0 +1,62 @@ +/* +* SDB - Smart Development Bridge +* +* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. +* +* Contact: +* Ho Namkoong +* Yoonki Park +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* Contributors: +* - S-Core Co., Ltd +* +*/ + +#ifndef SOCKETS_H_ +#define SOCKETS_H_ + +#include "common_modules.h" + +#define SET_SOCKET_STATUS(asocket, _status) ((asocket)->status |= (1 << _status)) +#define REMOVE_SOCKET_STATUS(asocket, _status) ((asocket)->status &= ~(1 << _status)) +#define HAS_SOCKET_STATUS(asocket, _status) ((asocket)->status & (1 << _status)) + +extern const unsigned int unsigned_int_bit; +extern const unsigned int remote_con_right_padding; +extern const unsigned int remote_con_flag; +extern unsigned int remote_con_cur_r_id; +extern unsigned int remote_con_cur_l_number; +extern const unsigned int remote_con_l_max; // Ox1111 +extern const unsigned int remote_con_r_max; +extern unsigned int remote_con_l_table[16]; + +typedef enum { + NOTIFY = 0, + DEVICE_TRACKER, + REMOTE_SOCKET, + REMOTE_CON +} SOCKET_STATUS; + +extern LIST_NODE* local_socket_list; + +SDB_SOCKET *find_local_socket(unsigned id); +int local_socket_enqueue(SDB_SOCKET *s, PACKET *p); +void local_socket_ready(SDB_SOCKET *s); +void local_socket_close(SDB_SOCKET *s); +SDB_SOCKET *create_local_socket(int fd); +void connect_to_remote(SDB_SOCKET *s, const char *destination); +int assign_remote_connect_socket_rid (SDB_SOCKET* s); +int device_tracker_send( SDB_SOCKET* local_socket, const char* buffer, int len ); +#endif /* SOCKETS_H_ */ diff --git a/src/strutils.c b/src/strutils.c old mode 100644 new mode 100755 index 33bff63..d4be7a3 --- a/src/strutils.c +++ b/src/strutils.c @@ -12,7 +12,7 @@ size_t tokenize(const char *str, const char *delim, char *tokens[], size_t max_t char tmp[PATH_MAX]; - strncpy(tmp, str, PATH_MAX); + strncpy(tmp, str, PATH_MAX - 1); char *p = strtok(tmp, delim); if (max_tokens < 1 || max_tokens > MAX_TOKENS) { max_tokens = 1; @@ -79,8 +79,8 @@ char *s_strncpy(char *dest, const char *source, size_t n) { } *dest++ = *source++; } + *dest = '\0'; } - *dest = '\0'; return start; } diff --git a/src/transport.c b/src/transport.c index 51a6abd..a0c0cac 100755 --- a/src/transport.c +++ b/src/transport.c @@ -21,17 +21,31 @@ #include #include "fdevent.h" #include "utils.h" +#include "transport.h" +#include "sockets.h" +#include "sdb_constants.h" +#include "strutils.h" +#include "memutils.h" +#include "listener.h" +#include "log.h" + #define TRACE_TAG TRACE_TRANSPORT -#include "sdb.h" -static void transport_unref(atransport *t); +static void transport_unref(TRANSPORT *t); +static void handle_packet(PACKET *p, TRANSPORT *t); +static void parse_banner(char *banner, TRANSPORT *t); +static void wakeup_select(T_PACKET* t_packet); +static void update_transports(void); +static void run_transport_close(TRANSPORT* t); +static void encoding_packet(PACKET* p); +static int check_header(PACKET *p); +static int check_data(PACKET *p); +static void dump_hex( const unsigned char* ptr, size_t len); -static atransport transport_list = { - .next = &transport_list, - .prev = &transport_list, -}; +LIST_NODE* transport_list = NULL; SDB_MUTEX_DEFINE( transport_lock ); +SDB_MUTEX_DEFINE( wakeup_select_lock ); #ifdef _WIN32 /* FIXME : move to sysdeps.h later */ int asprintf( char **, char *, ... ); @@ -60,183 +74,121 @@ int asprintf( char **sptr, char *fmt, ... ) } #endif -#if SDB_TRACE -#define MAX_DUMP_HEX_LEN 16 -static void dump_hex( const unsigned char* ptr, size_t len ) +#define MAX_DUMP_HEX_LEN 30 +static void dump_hex( const unsigned char* ptr, size_t len) { - int nn, len2 = len; - // Build a string instead of logging each character. - // MAX chars in 2 digit hex, one space, MAX chars, one '\0'. - char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer; + if(SDB_TRACING) { + char hex_str[]= "0123456789abcdef"; - if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN; + if(len > MAX_DUMP_HEX_LEN) { + len = MAX_DUMP_HEX_LEN; + } - for (nn = 0; nn < len2; nn++) { - sprintf(pb, "%02x", ptr[nn]); - pb += 2; - } - sprintf(pb++, " "); + int i; + char hex[len*2 + 1]; + for (i = 0; i < len; i++) { + hex[i*2 + 0] = hex_str[ptr[i] >> 4]; + hex[i*2 + 1] = hex_str[ptr[i] & 0x0F]; + } + hex[len*2] = '\0'; - for (nn = 0; nn < len2; nn++) { - int c = ptr[nn]; - if (c < 32 || c > 127) - c = '.'; - *pb++ = c; + char asci[len + 1]; + for (i = 0; i < len; i++) { + if ((int)ptr[i] >= 32 && (int)ptr[i] <= 127) { + asci[i] = ptr[i]; + } + else { + asci[i] = '.'; + } + } + asci[len] = '\0'; + + DR("HEX:'%s', ASCI:'%s'\n", hex, asci); } - *pb++ = '\0'; - DR("%s\n", buffer); } -#endif void -kick_transport(atransport* t) +kick_transport(TRANSPORT* t) { if (t && !t->kicked) { int kicked; - sdb_mutex_lock(&transport_lock); + sdb_mutex_lock(&transport_lock, "transport kick_transport"); kicked = t->kicked; if (!kicked) t->kicked = 1; - sdb_mutex_unlock(&transport_lock); + sdb_mutex_unlock(&transport_lock, "transport kick_transport"); if (!kicked) t->kick(t); } } -void -run_transport_disconnects(atransport* t) +static void run_transport_close(TRANSPORT* t) { - adisconnect* dis = t->disconnects.next; + D("T(%s)\n", t->serial); + LIST_NODE* curptr = listener_list; - D("%s: run_transport_disconnects\n", t->serial); - while (dis != &t->disconnects) { - adisconnect* next = dis->next; - dis->func( dis->opaque, t ); - dis = next; - } -} + while(curptr != NULL) { + LISTENER* l = curptr->data; + curptr = curptr->next_ptr; -#if SDB_TRACE -static void -dump_packet(const char* name, const char* func, apacket* p) -{ - unsigned command = p->msg.command; - int len = p->msg.data_length; - char cmd[9]; - char arg0[12], arg1[12]; - int n; - - for (n = 0; n < 4; n++) { - int b = (command >> (n*8)) & 255; - if (b < 32 || b >= 127) - break; - cmd[n] = (char)b; - } - if (n == 4) { - cmd[4] = 0; - } else { - /* There is some non-ASCII name in the command, so dump - * the hexadecimal value instead */ - snprintf(cmd, sizeof cmd, "%08x", command); + if(l->transport == t) { + D("LN(%s) being closed by T(%s)\n", l->local_name, t->serial); + remove_node(&listener_list, l->node, free_listener); + } } - if (p->msg.arg0 < 256U) - snprintf(arg0, sizeof arg0, "%d", p->msg.arg0); - else - snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0); + curptr = local_socket_list; + while(curptr != NULL) { + SDB_SOCKET* s = curptr->data; + curptr = curptr->next_ptr; - if (p->msg.arg1 < 256U) - snprintf(arg1, sizeof arg1, "%d", p->msg.arg1); - else - snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1); - - D("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", - name, func, cmd, arg0, arg1, len); - dump_hex(p->data, len); -} -#endif /* SDB_TRACE */ - -static int -read_packet(int fd, const char* name, apacket** ppacket) -{ - char *p = (char*)ppacket; /* really read a packet address */ - int r; - int len = sizeof(*ppacket); - char buff[8]; - if (!name) { - snprintf(buff, sizeof buff, "fd=%d", fd); - name = buff; - } - while(len > 0) { - r = sdb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; - return -1; + if(s->transport == t) { + D("LS(%X) FD(%d) being closed by T(%s)\n", s->local_id, s->fd, t->serial); + local_socket_close(s); } } - -#if SDB_TRACE - if (SDB_TRACING) { - dump_packet(name, "from remote", *ppacket); - } -#endif - return 0; } -static int -write_packet(int fd, const char* name, apacket** ppacket) + +void dump_packet(const char* name, const char* func, PACKET* p) { - char *p = (char*) ppacket; /* we really write the packet address */ - int r, len = sizeof(ppacket); - char buff[8]; - if (!name) { - snprintf(buff, sizeof buff, "fd=%d", fd); - name = buff; - } + if(SDB_TRACING) { + unsigned cmd = p->msg.command; + char command[9]; -#if SDB_TRACE - if (SDB_TRACING) { - dump_packet(name, "to remote", *ppacket); - } -#endif - len = sizeof(ppacket); - while(len > 0) { - r = sdb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno)); - if((r < 0) && (errno == EINTR)) continue; - return -1; + if(cmd == A_CLSE) { + snprintf(command, sizeof command, "%s", "A_CLSE"); } - } - return 0; -} - -static void transport_socket_events(int fd, unsigned events, void *_t) -{ - atransport *t = _t; - D("transport_socket_events(fd=%d, events=%04x,...)\n", fd, events); - if(events & FDE_READ){ - apacket *p = 0; - if(read_packet(fd, t->serial, &p)){ - D("%s: failed to read packet from transport socket on fd %d\n", t->serial, fd); - } else { - handle_packet(p, (atransport *) _t); + else if(cmd == A_CNXN) { + snprintf(command, sizeof command, "%s", "A_CNXN"); + } + else if(cmd == A_OPEN) { + snprintf(command, sizeof command, "%s", "A_OPEN"); } + else if(cmd == A_OKAY) { + snprintf(command, sizeof command, "%s", "A_OKAY"); + } + else if(cmd == A_WRTE) { + snprintf(command, sizeof command, "%s", "A_WRTE"); + } + else if(cmd == A_TCLS) { + snprintf(command, sizeof command, "%s", "A_TCLS"); + } + else { + //unrecongnized command dump the hexadecimal value. + snprintf(command, sizeof command, "%08x", cmd); + } + + D("T(%s) %s: [%s] arg0=%X arg1=%X (len=%d) (total_msg_len=%d)\n", + name, func, command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->len); + dump_hex(p->data, p->msg.data_length); } } -void send_packet(apacket *p, atransport *t) -{ +static void encoding_packet(PACKET* p) { unsigned char *x; unsigned sum; unsigned count; @@ -250,147 +202,116 @@ void send_packet(apacket *p, atransport *t) sum += *x++; } p->msg.data_check = sum; +} - print_packet("send", p); +void send_packet(PACKET *p, TRANSPORT *t) +{ + if(t != NULL && t->connection_state != CS_OFFLINE) { + encoding_packet(p); - if (t == NULL) { - D("Transport is null \n"); - // Zap errno because print_packet() and other stuff have errno effect. - errno = 0; - fatal_errno("Transport is null"); + D("%s: transport got packet, sending to remote\n", t->serial); + t->write_to_remote(p, t); } - - if(write_packet(t->transport_socket, t->serial, &p)){ - fatal_errno("cannot enqueue packet on transport socket"); + else { + if (t == NULL) { + D("Transport is null \n"); + errno = 0; + LOG_FATAL("Transport is null\n"); + } + else { + D("%s: transport ignoring packet while offline\n", t->serial); + } } } -/* The transport is opened by transport_register_func before -** the input and output threads are started. -** -** The output thread issues a SYNC(1, token) message to let -** the input thread know to start things up. In the event -** of transport IO failure, the output thread will post a -** SYNC(0,0) message to ensure shutdown. -** -** The transport will not actually be closed until both -** threads exit, but the input thread will kick the transport -** on its way out to disconnect the underlying device. -*/ - -static void *output_thread(void *_t) -{ - atransport *t = _t; - apacket *p; - - D("%s: starting transport output thread on fd %d, SYNC online (%d)\n", - t->serial, t->fd, t->sync_token + 1); - p = get_apacket(); - p->msg.command = A_SYNC; - p->msg.arg0 = 1; - p->msg.arg1 = ++(t->sync_token); - p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, t->serial, &p)) { - put_apacket(p); - D("%s: failed to write SYNC packet\n", t->serial); - goto oops; - } +static __inline__ void wakeup_select(T_PACKET* t_packet) { + sdb_mutex_lock(&wakeup_select_lock, "wakeup_select"); + writex(fdevent_wakeup_send, &t_packet, sizeof(t_packet)); + sdb_mutex_unlock(&wakeup_select_lock, "wakeup_select"); +} - D("%s: data pump started\n", t->serial); - for(;;) { - p = get_apacket(); +static void handle_packet(PACKET *p, TRANSPORT *t) +{ + unsigned int cmd = p->msg.command; + T_PACKET* t_packet = malloc(sizeof(T_PACKET)); + t_packet->t = t; + t_packet->p = NULL; - if(t->read_from_remote(p, t) == 0){ - D("%s: received remote packet, sending to transport\n", - t->serial); - if(write_packet(t->fd, t->serial, &p)){ - put_apacket(p); - D("%s: failed to write apacket to transport\n", t->serial); - goto oops; - } - } else { - D("%s: remote read failed for transport\n", t->serial); - put_apacket(p); - break; - } + //below commands should be done in main thread. packet is used in wakeup_select_func. Do not put a packet + if(cmd == A_WRTE || cmd == A_CLSE || cmd == A_CNXN || cmd == A_OKAY || cmd == A_STAT) { + ++(t->req); + t_packet->p = p; + wakeup_select(t_packet); + return; } - - D("%s: SYNC offline for transport\n", t->serial); - p = get_apacket(); - p->msg.command = A_SYNC; - p->msg.arg0 = 0; - p->msg.arg1 = 0; - p->msg.magic = A_SYNC ^ 0xffffffff; - if(write_packet(t->fd, t->serial, &p)) { - put_apacket(p); - D("%s: failed to write SYNC apacket to transport", t->serial); + else if(cmd == A_OPEN) { + LOG_FATAL("server does not handle A_OPEN\n"); + exit(1); } - -oops: - D("%s: transport output thread is exiting\n", t->serial); - kick_transport(t); - transport_unref(t); - return 0; + D("Unknown packet command %08x\n", p->msg.command); + put_apacket(p); + free(t_packet); } -static void *input_thread(void *_t) +#define CNXN_DATA_MAX_TOKENS 3 +static void parse_banner(char *data, TRANSPORT *t) { - atransport *t = _t; - apacket *p; - int active = 0; + char *banner = s_strdup(data); + char *end = NULL; - D("%s: starting transport input thread, reading from fd %d\n", - t->serial, t->fd); + end = strchr(banner, ':'); + if(end) { + *end = '\0'; + } + const char* target_banner = STATE_HOST; + if(!strcmp(banner, STATE_DEVICE)) { + t->connection_state = CS_DEVICE; + target_banner = STATE_DEVICE; + } + else if(!strcmp(banner, STATE_BOOTLOADER)){ + t->connection_state = CS_BOOTLOADER; + target_banner = STATE_BOOTLOADER; + } + else if(!strcmp(banner, STATE_RECOVERY)) { + t->connection_state = CS_RECOVERY; + target_banner = STATE_RECOVERY; + } + else if(!strcmp(banner, STATE_SIDELOAD)) { + t->connection_state = CS_SIDELOAD; + target_banner = STATE_SIDELOAD; + } + else { + t->connection_state = CS_HOST; + } + if (banner != NULL) { + s_free(banner); + } + // since version 2 + char *tokens[CNXN_DATA_MAX_TOKENS]; + size_t cnt = tokenize(data, "::", tokens, CNXN_DATA_MAX_TOKENS); - for(;;){ - if(read_packet(t->fd, t->serial, &p)) { - D("%s: failed to read apacket from transport on fd %d\n", - t->serial, t->fd ); - break; - } - if(p->msg.command == A_SYNC){ - if(p->msg.arg0 == 0) { - D("%s: transport SYNC offline\n", t->serial); - put_apacket(p); - break; - } else { - if(p->msg.arg1 == t->sync_token) { - D("%s: transport SYNC online\n", t->serial); - active = 1; - } else { - D("%s: transport ignoring SYNC %d != %d\n", - t->serial, p->msg.arg1, t->sync_token); - } - } - } else { - if(active) { - D("%s: transport got packet, sending to remote\n", t->serial); - t->write_to_remote(p, t); - } else { - D("%s: transport ignoring packet while offline\n", t->serial); - } + if (cnt == 3) { + // update device_name except usb device but it should be changed soon. + if (strcmp(STATE_UNKNOWN, tokens[1])) { + t->device_name = strdup(tokens[1]); } - put_apacket(p); + if (!strcmp(tokens[2], "1")) { + t->connection_state = CS_PWLOCK; + target_banner = STATE_LOCKED; + } } - // this is necessary to avoid a race condition that occured when a transport closes - // while a client socket is still active. - close_all_sockets(t); + if (cnt) { + free_strings(tokens, cnt); + } - D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd); - kick_transport(t); - transport_unref(t); - return 0; + D("setting connection_state to '%s'\n", target_banner); + update_transports(); + return; } - -static int transport_registration_send = -1; -static int transport_registration_recv = -1; -static fdevent transport_registration_fde; - - -static int list_transports_msg(char* buffer, size_t bufferlen) +int list_transports_msg(char* buffer, size_t bufferlen) { char head[5]; int len; @@ -402,519 +323,221 @@ static int list_transports_msg(char* buffer, size_t bufferlen) return len; } -/* this adds support required by the 'track-devices' service. - * this is used to send the content of "list_transport" to any - * number of client connections that want it through a single - * live TCP connection - */ -typedef struct device_tracker device_tracker; -struct device_tracker { - asocket socket; - int update_needed; - device_tracker* next; -}; - -/* linked list of all device trackers */ -static device_tracker* device_tracker_list; - -static void -device_tracker_remove( device_tracker* tracker ) +static void update_transports(void) { - device_tracker** pnode = &device_tracker_list; - device_tracker* node = *pnode; + D("update transports\n"); + char buffer[1024]; + int len; - sdb_mutex_lock( &transport_lock ); - while (node) { - if (node == tracker) { - *pnode = node->next; - break; - } - pnode = &node->next; - node = *pnode; - } - sdb_mutex_unlock( &transport_lock ); -} + len = list_transports_msg(buffer, sizeof(buffer)); -static void -device_tracker_close( asocket* socket ) -{ - device_tracker* tracker = (device_tracker*) socket; - asocket* peer = socket->peer; - D( "device tracker %p removed\n", tracker); - if (peer) { - peer->peer = NULL; - peer->close(peer); + LIST_NODE* curptr = local_socket_list; + while(curptr != NULL) { + SDB_SOCKET *s = curptr->data; + curptr = curptr->next_ptr; + if (HAS_SOCKET_STATUS(s, DEVICE_TRACKER)) { + device_tracker_send(s, buffer, len); + } } - device_tracker_remove(tracker); - free(tracker); } -static int -device_tracker_enqueue( asocket* socket, apacket* p ) -{ - /* you can't read from a device tracker, close immediately */ - put_apacket(p); - device_tracker_close(socket); - return -1; -} - -static int -device_tracker_send( device_tracker* tracker, - const char* buffer, - int len ) -{ - apacket* p = get_apacket(); - asocket* peer = tracker->socket.peer; - - memcpy(p->data, buffer, len); - p->len = len; - return peer->enqueue( peer, p ); -} +void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t) { + PACKET *p = get_apacket(); + p->msg.arg0 = arg0; + p->msg.arg1 = arg1; + p->msg.command = cmd; - -static void -device_tracker_ready( asocket* socket ) -{ - device_tracker* tracker = (device_tracker*) socket; - - /* we want to send the device list when the tracker connects - * for the first time, even if no update occured */ - if (tracker->update_needed > 0) { - char buffer[1024]; - int len; - - tracker->update_needed = 0; - - len = list_transports_msg(buffer, sizeof(buffer)); - device_tracker_send(tracker, buffer, len); + if(data != NULL) { + snprintf((char*)p->data, sizeof(p->data), "%s", data); + p->msg.data_length = strlen((char*)p->data) + 1; } -} - - -asocket* -create_device_tracker(void) -{ - device_tracker* tracker = calloc(1,sizeof(*tracker)); - - if(tracker == 0) fatal("cannot allocate device tracker"); - - D( "device tracker %p created\n", tracker); - tracker->socket.enqueue = device_tracker_enqueue; - tracker->socket.ready = device_tracker_ready; - tracker->socket.close = device_tracker_close; - tracker->update_needed = 1; - - tracker->next = device_tracker_list; - device_tracker_list = tracker; - - return &tracker->socket; + send_packet(p, t); + put_apacket(p); } - -/* call this function each time the transport list has changed */ -void update_transports(void) +static void *transport_thread(void *_t) { - char buffer[1024]; - int len; - device_tracker* tracker; - - len = list_transports_msg(buffer, sizeof(buffer)); - - tracker = device_tracker_list; - while (tracker != NULL) { - device_tracker* next = tracker->next; - /* note: this may destroy the tracker if the connection is closed */ - device_tracker_send(tracker, buffer, len); - tracker = next; - } -} + TRANSPORT *t = _t; + PACKET *p; -typedef struct tmsg tmsg; -struct tmsg -{ - atransport *transport; - int action; -}; + D("T(%s), FD(%d)\n", t->serial, t->sfd); + t->connection_state = CS_WAITCNXN; + send_cmd(A_VERSION, MAX_PAYLOAD, A_CNXN, "host::", t); + t->connection_state = CS_OFFLINE; + // allow the device some time to respond to the connect message + sdb_sleep_ms(1000); -static int -transport_read_action(int fd, struct tmsg* m) -{ - char *p = (char*)m; - int len = sizeof(*m); - int r; + D("%s: data dump started\n", t->serial); + while(1) { + p = get_apacket(); + LOG_INFO("T(%s) remote read start\n", t->serial); - while(len > 0) { - r = sdb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if((r < 0) && (errno == EINTR)) continue; - D("transport_read_action: on fd %d, error %d: %s\n", - fd, errno, strerror(errno)); - return -1; + if(t->read_from_remote(t, &p->msg, sizeof(MESSAGE))) { + break; } - } - return 0; -} - -static int -transport_write_action(int fd, struct tmsg* m) -{ - char *p = (char*)m; - int len = sizeof(*m); - int r; - - while(len > 0) { - r = sdb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if((r < 0) && (errno == EINTR)) continue; - D("transport_write_action: on fd %d, error %d: %s\n", - fd, errno, strerror(errno)); - return -1; + if(check_header(p)) { + break; + } + if(p->msg.data_length) { + if(t->read_from_remote(t, p->data, p->msg.data_length)){ + break; + } + } + if(check_data(p)) { + break; + } + dump_packet(t->serial, "remote_read", p); + D("%s: received remote packet, sending to transport\n", + t->serial); + handle_packet(p, t); + } + LOG_INFO("T(%s) remote read fail. terminate transport\n", t->serial); + put_apacket(p); + + t->connection_state = CS_OFFLINE; + do { + if(t->req == t->res) { + p = get_apacket(); + p->msg.command = A_TCLS; + T_PACKET* t_packet = malloc(sizeof(T_PACKET)); + t_packet->t = t; + t_packet->p = p; + wakeup_select(t_packet); + break; + } + else { + //TODO this should be changed to wait later. + sdb_sleep_ms(1000); } } + while(1); return 0; } -static sdb_cond_t cond;// = PTHREAD_COND_INITIALIZER; - -static void transport_registration_func(int _fd, unsigned ev, void *data) +void register_transport(TRANSPORT *t) { - tmsg m; - sdb_thread_t output_thread_ptr; - sdb_thread_t input_thread_ptr; - int s[2]; - atransport *t; - - if(!(ev & FDE_READ)) { - return; - } - - if(transport_read_action(_fd, &m)) { - fatal_errno("cannot read transport registration socket"); - } - - t = m.transport; - - if(m.action == 0){ - D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); - - /* IMPORTANT: the remove closes one half of the - ** socket pair. The close closes the other half. - */ - fdevent_remove(&(t->transport_fde)); - sdb_close(t->fd); - - sdb_mutex_lock(&transport_lock); - t->next->prev = t->prev; - t->prev->next = t->next; - - sdb_cond_broadcast(&cond); - sdb_mutex_unlock(&transport_lock); - - run_transport_disconnects(t); - - if (t->product) - free(t->product); - if (t->serial) - free(t->serial); - if (t->device_name) - free(t->device_name); - - memset(t,0xee,sizeof(atransport)); - free(t); - - update_transports(); - return; - } - - /* don't create transport threads for inaccessible devices */ - if (t->connection_state != CS_NOPERM) { - /* initial references are the two threads */ - t->ref_count = 2; - - if(sdb_socketpair(s)) { - fatal_errno("cannot open transport socketpair"); - } - - D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); - - t->transport_socket = s[0]; - t->fd = s[1]; - - fdevent_install(&(t->transport_fde), - t->transport_socket, - transport_socket_events, - t); - - fdevent_set(&(t->transport_fde), FDE_READ); + D("T(%s), device name: '%s'\n", t->serial, t->device_name); + sdb_thread_t transport_thread_ptr; - if(sdb_thread_create(&input_thread_ptr, input_thread, t)){ - fatal_errno("cannot create input thread"); - } - - if(sdb_thread_create(&output_thread_ptr, output_thread, t)){ - fatal_errno("cannot create output thread"); - } + //transport is updated by transport_thread, we do not have to update here. + if(sdb_thread_create(&transport_thread_ptr, transport_thread, t)){ + LOG_FATAL("cannot create output thread\n"); } /* put us on the master device list */ - sdb_mutex_lock(&transport_lock); - t->next = &transport_list; - t->prev = transport_list.prev; - t->next->prev = t; - t->prev->next = t; - - sdb_cond_broadcast(&cond); - sdb_mutex_unlock(&transport_lock); - - t->disconnects.next = t->disconnects.prev = &t->disconnects; - - update_transports(); + sdb_mutex_lock(&transport_lock, "transport register_transport"); + t->node = prepend(&transport_list, t); + sdb_mutex_unlock(&transport_lock, "transport register_transport"); } -void init_transport_registration(void) +//lock is done by transport_unref +static void remove_transport(TRANSPORT *t) { - int s[2]; + D("transport removed. serial: %s, device name: %s\n", t->serial, t->device_name); - sdb_cond_init(&cond, NULL); - if(sdb_socketpair(s)){ - fatal_errno("cannot open transport registration socketpair"); - } + remove_node(&transport_list, t->node, no_free); - transport_registration_send = s[0]; - transport_registration_recv = s[1]; + run_transport_close(t); - fdevent_install(&transport_registration_fde, - transport_registration_recv, - transport_registration_func, - 0); + if (t->serial) + free(t->serial); + if (t->device_name) + free(t->device_name); - fdevent_set(&transport_registration_fde, FDE_READ); + free(t); } -/* the fdevent select pump is single threaded */ -static void register_transport(atransport *transport) + +static void transport_unref(TRANSPORT *t) { - tmsg m; - m.transport = transport; - m.action = 1; - D("transport: %s registered\n", transport->serial); - if(transport_write_action(transport_registration_send, &m)) { - fatal_errno("cannot write transport registration socket\n"); + if (t == NULL) { + return; } -} -static void remove_transport(atransport *transport) -{ - tmsg m; - m.transport = transport; - m.action = 0; - D("transport: %s removed\n", transport->serial); - if(transport_write_action(transport_registration_send, &m)) { - fatal_errno("cannot write transport registration socket\n"); + sdb_mutex_lock(&transport_lock, "transport_unref transport"); + int nr; + + D("transport: %s unref (kicking and closing)\n", t->serial); + if (!t->kicked) { + t->kicked = 1; + t->kick(t); } -} + t->close(t); + remove_transport(t); + LIST_NODE* curptr = transport_list; -static void transport_unref_locked(atransport *t) -{ - atransport *tmp; - int nr; - t->ref_count--; - if (t->ref_count == 0) { - D("transport: %s unref (kicking and closing)\n", t->serial); - if (!t->kicked) { - t->kicked = 1; - t->kick(t); - } - t->close(t); - remove_transport(t); - - /* update tizen specific device name */ - for (tmp = t->next; tmp && tmp != &transport_list; tmp = tmp->next) { - if (tmp->type == kTransportUsb) { - D("update tizen specific device name: %s\n", tmp->device_name); - if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) { - free(tmp->device_name); - asprintf(&tmp->device_name, "device-%d", nr - 1); - } + while(curptr != NULL) { + TRANSPORT* tmp = curptr->data; + curptr = curptr->next_ptr; + if (tmp->type == kTransportUsb) { + if (tmp->device_name && sscanf(tmp->device_name, "device-%d", &nr) == 1) { + free(tmp->device_name); + asprintf(&tmp->device_name, "device-%d", nr - 1); } } - } else { - D("transport: %s unref (count=%d)\n", t->serial, t->ref_count); } -} -static void transport_unref(atransport *t) -{ - if (t) { - sdb_mutex_lock(&transport_lock); - transport_unref_locked(t); - sdb_mutex_unlock(&transport_lock); - } + sdb_mutex_unlock(&transport_lock, "transport_unref transport"); + update_transports(); } -void add_transport_disconnect(atransport* t, adisconnect* dis) +TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char** error_out) { - sdb_mutex_lock(&transport_lock); - dis->next = &t->disconnects; - dis->prev = dis->next->prev; - dis->prev->next = dis; - dis->next->prev = dis; - sdb_mutex_unlock(&transport_lock); -} + TRANSPORT *result = NULL; + char* null_str = NULL; -void remove_transport_disconnect(atransport* t, adisconnect* dis) -{ - dis->prev->next = dis->next; - dis->next->prev = dis->prev; - dis->next = dis->prev = dis; -} + if(error_out == NULL) { + error_out = &null_str; + } + sdb_mutex_lock(&transport_lock, "transport acquire_one_transport"); -atransport *acquire_one_transport(int state, transport_type ttype, const char* serial, char** error_out) -{ - atransport *t; - atransport *result = NULL; - int ambiguous = 0; - -retry: - if (error_out) - *error_out = "device not found"; - - sdb_mutex_lock(&transport_lock); - for (t = transport_list.next; t != &transport_list; t = t->next) { - if (t->connection_state == CS_NOPERM) { - if (error_out) - *error_out = "insufficient permissions for device"; - continue; - } + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* transport_ = curptr->data; + curptr = curptr->next_ptr; /* check for matching serial number */ if (serial) { - if (t->serial && !strcmp(serial, t->serial)) { - result = t; + if (transport_->serial && !strcmp(serial, transport_->serial)) { + result = transport_; break; } } else { - if (ttype == kTransportUsb && t->type == kTransportUsb) { + if(ttype == kTransportAny) { if (result) { - if (error_out) - *error_out = "more than one device"; - ambiguous = 1; + *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_TARGET; result = NULL; break; } - result = t; - } else if (ttype == kTransportLocal && t->type == kTransportLocal) { - if (result) { - if (error_out) - *error_out = "more than one emulator"; - ambiguous = 1; - result = NULL; - break; - } - result = t; - } else if (ttype == kTransportAny) { + result = transport_; + } + if (ttype == transport_->type) { if (result) { - if (error_out) - *error_out = "more than one device and emulator"; - ambiguous = 1; + if(ttype == kTransportUsb) { + *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_DEV; + } + else if(ttype == kTransportLocal) { + *error_out = (char*)TRANSPORT_ERR_MORE_THAN_ONE_EMUL; + } result = NULL; break; } - result = t; + result = transport_; } } } - sdb_mutex_unlock(&transport_lock); - - if (result) { - /* offline devices are ignored -- they are either being born or dying */ - if (result && result->connection_state == CS_OFFLINE) { - if (error_out) - *error_out = "device offline"; - result = NULL; - } - /* check for required connection state */ - if (result && state != CS_ANY && result->connection_state != state) { - if (error_out) - *error_out = "invalid device state"; - result = NULL; - } - } - - if (result) { - /* found one that we can take */ - if (error_out) - *error_out = NULL; - } else if (state != CS_ANY && (serial || !ambiguous)) { - sdb_sleep_ms(1000); - goto retry; - } - return result; -} - -static const char *statename(atransport *t) -{ - switch(t->connection_state){ - case CS_OFFLINE: return "offline"; - case CS_BOOTLOADER: return "bootloader"; - case CS_DEVICE: return "device"; - case CS_HOST: return "host"; - case CS_RECOVERY: return "recovery"; - case CS_SIDELOAD: return "sideload"; - case CS_NOPERM: return "no permissions"; - default: return "unknown"; - } -} - -/* - * find number of devices which serial match with the prefix - */ -int find_transports(char **serial_out, const char *prefix) -{ - int nr = 0; // not found - char *match = NULL; - atransport *t; - - if (!serial_out || !prefix) - return -1; - - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - char* serial = t->serial; - if (!serial || !serial[0]) - continue; - if (!strncmp(prefix, serial, strlen(prefix))) { - match = serial; - nr++; - } + sdb_mutex_unlock(&transport_lock, "transport acquire_one_transport"); - if (nr > 1) { - match = NULL; - break; - } - } - sdb_mutex_unlock(&transport_lock); - - if (nr == 1 && match) { - *serial_out = strdup(match); - } else if (nr == 0) { - asprintf(serial_out, "device not found"); - } else if (nr > 1) { - asprintf(serial_out, "more than one device and emulator"); + if (result == NULL ) { + *error_out = (char*)TRANSPORT_ERR_TARGET_NOT_FOUND; } - return nr; + return result; } int list_transports(char *buf, size_t bufsize) @@ -922,16 +545,20 @@ int list_transports(char *buf, size_t bufsize) char* p = buf; char* end = buf + bufsize; int len; - atransport *t; /* XXX OVERRUN PROBLEMS XXX */ - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { + sdb_mutex_lock(&transport_lock, "transport list_transports"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; const char* serial = t->serial; const char* devicename = (t->device_name == NULL) ? DEFAULT_DEVICENAME : t->device_name; /* tizen specific */ if (!serial || !serial[0]) serial = "????????????"; - len = snprintf(p, end - p, "%s\t%s\t%s\n", serial, statename(t), devicename); + // FIXME: what if each string length is longger than static length? + len = snprintf(p, end - p, "%-20s\t%-10s\t%s\n", serial, connection_state_name(t), devicename); if (p + len >= end) { /* discard last line if buffer is too short */ @@ -939,168 +566,48 @@ int list_transports(char *buf, size_t bufsize) } p += len; } + p[0] = 0; - sdb_mutex_unlock(&transport_lock); + sdb_mutex_unlock(&transport_lock, "transport list_transports"); return p - buf; } +int register_device_con_transport(int s, const char *serial) { -/* hack for osx */ -void close_usb_devices() -{ - atransport *t; - - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if ( !t->kicked ) { - t->kicked = 1; - t->kick(t); - } + //TODO REMOTE_DEVICE_CONNECT complete device connect after resolving security issue +#if 0 + if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) { + LOG_ERROR("Too many tcp connection\n"); + return -1; } - sdb_mutex_unlock(&transport_lock); -} -void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name) -{ - atransport *t = calloc(1, sizeof(atransport)); + TRANSPORT *t = calloc(1, sizeof(TRANSPORT)); char buff[32]; if (!serial) { snprintf(buff, sizeof buff, "T-%p", t); - serial = buff; - } - D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name); - if ( init_socket_transport(t, s, port, local) < 0 ) { - sdb_close(s); - free(t); - atransport *old_t = find_transport(serial); - if (old_t) { - unregister_transport(old_t); - } else { - D("No such device %s", serial); - } - return; } - if(serial) { - t->serial = strdup(serial); + else { + snprintf(buff, sizeof buff, "T-%s", serial); } + serial = buff; - if (device_name) {/* tizen specific */ - t->device_name = strdup(device_name); - } else { // device_name could be null when sdb server was forked before qemu has sent the connect message. - char device_name[DEVICENAME_MAX]; - if (get_devicename_from_shdmem(port, device_name) == 0) { - t->device_name = strdup(device_name); - } + init_socket_transport(t, s, 0); + t->remote_cnxn_socket = NULL; + t->serial = strdup(buff); + t->device_name = strdup("unknown"); + t->type = kTransportRemoteDevCon; + TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL); + if(old_t != NULL) { + D("old transport '%s' is found. Unregister it\n", old_t->serial); + kick_transport(old_t); } + ++current_local_transports; register_transport(t); -} - -atransport *find_transport(const char *serial) -{ - atransport *t; - - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (t->serial && !strcmp(serial, t->serial)) { - break; - } - } - sdb_mutex_unlock(&transport_lock); - - if (t != &transport_list) - return t; - else - return 0; -} - -void unregister_transport(atransport *t) -{ - sdb_mutex_lock(&transport_lock); - t->next->prev = t->prev; - t->prev->next = t->next; - sdb_mutex_unlock(&transport_lock); - - kick_transport(t); - transport_unref(t); -} - -// unregisters all non-emulator TCP transports -void unregister_all_tcp_transports() -{ - atransport *t, *next; - sdb_mutex_lock(&transport_lock); - for (t = transport_list.next; t != &transport_list; t = next) { - next = t->next; - if (t->type == kTransportLocal && t->sdb_port == 0) { - t->next->prev = t->prev; - t->prev->next = next; - // we cannot call kick_transport when holding transport_lock - if (!t->kicked) - { - t->kicked = 1; - t->kick(t); - } - transport_unref_locked(t); - } - } - - sdb_mutex_unlock(&transport_lock); -} - -static int get_connected_device_count(transport_type type) -{ - int cnt = 0; - atransport *t; - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (type == t->type) - cnt++; - } - - sdb_mutex_unlock(&transport_lock); - D("connected device count:%d\n",cnt); - return cnt; -} - -void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable) -{ - atransport *t = calloc(1, sizeof(atransport)); - char device_name[256]; - - D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, - serial ? serial : ""); - init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM)); - if(serial) { - t->serial = strdup(serial); - } - /* - * send register request to server thread and wait it finished - */ - sdb_mutex_lock(&transport_lock); - register_transport(t); - - sdb_cond_wait(&cond, &transport_lock); - sdb_mutex_unlock(&transport_lock); - /* tizen specific */ - sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb)); - t->device_name = strdup(device_name); -} - -/* this should only be used for transports with connection_state == CS_NOPERM */ -void unregister_usb_transport(usb_handle *usb) -{ - atransport *t; - sdb_mutex_lock(&transport_lock); - for(t = transport_list.next; t != &transport_list; t = t->next) { - if (t->usb == usb && t->connection_state == CS_NOPERM) { - t->next->prev = t->prev; - t->prev->next = t->next; - break; - } - } - sdb_mutex_unlock(&transport_lock); + return 0; +#endif + return -1; } #undef TRACE_TAG @@ -1109,79 +616,67 @@ void unregister_usb_transport(usb_handle *usb) int readx(int fd, void *ptr, size_t len) { char *p = ptr; - int r; -#if SDB_TRACE - int len0 = len; -#endif - D("readx: fd=%d wanted=%d\n", fd, (int)len); + D("FD(%d) wanted=%d\n", fd, (int)len); while(len > 0) { - r = sdb_read(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("readx: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("readx: fd=%d disconnected\n", fd); + int r = sdb_read(fd, p, len); + if(r < 0) { + if(errno == EINTR) { + continue; } + LOG_ERROR("FD(%d) error %d: %s\n", fd, errno, strerror(errno)); + return -1; + } + if( r == 0) { + D("FD(%d) disconnected\n", fd); return -1; } + len -= r; + p += r; } - -#if SDB_TRACE - D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len); - dump_hex( ptr, len0 ); -#endif return 0; } int writex(int fd, const void *ptr, size_t len) { - char *p = (char*) ptr; - int r; + char *p = (char *)ptr; -#if SDB_TRACE - D("writex: fd=%d len=%d: ", fd, (int)len); - dump_hex( ptr, len ); -#endif - while(len > 0) { - r = sdb_write(fd, p, len); - if(r > 0) { - len -= r; - p += r; - } else { - if (r < 0) { - D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno)); - if (errno == EINTR) - continue; - } else { - D("writex: fd=%d disconnected\n", fd); + while( len > 0) { + int r = sdb_write(fd, p, len); + if(r < 0) { + if (errno == EINTR) { + continue; } + D("fd=%d error %d: %s\n", fd, errno, strerror(errno)); return -1; } + if( r == 0) { + D("fd=%d disconnected\n", fd); + return -1; + } + + len -= r; + p += r; } return 0; } -int check_header(apacket *p) +static int check_header(PACKET *p) { if(p->msg.magic != (p->msg.command ^ 0xffffffff)) { - D("check_header(): invalid magic\n"); + LOG_ERROR("check_header(): invalid magic\n"); return -1; } if(p->msg.data_length > MAX_PAYLOAD) { - D("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); + LOG_ERROR("check_header(): %d > MAX_PAYLOAD\n", p->msg.data_length); return -1; } + LOG_INFO("success to check header\n"); return 0; } -int check_data(apacket *p) +static int check_data(PACKET *p) { unsigned count, sum; unsigned char *x; @@ -1199,3 +694,165 @@ int check_data(apacket *p) return 0; } } + +static unsigned int decoding_to_remote_ls_id(unsigned int encoded_ls_id) { + unsigned int remote_ls_id = encoded_ls_id & ~15; + return remote_ls_id; +} + +static unsigned int decoding_to_local_ls_id(unsigned encoded_ls_id) { + unsigned int local_ls_id = encoded_ls_id & 15; + local_ls_id |= remote_con_flag; + return local_ls_id; +} + +void wakeup_select_func(int _fd, unsigned ev, void *data) { + T_PACKET* t_packet = NULL; + + readx(_fd, &t_packet, sizeof(t_packet)); + + TRANSPORT* t= t_packet->t; + D("T(%s)\n", t->serial); + PACKET* p = t_packet->p; + free(t_packet); + + if(p == NULL) { + D("T(%S) packet NULL\n", t->serial); + return; + } + + int c_state = t->connection_state; + unsigned int cmd = p->msg.command; + unsigned int local_id = p->msg.arg1; + unsigned int remote_id = p->msg.arg0; + SDB_SOCKET* sock = NULL; + //CNXN cannot be distinguished using remote_con_flag + if(t->remote_cnxn_socket != NULL && cmd == A_CNXN) { + dump_packet("remote_con", "wakeup_select_func", p); + sock = t->remote_cnxn_socket->data; + if(sock != NULL) { + remove_first(&(t->remote_cnxn_socket), no_free); + LOG_INFO("LS_L(%X)\n", sock->local_id); + p->ptr = (void*)(&p->msg); + p->len = sizeof(MESSAGE) + p->msg.data_length; + local_socket_enqueue(sock, p); + } + goto endup; + } + //If transport is remote device, packet should not have to be decoded. + if((local_id & remote_con_flag) && t->type != kTransportRemoteDevCon) { + LOG_INFO("LS_L(%X), LS_R(%X), LS_E(%X)\n", decoding_to_local_ls_id(local_id), + decoding_to_remote_ls_id(local_id), local_id); + sock = find_local_socket(decoding_to_local_ls_id(local_id)); + p->msg.arg1 = decoding_to_remote_ls_id(local_id); + p->ptr = (void*)(&p->msg); + p->len = sizeof(MESSAGE) + p->msg.data_length; + local_socket_enqueue(sock, p); + goto endup; + } + sock = find_local_socket(local_id); + + if(c_state != CS_OFFLINE && sock != NULL) { + //packet is used by local_socket_enqueue do not put a packet. + if(cmd == A_WRTE) { + D("T(%s) write packet from RS(%d) to LS(%X)\n", t->serial, remote_id, local_id); + p->len = p->msg.data_length; + p->ptr = p->data; + if(local_socket_enqueue(sock, p) == 0) { + send_cmd(local_id, remote_id, A_OKAY, NULL, t); + } + goto endup; + } + else if(cmd == A_OKAY) { + if(!HAS_SOCKET_STATUS(sock, REMOTE_SOCKET)) { + SET_SOCKET_STATUS(sock, REMOTE_SOCKET); + D("remote socket attached LS(%X), RS(%d)\n", sock->local_id, sock->remote_id); + sock->remote_id = remote_id; + sock->transport = t; + } + local_socket_ready(sock); + } + } + if(cmd == A_CLSE) { + if(sock != NULL) { + D("T(%s) close LS(%X)\n", t->serial, local_id); + local_socket_close(sock); + } + } + else if(cmd == A_CNXN) { + D("T(%s) gets CNXN\n", t->serial); + if(t->connection_state != CS_OFFLINE) { + t->connection_state = CS_OFFLINE; + run_transport_close(t); + } + parse_banner((char*) p->data, t); + } + else if(cmd == A_STAT) { + D("T(%s) gets A_STAT:%d\n", t->serial, p->msg.arg0); + if (t->connection_state != CS_OFFLINE) { + t->connection_state = CS_OFFLINE; + } + if (p->msg.arg0 == 1) { + t->connection_state = CS_PWLOCK; + } else { + t->connection_state = CS_DEVICE; + } + update_transports(); + } + else if(cmd == A_TCLS) { + //transport thread is finished + transport_unref(t); + return; + } + put_apacket(p); + +endup: + //request is done. res increases 1. + ++(t->res); +} + +const char *connection_state_name(TRANSPORT *t) +{ + if(t != NULL) { + int state = t->connection_state; + + if(state == CS_OFFLINE) { + return STATE_OFFLINE; + } + if(state == CS_BOOTLOADER) { + return STATE_BOOTLOADER; + } + if(state == CS_DEVICE) { + return STATE_DEVICE; + } + if(state == CS_HOST) { + return STATE_HOST; + } + if(state == CS_RECOVERY) { + return STATE_RECOVERY; + } + if(state == CS_SIDELOAD) { + return STATE_SIDELOAD; + } + if (state == CS_PWLOCK) { + return STATE_LOCKED; + } + } + return STATE_UNKNOWN; +} + +PACKET *get_apacket(void) +{ + PACKET *p = malloc(sizeof(PACKET)); + if(p == 0) { + LOG_FATAL("failed to allocate an apacket\n"); + } + memset(p, 0, sizeof(PACKET) - MAX_PAYLOAD); + return p; +} + +void put_apacket(void *p) +{ + PACKET* packet = p; + free(packet); +} diff --git a/src/transport.h b/src/transport.h old mode 100644 new mode 100755 index 511b37e..d7c18af --- a/src/transport.h +++ b/src/transport.h @@ -17,10 +17,55 @@ #ifndef __TRANSPORT_H #define __TRANSPORT_H -/* convenience wrappers around read/write that will retry on -** EINTR and/or short read/write. Returns 0 on success, -1 -** on error or EOF. -*/ -int readx(int fd, void *ptr, size_t len); -int writex(int fd, const void *ptr, size_t len); +#include "common_modules.h" + +#define LOCAL_CLIENT_PREFIX "emulator-" + +#define A_CNXN 0x4e584e43 +#define A_OPEN 0x4e45504f +#define A_OKAY 0x59414b4f +#define A_CLSE 0x45534c43 +#define A_WRTE 0x45545257 +#define A_TCLS 0x534C4354 +#define A_STAT 0x54415453 + +#define CS_NONE -10000 +#define CS_ANY -1 +#define CS_OFFLINE 0 +#define CS_BOOTLOADER 1 +#define CS_DEVICE 2 +#define CS_HOST 3 +#define CS_RECOVERY 4 +#define CS_SIDELOAD 6 +#define CS_WAITCNXN 7 +#define CS_PWLOCK 10 + +#define DEFAULT_SDB_LOCAL_TRANSPORT_PORT 26101 +#define SDB_LOCAL_TRANSPORT_MAX 15 + +extern LIST_NODE* transport_list; +extern int current_local_transports; + +#ifdef _WIN32 /* FIXME : move to sysdeps.h later */ +int asprintf( char **, char *, ... ); +int vasprintf( char **, char *, va_list ); +#endif + +void wakeup_select_func(int _fd, unsigned ev, void *data); +void dump_packet(const char* name, const char* func, PACKET* p); +void send_packet(PACKET *p, TRANSPORT *t); +const char *connection_state_name(TRANSPORT *t); +PACKET *get_apacket(void); +void put_apacket(void *p); +void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name); +void register_usb_transport(usb_handle *usb, const char *serial); +int register_device_con_transport(int s, const char *serial); +void send_cmd(unsigned arg0, unsigned arg1, unsigned cmd, char* data, TRANSPORT* t); +void close_usb_devices(); +int list_transports_msg(char* buffer, size_t bufferlen); +int list_transports(char *buf, size_t bufsize); +int local_connect(int port, const char *device_name); +TRANSPORT *acquire_one_transport(transport_type ttype, const char* serial, char **error_out); +void kick_transport( TRANSPORT* t ); +void register_transport(TRANSPORT *t); #endif /* __TRANSPORT_H */ diff --git a/src/transport_local.c b/src/transport_local.c old mode 100644 new mode 100755 index 8fca32d..80fc669 --- a/src/transport_local.c +++ b/src/transport_local.c @@ -18,8 +18,6 @@ #include #include #include -#include "fdevent.h" -#include "utils.h" #include #ifndef OS_WINDOWS @@ -29,106 +27,91 @@ #endif #define TRACE_TAG TRACE_TRANSPORT -#include "sdb.h" - -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -#else -#define fix_endians(p) do {} while (0) -#endif +#include "strutils.h" +#include "log.h" +#include "common_modules.h" +#include "fdevent.h" +#include "utils.h" +#include "transport.h" /* we keep a list of opened transports. The atransport struct knows to which * local transport it is connected. The list is used to detect when we're * trying to connect twice to a given local transport. */ -#define SDB_LOCAL_TRANSPORT_MAX 16 -SDB_MUTEX_DEFINE( local_transports_lock ); +int current_local_transports = 0; -static atransport* local_transports[ SDB_LOCAL_TRANSPORT_MAX ]; +static int get_devicename_from_shdmem(int port, char *device_name); -static int remote_read(apacket *p, atransport *t) -{ - if(readx(t->sfd, &p->msg, sizeof(amessage))){ - D("remote local: read terminated (message)\n"); +static int remote_read(TRANSPORT* t, void* data, int len) { + return readx(t->sfd, data, len); +} + +static int remote_write(PACKET *p, TRANSPORT *t) { + dump_packet(t->serial, "remote_write_local", p); + if(writex(t->sfd, &p->msg, sizeof(MESSAGE) + p->msg.data_length)) { + LOG_ERROR("remote local: write terminated\n"); return -1; } + return 0; +} - fix_endians(p); +static int notify_sensord(int sdb_port) { -#if 0 && defined HAVE_BIG_ENDIAN - D("read remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif - if(check_header(p)) { - D("bad header: terminated (data)\n"); - return -1; - } + int fd = -1; + int sensord_port = sdb_port + 2; - if(readx(t->sfd, p->data, p->msg.data_length)){ - D("remote local: terminated (data)\n"); - return -1; - } + fd = sdb_host_connect("127.0.0.1", sensord_port, SOCK_DGRAM); - if(check_data(p)) { - D("bad data: terminated (data)\n"); + if (fd < 0) { + LOG_ERROR("failed to create socket to localhost(%d)\n", sensord_port); return -1; } - return 0; -} - -static int remote_write(apacket *p, atransport *t) -{ - int length = p->msg.data_length; - - fix_endians(p); + char request[16]; + snprintf(request, sizeof request, "2\n"); -#if 0 && defined HAVE_BIG_ENDIAN - D("write remote packet: %04x arg0=%0x arg1=%0x data_length=%0x data_check=%0x magic=%0x\n", - p->msg.command, p->msg.arg0, p->msg.arg1, p->msg.data_length, p->msg.data_check, p->msg.magic); -#endif - if(writex(t->sfd, &p->msg, sizeof(amessage) + length)) { - D("remote local: write terminated\n"); - return -1; + // send to sensord with udp + if (sdb_write(fd, request, strlen(request)) < 0) { + LOG_ERROR("could not send sensord request\n"); } + sdb_close(fd); return 0; } +int local_connect(int sdb_port, const char *device_name) { -int local_connect(int port, const char *device_name) { - return local_connect_arbitrary_ports(port-1, port, device_name); -} - -int local_connect_arbitrary_ports(int console_port, int sdb_port, const char *device_name) -{ char buf[64]; - int fd = -1; - fd = socket_loopback_client(sdb_port, SOCK_STREAM); + // in case of windows, it takes a long time to connect localhost compare to linux +#if defined(OS_WINDOWS) + char devname[DEVICENAME_MAX]={0,}; + if (get_devicename_from_shdmem(sdb_port, devname) == -1) { + return -1; + } +#endif + + int fd = sdb_host_connect("127.0.0.1", sdb_port, SOCK_STREAM); if (fd >= 0) { - D("client: connected on remote on fd %d\n", fd); + D("connected on remote on fd '%d', port '%d'\n", fd, sdb_port); close_on_exec(fd); disable_tcp_nagle(fd); - snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port); + + + snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, sdb_port); register_socket_transport(fd, buf, sdb_port, 1, device_name); + + // noti to sensord port to enable shell context menu on + notify_sensord(sdb_port); return 0; } + D("failed to connect on port '%d'\n", sdb_port); return -1; } -int get_devicename_from_shdmem(int port, char *device_name) +static int get_devicename_from_shdmem(int port, char *device_name) { char *vms = NULL; #ifndef OS_WINDOWS @@ -136,8 +119,10 @@ int get_devicename_from_shdmem(int port, char *device_name) void *shared_memory = (void *)0; shm_id = shmget( (key_t)port-1, 0, 0); - if (shm_id == -1) + if (shm_id == -1) { + D("failed to get shm from key:(%d)\n", port-1); return -1; + } shared_memory = shmat(shm_id, (void *)0, SHM_RDONLY); @@ -147,10 +132,12 @@ int get_devicename_from_shdmem(int port, char *device_name) return -1; } vms = strstr((char*)shared_memory, VMS_PATH); - if (vms != NULL) - strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); - else - strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); + if (vms != NULL) { + s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); + } else { + D("failed to get vm name from(%s)\n", shared_memory); + return -1; + } #else /* _WIN32*/ HANDLE hMapFile; @@ -161,7 +148,7 @@ int get_devicename_from_shdmem(int port, char *device_name) hMapFile = OpenFileMapping(FILE_MAP_READ, TRUE, s_port); if(hMapFile == NULL) { - D("faild to get shdmem key (%ld) : %s\n", port, GetLastError() ); + D("faild to get shdmem key from port (%d) : (%ld)\n", port, GetLastError() ); return -1; } pBuf = (char*)MapViewOfFile(hMapFile, @@ -176,158 +163,102 @@ int get_devicename_from_shdmem(int port, char *device_name) } vms = strstr((char*)pBuf, VMS_PATH); - if (vms != NULL) - strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); - else - strncpy(device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); + if (vms != NULL) { + s_strncpy(device_name, vms+strlen(VMS_PATH), DEVICENAME_MAX); + } else { + D("failed to get vm name from(%s)\n", pBuf); + CloseHandle(hMapFile); + return -1; + } CloseHandle(hMapFile); #endif - // apply for new vms path policy from Jan 23 2013 // vms path should be: ~/tizen-sdk-data/emulator-vms/vms/{name}/emulimg-em1.~~ vms = strtok(device_name, OS_PATH_SEPARATOR_STR); if (vms != NULL) { - strncpy(device_name, vms, DEVICENAME_MAX); + s_strncpy(device_name, vms, DEVICENAME_MAX); + } else { + D("failed to get vm name from(%s)\n", device_name); + return -1; } D("init device name %s on port %d\n", device_name, port); return 0; } -static void *register_local_connections(void *x) -{ - int port = DEFAULT_SDB_LOCAL_TRANSPORT_PORT; - int count = SDB_LOCAL_TRANSPORT_MAX; - - D("transport: client_socket_thread() starting\n"); - - /* try to connect to any number of running emulator instances */ - /* this is only done when SDB starts up. later, each new emulator */ - /* will send a message to SDB to indicate that is is starting up */ - for ( ; count > 0; count--, port += 10 ) { - (void) local_connect(port, NULL); - } - - return 0; -} - -/** - * register local connections - */ -void local_init(int port) -{ - sdb_thread_t thr; - void* (*func)(void *); - - func = register_local_connections; - - if(sdb_thread_create(&thr, func, (void *)port)) { - fatal_errno("cannot create local socket %s thread", - HOST ? "client" : "server"); - } -} - -static void remote_kick(atransport *t) +static void remote_kick(TRANSPORT *t) { int fd = t->sfd; - int nn; t->sfd = -1; sdb_shutdown(fd); sdb_close(fd); - sdb_mutex_lock( &local_transports_lock ); - for (nn = 0; nn < SDB_LOCAL_TRANSPORT_MAX; nn++) { - if (local_transports[nn] == t) { - local_transports[nn] = NULL; - break; - } - } - - sdb_mutex_unlock( &local_transports_lock ); -} - -static void remote_close(atransport *t) -{ - sdb_close(t->fd); -} - - -/* Only call this function if you already hold local_transports_lock. */ -atransport* find_emulator_transport_by_sdb_port_locked(int sdb_port) -{ - int i; - for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) { - if (local_transports[i] && local_transports[i]->sdb_port == sdb_port) { - return local_transports[i]; - } - } - return NULL; -} - -atransport* find_emulator_transport_by_sdb_port(int sdb_port) -{ - sdb_mutex_lock( &local_transports_lock ); - atransport* result = find_emulator_transport_by_sdb_port_locked(sdb_port); - sdb_mutex_unlock( &local_transports_lock ); - return result; -} - -/* Only call this function if you already hold local_transports_lock. */ -int get_available_local_transport_index_locked() -{ - int i; - for (i = 0; i < SDB_LOCAL_TRANSPORT_MAX; i++) { - if (local_transports[i] == NULL) { - return i; - } - } - return -1; + --current_local_transports; } -int get_available_local_transport_index() +static void remote_close(TRANSPORT *t) { - sdb_mutex_lock( &local_transports_lock ); - int result = get_available_local_transport_index_locked(); - sdb_mutex_unlock( &local_transports_lock ); - return result; + //nothing to close + D("close remote socket. serial: '%s', device name: '%s'\n", t->serial, t->device_name); } -int init_socket_transport(atransport *t, int s, int sdb_port, int local) +static void init_socket_transport(TRANSPORT *t, int s, int sdb_port) { - int fail = 0; - t->kick = remote_kick; t->close = remote_close; t->read_from_remote = remote_read; t->write_to_remote = remote_write; t->sfd = s; - t->sync_token = 1; t->connection_state = CS_OFFLINE; t->type = kTransportLocal; - t->sdb_port = 0; - - if (HOST && local) { - sdb_mutex_lock( &local_transports_lock ); - { - t->sdb_port = sdb_port; - atransport* existing_transport = - find_emulator_transport_by_sdb_port_locked(sdb_port); - int index = get_available_local_transport_index_locked(); - if (existing_transport != NULL) { - D("local transport for port %d already registered (%p)?\n", - sdb_port, existing_transport); - fail = -1; - } else if (index < 0) { - // Too many emulators. - D("cannot register more emulators. Maximum is %d\n", - SDB_LOCAL_TRANSPORT_MAX); - fail = -1; - } else { - local_transports[index] = t; - } - } - sdb_mutex_unlock( &local_transports_lock ); + t->node = NULL; + t->req = 0; + t->res = 0; + t->sdb_port = sdb_port; +} + +void register_socket_transport(int s, const char *serial, int port, int local, const char *device_name) +{ + if(current_local_transports >= SDB_LOCAL_TRANSPORT_MAX) { + D("Too many emulators\n"); + sdb_close(s); + return; + } + + TRANSPORT *t = calloc(1, sizeof(TRANSPORT)); + char buff[32]; + + if (!serial) { + snprintf(buff, sizeof buff, "T-%p", t); + serial = buff; + } + D("transport: %s init'ing for socket %d, on port %d (%s)\n", serial, s, port, device_name); + int _port = port; + if(!local) { + _port = 0; + } + init_socket_transport(t, s, _port); + TRANSPORT* old_t = acquire_one_transport(kTransportAny, serial, NULL); + if(old_t != NULL) { + D("old transport '%s' is found. Unregister it\n", old_t->serial); + kick_transport(old_t); + } + + t->remote_cnxn_socket = NULL; + if(serial) { + t->serial = strdup(serial); + } + + if (device_name) { + t->device_name = strdup(device_name); + } else { + // device_name could be null when sdb server was forked before qemu has sent the connect message. + t->device_name = (char*) malloc(DEVICENAME_MAX+1); + if (get_devicename_from_shdmem(port, t->device_name) == -1) { + s_strncpy(t->device_name, DEFAULT_DEVICENAME, DEVICENAME_MAX); + } } - return fail; + ++current_local_transports; + register_transport(t); } diff --git a/src/transport_usb.c b/src/transport_usb.c old mode 100644 new mode 100755 index b0e557b..270bddd --- a/src/transport_usb.c +++ b/src/transport_usb.c @@ -18,107 +18,100 @@ #include #include +#include "log.h" #include "fdevent.h" #include "utils.h" #define TRACE_TAG TRACE_TRANSPORT -#include "sdb.h" #include "sdb_usb.h" +#include "transport.h" -#ifdef HAVE_BIG_ENDIAN -#define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) -static inline void fix_endians(apacket *p) -{ - p->msg.command = H4(p->msg.command); - p->msg.arg0 = H4(p->msg.arg0); - p->msg.arg1 = H4(p->msg.arg1); - p->msg.data_length = H4(p->msg.data_length); - p->msg.data_check = H4(p->msg.data_check); - p->msg.magic = H4(p->msg.magic); -} -unsigned host_to_le32(unsigned n) -{ - return H4(n); -} -#else -#define fix_endians(p) do {} while (0) -unsigned host_to_le32(unsigned n) -{ - return n; -} -#endif +static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state); -static int remote_read(apacket *p, atransport *t) +static int remote_read(TRANSPORT* t, void* data, int len) { - if(sdb_usb_read(t->usb, &p->msg, sizeof(amessage))){ - D("remote usb: read terminated (message)\n"); - return -1; - } - - fix_endians(p); - - if(check_header(p)) { - D("remote usb: check_header failed\n"); - return -1; - } - - if(p->msg.data_length) { - if(sdb_usb_read(t->usb, p->data, p->msg.data_length)){ - D("remote usb: terminated (data)\n"); - return -1; - } - } - - if(check_data(p)) { - D("remote usb: check_data failed\n"); - return -1; - } - - return 0; + return sdb_usb_read(t->usb, data, len); } -static int remote_write(apacket *p, atransport *t) +static int remote_write(PACKET *p, TRANSPORT *t) { - unsigned size = p->msg.data_length; - - fix_endians(p); - - if(sdb_usb_write(t->usb, &p->msg, sizeof(amessage))) { - D("remote usb: 1 - write terminated\n"); + dump_packet(t->serial, "remote_write_usb", p); + if(sdb_usb_write(t->usb, &p->msg, sizeof(MESSAGE))) { + LOG_ERROR("mesage write error\n"); return -1; } - if(p->msg.data_length == 0) return 0; - if(sdb_usb_write(t->usb, &p->data, size)) { - D("remote usb: 2 - write terminated\n"); - return -1; + + if(p->msg.data_length != 0) { + if(sdb_usb_write(t->usb, &p->data, p->msg.data_length)) { + D("remote usb: 2 - write terminated\n"); + return -1; + } } return 0; } -static void remote_close(atransport *t) +static void remote_close(TRANSPORT *t) { sdb_usb_close(t->usb); t->usb = 0; } -static void remote_kick(atransport *t) +static void remote_kick(TRANSPORT *t) { sdb_usb_kick(t->usb); } -void init_usb_transport(atransport *t, usb_handle *h, int state) +static void init_usb_transport(TRANSPORT *t, usb_handle *h, int state) { D("transport: usb\n"); t->close = remote_close; t->kick = remote_kick; t->read_from_remote = remote_read; t->write_to_remote = remote_write; - t->sync_token = 1; t->connection_state = state; t->type = kTransportUsb; t->usb = h; + t->sdb_port = -1; + t->req = 0; + t->res = 0; +} + +static int get_connected_device_count(transport_type type) +{ + int cnt = 0; + sdb_mutex_lock(&transport_lock, "transport get_connected_device_count"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT *t = curptr->data; + curptr = curptr->next_ptr; + if (type == t->type) { + cnt++; + } + } + + sdb_mutex_unlock(&transport_lock, "transport get_connected_device_count"); + D("connected device count:%d\n",cnt); + return cnt; +} - HOST = 1; +void register_usb_transport(usb_handle *usb, const char *serial) +{ + TRANSPORT *t = calloc(1, sizeof(TRANSPORT)); + char device_name[256]; + + D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb, + serial ? serial : ""); + init_usb_transport(t, usb, CS_OFFLINE); + if(serial) { + t->serial = strdup(serial); + } + t->remote_cnxn_socket = NULL; + register_transport(t); + + /* tizen specific */ + sprintf(device_name, "device-%d",get_connected_device_count(kTransportUsb)); + t->device_name = strdup(device_name); } int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_protocol) @@ -133,3 +126,20 @@ int is_sdb_interface(int vendor_id, int usb_class, int usb_subclass, int usb_pro return 0; } + +void close_usb_devices() +{ + sdb_mutex_lock(&transport_lock, "transport close_usb_devices"); + + LIST_NODE* curptr = transport_list; + while(curptr != NULL) { + TRANSPORT* t = curptr->data; + curptr = curptr->next_ptr; + if ( !t->kicked ) { + t->kicked = 1; + t->kick(t); + } + } + + sdb_mutex_unlock(&transport_lock, "transport close_usb_devices"); +} diff --git a/src/usb_darwin.c b/src/usb_darwin.c new file mode 100755 index 0000000..7e9024d --- /dev/null +++ b/src/usb_darwin.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * documents from https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/USBBook/USBOverview/USBOverview.html + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "fdevent.h" +#include "strutils.h" +#include "memutils.h" +#include "sdb_usb.h" +#include "device_vendors.h" +#include "log.h" +#include "utils.h" +#include "linkedlist.h" +#include "transport.h" + +#define 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); +} diff --git a/src/usb_linux.c b/src/usb_linux.c old mode 100755 new mode 100644 index 499b0c3..29aec30 --- a/src/usb_linux.c +++ b/src/usb_linux.c @@ -13,433 +13,444 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include #include #include #include - -#include -#include -#include -#include -#include #include -#include - -#include -#include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) +#include +#include #include -#else -#include -#endif -#include - +#include +#include +#include -#include "fdevent.h" #include "utils.h" -#define TRACE_TAG TRACE_USB -#include "sdb.h" - +#include "fdevent.h" +#include "strutils.h" +#include "sdb_usb.h" +#include "log.h" +#include "transport.h" -/* usb scan debugging is waaaay too verbose */ -#define DBGX(x...) +#define TRACE_TAG TRACE_USB SDB_MUTEX_DEFINE( usb_lock ); +LIST_NODE* usb_list = NULL; + struct usb_handle { - usb_handle *prev; - usb_handle *next; + LIST_NODE* node; - char fname[64]; - int desc; - unsigned char ep_in; - unsigned char ep_out; - - unsigned zero_mask; - unsigned writeable; + char unique_node_path[PATH_MAX+1]; + int node_fd; + unsigned char end_point[2]; // 0:in, 1:out + int interface; +}; - struct usbdevfs_urb urb_in; - struct usbdevfs_urb urb_out; +int register_device(const char* node, const char* serial) { + int fd; + unsigned char device_desc[4096]; + unsigned char* desc_current_ptr = NULL; - int urb_in_busy; - int urb_out_busy; - int dead; + if (node == NULL) { + return -1; + } + if (is_device_registered(node)) { + D("already registered device: %s\n", node); + return -1; + } + if ((fd = open(node, O_RDWR)) < 0) { + D ("failed to open usb node %s (%s)\n", node, strerror(errno)); + return -1; + } - sdb_cond_t notify; - sdb_mutex_t lock; + if (read(fd, device_desc, sizeof(device_desc)) < 0) { + D ("failed to read usb node %s (%s)\n", node, strerror(errno)); + close(fd); + return -1; + } + desc_current_ptr = device_desc; - // for garbage collecting disconnected devices - int mark; + // get device descriptor from head first + struct usb_device_descriptor* usb_dev = (struct usb_device_descriptor*)desc_current_ptr; - // ID of thread currently in REAPURB - pthread_t reaper_thread; -}; + if (USB_DT_DEVICE_SIZE != usb_dev->bLength) { + D("failed to get usb device descriptor\n"); + return -1; + } -static usb_handle handle_list = { - .prev = &handle_list, - .next = &handle_list, -}; + // move to get device config + desc_current_ptr += usb_dev->bLength; -static int known_device(const char *dev_name) -{ - usb_handle *usb; - - sdb_mutex_lock(&usb_lock); - for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ - if(!strcmp(usb->fname, dev_name)) { - // set mark flag to indicate this device is still alive - usb->mark = 1; - sdb_mutex_unlock(&usb_lock); - return 1; + // enumerate all available configuration descriptors + int i = 0; + for (i = 0; i < usb_dev->bNumConfigurations; i++) { + struct usb_config_descriptor* usb_config = (struct usb_config_descriptor *) desc_current_ptr; + if (USB_DT_CONFIG_SIZE != usb_config->bLength) { + D("failed to get usb config descriptor\n"); + break; } - } - sdb_mutex_unlock(&usb_lock); - return 0; -} + desc_current_ptr += usb_config->bLength; -static void linux_kick_disconnected_devices() -{ - usb_handle *usb; - - sdb_mutex_lock(&usb_lock); - // kick any devices in the device list that were not found in the device scan - for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ - if (usb->mark == 0) { - sdb_usb_kick(usb); - } else { - usb->mark = 0; + unsigned int wTotalLength = usb_config->wTotalLength; + unsigned int wSumLength = usb_config->bLength; + + if (usb_config->bNumInterfaces < 1) { + D("there is no interfaces\n"); + break; } - } - sdb_mutex_unlock(&usb_lock); -} + while (wSumLength < wTotalLength) + { + int bLength = desc_current_ptr[0]; + int bType = desc_current_ptr[1]; + + struct usb_interface_descriptor* usb_interface = (struct usb_interface_descriptor *)desc_current_ptr; + + if (is_sdb_interface(usb_dev->idVendor, usb_interface->bInterfaceClass, usb_interface->bInterfaceSubClass, + usb_interface->bInterfaceProtocol) && + (USB_DT_INTERFACE_SIZE == bLength && USB_DT_INTERFACE == bType && 2 == usb_interface->bNumEndpoints)) { + desc_current_ptr += usb_interface->bLength; + wSumLength += usb_interface->bLength; + struct usb_endpoint_descriptor *endpoint1 = (struct usb_endpoint_descriptor *) desc_current_ptr; + desc_current_ptr += endpoint1->bLength; + wSumLength += endpoint1->bLength; + struct usb_endpoint_descriptor *endpoint2 = (struct usb_endpoint_descriptor *) desc_current_ptr; + unsigned char endpoint_in; + unsigned char endpoint_out; + unsigned char interface = usb_interface->bInterfaceNumber; + // TODO: removed! + { + int bConfigurationValue = 2; + int n = ioctl(fd, USBDEVFS_RESET); + if (n != 0) { + D("usb reset failed\n"); + } + n = ioctl(fd, USBDEVFS_SETCONFIGURATION, &bConfigurationValue); + if (n != 0) { + D("check kernel is supporting %dth configuration\n", bConfigurationValue); + } -static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out, - int ifc, int serial_index, unsigned zero_mask); + n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface); + if (n != 0) { + D("usb claim failed\n"); + } + } -static inline int badname(const char *name) -{ - while(*name) { - if(!isdigit(*name++)) return 1; - } - return 0; -} + // find in/out endpoint address + if ((endpoint1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + endpoint_in = endpoint1->bEndpointAddress; + endpoint_out = endpoint2->bEndpointAddress; + } else { + endpoint_out = endpoint1->bEndpointAddress; + endpoint_in = endpoint2->bEndpointAddress; + } + // for now i can agree to register usb + { + usb_handle* usb = NULL; + usb = calloc(1, sizeof(usb_handle)); -static void find_usb_device(const char *base, - void (*register_device_callback) - (const char *, unsigned char, unsigned char, int, int, unsigned)) -{ - char busname[32], devname[32]; - unsigned char local_ep_in, local_ep_out; - DIR *busdir , *devdir ; - struct dirent *de; - int fd ; - - busdir = opendir(base); - if(busdir == 0) return; - - while((de = readdir(busdir)) != 0) { - if(badname(de->d_name)) continue; - - snprintf(busname, sizeof busname, "%s/%s", base, de->d_name); - devdir = opendir(busname); - if(devdir == 0) continue; - -// DBGX("[ scanning %s ]\n", busname); - while((de = readdir(devdir))) { - unsigned char devdesc[4096]; - unsigned char* bufptr = devdesc; - unsigned char* bufend; - struct usb_device_descriptor* device; - struct usb_config_descriptor* config; - struct usb_interface_descriptor* interface; - struct usb_endpoint_descriptor *ep1, *ep2; - unsigned zero_mask = 0; - unsigned vid, pid; - unsigned int desclength; - - if(badname(de->d_name)) continue; - snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name); - - if(known_device(devname)) { - DBGX("skipping %s\n", devname); - continue; - } + if (usb == NULL) { + break; + } + usb->node_fd = fd; + usb->interface = usb_interface->bInterfaceNumber; + usb->end_point[0] = endpoint_in; + usb->end_point[1] = endpoint_out; -// DBGX("[ scanning %s ]\n", devname); - if((fd = unix_open(devname, O_RDONLY)) < 0) { - continue; - } + char usb_serial[256] = {0,}; - desclength = sdb_read(fd, devdesc, sizeof(devdesc)); - bufend = bufptr + desclength; + if (serial != NULL) { + s_strncpy(usb_serial, serial, sizeof(usb_serial)); + } else { + strcpy(usb_serial, "unknown"); + } + s_strncpy(usb->unique_node_path, node, sizeof(usb->unique_node_path)); - // should have device and configuration descriptors, and atleast two endpoints - if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) { - D("desclength %d is too small\n", desclength); - sdb_close(fd); - continue; - } + sdb_mutex_lock(&usb_lock, "usb register locked"); + usb->node = prepend(&usb_list, usb); + D("-register new device (in: %04x, out: %04x) from %s\n", usb->end_point[0], usb->end_point[1], node); - device = (struct usb_device_descriptor*)bufptr; - bufptr += USB_DT_DEVICE_SIZE; + register_usb_transport(usb, usb_serial); + sdb_mutex_unlock(&usb_lock, "usb register unlocked"); + } + desc_current_ptr += endpoint2->bLength; + wSumLength += endpoint2->bLength; - if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) { - sdb_close(fd); - continue; + } else { + wSumLength += usb_interface->bLength; + desc_current_ptr += usb_interface->bLength; } + } + } + return 0; +} + +static void usb_plugged(struct udev_device *dev) { + if (udev_device_get_devnode(dev) != NULL) { + register_device(udev_device_get_devnode(dev), udev_device_get_sysattr_value(dev, "serial")); + } +} - vid = device->idVendor; - pid = device->idProduct; - DBGX("[ %s is V:%04x P:%04x ]\n", devname, vid, pid); +static void usb_unplugged(struct udev_device *dev) { + LOG_INFO("check device is removed from the list\n"); +} - // should have config descriptor next - config = (struct usb_config_descriptor *)bufptr; +int usb_register_callback(int msec) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; + + struct udev_monitor *mon; + int fd; + + // Create the udev object + udev = udev_new(); + if (!udev) { + D("Can't create udev\n"); + exit(1); + } - /* tizen specific */ - if (device->bNumConfigurations > 1) { - bufptr += config->wTotalLength; - config = (struct usb_config_descriptor *)bufptr; - bufend = bufptr + config->wTotalLength; - } + // Set up a monitor to monitor hidraw devices + mon = udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device"); + udev_monitor_enable_receiving(mon); - bufptr += USB_DT_CONFIG_SIZE; - if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) { - D("usb_config_descriptor not found\n"); - sdb_close(fd); - continue; - } + // Get the file descriptor (fd) for the monitor. This fd will get passed to select() + fd = udev_monitor_get_fd(mon); - // loop through all the descriptors and look for the SDB interface - while (bufptr < bufend) { - unsigned char length = bufptr[0]; - unsigned char type = bufptr[1]; + // Create a list of the devices in the 'usb' subsystem. + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "usb"); + udev_enumerate_scan_devices(enumerate); - if (type == USB_DT_INTERFACE) { - interface = (struct usb_interface_descriptor *)bufptr; - bufptr += length; + devices = udev_enumerate_get_list_entry(enumerate); - if (length != USB_DT_INTERFACE_SIZE) { - D("interface descriptor has wrong size\n"); - break; - } + D("doing lsusb to find tizen devices\n"); + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path; - DBGX("bInterfaceClass: %d, bInterfaceSubClass: %d," - "bInterfaceProtocol: %d, bNumEndpoints: %d\n", - interface->bInterfaceClass, interface->bInterfaceSubClass, - interface->bInterfaceProtocol, interface->bNumEndpoints); - - if (interface->bNumEndpoints == 2 && - is_sdb_interface(vid, interface->bInterfaceClass, - interface->bInterfaceSubClass, interface->bInterfaceProtocol)) { - - D("looking for bulk endpoints\n"); - // looks like SDB... - ep1 = (struct usb_endpoint_descriptor *)bufptr; - bufptr += USB_DT_ENDPOINT_SIZE; - ep2 = (struct usb_endpoint_descriptor *)bufptr; - bufptr += USB_DT_ENDPOINT_SIZE; - - if (bufptr > devdesc + desclength || - ep1->bLength != USB_DT_ENDPOINT_SIZE || - ep1->bDescriptorType != USB_DT_ENDPOINT || - ep2->bLength != USB_DT_ENDPOINT_SIZE || - ep2->bDescriptorType != USB_DT_ENDPOINT) { - D("endpoints not found\n"); - break; - } - - // both endpoints should be bulk - if (ep1->bmAttributes != USB_ENDPOINT_XFER_BULK || - ep2->bmAttributes != USB_ENDPOINT_XFER_BULK) { - D("bulk endpoints not found\n"); - continue; - } - /* aproto 01 needs 0 termination */ - if(interface->bInterfaceProtocol == 0x01) { - zero_mask = ep1->wMaxPacketSize - 1; - } - - // we have a match. now we just need to figure out which is in and which is out. - if (ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { - local_ep_in = ep1->bEndpointAddress; - local_ep_out = ep2->bEndpointAddress; - } else { - local_ep_in = ep2->bEndpointAddress; - local_ep_out = ep1->bEndpointAddress; - } - - register_device_callback(devname, local_ep_in, local_ep_out, - interface->bInterfaceNumber, device->iSerialNumber, zero_mask); - break; - } + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + usb_plugged(dev); + udev_device_unref(dev); + + } + // Free the enumerator object + udev_enumerate_unref(enumerate); + D("done lsusb to find tizen devices\n"); + while (1) { + fd_set fds; + struct timeval tv; + int ret; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + ret = select(fd+1, &fds, NULL, NULL, &tv); + + if (ret > 0 && FD_ISSET(fd, &fds)) { + dev = udev_monitor_receive_device(mon); + if (dev) { + if (!strcmp("add", udev_device_get_action(dev))) { + usb_plugged(dev); } else { - bufptr += length; + usb_unplugged(dev); } - } // end of while + udev_device_unref(dev); + } else { + D("failed to get noti from udev monitor\n"); + } + } + usleep(msec); + } + udev_unref(udev); - sdb_close(fd); - } // end of devdir while - closedir(devdir); - } //end of busdir while - closedir(busdir); + return 0; } -void sdb_usb_cleanup() +int is_device_registered(const char *unique_node_path) { + int r = 0; + sdb_mutex_lock(&usb_lock, "usb registering locked"); + + LIST_NODE* curptr = usb_list; + while(curptr != NULL) { + usb_handle *usb = curptr->data; + if (!strcmp(usb->unique_node_path, unique_node_path)) { + r = 1; + break; + } + curptr = curptr->next_ptr; + } + + sdb_mutex_unlock(&usb_lock, "usb registering unlocked"); + return r; } -static int usb_bulk_write(usb_handle *h, const void *data, int len) +void* usb_callback_thread(void* sleep_msec) { - struct usbdevfs_urb *urb = &h->urb_out; - int res; - struct timeval tv; - struct timespec ts; - - memset(urb, 0, sizeof(*urb)); - urb->type = USBDEVFS_URB_TYPE_BULK; - urb->endpoint = h->ep_out; - urb->status = -1; - urb->buffer = (void*) data; - urb->buffer_length = len; - - D("++ write ++\n"); - - sdb_mutex_lock(&h->lock); - if(h->dead) { - res = -1; - goto fail; - } - do { - res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb); - } while((res < 0) && (errno == EINTR)); + D("created usb callback thread\n"); + int mseconds = (int) sleep_msec; - if(res < 0) { - goto fail; - } + usb_register_callback(mseconds); - res = -1; - h->urb_out_busy = 1; - for(;;) { - /* time out after five seconds */ - gettimeofday(&tv, NULL); - ts.tv_sec = tv.tv_sec + 5; - ts.tv_nsec = tv.tv_usec * 1000L; - res = pthread_cond_timedwait(&h->notify, &h->lock, &ts); - if(res < 0 || h->dead) { - break; - } - if(h->urb_out_busy == 0) { - if(urb->status == 0) { - res = urb->actual_length; - } - break; - } + return NULL; +} + +void sdb_usb_init(void) +{ + sdb_thread_t tid; + + if(sdb_thread_create(&tid, usb_callback_thread, (void*)(250*1000))){ + LOG_FATAL("cannot create input thread\n"); } -fail: - sdb_mutex_unlock(&h->lock); - D("-- write --\n"); - return res; } -static int usb_bulk_read(usb_handle *h, void *data, int len) +void sdb_usb_cleanup() { - struct usbdevfs_urb *urb = &h->urb_in; - struct usbdevfs_urb *out = NULL; - int res; - - memset(urb, 0, sizeof(*urb)); - urb->type = USBDEVFS_URB_TYPE_BULK; - urb->endpoint = h->ep_in; - urb->status = -1; - urb->buffer = data; - urb->buffer_length = len; - - - sdb_mutex_lock(&h->lock); - if(h->dead) { - res = -1; - goto fail; + close_usb_devices(); +} + +#define URB_USERCONTEXT_COOKIE ((void *)0x1) + +static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size, int timeout) { + struct usbdevfs_urb urb; + int bytesdone = 0, requested; + struct timeval tv, tv_ref, tv_now; + struct usbdevfs_urb *context; + int ret, waiting; + + struct timeval tv_cur; + /* + * HACK: The use of urb.usercontext is a hack to get threaded applications + * sort of working again. Threaded support is still not recommended, but + * this should allow applications to work in the common cases. Basically, + * if we get the completion for an URB we're not waiting for, then we update + * the usercontext pointer to 1 for the other threads URB and it will see + * the change after it wakes up from the the timeout. Ugly, but it works. + */ + + /* + * Get actual time, and add the timeout value. The result is the absolute + * time where we have to quit waiting for an message. + */ + if (gettimeofday(&tv_cur, NULL) != 0) { + D("failed to read clock\n"); + return -1; } - do { - res = ioctl(h->desc, USBDEVFS_SUBMITURB, urb); - } while((res < 0) && (errno == EINTR)); + tv_cur.tv_sec = tv_cur.tv_sec + timeout / 1000; + tv_cur.tv_usec = tv_cur.tv_usec + (timeout % 1000) * 1000; - if(res < 0) { - goto fail; + if (tv_cur.tv_usec > 1000000) { + tv_cur.tv_usec -= 1000000; + tv_cur.tv_sec++; } - h->urb_in_busy = 1; - for(;;) { - D("[ reap urb - wait ]\n"); - h->reaper_thread = pthread_self(); - sdb_mutex_unlock(&h->lock); - res = ioctl(h->desc, USBDEVFS_REAPURB, &out); - int saved_errno = errno; - sdb_mutex_lock(&h->lock); - h->reaper_thread = 0; - if(h->dead) { - res = -1; - break; - } - if(res < 0) { - if(saved_errno == EINTR) { - continue; - } - D("[ reap urb - error ]\n"); - break; + do { + fd_set writefds; + + requested = size - bytesdone; + if (requested > MAX_READ_WRITE) + requested = MAX_READ_WRITE; + + urb.type = USBDEVFS_URB_TYPE_BULK; + urb.endpoint = ep; + urb.flags = 0; + urb.buffer = bytes + bytesdone; + urb.buffer_length = requested; + urb.signr = 0; + urb.actual_length = 0; + urb.number_of_packets = 0; /* don't do isochronous yet */ + urb.usercontext = NULL; + + ret = ioctl(h->node_fd, USBDEVFS_SUBMITURB, &urb); + if (ret < 0) { + D("failed to submit urb: %s\n", strerror(errno)); + return -1; } - D("[ urb @%p status = %d, actual = %d ]\n", - out, out->status, out->actual_length); - - if(out == &h->urb_in) { - D("[ reap urb - IN complete ]\n"); - h->urb_in_busy = 0; - if(urb->status == 0) { - res = urb->actual_length; - } else { - res = -1; + + FD_ZERO(&writefds); + FD_SET(h->node_fd, &writefds); + +restart: waiting = 1; + context = NULL; + while (!urb.usercontext && ((ret = ioctl(h->node_fd, USBDEVFS_REAPURBNDELAY, &context)) == -1) && waiting) { + tv.tv_sec = 0; + tv.tv_usec = 1000; // 1 msec + + select(h->node_fd + 1, NULL, &writefds, NULL, &tv); //sub second wait + + if (timeout) { + /* compare with actual time, as the select timeout is not that precise */ + gettimeofday(&tv_now, NULL); + + if ((tv_now.tv_sec > tv_cur.tv_sec) + || ((tv_now.tv_sec == tv_cur.tv_sec) && (tv_now.tv_usec >= tv_ref.tv_usec))) + waiting = 0; } - break; } - if(out == &h->urb_out) { - D("[ reap urb - OUT compelete ]\n"); - h->urb_out_busy = 0; - sdb_cond_broadcast(&h->notify); + + if (context && context != &urb) { + context->usercontext = URB_USERCONTEXT_COOKIE; + /* We need to restart since we got a successful URB, but not ours */ + goto restart; } + + /* + * If there was an error, that wasn't EAGAIN (no completion), then + * something happened during the reaping and we should return that + * error now + */ + if (ret < 0 && !urb.usercontext && errno != EAGAIN) + D("error reaping URB: %s\n", strerror(errno)); + + bytesdone += urb.actual_length; + } while ((ret == 0 || urb.usercontext) && bytesdone < size && urb.actual_length == requested); + + /* If the URB didn't complete in success or error, then let's unlink it */ + if (ret < 0 && !urb.usercontext) { + int rc; + if (!waiting) + rc = -ETIMEDOUT; + else + rc = urb.status; + + ret = ioctl(h->node_fd, USBDEVFS_DISCARDURB, &urb); + if (ret < 0 && errno != EINVAL) + D("error discarding URB: %s\n", strerror(errno)); + + /* + * When the URB is unlinked, it gets moved to the completed list and + * then we need to reap it or else the next time we call this function, + * we'll get the previous completion and exit early + */ + ioctl(h->node_fd, USBDEVFS_REAPURB, &context); + + return rc; } -fail: - sdb_mutex_unlock(&h->lock); - return res; -} + return bytesdone; +} int sdb_usb_write(usb_handle *h, const void *_data, int len) { - unsigned char *data = (unsigned char*) _data; - int n; - int need_zero = 0; - - if(h->zero_mask) { - /* if we need 0-markers and our transfer - ** is an even multiple of the packet size, - ** we make note of it - */ - if(!(len & h->zero_mask)) { - need_zero = 1; - } - } + char *data = (char*) _data; + int n = 0; + + D("+sdb_usb_write\n"); while(len > 0) { - int xfer = (len > 4096) ? 4096 : len; + int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len; - n = usb_bulk_write(h, data, xfer); + n = usb_urb_transfer(h, h->end_point[1], data, xfer, 0); if(n != xfer) { - D("ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); + D("fail to usb write: n = %d, errno = %d (%s)\n", n, errno, strerror(errno)); return -1; } @@ -447,37 +458,32 @@ int sdb_usb_write(usb_handle *h, const void *_data, int len) data += xfer; } - if(need_zero){ - n = usb_bulk_write(h, _data, 0); - return n; - } + D("-usb_write\n"); return 0; } int sdb_usb_read(usb_handle *h, void *_data, int len) { - unsigned char *data = (unsigned char*) _data; + char *data = (char*) _data; int n; - D("++ usb_read ++\n"); + D("+sdb_usb_read\n"); + while(len > 0) { - int xfer = (len > 4096) ? 4096 : len; + int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len; - D("[ usb read %d fd = %d], fname=%s\n", xfer, h->desc, h->fname); - n = usb_bulk_read(h, data, xfer); - D("[ usb read %d ] = %d, fname=%s\n", xfer, n, h->fname); + n = usb_urb_transfer(h, h->end_point[0], data, xfer, 0); if(n != xfer) { - if((errno == ETIMEDOUT) && (h->desc != -1)) { - D("[ timeout ]\n"); + if((errno == ETIMEDOUT)) { + D("usb bulk read timeout\n"); if(n > 0){ data += n; len -= n; } continue; } - D("ERROR: n = %d, errno = %d (%s)\n", - n, errno, strerror(errno)); + D("fail to usb read: n = %d, errno = %d (%s)\n", n, errno, strerror(errno)); return -1; } @@ -485,230 +491,28 @@ int sdb_usb_read(usb_handle *h, void *_data, int len) data += xfer; } - D("-- usb_read --\n"); + D("-sdb_usb_read\n"); + return 0; } void sdb_usb_kick(usb_handle *h) { - D("[ kicking %p (fd = %d) ]\n", h, h->desc); - sdb_mutex_lock(&h->lock); - if(h->dead == 0) { - h->dead = 1; - - if (h->writeable) { - /* HACK ALERT! - ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB). - ** This is a workaround for that problem. - */ - if (h->reaper_thread) { - pthread_kill(h->reaper_thread, SIGALRM); - } - - /* cancel any pending transactions - ** these will quietly fail if the txns are not active, - ** but this ensures that a reader blocked on REAPURB - ** will get unblocked - */ - ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in); - ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out); - h->urb_in.status = -ENODEV; - h->urb_out.status = -ENODEV; - h->urb_in_busy = 0; - h->urb_out_busy = 0; - sdb_cond_broadcast(&h->notify); - } else { - unregister_usb_transport(h); - } - } - sdb_mutex_unlock(&h->lock); + D("+kicking\n"); + D("-kicking\n"); } int sdb_usb_close(usb_handle *h) { - D("[ usb close ... ]\n"); - sdb_mutex_lock(&usb_lock); - h->next->prev = h->prev; - h->prev->next = h->next; - h->prev = 0; - h->next = 0; - - sdb_close(h->desc); - D("[ usb closed %p (fd = %d) ]\n", h, h->desc); - sdb_mutex_unlock(&usb_lock); - - free(h); - return 0; -} + D("+usb close\n"); -static void register_device(const char *dev_name, - unsigned char ep_in, unsigned char ep_out, - int interface, int serial_index, unsigned zero_mask) -{ - usb_handle* usb = 0; - int n = 0; - char serial[256]; - int bConfigurationValue = 2; /* tizen specific : sdb needs 2nd configruation */ - - /* Since Linux will not reassign the device ID (and dev_name) - ** as long as the device is open, we can add to the list here - ** once we open it and remove from the list when we're finally - ** closed and everything will work out fine. - ** - ** If we have a usb_handle on the list 'o handles with a matching - ** name, we have no further work to do. - */ - sdb_mutex_lock(&usb_lock); - for(usb = handle_list.next; usb != &handle_list; usb = usb->next){ - if(!strcmp(usb->fname, dev_name)) { - sdb_mutex_unlock(&usb_lock); - return; - } - } - sdb_mutex_unlock(&usb_lock); - - D("[ usb located new device %s (%d/%d/%d) ]\n", - dev_name, ep_in, ep_out, interface); - usb = calloc(1, sizeof(usb_handle)); - strcpy(usb->fname, dev_name); - usb->ep_in = ep_in; - usb->ep_out = ep_out; - usb->zero_mask = zero_mask; - usb->writeable = 1; - - sdb_cond_init(&usb->notify, 0); - sdb_mutex_init(&usb->lock, 0); - /* initialize mark to 1 so we don't get garbage collected after the device scan */ - usb->mark = 1; - usb->reaper_thread = 0; - - usb->desc = unix_open(usb->fname, O_RDWR); - if(usb->desc < 0) { - /* if we fail, see if have read-only access */ - usb->desc = unix_open(usb->fname, O_RDONLY); - if(usb->desc < 0) goto fail; - usb->writeable = 0; - D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc); - } else { - D("[ usb open %s fd = %d]\n", usb->fname, usb->desc); - // TODO: verify reset is really needed! - n = ioctl(usb->desc, USBDEVFS_RESET); - if(n != 0) { - D("[ usb reset failed %s fd = %d]\n", usb->fname, usb->desc); - } - n = ioctl(usb->desc, USBDEVFS_SETCONFIGURATION, &bConfigurationValue); - if (n != 0) { - D("[ usb set %d configuration failed %s fd = %d]\n", bConfigurationValue, usb->fname, usb->desc); - D("check kernel is supporting %dth configuration\n", bConfigurationValue); - } - - n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface); - if(n != 0) { - D("[ usb claim failed %s fd = %d]\n", usb->fname, usb->desc); - } + if (h != NULL) { + remove_node(&usb_list, h->node, no_free); + sdb_close(h->node_fd); + free(h); + h = NULL; } - - /* read the device's serial number */ - serial[0] = 0; - memset(serial, 0, sizeof(serial)); - if (serial_index) { - struct usbdevfs_ctrltransfer ctrl; - __u16 buffer[128]; - __u16 languages[128]; - int i, result; - int languageCount = 0; - - memset(languages, 0, sizeof(languages)); - memset(&ctrl, 0, sizeof(ctrl)); - - // read list of supported languages - ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; - ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; - ctrl.wValue = (USB_DT_STRING << 8) | 0; - ctrl.wIndex = 0; - ctrl.wLength = sizeof(languages); - ctrl.data = languages; - ctrl.timeout = 1000; - - result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl); - if (result > 0) - languageCount = (result - 2) / 2; - - for (i = 1; i <= languageCount; i++) { - memset(buffer, 0, sizeof(buffer)); - memset(&ctrl, 0, sizeof(ctrl)); - - ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; - ctrl.bRequest = USB_REQ_GET_DESCRIPTOR; - ctrl.wValue = (USB_DT_STRING << 8) | serial_index; - ctrl.wIndex = __le16_to_cpu(languages[i]); - ctrl.wLength = sizeof(buffer); - ctrl.data = buffer; - ctrl.timeout = 1000; - - result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl); - if (result > 0) { - int j; - // skip first word, and copy the rest to the serial string, changing shorts to bytes. - result /= 2; - for (j = 1; j < result; j++) { - serial[j - 1] = __le16_to_cpu(buffer[j]); - } - serial[j - 1] = 0; - break; - } - } - } - - /* add to the end of the active handles */ - sdb_mutex_lock(&usb_lock); - usb->next = &handle_list; - usb->prev = handle_list.prev; - usb->prev->next = usb; - usb->next->prev = usb; - sdb_mutex_unlock(&usb_lock); - - register_usb_transport(usb, serial, usb->writeable); - return; - -fail: - D("[ usb open %s error=%d, err_str = %s]\n", - usb->fname, errno, strerror(errno)); - if(usb->desc >= 0) { - sdb_close(usb->desc); - } - free(usb); -} - -void* device_poll_thread(void* unused) -{ - D("Created device thread\n"); - for(;;) { - /* XXX use inotify */ - find_usb_device("/dev/bus/usb", register_device); - linux_kick_disconnected_devices(); - sleep(1); - } - return NULL; -} - -static void sigalrm_handler(int signo) -{ - // don't need to do anything here + D("-usb close\n"); + return 0; } -void sdb_usb_init() -{ - sdb_thread_t tid; - struct sigaction actions; - - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = sigalrm_handler; - sigaction(SIGALRM,& actions, NULL); - - if(sdb_thread_create(&tid, device_poll_thread, NULL)){ - fatal_errno("cannot create input thread"); - } -} diff --git a/src/utils.c b/src/utils.c old mode 100644 new mode 100755 index aab3afb..16e1fec --- a/src/utils.c +++ b/src/utils.c @@ -21,10 +21,12 @@ #include "utils.h" #include "utils_backend.h" +#include "log.h" #include "fdevent.h" #include "sdb_constants.h" -#include "sdb.h" + +#define TRACE_TAG TRACE_SDB #if defined(OS_WINDOWS) const struct utils_os_backend* utils_backend = &utils_windows_backend; @@ -187,18 +189,23 @@ char* ansi_to_utf8(const char *str) { } int sdb_open(const char* path, int options) { + LOG_INFO("path %s, options %d\n", path, options); return utils_backend->sdb_open(path, options); } -int sdb_open_mode(const char* pathname, int options, int mode) { - return utils_backend->sdb_open_mode(pathname, options, mode); -} - int unix_open(const char* path, int options, ...) { - return utils_backend->unix_open(path, options); + int mode; + va_list args; + + va_start( args, options); + mode = va_arg( args, int ); + va_end( args); + + return open(path, options, mode); } int sdb_creat(const char* path, int mode) { + LOG_INFO("path %s mode %d\n", path, mode); return utils_backend->sdb_creat(path, mode); } @@ -210,10 +217,6 @@ int sdb_write(int fd, const void* buf, size_t len) { return utils_backend->sdb_write(fd, buf, len); } -int sdb_lseek(int fd, int pos, int where) { - return utils_backend->sdb_lseek(fd, pos, where); -} - int sdb_shutdown(int fd) { return utils_backend->sdb_shutdown(fd); } @@ -222,8 +225,16 @@ int sdb_close(int fd) { return utils_backend->sdb_close(fd); } -int sdb_unlink(const char* path) { - return utils_backend->sdb_unlink(path); +int unix_unlink(const char* path) { + int rc = unlink(path); + + if (rc == -1 && errno == EACCES) { + rc = chmod(path, S_IREAD | S_IWRITE); + if (rc == 0) { + rc = unlink(path); + } + } + return rc; } int sdb_mkdir(const char* path, int mode) { @@ -234,11 +245,13 @@ void close_on_exec(int fd) { return utils_backend->close_on_exec(fd); } -int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { - return utils_backend->sdb_socket_accept(serverfd, addr, addrlen); +int sdb_socket_accept(int serverfd) { + LOG_INFO("FD(%d)\n"); + return utils_backend->sdb_socket_accept(serverfd); } int sdb_socketpair(int sv[2]) { + LOG_INFO("\n"); return utils_backend->sdb_socketpair(sv); } @@ -266,11 +279,17 @@ int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg) return utils_backend->sdb_thread_create(pthread, start, arg); } -int sdb_mutex_lock(sdb_mutex_t *mutex) { +int sdb_mutex_lock(sdb_mutex_t *mutex, char* name) { + if(name != NULL) { + D("lock %s\n", name); + } return utils_backend->sdb_mutex_lock(mutex); } -int sdb_mutex_unlock(sdb_mutex_t *mutex) { +int sdb_mutex_unlock(sdb_mutex_t *mutex, char *name) { + if(name != NULL) { + D("unlock %s\n", name); + } return utils_backend->sdb_mutex_unlock(mutex); } @@ -290,18 +309,13 @@ void sdb_sysdeps_init(void) { return utils_backend->sdb_sysdeps_init(); } -int socket_loopback_client(int port, int type) { - return utils_backend->socket_loopback_client(port, type); +int sdb_host_connect(const char *host, int port, int type) { + LOG_INFO("host %s, port %d\n", host, port); + return utils_backend->sdb_host_connect(host, port, type); } -int socket_network_client(const char *host, int port, int type) { - return utils_backend->socket_network_client(host, port, type); +int sdb_port_listen(uint32_t inet, int port, int type) { + LOG_INFO("port %d, type %d\n", port, type); + return utils_backend->sdb_port_listen(inet, port, type); } -int socket_loopback_server(int port, int type) { - return utils_backend->socket_loopback_server(port, type); -} - -int socket_inaddr_any_server(int port, int type) { - return utils_backend->socket_inaddr_any_server(port, type); -} diff --git a/src/utils.h b/src/utils.h index 1d87666..a31af34 100644 --- a/src/utils.h +++ b/src/utils.h @@ -83,14 +83,17 @@ extern int unix_read(int fd, void* buf, size_t len); typedef pthread_t sdb_thread_t; typedef pthread_mutex_t sdb_mutex_t; #define sdb_cond_t pthread_cond_t -#define sdb_mutex_init pthread_mutex_init +#define sdb_mutex_init pthread_mutex_init +#define sdb_cond_signal pthread_cond_signal +#define sdb_cond_destroy pthread_cond_destroy +#define sdb_mutex_destroy pthread_mutex_destroy typedef void* (*sdb_thread_func_t)( void* arg ); void sdb_sysdeps_init(void); int sdb_thread_create(sdb_thread_t *pthread, sdb_thread_func_t start, void* arg); -int sdb_mutex_lock(sdb_mutex_t *mutex); -int sdb_mutex_unlock(sdb_mutex_t *mutex); +int sdb_mutex_lock(sdb_mutex_t *mutex, char* lock_name); +int sdb_mutex_unlock(sdb_mutex_t *mutex, char* lock_name); int sdb_cond_init(sdb_cond_t *cond, const void *unused); int sdb_cond_wait(sdb_cond_t *cond, sdb_mutex_t *mutex); int sdb_cond_broadcast(sdb_cond_t *cond); @@ -98,9 +101,8 @@ int sdb_cond_broadcast(sdb_cond_t *cond); #define SDB_MUTEX(x) sdb_mutex_t x; SDB_MUTEX(dns_lock) -SDB_MUTEX(socket_list_lock) SDB_MUTEX(transport_lock) -SDB_MUTEX(local_transports_lock) +SDB_MUTEX(wakeup_select_lock) SDB_MUTEX(usb_lock) SDB_MUTEX(D_lock) @@ -113,13 +115,12 @@ int unix_open(const char* path, int options, ...); int sdb_creat(const char* path, int mode); int sdb_read(int fd, void* buf, size_t len); int sdb_write(int fd, const void* buf, size_t len); -int sdb_lseek(int fd, int pos, int where); int sdb_shutdown(int fd); int sdb_close(int fd); -int sdb_unlink(const char* path); +int unix_unlink(const char* path); int sdb_mkdir(const char* path, int mode); void close_on_exec(int fd); -int sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); +int sdb_socket_accept(int serverfd); int sdb_socketpair(int sv[2]); void sdb_sleep_ms(int mseconds); char* sdb_dirstart(const char* path); @@ -128,10 +129,10 @@ int sdb_socket_setbufsize(int fd, int bufsize); void disable_tcp_nagle(int fd); // sockets -int socket_loopback_client(int port, int type); -int socket_network_client(const char *host, int port, int type); -int socket_loopback_server(int port, int type); -int socket_inaddr_any_server(int port, int type); +#define LISTEN_BACKLOG 4 + +int sdb_host_connect(const char *host, int port, int type); +int sdb_port_listen(uint32_t inet, int port, int type); #define DEVICEMAP_SEPARATOR ":" #define DEVICENAME_MAX 256 diff --git a/src/utils_backend.h b/src/utils_backend.h old mode 100644 new mode 100755 index 39d0295..f8feb7a --- a/src/utils_backend.h +++ b/src/utils_backend.h @@ -17,100 +17,37 @@ #ifndef _SDB_BACKEND_UTILS_H #define _SDB_BACKEND_UTILS_H -#if defined(OS_WINDOWS) - -typedef const struct FHClassRec_* FHClass; - -typedef struct FHRec_* FH; - -typedef struct EventHookRec_* EventHook; - -typedef struct FHClassRec_ -{ - void (*_fh_init) ( FH f ); - int (*_fh_close)( FH f ); - int (*_fh_lseek)( FH f, int pos, int origin ); - int (*_fh_read) ( FH f, void* buf, int len ); - int (*_fh_write)( FH f, const void* buf, int len ); - void (*_fh_hook) ( FH f, int events, EventHook hook ); - -} FHClassRec; +#include "linkedlist.h" +#include "sdb_map.h" -/* used to emulate unix-domain socket pairs */ -typedef struct SocketPairRec_* SocketPair; -typedef struct FHRec_ -{ - FHClass clazz; - int used; - int eof; - union { - HANDLE handle; - SOCKET socket; - SocketPair pair; - } u; +#if defined(OS_WINDOWS) - HANDLE event; - int mask; +struct sdb_handle { + union { + HANDLE file_handle; + SOCKET socket; + } u; + int fd; +}; - char name[32]; +typedef struct sdb_handle SDB_HANDLE; -} FHRec; +struct sdb_socket_handle { + SDB_HANDLE handle; + int event_location; +}; -#define fh_handle u.handle -#define fh_socket u.socket -#define fh_pair u.pair +typedef struct sdb_socket_handle SDB_SOCK_HANDLE; #define BIP_BUFFER_SIZE 4096 -#define WIN32_FH_BASE 100 -#define WIN32_MAX_FHS 128 - -typedef struct BipBufferRec_ -{ - int a_start; - int a_end; - int b_end; - int fdin; - int fdout; - int closed; - int can_write; /* boolean */ - HANDLE evt_write; /* event signaled when one can write to a buffer */ - int can_read; /* boolean */ - HANDLE evt_read; /* event signaled when one can read from a buffer */ - CRITICAL_SECTION lock; - unsigned char buff[ BIP_BUFFER_SIZE ]; - -} BipBufferRec, *BipBuffer; - -typedef struct EventLooperRec_* EventLooper; - -typedef struct EventHookRec_ -{ - EventHook next; - FH fh; - HANDLE h; - int wanted; /* wanted event flags */ - int ready; /* ready event flags */ - void* aux; - void (*prepare)( EventHook hook ); - int (*start) ( EventHook hook ); - void (*stop) ( EventHook hook ); - int (*check) ( EventHook hook ); - int (*peek) ( EventHook hook ); -} EventHookRec; - #define MAX_LOOPER_HANDLES WIN32_MAX_FHS +#define IS_SOCKET_HANDLE(handle) (handle->fd < WIN32_MAX_FHS) +#define IS_SOCKET_FD(fd) (fd < WIN32_MAX_FHS) -typedef struct EventLooperRec_ -{ - EventHook hooks; - HANDLE htab[ MAX_LOOPER_HANDLES ]; - int htab_count; - -} EventLooperRec; - -int _fh_to_int( FH f ); -FH _fh_from_int( int fd ); +SDB_HANDLE* sdb_handle_map_get(int _key); +void sdb_handle_map_put(int _key, SDB_HANDLE* value); +void sdb_handle_map_remove(int _key); #else #endif // end of unix @@ -123,18 +60,14 @@ struct utils_os_backend { void (*start_logging)(void); char* (*ansi_to_utf8)(const char *str); int (*sdb_open)(const char* path, int options); - int (*sdb_open_mode)(const char* path, int options, int mode); - int (*unix_open)(const char* path, int options, ...); int (*sdb_creat)(const char* path, int mode); int (*sdb_read)(int fd, void* buf, size_t len); int (*sdb_write)(int fd, const void* buf, size_t len); - int (*sdb_lseek)(int fd, int pos, int where); int (*sdb_shutdown)(int fd); int (*sdb_close)(int fd); - int (*sdb_unlink)(const char* path); int (*sdb_mkdir)(const char* path, int mode); void (*close_on_exec)(int fd); - int (*sdb_socket_accept)(int serverfd, struct sockaddr* addr, socklen_t *addrlen); + int (*sdb_socket_accept)(int serverfd); int (*sdb_socketpair)(int sv[2]); void (*sdb_sleep_ms)(int mseconds); char* (*sdb_dirstart)(const char* path); @@ -156,10 +89,8 @@ struct utils_os_backend { int (*sdb_cond_broadcast)(sdb_cond_t *cond); void (*sdb_sysdeps_init)(void); // helpers for sockets - int (*socket_loopback_client)(int port, int type); - int (*socket_network_client)(const char *host, int port, int type); - int (*socket_loopback_server)(int port, int type); - int (*socket_inaddr_any_server)(int port, int type); + int (*sdb_host_connect)(const char *host, int port, int type); + int (*sdb_port_listen)(uint32_t inet, int port, int type); }; diff --git a/src/utils_unix.c b/src/utils_unix.c old mode 100644 new mode 100755 index c9227a1..5f29b68 --- a/src/utils_unix.c +++ b/src/utils_unix.c @@ -46,12 +46,8 @@ #include "fdevent.h" #define TRACE_TAG TRACE_SYSDEPS -#include "sdb.h" #include "utils_backend.h" - -#define LISTEN_BACKLOG 4 - -static void _close_on_exec(int fd); +#include "log.h" #if defined(OS_DARWIN) @@ -104,6 +100,8 @@ static int _launch_server(int server_port) dup2(fd[1], STDERR_FILENO); sdb_close(fd[1]); + sdb_close(STDOUT_FILENO); + // child process int result = execl(path, "sdb", "fork-server", "server", NULL); // this should not return @@ -119,6 +117,7 @@ static int _launch_server(int server_port) int ret = sdb_read(fd[0], temp, 3); int saved_errno = errno; sdb_close(fd[0]); + if (ret < 0) { fprintf(stderr, "could not read ok from SDB Server, errno = %d\n", saved_errno); return -1; @@ -136,23 +135,36 @@ static int _launch_server(int server_port) static void _start_logging(void) { - const char* p = getenv("SDB_TRACE"); + const char* p = getenv(DEBUG_ENV); if (p == NULL) { return; } int fd; fd = unix_open("/dev/null", O_RDONLY); - dup2(fd, 0); - sdb_close(fd); + if (fd >= 0) { + dup2(fd, 0); + sdb_close(fd); + } + else { + sdb_close(0); + } fd = unix_open("/tmp/sdb.log", O_WRONLY | O_CREAT | O_APPEND, 0640); if(fd < 0) { + fprintf(stderr, "fail to open '/tmp/sdb.log' logging fails\n"); fd = unix_open("/dev/null", O_WRONLY); + if( fd < 0 ) { + fprintf(stderr, "fail to open /dev/null\n"); + fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid()); + return; + } } + dup2(fd, 1); dup2(fd, 2); sdb_close(fd); + fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid()); } @@ -169,21 +181,9 @@ static char* _ansi_to_utf8(const char *str) return utf8; } -static int _unix_open(const char* path, int options,...) +static void _close_on_exec(int fd) { - if ((options & O_CREAT) == 0) - { - return open(path, options); - } - else - { - int mode; - va_list args; - va_start( args, options ); - mode = va_arg( args, int ); - va_end( args ); - return open(path, options, mode); - } + fcntl( fd, F_SETFD, FD_CLOEXEC ); } static int _sdb_open( const char* pathname, int options ) @@ -195,15 +195,9 @@ static int _sdb_open( const char* pathname, int options ) return fd; } -static int _sdb_open_mode( const char* pathname, int options, int mode ) -{ - return open( pathname, options, mode ); -} - - static int _sdb_creat(const char* path, int mode) { - int fd = creat(path, mode); + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); if ( fd < 0 ) return -1; @@ -222,11 +216,6 @@ static int _sdb_write(int fd, const void* buf, size_t len) return write(fd, buf, len); } -static int _sdb_lseek(int fd, int pos, int where) -{ - return lseek(fd, pos, where); -} - static int _sdb_shutdown(int fd) { return shutdown(fd, SHUT_RDWR); @@ -237,26 +226,19 @@ static int _sdb_close(int fd) return close(fd); } -static void _close_on_exec(int fd) -{ - fcntl( fd, F_SETFD, FD_CLOEXEC ); -} - -static int _sdb_unlink(const char* path) -{ - return unlink(path); -} - static int _sdb_mkdir(const char* path, int mode) { return mkdir(path, mode); } -static int _sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) +static int _sdb_socket_accept(int serverfd) { int fd; + struct sockaddr addr; + socklen_t alen = sizeof(addr); + + fd = accept(serverfd, &addr, &alen); - fd = accept(serverfd, addr, addrlen); if (fd >= 0) { _close_on_exec(fd); } @@ -343,44 +325,32 @@ static void _sdb_sysdeps_init(void) { } -static int _socket_loopback_client(int port, int type) +static int _sdb_host_connect(const char *host, int port, int type) { + struct hostent *hp; struct sockaddr_in addr; int s; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - s = socket(AF_INET, type, 0); - if(s < 0) return -1; - - if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - sdb_close(s); + // FIXME: might take a long time to get information + if ((hp = gethostbyname(host)) == NULL) { + LOG_ERROR("failed to get hostname:%s(%d)\n", host, port); return -1; } - return s; - -} - -static int _socket_network_client(const char *host, int port, int type) -{ - struct hostent *hp; - struct sockaddr_in addr; - int s; - - hp = gethostbyname(host); - if(hp == 0) return -1; - memset(&addr, 0, sizeof(addr)); addr.sin_family = hp->h_addrtype; addr.sin_port = htons(port); memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - s = socket(hp->h_addrtype, type, 0); - if(s < 0) return -1; + if (type == SOCK_STREAM) { + s = socket(AF_INET, type, 0); + } else { + s = socket(AF_INET, type, IPPROTO_UDP); + } + if (s < 0) { + LOG_ERROR("failed to create socket to %s(%d)\n", host, port); + return -1; + } if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { sdb_close(s); @@ -391,61 +361,21 @@ static int _socket_network_client(const char *host, int port, int type) } -static int _socket_loopback_server(int port, int type) +static int _sdb_port_listen(uint32_t inet, int port, int type) { struct sockaddr_in addr; int s, n; - int cnt_max = 30; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(inet); addr.sin_port = htons(port); - if(cnt_max ==0) - addr.sin_addr.s_addr = htonl(INADDR_ANY); - else - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - s = socket(AF_INET, type, 0); - if(s < 0) return -1; - - n = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); - - - - if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - sdb_close(s); + if ((s = socket(AF_INET, type, 0)) < 0) { + LOG_ERROR("failed to create socket to %u(%d)\n", inet, port); return -1; } - if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - - if (ret < 0) { - sdb_close(s); - return -1; - } - } - - return s; -} - -static int _socket_inaddr_any_server(int port, int type) -{ - struct sockaddr_in addr; - int s, n; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - s = socket(AF_INET, type, 0); - if(s < 0) return -1; - n = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); @@ -454,12 +384,9 @@ static int _socket_inaddr_any_server(int port, int type) return -1; } + // only listen if tcp mode if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - - if (ret < 0) { + if (listen(s, LISTEN_BACKLOG) < 0) { sdb_close(s); return -1; } @@ -468,22 +395,19 @@ static int _socket_inaddr_any_server(int port, int type) return s; } + const struct utils_os_backend utils_unix_backend = { .name = "unix utils", .launch_server = _launch_server, .start_logging = _start_logging, .ansi_to_utf8 = _ansi_to_utf8, .sdb_open = _sdb_open, - .sdb_open_mode = _sdb_open_mode, - .unix_open = _unix_open, .sdb_creat = _sdb_creat, .sdb_read = _sdb_read, .sdb_write = _sdb_write, - .sdb_lseek = _sdb_lseek, .sdb_shutdown = _sdb_shutdown, .sdb_close = _sdb_close, .close_on_exec = _close_on_exec, - .sdb_unlink = _sdb_unlink, .sdb_mkdir = _sdb_mkdir, .sdb_socket_accept = _sdb_socket_accept, .sdb_socketpair = _sdb_socketpair, @@ -500,8 +424,6 @@ const struct utils_os_backend utils_unix_backend = { .sdb_cond_wait = _sdb_cond_wait, .sdb_cond_broadcast = _sdb_cond_broadcast, .sdb_sysdeps_init = _sdb_sysdeps_init, - .socket_loopback_client = _socket_loopback_client, - .socket_network_client = _socket_network_client, - .socket_loopback_server = _socket_loopback_server, - .socket_inaddr_any_server = _socket_inaddr_any_server + .sdb_host_connect = _sdb_host_connect, + .sdb_port_listen = _sdb_port_listen }; diff --git a/src/utils_windows.c b/src/utils_windows.c old mode 100644 new mode 100755 index 3f1b5eb..33edf5a --- a/src/utils_windows.c +++ b/src/utils_windows.c @@ -13,17 +13,108 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include #include #include #include +#include #include "utils.h" #include "fdevent.h" #include "fdevent_backend.h" +#include "sdb_map.h" #define TRACE_TAG TRACE_SYSDEPS -#include "sdb.h" #include "utils_backend.h" +#include "log.h" + +// error mapping table between windoes & unix +// error codes are described: http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx +void setBaseErrno(DWORD dwLastErrorCode); +int getBaseErrno(DWORD dwLastErrorCode); + +static int total_handle_number = 0; +static LIST_NODE* free_socket_handle_list = NULL; +//this increases 1 when one file fd is created. +static int file_handle_count = WIN32_MAX_FHS; +//this indicates total number of socket fds. +static int socket_handle_number = 0; + +struct errno_lists { + unsigned long wincode; + int posixcode; +}; + +static struct errno_lists errno_list[] = { + { 0, 0 }, /* 0 return 0 as normal operation */ + { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 Incorrect function. */ + { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 The system cannot find the file specified. */ + { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 The system cannot find the path specified. */ + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 The system cannot open the file. */ + { ERROR_ACCESS_DENIED, EACCES }, /* 5 Access is denied. */ + { ERROR_INVALID_HANDLE, EBADF }, /* 6 The handle is invalid. */ + { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 The storage control blocks were destroyed.*/ + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 Not enough storage is available to process this command. */ + { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 he storage control block address is invalid. */ + { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 The environment is incorrect. */ + { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 An attempt was made to load a program with an incorrect format. */ + { ERROR_INVALID_ACCESS, EINVAL }, /* 12 The access code is invalid. */ + { ERROR_INVALID_DATA, EINVAL }, /* 13 The data is invalid. */ + { ERROR_OUTOFMEMORY, ENOMEM }, /* 14 Not enough storage is available to complete this operation. */ + { ERROR_INVALID_DRIVE, ENOENT }, /* 15 The system cannot find the drive specified.*/ + { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */ + { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */ + { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */ + { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */ + { ERROR_BAD_NETPATH, ENOENT }, /* 53 */ + { ERROR_NETWORK_ACCESS_DENIED, EACCES },/* 65 */ + { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */ + { ERROR_FILE_EXISTS, EEXIST }, /* 80 */ + { ERROR_CANNOT_MAKE, EACCES }, /* 82 */ + { ERROR_FAIL_I24, EACCES }, /* 83 */ + { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */ + { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */ + { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */ + { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */ + { ERROR_DISK_FULL, ENOSPC }, /* 112 */ + { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */ + { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */ + { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */ + { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */ + { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */ + { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */ + { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */ + { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */ + { ERROR_NOT_LOCKED, EACCES }, /* 158 */ + { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */ + { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */ + { ERROR_LOCK_FAILED, EACCES }, /* 167 */ + { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */ + { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */ + { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */ + { ERROR_NO_DATA, EPIPE }, /* 232 */ + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }, /* 1816 */ + { WSAEINTR, EINTR }, /* 10004 Interrupted function call. */ + { WSAEWOULDBLOCK, EAGAIN } /* 10035 This error is returned from operations on nonblocking sockets that cannot be completed immediately */ +}; + +void setBaseErrno(DWORD dwLastErrorCode) +{ + errno = getBaseErrno(dwLastErrorCode); +} + +int getBaseErrno(DWORD dwLastErrorCode) +{ + int i; + + for (i = 0; i < sizeof(errno_list)/sizeof(errno_list[0]); ++i) { + if (dwLastErrorCode == errno_list[i].posixcode) { + return errno_list[i].posixcode; + } + } + LOG_FIXME("unsupport error code: %ld\n", dwLastErrorCode); + return EINVAL; +} /* * from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx @@ -122,7 +213,7 @@ static int _launch_server(int server_port) { static void _start_logging(void) { - const char* p = getenv("SDB_TRACE"); + const char* p = getenv(DEBUG_ENV); if (p == NULL) { return; } @@ -150,11 +241,6 @@ static void _start_logging(void) fprintf(stderr,"--- sdb starting (pid %d) ---\n", getpid()); } - -extern void fatal(const char *fmt, ...); - -#define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0) - /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -164,344 +250,275 @@ extern void fatal(const char *fmt, ...); /**************************************************************************/ static sdb_mutex_t _win32_lock; -static FHRec _win32_fhs[WIN32_MAX_FHS]; -static int _win32_fh_count; - -FH _fh_from_int(int fd) { - FH f; - - fd -= WIN32_FH_BASE; - - if (fd < 0 || fd >= _win32_fh_count) { - D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE); - errno = EBADF; - return NULL; +static sdb_mutex_t sdb_handle_map_lock; +static sdb_mutex_t free_socket_handle_list_lock; + +static SDB_HANDLE* alloc_handle(int socket) { + + SDB_HANDLE* _h = NULL; + sdb_mutex_lock(&_win32_lock, "_fh_alloc"); + + if(total_handle_number < WIN32_MAX_FHS) { + total_handle_number++; + if(socket) { + if(free_socket_handle_list == NULL) { + SDB_SOCK_HANDLE* __h = malloc(sizeof(SDB_SOCK_HANDLE)); + __h->event_location = -1; + _h = (SDB_HANDLE*)__h; + _h->fd = socket_handle_number++; + LOG_INFO("no free socket. assign socket fd FD(%d)\n", _h->fd); + } + else { + sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_alloc"); + _h = free_socket_handle_list->data; + remove_first(&free_socket_handle_list, no_free); + sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_alloc"); + LOG_INFO("reuse socket fd FD(%d)\n", _h->fd); + } + _h->u.socket = INVALID_SOCKET; + } + else { + _h = malloc(sizeof(SDB_HANDLE)); + _h->fd = file_handle_count++; + _h->u.file_handle = INVALID_HANDLE_VALUE; + } + + sdb_handle_map_put(_h->fd, _h); } - - f = &_win32_fhs[fd]; - - if (f->used == 0) { - D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE); - errno = EBADF; - return NULL; - } - - return f; -} - -int _fh_to_int(FH f) { - if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS) - return (int) (f - _win32_fhs) + WIN32_FH_BASE; - - return -1; + else { + errno = ENOMEM; + LOG_ERROR("no more space for file descriptor. max file descriptor is %d\n", WIN32_MAX_FHS); + } + + sdb_mutex_unlock(&_win32_lock, "_fh_alloc"); + return _h; +} + +SDB_HANDLE* sdb_handle_map_get(int _key) { + MAP_KEY key; + key.key_int = _key; + sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_get"); + SDB_HANDLE* result = map_get(&sdb_handle_map, key); + sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_get"); + return result; +} + +void sdb_handle_map_put(int _key, SDB_HANDLE* value) { + MAP_KEY key; + key.key_int = _key; + sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_put"); + map_put(&sdb_handle_map, key, value); + sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_put"); +} + +void sdb_handle_map_remove(int _key) { + MAP_KEY key; + key.key_int = _key; + sdb_mutex_lock(&sdb_handle_map_lock, "sdb_handle_map_remove"); + map_remove(&sdb_handle_map, key); + sdb_mutex_unlock(&sdb_handle_map_lock, "sdb_handle_map_remove"); +} + +static int _fh_close(SDB_HANDLE* _h) { + if(IS_SOCKET_HANDLE(_h)) { + shutdown(_h->u.socket, SD_BOTH); + closesocket(_h->u.socket); + _h->u.socket = INVALID_SOCKET; + sdb_handle_map_remove(_h->fd); + sdb_mutex_lock(&free_socket_handle_list_lock, "_fh_close"); + prepend(&free_socket_handle_list, _h); + sdb_mutex_unlock(&free_socket_handle_list_lock, "_fh_close"); + } + else { + CloseHandle(_h->u.file_handle); + _h->u.file_handle = INVALID_HANDLE_VALUE; + free(_h); + } + total_handle_number--; + return 0; } -static FH _fh_alloc(FHClass clazz) { - int nn; - FH f = NULL; +static int check_socket_err(int result) { - sdb_mutex_lock(&_win32_lock); + if(result != SOCKET_ERROR) { + return result; + } - if (_win32_fh_count < WIN32_MAX_FHS) { - f = &_win32_fhs[_win32_fh_count++]; - goto Exit; - } + DWORD err = WSAGetLastError(); - for (nn = 0; nn < WIN32_MAX_FHS; nn++) { - if (_win32_fhs[nn].clazz == NULL) { - f = &_win32_fhs[nn]; - goto Exit; - } - } - D( "_fh_alloc: no more free file descriptors\n"); - Exit: if (f) { - f->clazz = clazz; - f->used = 1; - f->eof = 0; - clazz->_fh_init(f); - } - sdb_mutex_unlock(&_win32_lock); - return f; -} - -static int _fh_close(FH f) { - if (f->used) { - f->clazz->_fh_close(f); - f->used = 0; - f->eof = 0; - f->clazz = NULL; - } - return 0; + if(err == WSAEWOULDBLOCK) { + errno = EAGAIN; + LOG_ERROR("socket error EAGAIN\n"); + } + else if(err == WSAEINTR) { + errno = EINTR; + LOG_ERROR("socket error EINTR\n"); + } + else if(err == 0) { + errno = 0; + LOG_ERROR("socket error 0\n"); + } + else { + errno = EINVAL; + LOG_ERROR("unknown error %d\n", err); + } + return -1; } -/* forward definitions */ -static const FHClassRec _fh_file_class; -static const FHClassRec _fh_socket_class; +static int check_file_err(HANDLE h) { -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** file-based descriptor handling *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ + if (h != INVALID_HANDLE_VALUE) { + return 1; + } -static void _fh_file_init(FH f) { - f->fh_handle = INVALID_HANDLE_VALUE; -} + _fh_close(h); + DWORD err = GetLastError(); -static int _fh_file_close(FH f) { - CloseHandle(f->fh_handle); - f->fh_handle = INVALID_HANDLE_VALUE; - return 0; + if(err == ERROR_PATH_NOT_FOUND) { + LOG_ERROR("path not found\n"); + errno = ENOTDIR; + } + else if (err == ERROR_FILE_NOT_FOUND) { + LOG_ERROR("file not found\n"); + errno = ENOENT; + } + else { + LOG_ERROR("unknown erro %d\n", err); + errno = ENOENT; + } + return -1; } -static int _fh_file_read(FH f, void* buf, int len) { - DWORD read_bytes; - - if (!ReadFile(f->fh_handle, buf, (DWORD) len, &read_bytes, NULL)) { - D( "sdb_read: could not read %d bytes from %s\n", len, f->name); - errno = EIO; - return -1; - } else if (read_bytes < (DWORD) len) { - f->eof = 1; - } - return (int) read_bytes; -} +static int _sdb_open(const char* path, int file_options) { -static int _fh_file_write(FH f, const void* buf, int len) { - DWORD wrote_bytes; + DWORD access_mode = 0; + DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE; - if (!WriteFile(f->fh_handle, buf, (DWORD) len, &wrote_bytes, NULL)) { - D( "sdb_file_write: could not write %d bytes from %s\n", len, f->name); - errno = EIO; - return -1; - } else if (wrote_bytes < (DWORD) len) { - f->eof = 1; + if(file_options == O_RDONLY) { + access_mode = GENERIC_READ; } - return (int) wrote_bytes; -} - -static int _fh_file_lseek(FH f, int pos, int origin) { - DWORD method; - DWORD result; - - switch (origin) { - case SEEK_SET: - method = FILE_BEGIN; - break; - case SEEK_CUR: - method = FILE_CURRENT; - break; - case SEEK_END: - method = FILE_END; - break; - default: - errno = EINVAL; - return -1; + else if(file_options == O_WRONLY) { + access_mode = GENERIC_WRITE; } - - result = SetFilePointer(f->fh_handle, pos, NULL, method); - if (result == INVALID_SET_FILE_POINTER) { - errno = EIO; - return -1; - } else { - f->eof = 0; + else if(file_options == O_RDWR) { + access_mode = GENERIC_READ | GENERIC_WRITE; } - return (int) result; -} - -static void _fh_file_hook(FH f, int event, EventHook eventhook); /* forward */ - -static const FHClassRec _fh_file_class = { _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read, _fh_file_write, - _fh_file_hook }; - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** file-based descriptor handling *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -static int _sdb_open(const char* path, int options) { - FH f; - - DWORD desiredAccess = 0; - DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - - switch (options) { - case O_RDONLY: - desiredAccess = GENERIC_READ; - break; - case O_WRONLY: - desiredAccess = GENERIC_WRITE; - break; - case O_RDWR: - desiredAccess = GENERIC_READ | GENERIC_WRITE; - break; - default: - D("sdb_open: invalid options (0x%0x)\n", options); + else { + LOG_ERROR("invalid options (0x%0x)\n", file_options); errno = EINVAL; return -1; } - f = _fh_alloc(&_fh_file_class); - if (!f) { + SDB_HANDLE* _h; + _h = alloc_handle(0); + if (!_h) { errno = ENOMEM; return -1; } - f->fh_handle = CreateFile(path, desiredAccess, shareMode, NULL, OPEN_EXISTING, 0, NULL); - - if (f->fh_handle == INVALID_HANDLE_VALUE) { - _fh_close(f); - D( "sdb_open: could not open '%s':", path); - switch (GetLastError()) { - case ERROR_FILE_NOT_FOUND: - D( "file not found\n"); - errno = ENOENT; - return -1; - - case ERROR_PATH_NOT_FOUND: - D( "path not found\n"); - errno = ENOTDIR; - return -1; - - default: - D( "unknown error\n"); - errno = ENOENT; - return -1; - } - } - - snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path); - D( "sdb_open: '%s' => fd %d\n", path, _fh_to_int(f)); - return _fh_to_int(f); -} - -static int _sdb_open_mode(const char* path, int options, int mode) { - return sdb_open(path, options); -} + _h->u.file_handle = CreateFile(path, access_mode, share_mode, NULL, OPEN_EXISTING, 0, NULL); -static int _unix_open(const char* path, int options, ...) { - if ((options & O_CREAT) == 0) { - return open(path, options); - } else { - int mode; - va_list args; - va_start( args, options); - mode = va_arg( args, int ); - va_end( args); - return open(path, options, mode); + if(check_file_err(_h->u.file_handle) == -1) { + return -1; } + return _h->fd; } -/* ignore mode on Win32 */ static int _sdb_creat(const char* path, int mode) { - FH f; + SDB_HANDLE* _h = alloc_handle(0); - f = _fh_alloc(&_fh_file_class); - if (!f) { - errno = ENOMEM; + if (!_h) { + errno = ENOMEM; return -1; } - - f->fh_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, + _h->u.file_handle = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (f->fh_handle == INVALID_HANDLE_VALUE) { - _fh_close(f); - D( "sdb_creat: could not open '%s':", path); - switch (GetLastError()) { - case ERROR_FILE_NOT_FOUND: - D( "file not found\n"); - errno = ENOENT; - return -1; - - case ERROR_PATH_NOT_FOUND: - D( "path not found\n"); - errno = ENOTDIR; - return -1; - - default: - D( "unknown error\n"); - errno = ENOENT; - return -1; - } + if(check_file_err(_h->u.file_handle) == -1) { + return -1; } - snprintf(f->name, sizeof(f->name), "%d(%s)", _fh_to_int(f), path); - D( "sdb_creat: '%s' => fd %d\n", path, _fh_to_int(f)); - return _fh_to_int(f); + return _h->fd; } -static int _sdb_read(int fd, void* buf, size_t len) { - FH f = _fh_from_int(fd); +static int _sdb_read(int fd, void* buffer, size_t r_length) { + SDB_HANDLE* _h = sdb_handle_map_get(fd); - if (f == NULL) { - return -1; + if (_h == NULL) { + LOG_ERROR("FD(%d) disconnected\n", fd); + return 0; } - return f->clazz->_fh_read(f, buf, len); -} - -static int _sdb_write(int fd, const void* buf, size_t len) { - FH f = _fh_from_int(fd); - - if (f == NULL) { - return -1; + if(IS_SOCKET_HANDLE(_h)) { + return check_socket_err(recv(_h->u.socket, buffer, r_length, 0)); } + else { + DWORD r_bytes; - return f->clazz->_fh_write(f, buf, len); + if (!ReadFile(_h->u.file_handle, buffer, (DWORD) r_length, &r_bytes, NULL)) { + D( "sdb_read: could not read %d bytes from FD(%d)\n", r_length, _h->fd); + errno = EIO; + return -1; + } + return (int) r_bytes; + } } -static int _sdb_lseek(int fd, int pos, int where) { - FH f = _fh_from_int(fd); +static int _sdb_write(int fd, const void* buffer, size_t w_length) { + SDB_HANDLE* _h = sdb_handle_map_get(fd); - if (!f) { - return -1; + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists. disconnected\n", fd); + return 0; } - return f->clazz->_fh_lseek(f, pos, where); + if(IS_SOCKET_HANDLE(_h)) { + return check_socket_err(send(_h->u.socket, buffer, w_length, 0)); + } + else { + DWORD w_bytes; + + if (!WriteFile(_h->u.file_handle, buffer, (DWORD) w_length, &w_bytes, NULL)) { + D( "sdb_file_write: could not write %d bytes from FD(%d)\n", w_length, _h->fd); + errno = EIO; + return -1; + } + return (int) w_bytes; + } } static int _sdb_shutdown(int fd) { - FH f = _fh_from_int(fd); - if (!f) { + if(!IS_SOCKET_FD(fd)) { + LOG_ERROR("FD(%d) is file fd\n", fd); + return -1; + } + + SDB_HANDLE* _h = sdb_handle_map_get(fd); + + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists\n", fd); return -1; } - D( "sdb_shutdown: %s\n", f->name); - shutdown(f->fh_socket, SD_BOTH); + D( "sdb_shutdown: FD(%d)\n", fd); + shutdown(_h->u.socket, SD_BOTH); return 0; } static int _sdb_close(int fd) { - FH f = _fh_from_int(fd); - if (!f) { + SDB_HANDLE* _h = sdb_handle_map_get(fd); + + if (_h == NULL) { + LOG_ERROR("FD(%d) not exists\n", fd); return -1; } - D( "sdb_close: %s\n", f->name); - _fh_close(f); + D( "sdb_close: FD(%d)\n", fd); + _fh_close(_h); return 0; } -static int _sdb_unlink(const char* path) { - int rc = unlink(path); - - if (rc == -1 && errno == EACCES) { - /* unlink returns EACCES when the file is read-only, so we first */ - /* try to make it writable, then unlink again... */ - rc = chmod(path, _S_IREAD | _S_IWRITE); - if (rc == 0) - rc = unlink(path); - } - return rc; -} - static int _sdb_mkdir(const char* path, int mode) { return _mkdir(path); } @@ -555,146 +572,30 @@ static char* _sdb_dirstop(const char* path) { return p; } -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** socket-based file descriptors *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -static void _socket_set_errno(void) { - switch (WSAGetLastError()) { - case 0: - errno = 0; - break; - case WSAEWOULDBLOCK: - errno = EAGAIN; - break; - case WSAEINTR: - errno = EINTR; - break; - default: - D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError()); - errno = EINVAL; - } -} - -static void _fh_socket_init(FH f) { - f->fh_socket = INVALID_SOCKET; - f->event = WSACreateEvent(); - f->mask = 0; -} - -static int _fh_socket_close(FH f) { - /* gently tell any peer that we're closing the socket */ - shutdown(f->fh_socket, SD_BOTH); - closesocket(f->fh_socket); - f->fh_socket = INVALID_SOCKET; - CloseHandle(f->event); - f->mask = 0; - return 0; -} - -static int _fh_socket_lseek(FH f, int pos, int origin) { - errno = EPIPE; - return -1; -} - -static int _fh_socket_read(FH f, void* buf, int len) { - int result = recv(f->fh_socket, buf, len, 0); - if (result == SOCKET_ERROR) { - _socket_set_errno(); - result = -1; - } - return result; -} - -static int _fh_socket_write(FH f, const void* buf, int len) { - int result = send(f->fh_socket, buf, len, 0); - if (result == SOCKET_ERROR) { - _socket_set_errno(); - result = -1; - } - return result; -} - -static void _fh_socket_hook(FH f, int event, EventHook hook); /* forward */ - -static const FHClassRec _fh_socket_class = { _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read, - _fh_socket_write, _fh_socket_hook }; - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** replacement for libs/cutils/socket_xxxx.c *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -#include - static int _winsock_init; -static void _cleanup_winsock(void) { +static void _cleanup_winsock() { WSACleanup(); } static void _init_winsock(void) { if (!_winsock_init) { WSADATA wsaData; - int rc = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (rc != 0) { - fatal("sdb: could not initialize Winsock\n"); + if(WSAStartup(MAKEWORD(2, 2), &wsaData)) { + LOG_FATAL("sdb: could not initialize Winsock\n"); } - atexit(_cleanup_winsock); _winsock_init = 1; + atexit(_cleanup_winsock); } } -static int _socket_loopback_client(int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); - struct sockaddr_in addr; - SOCKET s; - - if (!f) - return -1; - - if (!_winsock_init) - _init_winsock(); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - s = socket(AF_INET, type, 0); - if (s == INVALID_SOCKET) { - D("socket_loopback_client: could not create socket\n"); - _fh_close(f); - return -1; - } - - f->fh_socket = s; - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port); - _fh_close(f); - return -1; - } - snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); -} - -#define LISTEN_BACKLOG 4 - -static int _socket_loopback_server(int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); +static int _sdb_port_listen(uint32_t inet, int port, int type) { + SDB_HANDLE* _h = alloc_handle(1); struct sockaddr_in addr; SOCKET s; int n; - if (!f) { + if (_h == NULL) { return -1; } @@ -703,51 +604,51 @@ static int _socket_loopback_server(int port, int type) { memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(inet); addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - s = socket(AF_INET, type, 0); - if (s == INVALID_SOCKET) + if ((s = socket(AF_INET, type, 0)) == INVALID_SOCKET) { + LOG_ERROR("failed to create socket to %u(%d)\n", inet, port); return -1; + } - f->fh_socket = s; + _h->u.socket = s; n = 1; setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n)); if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + _fh_close(_h); return -1; } + // only listen if tcp mode if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - if (ret < 0) { - _fh_close(f); + if (listen(s, LISTEN_BACKLOG) < 0) { + _fh_close(_h); return -1; } } - snprintf(f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); + + D( "sdb_port_listen: port %d type %s => FD(%d)\n", port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd); + return _h->fd; } -static int _socket_network_client(const char *host, int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); +static int _sdb_host_connect(const char *host, int port, int type) { + SDB_HANDLE* _h = alloc_handle(1); struct hostent *hp; struct sockaddr_in addr; SOCKET s; - if (!f) + if (!_h) return -1; if (!_winsock_init) _init_winsock(); - hp = gethostbyname(host); - if (hp == 0) { - _fh_close(f); + // FIXME: might take a long time to get information + if ((hp = gethostbyname(host)) == NULL) { + LOG_ERROR("failed to get hostname:%s(%d)\n", host, port); + _fh_close(_h); return -1; } @@ -756,503 +657,167 @@ static int _socket_network_client(const char *host, int port, int type) { addr.sin_port = htons(port); memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); - s = socket(hp->h_addrtype, type, 0); - if (s == INVALID_SOCKET) { - _fh_close(f); + if ((s = socket(hp->h_addrtype, type, 0)) == INVALID_SOCKET) { + LOG_ERROR("failed to create socket to %s(%d)\n", host, port); + _fh_close(_h); return -1; } - f->fh_socket = s; + + _h->u.socket = s; if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + _fh_close(_h); return -1; } - snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( - "socket_network_client: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); + D("sdb_host_connect: host '%s' port %d type %s => FD(%d)\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _h->fd); + return _h->fd; } -static int _socket_inaddr_any_server(int port, int type) { - FH f = _fh_alloc(&_fh_socket_class); - struct sockaddr_in addr; - SOCKET s; - int n; +static int _sdb_socket_accept(int serverfd) { - if (!f) - return -1; + if(!IS_SOCKET_FD(serverfd)) { + LOG_ERROR("FD(%d) is file fd\n", serverfd); + return -1; + } - if (!_winsock_init) - _init_winsock(); + SDB_HANDLE* server_h = sdb_handle_map_get(serverfd); + struct sockaddr addr; + socklen_t alen = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - s = socket(AF_INET, type, 0); - if (s == INVALID_SOCKET) { - _fh_close(f); + if (!server_h) { + LOG_ERROR( "FD(%d) Invalid server fd\n", serverfd); return -1; } - f->fh_socket = s; - n = 1; - setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &n, sizeof(n)); - - if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + SDB_HANDLE* _h = alloc_handle(1); + if (!_h) { return -1; } - if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - if (ret < 0) { - _fh_close(f); - return -1; - } - } - snprintf(f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port); - D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f)); - return _fh_to_int(f); -} - -static int _sdb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { - FH serverfh = _fh_from_int(serverfd); - FH fh; - - if (!serverfh || serverfh->clazz != &_fh_socket_class) { - D( "sdb_socket_accept: invalid fd %d\n", serverfd); - return -1; - } - - fh = _fh_alloc(&_fh_socket_class); - if (!fh) { - D( "sdb_socket_accept: not enough memory to allocate accepted socket descriptor\n"); - return -1; - } - - fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen); - if (fh->fh_socket == INVALID_SOCKET) { - _fh_close(fh); - D( "sdb_socket_accept: accept on fd %d return error %ld\n", serverfd, GetLastError()); + _h->u.socket = accept(server_h->u.socket, &addr, &alen); + if (_h->u.socket == INVALID_SOCKET) { + _fh_close(_h); + LOG_ERROR( "sdb_socket_accept: accept on FD(%d) return error %ld\n", serverfd, GetLastError()); return -1; } - snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name); - D( "sdb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh)); - return _fh_to_int(fh); + LOG_INFO( "sdb_socket_accept on FD(%d) returns FD(%d)\n", serverfd, _h->fd); + return _h->fd; } static void _disable_tcp_nagle(int fd) { - FH fh = _fh_from_int(fd); - int on; - - if (!fh || fh->clazz != &_fh_socket_class) - return; - - setsockopt(fh->fh_socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)); -} - -/**************************************************************************/ -/**************************************************************************/ -/***** *****/ -/***** emulated socketpairs *****/ -/***** *****/ -/**************************************************************************/ -/**************************************************************************/ - -/* we implement socketpairs directly in use space for the following reasons: - * - it avoids copying data from/to the Nt kernel - * - it allows us to implement fdevent hooks easily and cheaply, something - * that is not possible with standard Win32 pipes !! - * - * basically, we use two circular buffers, each one corresponding to a given - * direction. - * - * each buffer is implemented as two regions: - * - * region A which is (a_start,a_end) - * region B which is (0, b_end) with b_end <= a_start - * - * an empty buffer has: a_start = a_end = b_end = 0 - * - * a_start is the pointer where we start reading data - * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE, - * then you start writing at b_end - * - * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE - * - * there is room when b_end < a_start || a_end < BUFER_SIZE - * - * when reading, a_start is incremented, it a_start meets a_end, then - * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on.. - */ - -#define BIP_BUFFER_SIZE 4096 - -#if 0 -#include -# define BIPD(x) D x -# define BIPDUMP bip_dump_hex -static void bip_dump_hex( const unsigned char* ptr, size_t len ) -{ - int nn, len2 = len; - - if (len2 > 8) len2 = 8; - - for (nn = 0; nn < len2; nn++) - printf("%02x", ptr[nn]); - printf(" "); - - for (nn = 0; nn < len2; nn++) { - int c = ptr[nn]; - if (c < 32 || c > 127) - c = '.'; - printf("%c", c); - } - printf("\n"); - fflush(stdout); -} + if(!IS_SOCKET_FD(fd)) { + LOG_ERROR("FD(%d) is file fd\n", fd); + return; + } -#else -# define BIPD(x) do {} while (0) -# define BIPDUMP(p,l) BIPD(p) -#endif - - -static void bip_buffer_init(BipBuffer buffer) { - D( "bit_buffer_init %p\n", buffer); - buffer->a_start = 0; - buffer->a_end = 0; - buffer->b_end = 0; - buffer->can_write = 1; - buffer->can_read = 0; - buffer->fdin = 0; - buffer->fdout = 0; - buffer->closed = 0; - buffer->evt_write = CreateEvent(NULL, TRUE, TRUE, NULL); - buffer->evt_read = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&buffer->lock); -} - -static void bip_buffer_close(BipBuffer bip) { - bip->closed = 1; - - if (!bip->can_read) { - SetEvent(bip->evt_read); - } - if (!bip->can_write) { - SetEvent(bip->evt_write); + SDB_HANDLE* _h = sdb_handle_map_get(fd); + if (!_h) { + return; } -} -static void bip_buffer_done(BipBuffer bip) { - BIPD(( "bip_buffer_done: %d->%d\n", bip->fdin, bip->fdout )); - CloseHandle(bip->evt_read); - CloseHandle(bip->evt_write); - DeleteCriticalSection(&bip->lock); + int on; + setsockopt(_h->u.socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &on, sizeof(on)); } -static int bip_buffer_write(BipBuffer bip, const void* src, int len) { - int avail, count = 0; - - if (len <= 0) - return 0; - - BIPD(( "bip_buffer_write: enter %d->%d len %d\n", bip->fdin, bip->fdout, len )); - BIPDUMP( src, len); - - EnterCriticalSection(&bip->lock); - - while (!bip->can_write) { - int ret; - LeaveCriticalSection(&bip->lock); - - if (bip->closed) { - errno = EPIPE; - return -1; - } - /* spinlocking here is probably unfair, but let's live with it */ - ret = WaitForSingleObject(bip->evt_write, INFINITE); - if (ret != WAIT_OBJECT_0) { /* buffer probably closed */ - D( - "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError()); - return 0; - } - if (bip->closed) { - errno = EPIPE; - return -1; - } - EnterCriticalSection(&bip->lock); - } - - BIPD(( "bip_buffer_write: exec %d->%d len %d\n", bip->fdin, bip->fdout, len )); - - avail = BIP_BUFFER_SIZE - bip->a_end; - if (avail > 0) { - /* we can append to region A */ - if (avail > len) - avail = len; +static int socketpair_impl(int af, int type, int protocol, SOCKET socks[2]) +{ + struct sockaddr_in addr; + SOCKET s; - memcpy(bip->buff + bip->a_end, src, avail); - src += avail; - count += avail; - len -= avail; + LOG_INFO("+socketpair impl in\n"); - bip->a_end += avail; - if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) { - bip->can_write = 0; - ResetEvent(bip->evt_write); - goto Exit; - } + if (!_winsock_init) { + _init_winsock(); } + // Create a socket, bind it to 127.0.0.1 and a random port, and listen. + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + addr.sin_port = 0; - if (len == 0) - goto Exit; - - avail = bip->a_start - bip->b_end; - assert( avail > 0); - /* since can_write is TRUE */ - - if (avail > len) - avail = len; - - memcpy(bip->buff + bip->b_end, src, avail); - count += avail; - bip->b_end += avail; + socks[0] = socks[1] = INVALID_SOCKET; - if (bip->b_end == bip->a_start) { - bip->can_write = 0; - ResetEvent(bip->evt_write); + if ((s = socket(af, type, 0)) == INVALID_SOCKET) { + return -1; } - Exit: - assert( count > 0); - - if (!bip->can_read) { - bip->can_read = 1; - SetEvent(bip->evt_read); + if (bind(s, (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { + closesocket(s); + return -1; } - BIPD( - ( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read )); - LeaveCriticalSection(&bip->lock); - - return count; -} - -static int bip_buffer_read(BipBuffer bip, void* dst, int len) { - int avail, count = 0; - - if (len <= 0) - return 0; - - BIPD(( "bip_buffer_read: enter %d->%d len %d\n", bip->fdin, bip->fdout, len )); - - EnterCriticalSection(&bip->lock); - while (!bip->can_read) { -#if 0 - LeaveCriticalSection( &bip->lock ); - errno = EAGAIN; + int addr_len = sizeof(addr); + if (getsockname(s, (struct sockaddr*) &addr, &addr_len) == SOCKET_ERROR) { + closesocket(s); return -1; -#else - int ret; - LeaveCriticalSection(&bip->lock); + } - if (bip->closed) { - errno = EPIPE; - return -1; + do + { + if (listen(s, 1) == SOCKET_ERROR) { + break; } - - ret = WaitForSingleObject(bip->evt_read, INFINITE); - if (ret != WAIT_OBJECT_0) { /* probably closed buffer */ - D( - "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld\n", bip->fdin, bip->fdout, ret, GetLastError()); - return 0; + // Creates the second socket and connects it to the same address and port. + if ((socks[0] = socket(af, type, 0)) == INVALID_SOCKET) { + break; } - if (bip->closed) { - errno = EPIPE; - return -1; + if (connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { + break; } - EnterCriticalSection(&bip->lock); -#endif - } - - BIPD(( "bip_buffer_read: exec %d->%d len %d\n", bip->fdin, bip->fdout, len )); - - avail = bip->a_end - bip->a_start; - assert( avail > 0); - /* since can_read is TRUE */ - - if (avail > len) - avail = len; - - memcpy(dst, bip->buff + bip->a_start, avail); - dst += avail; - count += avail; - len -= avail; - - bip->a_start += avail; - if (bip->a_start < bip->a_end) - goto Exit; - - bip->a_start = 0; - bip->a_end = bip->b_end; - bip->b_end = 0; - - avail = bip->a_end; - if (avail > 0) { - if (avail > len) - avail = len; - memcpy(dst, bip->buff, avail); - count += avail; - bip->a_start += avail; - - if (bip->a_start < bip->a_end) - goto Exit; - - bip->a_start = bip->a_end = 0; - } - - bip->can_read = 0; - ResetEvent(bip->evt_read); - - Exit: - assert( count > 0); - - if (!bip->can_write) { - bip->can_write = 1; - SetEvent(bip->evt_write); - } - - BIPDUMP( (const unsigned char*)dst - count, count); - BIPD( - ( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d\n", bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read )); - LeaveCriticalSection(&bip->lock); - - return count; -} - -typedef struct SocketPairRec_ { - BipBufferRec a2b_bip; - BipBufferRec b2a_bip; - FH a_fd; - int used; - -} SocketPairRec; - -void _fh_socketpair_init(FH f) { - f->fh_pair = NULL; -} - -static int _fh_socketpair_close(FH f) { - if (f->fh_pair) { - SocketPair pair = f->fh_pair; - - if (f == pair->a_fd) { - pair->a_fd = NULL; + if ((socks[1] = accept(s, NULL, NULL)) == INVALID_SOCKET) { + break; } + closesocket(s); + LOG_INFO("-socketpair impl out\n"); + return 0; - bip_buffer_close(&pair->b2a_bip); - bip_buffer_close(&pair->a2b_bip); + } while (0); - if (--pair->used == 0) { - bip_buffer_done(&pair->b2a_bip); - bip_buffer_done(&pair->a2b_bip); - free(pair); - } - f->fh_pair = NULL; - } - return 0; -} + closesocket(socks[0]); + closesocket(socks[1]); + closesocket(s); -static int _fh_socketpair_lseek(FH f, int pos, int origin) { - errno = ESPIPE; + LOG_ERROR("socketpair error: %ld\n", WSAGetLastError()); return -1; } -static int _fh_socketpair_read(FH f, void* buf, int len) { - SocketPair pair = f->fh_pair; - BipBuffer bip; +static int _sdb_socketpair(int sv[2]) { + SOCKET socks[2]; + int r = 0; - if (!pair) + r = socketpair_impl( AF_INET, SOCK_STREAM, IPPROTO_TCP, socks); + if (r < 0) { + LOG_ERROR("failed to create socket pair:(%ld)\n", GetLastError()); return -1; + } - if (f == pair->a_fd) - bip = &pair->b2a_bip; - else - bip = &pair->a2b_bip; - - return bip_buffer_read(bip, buf, len); -} - -static int _fh_socketpair_write(FH f, const void* buf, int len) { - SocketPair pair = f->fh_pair; - BipBuffer bip; + SDB_HANDLE* _ha = alloc_handle(1); + SDB_HANDLE* _hb = alloc_handle(1); - if (!pair) + if (!_ha || !_hb) { return -1; - - if (f == pair->a_fd) - bip = &pair->a2b_bip; - else - bip = &pair->b2a_bip; - - return bip_buffer_write(bip, buf, len); -} - -static void _fh_socketpair_hook(FH f, int event, EventHook hook); /* forward */ - -static const FHClassRec _fh_socketpair_class = { _fh_socketpair_init, _fh_socketpair_close, _fh_socketpair_lseek, - _fh_socketpair_read, _fh_socketpair_write, _fh_socketpair_hook }; - -static int _sdb_socketpair(int sv[2]) { - FH fa, fb; - SocketPair pair; - - fa = _fh_alloc(&_fh_socketpair_class); - fb = _fh_alloc(&_fh_socketpair_class); - - if (!fa || !fb) - goto Fail; - - pair = malloc(sizeof(*pair)); - if (pair == NULL) { - D("sdb_socketpair: not enough memory to allocate pipes\n"); - goto Fail; } - bip_buffer_init(&pair->a2b_bip); - bip_buffer_init(&pair->b2a_bip); + _ha->u.socket = socks[0]; + _hb->u.socket = socks[1]; - fa->fh_pair = pair; - fb->fh_pair = pair; - pair->used = 2; - pair->a_fd = fa; - - sv[0] = _fh_to_int(fa); - sv[1] = _fh_to_int(fb); - - pair->a2b_bip.fdin = sv[0]; - pair->a2b_bip.fdout = sv[1]; - pair->b2a_bip.fdin = sv[1]; - pair->b2a_bip.fdout = sv[0]; + if (_ha->u.socket == INVALID_SOCKET || _hb->u.socket == INVALID_SOCKET) { + _fh_close(_ha); + _fh_close(_hb); + LOG_ERROR( "failed to get socket:(%ld)\n", GetLastError()); + return -1; + } + sv[0] = _ha->fd; + sv[1] = _hb->fd; - snprintf(fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1]); - snprintf(fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0]); - D( "sdb_socketpair: returns (%d, %d)\n", sv[0], sv[1]); + D( "sdb_socketpair: returns (FD(%d), FD(%d))\n", sv[0], sv[1] ); return 0; - - Fail: _fh_close(fb); - _fh_close(fa); - return -1; } + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -1264,199 +829,18 @@ static int _sdb_socketpair(int sv[2]) { /**************************************************************************/ /**************************************************************************/ - -/** FILE EVENT HOOKS - **/ - -static void _event_file_prepare(EventHook hook) { - if (hook->wanted & (FDE_READ | FDE_WRITE)) { - /* we can always read/write */ - hook->ready |= hook->wanted & (FDE_READ | FDE_WRITE); - } -} - -static int _event_file_peek(EventHook hook) { - return (hook->wanted & (FDE_READ | FDE_WRITE)); -} - -static void _fh_file_hook(FH f, int events, EventHook hook) { - hook->h = f->fh_handle; - hook->prepare = _event_file_prepare; - hook->peek = _event_file_peek; -} - -/** SOCKET EVENT HOOKS - **/ - -static void _event_socket_verify(EventHook hook, WSANETWORKEVENTS* evts) { - if (evts->lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) { - if (hook->wanted & FDE_READ) - hook->ready |= FDE_READ; - if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR) - hook->ready |= FDE_ERROR; - } - if (evts->lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE)) { - if (hook->wanted & FDE_WRITE) - hook->ready |= FDE_WRITE; - if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR) - hook->ready |= FDE_ERROR; - } - if (evts->lNetworkEvents & FD_OOB) { - if (hook->wanted & FDE_ERROR) - hook->ready |= FDE_ERROR; - } -} - -static void _event_socket_prepare(EventHook hook) { - WSANETWORKEVENTS evts; - - /* look if some of the events we want already happened ? */ - if (!WSAEnumNetworkEvents(hook->fh->fh_socket, NULL, &evts)) - _event_socket_verify(hook, &evts); -} - -static int _socket_wanted_to_flags(int wanted) { - int flags = 0; - if (wanted & FDE_READ) - flags |= FD_READ | FD_ACCEPT | FD_CLOSE; - - if (wanted & FDE_WRITE) - flags |= FD_WRITE | FD_CONNECT | FD_CLOSE; - - if (wanted & FDE_ERROR) - flags |= FD_OOB; - - return flags; -} - -static int _event_socket_start(EventHook hook) { - /* create an event which we're going to wait for */ - FH fh = hook->fh; - long flags = _socket_wanted_to_flags(hook->wanted); - - hook->h = fh->event; - if (hook->h == INVALID_HANDLE_VALUE) { - D( "_event_socket_start: no event for %s\n", fh->name); - return 0; - } - - if (flags != fh->mask) { - D( "_event_socket_start: hooking %s for %x (flags %ld)\n", hook->fh->name, hook->wanted, flags); - if (WSAEventSelect(fh->fh_socket, hook->h, flags)) { - D( "_event_socket_start: WSAEventSelect() for %s failed, error %d\n", hook->fh->name, WSAGetLastError()); - CloseHandle(hook->h); - hook->h = INVALID_HANDLE_VALUE; - exit(1); - return 0; - } - fh->mask = flags; - } - return 1; -} - -static void _event_socket_stop(EventHook hook) { - hook->h = INVALID_HANDLE_VALUE; -} - -static int _event_socket_check(EventHook hook) { - int result = 0; - FH fh = hook->fh; - WSANETWORKEVENTS evts; - - if (!WSAEnumNetworkEvents(fh->fh_socket, hook->h, &evts)) { - _event_socket_verify(hook, &evts); - result = (hook->ready != 0); - if (result) { - ResetEvent(hook->h); - } - } - D( "_event_socket_check %s returns %d\n", fh->name, result); - return result; -} - -static int _event_socket_peek(EventHook hook) { - WSANETWORKEVENTS evts; - FH fh = hook->fh; - - /* look if some of the events we want already happened ? */ - if (!WSAEnumNetworkEvents(fh->fh_socket, NULL, &evts)) { - _event_socket_verify(hook, &evts); - if (hook->ready) - ResetEvent(hook->h); - } - - return hook->ready != 0; -} - -static void _fh_socket_hook(FH f, int events, EventHook hook) { - hook->prepare = _event_socket_prepare; - hook->start = _event_socket_start; - hook->stop = _event_socket_stop; - hook->check = _event_socket_check; - hook->peek = _event_socket_peek; - - _event_socket_start(hook); -} - -/** SOCKETPAIR EVENT HOOKS - **/ - -static void _event_socketpair_prepare(EventHook hook) { - FH fh = hook->fh; - SocketPair pair = fh->fh_pair; - BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip; - BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip; - - if (hook->wanted & FDE_READ && rbip->can_read) - hook->ready |= FDE_READ; - - if (hook->wanted & FDE_WRITE && wbip->can_write) - hook->ready |= FDE_WRITE; -} - -static int _event_socketpair_start(EventHook hook) { - FH fh = hook->fh; - SocketPair pair = fh->fh_pair; - BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip; - BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip; - - if (hook->wanted == FDE_READ) - hook->h = rbip->evt_read; - - else if (hook->wanted == FDE_WRITE) - hook->h = wbip->evt_write; - - else { - D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE\n"); - return 0; - } - D( "_event_socketpair_start: hook %s for %x wanted=%x\n", hook->fh->name, _fh_to_int(fh), hook->wanted); - return 1; -} - -static int _event_socketpair_peek(EventHook hook) { - _event_socketpair_prepare(hook); - return hook->ready != 0; -} - -static void _fh_socketpair_hook(FH fh, int events, EventHook hook) { - hook->prepare = _event_socketpair_prepare; - hook->start = _event_socketpair_start; - hook->peek = _event_socketpair_peek; -} - static void _sdb_sysdeps_init(void) { //re define mutex variable & initialized #undef SDB_MUTEX #define SDB_MUTEX(x) InitializeCriticalSection( & x ); SDB_MUTEX(dns_lock) - SDB_MUTEX(socket_list_lock) SDB_MUTEX(transport_lock) - SDB_MUTEX(local_transports_lock) SDB_MUTEX(usb_lock) SDB_MUTEX(wakeup_select_lock) SDB_MUTEX(D_lock) SDB_MUTEX(_win32_lock); + SDB_MUTEX(sdb_handle_map_lock); + SDB_MUTEX(free_socket_handle_list_lock); } typedef void (*win_thread_func_t)(void* arg); @@ -1610,16 +994,12 @@ const struct utils_os_backend utils_windows_backend = { .start_logging = _start_logging, .ansi_to_utf8 = _ansi_to_utf8, .sdb_open = _sdb_open, - .sdb_open_mode = _sdb_open_mode, - .unix_open = _unix_open, .sdb_creat = _sdb_creat, .sdb_read = _sdb_read, .sdb_write = _sdb_write, - .sdb_lseek = _sdb_lseek, .sdb_shutdown = _sdb_shutdown, .sdb_close = _sdb_close, .close_on_exec = _close_on_exec, - .sdb_unlink = _sdb_unlink, .sdb_mkdir = _sdb_mkdir, .sdb_socket_accept = _sdb_socket_accept, .sdb_socketpair = _sdb_socketpair, @@ -1636,8 +1016,6 @@ const struct utils_os_backend utils_windows_backend = { .sdb_cond_init = _pthread_cond_init, .sdb_cond_broadcast = _pthread_cond_broadcast, .sdb_sysdeps_init = _sdb_sysdeps_init, - .socket_loopback_client = _socket_loopback_client, - .socket_network_client = _socket_network_client, - .socket_loopback_server = _socket_loopback_server, - .socket_inaddr_any_server = _socket_inaddr_any_server + .sdb_host_connect = _sdb_host_connect, + .sdb_port_listen = _sdb_port_listen };