init
parent
08d6a8500a
commit
a9643ea85c
|
@ -0,0 +1,7 @@
|
|||
*~
|
||||
*.a
|
||||
*.core
|
||||
*.lo
|
||||
*.la
|
||||
*.o
|
||||
*.so
|
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
|
@ -0,0 +1,216 @@
|
|||
Main code of F-Stack is BSD 2-Clause licensed.
|
||||
Copyright (C) 2017 THL A29 Limited, a Tencent company.
|
||||
All rights reserved.
|
||||
|
||||
Other Dependencies:
|
||||
------------------------------------------------------------------------------
|
||||
This work contains some softwares from:
|
||||
DPDK(http://dpdk.org/),
|
||||
FreeBSD(https://www.freebsd.org/),
|
||||
Nginx(http://nginx.org),
|
||||
Redis(https://github.com/antirez/redis),
|
||||
Microthread framework(https://github.com/Tencent/MSEC/tree/master/spp_rpc/src/sync_frame/micro_thread).
|
||||
|
||||
This work uses some codes from:
|
||||
Libplebnet(https://gitorious.org/freebsd/kmm-sandbox/commit/fa8a11970bc0ed092692736f175925766bebf6af?p=freebsd:kmm-sandbox.git;a=tree;f=lib/libplebnet;h=ae446dba0b4f8593b69b339ea667e12d5b709cfb;hb=refs/heads/work/svn_trunk_libplebnet),
|
||||
Libuinet(https://github.com/pkelsey/libuinet),
|
||||
inih(https://github.com/benhoyt/inih).
|
||||
|
||||
1.DPDK
|
||||
|
||||
BSD 3-Clause, Copyright(c) 2010-2017 Intel Corporation.All rights reserved.
|
||||
|
||||
2.FreeBSD
|
||||
|
||||
BSD 2-Clause, Copyright 1992-2016 The FreeBSD Project. All rights reserved.
|
||||
|
||||
3.Libplebnet
|
||||
|
||||
BSD 2-Clause, Copyright (c) 2010-2011 Kip Macy.All rights reserved.
|
||||
|
||||
4.Libuinet
|
||||
|
||||
BSD 2-Clause, Copyright (c) 2015 Patrick Kelsey.All rights reserved.
|
||||
|
||||
5.inih(a simple .INI file parser)
|
||||
|
||||
BSD 3-Clause, Copyright (c) 2009, Ben Hoyt.All rights reserved.
|
||||
|
||||
6.Nginx
|
||||
|
||||
BSD 2-Clause, Copyright (C) 2002-2017 Igor Sysoev.
|
||||
Copyright (C) 2011-2017 Nginx, Inc.All rights reserved.
|
||||
|
||||
7.Redis
|
||||
|
||||
BSD 2-Clause, Copyright (c) 2006-2015, Salvatore Sanfilippo.All rights reserved.
|
||||
|
||||
8.Microthread framework
|
||||
|
||||
GPL-2.0, Copyright (C) 2016 THL A29 Limited, a Tencent company.All rights reserved.
|
||||
|
||||
|
||||
Terms of the BSD 2-Clause License:
|
||||
-----------------------------------------------------------------------------
|
||||
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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
|
||||
|
||||
|
||||
Terms of the BSD 3-Clause License:
|
||||
-----------------------------------------------------------------------------
|
||||
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. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
|
||||
|
||||
Terms of the GPL-2.0 License:
|
||||
-------------------------------------------------------------------------------
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 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.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, 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 or use pieces of it in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification follow.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's 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 give any other recipients of the Program a copy of this License along with the Program.
|
||||
|
||||
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 Program or any portion of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
|
||||
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, 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 Program, 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 Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) 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; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
|
||||
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, 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 executable. However, as a special exception, the source code 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.
|
||||
|
||||
If distribution of executable or 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 counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program 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.
|
||||
|
||||
5. 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 Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program 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 to this License.
|
||||
|
||||
7. 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 Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program 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 Program.
|
||||
|
||||
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.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program 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.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions of the 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 Program 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 Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 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 Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
One line to give the program's name and a brief idea of what it does.
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
|
||||
|
106
README.md
106
README.md
|
@ -1,2 +1,106 @@
|
|||
# F-Stack
|
||||
Since the F-Stack project involves a large number of third party code, there are many open source licenses, copyrights need to be reviewed. So, the project is closed temporarily, and when this work is completed, we will reopen the project before April 24th.
|
||||
![](F-Stack.png)
|
||||
|
||||
## Introduction
|
||||
With the rapid development of NIC, the poor performance of data packets processing with Linux kernel has become the bottleneck. However, the rapid development of the Internet needs high performance of network processing, kernel bypass has caught more and more attention. There are various similar technologies appear, such as DPDK, NETMAP and PF_RING. The main idea of kernel bypass is that Linux is only used to deal with control flow, all data streams are processed in user space. Therefore, kernel bypass can avoid performance bottlenecks caused by kernel packet copy, thread scheduling, system calls and interrupt. Furthermore, kernel bypass can achieve higher performance with multi optimizing methods. Within various techniques, DPDK has been widely used because of its more thorough isolation from kernel scheduling and active community support.
|
||||
|
||||
[F-Stack](http://www.f-stack.org/?from=github) is an open source network framework with high performance based on DPDK. With follow characteristics
|
||||
|
||||
1. Ultra high network performance which can achieve network card under full load, 10 million concurrent connection, 5 million RPS, 1 million CPS.
|
||||
2. Transplant FreeBSD 11.01 user space stack, provides a complete stack function, cut a great amount of irrelevant features. Therefore greatly enhance the performance.
|
||||
3. Support Nginx, Redis and other mature applications, service can easily use F-Stack
|
||||
4. With Multi-process architecture, easy to extend
|
||||
5. Provide micro thread interface. Various applications with stateful app can easily use F-Stack to get high performance without processing complex asynchronous logic.
|
||||
6. Provide Epoll/Kqueue interface that allow many kinds of applications easily use F-Stack
|
||||
|
||||
## History
|
||||
|
||||
In order to deal with the increasingly severe DDoS attacks, authorized DNS server of Tencent Cloud DNSPod switched from Gigabit Ethernet to 10-Gigabit at the end of 2012. We faced several options, one is to continue to use the original model another is to use kernel bypass technology. After several rounds of investigation, we finally chose to develop our next generation of DNS server based on DPDK. The reason is DPDK provides ultra-high performance and can be seamlessly extended to 40G, or even 100G NIC in the future.
|
||||
|
||||
After several months of development and testing, DKDNS, high-performance DNS server based on DPDK officially released in October 2013. It's capable of achieving up to 11 million QPS with a single 10GE port and 18.2 million QPS with two 10GE ports. And then we developed a user-space TCP/IP stack called F-Stack that can process 0.6 million RPS with a single 10GE port.
|
||||
|
||||
With the fast growth of Tencent Cloud, more and more services need higher network access performance. Meanwhile, F-Stack was continuous improving driven by the business growth, and ultimately developed into a general network access framework. But this TCP/IP stack couldn't meet the needs of these services while continue to develop and maintain a complete network stack will cost high, we've tried several plans and finally determined to port FreeBSD(11.0 stable) TCP/IP stack into F-Stack. Thus, we can reduce the cost of maintenance and follow up the improvement from community quickly.Thanks to [libplebnet](https://gitorious.org/freebsd/kmm-sandbox/commit/fa8a11970bc0ed092692736f175925766bebf6af?p=freebsd:kmm-sandbox.git;a=tree;f=lib/libplebnet;h=ae446dba0b4f8593b69b339ea667e12d5b709cfb;hb=refs/heads/work/svn_trunk_libplebnet) and [libuinet](https://github.com/pkelsey/libuinet), this work becomes a lot easier.
|
||||
|
||||
With the rapid development of all kinds of application, in order to help different APPs quick and easily use F-Stack, F-Stack has integrated Nginx, Redis and other commonly used APPs, and a micro thread framework, and provides a standard Epoll/Kqueue interface.
|
||||
|
||||
Currently, besides authorized DNS server of DNSPod, there are various products in Tencent Cloud has used the F-Stack, such as HttpDNS (D+), COS access module, CDN access module, etc..
|
||||
|
||||
## Quick Start
|
||||
|
||||
#clone F-Stack
|
||||
mkdir /data/f-stack
|
||||
git clone https://github.com/F-Stack/f-stack.git /data/f-stack
|
||||
|
||||
cd f-stack
|
||||
# compile DPDK
|
||||
cd dpdk/tools
|
||||
./dpdk-setup.sh # compile with x86_64-native-linuxapp-gcc
|
||||
|
||||
# Set hugepage
|
||||
# single-node system
|
||||
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
|
||||
|
||||
# or NUMA
|
||||
echo 1024 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
|
||||
echo 1024 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages
|
||||
|
||||
# Using Hugepage with the DPDK
|
||||
mkdir /mnt/huge
|
||||
mount -t hugetlbfs nodev /mnt/huge
|
||||
|
||||
# offload NIC
|
||||
modprobe uio
|
||||
insmod /data/f-stack/dpdk/x86_64-native-linuxapp-gcc/build/kmod/igb_uio.ko
|
||||
insmod /data/f-stack/dpdk/x86_64-native-linuxapp-gcc/build/kmod/rte_kni.ko
|
||||
python dpdk-devbind.py --status
|
||||
ifconfig eth0 down
|
||||
python dpdk-devbind.py --bind=igb_uio eth0 # assuming that use 10GE NIC and eth0
|
||||
|
||||
# Compile F-Stack
|
||||
cd ../../lib/
|
||||
make
|
||||
export FF_PATH=/data/f-stack
|
||||
export FF_DPDK=/data/f-stack/dpdk/x86_64-native-linuxapp-gcc/lib
|
||||
|
||||
#### Nginx
|
||||
|
||||
cd app/nginx-1.11.10
|
||||
./configure --prefix=/usr/local/nginx_fstack --with-ff_module
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
./start.sh -b /usr/local/nginx_fstack/sbin/nginx -c config.ini
|
||||
|
||||
#### Redis
|
||||
|
||||
cd app/redis-3.2.8/
|
||||
make
|
||||
make install
|
||||
|
||||
|
||||
## Nginx Testing Result
|
||||
|
||||
Test environment
|
||||
|
||||
NIC:Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+
|
||||
CPU:Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
|
||||
Memory:128G
|
||||
OS:CentOS Linux release 7.2 (Final)
|
||||
Kernel:3.10.104-1-tlinux2-0041.tl2
|
||||
|
||||
Nginx uses linux kernel's default config, all soft interrupts are working in the first CPU core.
|
||||
|
||||
Nginx si means modify the smp_affinity of every IRQ, so that the decision to service an interrupt with a particular CPU is made at the hardware level, with no intervention from the kernel.
|
||||
|
||||
|
||||
CPS (Connection:close, Small data packet) test result
|
||||
![](http://i.imgur.com/PvCRmXR.png)
|
||||
|
||||
RPS (Connection:Keep-Alive, Small data packet) test data
|
||||
![](http://i.imgur.com/CTDPx3a.png)
|
||||
|
||||
Bandwidth (Connection:Keep-Alive, 3.7k bytes data packet) test data
|
||||
![](http://i.imgur.com/1ZM6yT9.png)
|
||||
|
||||
## Licenses
|
||||
See [LICENSE](LICENSE)
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
#
|
||||
# Tencent is pleased to support the open source community by making MSEC available.
|
||||
#
|
||||
# Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#
|
||||
# Licensed under the GNU General Public 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
|
||||
#
|
||||
# https://opensource.org/licenses/GPL-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.
|
||||
#
|
||||
|
||||
|
||||
########MAKEFILE##########
|
||||
|
||||
ifeq ($(FF_PATH),)
|
||||
$(error variable FF_PATH is not set)
|
||||
endif
|
||||
|
||||
DEBUG= -g
|
||||
BINARY = libmt.a
|
||||
FF_LIB=$(FF_PATH)/libfstack.a
|
||||
DPDK_LIBS = $(shell pkg-config --define-variable=TOPDIR=${FF_PATH} --libs f-stack.pc)
|
||||
|
||||
# Comment the following line if you are not using the gnu c compiler
|
||||
#C_ARGS = -Wall -g -fPIC -D_DEBUG
|
||||
C_ARGS = -Wall -g -fPIC -O0 -DMT_REAL_TIME
|
||||
#.SUFFIXES: .o .cpp
|
||||
|
||||
ifeq ($(ARCH),32)
|
||||
C_ARGS += -march=pentium4 -m32 -DSUS_LINUX -pthread
|
||||
else
|
||||
C_ARGS += -m64 -DSUS_LINUX -pthread
|
||||
endif
|
||||
# You might have to change this if your c compiler is not cc
|
||||
CC = g++
|
||||
|
||||
# You shouldn't need to make any more changes below this line.
|
||||
INCCOMM=-I./valgrind -I$(FF_PATH)/lib
|
||||
|
||||
#.c.o:
|
||||
# $(CC) -c $*.c
|
||||
|
||||
all: $(BINARY)
|
||||
|
||||
### shell color config
|
||||
RED = \\e[1m\\e[31m
|
||||
DARKRED = \\e[31m
|
||||
GREEN = \\e[1m\\e[32m
|
||||
DARKGREEN = \\e[32m
|
||||
BLUE = \\e[1m\\e[34m
|
||||
DARKBLUE = \\e[34m
|
||||
YELLOW = \\e[1m\\e[33m
|
||||
DARKYELLOW = \\e[33m
|
||||
MAGENTA = \\e[1m\\e[35m
|
||||
DARKMAGENTA = \\e[35m
|
||||
CYAN = \\e[1m\\e[36m
|
||||
DARKCYAN = \\e[36m
|
||||
RESET = \\e[m
|
||||
CRESET = ;echo -ne \\e[m; test -s $@
|
||||
|
||||
%.o: %.cpp
|
||||
@echo -e Compiling $(GREEN)$<$(RESET) ...$(RED)
|
||||
@$(CC) $(C_ARGS) -c -o $@ $< $(INCCOMM) $(CRESET)
|
||||
|
||||
%.o: %.c
|
||||
@echo -e Compiling $(GREEN)$<$(RESET) ...$(RED)
|
||||
@$(CC) $(C_ARGS) -c -o $@ $< $(INCCOMM) $(CRESET)
|
||||
|
||||
%.o: %.S
|
||||
@echo -e Compiling $(GREEN)$<$(RESET) ...$(RED)
|
||||
@$(CC) $(C_ARGS) -c -o $@ $< $(INCCOMM) $(CRESET)
|
||||
|
||||
clean:
|
||||
@rm -f $(BINARY) *.a *.o echo
|
||||
|
||||
|
||||
LIB_OBJ = micro_thread.o kqueue_proxy.o arch_ctx.o mt_session.o mt_notify.o mt_action.o mt_mbuf_pool.o mt_api.o\
|
||||
mt_connection.o mt_concurrent.o mt_sys_hook.o ff_hook.o heap_timer.o mt_cache.o mt_net.o
|
||||
|
||||
libmt.a: $(LIB_OBJ)
|
||||
@echo -e Linking $(CYAN)$@$(RESET) ...$(RED)
|
||||
@-rm -f $@
|
||||
@ar crs $@ $^ $(FST_LIB) $(CRESET)
|
||||
@chmod +x $@
|
||||
|
||||
echo: echo.o libmt.a
|
||||
@echo -e Compile $(CYAN)$@$(RESET) ...$(RED)
|
||||
@$(CC) -O -gdwarf-2 -o $@ $^ -lstdc++ -ldl -lm $(DPDK_LIBS) $(CRESET)
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
#
|
||||
# context x86 or x86_64 save and restore
|
||||
#
|
||||
# x86_64 x86
|
||||
# 0 %rbx %ebx
|
||||
# 1 %rsp %esp
|
||||
# 2 %rbp %ebp
|
||||
# 3 %r12 %esi
|
||||
# 4 %r13 %edi
|
||||
# 5 %r14 %eip
|
||||
# 6 %r15
|
||||
# 7 %rip
|
||||
|
||||
|
||||
|
||||
#if defined(__amd64__) || defined(__x86_64__)
|
||||
|
||||
##
|
||||
# @brief save_context
|
||||
##
|
||||
.text
|
||||
.align 4
|
||||
.globl save_context
|
||||
.type save_context, @function
|
||||
save_context:
|
||||
pop %rsi
|
||||
xorl %eax,%eax
|
||||
movq %rbx,(%rdi)
|
||||
movq %rsp,8(%rdi)
|
||||
push %rsi
|
||||
movq %rbp,16(%rdi)
|
||||
movq %r12,24(%rdi)
|
||||
movq %r13,32(%rdi)
|
||||
movq %r14,40(%rdi)
|
||||
movq %r15,48(%rdi)
|
||||
movq %rsi,56(%rdi)
|
||||
ret
|
||||
|
||||
.size save_context,.-save_context
|
||||
|
||||
##
|
||||
# @brief restore_context
|
||||
##
|
||||
.text
|
||||
.align 4
|
||||
.globl restore_context
|
||||
.type restore_context, @function
|
||||
restore_context:
|
||||
movl %esi,%eax
|
||||
movq (%rdi),%rbx
|
||||
movq 8(%rdi),%rsp
|
||||
movq 16(%rdi),%rbp
|
||||
movq 24(%rdi),%r12
|
||||
movq 32(%rdi),%r13
|
||||
movq 40(%rdi),%r14
|
||||
movq 48(%rdi),%r15
|
||||
jmp *56(%rdi)
|
||||
|
||||
.size restore_context,.-restore_context
|
||||
|
||||
##
|
||||
# @brief replace_esp
|
||||
##
|
||||
.text
|
||||
.align 4
|
||||
.globl replace_esp
|
||||
.type replace_esp, @function
|
||||
replace_esp:
|
||||
movq %rsi,8(%rdi)
|
||||
ret
|
||||
|
||||
.size replace_esp,.-replace_esp
|
||||
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
##
|
||||
# @brief save_context
|
||||
##
|
||||
.text
|
||||
.align 4
|
||||
.globl save_context
|
||||
.type save_context, @function
|
||||
save_context:
|
||||
movl 4(%esp),%edx
|
||||
popl %ecx
|
||||
xorl %eax,%eax
|
||||
movl %ebx,(%edx)
|
||||
movl %esp,4(%edx)
|
||||
pushl %ecx
|
||||
movl %ebp,8(%edx)
|
||||
movl %esi,12(%edx)
|
||||
movl %edi,16(%edx)
|
||||
movl %ecx,20(%edx)
|
||||
ret
|
||||
|
||||
.size save_context,.-save_context
|
||||
|
||||
|
||||
##
|
||||
# @brief restore_context
|
||||
##
|
||||
.text
|
||||
.align 4
|
||||
.globl restore_context
|
||||
.type restore_context, @function
|
||||
restore_context:
|
||||
movl 4(%esp),%edx
|
||||
movl 8(%esp),%eax
|
||||
movl (%edx),%ebx
|
||||
movl 4(%edx),%esp
|
||||
movl 8(%edx),%ebp
|
||||
movl 12(%edx),%esi
|
||||
movl 16(%edx),%edi
|
||||
jmp *20(%edx)
|
||||
|
||||
.size restore_context,.-restore_context
|
||||
|
||||
##
|
||||
# @brief replace_esp
|
||||
##
|
||||
.text
|
||||
.align 4
|
||||
.globl replace_esp
|
||||
.type replace_esp, @function
|
||||
replace_esp:
|
||||
movl 4(%esp),%edx
|
||||
movl 8(%esp),%eax
|
||||
movl %eax,4(%edx)
|
||||
ret
|
||||
|
||||
.size replace_esp,.-replace_esp
|
||||
|
||||
|
||||
#else
|
||||
#error "Linux cpu arch not supported"
|
||||
#endif
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mt_incl.h"
|
||||
#include "micro_thread.h"
|
||||
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
int set_fd_nonblock(int fd)
|
||||
{
|
||||
int nonblock = 1;
|
||||
return ioctl(fd, FIONBIO, &nonblock);
|
||||
}
|
||||
|
||||
int create_tcp_sock()
|
||||
{
|
||||
int fd;
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "create tcp socket failed, error: %m\n");
|
||||
return -1;
|
||||
}
|
||||
if (set_fd_nonblock(fd) == -1) {
|
||||
fprintf(stderr, "set tcp socket nonblock failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void echo(void *arg)
|
||||
{
|
||||
int ret;
|
||||
int *p = (int *)arg;
|
||||
int clt_fd = *p;
|
||||
delete p;
|
||||
char buf[64 * 1024];
|
||||
while (true) {
|
||||
ret = mt_recv(clt_fd, (void *)buf, 64 * 1024, 0, -1);
|
||||
if (ret < 0) {
|
||||
printf("recv from client error\n");
|
||||
break;
|
||||
}
|
||||
ret = mt_send(clt_fd, (void *)buf, ret, 0, 1000);
|
||||
if (ret < 0) {
|
||||
//printf("send data to client error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(clt_fd);
|
||||
}
|
||||
|
||||
int echo_server()
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(80);
|
||||
|
||||
int fd = create_tcp_sock();
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "create listen socket failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
close(fd);
|
||||
fprintf(stderr, "bind failed [%m]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(fd, 1024) < 0) {
|
||||
close(fd);
|
||||
fprintf(stderr, "listen failed [%m]\n");
|
||||
return -1;
|
||||
}
|
||||
int clt_fd = 0;
|
||||
int *p;
|
||||
while (true) {
|
||||
struct sockaddr_in client_addr;
|
||||
int addr_len = sizeof(client_addr);
|
||||
|
||||
clt_fd = mt_accept(fd, (struct sockaddr*)&client_addr, (socklen_t*)&addr_len, -1);
|
||||
if (clt_fd < 0) {
|
||||
mt_sleep(1);
|
||||
continue;
|
||||
}
|
||||
if (set_fd_nonblock(clt_fd) == -1) {
|
||||
fprintf(stderr, "set clt_fd nonblock failed [%m]\n");
|
||||
break;
|
||||
}
|
||||
|
||||
p = new int(clt_fd);
|
||||
mt_start_thread((void *)echo, (void *)p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
mt_init_frame("./config.ini", argc, argv);
|
||||
echo_server();
|
||||
}
|
|
@ -0,0 +1,561 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename epoll_proxy.cpp
|
||||
* @info epoll for micro thread manage
|
||||
*/
|
||||
|
||||
#include "epoll_proxy.h"
|
||||
#include "micro_thread.h"
|
||||
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
EpollProxy::EpollProxy()
|
||||
{
|
||||
_maxfd = EpollProxy::DEFAULT_MAX_FD_NUM;
|
||||
_epfd = -1;
|
||||
_evtlist = NULL;
|
||||
_eprefs = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief epoll初始化, 申请动态内存等
|
||||
*/
|
||||
int EpollProxy::InitEpoll(int max_num)
|
||||
{
|
||||
int rc = 0;
|
||||
if (max_num > _maxfd) // 如果设置的数目较大, 则调整最大fd数目
|
||||
{
|
||||
_maxfd = max_num;
|
||||
}
|
||||
|
||||
_epfd = epoll_create(_maxfd);
|
||||
if (_epfd < 0)
|
||||
{
|
||||
rc = -1;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
fcntl(_epfd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
_eprefs = new FdRef[_maxfd];
|
||||
if (NULL == _eprefs)
|
||||
{
|
||||
rc = -2;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
_evtlist = (EpEvent*)calloc(_maxfd, sizeof(EpEvent));
|
||||
if (NULL == _evtlist)
|
||||
{
|
||||
rc = -3;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
struct rlimit rlim;
|
||||
memset(&rlim, 0, sizeof(rlim));
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
|
||||
{
|
||||
if ((int)rlim.rlim_max < _maxfd)
|
||||
{
|
||||
rlim.rlim_cur = rlim.rlim_max;
|
||||
setrlimit(RLIMIT_NOFILE, &rlim);
|
||||
rlim.rlim_cur = _maxfd;
|
||||
rlim.rlim_max = _maxfd;
|
||||
setrlimit(RLIMIT_NOFILE, &rlim);
|
||||
}
|
||||
}
|
||||
|
||||
EXIT_LABEL:
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
TermEpoll();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief epoll反初始化
|
||||
*/
|
||||
void EpollProxy::TermEpoll()
|
||||
{
|
||||
if (_epfd > 0)
|
||||
{
|
||||
close(_epfd);
|
||||
_epfd = -1;
|
||||
}
|
||||
|
||||
if (_evtlist != NULL)
|
||||
{
|
||||
free(_evtlist);
|
||||
_evtlist = NULL;
|
||||
}
|
||||
|
||||
if (_eprefs != NULL)
|
||||
{
|
||||
delete []_eprefs;
|
||||
_eprefs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将一个微线程侦听的所有socket送入epoll管理
|
||||
* @param fdset 微线程侦听的socket集合
|
||||
* @return true 成功, false 失败, 失败会尽力回滚, 减少影响
|
||||
*/
|
||||
bool EpollProxy::EpollAdd(EpObjList& obj_list)
|
||||
{
|
||||
bool ret = true;
|
||||
EpollerObj *epobj = NULL;
|
||||
EpollerObj *epobj_error = NULL;
|
||||
TAILQ_FOREACH(epobj, &obj_list, _entry)
|
||||
{
|
||||
if (!EpollAddObj(epobj))
|
||||
{
|
||||
MTLOG_ERROR("epobj add failed, fd: %d", epobj->GetOsfd());
|
||||
epoll_assert(0);
|
||||
epobj_error = epobj;
|
||||
ret = false;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
}
|
||||
|
||||
EXIT_LABEL:
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
TAILQ_FOREACH(epobj, &obj_list, _entry)
|
||||
{
|
||||
if (epobj == epobj_error)
|
||||
{
|
||||
break;
|
||||
}
|
||||
EpollDelObj(epobj);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将一个微线程侦听的所有socket移除epoll管理
|
||||
* @param fdset 微线程侦听的socket集合
|
||||
* @return true 成功, false 失败
|
||||
*/
|
||||
bool EpollProxy::EpollDel(EpObjList& obj_list)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
EpollerObj *epobj = NULL;
|
||||
TAILQ_FOREACH(epobj, &obj_list, _entry)
|
||||
{
|
||||
if (!EpollDelObj(epobj)) // failed also need continue, be sure ref count ok
|
||||
{
|
||||
MTLOG_ERROR("epobj del failed, fd: %d", epobj->GetOsfd());
|
||||
epoll_assert(0);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 单个epfd更新epctrl, 成功需要更新当前监听事件值
|
||||
*/
|
||||
bool EpollProxy::EpollCtrlAdd(int fd, int events)
|
||||
{
|
||||
FdRef* item = FdRefGet(fd);
|
||||
if (NULL == item)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("epfd ref not find, failed, fd: %d", fd);
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新引用计数, 部分流程会依赖该计数, 失败要回滚
|
||||
item->AttachEvents(events);
|
||||
|
||||
int old_events = item->GetListenEvents();
|
||||
int new_events = old_events | events;
|
||||
if (old_events == new_events) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
|
||||
EpEvent ev;
|
||||
ev.events = new_events;
|
||||
ev.data.fd = fd;
|
||||
if ((epoll_ctl(_epfd, op, fd, &ev) < 0) && !(op == EPOLL_CTL_ADD && errno == EEXIST))
|
||||
{
|
||||
MT_ATTR_API(320850, 1); // epoll error
|
||||
MTLOG_ERROR("epoll ctrl failed, fd: %d, op: %d, errno: %d", fd, op, errno);
|
||||
item->DetachEvents(events);
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
item->SetListenEvents(new_events);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 单个epfd更新epctrl, 成功需要更新当前监听事件值
|
||||
*/
|
||||
bool EpollProxy::EpollCtrlDel(int fd, int events)
|
||||
{
|
||||
return EpollCtrlDelRef(fd, events, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 单个epfd更新epctrl, 检查引用计数, 可以预设长连接, 不会每次都epollctl
|
||||
*/
|
||||
bool EpollProxy::EpollCtrlDelRef(int fd, int events, bool use_ref)
|
||||
{
|
||||
FdRef* item = FdRefGet(fd);
|
||||
if (NULL == item)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("epfd ref not find, failed, fd: %d", fd);
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
item->DetachEvents(events); // delete 失败不回滚处理
|
||||
int old_events = item->GetListenEvents();
|
||||
int new_events = old_events &~ events; // 默认情况
|
||||
|
||||
// 如果要按引用删除, 需要核查是否满足删除条件
|
||||
if (use_ref)
|
||||
{
|
||||
new_events = old_events;
|
||||
if (0 == item->ReadRefCnt()) {
|
||||
new_events = new_events & ~EPOLLIN;
|
||||
}
|
||||
if (0 == item->WriteRefCnt()) {
|
||||
new_events = new_events & ~EPOLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_events == new_events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int op = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
|
||||
EpEvent ev;
|
||||
ev.events = new_events;
|
||||
ev.data.fd = fd;
|
||||
if ((epoll_ctl(_epfd, op, fd, &ev) < 0) && !(op == EPOLL_CTL_DEL && errno == ENOENT))
|
||||
{
|
||||
MT_ATTR_API(320850, 1); // epoll error
|
||||
MTLOG_ERROR("epoll ctrl failed, fd: %d, op: %d, errno: %d", fd, op, errno);
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
item->SetListenEvents(new_events);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 单个epfd更新epctrl, 如果失败, 完整回退
|
||||
*/
|
||||
bool EpollProxy::EpollAddObj(EpollerObj* obj)
|
||||
{
|
||||
if (NULL == obj)
|
||||
{
|
||||
MTLOG_ERROR("epobj input invalid, %p", obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
FdRef* item = FdRefGet(obj->GetOsfd());
|
||||
if (NULL == item)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("epfd ref not find, failed, fd: %d", obj->GetOsfd());
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 不同的回调状态, 不同的方式处理 del 事件, 屏蔽连接复用方式的处理复杂性
|
||||
int ret = obj->EpollCtlAdd(item);
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_ERROR("epoll ctrl callback failed, fd: %d, obj: %p", obj->GetOsfd(), obj);
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将一个微线程侦听的所有socket移除epoll管理
|
||||
* @param fdset 微线程侦听的socket集合
|
||||
* @return true 成功, false 失败
|
||||
*/
|
||||
bool EpollProxy::EpollDelObj(EpollerObj* obj)
|
||||
{
|
||||
if (NULL == obj)
|
||||
{
|
||||
MTLOG_ERROR("fdobj input invalid, %p", obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
FdRef* item = FdRefGet(obj->GetOsfd());
|
||||
if (NULL == item)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("epfd ref not find, failed, fd: %d", obj->GetOsfd());
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 不同的回调状态, 不同的方式处理 del 事件, 屏蔽连接复用方式的处理复杂性
|
||||
int ret = obj->EpollCtlDel(item);
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_ERROR("epoll ctrl callback failed, fd: %d, obj: %p", obj->GetOsfd(), obj);
|
||||
epoll_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 更新每个socket的最新接收事件信息
|
||||
* @param evtfdnum 收到事件的fd集合数目
|
||||
*/
|
||||
void EpollProxy::EpollRcvEventList(int evtfdnum)
|
||||
{
|
||||
int ret = 0;
|
||||
int osfd = 0;
|
||||
int revents = 0;
|
||||
FdRef* item = NULL;
|
||||
EpollerObj* obj = NULL;
|
||||
|
||||
for (int i = 0; i < evtfdnum; i++)
|
||||
{
|
||||
osfd = _evtlist[i].data.fd;
|
||||
item = FdRefGet(osfd);
|
||||
if (NULL == item)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("epfd ref not find, failed, fd: %d", osfd);
|
||||
epoll_assert(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
revents = _evtlist[i].events;
|
||||
obj = item->GetNotifyObj();
|
||||
if (NULL == obj)
|
||||
{
|
||||
MTLOG_ERROR("fd notify obj null, failed, fd: %d", osfd);
|
||||
EpollCtrlDel(osfd, (revents & (EPOLLIN | EPOLLOUT)));
|
||||
continue;
|
||||
}
|
||||
obj->SetRcvEvents(revents);
|
||||
|
||||
// 1. 错误处理, 完毕后直接跳出
|
||||
if (revents & (EPOLLERR | EPOLLHUP))
|
||||
{
|
||||
obj->HangupNotify();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. 可读事件, 非0返回值会跳出
|
||||
if (revents & EPOLLIN) {
|
||||
ret = obj->InputNotify();
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 可写事件, 非0返回值会跳出
|
||||
if (revents & EPOLLOUT) {
|
||||
ret = obj->OutputNotify();
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief epoll_wait 以及分发处理过程
|
||||
*/
|
||||
void EpollProxy::EpollDispath()
|
||||
{
|
||||
int wait_time = EpollGetTimeout();
|
||||
int nfd = epoll_wait(_epfd, _evtlist, _maxfd, wait_time);
|
||||
if (nfd <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
EpollRcvEventList(nfd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
int EpollerObj::InputNotify()
|
||||
{
|
||||
MicroThread* thread = this->GetOwnerThread();
|
||||
if (NULL == thread)
|
||||
{
|
||||
epoll_assert(0);
|
||||
MTLOG_ERROR("Epoll fd obj, no thread ptr, wrong");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 多个事件同时到达, 防重复操作
|
||||
if (thread->HasFlag(MicroThread::IO_LIST))
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->RemoveIoWait(thread);
|
||||
frame->InsertRunable(thread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
int EpollerObj::OutputNotify()
|
||||
{
|
||||
MicroThread* thread = this->GetOwnerThread();
|
||||
if (NULL == thread)
|
||||
{
|
||||
epoll_assert(0);
|
||||
MTLOG_ERROR("Epoll fd obj, no thread ptr, wrong");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 多个事件同时到达, 防重复操作
|
||||
if (thread->HasFlag(MicroThread::IO_LIST))
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->RemoveIoWait(thread);
|
||||
frame->InsertRunable(thread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口, 关闭fd侦听, thread等待处理超时
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
int EpollerObj::HangupNotify()
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->EpollCtrlDel(this->GetOsfd(), this->GetEvents());
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
int EpollerObj::EpollCtlAdd(void* args)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
FdRef* fd_ref = (FdRef*)args;
|
||||
epoll_assert(fd_ref != NULL);
|
||||
|
||||
int osfd = this->GetOsfd();
|
||||
int new_events = this->GetEvents();
|
||||
|
||||
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
|
||||
EpollerObj* old_obj = fd_ref->GetNotifyObj();
|
||||
if ((old_obj != NULL) && (old_obj != this))
|
||||
{
|
||||
MTLOG_ERROR("epfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
|
||||
return -1;
|
||||
}
|
||||
fd_ref->SetNotifyObj(this);
|
||||
|
||||
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
|
||||
if (!frame->EpollCtrlAdd(osfd, new_events))
|
||||
{
|
||||
MTLOG_ERROR("epfd ref add failed, log");
|
||||
fd_ref->SetNotifyObj(old_obj);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
int EpollerObj::EpollCtlDel(void* args)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
FdRef* fd_ref = (FdRef*)args;
|
||||
epoll_assert(fd_ref != NULL);
|
||||
|
||||
int osfd = this->GetOsfd();
|
||||
int events = this->GetEvents();
|
||||
|
||||
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
|
||||
EpollerObj* old_obj = fd_ref->GetNotifyObj();
|
||||
if (old_obj != this)
|
||||
{
|
||||
MTLOG_ERROR("epfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
|
||||
return -1;
|
||||
}
|
||||
fd_ref->SetNotifyObj(NULL);
|
||||
|
||||
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
|
||||
if (!frame->EpollCtrlDelRef(osfd, events, false)) // 引用有风险, 弊大于利, 关闭掉
|
||||
{
|
||||
MTLOG_ERROR("epfd ref del failed, log");
|
||||
fd_ref->SetNotifyObj(old_obj);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,434 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename epoll_proxy.h
|
||||
* @info epoll for micro thread manage
|
||||
*/
|
||||
|
||||
#ifndef _EPOLL_PROXY___
|
||||
#define _EPOLL_PROXY___
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
using std::set;
|
||||
using std::vector;
|
||||
|
||||
#define epoll_assert(statement)
|
||||
//#define epoll_assert(statement) assert(statement)
|
||||
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 操作系统头文件适配定义 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief add more detail for linux <sys/queue.h>, freebsd and University of California
|
||||
* @info queue.h version 8.3 (suse) diff version 8.5 (tlinux)
|
||||
*/
|
||||
#ifndef TAILQ_CONCAT
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) \
|
||||
do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TAILQ_FOREACH_SAFE // tlinux no this define
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* Epoll proxy 定义与实现部分 */
|
||||
/******************************************************************************/
|
||||
|
||||
class EpollProxy;
|
||||
class MicroThread;
|
||||
|
||||
/**
|
||||
* @brief epoll通知对象基类定义
|
||||
*/
|
||||
class EpollerObj
|
||||
{
|
||||
protected:
|
||||
int _fd; ///< 系统FD 或 socket
|
||||
int _events; ///< 监听的事件类型
|
||||
int _revents; ///< 收到的事件类型
|
||||
int _type; ///< 工厂类别定义
|
||||
MicroThread* _thread; ///< 关联线程指针对象
|
||||
|
||||
public:
|
||||
|
||||
TAILQ_ENTRY(EpollerObj) _entry; ///< 关联微线程的管理入口
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
explicit EpollerObj(int fd = -1) {
|
||||
_fd = fd;
|
||||
_events = 0;
|
||||
_revents = 0;
|
||||
_type = 0;
|
||||
_thread = NULL;
|
||||
};
|
||||
virtual ~EpollerObj(){};
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int InputNotify();
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int OutputNotify();
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
virtual int HangupNotify();
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int EpollCtlAdd(void* args);
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int EpollCtlDel(void* args);
|
||||
|
||||
/**
|
||||
* @brief fd打开可读事件侦听
|
||||
*/
|
||||
void EnableInput() { _events |= EPOLLIN; };
|
||||
|
||||
/**
|
||||
* @brief fd打开可写事件侦听
|
||||
*/
|
||||
void EnableOutput() { _events |= EPOLLOUT; };
|
||||
|
||||
/**
|
||||
* @brief fd关闭可读事件侦听
|
||||
*/
|
||||
void DisableInput() { _events &= ~EPOLLIN; };
|
||||
|
||||
/**
|
||||
* @brief fd关闭可写事件侦听
|
||||
*/
|
||||
void DisableOutput() { _events &= ~EPOLLOUT; };
|
||||
|
||||
/**
|
||||
* @brief 系统socket设置读取封装
|
||||
*/
|
||||
int GetOsfd() { return _fd; };
|
||||
void SetOsfd(int fd) { _fd = fd; };
|
||||
|
||||
/**
|
||||
* @brief 监听事件与收到事件的访问方法
|
||||
*/
|
||||
int GetEvents() { return _events; };
|
||||
void SetRcvEvents(int revents) { _revents = revents; };
|
||||
int GetRcvEvents() { return _revents; };
|
||||
|
||||
/**
|
||||
* @brief 工厂管理方法, 获取真实类型
|
||||
*/
|
||||
int GetNtfyType() { return _type; };
|
||||
virtual void Reset() {
|
||||
_fd = -1;
|
||||
_events = 0;
|
||||
_revents = 0;
|
||||
_type = 0;
|
||||
_thread = NULL;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置与获取所属的微线程句柄接口
|
||||
* @param thread 关联的线程指针
|
||||
*/
|
||||
void SetOwnerThread(MicroThread* thread) { _thread = thread; };
|
||||
MicroThread* GetOwnerThread() { return _thread; };
|
||||
|
||||
};
|
||||
|
||||
typedef TAILQ_HEAD(__EpFdList, EpollerObj) EpObjList; ///< 高效的双链管理
|
||||
typedef struct epoll_event EpEvent; ///< 重定义一下epoll event
|
||||
|
||||
|
||||
/**
|
||||
* @brief EPOLL支持同一FD多个线程侦听, 建立一个引用计数数组, 元素定义
|
||||
* @info 引用计数弊大于利, 没有实际意义, 字段保留, 功能移除掉 20150623
|
||||
*/
|
||||
class FdRef
|
||||
{
|
||||
private:
|
||||
int _wr_ref; ///< 监听写的引用计数
|
||||
int _rd_ref; ///< 监听读的引用计数
|
||||
int _events; ///< 当前正在侦听的事件列表
|
||||
int _revents; ///< 当前该fd收到的事件信息, 仅在epoll_wait后处理中有效
|
||||
EpollerObj* _epobj; ///< 单独注册调度器对象,一个fd关联一个对象
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
FdRef() {
|
||||
_wr_ref = 0;
|
||||
_rd_ref = 0;
|
||||
_events = 0;
|
||||
_revents = 0;
|
||||
_epobj = NULL;
|
||||
};
|
||||
~FdRef(){};
|
||||
|
||||
/**
|
||||
* @brief 监听事件获取与设置接口
|
||||
*/
|
||||
void SetListenEvents(int events) {
|
||||
_events = events;
|
||||
};
|
||||
int GetListenEvents() {
|
||||
return _events;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 监听对象获取与设置接口
|
||||
*/
|
||||
void SetNotifyObj(EpollerObj* ntfy) {
|
||||
_epobj = ntfy;
|
||||
};
|
||||
EpollerObj* GetNotifyObj() {
|
||||
return _epobj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 监听引用计数的更新
|
||||
*/
|
||||
void AttachEvents(int event) {
|
||||
if (event & EPOLLIN) {
|
||||
_rd_ref++;
|
||||
}
|
||||
if (event & EPOLLOUT){
|
||||
_wr_ref++;
|
||||
}
|
||||
};
|
||||
void DetachEvents(int event) {
|
||||
if (event & EPOLLIN) {
|
||||
if (_rd_ref > 0) {
|
||||
_rd_ref--;
|
||||
} else {
|
||||
_rd_ref = 0;
|
||||
}
|
||||
}
|
||||
if (event & EPOLLOUT){
|
||||
if (_wr_ref > 0) {
|
||||
_wr_ref--;
|
||||
} else {
|
||||
_wr_ref = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取引用计数
|
||||
*/
|
||||
int ReadRefCnt() { return _rd_ref; };
|
||||
int WriteRefCnt() { return _wr_ref; };
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief EPOLL代理, 封装epoll操作与epoll全局数据
|
||||
*/
|
||||
class EpollProxy
|
||||
{
|
||||
public:
|
||||
static const int DEFAULT_MAX_FD_NUM = 100000; ///< 默认最大监控的fd
|
||||
|
||||
private:
|
||||
int _epfd; ///< epoll 主句柄
|
||||
int _maxfd; ///< 最大的文件句柄数
|
||||
EpEvent* _evtlist; ///< epoll返回给用户的事件列表指针
|
||||
FdRef* _eprefs; ///< 用户监听的事件本地管理数组
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
EpollProxy();
|
||||
virtual ~EpollProxy(){};
|
||||
|
||||
/**
|
||||
* @brief epoll初始化与终止处理, 申请动态内存等
|
||||
* @param max_num 最大可管理的fd数目
|
||||
*/
|
||||
int InitEpoll(int max_num);
|
||||
void TermEpoll(void);
|
||||
|
||||
/**
|
||||
* @brief epoll_wait 获取最大等待时间接口
|
||||
* @return 目前需要等待的时间, 单位MS
|
||||
*/
|
||||
virtual int EpollGetTimeout(void) { return 0;};
|
||||
|
||||
/**
|
||||
* @brief epoll 触发调度接口
|
||||
* @param fdlist 多路并发请求, 所有发送的socket集合
|
||||
* @param fd 单个socket, 触发等待
|
||||
* @param timeout 超时时间设置, 毫秒
|
||||
* @return true 成功, false 失败
|
||||
*/
|
||||
virtual bool EpollSchedule(EpObjList* fdlist, EpollerObj* fd, int timeout) { return false;};
|
||||
|
||||
/**
|
||||
* @brief 将一个微线程侦听的所有socket送入epoll管理
|
||||
* @param fdset 微线程侦听的socket集合
|
||||
* @return true 成功, false 失败
|
||||
*/
|
||||
bool EpollAdd(EpObjList& fdset);
|
||||
|
||||
/**
|
||||
* @brief 将一个微线程侦听的所有socket移除epoll管理
|
||||
* @param fdset 微线程侦听的socket集合
|
||||
* @return true 成功, false 失败
|
||||
*/
|
||||
bool EpollDel(EpObjList& fdset);
|
||||
|
||||
/**
|
||||
* @brief epoll_wait 以及分发处理过程
|
||||
*/
|
||||
void EpollDispath(void);
|
||||
|
||||
/**
|
||||
* @brief 单独一个fd注册, 关联侦听事件
|
||||
* @param fd 文件句柄与事件信息
|
||||
* @param obj epoll回调对象
|
||||
*/
|
||||
bool EpollAddObj(EpollerObj* obj);
|
||||
|
||||
/**
|
||||
* @brief 取消一个fd注册, 关联侦听事件
|
||||
* @param fd 文件句柄与事件信息
|
||||
* @param obj epoll回调对象
|
||||
*/
|
||||
bool EpollDelObj(EpollerObj* obj);
|
||||
|
||||
/**
|
||||
* @brief 封装epoll ctl的处理与当前监听事件的记录, 内部接口
|
||||
* @param fd 操作的文件句柄
|
||||
* @param new_events 需要新增的监听事件
|
||||
*/
|
||||
bool EpollCtrlAdd(int fd, int new_events);
|
||||
|
||||
/**
|
||||
* @brief 封装epoll ctl的处理与当前监听事件的记录, 内部接口
|
||||
* @param fd 操作的文件句柄
|
||||
* @param new_events 需要新删除的监听事件
|
||||
*/
|
||||
bool EpollCtrlDel(int fd, int new_events);
|
||||
bool EpollCtrlDelRef(int fd, int new_events, bool use_ref);
|
||||
|
||||
/**
|
||||
* @brief 根据fd获取本地引用的结构, 按fd生成策略, 目前简单管理
|
||||
* @param fd 文件描述符
|
||||
* @return 本地文件引用结构, NULL 表示失败
|
||||
*/
|
||||
FdRef* FdRefGet(int fd) {
|
||||
return ((fd >= _maxfd) || (fd < 0)) ? (FdRef*)NULL : &_eprefs[fd];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 单独的注册接口, 用于注册或取消注册通知对象
|
||||
* @param fd 操作的文件句柄
|
||||
* @param obj 待注册或取消注册的对象
|
||||
*/
|
||||
void EpollNtfyReg(int fd, EpollerObj* obj) {
|
||||
FdRef* ref = FdRefGet(fd);
|
||||
if (ref) {
|
||||
ref->SetNotifyObj(obj);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief 更新每个socket的最新接收事件信息
|
||||
* @param evtfdnum 收到事件的fd集合数目
|
||||
*/
|
||||
void EpollRcvEventList(int evtfdnum);
|
||||
|
||||
};
|
||||
}//NAMESPCE
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
DPDK = ${TOPDIR}/dpdk/x86_64-native-linuxapp-gcc
|
||||
|
||||
Name: F-Stack
|
||||
Description: F-Stack pkg-config pc
|
||||
Version: 1.0
|
||||
Libs: -L${TOPDIR}/lib -Wl,--whole-archive,-lfstack,--no-whole-archive -Wl,--no-as-needed -fvisibility=default -pthread -lm -lrt -L${DPDK}/lib -Wl,--whole-archive -lrte_pmd_vmxnet3_uio -lrte_pmd_i40e -lrte_pmd_ixgbe -lrte_pmd_e1000 -lrte_pmd_ring -Wl,--whole-archive -lrte_hash -lrte_kvargs -Wl,-lrte_mbuf -lethdev -lrte_eal -Wl,-lrte_mempool -lrte_ring -lrte_cmdline -lrte_cfgfile -lrte_kni -lrte_timer -Wl,-lrte_pmd_virtio -Wl,--no-whole-archive -lrt -lm -ldl -lcrypto
|
||||
Cflags: -Wall -Werror -include ${DPDK}/include/rte_config.h -I${DPDK}/include -march=native -DRTE_MACHINE_CPUFLAG_SSE -DRTE_MACHINE_CPUFLAG_SSE2 -DRTE_MACHINE_CPUFLAG_SSE3 -DRTE_MACHINE_CPUFLAG_SSSE3 -DRTE_MACHINE_CPUFLAG_SSE4_1 -DRTE_MACHINE_CPUFLAG_SSE4_2 -DRTE_COMPILE_TIME_CPUFLAGS=RTE_CPUFLAG_SSE,RTE_CPUFLAG_SSE2,RTE_CPUFLAG_SSE3,RTE_CPUFLAG_SSSE3,RTE_CPUFLAG_SSE4_1,RTE_CPUFLAG_SSE4_2
|
|
@ -0,0 +1,222 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include "ff_api.h"
|
||||
#include "mt_sys_hook.h"
|
||||
#include "ff_hook.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void ff_hook_new_fd(int fd)
|
||||
{
|
||||
if (fd < 0 || fd >= ff_HOOK_MAX_FD) {
|
||||
return;
|
||||
}
|
||||
g_ff_hook_fd_tab[fd] = 1;
|
||||
}
|
||||
|
||||
bool ff_hook_find_fd(int fd) {
|
||||
if (fd < 0 || fd >= ff_HOOK_MAX_FD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_ff_hook_fd_tab[fd] == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ff_hook_free_fd(int fd)
|
||||
{
|
||||
if (fd < 0 || fd >= ff_HOOK_MAX_FD) {
|
||||
return;
|
||||
}
|
||||
g_ff_hook_fd_tab[fd] = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int ff_hook_socket(int domain, int type, int protocol)
|
||||
{
|
||||
if (!ff_hook_active() || (AF_INET != domain) || (SOCK_STREAM != type && SOCK_DGRAM != type)) {
|
||||
return mt_real_func(socket)(domain, type, protocol);
|
||||
}
|
||||
int fd = ff_socket(domain, type, protocol);
|
||||
if (fd >= 0) {
|
||||
fd |= 1 << FF_FD_BITS;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int ff_hook_close(int fd)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_close(fd);
|
||||
} else {
|
||||
return mt_real_func(close)(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_hook_connect(int fd, const struct sockaddr *address, socklen_t addrlen_len)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_connect(fd, (struct linux_sockaddr *)address, addrlen_len);
|
||||
} else {
|
||||
return mt_real_func(connect)(fd, address, addrlen_len);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t ff_hook_read(int fd, void *buf, size_t nbyte)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_read(fd, buf, nbyte);
|
||||
} else {
|
||||
return mt_real_func(read)(fd, buf, nbyte);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t ff_hook_write(int fd, const void *buf, size_t nbyte)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_write(fd, buf, nbyte);
|
||||
} else {
|
||||
return mt_real_func(write)(fd, buf, nbyte);
|
||||
}
|
||||
}
|
||||
ssize_t ff_hook_sendto(int fd, const void *message, size_t length, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t dest_len)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_sendto(fd, message, length, flags, (struct linux_sockaddr *)dest_addr, dest_len);
|
||||
} else {
|
||||
return mt_real_func(sendto)(fd, message, length, flags, dest_addr, dest_len);
|
||||
}
|
||||
}
|
||||
ssize_t ff_hook_recvfrom(int fd, void *buffer, size_t length, int flags,
|
||||
struct sockaddr *address, socklen_t *address_len)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_recvfrom(fd, buffer, length, flags, (struct linux_sockaddr *)address, address_len);
|
||||
} else {
|
||||
return mt_real_func(recvfrom)(fd, buffer, length, flags, address, address_len);
|
||||
}
|
||||
}
|
||||
ssize_t ff_hook_recv(int fd, void *buffer, size_t length, int flags)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_recv(fd, buffer, length, flags);
|
||||
} else {
|
||||
return mt_real_func(recv)(fd, buffer, length, flags);
|
||||
}
|
||||
}
|
||||
ssize_t ff_hook_send(int fd, const void *buf, size_t nbyte, int flags)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_send(fd, buf, nbyte, flags);
|
||||
} else {
|
||||
return mt_real_func(send)(fd, buf, nbyte, flags);
|
||||
}
|
||||
|
||||
}
|
||||
int ff_hook_setsockopt(int fd, int level, int option_name, const void *option_value, socklen_t option_len)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_setsockopt(fd, level, option_name, option_value, option_len);
|
||||
} else {
|
||||
return mt_real_func(setsockopt)(fd, level, option_name, option_value, option_len);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_hook_ioctl(int fd, int cmd, void *arg)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_ioctl(fd, cmd, arg);
|
||||
} else {
|
||||
return mt_real_func(ioctl)(fd, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_hook_fcntl(int fd, int cmd, void *arg)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_fcntl(fd, cmd, arg);
|
||||
} else {
|
||||
return mt_real_func(fcntl)(fd, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_hook_listen(int fd, int backlog)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_listen(fd, backlog);
|
||||
} else {
|
||||
return mt_real_func(listen)(fd, backlog);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_hook_bind(int fd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
return ff_bind(fd, (struct linux_sockaddr *)addr, addrlen);
|
||||
} else {
|
||||
return mt_real_func(bind)(fd, addr, addrlen);
|
||||
}
|
||||
}
|
||||
int ff_hook_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
int c = ff_accept(fd, (struct linux_sockaddr *)addr, addrlen);
|
||||
if (c < 0) {
|
||||
return c;
|
||||
}
|
||||
c |= 1 << FF_FD_BITS;
|
||||
return c;
|
||||
} else {
|
||||
return mt_real_func(accept)(fd, addr, addrlen);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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 __FF_HOOK_H__
|
||||
#define __FF_HOOK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FF_FD_BITS 16
|
||||
#define CHK_FD_BIT(fd) (fd & (1 << FF_FD_BITS))
|
||||
#define CLR_FD_BIT(fd) (fd & ~(1 << FF_FD_BITS))
|
||||
|
||||
void ff_hook_new_fd(int fd);
|
||||
bool ff_hook_find_fd(int fd);
|
||||
|
||||
void ff_hook_free_fd(int fd);
|
||||
int ff_hook_socket(int domain, int type, int protocol);
|
||||
int ff_hook_close(int fd);
|
||||
|
||||
int ff_hook_connect(int fd, const struct sockaddr *address, socklen_t addrlen_len);
|
||||
|
||||
ssize_t ff_hook_read(int fd, void *buf, size_t nbyte);
|
||||
|
||||
ssize_t ff_hook_write(int fd, const void *buf, size_t nbyte);
|
||||
ssize_t ff_hook_sendto(int fd, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
|
||||
ssize_t ff_hook_recvfrom(int fd, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len);
|
||||
ssize_t ff_hook_recv(int fd, void *buffer, size_t length, int flags);
|
||||
ssize_t ff_hook_send(int fd, const void *buf, size_t nbyte, int flags);
|
||||
int ff_hook_setsockopt(int fd, int level, int option_name, const void *option_value, socklen_t option_len);
|
||||
int ff_hook_ioctl(int fd, int cmd, void *arg);
|
||||
|
||||
int ff_hook_fcntl(int fd, int cmd, void *arg);
|
||||
|
||||
int ff_hook_listen(int fd, int backlog);
|
||||
|
||||
int ff_hook_bind(int fd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int ff_hook_accept(int fd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,290 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename hash_list.h
|
||||
* @info 开链hash类, 简单hash存储实现; 继承来实现hash映射, 注意插入元素的
|
||||
* 生命周期, 如栈变量等会自动析构的元素, 不要存放于此, 否则会坏链
|
||||
* @time 2013-06-11
|
||||
*/
|
||||
|
||||
#ifndef __HASH_LIST_FILE__
|
||||
#define __HASH_LIST_FILE__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
/**
|
||||
* @brief Hash存放元素的基类, 继承该元素即可实现扩展
|
||||
*/
|
||||
class HashKey
|
||||
{
|
||||
private:
|
||||
HashKey* _next_entry; ///< 开链hash的链接元素
|
||||
uint32_t _hash_value; ///< hash value信息, 节约比较的时间
|
||||
void* _data_ptr; ///< hash data数据指针, 可key - value 聚合存储
|
||||
|
||||
public:
|
||||
|
||||
friend class HashList; ///< hash表可以直接访问next指针
|
||||
|
||||
/**
|
||||
* @brief 构造与虚析构函数
|
||||
*/
|
||||
HashKey():_next_entry(NULL), _hash_value(0), _data_ptr(NULL) {};
|
||||
virtual ~HashKey(){};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的hash算法, 获取key的hash值
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual uint32_t HashValue() = 0;
|
||||
|
||||
/**
|
||||
* @brief 节点元素的cmp方法, 同一桶ID下, 按key比较
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual int HashCmp(HashKey* rhs) = 0;
|
||||
|
||||
/**
|
||||
* @brief 堆遍历接口, 用于调试, 在遍历每个元素时被调用, 可选实现
|
||||
*/
|
||||
virtual void HashIterate() {
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的实际数据指针设置与获取
|
||||
*/
|
||||
void* GetDataPtr() {
|
||||
return _data_ptr;
|
||||
};
|
||||
void SetDataPtr(void* data) {
|
||||
_data_ptr = data;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Hash管理类, 开链式hash, 注意选择合适的hash函数, 避免冲突过长
|
||||
*/
|
||||
class HashList
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造函数与析构函数
|
||||
*/
|
||||
explicit HashList(int max = 100000) {
|
||||
_max = GetMaxPrimeNum((max > 2) ? max : 100000);
|
||||
_buckets = (HashKey**)calloc(_max, sizeof(HashKey*));
|
||||
_count = 0;
|
||||
};
|
||||
virtual ~HashList() {
|
||||
if (_buckets) {
|
||||
free(_buckets);
|
||||
_buckets = NULL;
|
||||
}
|
||||
_count = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取hash的元素个数
|
||||
* @return 堆元素实际数目
|
||||
*/
|
||||
int HashSize() {
|
||||
return _count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief hash插入元素, 要在该元素析构前, 调用remove
|
||||
* @param key 待插入的元素指针, 注意元素的生命周期, 不要插入栈变量
|
||||
* @return 0 成功, -1 参数无效或未初始化, -2 重复插入或脏数据
|
||||
*/
|
||||
int HashInsert(HashKey* key) {
|
||||
if (!key || !_buckets) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((key->_hash_value != 0) || (key->_next_entry != NULL)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
key->_hash_value = key->HashValue();
|
||||
int idx = (key->_hash_value) % _max;
|
||||
|
||||
HashKey* next_item = _buckets[idx];
|
||||
_buckets[idx] = key;
|
||||
key->_next_entry = next_item;
|
||||
_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief hash查找元素
|
||||
* @param key 待查询的key指针
|
||||
* @return 查询结果对象指针, NULL表明无数据
|
||||
*/
|
||||
HashKey* HashFind(HashKey* key) {
|
||||
if (!key || !_buckets) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t hash = key->HashValue();
|
||||
int idx = hash % _max;
|
||||
HashKey* item = _buckets[idx];
|
||||
|
||||
for (; item != NULL; item = item->_next_entry) {
|
||||
if (item->_hash_value != hash) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->HashCmp(key) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief hash查找元素
|
||||
* @param key 待查询的key指针
|
||||
* @return 查询结果对象指针, NULL表明无数据
|
||||
*/
|
||||
void* HashFindData(HashKey* key) {
|
||||
HashKey* item = HashFind(key);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
} else {
|
||||
return item->_data_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief hash删除元素
|
||||
* @param key 待删除的key指针
|
||||
*/
|
||||
void HashRemove(HashKey* key) {
|
||||
if (!key || !_buckets) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t hash = key->HashValue();
|
||||
int idx = hash % _max;
|
||||
HashKey* item = _buckets[idx];
|
||||
HashKey* prev = NULL;
|
||||
|
||||
for (; item != NULL; prev = item, item = item->_next_entry) {
|
||||
if ((item->_hash_value == hash) && (item->HashCmp(key) == 0)){
|
||||
if (prev == NULL) {
|
||||
_buckets[idx] = item->_next_entry;
|
||||
} else {
|
||||
prev->_next_entry = item->_next_entry;
|
||||
}
|
||||
item->_hash_value = 0;
|
||||
item->_next_entry = NULL;
|
||||
_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief hash遍历元素, 调用迭代函数
|
||||
*/
|
||||
void HashForeach() {
|
||||
if (!_buckets) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _max; i++) {
|
||||
HashKey* item = _buckets[i];
|
||||
for (; item != NULL; item = item->_next_entry) {
|
||||
item->HashIterate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief hash清理遍历, 性能低下, 只用于最终遍历清理
|
||||
*/
|
||||
HashKey* HashGetFirst() {
|
||||
if (!_buckets) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _max; i++) {
|
||||
if (_buckets[i]) {
|
||||
return _buckets[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief 获取桶长度的最大质数
|
||||
*/
|
||||
int GetMaxPrimeNum(int num)
|
||||
{
|
||||
int sqrt_value = (int)sqrt(num);
|
||||
for (int i = num; i > 0; i--)
|
||||
{
|
||||
int flag = 1;
|
||||
for (int k = 2; k <= sqrt_value; k++)
|
||||
{
|
||||
if (i % k == 0)
|
||||
{
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag == 1)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
HashKey** _buckets; ///< 桶指针
|
||||
int _count; ///< 有效元素个数
|
||||
int _max; ///< 最大节点个数
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,441 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename heap.h
|
||||
* @info 灵活插入删除的堆, 如果是没有随机删除需求, 可以用std::make_heap
|
||||
* @time 2013-06-11
|
||||
*/
|
||||
|
||||
#ifndef __HEAP_ENTRY_FILE__
|
||||
#define __HEAP_ENTRY_FILE__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define heap_assert(statement)
|
||||
//#define heap_assert(statement) assert(statement)
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
class HeapEntry; // 堆元素类, 继承实现扩展
|
||||
class HeapList; // 堆管理类, 通用
|
||||
|
||||
/**
|
||||
* @brief 最小堆的堆元素定义, 用于构建通用的堆, 继承该元素即可扩展
|
||||
*/
|
||||
class HeapEntry
|
||||
{
|
||||
private:
|
||||
int _index; ///< 堆元素下标, 利于快速索引删除操作
|
||||
|
||||
public:
|
||||
friend class HeapList;
|
||||
|
||||
/**
|
||||
* @brief 构造与虚析构函数
|
||||
*/
|
||||
HeapEntry():_index(0){};
|
||||
virtual ~HeapEntry(){};
|
||||
|
||||
/**
|
||||
* @brief 堆元素取值函数, 用于返回值比较, 需子函数实现, 否则默认无序
|
||||
* @return 堆元素映射的值
|
||||
*/
|
||||
virtual unsigned long long HeapValue() = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 堆遍历接口, 用于调试, 在遍历每个元素时被调用, 可选实现
|
||||
*/
|
||||
virtual void HeapIterate() {
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 堆元素插入堆中
|
||||
* @param list 堆指针
|
||||
* @return 0 成功; 其它失败 -1 堆满; -2 重复插入
|
||||
*/
|
||||
inline int InsertIntoHeap(HeapList* list);
|
||||
|
||||
/**
|
||||
* @brief 堆元素从堆中删除
|
||||
* @param list 堆指针
|
||||
* @return 0 成功; 其它失败 -1 堆空; -2 重复删除或脏数据
|
||||
*/
|
||||
inline int DeleteFromHeap(HeapList* list);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 堆元素下标信息获取, 内部管理使用
|
||||
* @return 堆元素在堆中下标信息
|
||||
*/
|
||||
inline int GetIndex() {
|
||||
return _index;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
inline int HeapValueCmp(HeapEntry* rhs) {
|
||||
if (this->HeapValue() == rhs->HeapValue()) {
|
||||
return 0;
|
||||
} else if (this->HeapValue() > rhs->HeapValue()) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
inline void SetIndex(int index) {
|
||||
_index = index;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 最小堆队列类, 通用类
|
||||
*/
|
||||
class HeapList
|
||||
{
|
||||
private:
|
||||
HeapEntry** _list; // 堆元素的指针数组, 目前定长
|
||||
int _max; // 堆可管理最大元素个数
|
||||
int _count; // 堆已经管理的元素个数
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造函数与析构函数
|
||||
*/
|
||||
explicit HeapList(int max = 100000) {
|
||||
_max = (max > 0) ? max : 100000;
|
||||
_list = (HeapEntry**)malloc (sizeof(HeapEntry*) * (_max+1));
|
||||
heap_assert(_list);
|
||||
memset(_list, 0, sizeof(HeapEntry*) * (_max+1));
|
||||
_count = 0;
|
||||
};
|
||||
virtual ~HeapList() {
|
||||
if (_list) {
|
||||
free(_list);
|
||||
_list = NULL;
|
||||
}
|
||||
_max = 0;
|
||||
_count = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 扩展heap的大小, 缩小则忽略
|
||||
* @param size 新的堆元素个数
|
||||
* @return 0 成功; -1 失败
|
||||
*/
|
||||
int HeapResize(int size) {
|
||||
if (_max >= size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HeapEntry** new_list = (HeapEntry**)malloc(sizeof(HeapEntry*) * (size+1));
|
||||
if (NULL == new_list) {
|
||||
return -1;
|
||||
}
|
||||
memset(new_list, 0, sizeof(HeapEntry*) * (size+1));
|
||||
memcpy(new_list, _list, sizeof(HeapEntry*) * (_max+1));
|
||||
free(_list);
|
||||
_list = new_list;
|
||||
_max = size;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 插入堆元素
|
||||
* @param entry 堆元素指针
|
||||
* @return 0 成功; 其它失败 -1 堆满; -2 重复插入
|
||||
*/
|
||||
int HeapPush(HeapEntry* entry);
|
||||
|
||||
/**
|
||||
* @brief 取堆顶元素, 并移除该元素
|
||||
* @return 堆顶元素指针, NULL 表示堆为空
|
||||
*/
|
||||
HeapEntry* HeapPop();
|
||||
|
||||
/**
|
||||
* @brief 移除任意堆元素
|
||||
* @param entry 堆元素指针
|
||||
* @return 0 成功; 其它失败 -1 堆空; -2 重复删除或脏数据
|
||||
*/
|
||||
int HeapDelete(HeapEntry* entry);
|
||||
|
||||
/**
|
||||
* @brief 调试接口, 按2叉堆方式打印元素, 同时调用每元素的迭代接口
|
||||
*/
|
||||
void HeapForeach();
|
||||
|
||||
/**
|
||||
* @brief 获取堆的元素个数
|
||||
* @return 堆元素实际数目
|
||||
*/
|
||||
int HeapSize() {
|
||||
return _count;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 取堆顶元素, 不移除该元素
|
||||
* @return 堆顶元素指针, NULL 表示堆为空
|
||||
*/
|
||||
HeapEntry* HeapTop() {
|
||||
return (_count > 0) ? _list[1] : NULL;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief 判定堆是否满
|
||||
* @return true 满
|
||||
*/
|
||||
bool HeapFull() {
|
||||
return (_count >= _max);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 判定堆是否空
|
||||
* @return true 空
|
||||
*/
|
||||
bool HeapEmpty() {
|
||||
return (_count == 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 按比较函数, 向上重排堆元素
|
||||
*/
|
||||
void HeapUp();
|
||||
|
||||
/**
|
||||
* @brief 按比较函数, 向下重排堆元素
|
||||
*/
|
||||
void HeapDown(int index);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 按比较函数, 向上重排堆元素
|
||||
*/
|
||||
inline void HeapList::HeapUp()
|
||||
{
|
||||
for (int pos = _count; pos > 0; pos = pos/2)
|
||||
{
|
||||
if (pos/2 < 1) // pos == 1 已经到顶, 0 属于保留
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (_list[pos]->HeapValueCmp(_list[pos/2]) < 0)
|
||||
{
|
||||
HeapEntry* tmp = _list[pos/2];
|
||||
_list[pos/2] = _list[pos];
|
||||
_list[pos] = tmp;
|
||||
|
||||
_list[pos]->SetIndex(pos);
|
||||
_list[pos/2]->SetIndex(pos/2);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按比较函数, 向下重排堆元素
|
||||
* @param index 从该位置开始重排
|
||||
*/
|
||||
inline void HeapList::HeapDown(int index)
|
||||
{
|
||||
int min_son;
|
||||
for (int pos = index; pos <= _count; pos = min_son)
|
||||
{
|
||||
if (pos*2 > _count) // pos是叶子节点了
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (pos*2 == _count)
|
||||
{
|
||||
min_son = pos*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_list[pos*2+1]->HeapValueCmp(_list[pos*2]) < 0)
|
||||
{
|
||||
min_son = pos*2+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
min_son = pos*2;
|
||||
}
|
||||
}
|
||||
|
||||
if (_list[pos]->HeapValueCmp(_list[min_son]) > 0)
|
||||
{
|
||||
HeapEntry* tmp = _list[min_son];
|
||||
_list[min_son] = _list[pos];
|
||||
_list[pos] = tmp;
|
||||
|
||||
_list[pos]->SetIndex(pos);
|
||||
_list[min_son]->SetIndex(min_son);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 插入堆元素
|
||||
* @param entry 堆元素指针
|
||||
* @return 0 成功; 其它失败 -1 堆满; -2 重复插入
|
||||
*/
|
||||
inline int HeapList::HeapPush(HeapEntry* item)
|
||||
{
|
||||
if (HeapFull()) {
|
||||
heap_assert(0); // 满, 理论上是可能的, 实际运行不太可能过10W
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (item->GetIndex() != 0) {
|
||||
heap_assert(0); // 重复插入
|
||||
return -2;
|
||||
}
|
||||
|
||||
_count++;
|
||||
_list[_count] = item;
|
||||
item->SetIndex(_count);
|
||||
|
||||
HeapUp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 取堆顶元素, 并移除该元素
|
||||
* @return 堆顶元素指针, NULL 表示堆为空
|
||||
*/
|
||||
inline HeapEntry* HeapList::HeapPop()
|
||||
{
|
||||
if (HeapEmpty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HeapEntry* top = _list[1]; // 0 保留
|
||||
|
||||
_list[1] = _list[_count];
|
||||
_list[1]->SetIndex(1);
|
||||
_list[_count] = 0;
|
||||
|
||||
_count--;
|
||||
HeapDown(1);
|
||||
|
||||
heap_assert(top->GetIndex() == 1);
|
||||
top->SetIndex(0);
|
||||
return top;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除任意堆元素
|
||||
* @param entry 堆元素指针
|
||||
* @return 0 成功; 其它失败 -1 堆空; -2 重复删除或脏数据
|
||||
*/
|
||||
inline int HeapList::HeapDelete(HeapEntry* item)
|
||||
{
|
||||
if (HeapEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pos = item->GetIndex() ;
|
||||
if ((pos > _count) ||(pos <= 0))
|
||||
{
|
||||
heap_assert(0); // 非法数据或重复删除
|
||||
return -2;
|
||||
}
|
||||
|
||||
HeapEntry* del = _list[pos];
|
||||
_list[pos] = _list[_count];
|
||||
_list[pos]->SetIndex(pos);
|
||||
|
||||
_list[_count] = 0;
|
||||
_count--;
|
||||
|
||||
HeapDown(pos);
|
||||
heap_assert(pos == del->GetIndex());
|
||||
del->SetIndex(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 调试接口, 按2叉堆方式打印元素, 同时调用每元素的迭代接口
|
||||
*/
|
||||
inline void HeapList::HeapForeach()
|
||||
{
|
||||
int per = 1;
|
||||
for (int i = 1; i <= _count; i++)
|
||||
{
|
||||
if (i >= per*2)
|
||||
{
|
||||
printf("\n");
|
||||
per *=2;
|
||||
}
|
||||
printf("%llu ", _list[i]->HeapValue());
|
||||
|
||||
_list[i]->HeapIterate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 堆元素插入堆中
|
||||
* @param list 堆指针
|
||||
* @return 0 成功; 其它失败 -1 堆满; -2 重复插入
|
||||
*/
|
||||
inline int HeapEntry::InsertIntoHeap(HeapList* list) {
|
||||
return list->HeapPush(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 堆元素从堆中删除
|
||||
* @param list 堆指针
|
||||
* @return 0 成功; 其它失败 -1 堆空; -2 重复删除或脏数据
|
||||
*/
|
||||
inline int HeapEntry::DeleteFromHeap(HeapList* list) {
|
||||
return list->HeapDelete(this);
|
||||
};
|
||||
|
||||
} // namespace end
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file heap_timer.cpp
|
||||
*/
|
||||
|
||||
#include "heap_timer.h"
|
||||
#include "micro_thread.h"
|
||||
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
CTimerMng::CTimerMng(uint32_t max_item)
|
||||
{
|
||||
#define TIMER_MIN 100000
|
||||
|
||||
if (max_item < TIMER_MIN)
|
||||
{
|
||||
max_item = TIMER_MIN;
|
||||
}
|
||||
|
||||
_heap = new HeapList(max_item);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
CTimerMng::~CTimerMng()
|
||||
{
|
||||
if (_heap) {
|
||||
delete _heap;
|
||||
_heap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 定时器设置函数
|
||||
* @param timerable 定时器对象
|
||||
* @param interval 超时的间隔 ms单位
|
||||
* @return 成功返回true, 否则失败
|
||||
*/
|
||||
bool CTimerMng::start_timer(CTimerNotify* timerable, uint32_t interval)
|
||||
{
|
||||
if (!_heap || !timerable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
utime64_t now_ms = MtFrame::Instance()->GetLastClock();
|
||||
timerable->set_expired_time(now_ms + interval);
|
||||
int32_t ret = _heap->HeapPush(timerable);
|
||||
if (ret < 0) {
|
||||
MTLOG_ERROR("timer start failed(%p), ret(%d)", timerable, ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定时器停止接口函数
|
||||
* @param timerable 定时器对象
|
||||
*/
|
||||
void CTimerMng::stop_timer(CTimerNotify* timerable)
|
||||
{
|
||||
if (!_heap || !timerable) {
|
||||
return;
|
||||
}
|
||||
|
||||
_heap->HeapDelete(timerable);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定时器超时检测函数
|
||||
*/
|
||||
void CTimerMng::check_expired()
|
||||
{
|
||||
if (!_heap) {
|
||||
return;
|
||||
}
|
||||
|
||||
utime64_t now = MtFrame::Instance()->GetLastClock();
|
||||
CTimerNotify* timer = dynamic_cast<CTimerNotify*>(_heap->HeapTop());
|
||||
while (timer && (timer->get_expired_time() <= now))
|
||||
{
|
||||
_heap->HeapDelete(timer);
|
||||
timer->timer_notify();
|
||||
timer = dynamic_cast<CTimerNotify*>(_heap->HeapTop());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file heap_timer.h
|
||||
*/
|
||||
|
||||
#ifndef _MICRO_THREAD_TIMER_H_
|
||||
#define _MICRO_THREAD_TIMER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "heap.h"
|
||||
|
||||
namespace NS_MICRO_THREAD
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief 定时器对象基类
|
||||
*/
|
||||
class CTimerNotify : public HeapEntry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 超时通知函数, 子类实现逻辑
|
||||
*/
|
||||
virtual void timer_notify() { return;};
|
||||
|
||||
/**
|
||||
* @brief 堆元素取值函数, 用于返回值比较, 需子函数实现, 否则默认无序
|
||||
* @return 堆元素映射的值
|
||||
*/
|
||||
virtual unsigned long long HeapValue() {
|
||||
return (unsigned long long)_time_expired;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
CTimerNotify() : _time_expired(0) {};
|
||||
|
||||
/**
|
||||
* @brief 虚析构函数
|
||||
*/
|
||||
virtual ~CTimerNotify(){};
|
||||
|
||||
/**
|
||||
* @brief 设置绝对超时时间, 单位ms
|
||||
* @param expired 绝对超时时间 ms单位
|
||||
*/
|
||||
void set_expired_time(uint64_t expired) {
|
||||
_time_expired = expired;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取绝对超时时间, 单位ms
|
||||
* @return 绝对超时时间 ms单位
|
||||
*/
|
||||
uint64_t get_expired_time() {
|
||||
return _time_expired;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
uint64_t _time_expired; // 绝对的超时时间ms单位
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 定时器管理单例类
|
||||
*/
|
||||
class CTimerMng
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
* @param max_item 最大可管理的定时器对象数目(指针数目)
|
||||
*/
|
||||
explicit CTimerMng(uint32_t max_item = 100000);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~CTimerMng();
|
||||
|
||||
/**
|
||||
* @brief 定时器设置函数
|
||||
* @param timerable 定时器对象
|
||||
* @param interval 超时的间隔 ms单位
|
||||
* @return 成功返回true, 否则失败
|
||||
*/
|
||||
bool start_timer(CTimerNotify* timerable, uint32_t interval);
|
||||
|
||||
/**
|
||||
* @brief 定时器停止接口函数
|
||||
* @param timerable 定时器对象
|
||||
*/
|
||||
void stop_timer(CTimerNotify* timerable);
|
||||
|
||||
/**
|
||||
* @brief 定时器超时检测函数
|
||||
*/
|
||||
void check_expired();
|
||||
|
||||
private:
|
||||
|
||||
HeapList* _heap; // 最小堆指针
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,561 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @filename kqueue_proxy.cpp
|
||||
* @info kqueue for micro thread manage
|
||||
*/
|
||||
|
||||
#include "kqueue_proxy.h"
|
||||
#include "micro_thread.h"
|
||||
#include "ff_hook.h"
|
||||
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
KqueueProxy::KqueueProxy()
|
||||
{
|
||||
_maxfd = KqueueProxy::DEFAULT_MAX_FD_NUM;
|
||||
_kqfd = -1;
|
||||
_evtlist = NULL;
|
||||
_kqrefs = NULL;
|
||||
}
|
||||
|
||||
int KqueueProxy::InitKqueue(int max_num)
|
||||
{
|
||||
int rc = 0;
|
||||
if (max_num > _maxfd)
|
||||
{
|
||||
_maxfd = max_num;
|
||||
}
|
||||
|
||||
_kqfd = ff_kqueue();
|
||||
if (_kqfd < 0)
|
||||
{
|
||||
rc = -1;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
ff_fcntl(_kqfd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
_kqrefs = new KqFdRef[_maxfd];
|
||||
if (_kqrefs == NULL)
|
||||
{
|
||||
rc = -2;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
_evtlist = (KqEvent*)calloc(_maxfd, sizeof(KqEvent));
|
||||
if (_evtlist == NULL)
|
||||
{
|
||||
rc = -3;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
|
||||
struct rlimit rlim;
|
||||
memset(&rlim, 0, sizeof(rlim));
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
|
||||
{
|
||||
if ((int)rlim.rlim_max < _maxfd)
|
||||
{
|
||||
rlim.rlim_cur = rlim.rlim_max;
|
||||
setrlimit(RLIMIT_NOFILE, &rlim);
|
||||
rlim.rlim_cur = _maxfd;
|
||||
rlim.rlim_max = _maxfd;
|
||||
setrlimit(RLIMIT_NOFILE, &rlim);
|
||||
}
|
||||
}
|
||||
|
||||
EXIT_LABEL:
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
TermKqueue();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void KqueueProxy::TermKqueue()
|
||||
{
|
||||
if (_kqfd > 0)
|
||||
{
|
||||
close(_kqfd);
|
||||
_kqfd = -1;
|
||||
}
|
||||
|
||||
if (_evtlist != NULL)
|
||||
{
|
||||
free(_evtlist);
|
||||
_evtlist = NULL;
|
||||
}
|
||||
|
||||
if (_kqrefs != NULL)
|
||||
{
|
||||
delete []_kqrefs;
|
||||
_kqrefs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool KqueueProxy::KqueueAdd(KqObjList& obj_list)
|
||||
{
|
||||
bool ret = true;
|
||||
KqueuerObj *kqobj = NULL;
|
||||
KqueuerObj *kqobj_error = NULL;
|
||||
TAILQ_FOREACH(kqobj, &obj_list, _entry)
|
||||
{
|
||||
if (!KqueueAddObj(kqobj))
|
||||
{
|
||||
MTLOG_ERROR("kqobj add failed, fd: %d", kqobj->GetOsfd());
|
||||
kqueue_assert(0);
|
||||
kqobj_error = kqobj;
|
||||
ret = false;
|
||||
goto EXIT_LABEL;
|
||||
}
|
||||
}
|
||||
|
||||
EXIT_LABEL:
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
TAILQ_FOREACH(kqobj, &obj_list, _entry)
|
||||
{
|
||||
if (kqobj == kqobj_error)
|
||||
{
|
||||
break;
|
||||
}
|
||||
KqueueDelObj(kqobj);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool KqueueProxy::KqueueDel(KqObjList& obj_list)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
KqueuerObj *kqobj = NULL;
|
||||
TAILQ_FOREACH(kqobj, &obj_list, _entry)
|
||||
{
|
||||
if (!KqueueDelObj(kqobj)) // failed also need continue, be sure ref count ok
|
||||
{
|
||||
MTLOG_ERROR("epobj del failed, fd: %d", kqobj->GetOsfd());
|
||||
kqueue_assert(0);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool KqueueProxy::KqueueCtrlAdd(int fd, int events)
|
||||
{
|
||||
KqFdRef* item = KqFdRefGet(fd);
|
||||
if (item == NULL)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error, wtf?
|
||||
MTLOG_ERROR("kqfd ref not find, failed, fd: %d", fd);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
item->AttachEvents(events);
|
||||
|
||||
int old_events = item->GetListenEvents();
|
||||
int new_events = old_events | events;
|
||||
if (old_events == new_events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
KqEvent ke;
|
||||
int ret;
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
}
|
||||
if (old_events & KQ_EVENT_WRITE) {
|
||||
EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
// TODO, error check
|
||||
item->DetachEvents(events);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (old_events & KQ_EVENT_READ) {
|
||||
EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
// TODO, error check
|
||||
item->DetachEvents(events);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (events & KQ_EVENT_WRITE) {
|
||||
EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
// TODO, error check
|
||||
item->DetachEvents(events);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (events & KQ_EVENT_READ) {
|
||||
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
// TODO, error check
|
||||
item->DetachEvents(events);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
item->SetListenEvents(new_events);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool KqueueProxy::KqueueCtrlDel(int fd, int events)
|
||||
{
|
||||
return KqueueCtrlDelRef(fd, events, false);
|
||||
}
|
||||
|
||||
bool KqueueProxy::KqueueCtrlDelRef(int fd, int events, bool use_ref)
|
||||
{
|
||||
KqFdRef* item = KqFdRefGet(fd);
|
||||
if (item == NULL)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("kqfd ref not find, failed, fd: %d", fd);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
item->DetachEvents(events);
|
||||
int old_events = item->GetListenEvents();
|
||||
int new_events = old_events &~ events;
|
||||
|
||||
if (use_ref) {
|
||||
new_events = old_events;
|
||||
if (item->ReadRefCnt() == 0) {
|
||||
new_events = new_events & ~KQ_EVENT_READ;
|
||||
}
|
||||
if (item->WriteRefCnt() == 0) {
|
||||
new_events = new_events & ~KQ_EVENT_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_events == new_events)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
KqEvent ke;
|
||||
int ret;
|
||||
if (CHK_FD_BIT(fd)) {
|
||||
fd = CLR_FD_BIT(fd);
|
||||
}
|
||||
if (old_events & KQ_EVENT_WRITE) {
|
||||
EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (old_events & KQ_EVENT_READ) {
|
||||
EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_events & KQ_EVENT_WRITE) {
|
||||
EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (new_events & KQ_EVENT_READ) {
|
||||
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
ret = ff_kevent(_kqfd, &ke, 1, NULL, 0, NULL);
|
||||
if (ret == -1) {
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
item->SetListenEvents(new_events);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KqueueProxy::KqueueAddObj(KqueuerObj* obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
{
|
||||
MTLOG_ERROR("kqobj input invalid, %p", obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
KqFdRef* item = KqFdRefGet(obj->GetOsfd());
|
||||
if (item == NULL)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("kqfd ref not find, failed, fd: %d", obj->GetOsfd());
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = obj->KqueueCtlAdd(item);
|
||||
if (ret < 0) {
|
||||
MTLOG_ERROR("kqueue ctrl callback failed, fd: %d, obj: %p", obj->GetOsfd(), obj);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KqueueProxy::KqueueDelObj(KqueuerObj* obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
{
|
||||
MTLOG_ERROR("kqobj input invalid, %p", obj);
|
||||
return false;
|
||||
}
|
||||
KqFdRef* item = KqFdRefGet(obj->GetOsfd());
|
||||
if (item == NULL)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("kqfd ref not find, failed, fd: %d", obj->GetOsfd());
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = obj->KqueueCtlDel(item);
|
||||
if (ret < 0) {
|
||||
MTLOG_ERROR("kqueue ctrl callback failed, fd: %d, obj: %p", obj->GetOsfd(), obj);
|
||||
kqueue_assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KqueueProxy::KqueueRcvEventList(int evtfdnum)
|
||||
{
|
||||
int ret = 0;
|
||||
int osfd = 0;
|
||||
int revents = 0;
|
||||
int tmp_evts = 0;
|
||||
KqFdRef* item = NULL;
|
||||
KqueuerObj* obj = NULL;
|
||||
|
||||
for (int i = 0; i < evtfdnum; i++)
|
||||
{
|
||||
osfd = _evtlist[i].ident |= 1 << FF_FD_BITS;
|
||||
|
||||
item = KqFdRefGet(osfd);
|
||||
if (item == NULL)
|
||||
{
|
||||
MT_ATTR_API(320851, 1); // fd error
|
||||
MTLOG_ERROR("kqfd ref not find, failed, fd: %d", osfd);
|
||||
kqueue_assert(0);
|
||||
continue;
|
||||
}
|
||||
tmp_evts = _evtlist[i].filter;
|
||||
if (tmp_evts == EVFILT_READ) {
|
||||
revents |= KQ_EVENT_READ;
|
||||
}
|
||||
if (tmp_evts == EVFILT_WRITE) {
|
||||
revents |= KQ_EVENT_WRITE;
|
||||
}
|
||||
obj = item->GetNotifyObj();
|
||||
if (obj == NULL)
|
||||
{
|
||||
MTLOG_ERROR("fd notify obj null, failed, fd: %d", osfd);
|
||||
KqueueCtrlDel(osfd, (revents & (KQ_EVENT_READ | KQ_EVENT_WRITE)));
|
||||
continue;
|
||||
}
|
||||
obj->SetRcvEvents(revents);
|
||||
|
||||
if (tmp_evts == EV_ERROR)
|
||||
{
|
||||
obj->HangupNotify();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (revents & KQ_EVENT_READ)
|
||||
{
|
||||
ret = obj->InputNotify();
|
||||
if (ret != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (revents & KQ_EVENT_WRITE)
|
||||
{
|
||||
ret = obj->OutputNotify();
|
||||
if (ret != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KqueueProxy::KqueueDispatch()
|
||||
{
|
||||
int nfd;
|
||||
int wait_time = KqueueGetTimeout();
|
||||
if (wait_time) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = wait_time / 1000;
|
||||
ts.tv_nsec = 0;
|
||||
nfd = ff_kevent(_kqfd, NULL, 0, _evtlist, _maxfd, &ts);
|
||||
} else {
|
||||
nfd = ff_kevent(_kqfd, NULL, 0, _evtlist, _maxfd, NULL);
|
||||
}
|
||||
if (nfd <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
KqueueRcvEventList(nfd);
|
||||
}
|
||||
|
||||
int KqueuerObj::InputNotify()
|
||||
{
|
||||
MicroThread* thread = this->GetOwnerThread();
|
||||
if (thread == NULL)
|
||||
{
|
||||
kqueue_assert(0);
|
||||
MTLOG_ERROR("kqueue fd obj, no thread ptr, wrong");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (thread->HasFlag(MicroThread::IO_LIST))
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->RemoveIoWait(thread);
|
||||
frame->InsertRunable(thread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KqueuerObj::OutputNotify()
|
||||
{
|
||||
MicroThread* thread = this->GetOwnerThread();
|
||||
if (NULL == thread)
|
||||
{
|
||||
kqueue_assert(0);
|
||||
MTLOG_ERROR("kqueue fd obj, no thread ptr, wrong");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 多个事件同时到达, 防重复操作
|
||||
if (thread->HasFlag(MicroThread::IO_LIST))
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->RemoveIoWait(thread);
|
||||
frame->InsertRunable(thread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KqueuerObj::HangupNotify()
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->KqueueCtrlDel(this->GetOsfd(), this->GetEvents());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KqueuerObj::KqueueCtlAdd(void* args)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
KqFdRef* fd_ref = (KqFdRef*)args;
|
||||
kqueue_assert(fd_ref != NULL);
|
||||
|
||||
int osfd = this->GetOsfd();
|
||||
int new_events = this->GetEvents();
|
||||
|
||||
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
|
||||
KqueuerObj* old_obj = fd_ref->GetNotifyObj();
|
||||
if ((old_obj != NULL) && (old_obj != this))
|
||||
{
|
||||
MTLOG_ERROR("kqfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
|
||||
return -1;
|
||||
}
|
||||
fd_ref->SetNotifyObj(this);
|
||||
|
||||
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
|
||||
if (!frame->KqueueCtrlAdd(osfd, new_events))
|
||||
{
|
||||
MTLOG_ERROR("kqfd ref add failed, log");
|
||||
fd_ref->SetNotifyObj(old_obj);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int KqueuerObj::KqueueCtlDel(void* args)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
KqFdRef* fd_ref = (KqFdRef*)args;
|
||||
kqueue_assert(fd_ref != NULL);
|
||||
|
||||
int osfd = this->GetOsfd();
|
||||
int events = this->GetEvents();
|
||||
|
||||
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
|
||||
KqueuerObj* old_obj = fd_ref->GetNotifyObj();
|
||||
if (old_obj != this)
|
||||
{
|
||||
MTLOG_ERROR("kqfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
|
||||
return -1;
|
||||
}
|
||||
fd_ref->SetNotifyObj(NULL);
|
||||
|
||||
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
|
||||
if (!frame->KqueueCtrlDelRef(osfd, events, false)) // 引用有风险, 弊大于利, 关闭掉
|
||||
{
|
||||
MTLOG_ERROR("kqfd ref del failed, log");
|
||||
fd_ref->SetNotifyObj(old_obj);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename kqueue.h
|
||||
* @info kqueue for micro thread manage
|
||||
*/
|
||||
|
||||
#ifndef _KQUEUE_PROXY___
|
||||
#define _KQUEUE_PROXY___
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "ff_api.h"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
using std::set;
|
||||
using std::vector;
|
||||
|
||||
#define kqueue_assert(statement)
|
||||
//#define kqueue_assert(statement) assert(statement)
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
#define KQ_EVENT_NONE 0
|
||||
#define KQ_EVENT_READ 1
|
||||
#define KQ_EVENT_WRITE 2
|
||||
|
||||
/******************************************************************************/
|
||||
/* 操作系统头文件适配定义 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief add more detail for linux <sys/queue.h>, freebsd and University of California
|
||||
* @info queue.h version 8.3 (suse) diff version 8.5 (tlinux)
|
||||
*/
|
||||
#ifndef TAILQ_CONCAT
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) \
|
||||
do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TAILQ_FOREACH_SAFE // tlinux no this define
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* Kqueue proxy 定义与实现部分 */
|
||||
/******************************************************************************/
|
||||
|
||||
class KqueueProxy;
|
||||
class MicroThread;
|
||||
|
||||
/**
|
||||
* @brief kqueue通知对象基类定义
|
||||
*/
|
||||
class KqueuerObj
|
||||
{
|
||||
protected:
|
||||
int _fd;
|
||||
int _events;
|
||||
int _revents;
|
||||
int _type;
|
||||
MicroThread* _thread;
|
||||
|
||||
public:
|
||||
|
||||
TAILQ_ENTRY(KqueuerObj) _entry;
|
||||
|
||||
explicit KqueuerObj(int fd = -1) {
|
||||
_fd = fd;
|
||||
_events = 0;
|
||||
_revents = 0;
|
||||
_type = 0;
|
||||
_thread = NULL;
|
||||
};
|
||||
virtual ~KqueuerObj(){};
|
||||
|
||||
virtual int InputNotify();
|
||||
virtual int OutputNotify();
|
||||
virtual int HangupNotify();
|
||||
virtual int KqueueCtlAdd(void* args);
|
||||
virtual int KqueueCtlDel(void* args);
|
||||
|
||||
/**
|
||||
* @brief fd打开可读事件侦听
|
||||
*/
|
||||
void EnableInput() { _events |= KQ_EVENT_READ; };
|
||||
|
||||
/**
|
||||
* @brief fd打开可写事件侦听
|
||||
*/
|
||||
void EnableOutput() { _events |= KQ_EVENT_WRITE; };
|
||||
|
||||
/**
|
||||
* @brief fd关闭可读事件侦听
|
||||
*/
|
||||
void DisableInput() { _events &= ~KQ_EVENT_READ; };
|
||||
|
||||
/**
|
||||
* @brief fd关闭可写事件侦听
|
||||
*/
|
||||
void DisableOutput() { _events &= ~KQ_EVENT_WRITE; };
|
||||
|
||||
/**
|
||||
* @brief 系统socket设置读取封装
|
||||
*/
|
||||
int GetOsfd() { return _fd; };
|
||||
void SetOsfd(int fd) { _fd = fd; };
|
||||
|
||||
/**
|
||||
* @brief 监听事件与收到事件的访问方法
|
||||
*/
|
||||
int GetEvents() { return _events; };
|
||||
void SetRcvEvents(int revents) { _revents = revents; };
|
||||
int GetRcvEvents() { return _revents; };
|
||||
|
||||
/**
|
||||
* @brief 工厂管理方法, 获取真实类型
|
||||
*/
|
||||
int GetNtfyType() { return _type; };
|
||||
virtual void Reset() {
|
||||
_fd = -1;
|
||||
_events = 0;
|
||||
_revents = 0;
|
||||
_type = 0;
|
||||
_thread = NULL;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置与获取所属的微线程句柄接口
|
||||
* @param thread 关联的线程指针
|
||||
*/
|
||||
void SetOwnerThread(MicroThread* thread) { _thread = thread; };
|
||||
MicroThread* GetOwnerThread() { return _thread; };
|
||||
|
||||
};
|
||||
|
||||
typedef TAILQ_HEAD(__KqFdList, KqueuerObj) KqObjList; ///< 高效的双链管理
|
||||
typedef struct kevent KqEvent; ///< 重定义一下kqueue event
|
||||
|
||||
|
||||
/**
|
||||
* @brief EPOLL支持同一FD多个线程侦听, 建立一个引用计数数组, 元素定义
|
||||
* @info 引用计数弊大于利, 没有实际意义, 字段保留, 功能移除掉 20150623
|
||||
*/
|
||||
class KqFdRef
|
||||
{
|
||||
private:
|
||||
int _wr_ref; ///< 监听写的引用计数
|
||||
int _rd_ref; ///< 监听读的引用计数
|
||||
int _events; ///< 当前正在侦听的事件列表
|
||||
int _revents; ///< 当前该fd收到的事件信息, 仅在epoll_wait后处理中有效
|
||||
KqueuerObj* _kqobj; ///< 单独注册调度器对象,一个fd关联一个对象
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
KqFdRef() {
|
||||
_wr_ref = 0;
|
||||
_rd_ref = 0;
|
||||
_events = 0;
|
||||
_revents = 0;
|
||||
_kqobj = NULL;
|
||||
};
|
||||
~KqFdRef(){};
|
||||
|
||||
/**
|
||||
* @brief 监听事件获取与设置接口
|
||||
*/
|
||||
void SetListenEvents(int events) {
|
||||
_events = events;
|
||||
};
|
||||
int GetListenEvents() {
|
||||
return _events;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 监听对象获取与设置接口
|
||||
*/
|
||||
void SetNotifyObj(KqueuerObj* ntfy) {
|
||||
_kqobj = ntfy;
|
||||
};
|
||||
KqueuerObj* GetNotifyObj() {
|
||||
return _kqobj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 监听引用计数的更新
|
||||
*/
|
||||
void AttachEvents(int event) {
|
||||
if (event & KQ_EVENT_READ) {
|
||||
_rd_ref++;
|
||||
}
|
||||
if (event & KQ_EVENT_WRITE){
|
||||
_wr_ref++;
|
||||
}
|
||||
};
|
||||
void DetachEvents(int event) {
|
||||
if (event & KQ_EVENT_READ) {
|
||||
if (_rd_ref > 0) {
|
||||
_rd_ref--;
|
||||
} else {
|
||||
_rd_ref = 0;
|
||||
}
|
||||
}
|
||||
if (event & KQ_EVENT_WRITE){
|
||||
if (_wr_ref > 0) {
|
||||
_wr_ref--;
|
||||
} else {
|
||||
_wr_ref = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取引用计数
|
||||
*/
|
||||
int ReadRefCnt() { return _rd_ref; };
|
||||
int WriteRefCnt() { return _wr_ref; };
|
||||
|
||||
};
|
||||
|
||||
|
||||
class KqueueProxy
|
||||
{
|
||||
public:
|
||||
static const int DEFAULT_MAX_FD_NUM = 100000;
|
||||
|
||||
private:
|
||||
int _kqfd;
|
||||
int _maxfd;
|
||||
KqEvent* _evtlist;
|
||||
KqFdRef* _kqrefs;
|
||||
|
||||
public:
|
||||
KqueueProxy();
|
||||
virtual ~KqueueProxy(){};
|
||||
|
||||
int InitKqueue(int max_num);
|
||||
void TermKqueue(void);
|
||||
|
||||
virtual int KqueueGetTimeout(void) { return 0; };
|
||||
virtual bool KqueueSchedule(KqObjList* fdlist, KqueuerObj* fd, int timeout) { return false; };
|
||||
|
||||
bool KqueueAdd(KqObjList& fdset);
|
||||
bool KqueueDel(KqObjList& fdset);
|
||||
void KqueueDispatch(void);
|
||||
bool KqueueAddObj(KqueuerObj* obj);
|
||||
bool KqueueDelObj(KqueuerObj* obj);
|
||||
bool KqueueCtrlAdd(int fd, int new_events);
|
||||
bool KqueueCtrlDel(int fd, int new_events);
|
||||
bool KqueueCtrlDelRef(int fd, int new_events, bool use_ref);
|
||||
|
||||
KqFdRef* KqFdRefGet(int fd) {
|
||||
return ((fd >= _maxfd) || (fd < 0)) ? (KqFdRef*)NULL : &_kqrefs[fd];
|
||||
}
|
||||
|
||||
void KqueueNtfyReg(int fd, KqueuerObj* obj) {
|
||||
KqFdRef* ref = KqFdRefGet(fd);
|
||||
if (ref) {
|
||||
ref->SetNotifyObj(obj);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
void KqueueRcvEventList(int evtfdnum);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,925 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename micro_thread.h
|
||||
* @info micro thread manager
|
||||
*/
|
||||
|
||||
#ifndef ___MICRO_THREAD_H__
|
||||
#define ___MICRO_THREAD_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/queue.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include "heap.h"
|
||||
#include "kqueue_proxy.h"
|
||||
#include "heap_timer.h"
|
||||
|
||||
using std::vector;
|
||||
using std::set;
|
||||
using std::queue;
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
#define STACK_PAD_SIZE 128 ///< 栈上下隔离区域的大小
|
||||
#define MEM_PAGE_SIZE 4096 ///< 内存页默认大小
|
||||
#define DEFAULT_STACK_SIZE 128*1024 ///< 默认栈大小128K
|
||||
#define DEFAULT_THREAD_NUM 2000 ///< 默认2000个初始线程
|
||||
|
||||
typedef unsigned long long utime64_t; ///< 64位的时间定义
|
||||
typedef void (*ThreadStart)(void*); ///< 微线程入口函数定义
|
||||
|
||||
/**
|
||||
* @brief 线程调度的适配对象定义, 框架类最小接口封装
|
||||
*/
|
||||
class ScheduleObj
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 单例类访问句柄入口
|
||||
*/
|
||||
static ScheduleObj* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 获取全局的时间戳, 毫秒单位
|
||||
*/
|
||||
utime64_t ScheduleGetTime(void);
|
||||
|
||||
/**
|
||||
* @brief 调度其它微线程来运行
|
||||
*/
|
||||
void ScheduleThread(void);
|
||||
|
||||
/**
|
||||
* @brief 线程调度主动进入sleep状态
|
||||
*/
|
||||
void ScheduleSleep(void);
|
||||
|
||||
/**
|
||||
* @brief 线程调度主动进入pend状态
|
||||
*/
|
||||
void SchedulePend(void);
|
||||
|
||||
/**
|
||||
* @brief 线程调度取消pend状态, 外部调度取消
|
||||
*/
|
||||
void ScheduleUnpend(void* thread);
|
||||
|
||||
/**
|
||||
* @brief 线程执行完毕后, 回收处理
|
||||
*/
|
||||
void ScheduleReclaim(void);
|
||||
|
||||
/**
|
||||
* @brief 调度器调度初始执行
|
||||
*/
|
||||
void ScheduleStartRun(void);
|
||||
|
||||
private:
|
||||
static ScheduleObj* _instance; // 私有句柄
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 线程通用的栈帧结构定义
|
||||
*/
|
||||
struct MtStack
|
||||
{
|
||||
int _stk_size; ///< 栈的大小, 有效使用空间
|
||||
int _vaddr_size; ///< 申请的buff总大小
|
||||
char *_vaddr; ///< 申请的内存基地址
|
||||
void *_esp; ///< 栈的esp寄存器
|
||||
char *_stk_bottom; ///< 栈最低的地址空间
|
||||
char *_stk_top; ///< 栈最高的地址空间
|
||||
void *_private; ///< 线程私有数据
|
||||
int valgrind_id; ///< valgrind id
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 通用的线程模型定义
|
||||
*/
|
||||
class Thread : public HeapEntry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
explicit Thread(int stack_size = 0);
|
||||
virtual ~Thread(){};
|
||||
|
||||
/**
|
||||
* @brief 线程的实际工作函数
|
||||
*/
|
||||
virtual void Run(void){};
|
||||
|
||||
/**
|
||||
* @brief 初始化线程,如堆栈与上下文初始化
|
||||
*/
|
||||
bool Initial(void);
|
||||
|
||||
/**
|
||||
* @brief 终止线程,如堆栈与上下文释放
|
||||
*/
|
||||
void Destroy(void);
|
||||
|
||||
/**
|
||||
* @brief 线程状态重置, 可复用状态
|
||||
*/
|
||||
void Reset(void);
|
||||
|
||||
/**
|
||||
* @brief 线程主动进入睡眠, 单位毫秒
|
||||
* @param ms 睡眠毫秒数
|
||||
*/
|
||||
void sleep(int ms);
|
||||
|
||||
/**
|
||||
* @brief 线程主动进入等待, 让二级线程先运行
|
||||
*/
|
||||
void Wait();
|
||||
|
||||
/**
|
||||
* @brief 主动切换, 保存状态, 触发调度
|
||||
*/
|
||||
void SwitchContext(void);
|
||||
|
||||
/**
|
||||
* @brief 恢复上下文, 切换运行
|
||||
*/
|
||||
void RestoreContext(void);
|
||||
|
||||
/**
|
||||
* @brief 获取最后唤醒时间
|
||||
* @return 线程的唤醒时间点
|
||||
*/
|
||||
utime64_t GetWakeupTime(void) {
|
||||
return _wakeup_time;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置最后唤醒时间
|
||||
* @param waketime 线程的唤醒时间点
|
||||
*/
|
||||
void SetWakeupTime(utime64_t waketime) {
|
||||
_wakeup_time = waketime;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置线程私有数据
|
||||
* @param data 线程私有数据指针,使用者需自己申请内存,这里只保存指针
|
||||
*/
|
||||
void SetPrivate(void *data)
|
||||
{
|
||||
_stack->_private = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取线程私有数据
|
||||
*/
|
||||
void* GetPrivate()
|
||||
{
|
||||
return _stack->_private;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化上下文,设置寄存器,堆栈
|
||||
*/
|
||||
bool CheckStackHealth(char *esp);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief 清理线程处理状态, 准备复用
|
||||
*/
|
||||
virtual void CleanState(void){};
|
||||
|
||||
/**
|
||||
* @brief 初始化堆栈信息
|
||||
*/
|
||||
virtual bool InitStack(void);
|
||||
|
||||
/**
|
||||
* @brief 释放堆栈信息
|
||||
*/
|
||||
virtual void FreeStack(void);
|
||||
|
||||
/**
|
||||
* @brief 初始化上下文,设置寄存器,堆栈
|
||||
*/
|
||||
virtual void InitContext(void);
|
||||
|
||||
private:
|
||||
MtStack* _stack; ///< 私有栈指针
|
||||
jmp_buf _jmpbuf; ///< 上下文jmpbuff
|
||||
int _stack_size; ///< 栈大小字段
|
||||
utime64_t _wakeup_time; ///< 睡眠唤醒时间
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程数据结构定义
|
||||
*/
|
||||
class MicroThread : public Thread
|
||||
{
|
||||
public:
|
||||
enum ThreadType
|
||||
{
|
||||
NORMAL = 0, ///< 默认普通线程, 没有动态申请的栈信息
|
||||
PRIMORDIAL = 1, ///< 原生线程, main函数开启
|
||||
DAEMON = 2, ///< 守护线程, 底层IO EPOLL管理与调度触发
|
||||
SUB_THREAD = 3, ///< 二级线程, 仅执行简单工作
|
||||
};
|
||||
|
||||
enum ThreadFlag
|
||||
{
|
||||
NOT_INLIST = 0x0, ///< 无队列状态
|
||||
FREE_LIST = 0x1, ///< 空闲队列中
|
||||
IO_LIST = 0x2, ///< IO等待队列中
|
||||
SLEEP_LIST = 0x4, ///< 主动SLEEP中
|
||||
RUN_LIST = 0x8, ///< 可运行队列中
|
||||
PEND_LIST = 0x10, ///< 阻塞队列中
|
||||
SUB_LIST = 0x20, ///< 二级线程队列中
|
||||
|
||||
};
|
||||
|
||||
enum ThreadState
|
||||
{
|
||||
INITIAL = 0, ///< 初始化状态
|
||||
RUNABLE = 1, ///< 可运行状态
|
||||
RUNNING = 2, ///< 正在运行中
|
||||
SLEEPING = 3, ///< IO等待或SLEEP中
|
||||
PENDING = 4, ///< 阻塞状态中, 等待子线程OK等
|
||||
};
|
||||
|
||||
typedef TAILQ_ENTRY(MicroThread) ThreadLink; ///< 微线程链接
|
||||
typedef TAILQ_HEAD(__ThreadSubTailq, MicroThread) SubThreadList; ///< 微线程队列定义
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 微线程构造与析构
|
||||
*/
|
||||
MicroThread(ThreadType type = NORMAL);
|
||||
~MicroThread(){};
|
||||
|
||||
ThreadLink _entry; ///< 状态队列入口
|
||||
ThreadLink _sub_entry; ///< 子线程队列入口
|
||||
|
||||
/**
|
||||
* @brief 微线程堆排序函数实现,按唤醒时间从早到晚排序
|
||||
* @return 线程的实际唤醒时间
|
||||
*/
|
||||
virtual utime64_t HeapValue() {
|
||||
return GetWakeupTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 线程的实际工作函数
|
||||
*/
|
||||
virtual void Run(void);
|
||||
|
||||
/**
|
||||
* @breif fd侦听管理对列操作
|
||||
*/
|
||||
void ClearAllFd(void) {
|
||||
TAILQ_INIT(&_fdset);
|
||||
};
|
||||
void AddFd(KqueuerObj* efpd) {
|
||||
TAILQ_INSERT_TAIL(&_fdset, efpd, _entry);
|
||||
};
|
||||
void AddFdList(KqObjList* fdset) {
|
||||
TAILQ_CONCAT(&_fdset, fdset, _entry);
|
||||
};
|
||||
KqObjList& GetFdSet(void) {
|
||||
return _fdset;
|
||||
};
|
||||
|
||||
/**
|
||||
* @breif 微线程类型管理操作
|
||||
*/
|
||||
void SetType(ThreadType type) {
|
||||
_type = type;
|
||||
};
|
||||
ThreadType GetType(void) {
|
||||
return _type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @breif 微线程类型检查接口
|
||||
*/
|
||||
bool IsDaemon(void) {
|
||||
return (DAEMON == _type);
|
||||
};
|
||||
bool IsPrimo(void) {
|
||||
return (PRIMORDIAL == _type);
|
||||
};
|
||||
bool IsSubThread(void) {
|
||||
return (SUB_THREAD == _type);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 父线程设置与更新
|
||||
*/
|
||||
void SetParent(MicroThread* parent) {
|
||||
_parent = parent;
|
||||
};
|
||||
MicroThread* GetParent() {
|
||||
return _parent;
|
||||
};
|
||||
void WakeupParent();
|
||||
|
||||
/**
|
||||
* @brief 子线程的管理
|
||||
*/
|
||||
void AddSubThread(MicroThread* sub);
|
||||
void RemoveSubThread(MicroThread* sub);
|
||||
bool HasNoSubThread();
|
||||
|
||||
/**
|
||||
* @brief 微线程类型状态操作
|
||||
*/
|
||||
void SetState(ThreadState state) {
|
||||
_state = state;
|
||||
};
|
||||
ThreadState GetState(void) {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @breif 微线程标记位处理
|
||||
*/
|
||||
void SetFlag(ThreadFlag flag) {
|
||||
_flag = (ThreadFlag)(_flag | flag);
|
||||
};
|
||||
void UnsetFlag(ThreadFlag flag) {
|
||||
_flag = (ThreadFlag)(_flag & ~flag);
|
||||
};
|
||||
bool HasFlag(ThreadFlag flag) {
|
||||
return _flag & flag;
|
||||
};
|
||||
ThreadFlag GetFlag() {
|
||||
return _flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* @breif 微线程入口函数管理注册
|
||||
*/
|
||||
void SetSartFunc(ThreadStart func, void* args) {
|
||||
_start = func;
|
||||
_args = args;
|
||||
};
|
||||
|
||||
void* GetThreadArgs() {
|
||||
return _args;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @breif 微线程复用状态清理
|
||||
*/
|
||||
virtual void CleanState(void);
|
||||
|
||||
private:
|
||||
ThreadState _state; ///< 微线程当前状态
|
||||
ThreadType _type; ///< 微线程类型
|
||||
ThreadFlag _flag; ///< 微线程标记位
|
||||
KqObjList _fdset; ///< 微线程关注的socket列表
|
||||
SubThreadList _sub_list; ///< 二级线程的队列
|
||||
MicroThread* _parent; ///< 二级线程的父线程
|
||||
ThreadStart _start; ///< 微线程注册函数
|
||||
void* _args; ///< 微线程注册参数
|
||||
|
||||
};
|
||||
typedef std::set<MicroThread*> ThreadSet; ///< 微线程set管理结构
|
||||
typedef std::queue<MicroThread*> ThreadList; ///< 微线程queue管理结构
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程日志接口, 底层库, 日志由调用者注入
|
||||
*/
|
||||
class LogAdapter
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 日志构造与析构
|
||||
*/
|
||||
LogAdapter(){};
|
||||
virtual ~LogAdapter(){};
|
||||
|
||||
/**
|
||||
* @brief 日志优先按等级过滤, 减少解析参数的开销
|
||||
* @return true 可以打印该级别, false 跳过不打印该级别
|
||||
*/
|
||||
virtual bool CheckDebug(){ return true;};
|
||||
virtual bool CheckTrace(){ return true;};
|
||||
virtual bool CheckError(){ return true;};
|
||||
|
||||
/**
|
||||
* @brief 日志分级记录接口
|
||||
*/
|
||||
virtual void LogDebug(char* fmt, ...){};
|
||||
virtual void LogTrace(char* fmt, ...){};
|
||||
virtual void LogError(char* fmt, ...){};
|
||||
|
||||
/**
|
||||
* @brief 属性上报接口
|
||||
*/
|
||||
virtual void AttrReportAdd(int attr, int iValue){};
|
||||
virtual void AttrReportSet(int attr, int iValue){};
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程池简单实现
|
||||
*/
|
||||
class ThreadPool
|
||||
{
|
||||
public:
|
||||
|
||||
static unsigned int default_thread_num; ///< 默认2000微线程待命
|
||||
static unsigned int default_stack_size; ///< 默认128K栈大小
|
||||
|
||||
/**
|
||||
* @brief 设置微线程的最小保留数目
|
||||
*/
|
||||
static void SetDefaultThreadNum(unsigned int num) {
|
||||
default_thread_num = num;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置微线程的默认栈大小, 需初始化前设置
|
||||
*/
|
||||
static void SetDefaultStackSize(unsigned int size) {
|
||||
default_stack_size = (size + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE * MEM_PAGE_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 微线程池初始化
|
||||
*/
|
||||
bool InitialPool(int max_num);
|
||||
|
||||
/**
|
||||
* @brief 微线程池反初始化
|
||||
*/
|
||||
void DestroyPool (void);
|
||||
|
||||
/**
|
||||
* @brief 微线程分配接口
|
||||
* @return 微线程对象
|
||||
*/
|
||||
MicroThread* AllocThread(void);
|
||||
|
||||
/**
|
||||
* @brief 微线程释放接口
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void FreeThread(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 获取当前微线程数量
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
int GetUsedNum(void);
|
||||
|
||||
private:
|
||||
ThreadList _freelist; ///< 空闲待命的微线程队列
|
||||
int _total_num; ///< 目前总的微线程数目,后续按需控制上限
|
||||
int _use_num; ///< 当前正在使用的微线程数目
|
||||
int _max_num; ///< 最大并发限制数, 放置内存过度使用
|
||||
};
|
||||
|
||||
typedef TAILQ_HEAD(__ThreadTailq, MicroThread) ThreadTailq; ///< 微线程队列定义
|
||||
|
||||
/**
|
||||
* @brief 微线程框架类, 全局的单例类
|
||||
*/
|
||||
class MtFrame : public KqueueProxy, public ThreadPool
|
||||
{
|
||||
private:
|
||||
static MtFrame* _instance; ///< 单例指针
|
||||
LogAdapter* _log_adpt; ///< 日志接口
|
||||
ThreadList _runlist; ///< 可运行queue, 无优先级
|
||||
ThreadTailq _iolist; ///< 等待队列,可随机脱离队列
|
||||
ThreadTailq _pend_list; ///< 等待队列,可随机脱离队列
|
||||
HeapList _sleeplist; ///< 等待超时的堆, 可随机脱离, 且随时获取最小堆首
|
||||
MicroThread* _daemon; ///< 守护线程, 执行epoll wait, 超时检测
|
||||
MicroThread* _primo; ///< 原生线程, 使用的是原生堆栈
|
||||
MicroThread* _curr_thread; ///< 当前运行线程
|
||||
utime64_t _last_clock; ///< 全局时间戳, 每次idle获取一次
|
||||
int _waitnum; ///< 等待运行的总线程数, 可调节调度的节奏
|
||||
CTimerMng* _timer; ///< TCP保活专用的timer定时器
|
||||
int _realtime; /// < 使用实时时间0, 未设置
|
||||
|
||||
public:
|
||||
friend class ScheduleObj; ///< 调度器对象, 是框架类的门面模式, 友元处理
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 微线程框架类, 全局实例获取
|
||||
*/
|
||||
static MtFrame* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 sendto
|
||||
* @param fd 系统socket信息
|
||||
* @param msg 待发送的消息指针
|
||||
* @param len 待发送的消息长度
|
||||
* @param to 目的地址的指针
|
||||
* @param tolen 目的地址的结构长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
static int sendto(int fd, const void *msg, int len, int flags, const struct sockaddr *to, int tolen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 recvfrom
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 接收消息缓冲区指针
|
||||
* @param len 接收消息缓冲区长度
|
||||
* @param from 来源地址的指针
|
||||
* @param fromlen 来源地址的结构长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
static int recvfrom(int fd, void *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 connect
|
||||
* @param fd 系统socket信息
|
||||
* @param addr 指定server的目的地址
|
||||
* @param addrlen 地址的长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
static int connect(int fd, const struct sockaddr *addr, int addrlen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 accept
|
||||
* @param fd 监听套接字
|
||||
* @param addr 客户端地址
|
||||
* @param addrlen 地址的长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >=0 accept的socket描述符, <0 失败
|
||||
*/
|
||||
static int accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 read
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 接收消息缓冲区指针
|
||||
* @param nbyte 接收消息缓冲区长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
static ssize_t read(int fd, void *buf, size_t nbyte, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 write
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 发送消息缓冲区指针
|
||||
* @param nbyte 发送消息缓冲区长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
static ssize_t write(int fd, const void *buf, size_t nbyte, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 recv
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 接收消息缓冲区指针
|
||||
* @param len 接收消息缓冲区长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
static int recv(int fd, void *buf, int len, int flags, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 send
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 待发送的消息指针
|
||||
* @param nbyte 待发送的消息长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
static ssize_t send(int fd, const void *buf, size_t nbyte, int flags, int timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程主动sleep接口, 单位ms
|
||||
*/
|
||||
static void sleep(int ms);
|
||||
|
||||
/**
|
||||
* @brief 微线程仅等待事件,不做额外的操作
|
||||
* @param fd 系统socket信息
|
||||
* @param events 事件类型 EPOLLIN or EPOLLOUT
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
static int WaitEvents(int fd, int events, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程创建接口
|
||||
* @param entry 线程入口函数
|
||||
* @param args 线程入口参数
|
||||
* @return 微线程指针, NULL表示失败
|
||||
*/
|
||||
static MicroThread* CreateThread(ThreadStart entry, void *args, bool runable = true);
|
||||
|
||||
/**
|
||||
* @brief 守护线程入口函数, 函数指针要求static类型
|
||||
* @param args 线程入口参数
|
||||
*/
|
||||
static void DaemonRun(void* args);
|
||||
static int Loop(void* args);
|
||||
|
||||
/**
|
||||
* @brief 获取当前线程的根线程
|
||||
*/
|
||||
MicroThread *GetRootThread();
|
||||
|
||||
/**
|
||||
* @brief 框架初始化, 默认不带日志运行
|
||||
*/
|
||||
bool InitFrame(LogAdapter* logadpt = NULL, int max_thread_num = 50000);
|
||||
|
||||
/**
|
||||
* @brief HOOK系统api的设置
|
||||
*/
|
||||
void SetHookFlag();
|
||||
|
||||
/**
|
||||
* @brief 框架反初始化
|
||||
*/
|
||||
void Destroy (void);
|
||||
|
||||
/**
|
||||
* @brief 微线程框架版本获取
|
||||
*/
|
||||
char* Version(void);
|
||||
|
||||
/**
|
||||
* @brief 框架获取全局时间戳
|
||||
*/
|
||||
utime64_t GetLastClock(void) {
|
||||
if(_realtime)
|
||||
{
|
||||
return GetSystemMS();
|
||||
}
|
||||
return _last_clock;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 框架获取当前线程
|
||||
*/
|
||||
MicroThread* GetActiveThread(void) {
|
||||
return _curr_thread;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 返回当前待运行的线程数, 直接计数, 效率高
|
||||
* @return 等待线程数
|
||||
*/
|
||||
int RunWaitNum(void) {
|
||||
return _waitnum;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 框架被注入的日志句柄访问
|
||||
*/
|
||||
LogAdapter* GetLogAdpt(void) {
|
||||
return _log_adpt;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取框架保活定时器指针
|
||||
*/
|
||||
CTimerMng* GetTimerMng(void) {
|
||||
return _timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 框架调用epoll wait前, 判定等待时间信息
|
||||
*/
|
||||
virtual int KqueueGetTimeout(void);
|
||||
|
||||
/**
|
||||
* @brief 微线程触发切换函数,调用成功 则让出cpu, 内部接口
|
||||
* @param fdlist 多路并发的socket列表
|
||||
* @param fd 单个请求的fd信息
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return true 成功, false 失败
|
||||
*/
|
||||
virtual bool KqueueSchedule(KqObjList* fdlist, KqueuerObj* fd, int timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程主动切换, 等待其它线程的唤醒
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
*/
|
||||
void WaitNotify(utime64_t timeout);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 移除IO等待状态, 内部接口
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void RemoveIoWait(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 插入可运行队列, 内部接口
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void InsertRunable(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 执行pend等待状态
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void InsertPend(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 移除PEND等待状态
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void RemovePend(MicroThread* thread);
|
||||
|
||||
void SetRealTime(int realtime_)
|
||||
{
|
||||
_realtime =realtime_;
|
||||
}
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief 微线程私有构造
|
||||
*/
|
||||
MtFrame():_realtime(1){ _curr_thread = NULL; };
|
||||
|
||||
/**
|
||||
* @brief 微线程私有获取守护线程
|
||||
*/
|
||||
MicroThread* DaemonThread(void){
|
||||
return _daemon;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 框架调度线程运行
|
||||
*/
|
||||
void ThreadSchdule(void);
|
||||
|
||||
/**
|
||||
* @brief 框架处理定时回调函数
|
||||
*/
|
||||
void CheckExpired();
|
||||
|
||||
/**
|
||||
* @brief 框架检测到超时, 唤醒所有的超时线程
|
||||
*/
|
||||
void WakeupTimeout(void);
|
||||
|
||||
/**
|
||||
* @brief 框架更新全局时间戳
|
||||
*/
|
||||
void SetLastClock(utime64_t clock) {
|
||||
_last_clock = clock;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 框架设置当前线程
|
||||
*/
|
||||
void SetActiveThread(MicroThread* thread) {
|
||||
_curr_thread = thread;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 框架的时钟源接口, 返回毫秒级别时钟
|
||||
*/
|
||||
utime64_t GetSystemMS(void) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 执行IO等待状态
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void InsertSleep(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 移除IO等待状态
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void RemoveSleep(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 执行IO等待状态
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void InsertIoWait(MicroThread* thread);
|
||||
|
||||
/**
|
||||
* @brief 框架管理线程单元, 移出可运行队列
|
||||
* @param thread 微线程对象
|
||||
*/
|
||||
void RemoveRunable(MicroThread* thread);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 日志宏的定义部分
|
||||
*/
|
||||
#define MTLOG_DEBUG(fmt, args...) \
|
||||
do { \
|
||||
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
|
||||
if (fm && fm->GetLogAdpt() && fm->GetLogAdpt()->CheckDebug()) \
|
||||
{ \
|
||||
fm->GetLogAdpt()->LogDebug((char*)"[%-10s][%-4d][%-10s]"fmt, \
|
||||
__FILE__, __LINE__, __FUNCTION__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MTLOG_TRACE(fmt, args...) \
|
||||
do { \
|
||||
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
|
||||
if (fm && fm->GetLogAdpt() && fm->GetLogAdpt()->CheckTrace()) \
|
||||
{ \
|
||||
fm->GetLogAdpt()->LogTrace((char*)"[%-10s][%-4d][%-10s]"fmt, \
|
||||
__FILE__, __LINE__, __FUNCTION__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MTLOG_ERROR(fmt, args...) \
|
||||
do { \
|
||||
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
|
||||
if (fm && fm->GetLogAdpt() && fm->GetLogAdpt()->CheckError()) \
|
||||
{ \
|
||||
fm->GetLogAdpt()->LogError((char*)"[%-10s][%-4d][%-10s]"fmt, \
|
||||
__FILE__, __LINE__, __FUNCTION__, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MT_ATTR_API(ATTR, VALUE) \
|
||||
do { \
|
||||
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
|
||||
if (fm && fm->GetLogAdpt()) \
|
||||
{ \
|
||||
fm->GetLogAdpt()->AttrReportAdd(ATTR, VALUE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MT_ATTR_API_SET(ATTR, VALUE) \
|
||||
do { \
|
||||
register NS_MICRO_THREAD::MtFrame *fm = NS_MICRO_THREAD::MtFrame::Instance(); \
|
||||
if (fm && fm->GetLogAdpt()) \
|
||||
{ \
|
||||
fm->GetLogAdpt()->AttrReportSet(ATTR, VALUE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
}// NAMESPACE NS_MICRO_THREAD
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_action.cpp
|
||||
* @info 微线程ACTION基类实现
|
||||
* @time 20130924
|
||||
**/
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_notify.h"
|
||||
#include "mt_connection.h"
|
||||
#include "mt_session.h"
|
||||
#include "mt_action.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 初始item状态
|
||||
*/
|
||||
void IMtAction::Init()
|
||||
{
|
||||
_flag = MULTI_FLAG_UNDEF;
|
||||
_proto = MT_UDP;
|
||||
_conn_type = CONN_TYPE_SHORT;
|
||||
_errno = ERR_NONE;
|
||||
_time_cost = 0;
|
||||
_buff_size = 0;
|
||||
_msg = NULL;
|
||||
_conn = NULL;
|
||||
_ntfy_name = 0;
|
||||
memset(&_addr, 0, sizeof(_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 允许复用, 清理item状态
|
||||
*/
|
||||
void IMtAction::Reset()
|
||||
{
|
||||
// 长连接, 处理成功才复用, 否则强制关闭
|
||||
bool force_free = false;
|
||||
if (_errno != ERR_NONE) {
|
||||
force_free = true;
|
||||
}
|
||||
|
||||
if (_conn) {
|
||||
ConnectionMgr::Instance()->FreeConnection(_conn, force_free);
|
||||
_conn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取连接对象, 通知对象, 消息对象
|
||||
*/
|
||||
KqueuerObj* IMtAction::GetNtfyObj() {
|
||||
IMtConnection* conn = GetIConnection();
|
||||
if (conn) {
|
||||
return conn->GetNtfyObj();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 后端连接环境初始化
|
||||
*/
|
||||
int IMtAction::InitConnEnv()
|
||||
{
|
||||
MtFrame* mtframe = MtFrame::Instance();
|
||||
ConnectionMgr* connmgr = ConnectionMgr::Instance();
|
||||
MsgBuffPool* msgmgr = MsgBuffPool::Instance();
|
||||
NtfyObjMgr* ntfymgr = NtfyObjMgr::Instance();
|
||||
SessionMgr* sessionmgr = SessionMgr::Instance();
|
||||
|
||||
if (_conn != NULL) {
|
||||
MTLOG_ERROR("Action init failed, maybe action reused in actionlist, check it!!");
|
||||
return -100;
|
||||
}
|
||||
|
||||
// 1. 分类获取conn句柄
|
||||
CONN_OBJ_TYPE conn_obj_type = OBJ_CONN_UNDEF;
|
||||
NTFY_OBJ_TYPE ntfy_obj_type = NTFY_OBJ_UNDEF;
|
||||
|
||||
MULTI_PROTO proto = this->GetProtoType();
|
||||
MULTI_CONNECT type = this->GetConnType();
|
||||
if ((MT_UDP == proto) && (CONN_TYPE_SESSION == type)) // UDP session模式
|
||||
{
|
||||
conn_obj_type = OBJ_UDP_SESSION;
|
||||
ntfy_obj_type = NTFY_OBJ_SESSION;
|
||||
}
|
||||
else if (MT_UDP == proto) // UDP 其它模式
|
||||
{
|
||||
conn_obj_type = OBJ_SHORT_CONN;
|
||||
ntfy_obj_type = NTFY_OBJ_THREAD;
|
||||
}
|
||||
else // TCP 模式
|
||||
{
|
||||
conn_obj_type = OBJ_TCP_KEEP;
|
||||
ntfy_obj_type = NTFY_OBJ_THREAD;
|
||||
}
|
||||
|
||||
_conn = connmgr->GetConnection(conn_obj_type, this->GetMsgDstAddr());
|
||||
if (!_conn) {
|
||||
MTLOG_ERROR("Get conn failed, type: %d", conn_obj_type);
|
||||
return -1;
|
||||
}
|
||||
_conn->SetIMtActon(this);
|
||||
|
||||
// 2. 获取msg buff句柄
|
||||
int max_len = this->GetMsgBuffSize();
|
||||
MtMsgBuf* msg_buff = msgmgr->GetMsgBuf(max_len);
|
||||
if (!msg_buff) {
|
||||
MTLOG_ERROR("Maybe no memory, buffsize: %d, get failed", max_len);
|
||||
return -2;
|
||||
}
|
||||
msg_buff->SetBuffType(BUFF_SEND);
|
||||
_conn->SetMtMsgBuff(msg_buff);
|
||||
|
||||
// 3. 获取 ntfy 对象句柄
|
||||
KqueuerObj* ntfy_obj = ntfymgr->GetNtfyObj(ntfy_obj_type, _ntfy_name);
|
||||
if (!ntfy_obj) {
|
||||
MTLOG_ERROR("Maybe no memory, ntfy type: %d, get failed", ntfy_obj_type);
|
||||
return -3;
|
||||
}
|
||||
_conn->SetNtfyObj(ntfy_obj);
|
||||
|
||||
// 4. SESSION模型, 建立session
|
||||
MicroThread* thread = mtframe->GetActiveThread();
|
||||
ntfy_obj->SetOwnerThread(thread);
|
||||
this->SetIMsgPtr((IMtMsg*)thread->GetThreadArgs());
|
||||
if (conn_obj_type == OBJ_UDP_SESSION)
|
||||
{
|
||||
this->SetOwnerThread(thread);
|
||||
this->SetSessionConn(_conn);
|
||||
this->SetSessionId(sessionmgr->GetSessionId());
|
||||
sessionmgr->InsertSession(this);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 代理虚函数, 简化接口与实现部分
|
||||
*/
|
||||
int IMtAction::DoEncode()
|
||||
{
|
||||
MtMsgBuf* msg_buff = NULL;
|
||||
if (_conn) {
|
||||
msg_buff = _conn->GetMtMsgBuff();
|
||||
}
|
||||
if (!_conn || !msg_buff) {
|
||||
MTLOG_ERROR("conn(%p) or msgbuff(%p) null", _conn, msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
int msg_len = msg_buff->GetMaxLen();
|
||||
int ret = this->HandleEncode(msg_buff->GetMsgBuff(), msg_len, _msg);
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_DEBUG("handleecode failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
msg_buff->SetMsgLen(msg_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 代理虚函数, 简化接口与实现部分
|
||||
*/
|
||||
int IMtAction::DoInput()
|
||||
{
|
||||
MtMsgBuf* msg_buff = NULL;
|
||||
if (_conn) {
|
||||
msg_buff = _conn->GetMtMsgBuff();
|
||||
}
|
||||
if (!_conn || !msg_buff) {
|
||||
MTLOG_ERROR("conn(%p) or msgbuff(%p) null", _conn, msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
int msg_len = msg_buff->GetHaveRcvLen();
|
||||
int ret = this->HandleInput(msg_buff->GetMsgBuff(), msg_len, _msg);
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_DEBUG("HandleInput failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int IMtAction::DoProcess()
|
||||
{
|
||||
MtMsgBuf* msg_buff = NULL;
|
||||
if (_conn) {
|
||||
msg_buff = _conn->GetMtMsgBuff();
|
||||
}
|
||||
if (!_conn || !msg_buff) {
|
||||
MTLOG_ERROR("conn(%p) or msgbuff(%p) null", _conn, msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
int ret = this->HandleProcess(msg_buff->GetMsgBuff(), msg_buff->GetMsgLen(), _msg);
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_DEBUG("handleprocess failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int IMtAction::DoError()
|
||||
{
|
||||
return this->HandleError((int)_errno, _msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 构造与析构处理
|
||||
*/
|
||||
IMtAction::IMtAction()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
IMtAction::~IMtAction()
|
||||
{
|
||||
Reset();
|
||||
Init();
|
||||
}
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_action.h
|
||||
* @info 微线程ACTION基类定义
|
||||
**/
|
||||
|
||||
#ifndef __MT_ACTION_H__
|
||||
#define __MT_ACTION_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <queue>
|
||||
#include "mt_msg.h"
|
||||
#include "mt_session.h"
|
||||
#include "mt_notify.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
|
||||
/**
|
||||
* @brief 并发处理状态标记定义
|
||||
*/
|
||||
enum MULTI_STATE
|
||||
{
|
||||
MULTI_FLAG_UNDEF = 0x0, ///< 初始化, 未启动
|
||||
MULTI_FLAG_INIT = 0x1, ///< socket创建已成功
|
||||
MULTI_FLAG_OPEN = 0x2, ///< socket连接已打开
|
||||
MULTI_FLAG_SEND = 0x4, ///< 请求报文已经发送
|
||||
MULTI_FLAG_FIN = 0x8, ///< 应答报文已经接收到
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 协议连接类型定义
|
||||
*/
|
||||
enum MULTI_CONNECT
|
||||
{
|
||||
CONN_UNKNOWN = 0,
|
||||
CONN_TYPE_SHORT = 0x1, ///< 短连接, 一次交互后关闭
|
||||
CONN_TYPE_LONG = 0x2, ///< 长连接,每次使用后, 可回收重复使用
|
||||
CONN_TYPE_SESSION = 0x4, ///< 长连接,按session id 复用, 防串包
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 错误码定义
|
||||
*/
|
||||
enum MULTI_ERROR
|
||||
{
|
||||
ERR_NONE = 0,
|
||||
ERR_SOCKET_FAIL = -1, ///< 创建sock失败
|
||||
ERR_CONNECT_FAIL = -2, ///< 连接失败
|
||||
ERR_SEND_FAIL = -3, ///< 发送报文失败
|
||||
ERR_RECV_FAIL = -4, ///< 接收失败
|
||||
ERR_RECV_TIMEOUT = -5, ///< 接收超时
|
||||
ERR_KQUEUE_FAIL = -6, ///< epoll失败
|
||||
ERR_FRAME_ERROR = -7, ///< 框架失败
|
||||
ERR_PEER_CLOSE = -8, ///< 对方关闭
|
||||
ERR_PARAM_ERROR = -9, ///< 参数错误
|
||||
ERR_MEMORY_ERROR = -10, ///< 内存申请失败
|
||||
ERR_ENCODE_ERROR = -11, ///< 封包失败
|
||||
ERR_DST_ADDR_ERROR = -12, ///< 目标地址获取失败
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程的后端交互抽象基类
|
||||
*/
|
||||
class IMtAction : public ISession
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 微线程并发行为基类
|
||||
*/
|
||||
IMtAction();
|
||||
virtual ~IMtAction();
|
||||
|
||||
/**
|
||||
* @brief 设置请求报文信息 (保证接口最大灵活兼容, 不使用inline)
|
||||
* @param dst -请求包待发送的地址
|
||||
*/
|
||||
void SetMsgDstAddr(struct sockaddr_in* dst) {
|
||||
memcpy(&_addr, dst, sizeof(_addr));
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取消息目的地址信息
|
||||
* @return 注册的目的地址
|
||||
*/
|
||||
struct sockaddr_in* GetMsgDstAddr() {
|
||||
return &_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置buff大小, 决定实际使用的msgbuff队列
|
||||
* @return 0成功
|
||||
*/
|
||||
void SetMsgBuffSize(int buff_size) {
|
||||
_buff_size = buff_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取预置的buff大小
|
||||
* @return 框架申请的消息buff最大长度
|
||||
*/
|
||||
int GetMsgBuffSize() {
|
||||
return (_buff_size > 0) ? _buff_size : 65535;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置长连接session的名字id
|
||||
* @return 0成功
|
||||
*/
|
||||
void SetSessionName(int name) {
|
||||
_ntfy_name = name;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取连接session的名字id
|
||||
* @return session 注册名
|
||||
*/
|
||||
int GetSessionName() {
|
||||
return _ntfy_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置本次处理的proto信息
|
||||
*/
|
||||
void SetProtoType(MULTI_PROTO proto) {
|
||||
_proto = proto;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取本次处理的proto信息
|
||||
* @return proto type
|
||||
*/
|
||||
MULTI_PROTO GetProtoType() {
|
||||
return _proto;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置本次处理的连接类型信息
|
||||
*/
|
||||
void SetConnType(MULTI_CONNECT type) {
|
||||
_conn_type = type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取本次处理的连接类型信息
|
||||
* @return conn type
|
||||
*/
|
||||
MULTI_CONNECT GetConnType() {
|
||||
return _conn_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置本次处理的errno
|
||||
*/
|
||||
void SetErrno(MULTI_ERROR err) {
|
||||
_errno = err;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取本次处理的ERRNO信息
|
||||
* @return ERRONO
|
||||
*/
|
||||
MULTI_ERROR GetErrno() {
|
||||
return _errno;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置本次处理的timecost
|
||||
*/
|
||||
void SetCost(int cost) {
|
||||
_time_cost = cost;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取本次处理的timecost信息
|
||||
* @return timecost
|
||||
*/
|
||||
int GetCost() {
|
||||
return _time_cost;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置处理状态信息
|
||||
* @param flag -消息处理状态
|
||||
*/
|
||||
void SetMsgFlag(MULTI_STATE flag) {
|
||||
_flag = flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取处理状态信息
|
||||
* @return flag -消息处理状态
|
||||
*/
|
||||
MULTI_STATE GetMsgFlag() {
|
||||
return _flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置内部消息指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
void SetIMsgPtr(IMtMsg* msg ) {
|
||||
_msg = msg;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取内部消息指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
IMtMsg* GetIMsgPtr() {
|
||||
return _msg;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置内部连接器指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
void SetIConnection(IMtConnection* conn) {
|
||||
_conn = conn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取内部连接器指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
IMtConnection* GetIConnection() {
|
||||
return _conn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化必要字段信息
|
||||
*/
|
||||
void Init();
|
||||
|
||||
/**
|
||||
* @brief 允许复用, 清理Action状态
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* @brief 获取连接对象, 通知对象, 消息对象
|
||||
*/
|
||||
KqueuerObj* GetNtfyObj();
|
||||
|
||||
/**
|
||||
* @brief 获取连接对象, 通知对象, 消息对象
|
||||
*/
|
||||
int InitConnEnv();
|
||||
|
||||
/**
|
||||
* @brief 代理虚函数, 简化接口与实现部分
|
||||
*/
|
||||
int DoEncode();
|
||||
int DoInput();
|
||||
int DoProcess();
|
||||
int DoError();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 本次连接的消息打包接口
|
||||
* @return >0 -成功, < 0 失败
|
||||
*/
|
||||
virtual int HandleEncode(void* buf, int& len, IMtMsg* msg){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 本次连接的CHECK接口, TCP的分包接口
|
||||
* @return > 0 已经成功接收,返回完整包大小, =0 继续等待, <0 出错(其中-65535 UDP串包)
|
||||
*/
|
||||
virtual int HandleInput(void* buf, int len, IMtMsg* msg){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 本次连接的应答处理接口, 接收一个完整分段包后调用
|
||||
* @return 0 成功, 其他失败
|
||||
*/
|
||||
virtual int HandleProcess(void* buf, int len, IMtMsg* msg){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 本次连接处理的错误通知, 定义参见 MULTI_ERROR 枚举
|
||||
* @info 除handleprocess失败, 其它异常都调用该接口
|
||||
* @return 0 成功, 其他失败
|
||||
*/
|
||||
virtual int HandleError(int err, IMtMsg* msg){return 0;};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
MULTI_STATE _flag; // 处理结束标记信息, 当前状态信息
|
||||
MULTI_PROTO _proto; // 协议类型 UDP/TCP
|
||||
MULTI_CONNECT _conn_type; // 连接类型 长短连接
|
||||
MULTI_ERROR _errno; // 错误码信息, 0成功其他错误
|
||||
struct sockaddr_in _addr; // 请求时填写,指定发送的stAddr
|
||||
int _time_cost; // 本次请求应答耗时, 毫秒
|
||||
int _buff_size; // 本次请求最大请求与应答长度
|
||||
int _ntfy_name; // 关联的session ntfy的名字, session模型适用
|
||||
|
||||
IMtMsg* _msg; // 消息指针, 上级指针
|
||||
IMtConnection* _conn; // 连接器指针, 下级指针, 管理生存期
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,410 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename mt_api.h
|
||||
* @info 微线程封装系统api, 同步调用微线程API,实现异步调度
|
||||
*/
|
||||
|
||||
#ifndef __MT_API_H__
|
||||
#define __MT_API_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <vector>
|
||||
|
||||
using std::vector;
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: UDP短连接收发接口 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 采用随机端口的socket收发接口, 由socket来决定上下文, 业务来保证上下文
|
||||
* [注意] UDP发送buff, 不推荐static变量, 有一定风险导致上下文错乱[重要]
|
||||
* @param dst -请求发送的目的地址
|
||||
* @param pkg -请求包封装的包体
|
||||
* @param len -请求包封装的包体长度
|
||||
* @param rcv_buf -接收应答包的buff
|
||||
* @param buf_size -modify-接收应答包的buff大小, 成功返回时, 修改为应答包长度
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败, 可打印errno
|
||||
*/
|
||||
int mt_udpsendrcv(struct sockaddr_in* dst, void* pkg, int len, void* rcv_buf, int& buf_size, int timeout);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: TCP连接池收发接口 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief TCP检测报文是否接收完整的回调函数定义
|
||||
* @param buf 报文保存缓冲区
|
||||
* @param len 已经接收的长度
|
||||
* @return >0 实际的报文长度; 0 还需要等待接收; <0 报文异常
|
||||
*/
|
||||
typedef int (*MtFuncTcpMsgLen)(void* buf, int len);
|
||||
|
||||
/**
|
||||
* @brief TCP会采用连接池的方式复用IP/PORT连接, 连接保持默认10分钟
|
||||
* [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要]
|
||||
* @param dst -请求发送的目的地址
|
||||
* @param pkg -请求包封装的包体
|
||||
* @param len -请求包封装的包体长度
|
||||
* @param rcv_buf -接收应答包的buff
|
||||
* @param buf_size -modify-接收应答包的buff大小, 成功返回时, 修改为应答包长度
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @param check_func -检测报文是否成功到达函数
|
||||
* @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败,
|
||||
* -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接,-10 参数无效
|
||||
*/
|
||||
int mt_tcpsendrcv(struct sockaddr_in* dst, void* pkg, int len, void* rcv_buf, int& buf_size,
|
||||
int timeout, MtFuncTcpMsgLen chek_func);
|
||||
|
||||
|
||||
enum MT_TCP_CONN_TYPE
|
||||
{
|
||||
MT_TCP_SHORT = 1, /// 短连接
|
||||
MT_TCP_LONG = 2, /// 长连接
|
||||
MT_TCP_SHORT_SNDONLY = 3, /// 短连接只发
|
||||
MT_TCP_LONG_SNDONLY = 4, /// 长连接只发
|
||||
MT_TCP_BUTT
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief TCP收发接口,可以选择后端保持连接或者短连接
|
||||
* [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要]
|
||||
* @param dst -请求发送的目的地址
|
||||
* @param pkg -请求包封装的包体
|
||||
* @param len -请求包封装的包体长度
|
||||
* @param rcv_buf -接收应答包的buff,只发不收可以设置为NULL
|
||||
* @param buf_size -modify-接收应答包的buff大小, 成功返回时, 修改为应答包长度,只发不收,设置为NULL
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @param check_func -检测报文是否成功到达函数
|
||||
* @param type - 连接类型
|
||||
* MT_TCP_SHORT: 一收一发短连接;
|
||||
* MT_TCP_LONG : 一发一收长连接;
|
||||
* MT_TCP_LONG_SNDONLY : 只发不收长连接;
|
||||
* MT_TCP_SHORT_SNDONLY: 只发不收短连接;
|
||||
* @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败,
|
||||
* -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接, -10 参数无效
|
||||
*/
|
||||
int mt_tcpsendrcv_ex(struct sockaddr_in* dst, void* pkg, int len, void* rcv_buf, int* buf_size,
|
||||
int timeout, MtFuncTcpMsgLen func, MT_TCP_CONN_TYPE type = MT_TCP_LONG);
|
||||
|
||||
/**
|
||||
* @brief TCP检测报文是否接收完整的回调函数
|
||||
* @param buf 报文保存缓冲区
|
||||
* @param len 已经接收的长度
|
||||
* @param closed 远端关闭连接,兼容通过链接关闭来确定报文长度的业务
|
||||
* @param msg_ctx 解析报文的上下文变量。通过该值,业务可以实现报文解析状态机等,避免重复检查
|
||||
* 业务在mt_tcpsendrcv中传入该参数,框架回调时传递给业务。该变量可以为类或者结构体,业务自定义。
|
||||
* 报文解析结果,保存在变量中,mt_tcpsendrcv返回后,直接使用
|
||||
* 【注意】 该回调函数传入的buf指针可能变化,所以报文解析状态机相关位置信息请使用偏移量
|
||||
* @param msg_len_detected 传出参数 如果业务确定了报文长度,则将其设置为true,否则为false。传入时为false。
|
||||
* 【注意】如果该值返回true,框架以函数返回值作为报文长度(>0)持续收包,在收包完成前,不再调用该MtFuncTcpMsgChecker函数;报文接收完成后,调用MtFuncTcpMsgChecker函数检查一次报文。减少因零碎收包引起的无效调用。
|
||||
* @return >0 建议的接收缓冲大小; 0 还需要等待接收; <0 报文异常
|
||||
* 【注意】
|
||||
* 以下两种情况可以返回大于0:
|
||||
* 1,业务确定报文长度,返回报文长度
|
||||
* 2,业务不确定报文长度,给出接收buf的建议长度,如果长度大于现有buf长度,框架根据该值realloc buf。
|
||||
*
|
||||
* 返回值为0,表示业务无法确定报文长度,需要接续接收。如果buf收满,框架将realloc buf,buf大小扩大一倍
|
||||
* 返回值小于0,表示业务确定报文错误
|
||||
*/
|
||||
typedef int (*MtFuncTcpMsgChecker)(void* buf, int len, bool closed, void* msg_ctx, bool &msg_len_detected);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief TCP收发接口,可以选择后端保持连接或者短连接
|
||||
* [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要]
|
||||
* @param dst -请求发送的目的地址
|
||||
* @param pkg -请求包封装的包体
|
||||
* @param len -请求包封装的包体长度
|
||||
* @param rcv_buf -【传出参数】,参考参数 keep_rcv_buf。业务不需要malloc该内存。void* rcv_buf=NULL: 传给框架即可
|
||||
* @param recv_pkg_size -接收应答包的buff的初始大小。函数返回0时,返回报文实际长度。
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @param check_func -检测报文是否成功到达函数
|
||||
* @param msg_ctx -解析报文的上下文变量。
|
||||
*
|
||||
* @param type - 连接类型
|
||||
* MT_TCP_SHORT: 一收一发短连接;
|
||||
* MT_TCP_LONG : 一发一收长连接;
|
||||
* MT_TCP_LONG_SNDONLY : 只发不收长连接;
|
||||
* MT_TCP_SHORT_SNDONLY: 只发不收短连接;
|
||||
* @param keep_rcv_buf -true,调用成功后,框架将最后的rcv_buf赋值给传出参数,业务负责释放该buf。否则框架在调用结束前释放该buf。【注意】
|
||||
* 业务需要自己在msg_ctx中保留相关信息。【框架通过malloc申请内存】 默认框架自动释放该buf,业务需要在ctx保存信息
|
||||
* @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败,
|
||||
* -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接, -10 参数无效, -11,申请接收buf失败
|
||||
*/
|
||||
int mt_tcpsendrcv_ex(struct sockaddr_in* dst, void* pkg, int len, void*& rcv_buf, int& recv_pkg_size,
|
||||
int timeout, MtFuncTcpMsgChecker check_func, void* msg_ctx=NULL,
|
||||
MT_TCP_CONN_TYPE type = MT_TCP_LONG, bool keep_rcv_buf=false);
|
||||
|
||||
/**
|
||||
* @brief TCP会采用连接池的方式复用IP/PORT连接, 连接保持默认10分钟
|
||||
* [注意] tcp接收发送buff, 不可以是static变量, 否则会上下文错乱 [重要]
|
||||
* @param dst -请求发送的目的地址
|
||||
* @param pkg -请求包封装的包体
|
||||
* @param len -请求包封装的包体长度
|
||||
* @param rcv_buf -【传出参数】,参考参数 keep_rcv_buf。
|
||||
* @param recv_pkg_size -接收应答包的buff的初始大小。函数返回0时,返回报文实际长度。
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @param check_func -检测报文是否成功到达函数
|
||||
* @param msg_ctx -解析报文的上下文变量。
|
||||
* @param keep_rcv_buf -true,框架将最后的rcv_buf赋值给传出参数,业务负责释放该buf。否则框架在调用结束前释放该buf。【注意】
|
||||
* 业务需要自己在msg_ctx中保留相关信息。【框架通过malloc申请内存】
|
||||
* @return 0 成功, -1 打开socket失败, -2 发送请求失败, -3 接收应答失败,
|
||||
* -4 连接失败, -5 检测报文失败, -6 接收空间不够, -7 后端主动关闭连接, -10 参数无效
|
||||
*/
|
||||
int mt_tcpsendrcv(struct sockaddr_in* dst, void* pkg, int len, void*& rcv_buf, int& recv_pkg_size,
|
||||
int timeout, MtFuncTcpMsgChecker check_func, void* msg_ctx=NULL, bool keep_rcv_buf=false);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: 微线程Task多路并发模型接口定义 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 微线程子任务对象定义
|
||||
*/
|
||||
class IMtTask
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 微线程任务类的处理流程入口函数
|
||||
* @return 0 -成功, < 0 失败
|
||||
*/
|
||||
virtual int Process() { return -1; };
|
||||
|
||||
/**
|
||||
* @brief 设置task执行结果
|
||||
* @info 即Process返回值
|
||||
*/
|
||||
void SetResult(int rc)
|
||||
{
|
||||
_result = rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取task执行结果
|
||||
* @info 即Process返回值
|
||||
*/
|
||||
int GetResult(void)
|
||||
{
|
||||
return _result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置task类型
|
||||
*/
|
||||
void SetTaskType(int type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取task类型
|
||||
* @info 如果业务有多种task,可以使用该字段区分不同的task类型
|
||||
* @return 获取task类型
|
||||
*/
|
||||
int GetTaskType(void)
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 微线程任务基类构造与析构
|
||||
*/
|
||||
IMtTask() {};
|
||||
virtual ~IMtTask() {};
|
||||
|
||||
protected:
|
||||
|
||||
int _type; // task类型,多种类型task,业务可以自定义类型,方便从基类转换
|
||||
int _result; // task执行结果,即Process返回值
|
||||
};
|
||||
|
||||
typedef vector<IMtTask*> IMtTaskList;
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发, Task-fork-wait模式接口
|
||||
* @param req_list -task list 封装独立api的task列表
|
||||
* @return 0 成功, -1 创建子线程失败
|
||||
*/
|
||||
int mt_exec_all_task(IMtTaskList& req_list);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: 微线程封装系统接口 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 微线程主动sleep接口, 单位ms
|
||||
* @info 业务需要主动让出CPU时使用
|
||||
*/
|
||||
void mt_sleep(int ms);
|
||||
|
||||
/**
|
||||
* @brief 微线程获取系统时间,单位ms
|
||||
*/
|
||||
unsigned long long mt_time_ms(void);
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: 微线程用户私有数据接口 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 设置当前IMtMsg的私有变量
|
||||
* @info 只保存指针,内存需要业务分配
|
||||
*/
|
||||
void mt_set_msg_private(void *data);
|
||||
|
||||
/**
|
||||
* @brief 获取当前IMtMsg的私有变量
|
||||
* @return 私有变量指针
|
||||
*/
|
||||
void* mt_get_msg_private();
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: 微线程封装系统接口(不推荐使用) */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 微线程框架初始化
|
||||
* @info 业务不使用spp,裸用微线程,需要调用该函数初始化框架;
|
||||
* 使用spp,直接调用SyncFrame的框架初始化函数即可
|
||||
* @return false:初始化失败 true:初始化成功
|
||||
*/
|
||||
bool mt_init_frame(const char *conf=NULL, int argc=0, char * const argv[]=NULL);
|
||||
|
||||
/**
|
||||
* @brief 设置微线程独立栈空间大小
|
||||
* @info 非必须设置,默认大小为128K
|
||||
*/
|
||||
void mt_set_stack_size(unsigned int bytes);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 recvfrom
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 接收消息缓冲区指针
|
||||
* @param len 接收消息缓冲区长度
|
||||
* @param from 来源地址的指针
|
||||
* @param fromlen 来源地址的结构长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
int mt_recvfrom(int fd, void *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 sendto
|
||||
* @param fd 系统socket信息
|
||||
* @param msg 待发送的消息指针
|
||||
* @param len 待发送的消息长度
|
||||
* @param to 目的地址的指针
|
||||
* @param tolen 目的地址的结构长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
int mt_sendto(int fd, const void *msg, int len, int flags, const struct sockaddr *to, int tolen, int timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 connect
|
||||
* @param fd 系统socket信息
|
||||
* @param addr 指定server的目的地址
|
||||
* @param addrlen 地址的长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
int mt_connect(int fd, const struct sockaddr *addr, int addrlen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 accept
|
||||
* @param fd 监听套接字
|
||||
* @param addr 客户端地址
|
||||
* @param addrlen 地址的长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >=0 accept的socket描述符, <0 失败
|
||||
*/
|
||||
int mt_accept(int fd, struct sockaddr *addr, socklen_t *addrlen, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 read
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 接收消息缓冲区指针
|
||||
* @param nbyte 接收消息缓冲区长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
ssize_t mt_read(int fd, void *buf, size_t nbyte, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 write
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 待发送的消息指针
|
||||
* @param nbyte 待发送的消息长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
ssize_t mt_write(int fd, const void *buf, size_t nbyte, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 recv
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 接收消息缓冲区指针
|
||||
* @param len 接收消息缓冲区长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功接收长度, <0 失败
|
||||
*/
|
||||
ssize_t mt_recv(int fd, void *buf, int len, int flags, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 微线程包裹的系统IO函数 send
|
||||
* @param fd 系统socket信息
|
||||
* @param buf 待发送的消息指针
|
||||
* @param nbyte 待发送的消息长度
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 成功发送长度, <0 失败
|
||||
*/
|
||||
ssize_t mt_send(int fd, const void *buf, size_t nbyte, int flags, int timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程等待epoll事件的包裹函数
|
||||
* @param fd 系统socket信息
|
||||
* @param events 等待的事件 IN/OUT
|
||||
* @param timeout 最长等待时间, 毫秒
|
||||
* @return >0 到达的事件, <0 失败
|
||||
*/
|
||||
int mt_wait_events(int fd, int events, int timeout);
|
||||
|
||||
|
||||
void* mt_start_thread(void* entry, void* args);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,869 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename mt_cache.cpp
|
||||
* @info TCP接入buffer管理实现
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include "mt_incl.h"
|
||||
#include "kqueue_proxy.h"
|
||||
#include "micro_thread.h"
|
||||
#include "mt_sys_hook.h"
|
||||
#include "ff_hook.h"
|
||||
|
||||
#include "mt_cache.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Buffer创建操作
|
||||
* @param size 实际的buff大小
|
||||
* @return 非NULL block块, 其它失败
|
||||
*/
|
||||
TSkBuffer* new_sk_buffer(uint32_t size)
|
||||
{
|
||||
uint32_t total = sizeof(TSkBuffer) + size;
|
||||
total = (total + SK_DFLT_ALIGN_SIZE - 1) / SK_DFLT_ALIGN_SIZE * SK_DFLT_ALIGN_SIZE;
|
||||
TSkBuffer* block = (TSkBuffer*)malloc(total);
|
||||
if (block == NULL)
|
||||
{
|
||||
MTLOG_ERROR("malloc failed, no more memory[%u]", total);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block->last_time = 0;
|
||||
block->size = size;
|
||||
block->head = block->buff;
|
||||
block->end = block->buff + size;
|
||||
|
||||
block->data = block->head;
|
||||
block->data_len = 0;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Buffer释放操作
|
||||
* @param block -buff块
|
||||
*/
|
||||
void delete_sk_buffer(TSkBuffer* block)
|
||||
{
|
||||
if (NULL == block) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(block);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 保留更大长度信息(非资源池化的buff,可扩展)
|
||||
* @param buff -已有的buff指针
|
||||
* @param size -需要扩展的最终长度大小
|
||||
* @return 实际的buff信息
|
||||
*/
|
||||
TSkBuffer* reserve_sk_buffer(TSkBuffer* buff, uint32_t size)
|
||||
{
|
||||
if (NULL == buff) {
|
||||
return new_sk_buffer(size);
|
||||
}
|
||||
|
||||
if (buff->size >= size) {
|
||||
return buff;
|
||||
}
|
||||
|
||||
TSkBuffer* new_buff = new_sk_buffer(size);
|
||||
if (NULL == new_buff) {
|
||||
return buff;
|
||||
}
|
||||
memcpy(new_buff->data, buff->data, buff->data_len);
|
||||
new_buff->data_len = buff->data_len;
|
||||
delete_sk_buffer(buff);
|
||||
|
||||
return new_buff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief cache 池的初始化接口
|
||||
* @param mng -管理池的指针
|
||||
* @param expired -保活的时间, 单位秒
|
||||
* @param size -本管理块默认生成的块大小
|
||||
*/
|
||||
void sk_buffer_mng_init(TSkBuffMng* mng, uint32_t expired, uint32_t size)
|
||||
{
|
||||
TAILQ_INIT(&mng->free_list);
|
||||
mng->expired = expired;
|
||||
mng->count = 0;
|
||||
mng->size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief cache 池的销毁接口
|
||||
* @param mng -管理池的指针
|
||||
*/
|
||||
void sk_buffer_mng_destroy(TSkBuffMng * mng)
|
||||
{
|
||||
TSkBuffer* item = NULL;
|
||||
TSkBuffer* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &mng->free_list, entry, tmp)
|
||||
{
|
||||
TAILQ_REMOVE(&mng->free_list, item, entry);
|
||||
delete_sk_buffer(item);
|
||||
}
|
||||
mng->count = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 申请或复用一块buff
|
||||
* @param mng -管理池的指针
|
||||
* @return 非NULL为成功获取的buff块指针
|
||||
*/
|
||||
TSkBuffer* alloc_sk_buffer(TSkBuffMng* mng)
|
||||
{
|
||||
if (NULL == mng) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TSkBuffer* item = TAILQ_FIRST(&mng->free_list);
|
||||
if (item != NULL)
|
||||
{
|
||||
TAILQ_REMOVE(&mng->free_list, item, entry);
|
||||
mng->count--;
|
||||
return item;
|
||||
}
|
||||
|
||||
item = new_sk_buffer(mng->size);
|
||||
if (NULL == item)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 释放指定的buff块
|
||||
* @param mng -管理池的指针
|
||||
* @param buff -待释放的buff指针
|
||||
*/
|
||||
void free_sk_buffer(TSkBuffMng* mng, TSkBuffer* buff)
|
||||
{
|
||||
if ((NULL == mng) || (NULL == buff)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&mng->free_list, buff, entry);
|
||||
mng->count++;
|
||||
|
||||
buff->last_time = (uint32_t)(mt_time_ms() / 1000);
|
||||
buff->data = buff->head;
|
||||
buff->data_len = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 回收过期的buff块
|
||||
* @param mng -管理池的指针
|
||||
* @param now -当前的时间, 秒级别
|
||||
*/
|
||||
void recycle_sk_buffer(TSkBuffMng* mng, uint32_t now)
|
||||
{
|
||||
TSkBuffer* item = NULL;
|
||||
TSkBuffer* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &mng->free_list, entry, tmp)
|
||||
{
|
||||
if ((now - item->last_time) < mng->expired)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&mng->free_list, item, entry);
|
||||
delete_sk_buffer(item);
|
||||
mng->count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache管理链初始化
|
||||
* @param cache -管理块指针
|
||||
* @param pool -buff池指针
|
||||
*/
|
||||
void rw_cache_init(TRWCache* cache, TSkBuffMng* pool)
|
||||
{
|
||||
TAILQ_INIT(&cache->list);
|
||||
cache->len = 0;
|
||||
cache->count = 0;
|
||||
cache->pool = pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache管理链销毁
|
||||
* @param cache -管理块指针
|
||||
*/
|
||||
void rw_cache_destroy(TRWCache* cache)
|
||||
{
|
||||
if ((cache == NULL) || (cache->pool == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TSkBuffer* item = NULL;
|
||||
TSkBuffer* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &cache->list, entry, tmp)
|
||||
{
|
||||
TAILQ_REMOVE(&cache->list, item, entry);
|
||||
free_sk_buffer(cache->pool, item);
|
||||
}
|
||||
cache->count = 0;
|
||||
cache->len = 0;
|
||||
cache->pool = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache删除并拷贝指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param buff -存放buff的指针
|
||||
* @param len -待删除的长度
|
||||
* @return 实际拷贝长度
|
||||
*/
|
||||
uint32_t cache_copy_out(TRWCache* cache, void* buff, uint32_t len)
|
||||
{
|
||||
if ((cache == NULL) || (cache->pool == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* out_buff = (char*)buff;
|
||||
uint32_t left = len, skip_len = 0;
|
||||
TSkBuffer* item = NULL;
|
||||
TSkBuffer* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &cache->list, entry, tmp)
|
||||
{
|
||||
// 1. 确认拷贝数据大小
|
||||
skip_len = (item->data_len > left) ? left : item->data_len;
|
||||
if (out_buff != NULL)
|
||||
{
|
||||
memcpy(out_buff, item->data, skip_len);
|
||||
out_buff += skip_len;
|
||||
}
|
||||
|
||||
left -= skip_len;
|
||||
item->data_len -= skip_len;
|
||||
item->data += skip_len;
|
||||
if (item->data_len > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// 2. 移除一个block
|
||||
if (cache->count > 0) {
|
||||
cache->count--;
|
||||
}
|
||||
TAILQ_REMOVE(&cache->list, item, entry);
|
||||
free_sk_buffer(cache->pool, item);
|
||||
|
||||
// 3. 循环变量控制
|
||||
if (left == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 整体考虑数据长度问题, 是否有足够的数据移除
|
||||
skip_len = len - left;
|
||||
if (cache->len > skip_len)
|
||||
{
|
||||
cache->len -= skip_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache->len = 0;
|
||||
}
|
||||
|
||||
return skip_len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache删除掉指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param len -待删除的长度
|
||||
*/
|
||||
void cache_skip_data(TRWCache* cache, uint32_t len)
|
||||
{
|
||||
cache_copy_out(cache, NULL, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache追加指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param buff -待追加的块指针
|
||||
*/
|
||||
void cache_append_buffer(TRWCache* cache, TSkBuffer* buff)
|
||||
{
|
||||
if ((NULL == cache) || (NULL == buff))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&cache->list, buff, entry);
|
||||
cache->len += buff->data_len;
|
||||
cache->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache移除第一块内存, 但不free
|
||||
* @param cache -管理块指针
|
||||
*/
|
||||
TSkBuffer* cache_skip_first_buffer(TRWCache* cache)
|
||||
{
|
||||
TSkBuffer* buff = TAILQ_FIRST(&cache->list);
|
||||
if ((NULL == cache) || (NULL == buff))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&cache->list, buff, entry);
|
||||
if (cache->len >= buff->data_len)
|
||||
{
|
||||
cache->len -= buff->data_len;
|
||||
}
|
||||
|
||||
if (cache->count > 0)
|
||||
{
|
||||
cache->count--;
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache追加指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param data -待追加的指针
|
||||
* @param len -待追加的长度
|
||||
*/
|
||||
int32_t cache_append_data(TRWCache* cache, const void* data, uint32_t len)
|
||||
{
|
||||
if ((NULL == data) || (NULL == cache) || (NULL == cache->pool))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t left = len;
|
||||
uint32_t remain = 0;
|
||||
|
||||
// 1. 尾空间先进行append, 因为需要回滚, 前一部分先不拷贝
|
||||
TSkBuffer* tail = TAILQ_LAST(&cache->list, __sk_buff_list);
|
||||
if (tail != NULL)
|
||||
{
|
||||
if (tail->end > (tail->data + tail->data_len))
|
||||
{
|
||||
remain = tail->end - tail->data - tail->data_len;
|
||||
}
|
||||
|
||||
if (remain >= len)
|
||||
{
|
||||
memcpy(tail->data + tail->data_len, data, len);
|
||||
tail->data_len += len;
|
||||
cache->len += len;
|
||||
return (int32_t)len;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 有剩余buff待处理, 先申请剩余的buff, 在修改尾节点
|
||||
TRWCache keep_list;
|
||||
rw_cache_init(&keep_list, cache->pool);
|
||||
left -= remain;
|
||||
while (left > 0)
|
||||
{
|
||||
TSkBuffer* item = alloc_sk_buffer(cache->pool);
|
||||
if (item == NULL)
|
||||
{
|
||||
rw_cache_destroy(&keep_list);
|
||||
return -2;
|
||||
}
|
||||
cache_append_buffer(&keep_list, item);
|
||||
|
||||
if (left <= item->size)
|
||||
{
|
||||
memcpy(item->head, (char*)data + len - left, left);
|
||||
item->data_len = left;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(item->head, (char*)data + len - left, item->size);
|
||||
item->data_len = item->size;
|
||||
left -= item->size;
|
||||
}
|
||||
|
||||
// 3. 尝试拷贝最初的buff, 这里不会回滚了
|
||||
if ((tail != NULL) && (remain > 0))
|
||||
{
|
||||
memcpy(tail->data + tail->data_len, data, remain);
|
||||
tail->data_len += remain;
|
||||
}
|
||||
|
||||
cache->len += len;
|
||||
cache->count += keep_list.count;
|
||||
TAILQ_CONCAT(&cache->list, &keep_list.list, entry);
|
||||
|
||||
return (int32_t)len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache整合的UDP收报接口, 消耗内存比较多, 不建议32位使用
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备收报的fd句柄
|
||||
* @param remote_addr -对端ip地址
|
||||
* @return 实际接收长度
|
||||
*/
|
||||
int32_t cache_udp_recv(TRWCache* cache, uint32_t fd, struct sockaddr_in* remote_addr)
|
||||
{
|
||||
if (NULL == cache)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t total = 0;
|
||||
for (uint32_t i = 0; i < 100; i++)
|
||||
{
|
||||
TSkBuffer* item = alloc_sk_buffer(cache->pool);
|
||||
if (NULL == item)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
socklen_t addr_len = sizeof(*remote_addr);
|
||||
mt_hook_syscall(recvfrom);
|
||||
int32_t rc = ff_hook_recvfrom(fd, item->data, item->size, 0, (struct sockaddr*)remote_addr, &addr_len);
|
||||
if (rc <= 0)
|
||||
{
|
||||
free_sk_buffer(cache->pool, item);
|
||||
|
||||
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("recvfrom failed, fd[%d] ret %d[%m]", fd, rc);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
item->data_len += rc;
|
||||
cache_append_buffer(cache, item);
|
||||
total += rc;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache整合的TCP收报接口
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备收报的fd句柄
|
||||
* @return 实际接收长度
|
||||
*/
|
||||
int32_t cache_tcp_recv(TRWCache* cache, uint32_t fd)
|
||||
{
|
||||
if (NULL == cache)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t total = 0;
|
||||
for (uint32_t i = 0; i < 100; i++)
|
||||
{
|
||||
// 1. 每次检查尾空间, 空间满或初始状态, 申请新空间
|
||||
TSkBuffer* item = TAILQ_LAST(&cache->list, __sk_buff_list);
|
||||
if ((NULL == item)
|
||||
|| ((item->data_len + item->data) >= item->end))
|
||||
{
|
||||
item = alloc_sk_buffer(cache->pool);
|
||||
if (item == NULL)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
cache_append_buffer(cache, item);
|
||||
}
|
||||
|
||||
// 2. 单次最多接收size大小, 默认64K
|
||||
uint8_t* buff = item->data + item->data_len;
|
||||
uint32_t remain = item->end - item->data - item->data_len;
|
||||
mt_hook_syscall(recv);
|
||||
int32_t recvd_len = ff_hook_recv(fd, buff, remain, 0);
|
||||
if (recvd_len == 0)
|
||||
{
|
||||
MTLOG_DEBUG("remote close, socket: %d", fd);
|
||||
return -SK_ERR_NEED_CLOSE;
|
||||
}
|
||||
else if (recvd_len < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
return total;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("recv tcp socket failed, error: %d[%m]", errno);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item->data_len += recvd_len;
|
||||
cache->len += recvd_len;
|
||||
total += recvd_len;
|
||||
if (recvd_len < (int32_t)remain) // 收不满, 可认为本次OK
|
||||
{
|
||||
return total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cache整合的TCP发送接口
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备发包的fd句柄
|
||||
* @return 实际发送长度
|
||||
*/
|
||||
int32_t cache_tcp_send(TRWCache* cache, uint32_t fd)
|
||||
{
|
||||
if ((NULL == cache) || (NULL == cache->pool))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cache->len == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t ret = 0, total = 0;
|
||||
TSkBuffer* item = NULL;
|
||||
TSkBuffer* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &cache->list, entry, tmp)
|
||||
{
|
||||
mt_hook_syscall(send);
|
||||
ret = ff_hook_send(fd, item->data, item->data_len, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
total += ret;
|
||||
if (ret < (int32_t)item->data_len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cache_skip_data(cache, total);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
MTLOG_ERROR("tcp socket send failed, error: %d[%m]", errno);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache整合的TCP发送接口, 未使用IOVEC
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备发包的fd句柄
|
||||
* @param data -发送完cache后, 继续发送的buff
|
||||
* @param len -继续发送的buff长度
|
||||
* @return 实际发送长度
|
||||
*/
|
||||
int32_t cache_tcp_send_buff(TRWCache* cache, uint32_t fd, const void* data, uint32_t len)
|
||||
{
|
||||
if ((NULL == cache) || (NULL == data))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 1. 优先发送CACHE数据
|
||||
int32_t ret = cache_tcp_send(cache, fd);
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_ERROR("tcp socket[%d] send cache data failed, rc: %d", fd, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 2. CACHE已经无数据
|
||||
int32_t send_len = 0;
|
||||
if (cache->len == 0)
|
||||
{
|
||||
mt_hook_syscall(send);
|
||||
ret = ff_hook_send(fd, data, len, 0);
|
||||
if (ret >= 0)
|
||||
{
|
||||
send_len += ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
MTLOG_ERROR("tcp socket[%d] send failed, error: %d[%m]", fd, errno);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t rc = cache_append_data(cache, (char*)data + send_len, len - send_len);
|
||||
if (rc < 0)
|
||||
{
|
||||
MTLOG_ERROR("tcp socket[%d] apend data failed, rc: %d", fd, rc);
|
||||
return -3;
|
||||
}
|
||||
|
||||
return send_len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取cache有效数据总长度
|
||||
* @param multi -管理块指针
|
||||
* @return 实际有效数据长度
|
||||
*/
|
||||
uint32_t get_data_len(TBuffVecPtr multi)
|
||||
{
|
||||
TRWCache* cache = (TRWCache*)multi;
|
||||
if (NULL == cache) {
|
||||
return 0;
|
||||
} else {
|
||||
return cache->len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取cache有效数据块个数
|
||||
* @param multi -管理块指针
|
||||
* @return 实际有效数据块个数
|
||||
*/
|
||||
uint32_t get_block_count(TBuffVecPtr multi)
|
||||
{
|
||||
TRWCache* cache = (TRWCache*)multi;
|
||||
if (NULL == cache) {
|
||||
return 0;
|
||||
} else {
|
||||
return cache->count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取cache的第一块数据指针
|
||||
* @param multi -管理块指针
|
||||
* @return 第一块数据指针
|
||||
*/
|
||||
TBuffBlockPtr get_first_block(TBuffVecPtr multi)
|
||||
{
|
||||
TRWCache* cache = (TRWCache*)multi;
|
||||
if (NULL == cache) {
|
||||
return NULL;
|
||||
} else {
|
||||
return (TBuffBlockPtr)TAILQ_FIRST(&cache->list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取cache的下一块数据指针
|
||||
* @param multi -管理块指针
|
||||
* @param block -当前块指针
|
||||
* @return 下一块数据指针
|
||||
*/
|
||||
TBuffBlockPtr get_next_block(TBuffVecPtr multi, TBuffBlockPtr block)
|
||||
{
|
||||
TRWCache* cache = (TRWCache*)multi;
|
||||
TSkBuffer* item = (TSkBuffer*)block;
|
||||
if ((NULL == cache) || (NULL == item))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (TBuffBlockPtr)TAILQ_NEXT(item, entry);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取数据块的指针与数据长度
|
||||
* @param block -当前块指针
|
||||
* @param data -数据指针-modify参数
|
||||
* @param len -长度指针 modify参数
|
||||
*/
|
||||
void get_block_data(TBuffBlockPtr block, const void** data, int32_t* len)
|
||||
{
|
||||
TSkBuffer* item = (TSkBuffer*)block;
|
||||
if (NULL == block)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
*(uint8_t**)data = item->data;
|
||||
}
|
||||
|
||||
if (len != NULL)
|
||||
{
|
||||
*len = (int32_t)item->data_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取数据块的指针与数据长度
|
||||
* @param multi -管理块指针
|
||||
* @param data -数据写入区域指针
|
||||
* @param len -长度
|
||||
* @return 数据读取的数据长度
|
||||
*/
|
||||
uint32_t read_cache_data(TBuffVecPtr multi, void* data, uint32_t len)
|
||||
{
|
||||
TRWCache* cache = (TRWCache*)multi;
|
||||
if (NULL == cache) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t left_len = len;
|
||||
uint32_t offset = 0;
|
||||
TSkBuffer* item = NULL;
|
||||
TSkBuffer* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &cache->list, entry, tmp)
|
||||
{
|
||||
uint32_t copy_len = 0;
|
||||
if (left_len <= item->data_len)
|
||||
{
|
||||
copy_len = left_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_len = item->data_len;
|
||||
}
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
memcpy((char*)data + offset, item->data, copy_len);
|
||||
}
|
||||
offset += copy_len;
|
||||
left_len -= copy_len;
|
||||
|
||||
if (left_len <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取数据块的指针与数据长度
|
||||
* @param multi -管理块指针
|
||||
* @param data -数据写入区域指针
|
||||
* @param len -长度
|
||||
* @return 数据读取的数据长度
|
||||
*/
|
||||
uint32_t read_cache_begin(TBuffVecPtr multi, uint32_t begin, void* data, uint32_t len)
|
||||
{
|
||||
TRWCache* cache = (TRWCache*)multi;
|
||||
if (NULL == cache) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (begin >= cache->len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t pos_left = begin;
|
||||
uint32_t copy_left = len;
|
||||
uint32_t offset = 0;
|
||||
TSkBuffer* item = NULL;
|
||||
TAILQ_FOREACH(item, &cache->list, entry)
|
||||
{
|
||||
// 1. 开始位置有剩余, 则跳过该部分
|
||||
uint8_t* start_ptr = item->data;
|
||||
uint32_t real_left = item->data_len;
|
||||
if (pos_left > 0)
|
||||
{
|
||||
uint32_t skip_len = pos_left > real_left ? real_left : pos_left;
|
||||
pos_left -= skip_len;
|
||||
real_left -= skip_len;
|
||||
start_ptr += skip_len;
|
||||
}
|
||||
|
||||
// 2. 跳过后无长度剩余, 则等待下一块
|
||||
if (real_left == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. 有剩余, 尽力拷贝最大长度
|
||||
uint32_t copy_len = copy_left > real_left ? real_left : copy_left;
|
||||
if (data != NULL)
|
||||
{
|
||||
memcpy((char*)data + offset, start_ptr, copy_len);
|
||||
}
|
||||
offset += copy_len;
|
||||
copy_left -= copy_len;
|
||||
if (copy_left == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename mt_cache.h
|
||||
* @info TCP接入buffer管理定义
|
||||
*/
|
||||
|
||||
#ifndef ___MT_BUFFER_CACHE_H
|
||||
#define ___MT_BUFFER_CACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
|
||||
// 默认的buff大小
|
||||
#define SK_DFLT_BUFF_SIZE 64*1024
|
||||
#define SK_DFLT_ALIGN_SIZE 8
|
||||
|
||||
#define SK_ERR_NEED_CLOSE 10000
|
||||
|
||||
/**
|
||||
* @brief 用户态 buffer 结构定义
|
||||
*/
|
||||
typedef struct _sk_buffer_tag
|
||||
{
|
||||
TAILQ_ENTRY(_sk_buffer_tag) entry; // list entry buffer LRU等
|
||||
uint32_t last_time; // 上次使用时间戳
|
||||
uint32_t size; // buffer节点的空间大小
|
||||
uint8_t* head; // buff数据区头指针
|
||||
uint8_t* end; // buff数据区结束指针
|
||||
uint8_t* data; // 有效数据的头指针
|
||||
uint32_t data_len; // 有效的数据长度
|
||||
uint8_t buff[0]; // 原始指针区域
|
||||
} TSkBuffer;
|
||||
typedef TAILQ_HEAD(__sk_buff_list, _sk_buffer_tag) TSkBuffList; // multi 事务命令队列
|
||||
|
||||
|
||||
/**
|
||||
* @brief 申请指定大小的buff块
|
||||
* @param size 有效数据区大小
|
||||
* @return 非NULL为成功返回的buff指针
|
||||
*/
|
||||
TSkBuffer* new_sk_buffer(uint32_t size = SK_DFLT_BUFF_SIZE);
|
||||
|
||||
/**
|
||||
* @brief 释放指定的buff块
|
||||
* @param 待释放的buff指针
|
||||
*/
|
||||
void delete_sk_buffer(TSkBuffer* buff);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 保留更大长度信息(非资源池化的buff,可扩展)
|
||||
* @param buff -已有的buff指针
|
||||
* @param size -需要扩展的最终长度大小
|
||||
* @return 实际的buff信息
|
||||
*/
|
||||
TSkBuffer* reserve_sk_buffer(TSkBuffer* buff, uint32_t size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief buffer cache 管理
|
||||
*/
|
||||
typedef struct _sk_buff_mng_tag
|
||||
{
|
||||
TSkBuffList free_list; // buff链表
|
||||
uint32_t expired; // 超时时间
|
||||
uint32_t size; // buff大小
|
||||
uint32_t count; // 块个数
|
||||
} TSkBuffMng;
|
||||
|
||||
|
||||
/**
|
||||
* @brief cache 池的初始化接口
|
||||
* @param mng -管理池的指针
|
||||
* @param expired -保活的时间, 单位秒
|
||||
* @param size -本管理块默认生成的块大小
|
||||
*/
|
||||
void sk_buffer_mng_init(TSkBuffMng* mng, uint32_t expired, uint32_t size = SK_DFLT_BUFF_SIZE);
|
||||
|
||||
/**
|
||||
* @brief cache 池的销毁接口
|
||||
* @param mng -管理池的指针
|
||||
*/
|
||||
void sk_buffer_mng_destroy(TSkBuffMng * mng);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 申请或复用一块buff
|
||||
* @param mng -管理池的指针
|
||||
* @return 非NULL为成功获取的buff块指针
|
||||
*/
|
||||
TSkBuffer* alloc_sk_buffer(TSkBuffMng* mng);
|
||||
|
||||
/**
|
||||
* @brief 释放指定的buff块
|
||||
* @param mng -管理池的指针
|
||||
* @param buff -待释放的buff指针
|
||||
*/
|
||||
void free_sk_buffer(TSkBuffMng* mng, TSkBuffer* buff);
|
||||
|
||||
/**
|
||||
* @brief 回收过期的buff块
|
||||
* @param mng -管理池的指针
|
||||
* @param now -当前的时间, 秒级别
|
||||
*/
|
||||
void recycle_sk_buffer(TSkBuffMng* mng, uint32_t now);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 原始的 buffer cache 定义
|
||||
*/
|
||||
typedef struct _sk_rw_cache_tag
|
||||
{
|
||||
TSkBuffList list; // buff链表
|
||||
uint32_t len; // 数据长度
|
||||
uint32_t count; // 块个数
|
||||
TSkBuffMng *pool; // 全局buff池指针
|
||||
} TRWCache;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache管理链初始化
|
||||
* @param cache -管理块指针
|
||||
* @param pool -buff池指针
|
||||
*/
|
||||
void rw_cache_init(TRWCache* cache, TSkBuffMng* pool);
|
||||
|
||||
/**
|
||||
* @brief Cache管理链销毁
|
||||
* @param cache -管理块指针
|
||||
*/
|
||||
void rw_cache_destroy(TRWCache* cache);
|
||||
|
||||
/**
|
||||
* @brief Cache删除掉指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param len -待删除的长度
|
||||
*/
|
||||
void cache_skip_data(TRWCache* cache, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Cache移除第一块内存
|
||||
* @param cache -管理块指针
|
||||
*/
|
||||
TSkBuffer* cache_skip_first_buffer(TRWCache* cache);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache追加指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param data -待追加的指针
|
||||
* @param len -待追加的长度
|
||||
*/
|
||||
int32_t cache_append_data(TRWCache* cache, const void* data, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief Cache追加指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param buff -待追加的块指针
|
||||
*/
|
||||
void cache_append_buffer(TRWCache* cache, TSkBuffer* buff);
|
||||
|
||||
/**
|
||||
* @brief Cache删除并拷贝指定长度数据
|
||||
* @param cache -管理块指针
|
||||
* @param buff -存放buff的指针
|
||||
* @param len -待删除的长度
|
||||
* @return 实际拷贝长度
|
||||
*/
|
||||
uint32_t cache_copy_out(TRWCache* cache, void* buff, uint32_t len);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cache整合的UDP收报接口, 消耗内存比较多, 不建议32位使用
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备收报的fd句柄
|
||||
* @param remote_addr -对端ip地址
|
||||
* @return 实际接收长度
|
||||
*/
|
||||
int32_t cache_udp_recv(TRWCache* cache, uint32_t fd, struct sockaddr_in* remote_addr);
|
||||
|
||||
/**
|
||||
* @brief Cache整合的TCP收报接口
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备收报的fd句柄
|
||||
* @return 实际接收长度
|
||||
*/
|
||||
int32_t cache_tcp_recv(TRWCache* cache, uint32_t fd);
|
||||
|
||||
/**
|
||||
* @brief Cache整合的TCP发送接口
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备发包的fd句柄
|
||||
* @return 实际发送长度
|
||||
*/
|
||||
int32_t cache_tcp_send(TRWCache* cache, uint32_t fd);
|
||||
|
||||
/**
|
||||
* @brief Cache整合的TCP发送接口, 未使用IOVEC
|
||||
* @param cache -管理块指针
|
||||
* @param fd - 准备发包的fd句柄
|
||||
* @param data -发送完cache后, 继续发送的buff
|
||||
* @param len -继续发送的buff长度
|
||||
* @return 实际发送长度
|
||||
*/
|
||||
int32_t cache_tcp_send_buff(TRWCache* cache, uint32_t fd, const void* data, uint32_t len);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// interface
|
||||
typedef void* TBuffVecPtr; ///< 多个block的cache管理指针句柄
|
||||
typedef void* TBuffBlockPtr; ///< 单个管理块指针句柄
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取cache有效数据总长度
|
||||
* @param multi -管理块指针
|
||||
* @return 实际有效数据长度
|
||||
*/
|
||||
uint32_t get_data_len(TBuffVecPtr multi);
|
||||
|
||||
/**
|
||||
* @brief 获取cache有效数据块个数
|
||||
* @param multi -管理块指针
|
||||
* @return 实际有效数据块个数
|
||||
*/
|
||||
uint32_t get_block_count(TBuffVecPtr multi);
|
||||
|
||||
/**
|
||||
* @brief 获取cache的第一块数据指针
|
||||
* @param multi -管理块指针
|
||||
* @return 第一块数据指针
|
||||
*/
|
||||
TBuffBlockPtr get_first_block(TBuffVecPtr multi);
|
||||
|
||||
/**
|
||||
* @brief 获取cache的下一块数据指针
|
||||
* @param multi -管理块指针
|
||||
* @param block -当前块指针
|
||||
* @return 下一块数据指针
|
||||
*/
|
||||
TBuffBlockPtr get_next_block(TBuffVecPtr multi, TBuffBlockPtr block);
|
||||
|
||||
/**
|
||||
* @brief 获取数据块的指针与数据长度
|
||||
* @param block -当前块指针
|
||||
* @param data -数据指针-modify参数
|
||||
* @param len -长度指针 modify参数
|
||||
*/
|
||||
void get_block_data(TBuffBlockPtr block, const void** data, int32_t* len);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取数据块的指针与数据长度
|
||||
* @param multi -管理块指针
|
||||
* @param data -数据写入区域指针
|
||||
* @param len -长度
|
||||
* @return 数据读取的数据长度
|
||||
*/
|
||||
uint32_t read_cache_data(TBuffVecPtr multi, void* data, uint32_t len);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取数据块的指针与数据长度
|
||||
* @param multi -管理块指针
|
||||
* @param data -数据写入区域指针
|
||||
* @param len -长度
|
||||
* @return 数据读取的数据长度
|
||||
*/
|
||||
uint32_t read_cache_begin(TBuffVecPtr multi, uint32_t begin, void* data, uint32_t len);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,528 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_concurrent.c
|
||||
* @info 多路并处理模型扩展
|
||||
* @time 20130924
|
||||
**/
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_msg.h"
|
||||
#include "mt_notify.h"
|
||||
#include "mt_connection.h"
|
||||
#include "mt_concurrent.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 多路IO的处理优化, 异步调度等待处理
|
||||
* @param req_list - 连接列表
|
||||
* @param how - EPOLLIN EPOLLOUT
|
||||
* @param timeout - 超时时长 毫秒单位
|
||||
* @return 0 成功, <0失败 -3 处理超时
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_multi_netfd_poll(IMtActList& req_list, int how, int timeout)
|
||||
{
|
||||
KqObjList fdlist;
|
||||
TAILQ_INIT(&fdlist);
|
||||
|
||||
KqueuerObj* obj = NULL;
|
||||
IMtAction* action = NULL;
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
action = *it;
|
||||
if (action) {
|
||||
obj = action->GetNtfyObj();
|
||||
}
|
||||
if (!action || !obj)
|
||||
{
|
||||
action->SetErrno(ERR_FRAME_ERROR);
|
||||
MTLOG_ERROR("input action %p, or ntify null, error", action);
|
||||
return -1;
|
||||
}
|
||||
|
||||
obj->SetRcvEvents(0);
|
||||
if (how & KQ_EVENT_READ)
|
||||
{
|
||||
obj->EnableInput();
|
||||
}
|
||||
else
|
||||
{
|
||||
obj->DisableInput();
|
||||
}
|
||||
|
||||
if (how & KQ_EVENT_WRITE)
|
||||
{
|
||||
obj->EnableOutput();
|
||||
}
|
||||
else
|
||||
{
|
||||
obj->DisableOutput();
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&fdlist, obj, _entry);
|
||||
|
||||
}
|
||||
|
||||
MtFrame* mtframe = MtFrame::Instance();
|
||||
if (!mtframe || !mtframe->KqueueSchedule(&fdlist, NULL, (int)timeout))
|
||||
{
|
||||
if (errno != ETIME)
|
||||
{
|
||||
action->SetErrno(ERR_KQUEUE_FAIL);
|
||||
MTLOG_ERROR("Mtframe %p, epoll schedule failed, errno %d", mtframe, errno);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 为每个ITEM建立上下文的socket
|
||||
* @param req_list - 连接列表
|
||||
* @return 0 成功, <0失败
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_multi_newsock(IMtActList& req_list)
|
||||
{
|
||||
int sock = -1, has_ok = 0;
|
||||
IMtAction* action = NULL;
|
||||
IMtConnection* net_handler = NULL;
|
||||
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
action = *it;
|
||||
if (NULL == action)
|
||||
{
|
||||
action->SetErrno(ERR_PARAM_ERROR);
|
||||
MTLOG_ERROR("Invalid param, conn %p null!!", action);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (action->GetErrno() != ERR_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
net_handler = action->GetIConnection();
|
||||
if (NULL == net_handler)
|
||||
{
|
||||
action->SetErrno(ERR_FRAME_ERROR);
|
||||
MTLOG_ERROR("Invalid param, conn %p null!!", net_handler);
|
||||
return -2;
|
||||
}
|
||||
|
||||
sock = net_handler->CreateSocket();
|
||||
if (sock < 0)
|
||||
{
|
||||
action->SetErrno(ERR_SOCKET_FAIL);
|
||||
MTLOG_ERROR("Get sock data failed, ret %d, errno %d!!", sock, errno);
|
||||
return -3;
|
||||
}
|
||||
has_ok = 1;
|
||||
|
||||
if (action->GetProtoType() == MT_UDP)
|
||||
{
|
||||
action->SetMsgFlag(MULTI_FLAG_OPEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
action->SetMsgFlag(MULTI_FLAG_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_ok)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 多路IO的处理, 打开连接
|
||||
* @param req_list - 连接列表
|
||||
* @param timeout - 超时时长 毫秒单位
|
||||
* @return 0 成功, <0失败
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_multi_open(IMtActList& req_list, int timeout)
|
||||
{
|
||||
utime64_t start_ms = MtFrame::Instance()->GetLastClock();
|
||||
utime64_t end_ms = start_ms + timeout;
|
||||
utime64_t curr_ms = 0;
|
||||
|
||||
int ret = 0, has_open = 0;
|
||||
IMtAction* action = NULL;
|
||||
IMtConnection* net_handler = NULL;
|
||||
IMtActList::iterator it;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IMtActList wait_list;
|
||||
for (it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
action = *it;
|
||||
if (action->GetErrno() != ERR_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (action->GetMsgFlag() == MULTI_FLAG_OPEN) {
|
||||
has_open = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
net_handler = action->GetIConnection();
|
||||
if (NULL == net_handler)
|
||||
{
|
||||
action->SetErrno(ERR_FRAME_ERROR);
|
||||
MTLOG_ERROR("Invalid param, conn %p null!!", net_handler);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = net_handler->OpenCnnect();
|
||||
if (ret < 0)
|
||||
{
|
||||
wait_list.push_back(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
action->SetMsgFlag(MULTI_FLAG_OPEN);
|
||||
}
|
||||
}
|
||||
|
||||
curr_ms = MtFrame::Instance()->GetLastClock();
|
||||
if (curr_ms > end_ms)
|
||||
{
|
||||
MTLOG_DEBUG("Open connect timeout, errno %d", errno);
|
||||
for (IMtActList::iterator it = wait_list.begin(); it != wait_list.end(); ++it)
|
||||
{
|
||||
(*it)->SetErrno(ERR_CONNECT_FAIL);
|
||||
}
|
||||
|
||||
if (!has_open)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_list.empty())
|
||||
{
|
||||
mt_multi_netfd_poll(wait_list, KQ_EVENT_WRITE, end_ms - curr_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 多路IO的处理, 发送数据
|
||||
* @param req_list - 连接列表
|
||||
* @param timeout - 超时时长 毫秒单位
|
||||
* @return 0 成功, <0失败
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_multi_sendto(IMtActList& req_list, int timeout)
|
||||
{
|
||||
utime64_t start_ms = MtFrame::Instance()->GetLastClock();
|
||||
utime64_t end_ms = start_ms + timeout;
|
||||
utime64_t curr_ms = 0;
|
||||
|
||||
int ret = 0, has_send = 0;
|
||||
IMtAction* action = NULL;
|
||||
IMtConnection* net_handler = NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IMtActList wait_list;
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
action = *it;
|
||||
if (action->GetErrno() != ERR_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (action->GetMsgFlag() == MULTI_FLAG_SEND) {
|
||||
has_send = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
net_handler = action->GetIConnection();
|
||||
if (NULL == net_handler)
|
||||
{
|
||||
action->SetErrno(ERR_FRAME_ERROR);
|
||||
MTLOG_ERROR("Invalid param, conn %p null!!", net_handler);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// 0 -还要继续发送; -1 停止发送; > 0 发送OK
|
||||
ret = net_handler->SendData();
|
||||
if (ret == -1)
|
||||
{
|
||||
action->SetErrno(ERR_SEND_FAIL);
|
||||
MTLOG_ERROR("MultiItem msg send error, %d", errno);
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
wait_list.push_back(action);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
action->SetMsgFlag(MULTI_FLAG_SEND);
|
||||
}
|
||||
}
|
||||
|
||||
curr_ms = MtFrame::Instance()->GetLastClock();
|
||||
if (curr_ms > end_ms)
|
||||
{
|
||||
MTLOG_DEBUG("send data timeout");
|
||||
for (IMtActList::iterator it = wait_list.begin(); it != wait_list.end(); ++it)
|
||||
{
|
||||
(*it)->SetErrno(ERR_SEND_FAIL);
|
||||
}
|
||||
|
||||
if (has_send)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_list.empty())
|
||||
{
|
||||
mt_multi_netfd_poll(wait_list, KQ_EVENT_WRITE, end_ms - curr_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发接收处理
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_multi_recvfrom(IMtActList& req_list, int timeout)
|
||||
{
|
||||
utime64_t start_ms = MtFrame::Instance()->GetLastClock();
|
||||
utime64_t end_ms = start_ms + timeout;
|
||||
utime64_t curr_ms = 0;
|
||||
|
||||
int ret = 0;
|
||||
IMtAction* action = NULL;
|
||||
IMtConnection* net_handler = NULL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
IMtActList wait_list;
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
action = *it;
|
||||
if (action->GetErrno() != ERR_NONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MULTI_FLAG_FIN == action->GetMsgFlag()) ///< 已处理完毕
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
net_handler = action->GetIConnection();
|
||||
if (NULL == net_handler)
|
||||
{
|
||||
action->SetErrno(ERR_FRAME_ERROR);
|
||||
MTLOG_ERROR("Invalid param, conn %p null!!", net_handler);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// <0 失败, 0 继续收, >0 成功
|
||||
ret = net_handler->RecvData();
|
||||
if (ret < 0)
|
||||
{
|
||||
action->SetErrno(ERR_RECV_FAIL);
|
||||
MTLOG_ERROR("MultiItem msg recv failed: %p", net_handler);
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
wait_list.push_back(action);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
action->SetMsgFlag(MULTI_FLAG_FIN);
|
||||
action->SetCost(MtFrame::Instance()->GetLastClock() - start_ms);
|
||||
}
|
||||
}
|
||||
|
||||
curr_ms = MtFrame::Instance()->GetLastClock();
|
||||
if (curr_ms > end_ms)
|
||||
{
|
||||
MTLOG_DEBUG("Recv data timeout, curr %llu, start: %llu", curr_ms, start_ms);
|
||||
for (IMtActList::iterator it = wait_list.begin(); it != wait_list.end(); ++it)
|
||||
{
|
||||
(*it)->SetErrno(ERR_RECV_TIMEOUT);
|
||||
}
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (!wait_list.empty())
|
||||
{
|
||||
mt_multi_netfd_poll(wait_list, KQ_EVENT_READ, end_ms - curr_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发接收处理
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_multi_sendrcv_ex(IMtActList& req_list, int timeout)
|
||||
{
|
||||
utime64_t start_ms = MtFrame::Instance()->GetLastClock();
|
||||
utime64_t curr_ms = 0;
|
||||
|
||||
int rc = mt_multi_newsock(req_list); // TODO, 可提取connect超时时间等
|
||||
if (rc < 0)
|
||||
{
|
||||
MT_ATTR_API(320842, 1); // socket失败
|
||||
MTLOG_ERROR("mt_multi_sendrcv new sock failed, ret: %d", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = mt_multi_open(req_list, timeout);
|
||||
if (rc < 0)
|
||||
{
|
||||
MT_ATTR_API(320843, 1); // connect失败
|
||||
MTLOG_ERROR("mt_multi_sendrcv open failed, ret: %d", rc);
|
||||
return -2;
|
||||
}
|
||||
|
||||
curr_ms = MtFrame::Instance()->GetLastClock();
|
||||
rc = mt_multi_sendto(req_list, timeout - (curr_ms - start_ms));
|
||||
if (rc < 0)
|
||||
{
|
||||
MT_ATTR_API(320844, 1); // 发送失败
|
||||
MTLOG_ERROR("mt_multi_sendrcv send failed, ret: %d", rc);
|
||||
return -3;
|
||||
}
|
||||
|
||||
curr_ms = MtFrame::Instance()->GetLastClock();
|
||||
rc = mt_multi_recvfrom(req_list, timeout - (curr_ms - start_ms));
|
||||
if (rc < 0)
|
||||
{
|
||||
MT_ATTR_API(320845, 1); // 接收未完全成功
|
||||
MTLOG_ERROR("mt_multi_sendrcv recv failed, ret: %d", rc);
|
||||
return -4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发接收处理接口, 封装ACTON接口模型, 内部关联msg
|
||||
* @param req_list -action list 实现封装函数接口
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @return 0 成功, -1 初始化环境失败, 其它成功或部分成功
|
||||
*/
|
||||
int NS_MICRO_THREAD::mt_msg_sendrcv(IMtActList& req_list, int timeout)
|
||||
{
|
||||
int iRet = 0;
|
||||
|
||||
// 第一步, 初始化action环境, 封装请求报文
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
IMtAction* pAction = *it;
|
||||
if (!pAction || pAction->InitConnEnv() < 0)
|
||||
{
|
||||
MTLOG_ERROR("invalid action(%p) or int failed, error", pAction);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iRet = pAction->DoEncode();
|
||||
if (iRet < 0)
|
||||
{
|
||||
pAction->SetErrno(ERR_ENCODE_ERROR);
|
||||
MTLOG_ERROR("pack action pkg failed, act %p, ret %d", pAction, iRet);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 第二步, 同步收发消息, 失败也需要通知处理
|
||||
mt_multi_sendrcv_ex(req_list, timeout);
|
||||
|
||||
// 第三步, 同步通知解包处理
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
IMtAction* pAction = *it;
|
||||
|
||||
if (pAction->GetMsgFlag() != MULTI_FLAG_FIN)
|
||||
{
|
||||
pAction->DoError();
|
||||
MTLOG_DEBUG("send recv failed: %d", pAction->GetErrno());
|
||||
continue;
|
||||
}
|
||||
|
||||
iRet = pAction->DoProcess();
|
||||
if (iRet < 0)
|
||||
{
|
||||
MTLOG_DEBUG("action process failed: %d", iRet);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 第四步, 清理框架内部资源, 兼容各类用法
|
||||
for (IMtActList::iterator it = req_list.begin(); it != req_list.end(); ++it)
|
||||
{
|
||||
IMtAction* pAction = *it;
|
||||
pAction->Reset();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_concurrent.h
|
||||
* @info 扩展状态线程的处理模型
|
||||
* @time 20130515
|
||||
**/
|
||||
|
||||
#ifndef __MT_CONCURRENT_H__
|
||||
#define __MT_CONCURRENT_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <vector>
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
using std::vector;
|
||||
|
||||
class IMtAction;
|
||||
typedef vector<IMtAction*> IMtActList;
|
||||
|
||||
/******************************************************************************/
|
||||
/* 微线程用户接口定义: 微线程Action多路并发模型接口定义 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发接收处理接口, 封装ACTON接口模型, 内部关联msg
|
||||
* @param req_list -action list 实现封装函数接口
|
||||
* @param timeout -超时时间, 单位ms
|
||||
* @return 0 成功, -1 打开socket失败, -2 发送请求失败, -100 接收应答部分失败, 可打印errno
|
||||
*/
|
||||
int mt_msg_sendrcv(IMtActList& req_list, int timeout);
|
||||
|
||||
/******************************************************************************/
|
||||
/* 内部实现定义部分 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief 多路IO的处理优化, 异步调度等待处理
|
||||
* @param req_list - 连接列表
|
||||
* @param how - EPOLLIN EPOLLOUT
|
||||
* @param timeout - 超时时长 毫秒单位
|
||||
* @return 0 成功, <0失败 -3 处理超时
|
||||
*/
|
||||
int mt_multi_netfd_poll(IMtActList& req_list, int how, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 为每个ITEM建立上下文的socket
|
||||
* @param req_list - 连接列表
|
||||
* @return 0 成功, <0失败
|
||||
*/
|
||||
int mt_multi_newsock(IMtActList& req_list);
|
||||
|
||||
/**
|
||||
* @brief 多路IO的处理, 打开连接
|
||||
* @param req_list - 连接列表
|
||||
* @param timeout - 超时时长 毫秒单位
|
||||
* @return 0 成功, <0失败
|
||||
*/
|
||||
int mt_multi_open(IMtActList& req_list, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 多路IO的处理, 发送数据
|
||||
* @param req_list - 连接列表
|
||||
* @param timeout - 超时时长 毫秒单位
|
||||
* @return 0 成功, <0失败
|
||||
*/
|
||||
int mt_multi_sendto(IMtActList& req_list, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发接收处理
|
||||
*/
|
||||
int mt_multi_recvfrom(IMtActList& req_list, int timeout);
|
||||
|
||||
/**
|
||||
* @brief 多路IO并发接收处理
|
||||
*/
|
||||
int mt_multi_sendrcv_ex(IMtActList& req_list, int timeout);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,921 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_connection.cpp
|
||||
* @info 微线程消息交互连接管理实现
|
||||
* @time 20130924
|
||||
**/
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_msg.h"
|
||||
#include "mt_notify.h"
|
||||
#include "mt_connection.h"
|
||||
#include "mt_sys_hook.h"
|
||||
#include "ff_hook.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 微线程连接基类构造与析构
|
||||
*/
|
||||
IMtConnection::IMtConnection()
|
||||
{
|
||||
_type = OBJ_CONN_UNDEF;
|
||||
_action = NULL;
|
||||
_ntfy_obj = NULL;
|
||||
_msg_buff = NULL;
|
||||
}
|
||||
IMtConnection::~IMtConnection()
|
||||
{
|
||||
if (_ntfy_obj) {
|
||||
NtfyObjMgr::Instance()->FreeNtfyObj(_ntfy_obj);
|
||||
_ntfy_obj = NULL;
|
||||
}
|
||||
|
||||
if (_msg_buff) {
|
||||
MsgBuffPool::Instance()->FreeMsgBuf(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
void IMtConnection::Reset()
|
||||
{
|
||||
if (_ntfy_obj) {
|
||||
NtfyObjMgr::Instance()->FreeNtfyObj(_ntfy_obj);
|
||||
_ntfy_obj = NULL;
|
||||
}
|
||||
|
||||
if (_msg_buff) {
|
||||
MsgBuffPool::Instance()->FreeMsgBuf(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
}
|
||||
|
||||
_action = NULL;
|
||||
_ntfy_obj = NULL;
|
||||
_msg_buff = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接的socket建立, 依赖连接的协议类型等
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
int UdpShortConn::CreateSocket()
|
||||
{
|
||||
// 1. UDP短连接, 每次新创SOCKET
|
||||
_osfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (_osfd < 0)
|
||||
{
|
||||
MTLOG_ERROR("socket create failed, errno %d(%s)", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2. 非阻塞设置
|
||||
int flags = 1;
|
||||
if (ioctl(_osfd, FIONBIO, &flags) < 0)
|
||||
{
|
||||
MTLOG_ERROR("socket unblock failed, errno %d(%s)", errno, strerror(errno));
|
||||
close(_osfd);
|
||||
_osfd = -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
// 3. 更新管理信息
|
||||
if (_ntfy_obj) {
|
||||
_ntfy_obj->SetOsfd(_osfd);
|
||||
}
|
||||
|
||||
return _osfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭系统socket, 重置一些状态
|
||||
*/
|
||||
int UdpShortConn::CloseSocket()
|
||||
{
|
||||
if (_osfd < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(_osfd);
|
||||
_osfd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 尝试发送数据, 仅发送一次
|
||||
* @return 0 发送被中断, 需重试. <0 系统失败. >0 本次发送成功
|
||||
*/
|
||||
int UdpShortConn::SendData()
|
||||
{
|
||||
if (!_action || !_msg_buff) {
|
||||
MTLOG_ERROR("conn not set action %p, or msg %p, error", _action, _msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
mt_hook_syscall(sendto);
|
||||
int ret = ff_hook_sendto(_osfd, _msg_buff->GetMsgBuff(), _msg_buff->GetMsgLen(), 0,
|
||||
(struct sockaddr*)_action->GetMsgDstAddr(), sizeof(struct sockaddr_in));
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EINPROGRESS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("socket send failed, fd %d, errno %d(%s)", _osfd,
|
||||
errno, strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_msg_buff->SetHaveSndLen(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尝试接收数据, 仅接收一次
|
||||
* @param buff 接收缓冲区指针
|
||||
* @return -1 对端关闭. -2 系统失败. >0 本次接收成功
|
||||
*/
|
||||
int UdpShortConn::RecvData()
|
||||
{
|
||||
if (!_action || !_msg_buff) {
|
||||
MTLOG_ERROR("conn not set action %p, or msg %p, error", _action, _msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
struct sockaddr_in from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
mt_hook_syscall(recvfrom);
|
||||
int ret = ff_hook_recvfrom(_osfd, _msg_buff->GetMsgBuff(), _msg_buff->GetMaxLen(),
|
||||
0, (struct sockaddr*)&from, &fromlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EINPROGRESS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("socket recv failed, fd %d, errno %d(%s)", _osfd,
|
||||
errno, strerror(errno));
|
||||
return -2; // 系统错误
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
return -1; // 对端关闭
|
||||
}
|
||||
else
|
||||
{
|
||||
_msg_buff->SetHaveRcvLen(ret);
|
||||
}
|
||||
|
||||
// 上下文检查, >0 收包完整; =0 继续等待; <0(-65535串包)其它异常
|
||||
ret = _action->DoInput();
|
||||
if (ret > 0)
|
||||
{
|
||||
_msg_buff->SetMsgLen(ret);
|
||||
return ret;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (ret == -65535)
|
||||
{
|
||||
_msg_buff->SetHaveRcvLen(0);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
void UdpShortConn::Reset()
|
||||
{
|
||||
CloseSocket();
|
||||
this->IMtConnection::Reset();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接打开与远端会话通道, 如TCP的connect等
|
||||
* @return 0 -成功, < 0 失败
|
||||
*/
|
||||
int TcpKeepConn::OpenCnnect()
|
||||
{
|
||||
if (!_action || !_msg_buff) {
|
||||
MTLOG_ERROR("conn not set action %p, or msg %p, error", _action, _msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
mt_hook_syscall(connect);
|
||||
int ret = ff_hook_connect(_osfd, (struct sockaddr*)_action->GetMsgDstAddr(), sizeof(struct sockaddr_in));
|
||||
if (ret < 0)
|
||||
{
|
||||
err = errno;
|
||||
if (err == EISCONN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((err == EINPROGRESS) || (err == EALREADY) || (err == EINTR))
|
||||
{
|
||||
MTLOG_DEBUG("Open connect not ok, maybe first try, sock %d, errno %d", _osfd, err);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("Open connect not ok, sock %d, errno %d", _osfd, err);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 基于sock的TCP复用连接
|
||||
*/
|
||||
int TcpKeepConn::CreateSocket()
|
||||
{
|
||||
if (_osfd > 0) // 复用连接时, 可跳过创建处理; 不能跳过设置ntfyfd
|
||||
{
|
||||
if (_ntfy_obj) {
|
||||
_ntfy_obj->SetOsfd(_osfd);
|
||||
}
|
||||
|
||||
return _osfd;
|
||||
}
|
||||
|
||||
// 第一次进入时, 创建socket
|
||||
_osfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_osfd < 0)
|
||||
{
|
||||
MTLOG_ERROR("create tcp socket failed, error: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 非阻塞设置
|
||||
int flags = 1;
|
||||
if (ioctl(_osfd, FIONBIO, &flags) < 0)
|
||||
{
|
||||
MTLOG_ERROR("set tcp socket unblock failed, error: %d", errno);
|
||||
close(_osfd);
|
||||
_osfd = -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
// 更新管理信息
|
||||
_keep_ntfy.SetOsfd(_osfd);
|
||||
_keep_ntfy.DisableOutput();
|
||||
_keep_ntfy.EnableInput();
|
||||
|
||||
if (_ntfy_obj) {
|
||||
_ntfy_obj->SetOsfd(_osfd);
|
||||
}
|
||||
|
||||
return _osfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尝试发送数据, 仅发送一次
|
||||
* @param dst 发送目的地址
|
||||
* @param buff 发送缓冲区指针
|
||||
* @param size 待发送的最大长度
|
||||
* @return 0 发送被中断, 需重试. <0 系统失败. >0 本次发送成功
|
||||
*/
|
||||
int TcpKeepConn::SendData()
|
||||
{
|
||||
if (!_action || !_msg_buff) {
|
||||
MTLOG_ERROR("conn not set action %p, or msg %p, error", _action, _msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
char* msg_ptr = (char*)_msg_buff->GetMsgBuff();
|
||||
int msg_len = _msg_buff->GetMsgLen();
|
||||
int have_send_len = _msg_buff->GetHaveSndLen();
|
||||
mt_hook_syscall(send);
|
||||
int ret = ff_hook_send(_osfd, msg_ptr + have_send_len, msg_len - have_send_len, 0);
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EINPROGRESS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("send tcp socket failed, error: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
have_send_len += ret;
|
||||
_msg_buff->SetHaveSndLen(have_send_len);
|
||||
}
|
||||
|
||||
// 全部发送完毕, 返回成功, 否则继续等待
|
||||
if (have_send_len >= msg_len)
|
||||
{
|
||||
return msg_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尝试接收数据, 仅接收一次
|
||||
* @param buff 接收缓冲区指针
|
||||
* @return -1 对端关闭. -2 系统失败. >0 本次接收成功
|
||||
*/
|
||||
int TcpKeepConn::RecvData()
|
||||
{
|
||||
if (!_action || !_msg_buff) {
|
||||
MTLOG_ERROR("conn not set action %p, or msg %p, error", _action, _msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
char* msg_ptr = (char*)_msg_buff->GetMsgBuff();
|
||||
int max_len = _msg_buff->GetMaxLen();
|
||||
int have_rcv_len = _msg_buff->GetHaveRcvLen();
|
||||
mt_hook_syscall(recv);
|
||||
int ret = ff_hook_recv(_osfd, (char*)msg_ptr + have_rcv_len, max_len - have_rcv_len, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EINPROGRESS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("recv tcp socket failed, error: %d", errno);
|
||||
return -2; // 系统错误
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
MTLOG_ERROR("tcp remote close, address: %s[%d]",
|
||||
inet_ntoa(_dst_addr.sin_addr), ntohs(_dst_addr.sin_port));
|
||||
return -1; // 对端关闭
|
||||
}
|
||||
else
|
||||
{
|
||||
have_rcv_len += ret;
|
||||
_msg_buff->SetHaveRcvLen(have_rcv_len);
|
||||
}
|
||||
|
||||
// 上下文检查, >0 收包完整; =0 继续等待; <0(-65535串包)其它异常
|
||||
ret = _action->DoInput();
|
||||
if (ret > 0)
|
||||
{
|
||||
_msg_buff->SetMsgLen(have_rcv_len);
|
||||
return ret;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭系统socket, 重置一些状态
|
||||
*/
|
||||
int TcpKeepConn::CloseSocket()
|
||||
{
|
||||
if (_osfd < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_keep_ntfy.SetOsfd(-1);
|
||||
|
||||
close(_osfd);
|
||||
_osfd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
void TcpKeepConn::Reset()
|
||||
{
|
||||
memset(&_dst_addr, 0 ,sizeof(_dst_addr));
|
||||
CloseSocket();
|
||||
this->IMtConnection::Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
void TcpKeepConn::ConnReuseClean()
|
||||
{
|
||||
this->IMtConnection::Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Idle缓存处理, epoll 侦听远端关闭等
|
||||
*/
|
||||
bool TcpKeepConn::IdleAttach()
|
||||
{
|
||||
if (_osfd < 0) {
|
||||
MTLOG_ERROR("obj %p attach failed, fd %d error", this, _osfd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_keep_flag & TCP_KEEP_IN_KQUEUE) {
|
||||
MTLOG_ERROR("obj %p repeat attach, error", this);
|
||||
return true;
|
||||
}
|
||||
|
||||
_keep_ntfy.DisableOutput();
|
||||
_keep_ntfy.EnableInput();
|
||||
|
||||
// 保活定时器添加
|
||||
CTimerMng* timer = MtFrame::Instance()->GetTimerMng();
|
||||
if ((NULL == timer) || !timer->start_timer(this, _keep_time))
|
||||
{
|
||||
MTLOG_ERROR("obj %p attach timer failed, error", this);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MtFrame::Instance()->KqueueAddObj(&_keep_ntfy))
|
||||
{
|
||||
_keep_flag |= TCP_KEEP_IN_KQUEUE;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("obj %p attach failed, error", this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Idle取消缓存处理, 不再由空闲线程侦听远端关闭
|
||||
*/
|
||||
bool TcpKeepConn::IdleDetach()
|
||||
{
|
||||
if (_osfd < 0) {
|
||||
MTLOG_ERROR("obj %p detach failed, fd %d error", this, _osfd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(_keep_flag & TCP_KEEP_IN_KQUEUE)) {
|
||||
MTLOG_DEBUG("obj %p repeat detach, error", this);
|
||||
return true;
|
||||
}
|
||||
|
||||
_keep_ntfy.DisableOutput();
|
||||
_keep_ntfy.EnableInput();
|
||||
|
||||
// 保活定时器删除
|
||||
CTimerMng* timer = MtFrame::Instance()->GetTimerMng();
|
||||
if (NULL != timer)
|
||||
{
|
||||
timer->stop_timer(this);
|
||||
}
|
||||
|
||||
if (MtFrame::Instance()->KqueueDelObj(&_keep_ntfy))
|
||||
{
|
||||
_keep_flag &= ~TCP_KEEP_IN_KQUEUE;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("obj %p detach failed, error", this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 超时通知函数, 子类实现逻辑
|
||||
*/
|
||||
void TcpKeepConn::timer_notify()
|
||||
{
|
||||
MTLOG_DEBUG("keep timeout[%u], fd %d, close connection", _keep_time, _osfd);
|
||||
ConnectionMgr::Instance()->CloseIdleTcpKeep(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
TcpKeepMgr::TcpKeepMgr()
|
||||
{
|
||||
_keep_hash = new HashList(10000);
|
||||
}
|
||||
|
||||
TcpKeepMgr::~TcpKeepMgr()
|
||||
{
|
||||
if (!_keep_hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashKey* hash_item = _keep_hash->HashGetFirst();
|
||||
while (hash_item)
|
||||
{
|
||||
delete hash_item;
|
||||
hash_item = _keep_hash->HashGetFirst();
|
||||
}
|
||||
|
||||
delete _keep_hash;
|
||||
_keep_hash = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按IP地址获取TCP的保持连接
|
||||
*/
|
||||
TcpKeepConn* TcpKeepMgr::GetTcpKeepConn(struct sockaddr_in* dst)
|
||||
{
|
||||
TcpKeepConn* conn = NULL;
|
||||
if (NULL == dst)
|
||||
{
|
||||
MTLOG_ERROR("input param dst null, error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TcpKeepKey key(dst);
|
||||
TcpKeepKey* conn_list = (TcpKeepKey*)_keep_hash->HashFindData(&key);
|
||||
if ((NULL == conn_list) || (NULL == conn_list->GetFirstConn()))
|
||||
{
|
||||
conn = _mem_queue.AllocPtr();
|
||||
if (conn) {
|
||||
conn->SetDestAddr(dst);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
conn = conn_list->GetFirstConn();
|
||||
conn_list->RemoveConn(conn);
|
||||
conn->IdleDetach();
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 按IP地址缓存TCP的保持连接
|
||||
*/
|
||||
bool TcpKeepMgr::RemoveTcpKeepConn(TcpKeepConn* conn)
|
||||
{
|
||||
struct sockaddr_in* dst = conn->GetDestAddr();
|
||||
if ((dst->sin_addr.s_addr == 0) || (dst->sin_port == 0))
|
||||
{
|
||||
MTLOG_ERROR("sock addr, invalid, %x:%d", dst->sin_addr.s_addr, dst->sin_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
TcpKeepKey key(dst);
|
||||
TcpKeepKey* conn_list = (TcpKeepKey*)_keep_hash->HashFindData(&key);
|
||||
if (!conn_list)
|
||||
{
|
||||
MTLOG_ERROR("no conn cache list, invalid, %x:%d", dst->sin_addr.s_addr, dst->sin_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
conn->IdleDetach();
|
||||
conn_list->RemoveConn(conn);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按IP地址缓存TCP的保持连接
|
||||
*/
|
||||
bool TcpKeepMgr::CacheTcpKeepConn(TcpKeepConn* conn)
|
||||
{
|
||||
struct sockaddr_in* dst = conn->GetDestAddr();
|
||||
if ((dst->sin_addr.s_addr == 0) || (dst->sin_port == 0))
|
||||
{
|
||||
MTLOG_ERROR("sock addr, invalid, %x:%d", dst->sin_addr.s_addr, dst->sin_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
TcpKeepKey key(dst);
|
||||
TcpKeepKey* conn_list = (TcpKeepKey*)_keep_hash->HashFindData(&key);
|
||||
if (!conn_list)
|
||||
{
|
||||
conn_list = new TcpKeepKey(conn->GetDestAddr());
|
||||
if (!conn_list) {
|
||||
MTLOG_ERROR("new conn list failed, error");
|
||||
return false;
|
||||
}
|
||||
_keep_hash->HashInsert(conn_list);
|
||||
}
|
||||
|
||||
if (!conn->IdleAttach())
|
||||
{
|
||||
MTLOG_ERROR("conn IdleAttach failed, error");
|
||||
return false;
|
||||
}
|
||||
|
||||
conn->ConnReuseClean();
|
||||
conn_list->InsertConn(conn);
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭或缓存tcp长连接
|
||||
*/
|
||||
void TcpKeepMgr::FreeTcpKeepConn(TcpKeepConn* conn, bool force_free)
|
||||
{
|
||||
if (force_free)
|
||||
{
|
||||
conn->Reset();
|
||||
_mem_queue.FreePtr(conn);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!CacheTcpKeepConn(conn))
|
||||
{
|
||||
conn->Reset();
|
||||
_mem_queue.FreePtr(conn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接的socket建立, 依赖连接的协议类型等
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
int UdpSessionConn::CreateSocket()
|
||||
{
|
||||
// 1. session连接类, 由通知对象创建管理fd
|
||||
if (!_action || !_ntfy_obj) {
|
||||
MTLOG_ERROR("conn not set action %p, or _ntfy_obj %p, error", _action, _ntfy_obj);
|
||||
return -100;
|
||||
}
|
||||
SessionProxy* proxy = dynamic_cast<SessionProxy*>(_ntfy_obj);
|
||||
if (!proxy) {
|
||||
MTLOG_ERROR("ntfy obj not match, _ntfy_obj %p, error", _ntfy_obj);
|
||||
return -200;
|
||||
}
|
||||
ISessionNtfy* real_ntfy = proxy->GetRealNtfyObj();
|
||||
if (!real_ntfy) {
|
||||
MTLOG_ERROR("real ntfy obj not match, _ntfy_obj %p, error", _ntfy_obj);
|
||||
return -300;
|
||||
}
|
||||
|
||||
// 2. 委派创建, 更新句柄信息
|
||||
int osfd = real_ntfy->GetOsfd();
|
||||
if (osfd <= 0)
|
||||
{
|
||||
osfd = real_ntfy->CreateSocket();
|
||||
if (osfd <= 0) {
|
||||
MTLOG_ERROR("real ntfy obj create fd failed, _ntfy_obj %p, error", real_ntfy);
|
||||
return -400;
|
||||
}
|
||||
}
|
||||
_ntfy_obj->SetOsfd(osfd);
|
||||
|
||||
return osfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭系统socket, 重置一些状态
|
||||
*/
|
||||
int UdpSessionConn::CloseSocket()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 尝试发送数据, 仅发送一次
|
||||
* @return 0 发送被中断, 需重试. <0 系统失败. >0 本次发送成功
|
||||
*/
|
||||
int UdpSessionConn::SendData()
|
||||
{
|
||||
if (!_action || !_msg_buff || !_ntfy_obj) {
|
||||
MTLOG_ERROR("conn not set action %p, or msg %p, ntfy %p error", _action, _msg_buff, _ntfy_obj);
|
||||
return -100;
|
||||
}
|
||||
|
||||
mt_hook_syscall(sendto);
|
||||
int ret = ff_hook_sendto(_ntfy_obj->GetOsfd(), _msg_buff->GetMsgBuff(), _msg_buff->GetMsgLen(), 0,
|
||||
(struct sockaddr*)_action->GetMsgDstAddr(), sizeof(struct sockaddr_in));
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EINPROGRESS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("socket send failed, fd %d, errno %d(%s)", _ntfy_obj->GetOsfd(),
|
||||
errno, strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_msg_buff->SetHaveSndLen(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尝试接收数据, 仅接收一次
|
||||
* @param buff 接收缓冲区指针
|
||||
* @return 0 -继续等待接收; >0 接收成功; < 0 失败
|
||||
*/
|
||||
int UdpSessionConn::RecvData()
|
||||
{
|
||||
if (!_ntfy_obj || !_msg_buff) {
|
||||
MTLOG_ERROR("conn not set _ntfy_obj %p, or msg %p, error", _ntfy_obj, _msg_buff);
|
||||
return -100;
|
||||
}
|
||||
|
||||
if (_ntfy_obj->GetRcvEvents() <= 0) {
|
||||
MTLOG_DEBUG("conn _ntfy_obj %p, no recv event, retry it", _ntfy_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// UDP Session 通知会替换msg buff, 通过type判定
|
||||
int msg_len = _msg_buff->GetMsgLen();
|
||||
if (BUFF_RECV == _msg_buff->GetBuffType())
|
||||
{
|
||||
return msg_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_DEBUG("conn msg buff %p, no recv comm", _msg_buff);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief session全局管理句柄
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
ConnectionMgr* ConnectionMgr::_instance = NULL;
|
||||
ConnectionMgr* ConnectionMgr::Instance (void)
|
||||
{
|
||||
if (NULL == _instance)
|
||||
{
|
||||
_instance = new ConnectionMgr();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief session管理全局的销毁接口
|
||||
*/
|
||||
void ConnectionMgr::Destroy()
|
||||
{
|
||||
if( _instance != NULL )
|
||||
{
|
||||
delete _instance;
|
||||
_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
ConnectionMgr::ConnectionMgr()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数, 不持有资源, 并不负责清理
|
||||
*/
|
||||
ConnectionMgr::~ConnectionMgr()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取接口
|
||||
*/
|
||||
IMtConnection* ConnectionMgr::GetConnection(CONN_OBJ_TYPE type, struct sockaddr_in* dst)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OBJ_SHORT_CONN:
|
||||
return _udp_short_queue.AllocPtr();
|
||||
break;
|
||||
|
||||
case OBJ_TCP_KEEP:
|
||||
return _tcp_keep_mgr.GetTcpKeepConn(dst);
|
||||
break;
|
||||
|
||||
case OBJ_UDP_SESSION:
|
||||
return _udp_session_queue.AllocPtr();
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 回收接口
|
||||
*/
|
||||
void ConnectionMgr::FreeConnection(IMtConnection* conn, bool force_free)
|
||||
{
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
CONN_OBJ_TYPE type = conn->GetConnType();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case OBJ_SHORT_CONN:
|
||||
conn->Reset();
|
||||
return _udp_short_queue.FreePtr(dynamic_cast<UdpShortConn*>(conn));
|
||||
break;
|
||||
|
||||
case OBJ_TCP_KEEP:
|
||||
return _tcp_keep_mgr.FreeTcpKeepConn(dynamic_cast<TcpKeepConn*>(conn), force_free);
|
||||
break;
|
||||
|
||||
case OBJ_UDP_SESSION:
|
||||
conn->Reset();
|
||||
return _udp_session_queue.FreePtr(dynamic_cast<UdpSessionConn*>(conn));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
delete conn;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 关闭idle的tcp长连接
|
||||
*/
|
||||
void ConnectionMgr::CloseIdleTcpKeep(TcpKeepConn* conn)
|
||||
{
|
||||
_tcp_keep_mgr.RemoveTcpKeepConn(conn);
|
||||
_tcp_keep_mgr.FreeTcpKeepConn(conn, true);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,563 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_connection.h
|
||||
* @info 微线程连接管理定义部分
|
||||
* @time 20130924
|
||||
**/
|
||||
|
||||
#ifndef __MT_CONNECTION_H__
|
||||
#define __MT_CONNECTION_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <queue>
|
||||
#include "mt_mbuf_pool.h"
|
||||
#include "hash_list.h"
|
||||
#include "mt_action.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
using std::queue;
|
||||
|
||||
/**
|
||||
* @brief 连接对象类型
|
||||
*/
|
||||
enum CONN_OBJ_TYPE
|
||||
{
|
||||
OBJ_CONN_UNDEF = 0, ///< 未定义的连接对象
|
||||
OBJ_SHORT_CONN = 1, ///< 短连接对象, fd关联会话, 每次用完CLOSE
|
||||
OBJ_TCP_KEEP = 2, ///< TCP的复用模型, 每次每连接使用该fd, 用完可复用
|
||||
OBJ_UDP_SESSION = 3, ///< UDP的session模型, 每连接可供任意线程使用
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 微线程一个后端请求, 映射一个连接对象
|
||||
*/
|
||||
class IMtConnection
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 微线程连接基类构造与析构
|
||||
*/
|
||||
IMtConnection();
|
||||
virtual ~IMtConnection();
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
virtual void Reset();
|
||||
|
||||
/**
|
||||
* @brief 获取连接对象的类型信息
|
||||
*/
|
||||
CONN_OBJ_TYPE GetConnType() {
|
||||
return _type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置内部ACTION指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
void SetIMtActon(IMtAction* action ) {
|
||||
_action = action;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取内部ACTION指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
IMtAction* GetIMtActon() {
|
||||
return _action;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置内部ACTION指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
void SetNtfyObj(KqueuerObj* obj ) {
|
||||
_ntfy_obj = obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取内部ACTION指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
KqueuerObj* GetNtfyObj() {
|
||||
return _ntfy_obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置内部msgbuff指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
void SetMtMsgBuff(MtMsgBuf* msg_buf) {
|
||||
_msg_buff = msg_buf;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取内部msgbuff指针
|
||||
* @return IMtConn指针
|
||||
*/
|
||||
MtMsgBuf* GetMtMsgBuff() {
|
||||
return _msg_buff;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 连接的socket建立, 依赖连接的协议类型等
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CreateSocket() {return 0;};
|
||||
|
||||
/**
|
||||
* @brief 连接打开与远端会话通道, 如TCP的connect等
|
||||
* @return 0 -成功, < 0 失败
|
||||
*/
|
||||
virtual int OpenCnnect() {return 0;};
|
||||
|
||||
/**
|
||||
* @brief 连接发送数据
|
||||
* @return >0 -成功, 返回实际发送长度, < 0 失败
|
||||
*/
|
||||
virtual int SendData() {return 0;};
|
||||
|
||||
/**
|
||||
* @brief 连接接收数据
|
||||
* @return >0 -成功, 返回本次接收长度, < 0 失败(-1 对端关闭; -2 接收错误)
|
||||
*/
|
||||
virtual int RecvData() {return 0;};
|
||||
|
||||
/**
|
||||
* @brief 关闭socket端口
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CloseSocket() {return 0;};
|
||||
|
||||
protected:
|
||||
|
||||
CONN_OBJ_TYPE _type; // 预置的type, 可按type做工厂管理
|
||||
IMtAction* _action; // 关联的action指针, 上级指针, 不关心资源生存期
|
||||
KqueuerObj* _ntfy_obj; // EPOLL通知对象, 下级指针, 关心生存期
|
||||
MtMsgBuf* _msg_buff; // 动态管理的buff字段, 下级指针, 关心生存期
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基于sock的短连接类型
|
||||
*/
|
||||
class UdpShortConn : public IMtConnection
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 基于socket的短连接的构造与析构
|
||||
*/
|
||||
UdpShortConn() {
|
||||
_osfd = -1;
|
||||
_type = OBJ_SHORT_CONN;
|
||||
};
|
||||
virtual ~UdpShortConn() {
|
||||
CloseSocket();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
virtual void Reset();
|
||||
|
||||
/**
|
||||
* @brief 连接的socket建立, 依赖连接的协议类型等
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CreateSocket();
|
||||
|
||||
/**
|
||||
* @brief 连接发送数据
|
||||
* @return >0 -成功, 返回实际发送长度, < 0 失败
|
||||
*/
|
||||
virtual int SendData();
|
||||
|
||||
/**
|
||||
* @brief 连接接收数据
|
||||
* @return >0 -成功, 返回本次接收长度, < 0 失败(-1 对端关闭; -2 接收错误)
|
||||
*/
|
||||
virtual int RecvData();
|
||||
|
||||
/**
|
||||
* @brief 关闭socket端口
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CloseSocket();
|
||||
|
||||
protected:
|
||||
int _osfd; // 每次连接单独创建socket
|
||||
};
|
||||
|
||||
|
||||
enum TcpKeepFlag
|
||||
{
|
||||
TCP_KEEP_IN_LIST = 0x1,
|
||||
TCP_KEEP_IN_KQUEUE = 0x2,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基于session的UDP复用连接
|
||||
*/
|
||||
class UdpSessionConn : public IMtConnection
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 基于socket的短连接的构造与析构
|
||||
*/
|
||||
UdpSessionConn() {
|
||||
_type = OBJ_UDP_SESSION;
|
||||
};
|
||||
virtual ~UdpSessionConn() { };
|
||||
|
||||
/**
|
||||
* @brief 连接的socket建立, 依赖连接的协议类型等
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CreateSocket();
|
||||
|
||||
/**
|
||||
* @brief 连接发送数据
|
||||
* @return >0 -成功, 返回实际发送长度, < 0 失败
|
||||
*/
|
||||
virtual int SendData();
|
||||
|
||||
/**
|
||||
* @brief 连接接收数据
|
||||
* @return >0 -成功, 返回本次接收长度, < 0 失败(-1 对端关闭; -2 接收错误)
|
||||
*/
|
||||
virtual int RecvData();
|
||||
|
||||
/**
|
||||
* @brief 关闭socket端口
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CloseSocket();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 基于sock的TCP复用连接
|
||||
*/
|
||||
typedef TAILQ_ENTRY(TcpKeepConn) KeepConnLink;
|
||||
typedef TAILQ_HEAD(__KeepConnTailq, TcpKeepConn) KeepConnList;
|
||||
class TcpKeepConn : public IMtConnection, public CTimerNotify
|
||||
{
|
||||
public:
|
||||
|
||||
int _keep_flag; // 队列状态标记
|
||||
KeepConnLink _keep_entry; // 队列管理入口
|
||||
|
||||
/**
|
||||
* @brief 基于socket的短连接的构造与析构
|
||||
*/
|
||||
TcpKeepConn() {
|
||||
_osfd = -1;
|
||||
_keep_time = 10*60*1000; // 默认10分钟, 可以按需调整
|
||||
_keep_flag = 0;
|
||||
_type = OBJ_TCP_KEEP;
|
||||
_keep_ntfy.SetKeepNtfyObj(this);
|
||||
};
|
||||
virtual ~TcpKeepConn() {
|
||||
CloseSocket();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 连接回收复用清理操作
|
||||
*/
|
||||
virtual void Reset();
|
||||
|
||||
/**
|
||||
* @brief 连接打开与远端会话通道, 如TCP的connect等
|
||||
* @return 0 -成功, < 0 失败
|
||||
*/
|
||||
virtual int OpenCnnect();
|
||||
|
||||
/**
|
||||
* @brief 连接的socket建立, 依赖连接的协议类型等
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CreateSocket();
|
||||
|
||||
/**
|
||||
* @brief 连接发送数据
|
||||
* @return >0 -成功, 返回实际发送长度, < 0 失败
|
||||
*/
|
||||
virtual int SendData();
|
||||
|
||||
/**
|
||||
* @brief 连接接收数据
|
||||
* @return >0 -成功, 返回本次接收长度, < 0 失败(-1 对端关闭; -2 接收错误)
|
||||
*/
|
||||
virtual int RecvData();
|
||||
|
||||
/**
|
||||
* @brief 关闭socket端口
|
||||
* @return >0 -成功, 返回系统fd, < 0 失败
|
||||
*/
|
||||
virtual int CloseSocket();
|
||||
|
||||
/**
|
||||
* @brief 连接保持复用
|
||||
*/
|
||||
void ConnReuseClean();
|
||||
|
||||
/**
|
||||
* @brief Idle缓存处理, epoll 侦听远端关闭等
|
||||
*/
|
||||
bool IdleAttach();
|
||||
|
||||
/**
|
||||
* @brief Idle取消缓存处理, 不再由空闲线程侦听远端关闭
|
||||
*/
|
||||
bool IdleDetach();
|
||||
|
||||
/**
|
||||
* @brief 存储目的地址信息, 用于复用
|
||||
*/
|
||||
void SetDestAddr(struct sockaddr_in* dst) {
|
||||
memcpy(&_dst_addr, dst, sizeof(_dst_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取目的地址信息
|
||||
*/
|
||||
struct sockaddr_in* GetDestAddr() {
|
||||
return &_dst_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 超时通知函数, 子类实现逻辑
|
||||
*/
|
||||
virtual void timer_notify();
|
||||
|
||||
/**
|
||||
* @brief 设置超时时间, 毫秒单位
|
||||
*/
|
||||
void SetKeepTime(unsigned int time) {
|
||||
_keep_time = time;
|
||||
};
|
||||
|
||||
protected:
|
||||
int _osfd; // 每次连接单独创建socket
|
||||
unsigned int _keep_time; // 设置保活的时间
|
||||
TcpKeepNtfy _keep_ntfy; // 关联一个保活连接对象
|
||||
struct sockaddr_in _dst_addr; // 远端地址信息
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按地址hash缓存长连接
|
||||
*/
|
||||
class TcpKeepKey : public HashKey
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
TcpKeepKey() {
|
||||
_addr_ipv4 = 0;
|
||||
_net_port = 0;
|
||||
TAILQ_INIT(&_keep_list);
|
||||
this->SetDataPtr(this);
|
||||
};
|
||||
|
||||
TcpKeepKey(struct sockaddr_in * dst) {
|
||||
_addr_ipv4 = dst->sin_addr.s_addr;
|
||||
_net_port = dst->sin_port;
|
||||
TAILQ_INIT(&_keep_list);
|
||||
this->SetDataPtr(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 这里暂不清理conn
|
||||
*/
|
||||
~TcpKeepKey() {
|
||||
TAILQ_INIT(&_keep_list);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的hash算法, 获取key的hash值
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual uint32_t HashValue(){
|
||||
return _addr_ipv4 ^ ((_net_port << 16) | _net_port);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的cmp方法, 同一桶ID下, 按key比较
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual int HashCmp(HashKey* rhs){
|
||||
TcpKeepKey* data = dynamic_cast<TcpKeepKey*>(rhs);
|
||||
if (!data) {
|
||||
return -1;
|
||||
}
|
||||
if (this->_addr_ipv4 != data->_addr_ipv4) {
|
||||
return this->_addr_ipv4 - data->_addr_ipv4;
|
||||
}
|
||||
if (this->_net_port != data->_net_port) {
|
||||
return this->_net_port - data->_net_port;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接对象管理
|
||||
*/
|
||||
void InsertConn(TcpKeepConn* conn) {
|
||||
if (conn->_keep_flag & TCP_KEEP_IN_LIST) {
|
||||
return;
|
||||
}
|
||||
TAILQ_INSERT_TAIL(&_keep_list, conn, _keep_entry);
|
||||
conn->_keep_flag |= TCP_KEEP_IN_LIST;
|
||||
};
|
||||
|
||||
void RemoveConn(TcpKeepConn* conn) {
|
||||
if (!(conn->_keep_flag & TCP_KEEP_IN_LIST)) {
|
||||
return;
|
||||
}
|
||||
TAILQ_REMOVE(&_keep_list, conn, _keep_entry);
|
||||
conn->_keep_flag &= ~TCP_KEEP_IN_LIST;
|
||||
};
|
||||
|
||||
TcpKeepConn* GetFirstConn() {
|
||||
return TAILQ_FIRST(&_keep_list);
|
||||
};
|
||||
|
||||
private:
|
||||
uint32_t _addr_ipv4; ///< ip地址
|
||||
uint16_t _net_port; ///< port 网络序列
|
||||
KeepConnList _keep_list; ///< 实际的空闲队列
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief TCP长连接的连接对象管理与内存cache
|
||||
*/
|
||||
class TcpKeepMgr
|
||||
{
|
||||
public:
|
||||
|
||||
typedef CPtrPool<TcpKeepConn> TcpKeepQueue; ///< 内存缓冲池
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
TcpKeepMgr();
|
||||
|
||||
~TcpKeepMgr();
|
||||
|
||||
|
||||
/**
|
||||
* @brief 按IP地址获取TCP的保持连接
|
||||
*/
|
||||
TcpKeepConn* GetTcpKeepConn(struct sockaddr_in* dst);
|
||||
|
||||
/**
|
||||
* @brief 按IP地址缓存TCP的保持连接
|
||||
*/
|
||||
bool CacheTcpKeepConn(TcpKeepConn* conn);
|
||||
|
||||
/**
|
||||
* @brief 按IP地址缓存TCP的保持连接, 去除CACHE
|
||||
*/
|
||||
bool RemoveTcpKeepConn(TcpKeepConn* conn);
|
||||
|
||||
/**
|
||||
* @brief 关闭或缓存tcp长连接
|
||||
*/
|
||||
void FreeTcpKeepConn(TcpKeepConn* conn, bool force_free);
|
||||
|
||||
private:
|
||||
|
||||
HashList* _keep_hash; ///< hash表, 存储按IP索引的连接队列
|
||||
TcpKeepQueue _mem_queue; ///< mem队列, 管理conn内存块
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接管理工厂模型
|
||||
*/
|
||||
class ConnectionMgr
|
||||
{
|
||||
public:
|
||||
|
||||
typedef CPtrPool<UdpShortConn> UdpShortQueue;
|
||||
typedef CPtrPool<UdpSessionConn> UdpSessionQueue;
|
||||
|
||||
/**
|
||||
* @brief 消息buff的全局管理句柄接口
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
static ConnectionMgr* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 消息清理接口
|
||||
*/
|
||||
static void Destroy(void);
|
||||
|
||||
/**
|
||||
* @brief 获取接口
|
||||
*/
|
||||
IMtConnection* GetConnection(CONN_OBJ_TYPE type, struct sockaddr_in* dst);
|
||||
|
||||
/**
|
||||
* @brief 回收接口
|
||||
*/
|
||||
void FreeConnection(IMtConnection* conn, bool force_free);
|
||||
|
||||
/**
|
||||
* @brief 关闭idle的tcp长连接
|
||||
*/
|
||||
void CloseIdleTcpKeep(TcpKeepConn* conn);
|
||||
|
||||
/**
|
||||
* @brief 消息buff的析构函数
|
||||
*/
|
||||
~ConnectionMgr();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
ConnectionMgr();
|
||||
|
||||
static ConnectionMgr * _instance; ///< 单例类句柄
|
||||
|
||||
UdpShortQueue _udp_short_queue; ///< 短连接的队列池
|
||||
UdpSessionQueue _udp_session_queue; ///< udp session 连接池
|
||||
TcpKeepMgr _tcp_keep_mgr; ///< tcp keep 管理器
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_incl.h
|
||||
* @info ΢Ïß³ÌÌṩ¸øspp_pluginµÄÍ·Îļþ
|
||||
* @time 20130924
|
||||
*/
|
||||
|
||||
#ifndef _MT_INCL_EX__
|
||||
#define _MT_INCL_EX__
|
||||
|
||||
#include "mt_version.h"
|
||||
#include "mt_msg.h"
|
||||
#include "mt_api.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_mbuf_pool.cpp
|
||||
* @info 微线程消息buf池管理实现
|
||||
* @time 20130924
|
||||
**/
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_mbuf_pool.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 连接管理全局访问接口
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
MsgBuffPool* MsgBuffPool::_instance = NULL;
|
||||
MsgBuffPool* MsgBuffPool::Instance (void)
|
||||
{
|
||||
if (NULL == _instance)
|
||||
{
|
||||
_instance = new MsgBuffPool;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 连接管理全局的销毁接口
|
||||
*/
|
||||
void MsgBuffPool::Destroy()
|
||||
{
|
||||
if( _instance != NULL )
|
||||
{
|
||||
delete _instance;
|
||||
_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
MsgBuffPool::MsgBuffPool(int max_free)
|
||||
{
|
||||
_max_free = max_free;
|
||||
_hash_map = new HashList(10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 消息buff的析构函数
|
||||
*/
|
||||
MsgBuffPool::~MsgBuffPool()
|
||||
{
|
||||
if (!_hash_map) {
|
||||
return;
|
||||
}
|
||||
|
||||
MsgBufMap* msg_map = NULL;
|
||||
HashKey* hash_item = _hash_map->HashGetFirst();
|
||||
while (hash_item)
|
||||
{
|
||||
_hash_map->HashRemove(hash_item);
|
||||
msg_map = dynamic_cast<MsgBufMap*>(hash_item);
|
||||
delete msg_map;
|
||||
|
||||
hash_item = _hash_map->HashGetFirst();
|
||||
}
|
||||
|
||||
delete _hash_map;
|
||||
_hash_map = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取消息buff元素
|
||||
* @return msgbuf指针, 失败为NULL
|
||||
*/
|
||||
MtMsgBuf* MsgBuffPool::GetMsgBuf(int max_size)
|
||||
{
|
||||
if (!_hash_map) {
|
||||
MTLOG_ERROR("MsgBuffPoll not init! hash %p,", _hash_map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MsgBufMap* msg_map = NULL;
|
||||
MsgBufMap msg_key(max_size);
|
||||
HashKey* hash_item = _hash_map->HashFind(&msg_key);
|
||||
if (hash_item) {
|
||||
msg_map = (MsgBufMap*)hash_item->GetDataPtr();
|
||||
if (msg_map) {
|
||||
return msg_map->GetMsgBuf();
|
||||
} else {
|
||||
MTLOG_ERROR("Hash item: %p, msg_map: %p impossible, clean it", hash_item, msg_map);
|
||||
_hash_map->HashRemove(hash_item);
|
||||
delete hash_item;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
msg_map = new MsgBufMap(max_size, _max_free);
|
||||
if (!msg_map) {
|
||||
MTLOG_ERROR("maybe no more memory, failed. size: %d", max_size);
|
||||
return NULL;
|
||||
}
|
||||
_hash_map->HashInsert(msg_map);
|
||||
|
||||
return msg_map->GetMsgBuf();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取消息buff元素
|
||||
* @return msgbuf指针, 失败为NULL
|
||||
*/
|
||||
void MsgBuffPool::FreeMsgBuf(MtMsgBuf* msg_buf)
|
||||
{
|
||||
if (!_hash_map || !msg_buf) {
|
||||
MTLOG_ERROR("MsgBuffPoll not init or input error! hash %p, msg_buf %p", _hash_map, msg_buf);
|
||||
delete msg_buf;
|
||||
return;
|
||||
}
|
||||
msg_buf->Reset();
|
||||
|
||||
MsgBufMap* msg_map = NULL;
|
||||
MsgBufMap msg_key(msg_buf->GetMaxLen());
|
||||
HashKey* hash_item = _hash_map->HashFind(&msg_key);
|
||||
if (hash_item) {
|
||||
msg_map = (MsgBufMap*)hash_item->GetDataPtr();
|
||||
}
|
||||
if (!hash_item || !msg_map) {
|
||||
MTLOG_ERROR("MsgBuffPoll find no queue, maybe error: %d", msg_buf->GetMaxLen());
|
||||
delete msg_buf;
|
||||
return;
|
||||
}
|
||||
msg_map->FreeMsgBuf(msg_buf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_mbuf_pool.h
|
||||
* @info 微线程同步消息buf池
|
||||
**/
|
||||
|
||||
#ifndef __MT_MBUF_POOL_H__
|
||||
#define __MT_MBUF_POOL_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <queue>
|
||||
#include "hash_list.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
using std::queue;
|
||||
|
||||
enum BUFF_TYPE
|
||||
{
|
||||
BUFF_UNDEF = 0, ///< 未定义类型
|
||||
BUFF_RECV = 1, ///< 接收buff
|
||||
BUFF_SEND = 2, ///< 发送buff
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 消息投递的buffer类
|
||||
*/
|
||||
typedef TAILQ_ENTRY(MtMsgBuf) MsgBufLink;
|
||||
typedef TAILQ_HEAD(__MtbuffTailq, MtMsgBuf) MsgBufQueue;
|
||||
class MtMsgBuf
|
||||
{
|
||||
private:
|
||||
int _max_len; // 最大的空间长度
|
||||
int _msg_len; // 实际的消息长度
|
||||
int _buf_type; // buff是发送还是接收
|
||||
int _recv_len; // 已接收的消息长度
|
||||
int _send_len; // 已发送的消息长度
|
||||
void* _msg_buff; // buffer 实际头指针
|
||||
|
||||
public:
|
||||
|
||||
MsgBufLink _entry;
|
||||
|
||||
/**
|
||||
* @brief 构造函数, 指定最大buff长度
|
||||
*/
|
||||
MtMsgBuf(int max_len) {
|
||||
_max_len = max_len;
|
||||
_msg_len = 0;
|
||||
_buf_type = BUFF_UNDEF;
|
||||
_recv_len = 0;
|
||||
_send_len = 0;
|
||||
_msg_buff = malloc(max_len);
|
||||
};
|
||||
|
||||
~MtMsgBuf() {
|
||||
if (_msg_buff) {
|
||||
free(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 消息类型的设置与读取
|
||||
*/
|
||||
void SetBuffType(BUFF_TYPE type) {
|
||||
_buf_type = (int)type;
|
||||
};
|
||||
BUFF_TYPE GetBuffType() {
|
||||
return (BUFF_TYPE)_buf_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 复用接口, 恢复初始状态
|
||||
*/
|
||||
void Reset() {
|
||||
_msg_len = 0;
|
||||
_recv_len = 0;
|
||||
_send_len = 0;
|
||||
_buf_type = BUFF_UNDEF;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 消息长度的设置与读取
|
||||
*/
|
||||
void SetMsgLen(int msg_len) {
|
||||
_msg_len = msg_len;
|
||||
};
|
||||
int GetMsgLen() {
|
||||
return _msg_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 最大长度与buffer指针获取
|
||||
*/
|
||||
int GetMaxLen() {
|
||||
return _max_len;
|
||||
};
|
||||
void* GetMsgBuff() {
|
||||
return _msg_buff;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 中间状态获取与更新
|
||||
*/
|
||||
int GetHaveSndLen() {
|
||||
return _send_len;
|
||||
};
|
||||
void SetHaveSndLen(int snd_len) {
|
||||
_send_len = snd_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 中间状态获取与更新
|
||||
*/
|
||||
int GetHaveRcvLen() {
|
||||
return _recv_len;
|
||||
};
|
||||
void SetHaveRcvLen(int rcv_len) {
|
||||
_recv_len = rcv_len;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 指定大小的buffer, 按最大长度映射成空闲队列
|
||||
*/
|
||||
class MsgBufMap : public HashKey
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 消息buff管理的构造
|
||||
* @param buff_size 该map元素上的所有buff, 其最大buff空间大小值
|
||||
* @param max_free 该队列管理元素, 最大保持的free数目
|
||||
*/
|
||||
MsgBufMap(int buff_size, int max_free) {
|
||||
_max_buf_size = buff_size;
|
||||
_max_free = max_free;
|
||||
this->SetDataPtr(this);
|
||||
_queue_num = 0;
|
||||
TAILQ_INIT(&_msg_queue);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 消息buff管理的构造, 简单构造, 仅设置key信息
|
||||
* @param buff_size 该map元素上的所有buff, 其最大buff空间大小值
|
||||
*/
|
||||
explicit MsgBufMap(int buff_size) {
|
||||
_max_buf_size = buff_size;
|
||||
TAILQ_INIT(&_msg_queue);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 消息buff管理的析构清理
|
||||
*/
|
||||
~MsgBufMap() {
|
||||
MtMsgBuf* ptr = NULL;
|
||||
MtMsgBuf* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(ptr, &_msg_queue, _entry, tmp)
|
||||
{
|
||||
TAILQ_REMOVE(&_msg_queue, ptr, _entry);
|
||||
delete ptr;
|
||||
_queue_num--;
|
||||
}
|
||||
|
||||
TAILQ_INIT(&_msg_queue);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取消息buff元素
|
||||
* @return msgbuf指针, 失败为NULL
|
||||
*/
|
||||
MtMsgBuf* GetMsgBuf(){
|
||||
MtMsgBuf* ptr = NULL;
|
||||
if (!TAILQ_EMPTY(&_msg_queue)) {
|
||||
ptr = TAILQ_FIRST(&_msg_queue);
|
||||
TAILQ_REMOVE(&_msg_queue, ptr, _entry);
|
||||
_queue_num--;
|
||||
} else {
|
||||
ptr = new MtMsgBuf(_max_buf_size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 释放消息buff元素
|
||||
* @param msgbuf指针
|
||||
*/
|
||||
void FreeMsgBuf(MtMsgBuf* ptr){
|
||||
if (_queue_num >= _max_free) {
|
||||
delete ptr;
|
||||
} else {
|
||||
ptr->Reset();
|
||||
TAILQ_INSERT_TAIL(&_msg_queue, ptr, _entry);
|
||||
_queue_num++;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的hash算法, 获取key的hash值
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual uint32_t HashValue(){
|
||||
return _max_buf_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的cmp方法, 同一桶ID下, 按key比较
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual int HashCmp(HashKey* rhs){
|
||||
return this->_max_buf_size - (int)rhs->HashValue();
|
||||
};
|
||||
|
||||
private:
|
||||
int _max_free; ///< 最大空闲保留个数
|
||||
int _max_buf_size; ///< 本队列最大的buffsize
|
||||
int _queue_num; ///< 空闲队列个数
|
||||
MsgBufQueue _msg_queue; ///< 实际的空闲队列
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 全局的buffer池对象, 统一分配与回收buffer
|
||||
*/
|
||||
class MsgBuffPool
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 消息buff的全局管理句柄接口
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
static MsgBuffPool* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 消息清理接口
|
||||
*/
|
||||
static void Destroy(void);
|
||||
|
||||
/**
|
||||
* @brief 消息buff的全局管理设置默认最大的空闲个数
|
||||
* @param max_free 最大空闲保留数目, 需要在分配元素前设置
|
||||
*/
|
||||
void SetMaxFreeNum(int max_free) {
|
||||
_max_free = max_free;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取消息buff元素
|
||||
* @return msgbuf指针, 失败为NULL
|
||||
*/
|
||||
MtMsgBuf* GetMsgBuf(int max_size);
|
||||
|
||||
/**
|
||||
* @brief 释放消息buff元素
|
||||
* @param msgbuf指针
|
||||
*/
|
||||
void FreeMsgBuf(MtMsgBuf* msg_buf);
|
||||
|
||||
/**
|
||||
* @brief 消息buff的全局类析构函数
|
||||
*/
|
||||
~MsgBuffPool();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
explicit MsgBuffPool(int max_free = 300);
|
||||
|
||||
static MsgBuffPool * _instance; ///< 单例类句柄
|
||||
int _max_free; ///< 最大保留空闲数目
|
||||
HashList* _hash_map; ///< 按size hashmap 保存空闲队列
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_msg.h
|
||||
* @info 微线程同步消息的基类
|
||||
**/
|
||||
|
||||
#ifndef __MT_MSG_H__
|
||||
#define __MT_MSG_H__
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
/**
|
||||
* @brief 微线程消息处理基类
|
||||
*/
|
||||
class IMtMsg
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 微线程消息类的处理流程入口函数
|
||||
* @return 0 -成功, < 0 失败
|
||||
*/
|
||||
virtual int HandleProcess() { return -1; };
|
||||
|
||||
/**
|
||||
* @brief 微线程消息基类构造与析构
|
||||
*/
|
||||
IMtMsg() {};
|
||||
virtual ~IMtMsg() {};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,718 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_net.h
|
||||
* @info 微线程封装的网络接口类
|
||||
**/
|
||||
|
||||
#ifndef __MT_NET_H__
|
||||
#define __MT_NET_H__
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "hash_list.h"
|
||||
#include "mt_api.h"
|
||||
#include "mt_cache.h"
|
||||
#include "mt_net_api.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
/**
|
||||
* @brief 连接类型定义
|
||||
*/
|
||||
enum MT_CONN_TYPE
|
||||
{
|
||||
TYPE_CONN_UNKNOWN = 0,
|
||||
TYPE_CONN_SHORT = 0x1, ///< 短连接, 一次交互后关闭
|
||||
TYPE_CONN_POOL = 0x2, ///< 长连接,每次使用后, 可回收重复使用
|
||||
TYPE_CONN_SESSION = 0x4, ///< 长连接,按session id 复用, 防串包
|
||||
TYPE_CONN_SENDONLY = 0x8, ///< 只发不收
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 内部实现部分 */
|
||||
/******************************************************************************/
|
||||
class CSockLink;
|
||||
|
||||
/**
|
||||
* @brief 定时回收的对象池模板实现
|
||||
* @info List必须是tailq, Type 需要有reset函数, releasetime, linkentry字段
|
||||
*/
|
||||
template <typename List, typename Type>
|
||||
class CRecyclePool
|
||||
{
|
||||
public:
|
||||
|
||||
// 构造函数, 默认60s超时
|
||||
CRecyclePool() {
|
||||
_expired = 60 * 1000;
|
||||
_count = 0;
|
||||
TAILQ_INIT(&_free_list);
|
||||
};
|
||||
|
||||
// 析构函数, 删除池中元素
|
||||
~CRecyclePool() {
|
||||
Type* item = NULL;
|
||||
Type* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &_free_list, _link_entry, tmp)
|
||||
{
|
||||
TAILQ_REMOVE(&_free_list, item, _link_entry);
|
||||
delete item;
|
||||
}
|
||||
_count = 0;
|
||||
};
|
||||
|
||||
// 复用或新创建对象
|
||||
Type* AllocItem() {
|
||||
Type* item = TAILQ_FIRST(&_free_list);
|
||||
if (item != NULL)
|
||||
{
|
||||
TAILQ_REMOVE(&_free_list, item, _link_entry);
|
||||
_count--;
|
||||
return item;
|
||||
}
|
||||
|
||||
item = new Type();
|
||||
if (NULL == item)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
// 释放管理对象
|
||||
void FreeItem(Type* obj) {
|
||||
//obj->Reset();
|
||||
TAILQ_INSERT_TAIL(&_free_list, obj, _link_entry);
|
||||
obj->_release_time = mt_time_ms();
|
||||
_count++;
|
||||
};
|
||||
|
||||
|
||||
// 回收句柄
|
||||
void RecycleItem(uint64_t now) {
|
||||
Type* item = NULL;
|
||||
Type* tmp = NULL;
|
||||
TAILQ_FOREACH_SAFE(item, &_free_list, _link_entry, tmp)
|
||||
{
|
||||
if ((now - item->_release_time) < _expired) {
|
||||
break;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&_free_list, item, _link_entry);
|
||||
delete item;
|
||||
_count--;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置自定义的超时时间
|
||||
void SetExpiredTime(uint64_t expired) {
|
||||
_expired = expired;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
List _free_list; ///< 空闲链表
|
||||
uint64_t _expired; ///< 超时时间
|
||||
uint32_t _count; ///< 元素计数
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 每次IO关联一个句柄对象
|
||||
*/
|
||||
class CNetHandler : public HashKey
|
||||
{
|
||||
public:
|
||||
|
||||
// 句柄状态描述
|
||||
enum {
|
||||
STATE_IN_SESSION = 0x1,
|
||||
STATE_IN_CONNECT = 0x2,
|
||||
STATE_IN_SEND = 0x4,
|
||||
STATE_IN_RECV = 0x8,
|
||||
STATE_IN_IDLE = 0x10,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的hash算法, 获取key的hash值
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual uint32_t HashValue();
|
||||
|
||||
/**
|
||||
* @brief 节点元素的cmp方法, 同一桶ID下, 按key比较
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual int HashCmp(HashKey* rhs);
|
||||
|
||||
// 同步收发接口
|
||||
int32_t SendRecv(void* data, uint32_t len, uint32_t timeout);
|
||||
|
||||
// 获取返回buff信息, 有效期直到helper析构
|
||||
void* GetRspBuff() {
|
||||
if (_rsp_buff != NULL) {
|
||||
return _rsp_buff->data;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取返回buff信息, 有效期直到helper析构
|
||||
uint32_t GetRspLen() {
|
||||
if (_rsp_buff != NULL) {
|
||||
return _rsp_buff->data_len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置rsp信息
|
||||
void SetRespBuff(TSkBuffer* buff) {
|
||||
if (_rsp_buff != NULL) {
|
||||
delete_sk_buffer(_rsp_buff);
|
||||
_rsp_buff = NULL;
|
||||
}
|
||||
|
||||
_rsp_buff = buff;
|
||||
};
|
||||
|
||||
// 设置协议的类型, 默认UDP
|
||||
void SetProtoType(MT_PROTO_TYPE type) {
|
||||
_proto_type = type;
|
||||
};
|
||||
|
||||
// 设置连接类型, 默认长连接
|
||||
void SetConnType(MT_CONN_TYPE type) {
|
||||
_conn_type = type;
|
||||
};
|
||||
|
||||
// 设置目的IP地址
|
||||
void SetDestAddress(struct sockaddr_in* dst) {
|
||||
if (dst != NULL) {
|
||||
memcpy(&_dest_ipv4, dst, sizeof(*dst));
|
||||
}
|
||||
};
|
||||
|
||||
// 设置session本次session id信息, 必须非0
|
||||
void SetSessionId(uint64_t sid) {
|
||||
_session_id = sid;
|
||||
};
|
||||
|
||||
// 设置session解析回调函数
|
||||
void SetSessionCallback(CHECK_SESSION_CALLBACK function) {
|
||||
_callback = function;
|
||||
};
|
||||
|
||||
// 获取回调函数信息
|
||||
CHECK_SESSION_CALLBACK GetSessionCallback() {
|
||||
return _callback;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 关联连接对象
|
||||
void Link(CSockLink* conn);
|
||||
|
||||
// 解耦连接对象
|
||||
void Unlink();
|
||||
|
||||
// 检查必要的参数信息
|
||||
int32_t CheckParams();
|
||||
|
||||
// 获取链接, 同时关联到等待连接的队列中
|
||||
int32_t GetConnLink();
|
||||
|
||||
// 检查必要的参数信息
|
||||
int32_t WaitConnect(uint64_t timeout);
|
||||
|
||||
// 检查必要的参数信息
|
||||
int32_t WaitSend(uint64_t timeout);
|
||||
|
||||
// 检查必要的参数信息
|
||||
int32_t WaitRecv(uint64_t timeout);
|
||||
|
||||
// 关联在等待连接队列
|
||||
void SwitchToConn();
|
||||
|
||||
// 切换到发送队列
|
||||
void SwitchToSend();
|
||||
|
||||
// 切换到接收队列
|
||||
void SwitchToRecv();
|
||||
|
||||
// 切换到空闲状态
|
||||
void SwitchToIdle();
|
||||
|
||||
// 解耦连接对象
|
||||
void DetachConn();
|
||||
|
||||
// 注册session管理
|
||||
bool RegistSession();
|
||||
|
||||
// 取消注册session
|
||||
void UnRegistSession();
|
||||
|
||||
// 跳过发送的请求长度
|
||||
uint32_t SkipSendPos(uint32_t len);
|
||||
|
||||
// 设置返回码
|
||||
void SetErrNo(int32_t err) {
|
||||
_err_no = err;
|
||||
};
|
||||
|
||||
// 获取关联的线程信息
|
||||
MicroThread* GetThread() {
|
||||
return _thread;
|
||||
};
|
||||
|
||||
// 获取待发送的指针与数据长度
|
||||
void GetSendData(void*& data, uint32_t& len) {
|
||||
data = _req_data;
|
||||
len = _req_len;
|
||||
};
|
||||
|
||||
// 复用接口
|
||||
void Reset();
|
||||
|
||||
// 构造与析构
|
||||
CNetHandler();
|
||||
~CNetHandler();
|
||||
|
||||
// 队列快捷访问的宏定义
|
||||
TAILQ_ENTRY(CNetHandler) _link_entry;
|
||||
uint64_t _release_time;
|
||||
|
||||
protected:
|
||||
|
||||
MicroThread* _thread; ///< 关联线程指针对象
|
||||
MT_PROTO_TYPE _proto_type; ///< 协议类型
|
||||
MT_CONN_TYPE _conn_type; ///< 连接类型
|
||||
struct sockaddr_in _dest_ipv4; ///< ipv4目的地址
|
||||
uint64_t _session_id; ///< 会话ID
|
||||
CHECK_SESSION_CALLBACK _callback; ///< 会话提取回调函数
|
||||
uint32_t _state_flags; ///< 内部状态字段
|
||||
int32_t _err_no; ///< 返回码信息
|
||||
void* _conn_ptr; ///< socket 链路指针
|
||||
uint32_t _send_pos; ///< 已发送的pos位置
|
||||
uint32_t _req_len; ///< 请求包长度
|
||||
void* _req_data; ///< 请求包指针
|
||||
TSkBuffer* _rsp_buff; ///< 应答buff信息
|
||||
|
||||
};
|
||||
typedef TAILQ_HEAD(__NetHandlerList, CNetHandler) TNetItemList; ///< 高效的双链管理
|
||||
typedef CRecyclePool<TNetItemList, CNetHandler> TNetItemPool; ///< 定时回收的对象池
|
||||
|
||||
|
||||
/**
|
||||
* @brief 长连接链路对象
|
||||
*/
|
||||
class CSockLink : public KqueuerObj
|
||||
{
|
||||
public:
|
||||
|
||||
// 句柄状态描述
|
||||
enum {
|
||||
LINK_CONNECTING = 0x1,
|
||||
LINK_CONNECTED = 0x2,
|
||||
};
|
||||
|
||||
// 状态队列定义
|
||||
enum {
|
||||
LINK_IDLE_LIST = 1,
|
||||
LINK_CONN_LIST = 2,
|
||||
LINK_SEND_LIST = 3,
|
||||
LINK_RECV_LIST = 4,
|
||||
};
|
||||
|
||||
// 检查或创建socket句柄
|
||||
int32_t CreateSock();
|
||||
|
||||
// 关闭链路的句柄
|
||||
void Close();
|
||||
|
||||
// 发起连接过程
|
||||
bool Connect();
|
||||
bool Connected() {
|
||||
return (_state & LINK_CONNECTED);
|
||||
}
|
||||
|
||||
// 异常终止的处理函数
|
||||
void Destroy();
|
||||
|
||||
// 获取管理链表
|
||||
TNetItemList* GetItemList(int32_t type);
|
||||
|
||||
// 管理句柄信息
|
||||
void AppendToList(int32_t type, CNetHandler* item);
|
||||
|
||||
// 管理句柄信息
|
||||
void RemoveFromList(int32_t type, CNetHandler* item);
|
||||
|
||||
// 获取目标ip信息
|
||||
struct sockaddr_in* GetDestAddr(struct sockaddr_in* addr);
|
||||
|
||||
// 发起连接过程
|
||||
int32_t SendData(void* data, uint32_t len);
|
||||
|
||||
// udp发送数据
|
||||
int32_t SendCacheUdp(void* data, uint32_t len);
|
||||
|
||||
// tcp发送数据
|
||||
int32_t SendCacheTcp(void* data, uint32_t len);
|
||||
|
||||
// 尝试接收更多的数据到临时buff
|
||||
void ExtendRecvRsp();
|
||||
|
||||
// 数据分发处理过程
|
||||
int32_t RecvDispath();
|
||||
|
||||
// 或者回调函数, 优先从排队等待中获取, 备份从父节点获取
|
||||
CHECK_SESSION_CALLBACK GetSessionCallback();
|
||||
|
||||
// TCP接收数据流处理与分发
|
||||
int32_t DispathTcp();
|
||||
|
||||
// UDP接收数据流处理与分发
|
||||
int32_t DispathUdp();
|
||||
|
||||
// 查询本地sessionid关联的session信息
|
||||
CNetHandler* FindSession(uint64_t sid);
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int InputNotify();
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int OutputNotify();
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
virtual int HangupNotify();
|
||||
|
||||
|
||||
// 构造与析构函数
|
||||
CSockLink();
|
||||
~CSockLink();
|
||||
|
||||
// 清理置初始化逻辑
|
||||
void Reset();
|
||||
|
||||
// 通知唤醒线程
|
||||
void NotifyThread(CNetHandler* item, int32_t result);
|
||||
|
||||
// 通知唤醒线程
|
||||
void NotifyAll(int32_t result);
|
||||
|
||||
// 设置协议类型, 决定buff池的指针
|
||||
void SetProtoType(MT_PROTO_TYPE type);
|
||||
|
||||
// 设置上级指针信息
|
||||
void SetParentsPtr(void* ptr) {
|
||||
_parents = ptr;
|
||||
};
|
||||
|
||||
// 获取上级节点指针
|
||||
void* GetParentsPtr() {
|
||||
return _parents;
|
||||
};
|
||||
|
||||
// 获取上次的访问时间
|
||||
uint64_t GetLastAccess() {
|
||||
return _last_access;
|
||||
};
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 队列快捷访问的宏定义
|
||||
TAILQ_ENTRY(CSockLink) _link_entry;
|
||||
uint64_t _release_time;
|
||||
|
||||
private:
|
||||
|
||||
TNetItemList _wait_connect;
|
||||
TNetItemList _wait_send;
|
||||
TNetItemList _wait_recv;
|
||||
TNetItemList _idle_list;
|
||||
MT_PROTO_TYPE _proto_type;
|
||||
int32_t _errno;
|
||||
uint32_t _state;
|
||||
uint64_t _last_access;
|
||||
TRWCache _recv_cache;
|
||||
TSkBuffer* _rsp_buff;
|
||||
void* _parents;
|
||||
};
|
||||
typedef TAILQ_HEAD(__SocklinkList, CSockLink) TLinkList; ///< 高效的双链管理
|
||||
typedef CRecyclePool<TLinkList, CSockLink> TLinkPool; ///< 定时回收的对象池
|
||||
|
||||
|
||||
class CDestLinks : public CTimerNotify, public HashKey
|
||||
{
|
||||
public:
|
||||
|
||||
// 构造函数
|
||||
CDestLinks();
|
||||
|
||||
// 析构函数
|
||||
~CDestLinks();
|
||||
|
||||
// 重置复用的接口函数
|
||||
void Reset();
|
||||
|
||||
// 启动定时器
|
||||
void StartTimer();
|
||||
|
||||
// 获取一个连接link, 暂时按轮询
|
||||
CSockLink* GetSockLink();
|
||||
|
||||
// 释放一个连接link
|
||||
void FreeSockLink(CSockLink* sock);
|
||||
|
||||
// 获取协议类型
|
||||
MT_PROTO_TYPE GetProtoType() {
|
||||
return _proto_type;
|
||||
};
|
||||
|
||||
// 获取连接类型
|
||||
MT_CONN_TYPE GetConnType() {
|
||||
return _conn_type;
|
||||
};
|
||||
|
||||
|
||||
// 设置关键信息
|
||||
void SetKeyInfo(uint32_t ipv4, uint16_t port, MT_PROTO_TYPE proto, MT_CONN_TYPE conn) {
|
||||
_addr_ipv4 = ipv4;
|
||||
_net_port = port;
|
||||
_proto_type = proto;
|
||||
_conn_type = conn;
|
||||
};
|
||||
|
||||
// 拷贝KEY信息
|
||||
void CopyKeyInfo(CDestLinks* key) {
|
||||
_addr_ipv4 = key->_addr_ipv4;
|
||||
_net_port = key->_net_port;
|
||||
_proto_type = key->_proto_type;
|
||||
_conn_type = key->_conn_type;
|
||||
};
|
||||
|
||||
// 获取IP port信息
|
||||
void GetDestIP(uint32_t& ip, uint16_t& port) {
|
||||
ip = _addr_ipv4;
|
||||
port = _net_port;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 超时通知函数, 检查空闲链路, 检查配置链路个数
|
||||
*/
|
||||
virtual void timer_notify();
|
||||
|
||||
/**
|
||||
* @brief 节点元素的hash算法, 获取key的hash值
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual uint32_t HashValue() {
|
||||
return _addr_ipv4 ^ (((uint32_t)_net_port << 16) | (_proto_type << 8) | _conn_type);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的cmp方法, 同一桶ID下, 按key比较
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual int HashCmp(HashKey* rhs) {
|
||||
CDestLinks* data = (CDestLinks*)(rhs);
|
||||
if (!data) {
|
||||
return -1;
|
||||
}
|
||||
if (this->_addr_ipv4 != data->_addr_ipv4) {
|
||||
return (this->_addr_ipv4 > data->_addr_ipv4) ? 1 : -1;
|
||||
}
|
||||
if (this->_net_port != data->_net_port) {
|
||||
return (this->_net_port > data->_net_port) ? 1 : -1;
|
||||
}
|
||||
if (this->_proto_type != data->_proto_type) {
|
||||
return (this->_proto_type > data->_proto_type) ? 1 : -1;
|
||||
}
|
||||
if (this->_conn_type != data->_conn_type) {
|
||||
return (this->_conn_type > data->_conn_type) ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// 设置session解析回调函数
|
||||
void SetDefaultCallback(CHECK_SESSION_CALLBACK function) {
|
||||
_dflt_callback = function;
|
||||
};
|
||||
|
||||
// 获取回调函数信息
|
||||
CHECK_SESSION_CALLBACK GetDefaultCallback() {
|
||||
return _dflt_callback;
|
||||
};
|
||||
|
||||
// 队列快捷访问的宏定义
|
||||
TAILQ_ENTRY(CDestLinks) _link_entry;
|
||||
uint64_t _release_time;
|
||||
|
||||
private:
|
||||
|
||||
uint32_t _timeout; ///< idle的超时时间
|
||||
uint32_t _addr_ipv4; ///< ip地址
|
||||
uint16_t _net_port; ///< port 网络序列
|
||||
MT_PROTO_TYPE _proto_type; ///< 协议类型
|
||||
MT_CONN_TYPE _conn_type; ///< 连接类型
|
||||
|
||||
uint32_t _max_links; ///< 最大连接数
|
||||
uint32_t _curr_link; ///< 当前连接数
|
||||
TLinkList _sock_list; ///< 连接链表
|
||||
CHECK_SESSION_CALLBACK _dflt_callback; ///< 默认的check函数
|
||||
|
||||
};
|
||||
typedef TAILQ_HEAD(__DestlinkList, CDestLinks) TDestList; ///< 高效的双链管理
|
||||
typedef CRecyclePool<TDestList, CDestLinks> TDestPool; ///< 定时回收的对象池
|
||||
|
||||
/**
|
||||
* @brief 连接管理工厂模型
|
||||
*/
|
||||
class CNetMgr
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 消息buff的全局管理句柄接口
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
static CNetMgr* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 消息清理接口
|
||||
*/
|
||||
static void Destroy(void);
|
||||
|
||||
// 查询是否已经存在同一个sid的对象
|
||||
CNetHandler* FindNetItem(CNetHandler* key);
|
||||
|
||||
// 注册一个item, 先查询后插入, 保证无冲突
|
||||
void InsertNetItem(CNetHandler* item);
|
||||
|
||||
// 移除一个item对象
|
||||
void RemoveNetItem(CNetHandler* item);
|
||||
|
||||
// 查询或创建一个目标ip的links节点
|
||||
CDestLinks* FindCreateDest(CDestLinks* key);
|
||||
|
||||
// 删除掉已有的目标链路信息
|
||||
void DeleteDestLink(CDestLinks* dst);
|
||||
|
||||
// 查询是否已经存在同一个sid的对象
|
||||
CDestLinks* FindDestLink(CDestLinks* key);
|
||||
|
||||
// 注册一个item, 先查询后插入, 保证无冲突
|
||||
void InsertDestLink(CDestLinks* item);
|
||||
|
||||
// 移除一个item对象
|
||||
void RemoveDestLink(CDestLinks* item);
|
||||
|
||||
/**
|
||||
* @brief 消息buff的析构函数
|
||||
*/
|
||||
~CNetMgr();
|
||||
|
||||
/**
|
||||
* @brief 回收资源信息
|
||||
*/
|
||||
void RecycleObjs(uint64_t now);
|
||||
|
||||
// 分配一个网络管理句柄
|
||||
CNetHandler* AllocNetItem() {
|
||||
return _net_item_pool.AllocItem();
|
||||
};
|
||||
|
||||
// 释放一个网络管理句柄
|
||||
void FreeNetItem(CNetHandler* item) {
|
||||
return _net_item_pool.FreeItem(item);
|
||||
};
|
||||
|
||||
// 分配一个SOCK连接链路
|
||||
CSockLink* AllocSockLink() {
|
||||
return _sock_link_pool.AllocItem();
|
||||
};
|
||||
|
||||
// 释放一个SOCK连接链路
|
||||
void FreeSockLink(CSockLink* item) {
|
||||
return _sock_link_pool.FreeItem(item);
|
||||
};
|
||||
|
||||
// 分配一个SOCK连接链路
|
||||
CDestLinks* AllocDestLink() {
|
||||
return _dest_ip_pool.AllocItem();
|
||||
};
|
||||
|
||||
// 释放一个SOCK连接链路
|
||||
void FreeDestLink(CDestLinks* item) {
|
||||
return _dest_ip_pool.FreeItem(item);
|
||||
};
|
||||
|
||||
// 获取udp的buff池信息
|
||||
TSkBuffMng* GetSkBuffMng(MT_PROTO_TYPE type) {
|
||||
if (type == NET_PROTO_TCP) {
|
||||
return &_tcp_pool;
|
||||
} else {
|
||||
return &_udp_pool;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
CNetMgr();
|
||||
|
||||
static CNetMgr * _instance; ///< 单例类句柄
|
||||
HashList* _ip_hash; ///< 目的地址hash
|
||||
HashList* _session_hash; ///< session id的hash
|
||||
TSkBuffMng _udp_pool; ///< udp pool, 64K
|
||||
TSkBuffMng _tcp_pool; ///< tcp pool, 4K
|
||||
TDestPool _dest_ip_pool; ///< 目的ip对象池
|
||||
TLinkPool _sock_link_pool; ///< socket pool
|
||||
TNetItemPool _net_item_pool; ///< net handle pool
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_net_api.h
|
||||
* @info 微线程封装的网络接口类
|
||||
**/
|
||||
|
||||
#ifndef __MT_NET_API_H__
|
||||
#define __MT_NET_API_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
/**
|
||||
* @brief 协议类型定义
|
||||
*/
|
||||
enum MT_PROTO_TYPE
|
||||
{
|
||||
NET_PROTO_UNDEF = 0,
|
||||
NET_PROTO_UDP = 0x1, ///< 连接类型 UDP
|
||||
NET_PROTO_TCP = 0x2 ///< 连接类型 TCP
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 返回类型定义
|
||||
*/
|
||||
enum MT_RC_TYPE
|
||||
{
|
||||
RC_SUCCESS = 0,
|
||||
RC_ERR_SOCKET = -1, ///< 创建socket失败
|
||||
RC_SEND_FAIL = -2, ///< 发送失败
|
||||
RC_RECV_FAIL = -3, ///< 接收失败
|
||||
RC_CONNECT_FAIL = -4, ///< 连接失败
|
||||
RC_CHECK_PKG_FAIL = -5, ///< 报文检测失败
|
||||
RC_NO_MORE_BUFF = -6, ///< 空间超过限制
|
||||
RC_REMOTE_CLOSED = -7, ///< 后端关闭连接
|
||||
|
||||
RC_INVALID_PARAM = -10, ///< 无效参数
|
||||
RC_INVALID_HANDLER = -11, ///< 无效的句柄
|
||||
RC_MEM_ERROR = -12, ///< 内存异常
|
||||
RC_CONFLICT_SID = -13, ///< SESSION ID冲突
|
||||
RC_KQUEUE_ERROR = -14, ///< rst信号等
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 检查报文是否完整, 并获取session的回调函数
|
||||
* @info 提供need_len参数的原因, 对于无法确认报文长度时, 可以每次扩展希望长度
|
||||
* 如果依赖返回值的隐含规则, 将无法处理这种情况
|
||||
* @param data -实际接收的数据指针
|
||||
* @param len -已经接收或准备的长度
|
||||
* @param session_id -成功解析的sessionid信息
|
||||
* @param need_len -希望扩展一下buff, 目前最大100M
|
||||
* @return >0 成功解析返回实际的包长度; =0 报文不完整, 期望接收更多数据; <0 解析失败
|
||||
*/
|
||||
typedef int32_t (*CHECK_SESSION_CALLBACK)(const void* data, uint32_t len,
|
||||
uint64_t* session_id, uint32_t* need_len);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 网络接口类定义
|
||||
*/
|
||||
class CNetHelper
|
||||
{
|
||||
public:
|
||||
|
||||
// 转发返回码信息, 按需获取
|
||||
static char* GetErrMsg(int32_t result);
|
||||
|
||||
// 同步收发接口
|
||||
int32_t SendRecv(void* data, uint32_t len, uint32_t timeout);
|
||||
|
||||
// 获取返回buff信息, 有效期直到helper析构
|
||||
void* GetRspBuff();
|
||||
|
||||
// 获取返回包的长度
|
||||
uint32_t GetRspLen();
|
||||
|
||||
// 设置协议的类型, 默认UDP
|
||||
void SetProtoType(MT_PROTO_TYPE type);
|
||||
|
||||
// 设置目的IP地址
|
||||
void SetDestAddress(struct sockaddr_in* dst);
|
||||
|
||||
// 设置session本次session id信息, 必须非0
|
||||
void SetSessionId(uint64_t sid);
|
||||
|
||||
// 设置session解析回调函数
|
||||
void SetSessionCallback(CHECK_SESSION_CALLBACK function);
|
||||
|
||||
// 构造与虚构
|
||||
CNetHelper();
|
||||
~CNetHelper();
|
||||
|
||||
private:
|
||||
|
||||
void* handler; // 私有句柄, 利于扩展
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,571 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_notify.cpp
|
||||
* @info 微线程调度注册对象管理实现
|
||||
* @time 20130924
|
||||
**/
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_session.h"
|
||||
#include "mt_msg.h"
|
||||
#include "mt_notify.h"
|
||||
#include "mt_connection.h"
|
||||
#include "mt_sys_hook.h"
|
||||
#include "ff_hook.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 通知代理进入等待状态, 挂入等待队列中
|
||||
* @param proxy 代理的session模型
|
||||
*/
|
||||
void ISessionNtfy::InsertWriteWait(SessionProxy* proxy)
|
||||
{
|
||||
if (!proxy->_flag) {
|
||||
TAILQ_INSERT_TAIL(&_write_list, proxy, _write_entry);
|
||||
proxy->_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通知代理移除等待状态
|
||||
* @param proxy 代理的session模型
|
||||
*/
|
||||
void ISessionNtfy::RemoveWriteWait(SessionProxy* proxy)
|
||||
{
|
||||
if (proxy->_flag) {
|
||||
TAILQ_REMOVE(&_write_list, proxy, _write_entry);
|
||||
proxy->_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 观察者模式, 通知写等待线程
|
||||
* @info UDP可以通知每个线程执行写操作, TCP需要排队写
|
||||
*/
|
||||
void UdpSessionNtfy::NotifyWriteWait()
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
SessionProxy* proxy = NULL;
|
||||
MicroThread* thread = NULL;
|
||||
TAILQ_FOREACH(proxy, &_write_list, _write_entry)
|
||||
{
|
||||
proxy->SetRcvEvents(KQ_EVENT_WRITE);
|
||||
|
||||
thread = proxy->GetOwnerThread();
|
||||
if (thread && thread->HasFlag(MicroThread::IO_LIST))
|
||||
{
|
||||
frame->RemoveIoWait(thread);
|
||||
frame->InsertRunable(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建socket, 监听可读事件
|
||||
* @return fd的句柄, <0 失败
|
||||
*/
|
||||
int UdpSessionNtfy::CreateSocket()
|
||||
{
|
||||
// 1. UDP短连接, 每次新创SOCKET
|
||||
int osfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (osfd < 0)
|
||||
{
|
||||
MTLOG_ERROR("socket create failed, errno %d(%s)", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 2. 非阻塞设置
|
||||
int flags = 1;
|
||||
if (ioctl(osfd, FIONBIO, &flags) < 0)
|
||||
{
|
||||
MTLOG_ERROR("socket unblock failed, errno %d(%s)", errno, strerror(errno));
|
||||
close(osfd);
|
||||
osfd = -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
// 可选bind执行, 设置本地port后执行
|
||||
if (_local_addr.sin_port != 0)
|
||||
{
|
||||
int ret = bind(osfd, (struct sockaddr *)&_local_addr, sizeof(_local_addr));
|
||||
if (ret < 0)
|
||||
{
|
||||
MTLOG_ERROR("socket bind(%s:%d) failed, errno %d(%s)", inet_ntoa(_local_addr.sin_addr),
|
||||
ntohs(_local_addr.sin_port), errno, strerror(errno));
|
||||
close(osfd);
|
||||
osfd = -1;
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 更新管理信息, 默认udp session 侦听 epollin
|
||||
this->SetOsfd(osfd);
|
||||
this->EnableInput();
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->KqueueNtfyReg(osfd, this);
|
||||
frame->KqueueCtrlAdd(osfd, KQ_EVENT_READ);
|
||||
|
||||
return osfd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 关闭socket, 停止监听可读事件
|
||||
*/
|
||||
void UdpSessionNtfy::CloseSocket()
|
||||
{
|
||||
int osfd = this->GetOsfd();
|
||||
if (osfd > 0)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->KqueueCtrlDel(osfd, KQ_EVENT_READ);
|
||||
frame->KqueueNtfyReg(osfd, NULL);
|
||||
this->DisableInput();
|
||||
this->SetOsfd(-1);
|
||||
close(osfd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
int UdpSessionNtfy::InputNotify()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int ret = 0;
|
||||
int have_rcv_len = 0;
|
||||
|
||||
// 1. 获取收包缓冲区, 优先选择未处理完的链接buff
|
||||
if (!_msg_buff) {
|
||||
_msg_buff = MsgBuffPool::Instance()->GetMsgBuf(this->GetMsgBuffSize());
|
||||
if (NULL == _msg_buff) {
|
||||
MTLOG_ERROR("Get memory failed, size %d, wait next time", this->GetMsgBuffSize());
|
||||
return 0;
|
||||
}
|
||||
_msg_buff->SetBuffType(BUFF_RECV);
|
||||
}
|
||||
char* buff = (char*)_msg_buff->GetMsgBuff();
|
||||
|
||||
// 2. 获取socket, 收包处理
|
||||
int osfd = this->GetOsfd();
|
||||
struct sockaddr_in from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
mt_hook_syscall(recvfrom);
|
||||
ret = ff_hook_recvfrom(osfd, buff, _msg_buff->GetMaxLen(),
|
||||
0, (struct sockaddr*)&from, &fromlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
if ((errno == EINTR) || (errno == EAGAIN) || (errno == EINPROGRESS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MTLOG_ERROR("recv error, fd %d", osfd);
|
||||
return 0; // 系统错误, UDP 暂不关闭
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
MTLOG_DEBUG("remote close connection, fd %d", osfd);
|
||||
return 0; // 对端关闭, UDP 暂不关闭
|
||||
}
|
||||
else
|
||||
{
|
||||
have_rcv_len = ret;
|
||||
_msg_buff->SetHaveRcvLen(have_rcv_len);
|
||||
_msg_buff->SetMsgLen(have_rcv_len);
|
||||
}
|
||||
|
||||
// 3. 检查消息的完整性, 提取sessionid
|
||||
int sessionid = 0;
|
||||
ret = this->GetSessionId(buff, have_rcv_len, sessionid);
|
||||
if (ret <= 0)
|
||||
{
|
||||
MTLOG_ERROR("recv get session failed, len %d, fd %d, drop it",
|
||||
have_rcv_len, osfd);
|
||||
MsgBuffPool::Instance()->FreeMsgBuf(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 4. 映射查询thread句柄, 连接handle句柄, 设置读事件来临, 挂接msgbuff
|
||||
ISession* session = SessionMgr::Instance()->FindSession(sessionid);
|
||||
if (NULL == session)
|
||||
{
|
||||
MT_ATTR_API(350403, 1); // session 到达已超时
|
||||
MTLOG_DEBUG("session %d, not find, maybe timeout, drop pkg", sessionid);
|
||||
MsgBuffPool::Instance()->FreeMsgBuf(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 5. 挂接recvbuff, 唤醒线程
|
||||
IMtConnection* conn = session->GetSessionConn();
|
||||
MicroThread* thread = session->GetOwnerThread();
|
||||
if (!thread || !conn || !conn->GetNtfyObj())
|
||||
{
|
||||
MTLOG_ERROR("sesson obj %p, no thread ptr %p, no conn %p wrong",
|
||||
session, thread, conn);
|
||||
MsgBuffPool::Instance()->FreeMsgBuf(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
return 0;
|
||||
}
|
||||
MtMsgBuf* msg = conn->GetMtMsgBuff();
|
||||
if (msg) {
|
||||
MsgBuffPool::Instance()->FreeMsgBuf(msg);
|
||||
}
|
||||
conn->SetMtMsgBuff(_msg_buff);
|
||||
_msg_buff = NULL;
|
||||
|
||||
conn->GetNtfyObj()->SetRcvEvents(KQ_EVENT_READ);
|
||||
if (thread->HasFlag(MicroThread::IO_LIST))
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->RemoveIoWait(thread);
|
||||
frame->InsertRunable(thread);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
int UdpSessionNtfy::OutputNotify()
|
||||
{
|
||||
NotifyWriteWait();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口, 关闭fd侦听, thread等待处理超时
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
int UdpSessionNtfy::HangupNotify()
|
||||
{
|
||||
// 1. 清理epoll ctl监听事件
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
frame->KqueueCtrlDel(this->GetOsfd(), this->GetEvents());
|
||||
|
||||
MTLOG_ERROR("sesson obj %p, recv error event. fd %d", this, this->GetOsfd());
|
||||
|
||||
// 2. 重新打开socket
|
||||
CloseSocket();
|
||||
|
||||
// 3. 重加入epoll listen
|
||||
CreateSocket();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
* @info 默认是监听可读事件的, 这里只处理可写事件的监听删除
|
||||
*/
|
||||
int UdpSessionNtfy::KqueueCtlAdd(void* args)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
KqFdRef* fd_ref = (KqFdRef*)args;
|
||||
//ASSERT(fd_ref != NULL);
|
||||
|
||||
int osfd = this->GetOsfd();
|
||||
|
||||
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
|
||||
KqueuerObj* old_obj = fd_ref->GetNotifyObj();
|
||||
if ((old_obj != NULL) && (old_obj != this))
|
||||
{
|
||||
MTLOG_ERROR("epfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
|
||||
if (!frame->KqueueCtrlAdd(osfd, KQ_EVENT_WRITE))
|
||||
{
|
||||
MTLOG_ERROR("epfd ref add failed, log");
|
||||
return -2;
|
||||
}
|
||||
this->EnableOutput();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
int UdpSessionNtfy::KqueueCtlDel(void* args)
|
||||
{
|
||||
MtFrame* frame = MtFrame::Instance();
|
||||
KqFdRef* fd_ref = (KqFdRef*)args;
|
||||
//ASSERT(fd_ref != NULL);
|
||||
|
||||
int osfd = this->GetOsfd();
|
||||
|
||||
// 通知对象需要更新, FD通知对象理论上不会复用, 这里做冲突检查, 异常log记录
|
||||
KqueuerObj* old_obj = fd_ref->GetNotifyObj();
|
||||
if (old_obj != this)
|
||||
{
|
||||
MTLOG_ERROR("epfd ref conflict, fd: %d, old: %p, now: %p", osfd, old_obj, this);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 调用框架的epoll ctl接口, 屏蔽epoll ctrl细节
|
||||
if (!frame->KqueueCtrlDel(osfd, KQ_EVENT_WRITE))
|
||||
{
|
||||
MTLOG_ERROR("epfd ref del failed, log");
|
||||
return -2;
|
||||
}
|
||||
this->DisableOutput();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
int TcpKeepNtfy::InputNotify()
|
||||
{
|
||||
KeepaliveClose();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
int TcpKeepNtfy::OutputNotify()
|
||||
{
|
||||
KeepaliveClose();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
int TcpKeepNtfy::HangupNotify()
|
||||
{
|
||||
KeepaliveClose();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 触发实际连接关闭操作
|
||||
*/
|
||||
void TcpKeepNtfy::KeepaliveClose()
|
||||
{
|
||||
if (_keep_conn) {
|
||||
MTLOG_DEBUG("remote close, fd %d, close connection", _fd);
|
||||
ConnectionMgr::Instance()->CloseIdleTcpKeep(_keep_conn);
|
||||
} else {
|
||||
MTLOG_ERROR("_keep_conn ptr null, error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief session全局管理句柄
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
NtfyObjMgr* NtfyObjMgr::_instance = NULL;
|
||||
NtfyObjMgr* NtfyObjMgr::Instance (void)
|
||||
{
|
||||
if (NULL == _instance)
|
||||
{
|
||||
_instance = new NtfyObjMgr;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief session管理全局的销毁接口
|
||||
*/
|
||||
void NtfyObjMgr::Destroy()
|
||||
{
|
||||
if( _instance != NULL )
|
||||
{
|
||||
delete _instance;
|
||||
_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
NtfyObjMgr::NtfyObjMgr()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数, 不持有资源, 并不负责清理
|
||||
*/
|
||||
NtfyObjMgr::~NtfyObjMgr()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册长连接session信息
|
||||
* @param session_name 长连接的标识, 每个连接处理一类session封装格式
|
||||
* @param session 长连接对象指针, 定义连接属性
|
||||
* @return 0 成功, < 0 失败
|
||||
*/
|
||||
int NtfyObjMgr::RegisterSession(int session_name, ISessionNtfy* session)
|
||||
{
|
||||
if (session_name <= 0 || NULL == session) {
|
||||
MTLOG_ERROR("session %d, register %p failed", session_name, session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SessionMap::iterator it = _session_map.find(session_name);
|
||||
if (it != _session_map.end())
|
||||
{
|
||||
MTLOG_ERROR("session %d, register %p already", session_name, session);
|
||||
return -2;
|
||||
}
|
||||
|
||||
_session_map.insert(SessionMap::value_type(session_name, session));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取注册长连接session信息
|
||||
* @param session_name 长连接的标识, 每个连接处理一类session封装格式
|
||||
* @return 长连接指针, 失败为NULL
|
||||
*/
|
||||
ISessionNtfy* NtfyObjMgr::GetNameSession(int session_name)
|
||||
{
|
||||
SessionMap::iterator it = _session_map.find(session_name);
|
||||
if (it != _session_map.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取通用通知对象, 如线程通知对象与session通知代理对象
|
||||
* @param type 类型, 线程通知类型,UDP/TCP SESSION通知等
|
||||
* @param session_name proxy模型,一并获取session对象
|
||||
* @return 通知对象的指针, 失败为NULL
|
||||
*/
|
||||
KqueuerObj* NtfyObjMgr::GetNtfyObj(int type, int session_name)
|
||||
{
|
||||
KqueuerObj* obj = NULL;
|
||||
SessionProxy* proxy = NULL;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NTFY_OBJ_THREAD:
|
||||
obj = _fd_ntfy_pool.AllocPtr();
|
||||
break;
|
||||
|
||||
case NTFY_OBJ_SESSION:
|
||||
proxy = _udp_proxy_pool.AllocPtr();
|
||||
obj = proxy;
|
||||
break;
|
||||
|
||||
case NTFY_OBJ_KEEPALIVE: // no need get this now
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 获取底层的长连接对象, 关联代理与实际的通知对象
|
||||
if (proxy) {
|
||||
ISessionNtfy* ntfy = this->GetNameSession(session_name);
|
||||
if (!ntfy) {
|
||||
MTLOG_ERROR("ntfy get session name(%d) failed", session_name);
|
||||
this->FreeNtfyObj(proxy);
|
||||
obj = NULL;
|
||||
} else {
|
||||
proxy->SetRealNtfyObj(ntfy);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 释放通知对象指针
|
||||
* @param obj 通知对象
|
||||
*/
|
||||
void NtfyObjMgr::FreeNtfyObj(KqueuerObj* obj)
|
||||
{
|
||||
SessionProxy* proxy = NULL;
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
int type = obj->GetNtfyType();
|
||||
obj->Reset();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NTFY_OBJ_THREAD:
|
||||
return _fd_ntfy_pool.FreePtr(obj);
|
||||
break;
|
||||
|
||||
case NTFY_OBJ_SESSION:
|
||||
proxy = dynamic_cast<SessionProxy*>(obj);
|
||||
return _udp_proxy_pool.FreePtr(proxy);
|
||||
break;
|
||||
|
||||
case NTFY_OBJ_KEEPALIVE:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
delete obj;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,568 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_notify.h
|
||||
* @info 微线程注册的通知对象定义与管理
|
||||
* @time 20130926
|
||||
**/
|
||||
|
||||
#ifndef __MT_NOTIFY_H__
|
||||
#define __MT_NOTIFY_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include "mt_mbuf_pool.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
using std::queue;
|
||||
using std::map;
|
||||
|
||||
class SessionProxy;
|
||||
class TcpKeepConn;
|
||||
|
||||
/**
|
||||
* @brief 通知对象类型
|
||||
*/
|
||||
enum NTFY_OBJ_TYPE
|
||||
{
|
||||
NTFY_OBJ_UNDEF = 0, ///< 未定义的连接对象
|
||||
NTFY_OBJ_THREAD = 1, ///< 短连接对象, 一个fd对应一个thread
|
||||
NTFY_OBJ_KEEPALIVE = 2, ///< TCP心跳保持的notify对象, 不关联 thread
|
||||
NTFY_OBJ_SESSION = 3, ///< UDP的session模型, 代理的长连接对象
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 协议类型定义
|
||||
*/
|
||||
enum MULTI_PROTO
|
||||
{
|
||||
MT_UNKNOWN = 0,
|
||||
MT_UDP = 0x1, ///< 连接类型 UDP
|
||||
MT_TCP = 0x2 ///< 连接类型 TCP
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 长连接session模型, 批量收发调度管理接口
|
||||
*/
|
||||
typedef TAILQ_ENTRY(SessionProxy) NtfyEntry;
|
||||
typedef TAILQ_HEAD(__NtfyList, SessionProxy) NtfyList;
|
||||
class ISessionNtfy : public KqueuerObj
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 检查报文完整性, 同时提取sessionid信息
|
||||
* @param pkg 报文指针
|
||||
* @param len 报文已接收长度
|
||||
* @param session 解析的sessionid, 输出参数
|
||||
* @return <=0 失败, >0 实际报文长度
|
||||
*/
|
||||
virtual int GetSessionId(void* pkg, int len, int& session) { return 0;};
|
||||
|
||||
/**
|
||||
* @brief 创建socket, 监听可读事件
|
||||
* @return fd的句柄, <0 失败
|
||||
*/
|
||||
virtual int CreateSocket(){return -1;};
|
||||
|
||||
/**
|
||||
* @brief 关闭socket, 停止监听可读事件
|
||||
*/
|
||||
virtual void CloseSocket(){};
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int InputNotify(){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int OutputNotify(){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
virtual int HangupNotify(){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int KqueueCtlAdd(void* args){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int KqueueCtlDel(void* args){return 0;};
|
||||
|
||||
/**
|
||||
* @brief 构造函数析构函数
|
||||
*/
|
||||
ISessionNtfy(): KqueuerObj(0) {
|
||||
_proto = MT_UDP;
|
||||
_buff_size = 0;
|
||||
_msg_buff = NULL;
|
||||
TAILQ_INIT(&_write_list);
|
||||
}
|
||||
virtual ~ISessionNtfy() { };
|
||||
|
||||
/**
|
||||
* @brief 设置本次处理的proto信息
|
||||
*/
|
||||
void SetProtoType(MULTI_PROTO proto) {
|
||||
_proto = proto;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取本次处理的proto信息
|
||||
* @return proto type
|
||||
*/
|
||||
MULTI_PROTO GetProtoType() {
|
||||
return _proto;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 设置buff大小, 决定实际使用的msgbuff队列
|
||||
* @return 0成功
|
||||
*/
|
||||
void SetMsgBuffSize(int buff_size) {
|
||||
_buff_size = buff_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取预置的buff大小, 如无设置, 返回65535
|
||||
* @return 框架申请的消息buff最大长度
|
||||
*/
|
||||
int GetMsgBuffSize() {
|
||||
return (_buff_size > 0) ? _buff_size : 65535;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通知代理进入等待状态
|
||||
*/
|
||||
void InsertWriteWait(SessionProxy* proxy);
|
||||
|
||||
/**
|
||||
* @brief 通知代理取消等待状态
|
||||
*/
|
||||
void RemoveWriteWait(SessionProxy* proxy);
|
||||
|
||||
/**
|
||||
* @brief 观察者模式, 通知写等待线程
|
||||
* @info UDP可以通知每个线程执行写操作, TCP需要排队写
|
||||
*/
|
||||
virtual void NotifyWriteWait(){};
|
||||
|
||||
protected:
|
||||
MULTI_PROTO _proto; // 协议类型 UDP/TCP
|
||||
int _buff_size; // 最大消息长度
|
||||
NtfyList _write_list; // 可写等待队列
|
||||
MtMsgBuf* _msg_buff; // 临时收包存放缓冲区
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief UDP长连接session模型的基类接口
|
||||
* @info 业务session需要继承该接口, 设置属性, 实现获取GetSessionId函数
|
||||
* @info 保留扩展, 如指定本地端口等
|
||||
*/
|
||||
class UdpSessionNtfy : public ISessionNtfy
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 检查报文完整性, 同时提取sessionid信息, 由继承类实现它
|
||||
* @param pkg 报文指针
|
||||
* @param len 报文已接收长度
|
||||
* @param session 解析的sessionid, 输出参数
|
||||
* @return <=0 失败, >0 实际报文长度
|
||||
*/
|
||||
virtual int GetSessionId(void* pkg, int len, int& session) { return 0;};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
UdpSessionNtfy() : ISessionNtfy(){
|
||||
ISessionNtfy::SetProtoType(MT_UDP);
|
||||
|
||||
_local_addr.sin_family = AF_INET;
|
||||
_local_addr.sin_addr.s_addr = 0;
|
||||
_local_addr.sin_port = 0;
|
||||
}
|
||||
virtual ~UdpSessionNtfy() { };
|
||||
|
||||
/**
|
||||
* @brief 观察者模式, 通知写等待线程
|
||||
* @info UDP可以通知每个线程执行写操作, TCP需要排队写
|
||||
*/
|
||||
virtual void NotifyWriteWait();
|
||||
|
||||
/**
|
||||
* @brief 创建socket, 监听可读事件
|
||||
* @return fd的句柄, <0 失败
|
||||
*/
|
||||
virtual int CreateSocket();
|
||||
|
||||
/**
|
||||
* @brief 关闭socket, 停止监听可读事件
|
||||
*/
|
||||
virtual void CloseSocket();
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int InputNotify();
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int OutputNotify();
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
virtual int HangupNotify();
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int KqueueCtlAdd(void* args);
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int KqueueCtlDel(void* args);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 设置udp本地的本地bind地址, 多进程bind会冲突, 暂时停用
|
||||
* 后续开放, 能保证每进程唯一port可使用
|
||||
*/
|
||||
void SetLocalAddr(struct sockaddr_in* local_addr) {
|
||||
memcpy(&_local_addr, local_addr, sizeof(_local_addr));
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
struct sockaddr_in _local_addr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief UDP模式session模型的代理通知对象, 多个代理映射到某一个session notify
|
||||
* @info session proxy 本身不在epoll注册, 不会有事件通知, 但需要关心超时等
|
||||
*/
|
||||
class SessionProxy : public KqueuerObj
|
||||
{
|
||||
public:
|
||||
int _flag; ///< 0-不在队列中, 1-在等待队列
|
||||
NtfyEntry _write_entry; ///< 关联可写等待队列的管理入口
|
||||
|
||||
/**
|
||||
* @brief 设置代理对象, 关联代理的fd句柄
|
||||
*/
|
||||
void SetRealNtfyObj(ISessionNtfy* obj) {
|
||||
_real_ntfy = obj;
|
||||
this->SetOsfd(obj->GetOsfd());
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取代理对象指针
|
||||
*/
|
||||
ISessionNtfy* GetRealNtfyObj() {
|
||||
return _real_ntfy;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 回收处理, 设置清理动作
|
||||
*/
|
||||
virtual void Reset() {
|
||||
_real_ntfy = NULL;
|
||||
this->KqueuerObj::Reset();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int KqueueCtlAdd(void* args) {
|
||||
if (!_real_ntfy) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int events = this->GetEvents();
|
||||
if (!(events & KQ_EVENT_WRITE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_real_ntfy->KqueueCtlAdd(args) < 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
_real_ntfy->InsertWriteWait(this);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 调整epoll侦听事件的回调接口, 长连接始终EPOLLIN, 偶尔EPOLLOUT
|
||||
* @param args fd引用对象的指针
|
||||
* @return 0 成功, < 0 失败, 要求事务回滚到操作前状态
|
||||
*/
|
||||
virtual int KqueueCtlDel(void* args) {
|
||||
if (!_real_ntfy) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int events = this->GetEvents();
|
||||
if (!(events & KQ_EVENT_WRITE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_real_ntfy->RemoveWriteWait(this);
|
||||
return _real_ntfy->KqueueCtlDel(args);
|
||||
};
|
||||
|
||||
private:
|
||||
ISessionNtfy* _real_ntfy; // 实际的执行者
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief TCP模式的keepalive通知对象, 仅仅关心可读事件, 确认是否对端关闭
|
||||
*/
|
||||
class TcpKeepNtfy: public KqueuerObj
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
TcpKeepNtfy() : _keep_conn(NULL){};
|
||||
|
||||
/**
|
||||
* @brief 可读事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int InputNotify();
|
||||
|
||||
/**
|
||||
* @brief 可写事件通知接口, 考虑通知处理可能会破坏环境, 可用返回值区分
|
||||
* @return 0 该fd可继续处理其它事件; !=0 该fd需跳出回调处理
|
||||
*/
|
||||
virtual int OutputNotify();
|
||||
|
||||
/**
|
||||
* @brief 异常通知接口
|
||||
* @return 忽略返回值, 跳过其它事件处理
|
||||
*/
|
||||
virtual int HangupNotify();
|
||||
|
||||
/**
|
||||
* @brief 设置代理对象
|
||||
*/
|
||||
void SetKeepNtfyObj(TcpKeepConn* obj) {
|
||||
_keep_conn = obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取代理对象指针
|
||||
*/
|
||||
TcpKeepConn* GetKeepNtfyObj() {
|
||||
return _keep_conn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 触发实际连接关闭操作
|
||||
*/
|
||||
void KeepaliveClose();
|
||||
|
||||
|
||||
private:
|
||||
TcpKeepConn* _keep_conn; // 实际的连接器对象
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 动态内存池模板类, 对于反复new/delete的对象操作, 可一定程度上提高性能
|
||||
*/
|
||||
template<typename ValueType>
|
||||
class CPtrPool
|
||||
{
|
||||
public:
|
||||
typedef typename std::queue<ValueType*> PtrQueue; ///< 内存指针队列
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 动态内存池构造函数
|
||||
* @param max 最大空闲队列保存的指针元素, 默认500
|
||||
*/
|
||||
explicit CPtrPool(int max = 500) : _max_free(max), _total(0){};
|
||||
|
||||
/**
|
||||
* @brief 动态内存池析构函数, 仅仅清理掉freelist
|
||||
*/
|
||||
~CPtrPool() {
|
||||
ValueType* ptr = NULL;
|
||||
while (!_ptr_list.empty()) {
|
||||
ptr = _ptr_list.front();
|
||||
_ptr_list.pop();
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 分配内存指针, 优先从缓存获取, 无空闲可用则动态 new 申请
|
||||
* @return 模板类型的指针元素, 空表示内存申请失败
|
||||
*/
|
||||
ValueType* AllocPtr() {
|
||||
ValueType* ptr = NULL;
|
||||
if (!_ptr_list.empty()) {
|
||||
ptr = _ptr_list.front();
|
||||
_ptr_list.pop();
|
||||
} else {
|
||||
ptr = new ValueType;
|
||||
_total++;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 释放内存指针, 若空闲队列超过配额, 则直接释放, 否则队列缓存
|
||||
*/
|
||||
void FreePtr(ValueType* ptr) {
|
||||
if ((int)_ptr_list.size() >= _max_free) {
|
||||
delete ptr;
|
||||
_total--;
|
||||
} else {
|
||||
_ptr_list.push(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
PtrQueue _ptr_list; ///< 空闲队列
|
||||
int _max_free; ///< 最大空闲元素
|
||||
int _total; ///< 所有new的对象个数统计
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 通知对象全局管理器
|
||||
*/
|
||||
class NtfyObjMgr
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::map<int, ISessionNtfy*> SessionMap;
|
||||
typedef CPtrPool<KqueuerObj> NtfyThreadQueue;
|
||||
typedef CPtrPool<SessionProxy> NtfySessionQueue;
|
||||
|
||||
/**
|
||||
* @brief 会话上下文的全局管理句柄接口
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
static NtfyObjMgr* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 清理接口
|
||||
*/
|
||||
static void Destroy(void);
|
||||
|
||||
/**
|
||||
* @brief 注册长连接session信息
|
||||
* @param session_name 长连接的标识, 每个连接处理一类session封装格式
|
||||
* @param session 长连接对象指针, 定义连接属性
|
||||
* @return 0 成功, < 0 失败
|
||||
*/
|
||||
int RegisterSession(int session_name, ISessionNtfy* session);
|
||||
|
||||
/**
|
||||
* @brief 获取注册长连接session信息
|
||||
* @param session_name 长连接的标识, 每个连接处理一类session封装格式
|
||||
* @return 长连接指针, 失败为NULL
|
||||
*/
|
||||
ISessionNtfy* GetNameSession(int session_name);
|
||||
|
||||
/**
|
||||
* @brief 获取通用通知对象, 如线程通知对象与session通知代理对象
|
||||
* @param type 类型, 线程通知类型,UDP/TCP SESSION通知等
|
||||
* @param session_name proxy模型,一并获取session对象
|
||||
* @return 通知对象的指针, 失败为NULL
|
||||
*/
|
||||
KqueuerObj* GetNtfyObj(int type, int session_name = 0);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 释放通知对象指针
|
||||
* @param obj 通知对象
|
||||
*/
|
||||
void FreeNtfyObj(KqueuerObj* obj);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~NtfyObjMgr();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
NtfyObjMgr();
|
||||
|
||||
static NtfyObjMgr * _instance; ///< 单例类句柄
|
||||
SessionMap _session_map; ///< 全局的注册session管理
|
||||
NtfyThreadQueue _fd_ntfy_pool; ///< fd通知对象
|
||||
NtfySessionQueue _udp_proxy_pool; ///< fd通知对象
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mt_incl.h"
|
||||
#include "micro_thread.h"
|
||||
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
static bool run = true;
|
||||
|
||||
static struct sockaddr_in addr;
|
||||
|
||||
int mt_tcp_create_sock(void)
|
||||
{
|
||||
int fd;
|
||||
//int flag;
|
||||
|
||||
// ´´½¨socket
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf("create tcp socket failed, error: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ÉèÖÃsocket·Ç×èÈû
|
||||
|
||||
/*
|
||||
flag = fcntl(fd, F_GETFL, 0);
|
||||
if (flag == -1)
|
||||
{
|
||||
::close(fd);
|
||||
printf("get fd flags failed, error: %m\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (flag & O_NONBLOCK)
|
||||
return fd;
|
||||
|
||||
if (fcntl(fd, F_SETFL, flag | O_NONBLOCK | O_NDELAY) == -1)
|
||||
{
|
||||
::close(fd);
|
||||
printf("set fd flags failed, error: %m\n");
|
||||
return -3;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int nb = 1;
|
||||
ioctl(fd, FIONBIO, &nb);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void echo(void* arg)
|
||||
{
|
||||
char buf[1024];
|
||||
int ret = 0;
|
||||
int *p = (int *)arg;
|
||||
int clt_fd = *p;
|
||||
printf("start to echo with client: %d\n", clt_fd);
|
||||
while (1) {
|
||||
ret = mt_recv(clt_fd, (void*)buf,1024,0,-1);
|
||||
if(ret<0)
|
||||
{
|
||||
printf("recv client data failed[%m]\n");
|
||||
mt_sleep(1);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = mt_send(clt_fd, (void*)buf, ret, 0, 1000);
|
||||
if (ret < 0) {
|
||||
printf("send client data failed[%m]\n");
|
||||
mt_sleep(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(clt_fd>0) close(clt_fd);
|
||||
delete p;
|
||||
}
|
||||
|
||||
void server(void* arg)
|
||||
{
|
||||
int fd = mt_tcp_create_sock();
|
||||
if(fd<0)
|
||||
{
|
||||
run = false;
|
||||
printf("create listen socket failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int optval = 1;
|
||||
unsigned optlen = sizeof(optval);
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
|
||||
|
||||
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
|
||||
{
|
||||
close(fd);
|
||||
printf("bind failed [%m]\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
if (listen(fd, 1024) < 0)
|
||||
{
|
||||
close(fd);
|
||||
printf("listen failed[%m]\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
int clt_fd = 0;
|
||||
int *p;
|
||||
while(run)
|
||||
{
|
||||
struct sockaddr_in client_addr;
|
||||
int addr_len = sizeof(client_addr);;
|
||||
|
||||
clt_fd = mt_accept(fd, (struct sockaddr*)&client_addr, (socklen_t*)&addr_len, -1);
|
||||
if(clt_fd<0)
|
||||
{
|
||||
mt_sleep(1);
|
||||
continue;
|
||||
}
|
||||
int nb = 1;
|
||||
ioctl(clt_fd, FIONBIO, &nb);
|
||||
p = new int(clt_fd);
|
||||
printf("start a new micro thread to echo with client: %d\n", clt_fd);
|
||||
mt_start_thread((void*)echo, (void *)p);
|
||||
mt_sleep(1);
|
||||
}
|
||||
printf("server exit\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
struct MsgCtx
|
||||
{
|
||||
int check_count;
|
||||
int msg_id;
|
||||
};
|
||||
|
||||
int TcpMsgChecker(void* buf, int len, bool closed, void* msg_ctx, bool& msg_len_detected)
|
||||
{
|
||||
|
||||
struct MsgCtx* ctx = (struct MsgCtx*)msg_ctx;
|
||||
|
||||
ctx->check_count++;
|
||||
printf("#%d msg check msg times #%d, buf=%p, len=%d, closed=%d\n", ctx->msg_id, ctx->check_count, buf,len,closed);
|
||||
|
||||
if(len<4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int r_len=ntohl(*(uint32_t*)buf);
|
||||
//if(r_len!=len)
|
||||
// {
|
||||
// return 0;
|
||||
//}
|
||||
msg_len_detected = true;
|
||||
|
||||
return r_len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void client(void* arg)
|
||||
{
|
||||
//char buf[1024];
|
||||
|
||||
struct MsgCtx ctx;
|
||||
void* rcv_buf = NULL;
|
||||
int rcv_len = 0;
|
||||
bool keep_rcv_buf = true;
|
||||
int ret = 0;
|
||||
char snd_ch = 1;
|
||||
int count=0;
|
||||
while(true)
|
||||
{
|
||||
rcv_buf = NULL;
|
||||
rcv_len = 1;
|
||||
keep_rcv_buf = (((++count)%2) == 0);
|
||||
ctx.check_count = 0;
|
||||
ctx.msg_id = count;
|
||||
ret = mt_tcpsendrcv_ex((struct sockaddr_in*)&addr, (void*)&snd_ch, 1, rcv_buf, rcv_len,20000, &TcpMsgChecker, (void*)&ctx, MT_TCP_SHORT,keep_rcv_buf);
|
||||
if(ret<0)
|
||||
{
|
||||
printf("client send rcv failed[%m]\n");
|
||||
continue;
|
||||
}
|
||||
printf("#%d client tcp finished: rcv_len=%d, rcv_buf=%p, keep_rcv_buf=%d\n",count, rcv_len, rcv_buf,keep_rcv_buf);
|
||||
|
||||
if(keep_rcv_buf)
|
||||
{
|
||||
if(rcv_buf==NULL)
|
||||
{
|
||||
printf("client should hold rcvbuf, something wrong\n");
|
||||
continue;
|
||||
}
|
||||
free(rcv_buf);
|
||||
}
|
||||
}
|
||||
|
||||
printf("client exit!");
|
||||
}
|
||||
*/
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
memset((void*)&addr,0,sizeof(addr));
|
||||
addr.sin_family=AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr("112.90.143.29");
|
||||
addr.sin_port = htons(19999);
|
||||
|
||||
mt_init_frame("./config.ini", argc, argv);
|
||||
|
||||
mt_start_thread((void*)server,NULL);
|
||||
|
||||
while (run) {
|
||||
mt_sleep(10);
|
||||
}
|
||||
|
||||
printf("main exit");
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_session.cpp
|
||||
* @info 微线程后端连接会话管理实现部分
|
||||
* @time 20130924
|
||||
**/
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_session.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
/**
|
||||
* @brief session接口资源自回收处理
|
||||
*/
|
||||
ISession::~ISession()
|
||||
{
|
||||
if (_session_flg) {
|
||||
SessionMgr* sessionmgr = SessionMgr::Instance();
|
||||
sessionmgr->RemoveSession(_session_id);
|
||||
_session_flg = (int)SESSION_IDLE; // 额外处理, 在remove函数内处理会加大开销
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief session全局管理句柄
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
SessionMgr* SessionMgr::_instance = NULL;
|
||||
SessionMgr* SessionMgr::Instance (void)
|
||||
{
|
||||
if (NULL == _instance)
|
||||
{
|
||||
_instance = new SessionMgr;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief session管理全局的销毁接口
|
||||
*/
|
||||
void SessionMgr::Destroy()
|
||||
{
|
||||
if( _instance != NULL )
|
||||
{
|
||||
delete _instance;
|
||||
_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
SessionMgr::SessionMgr()
|
||||
{
|
||||
_curr_session = 0;
|
||||
_hash_map = new HashList(100000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数, 不持有资源, 并不负责清理
|
||||
*/
|
||||
SessionMgr::~SessionMgr()
|
||||
{
|
||||
if (_hash_map) {
|
||||
delete _hash_map;
|
||||
_hash_map = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Session数据存储
|
||||
*/
|
||||
int SessionMgr::InsertSession(ISession* session)
|
||||
{
|
||||
if (!_hash_map || !session) {
|
||||
MTLOG_ERROR("Mngr not init(%p), or session null(%p)", _hash_map, session);
|
||||
return -100;
|
||||
}
|
||||
|
||||
int flag = session->GetSessionFlag();
|
||||
if (flag & SESSION_INUSE) {
|
||||
MTLOG_ERROR("Session already in hash, bugs, %p, %d", session, flag);
|
||||
return -200;
|
||||
}
|
||||
|
||||
session->SetSessionFlag((int)SESSION_INUSE);
|
||||
return _hash_map->HashInsert(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查询session数据
|
||||
*/
|
||||
ISession* SessionMgr::FindSession(int session_id)
|
||||
{
|
||||
if (!_hash_map) {
|
||||
MTLOG_ERROR("Mngr not init(%p)", _hash_map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISession key;
|
||||
key.SetSessionId(session_id);
|
||||
return dynamic_cast<ISession*>(_hash_map->HashFind(&key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除session数据
|
||||
*/
|
||||
void SessionMgr::RemoveSession(int session_id)
|
||||
{
|
||||
if (!_hash_map) {
|
||||
MTLOG_ERROR("Mngr not init(%p)", _hash_map);
|
||||
return;
|
||||
}
|
||||
|
||||
ISession key;
|
||||
key.SetSessionId(session_id);
|
||||
return _hash_map->HashRemove(&key);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_session.h
|
||||
* @info 微线程的事件会话管理部分, 每个后端连接关联一session信息
|
||||
* @time 20130924
|
||||
**/
|
||||
|
||||
#ifndef __MT_SESSION_H__
|
||||
#define __MT_SESSION_H__
|
||||
|
||||
#include "hash_list.h"
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
class MicroThread;
|
||||
class IMtConnection;
|
||||
|
||||
enum SESSION_FLAG
|
||||
{
|
||||
SESSION_IDLE = 0, ///< SESSION 未加入hash管理
|
||||
SESSION_INUSE = 1, ///< SESSION 进入管理状态
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 并发请求session接口定义, 根据session可映射出thread,action等
|
||||
*/
|
||||
class ISession : public HashKey
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 构造与析构函数
|
||||
*/
|
||||
ISession() : _session_id(0), _session_flg(0), _thread(NULL), _connection(NULL) {};
|
||||
virtual ~ISession();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 会话ID的设置与获取
|
||||
*/
|
||||
void SetSessionId(int id) {
|
||||
_session_id = id;
|
||||
};
|
||||
int GetSessionId() {
|
||||
return _session_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 关联线程的设置与获取
|
||||
*/
|
||||
MicroThread* GetOwnerThread(){
|
||||
return _thread;
|
||||
};
|
||||
void SetOwnerThread(MicroThread* thread) {
|
||||
_thread = thread;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 关联连接的设置与获取
|
||||
*/
|
||||
IMtConnection* GetSessionConn(){
|
||||
return _connection;
|
||||
};
|
||||
void SetSessionConn(IMtConnection* conn) {
|
||||
_connection = conn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 会话flag的设置与获取
|
||||
*/
|
||||
void SetSessionFlag(int flag) {
|
||||
_session_flg = flag;
|
||||
};
|
||||
int GetSessionFlag() {
|
||||
return _session_flg;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的hash算法, 获取key的hash值
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual uint32_t HashValue(){
|
||||
return _session_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 节点元素的cmp方法, 同一桶ID下, 按key比较
|
||||
* @return 节点元素的hash值
|
||||
*/
|
||||
virtual int HashCmp(HashKey* rhs){
|
||||
return this->_session_id - (int)rhs->HashValue();
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
int _session_id; // 会话id信息
|
||||
int _session_flg; // 记录session状态 0 -不在hash中, 1 -hash管理中
|
||||
MicroThread* _thread; // 会话所属的session
|
||||
IMtConnection* _connection; // 会话关联的连接
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 全局的session管理结构
|
||||
*/
|
||||
class SessionMgr
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief 会话上下文的全局管理句柄接口
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
static SessionMgr* Instance (void);
|
||||
|
||||
/**
|
||||
* @brief 全局的删除接口
|
||||
*/
|
||||
static void Destroy();
|
||||
|
||||
/**
|
||||
* @brief 获取sessionid
|
||||
* @return 全局句柄指针
|
||||
*/
|
||||
int GetSessionId(void) {
|
||||
_curr_session++;
|
||||
if (!_curr_session) {
|
||||
_curr_session++;
|
||||
}
|
||||
return _curr_session;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Session数据存储
|
||||
*/
|
||||
int InsertSession(ISession* session);
|
||||
|
||||
/**
|
||||
* @brief 查询session数据
|
||||
*/
|
||||
ISession* FindSession(int session_id);
|
||||
|
||||
/**
|
||||
* @brief 删除session数据
|
||||
*/
|
||||
void RemoveSession(int session_id);
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~SessionMgr();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief 消息buff的构造函数
|
||||
*/
|
||||
SessionMgr();
|
||||
|
||||
static SessionMgr * _instance; ///< 单例类句柄
|
||||
int _curr_session; ///< session种子
|
||||
HashList* _hash_map; ///< 按sessionid hash存储
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,413 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename mt_sys_hook.cpp
|
||||
* @info 微线程hook系统api, 以不用额外编译的优势, 转同步为异步库
|
||||
* 只hook socket相关的API, HOOK 部分, 参考pth与libco实现
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "micro_thread.h"
|
||||
#include "mt_sys_hook.h"
|
||||
#include "ff_hook.h"
|
||||
|
||||
using namespace NS_MICRO_THREAD;
|
||||
|
||||
|
||||
#define MT_HOOK_MAX_FD 65535*2
|
||||
#define MT_FD_FLG_INUSE 0x1
|
||||
#define MT_FD_FLG_UNBLOCK 0x2
|
||||
|
||||
|
||||
/**
|
||||
* @brief 每sockt分配一个管理结构, 标记是否需要HOOK, 超时时间等
|
||||
*/
|
||||
typedef struct socket_hook_info
|
||||
{
|
||||
int sock_flag; // 是否使用HOOK, 是否用户设置UNBLOCK
|
||||
int read_timeout; // socket读取超时时间, ms单位
|
||||
int write_timeout; // socket写入超时时间, ms单位
|
||||
}MtHookFd;
|
||||
|
||||
MtSyscallFuncTab g_mt_syscall_tab; // 全局符号表
|
||||
int g_mt_hook_flag; // 全局控制标记
|
||||
int g_ff_hook_flag; // 全局控制标记
|
||||
static MtHookFd g_mt_hook_fd_tab[MT_HOOK_MAX_FD]; // 全局fd管理
|
||||
|
||||
/**
|
||||
* @brief 内部接口, 获取hook fd相关的信息, socket 默认hook, open 默认no hook
|
||||
*/
|
||||
MtHookFd* mt_hook_find_fd(int fd)
|
||||
{
|
||||
if ((fd < 0) || (fd >= MT_HOOK_MAX_FD)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MtHookFd* fd_info = &g_mt_hook_fd_tab[fd];
|
||||
if (!(fd_info->sock_flag & MT_FD_FLG_INUSE)) {
|
||||
return NULL;
|
||||
} else {
|
||||
return fd_info;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 内部接口, 创建socket设置hook, 只处理socket, 不处理文件IO
|
||||
*/
|
||||
void mt_hook_new_fd(int fd)
|
||||
{
|
||||
if ((fd < 0) || (fd >= MT_HOOK_MAX_FD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MtHookFd* fd_info = &g_mt_hook_fd_tab[fd];
|
||||
fd_info->sock_flag = MT_FD_FLG_INUSE;
|
||||
fd_info->read_timeout = 500;
|
||||
fd_info->write_timeout = 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 内部接口, 关闭hook socket
|
||||
*/
|
||||
void mt_hook_free_fd(int fd)
|
||||
{
|
||||
if ((fd < 0) || (fd >= MT_HOOK_MAX_FD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MtHookFd* fd_info = &g_mt_hook_fd_tab[fd];
|
||||
fd_info->sock_flag = 0;
|
||||
fd_info->read_timeout = 0;
|
||||
fd_info->write_timeout = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 截获用户设置的非阻塞标记
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int ioctl(int fd, unsigned long cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, cmd);
|
||||
void* arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
mt_hook_syscall(ioctl);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_ioctl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
if (cmd == FIONBIO)
|
||||
{
|
||||
int flags = (arg != NULL) ? *((int*)arg) : 0;
|
||||
if (flags != 0) {
|
||||
hook_fd->sock_flag |= MT_FD_FLG_UNBLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
return ff_hook_ioctl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 默认设置unblock
|
||||
*/
|
||||
int socket(int domain, int type, int protocol)
|
||||
{
|
||||
mt_hook_syscall(socket);
|
||||
|
||||
if (!mt_hook_active())
|
||||
{
|
||||
return ff_hook_socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
int fd = ff_hook_socket(domain, type, protocol);
|
||||
if (fd < 0)
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
mt_hook_new_fd(fd);
|
||||
|
||||
|
||||
mt_hook_syscall(ioctl);
|
||||
int nb = 1;
|
||||
ff_hook_ioctl(fd, FIONBIO, &nb);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api
|
||||
*/
|
||||
int close(int fd)
|
||||
{
|
||||
mt_hook_syscall(close);
|
||||
if (!mt_hook_active())
|
||||
{
|
||||
return ff_hook_close(fd);
|
||||
}
|
||||
|
||||
mt_hook_free_fd(fd);
|
||||
return ff_hook_close(fd);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api
|
||||
*/
|
||||
int connect(int fd, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
mt_hook_syscall(connect);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_connect(fd, address, address_len);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_connect(fd, address, address_len);
|
||||
}
|
||||
|
||||
return MtFrame::connect(fd, address, (int)address_len, hook_fd->write_timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 用户已经设置unblock, 跳过
|
||||
*/
|
||||
ssize_t read(int fd, void *buf, size_t nbyte)
|
||||
{
|
||||
mt_hook_syscall(read);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_read(fd, buf, nbyte);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_read(fd, buf, nbyte);
|
||||
}
|
||||
|
||||
return MtFrame::read(fd, buf, nbyte, hook_fd->read_timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 用户已经设置unblock, 跳过
|
||||
*/
|
||||
ssize_t write(int fd, const void *buf, size_t nbyte)
|
||||
{
|
||||
mt_hook_syscall(write);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_write(fd, buf, nbyte);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_write(fd, buf, nbyte);
|
||||
}
|
||||
|
||||
return MtFrame::write(fd, buf, nbyte, hook_fd->write_timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 用户已经设置unblock, 跳过
|
||||
*/
|
||||
ssize_t sendto(int fd, const void *message, size_t length, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t dest_len)
|
||||
{
|
||||
mt_hook_syscall(sendto);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_sendto(fd, message, length, flags, dest_addr, dest_len);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_sendto(fd, message, length, flags, dest_addr, dest_len);
|
||||
}
|
||||
|
||||
return MtFrame::sendto(fd, message, (int)length, flags,
|
||||
dest_addr, dest_len, hook_fd->write_timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 用户已经设置unblock, 跳过
|
||||
*/
|
||||
ssize_t recvfrom(int fd, void *buffer, size_t length, int flags,
|
||||
struct sockaddr *address, socklen_t *address_len)
|
||||
{
|
||||
mt_hook_syscall(recvfrom);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_recvfrom(fd, buffer, length, flags, address, address_len);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_recvfrom(fd, buffer, length, flags, address, address_len);
|
||||
}
|
||||
|
||||
return MtFrame::recvfrom(fd, buffer, length, flags, address, address_len, hook_fd->read_timeout);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 用户已经设置unblock, 跳过
|
||||
*/
|
||||
ssize_t recv(int fd, void *buffer, size_t length, int flags)
|
||||
{
|
||||
mt_hook_syscall(recv);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_recv(fd, buffer, length, flags);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_recv(fd, buffer, length, flags);
|
||||
}
|
||||
|
||||
return MtFrame::recv(fd, buffer, length, flags, hook_fd->read_timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 用户已经设置unblock, 跳过
|
||||
*/
|
||||
ssize_t send(int fd, const void *buf, size_t nbyte, int flags)
|
||||
{
|
||||
mt_hook_syscall(send);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_send(fd, buf, nbyte, flags);
|
||||
}
|
||||
|
||||
if (hook_fd->sock_flag & MT_FD_FLG_UNBLOCK)
|
||||
{
|
||||
return ff_hook_send(fd, buf, nbyte, flags);
|
||||
}
|
||||
|
||||
return MtFrame::send(fd, buf, nbyte, flags, hook_fd->write_timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 截获用户设置的超时时间信息
|
||||
*/
|
||||
int setsockopt(int fd, int level, int option_name, const void *option_value, socklen_t option_len)
|
||||
{
|
||||
mt_hook_syscall(setsockopt);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_setsockopt(fd, level, option_name, option_value, option_len);
|
||||
}
|
||||
|
||||
if (SOL_SOCKET == level)
|
||||
{
|
||||
struct timeval *val = (struct timeval*)option_value;
|
||||
if (SO_RCVTIMEO == option_name)
|
||||
{
|
||||
hook_fd->read_timeout = val->tv_sec * 1000 + val->tv_usec / 1000;
|
||||
}
|
||||
else if (SO_SNDTIMEO == option_name)
|
||||
{
|
||||
hook_fd->write_timeout = val->tv_sec * 1000 + val->tv_usec / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return ff_hook_setsockopt(fd, level, option_name, option_value, option_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief HOOK接口, 初始化mt库后, 接管系统api, 截获用户设置的非阻塞标记
|
||||
*/
|
||||
int fcntl(int fd, int cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, cmd);
|
||||
void* arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
mt_hook_syscall(fcntl);
|
||||
MtHookFd* hook_fd = mt_hook_find_fd(fd);
|
||||
if (!mt_hook_active() || !hook_fd)
|
||||
{
|
||||
return ff_hook_fcntl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
if (cmd == F_SETFL)
|
||||
{
|
||||
va_start(ap, cmd);
|
||||
int flags = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
if (flags & O_NONBLOCK)
|
||||
{
|
||||
hook_fd->sock_flag |= MT_FD_FLG_UNBLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
return ff_hook_fcntl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
|
||||
int listen(int sockfd, int backlog)
|
||||
{
|
||||
mt_hook_syscall(listen);
|
||||
return ff_hook_listen(sockfd, backlog);
|
||||
}
|
||||
|
||||
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
mt_hook_syscall(bind);
|
||||
return ff_hook_bind(sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
mt_hook_syscall(accept);
|
||||
return ff_hook_accept(fd, addr, addrlen);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,130 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @filename mt_sys_hook.h
|
||||
* @info 微线程hook系统api, 以不用额外编译的优势, 转同步为异步库
|
||||
* HOOK 部分, 参考pth与libco实现
|
||||
*/
|
||||
|
||||
#ifndef _MT_SYS_HOOK___
|
||||
#define _MT_SYS_HOOK___
|
||||
|
||||
#include <poll.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "ff_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/* 1. HOOK 的函数定义部分 */
|
||||
/******************************************************************************/
|
||||
|
||||
typedef int (*func_socket)(int domain, int type, int protocol);
|
||||
typedef int (*func_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
typedef int (*func_listen)(int sockfd, int backlog);
|
||||
typedef int (*func_close)(int fd);
|
||||
typedef int (*func_connect)(int socket, const struct sockaddr *address, socklen_t address_len);
|
||||
typedef int (*func_accept)(int socket, struct sockaddr *address, socklen_t *addrlen);
|
||||
typedef ssize_t (*func_read)(int fildes, void *buf, size_t nbyte);
|
||||
typedef ssize_t (*func_write)(int fildes, const void *buf, size_t nbyte);
|
||||
typedef ssize_t (*func_sendto)(int socket, const void *message, size_t length,
|
||||
int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
|
||||
typedef ssize_t (*func_recvfrom)(int socket, void *buffer, size_t length,
|
||||
int flags, struct sockaddr *address, socklen_t *address_len);
|
||||
typedef size_t (*func_send)(int socket, const void *buffer, size_t length, int flags);
|
||||
typedef ssize_t (*func_recv)(int socket, void *buffer, size_t length, int flags);
|
||||
typedef int (*func_select)(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval *timeout);
|
||||
typedef int (*func_poll)(struct pollfd fds[], nfds_t nfds, int timeout);
|
||||
typedef int (*func_setsockopt)(int socket, int level, int option_name,
|
||||
const void *option_value, socklen_t option_len);
|
||||
typedef int (*func_ioctl)(int fd, unsigned long cmd, ...);
|
||||
typedef int (*func_fcntl)(int fd, int cmd, ...);
|
||||
|
||||
typedef unsigned int (*func_sleep)(unsigned int seconds);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 2. 全局的hook函数结构 */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Hook的原始函数集中管理定义, 支持动态新增处理
|
||||
*/
|
||||
typedef struct mt_syscall_func_tab
|
||||
{
|
||||
func_socket real_socket;
|
||||
func_bind real_bind;
|
||||
func_listen real_listen;
|
||||
func_close real_close;
|
||||
func_connect real_connect;
|
||||
func_read real_read;
|
||||
func_write real_write;
|
||||
func_sendto real_sendto;
|
||||
func_recvfrom real_recvfrom;
|
||||
func_send real_send;
|
||||
func_recv real_recv;
|
||||
func_setsockopt real_setsockopt;
|
||||
func_fcntl real_fcntl;
|
||||
func_ioctl real_ioctl;
|
||||
|
||||
func_sleep real_sleep; // 暂不支持,因为没有与fd关联, 防止滥用
|
||||
func_select real_select; // 暂不支持, 1024限制问题
|
||||
func_poll real_poll; // 暂不支持, 确认需求后实施
|
||||
|
||||
func_accept real_accept;
|
||||
}MtSyscallFuncTab;
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* 3. 直接调用原始系统api的接口 */
|
||||
/******************************************************************************/
|
||||
extern MtSyscallFuncTab g_mt_syscall_tab; // 全局符号表
|
||||
extern int g_mt_hook_flag; // 全局控制标记
|
||||
extern int g_ff_hook_flag; // 全局控制标记
|
||||
|
||||
#define mt_hook_syscall(name) \
|
||||
do { \
|
||||
if (!g_mt_syscall_tab.real_##name) { \
|
||||
g_mt_syscall_tab.real_##name = (func_##name)dlsym(RTLD_NEXT, #name);\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define mt_real_func(name) g_mt_syscall_tab.real_##name
|
||||
|
||||
#define mt_set_hook_flag() (g_mt_hook_flag = 1)
|
||||
#define mt_unset_hook_flag() (g_mt_hook_flag = 0)
|
||||
|
||||
#define mt_hook_active() (g_mt_hook_flag == 1)
|
||||
|
||||
#define ff_set_hook_flag() (g_ff_hook_flag = 1)
|
||||
#define ff_unset_hook_flag() (g_ff_hook_flag = 0)
|
||||
#define ff_hook_active() (g_ff_hook_flag == 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
/**
|
||||
* Tencent is pleased to support the open source community by making MSEC available.
|
||||
*
|
||||
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the GNU General Public 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
|
||||
*
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file mt_version.h
|
||||
* @info 微线程版本更新与记录信息文件
|
||||
* @time 20131018
|
||||
* ------------------------------------------------------------------------
|
||||
* @brief v0.2.0 - 支持UDP按session模式映射上下文
|
||||
* v0.2.1 - 支持TCP的sendrcv接口
|
||||
* v0.2.3 - 实时时间戳
|
||||
* v0.2.4 - 支持TCP的sendrcv接口动态扩展接收buf
|
||||
*/
|
||||
|
||||
#ifndef _MT_VERSION_EX__
|
||||
#define _MT_VERSION_EX__
|
||||
|
||||
namespace NS_MICRO_THREAD {
|
||||
|
||||
__attribute__((weak)) char IMT_VERSION[64] = "mt version: 0.2.4";
|
||||
|
||||
} // NAMESPACE NS_MICRO_THREAD
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2017 Igor Sysoev
|
||||
* Copyright (C) 2011-2017 Nginx, Inc.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*/
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
Documentation is available at http://nginx.org
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# aCC: HP ANSI C++ B3910B A.03.55.02
|
||||
|
||||
# C89 mode
|
||||
|
||||
CFLAGS="$CFLAGS -Ae"
|
||||
CC_TEST_FLAGS="-Ae"
|
||||
|
||||
PCRE_OPT="$PCRE_OPT -Ae"
|
||||
ZLIB_OPT="$ZLIB_OPT -Ae"
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# Borland C++ 5.5
|
||||
|
||||
# optimizations
|
||||
|
||||
# maximize speed
|
||||
CFLAGS="$CFLAGS -O2"
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium and Athlon
|
||||
CPU_OPT="-5"
|
||||
;;
|
||||
|
||||
pentiumpro)
|
||||
# optimize for Pentium Pro, Pentium II and Pentium III
|
||||
CPU_OPT="-6"
|
||||
;;
|
||||
esac
|
||||
|
||||
# __stdcall
|
||||
#CPU_OPT="$CPU_OPT -ps"
|
||||
# __fastcall
|
||||
#CPU_OPT="$CPU_OPT -pr"
|
||||
|
||||
CFLAGS="$CFLAGS $CPU_OPT"
|
||||
|
||||
# multithreaded
|
||||
CFLAGS="$CFLAGS -tWM"
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -w!"
|
||||
|
||||
# disable logo
|
||||
CFLAGS="$CFLAGS -q"
|
||||
|
||||
|
||||
# precompiled headers
|
||||
CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.csm"
|
||||
NGX_PCH="$NGX_OBJS/ngx_config.csm"
|
||||
NGX_BUILD_PCH="-H=$NGX_OBJS/ngx_config.csm"
|
||||
NGX_USE_PCH="-Hu -H=$NGX_OBJS/ngx_config.csm"
|
||||
|
||||
|
||||
# Win32 GUI mode application
|
||||
#LINK="\$(CC) -laa"
|
||||
|
||||
|
||||
# the resource file
|
||||
NGX_RES="$NGX_OBJS/nginx.res"
|
||||
NGX_RCC="brcc32 -fo$NGX_OBJS/nginx.res \$(CORE_INCS) $NGX_WIN32_RC"
|
||||
# the pragma allows to link the resource file using bcc32 and
|
||||
# to avoid the direct ilink32 calling and the c0w32.obj's WinMain/main problem
|
||||
NGX_PRAGMA="#pragma resource \"$NGX_OBJS/nginx.res\""
|
||||
|
||||
|
||||
ngx_include_opt="-I"
|
||||
ngx_objout="-o"
|
||||
ngx_binout="-e"
|
||||
ngx_objext="obj"
|
||||
ngx_binext=".exe"
|
||||
|
||||
ngx_long_start='@&&|
|
||||
'
|
||||
ngx_long_end='|'
|
||||
|
||||
ngx_regex_dirsep='\\'
|
||||
ngx_dirsep="\\"
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# Compaq C V6.5-207
|
||||
|
||||
ngx_include_opt="-I"
|
||||
|
||||
# warnings
|
||||
|
||||
CFLAGS="$CFLAGS -msg_enable level6 -msg_fatal level6"
|
||||
|
||||
CFLAGS="$CFLAGS -msg_disable unknownmacro"
|
||||
CFLAGS="$CFLAGS -msg_disable unusedincl"
|
||||
CFLAGS="$CFLAGS -msg_disable unnecincl"
|
||||
CFLAGS="$CFLAGS -msg_disable nestincl"
|
||||
CFLAGS="$CFLAGS -msg_disable strctpadding"
|
||||
CFLAGS="$CFLAGS -msg_disable ansialiascast"
|
||||
CFLAGS="$CFLAGS -msg_disable inlinestoclsmod"
|
||||
CFLAGS="$CFLAGS -msg_disable cxxkeyword"
|
||||
CFLAGS="$CFLAGS -msg_disable longlongsufx"
|
||||
CFLAGS="$CFLAGS -msg_disable valuepres"
|
||||
|
||||
# STUB
|
||||
CFLAGS="$CFLAGS -msg_disable truncintcast"
|
||||
CFLAGS="$CFLAGS -msg_disable trunclongcast"
|
||||
|
||||
CFLAGS="$CFLAGS -msg_disable truncintasn"
|
||||
CFLAGS="$CFLAGS -msg_disable trunclongint"
|
||||
CFLAGS="$CFLAGS -msg_disable intconcastsgn"
|
||||
CFLAGS="$CFLAGS -msg_disable intconstsign"
|
||||
CFLAGS="$CFLAGS -msg_disable switchlong"
|
||||
CFLAGS="$CFLAGS -msg_disable subscrbounds2"
|
||||
|
||||
CFLAGS="$CFLAGS -msg_disable hexoctunsign"
|
||||
|
||||
CFLAGS="$CFLAGS -msg_disable ignorecallval"
|
||||
CFLAGS="$CFLAGS -msg_disable nonstandcast"
|
||||
CFLAGS="$CFLAGS -msg_disable embedcomment"
|
||||
CFLAGS="$CFLAGS -msg_disable unreachcode"
|
||||
CFLAGS="$CFLAGS -msg_disable questcompare2"
|
||||
CFLAGS="$CFLAGS -msg_disable unusedtop"
|
||||
CFLAGS="$CFLAGS -msg_disable unrefdecl"
|
||||
|
||||
CFLAGS="$CFLAGS -msg_disable bitnotint"
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# clang
|
||||
|
||||
|
||||
NGX_CLANG_VER=`$CC -v 2>&1 | grep '\(clang\|LLVM\) version' 2>&1 \
|
||||
| sed -e 's/^.* version \(.*\)/\1/'`
|
||||
|
||||
echo " + clang version: $NGX_CLANG_VER"
|
||||
|
||||
have=NGX_COMPILER value="\"clang $NGX_CLANG_VER\"" . auto/define
|
||||
|
||||
|
||||
CC_TEST_FLAGS="-pipe"
|
||||
|
||||
|
||||
# optimizations
|
||||
|
||||
#NGX_CLANG_OPT="-O2"
|
||||
#NGX_CLANG_OPT="-Oz"
|
||||
NGX_CLANG_OPT="-O"
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium
|
||||
CPU_OPT="-march=pentium"
|
||||
NGX_CPU_CACHE_LINE=32
|
||||
;;
|
||||
|
||||
pentiumpro | pentium3)
|
||||
# optimize for Pentium Pro, Pentium II and Pentium III
|
||||
CPU_OPT="-march=pentiumpro"
|
||||
NGX_CPU_CACHE_LINE=32
|
||||
;;
|
||||
|
||||
pentium4)
|
||||
# optimize for Pentium 4
|
||||
CPU_OPT="-march=pentium4"
|
||||
NGX_CPU_CACHE_LINE=128
|
||||
;;
|
||||
|
||||
athlon)
|
||||
# optimize for Athlon
|
||||
CPU_OPT="-march=athlon"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
opteron)
|
||||
# optimize for Opteron
|
||||
CPU_OPT="-march=opteron"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS $CPU_OPT"
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS -pipe $CPU_OPT"
|
||||
|
||||
if [ ".$PCRE_OPT" = "." ]; then
|
||||
PCRE_OPT="-O2 -pipe $CPU_OPT"
|
||||
else
|
||||
PCRE_OPT="$PCRE_OPT -pipe"
|
||||
fi
|
||||
|
||||
if [ ".$ZLIB_OPT" = "." ]; then
|
||||
ZLIB_OPT="-O2 -pipe $CPU_OPT"
|
||||
else
|
||||
ZLIB_OPT="$ZLIB_OPT -pipe"
|
||||
fi
|
||||
|
||||
|
||||
# warnings
|
||||
|
||||
CFLAGS="$CFLAGS $NGX_CLANG_OPT -Wall -Wextra -Wpointer-arith"
|
||||
CFLAGS="$CFLAGS -Wconditional-uninitialized"
|
||||
#CFLAGS="$CFLAGS -Wmissing-prototypes"
|
||||
|
||||
# we have a lot of unused function arguments
|
||||
CFLAGS="$CFLAGS -Wno-unused-parameter"
|
||||
|
||||
# deprecated system OpenSSL library on OS X
|
||||
if [ "$NGX_SYSTEM" = "Darwin" ]; then
|
||||
CFLAGS="$CFLAGS -Wno-deprecated-declarations"
|
||||
fi
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
|
||||
# debug
|
||||
CFLAGS="$CFLAGS -g"
|
||||
|
||||
if [ ".$CPP" = "." ]; then
|
||||
CPP="$CC -E"
|
||||
fi
|
|
@ -0,0 +1,250 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
LINK="\$(CC)"
|
||||
|
||||
MAIN_LINK=
|
||||
MODULE_LINK="-shared"
|
||||
|
||||
ngx_include_opt="-I "
|
||||
ngx_compile_opt="-c"
|
||||
ngx_pic_opt="-fPIC"
|
||||
ngx_objout="-o "
|
||||
ngx_binout="-o "
|
||||
ngx_objext="o"
|
||||
ngx_binext=
|
||||
ngx_modext=".so"
|
||||
|
||||
ngx_long_start=
|
||||
ngx_long_end=
|
||||
|
||||
ngx_regex_dirsep="\/"
|
||||
ngx_dirsep='/'
|
||||
|
||||
ngx_regex_cont=' \\\
|
||||
'
|
||||
ngx_cont=' \
|
||||
'
|
||||
ngx_tab=' \
|
||||
'
|
||||
ngx_spacer=
|
||||
|
||||
ngx_long_regex_cont=$ngx_regex_cont
|
||||
ngx_long_cont=$ngx_cont
|
||||
|
||||
. auto/cc/name
|
||||
|
||||
if test -n "$CFLAGS"; then
|
||||
|
||||
CC_TEST_FLAGS="$CFLAGS $NGX_CC_OPT"
|
||||
|
||||
case $NGX_CC_NAME in
|
||||
|
||||
ccc)
|
||||
# Compaq C V6.5-207
|
||||
|
||||
ngx_include_opt="-I"
|
||||
;;
|
||||
|
||||
sunc)
|
||||
|
||||
MAIN_LINK=
|
||||
MODULE_LINK="-G"
|
||||
|
||||
case "$NGX_MACHINE" in
|
||||
|
||||
i86pc)
|
||||
NGX_AUX=" src/os/unix/ngx_sunpro_x86.il"
|
||||
;;
|
||||
|
||||
sun4u | sun4v)
|
||||
NGX_AUX=" src/os/unix/ngx_sunpro_sparc64.il"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
case $CPU in
|
||||
|
||||
amd64)
|
||||
NGX_AUX=" src/os/unix/ngx_sunpro_amd64.il"
|
||||
;;
|
||||
|
||||
esac
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
else
|
||||
|
||||
case $NGX_CC_NAME in
|
||||
gcc)
|
||||
# gcc 2.7.2.3, 2.8.1, 2.95.4, egcs-1.1.2
|
||||
# 3.0.4, 3.1.1, 3.2.3, 3.3.2, 3.3.3, 3.3.4, 3.4.0, 3.4.2
|
||||
# 4.0.0, 4.0.1, 4.1.0
|
||||
|
||||
. auto/cc/gcc
|
||||
;;
|
||||
|
||||
clang)
|
||||
# Clang C compiler
|
||||
|
||||
. auto/cc/clang
|
||||
;;
|
||||
|
||||
icc)
|
||||
# Intel C++ compiler 7.1, 8.0, 8.1
|
||||
|
||||
. auto/cc/icc
|
||||
;;
|
||||
|
||||
sunc)
|
||||
# Sun C 5.7 Patch 117837-04 2005/05/11
|
||||
|
||||
. auto/cc/sunc
|
||||
;;
|
||||
|
||||
ccc)
|
||||
# Compaq C V6.5-207
|
||||
|
||||
. auto/cc/ccc
|
||||
;;
|
||||
|
||||
acc)
|
||||
# aCC: HP ANSI C++ B3910B A.03.55.02
|
||||
|
||||
. auto/cc/acc
|
||||
;;
|
||||
|
||||
msvc*)
|
||||
# MSVC++ 6.0 SP2, MSVC++ Toolkit 2003
|
||||
|
||||
. auto/cc/msvc
|
||||
;;
|
||||
|
||||
owc)
|
||||
# Open Watcom C 1.0, 1.2
|
||||
|
||||
. auto/cc/owc
|
||||
;;
|
||||
|
||||
bcc)
|
||||
# Borland C++ 5.5
|
||||
|
||||
. auto/cc/bcc
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
CC_TEST_FLAGS="$CC_TEST_FLAGS $NGX_CC_OPT"
|
||||
|
||||
fi
|
||||
|
||||
CFLAGS="$CFLAGS $NGX_CC_OPT"
|
||||
NGX_TEST_LD_OPT="$NGX_LD_OPT"
|
||||
|
||||
if [ "$NGX_PLATFORM" != win32 ]; then
|
||||
|
||||
if test -n "$NGX_LD_OPT"; then
|
||||
ngx_feature=--with-ld-opt=\"$NGX_LD_OPT\"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test=
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
echo $0: error: the invalid value in --with-ld-opt=\"$NGX_LD_OPT\"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
ngx_feature="-Wl,-E switch"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=-Wl,-E
|
||||
ngx_feature_test=
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
MAIN_LINK="-Wl,-E"
|
||||
fi
|
||||
|
||||
|
||||
ngx_feature="gcc builtin atomic operations"
|
||||
ngx_feature_name=NGX_HAVE_GCC_ATOMIC
|
||||
ngx_feature_run=yes
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test="long n = 0;
|
||||
if (!__sync_bool_compare_and_swap(&n, 0, 1))
|
||||
return 1;
|
||||
if (__sync_fetch_and_add(&n, 1) != 1)
|
||||
return 1;
|
||||
if (n != 2)
|
||||
return 1;
|
||||
__sync_synchronize();"
|
||||
. auto/feature
|
||||
|
||||
|
||||
if [ "$NGX_CC_NAME" = "ccc" ]; then
|
||||
echo "checking for C99 variadic macros ... disabled"
|
||||
else
|
||||
ngx_feature="C99 variadic macros"
|
||||
ngx_feature_name="NGX_HAVE_C99_VARIADIC_MACROS"
|
||||
ngx_feature_run=yes
|
||||
ngx_feature_incs="#include <stdio.h>
|
||||
#define var(dummy, ...) sprintf(__VA_ARGS__)"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test="char buf[30]; buf[0] = '0';
|
||||
var(0, buf, \"%d\", 1);
|
||||
if (buf[0] != '1') return 1"
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
ngx_feature="gcc variadic macros"
|
||||
ngx_feature_name="NGX_HAVE_GCC_VARIADIC_MACROS"
|
||||
ngx_feature_run=yes
|
||||
ngx_feature_incs="#include <stdio.h>
|
||||
#define var(dummy, args...) sprintf(args)"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test="char buf[30]; buf[0] = '0';
|
||||
var(0, buf, \"%d\", 1);
|
||||
if (buf[0] != '1') return 1"
|
||||
. auto/feature
|
||||
|
||||
|
||||
ngx_feature="gcc builtin 64 bit byteswap"
|
||||
ngx_feature_name="NGX_HAVE_GCC_BSWAP64"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test="if (__builtin_bswap64(0)) return 1"
|
||||
. auto/feature
|
||||
|
||||
|
||||
# ngx_feature="inline"
|
||||
# ngx_feature_name=
|
||||
# ngx_feature_run=no
|
||||
# ngx_feature_incs="int inline f(void) { return 1 }"
|
||||
# ngx_feature_path=
|
||||
# ngx_feature_libs=
|
||||
# ngx_feature_test=
|
||||
# . auto/feature
|
||||
#
|
||||
# if [ $ngx_found = yes ]; then
|
||||
# fi
|
||||
|
||||
fi
|
|
@ -0,0 +1,178 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# gcc 2.7.2.3, 2.8.1, 2.95.4, egcs-1.1.2
|
||||
# 3.0.4, 3.1.1, 3.2.3, 3.3.2, 3.3.3, 3.3.4, 3.4.0, 3.4.2
|
||||
# 4.0.0, 4.0.1, 4.1.0
|
||||
|
||||
|
||||
NGX_GCC_VER=`$CC -v 2>&1 | grep 'gcc version' 2>&1 \
|
||||
| sed -e 's/^.* version \(.*\)/\1/'`
|
||||
|
||||
echo " + gcc version: $NGX_GCC_VER"
|
||||
|
||||
have=NGX_COMPILER value="\"gcc $NGX_GCC_VER\"" . auto/define
|
||||
|
||||
|
||||
# Solaris 7's /usr/ccs/bin/as does not support "-pipe"
|
||||
|
||||
CC_TEST_FLAGS="-pipe"
|
||||
|
||||
ngx_feature="gcc -pipe switch"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test=
|
||||
. auto/feature
|
||||
|
||||
CC_TEST_FLAGS=
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
PIPE="-pipe"
|
||||
fi
|
||||
|
||||
|
||||
case "$NGX_MACHINE" in
|
||||
|
||||
sun4u | sun4v | sparc | sparc64 )
|
||||
# "-mcpu=v9" enables the "casa" assembler instruction
|
||||
CFLAGS="$CFLAGS -mcpu=v9"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
# optimizations
|
||||
|
||||
#NGX_GCC_OPT="-O2"
|
||||
NGX_GCC_OPT="-Os"
|
||||
|
||||
#CFLAGS="$CFLAGS -fomit-frame-pointer"
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium and Athlon
|
||||
CPU_OPT="-march=pentium"
|
||||
NGX_CPU_CACHE_LINE=32
|
||||
;;
|
||||
|
||||
pentiumpro | pentium3)
|
||||
# optimize for Pentium Pro, Pentium II and Pentium III
|
||||
CPU_OPT="-march=pentiumpro"
|
||||
NGX_CPU_CACHE_LINE=32
|
||||
;;
|
||||
|
||||
pentium4)
|
||||
# optimize for Pentium 4, gcc 3.x
|
||||
CPU_OPT="-march=pentium4"
|
||||
NGX_CPU_CACHE_LINE=128
|
||||
;;
|
||||
|
||||
athlon)
|
||||
# optimize for Athlon, gcc 3.x
|
||||
CPU_OPT="-march=athlon"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
opteron)
|
||||
# optimize for Opteron, gcc 3.x
|
||||
CPU_OPT="-march=opteron"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
sparc32)
|
||||
# build 32-bit UltraSparc binary
|
||||
CPU_OPT="-m32"
|
||||
CORE_LINK="$CORE_LINK -m32"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
sparc64)
|
||||
# build 64-bit UltraSparc binary
|
||||
CPU_OPT="-m64"
|
||||
CORE_LINK="$CORE_LINK -m64"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
ppc64)
|
||||
# build 64-bit PowerPC binary
|
||||
CPU_OPT="-m64"
|
||||
CPU_OPT="$CPU_OPT -falign-functions=32 -falign-labels=32"
|
||||
CPU_OPT="$CPU_OPT -falign-loops=32 -falign-jumps=32"
|
||||
CORE_LINK="$CORE_LINK -m64"
|
||||
NGX_CPU_CACHE_LINE=128
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS $CPU_OPT"
|
||||
|
||||
case "$NGX_GCC_VER" in
|
||||
2.7*)
|
||||
# batch build
|
||||
CPU_OPT=
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS $PIPE $CPU_OPT"
|
||||
|
||||
if [ ".$PCRE_OPT" = "." ]; then
|
||||
PCRE_OPT="-O2 -fomit-frame-pointer $PIPE $CPU_OPT"
|
||||
else
|
||||
PCRE_OPT="$PCRE_OPT $PIPE"
|
||||
fi
|
||||
|
||||
if [ ".$ZLIB_OPT" = "." ]; then
|
||||
ZLIB_OPT="-O2 -fomit-frame-pointer $PIPE $CPU_OPT"
|
||||
else
|
||||
ZLIB_OPT="$ZLIB_OPT $PIPE"
|
||||
fi
|
||||
|
||||
|
||||
# warnings
|
||||
|
||||
# -W requires at least -O
|
||||
CFLAGS="$CFLAGS ${NGX_GCC_OPT:--O} -W"
|
||||
|
||||
CFLAGS="$CFLAGS -Wall -Wpointer-arith"
|
||||
#CFLAGS="$CFLAGS -Wconversion"
|
||||
#CFLAGS="$CFLAGS -Winline"
|
||||
#CFLAGS="$CFLAGS -Wmissing-prototypes"
|
||||
|
||||
case "$NGX_GCC_VER" in
|
||||
2.*)
|
||||
# we have a lot of the unused function arguments
|
||||
CFLAGS="$CFLAGS -Wno-unused"
|
||||
;;
|
||||
|
||||
*)
|
||||
# we have a lot of the unused function arguments
|
||||
CFLAGS="$CFLAGS -Wno-unused-parameter"
|
||||
# 4.2.1 shows the warning in wrong places
|
||||
#CFLAGS="$CFLAGS -Wunreachable-code"
|
||||
|
||||
# deprecated system OpenSSL library on OS X
|
||||
if [ "$NGX_SYSTEM" = "Darwin" ]; then
|
||||
CFLAGS="$CFLAGS -Wno-deprecated-declarations"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
|
||||
# debug
|
||||
CFLAGS="$CFLAGS -g"
|
||||
|
||||
# DragonFly's gcc3 generates DWARF
|
||||
#CFLAGS="$CFLAGS -g -gstabs"
|
||||
|
||||
if [ ".$CPP" = "." ]; then
|
||||
CPP="$CC -E"
|
||||
fi
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# Intel C++ compiler 7.1, 8.0, 8.1, 9.0, 11.1
|
||||
|
||||
NGX_ICC_VER=`$CC -V 2>&1 | grep 'Version' 2>&1 \
|
||||
| sed -e 's/^.* Version \([^ ]*\) *Build.*$/\1/'`
|
||||
|
||||
echo " + icc version: $NGX_ICC_VER"
|
||||
|
||||
have=NGX_COMPILER value="\"Intel C Compiler $NGX_ICC_VER\"" . auto/define
|
||||
|
||||
|
||||
# optimizations
|
||||
|
||||
CFLAGS="$CFLAGS -O"
|
||||
|
||||
CORE_LINK="$CORE_LINK -opt_report_file=$NGX_OBJS/opt_report_file"
|
||||
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium and Athlon
|
||||
CPU_OPT="-march=pentium"
|
||||
;;
|
||||
|
||||
pentiumpro)
|
||||
# optimize for Pentium Pro, Pentium II and Pentium III
|
||||
CPU_OPT="-mcpu=pentiumpro -march=pentiumpro"
|
||||
;;
|
||||
|
||||
pentium4)
|
||||
# optimize for Pentium 4, default
|
||||
CPU_OPT="-march=pentium4"
|
||||
;;
|
||||
esac
|
||||
|
||||
CFLAGS="$CFLAGS $CPU_OPT"
|
||||
|
||||
if [ ".$PCRE_OPT" = "." ]; then
|
||||
PCRE_OPT="-O $CPU_OPT"
|
||||
fi
|
||||
|
||||
if [ ".$ZLIB_OPT" = "." ]; then
|
||||
ZLIB_OPT="-O $CPU_OPT"
|
||||
fi
|
||||
|
||||
|
||||
# warnings
|
||||
|
||||
CFLAGS="$CFLAGS -w2"
|
||||
|
||||
# disable some warnings
|
||||
|
||||
# invalid type conversion: "int" to "char *"
|
||||
CFLAGS="$CFLAGS -wd171"
|
||||
# argument is incompatible with corresponding format string conversion
|
||||
CFLAGS="$CFLAGS -wd181"
|
||||
# zero used for undefined preprocessing identifier
|
||||
CFLAGS="$CFLAGS -wd193"
|
||||
# the format string ends before this argument
|
||||
CFLAGS="$CFLAGS -wd268"
|
||||
# invalid format string conversion
|
||||
CFLAGS="$CFLAGS -wd269"
|
||||
# conversion from "long long" to "size_t" may lose significant bits
|
||||
CFLAGS="$CFLAGS -wd810"
|
||||
# parameter was never referenced
|
||||
CFLAGS="$CFLAGS -wd869"
|
||||
# attribute "unused" is only allowed in a function definition, warning on pTHX_
|
||||
CFLAGS="$CFLAGS -wd1301"
|
||||
|
||||
# STUB
|
||||
# enumerated type mixed with another type
|
||||
CFLAGS="$CFLAGS -wd188"
|
||||
# controlling expression is constant
|
||||
CFLAGS="$CFLAGS -wd279"
|
||||
# operands are evaluated in unspecified order
|
||||
CFLAGS="$CFLAGS -wd981"
|
||||
# external definition with no prior declaration
|
||||
CFLAGS="$CFLAGS -wd1418"
|
||||
# external declaration in primary source file
|
||||
CFLAGS="$CFLAGS -wd1419"
|
||||
|
||||
case "$NGX_ICC_VER" in
|
||||
9.*)
|
||||
# "cc" clobber ignored, warnings for Linux's htonl()/htons()
|
||||
CFLAGS="$CFLAGS -wd1469"
|
||||
# explicit conversion of a 64-bit integral type to a smaller
|
||||
# integral type
|
||||
CFLAGS="$CFLAGS -wd1683"
|
||||
# conversion from pointer to same-sized integral type,
|
||||
# warning on offsetof()
|
||||
CFLAGS="$CFLAGS -wd1684"
|
||||
# floating-point equality and inequality comparisons are unreliable,
|
||||
# warning on SvTRUE()
|
||||
CFLAGS="$CFLAGS -wd1572"
|
||||
;;
|
||||
|
||||
8.*)
|
||||
# "cc" clobber ignored, warnings for Linux's htonl()/htons()
|
||||
CFLAGS="$CFLAGS -wd1469"
|
||||
# floating-point equality and inequality comparisons are unreliable,
|
||||
# warning on SvTRUE()
|
||||
CFLAGS="$CFLAGS -wd1572"
|
||||
;;
|
||||
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
|
||||
# debug
|
||||
CFLAGS="$CFLAGS -g"
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# MSVC 6.0 SP2 cl 12.00
|
||||
# MSVC Toolkit 2003 (7.1) cl 13.10
|
||||
# MSVC 2005 Express Edition SP1 (8.0) cl 14.00
|
||||
# MSVC 2008 Express Edition (9.0) cl 15.00
|
||||
# MSVC 2010 (10.0) cl 16.00
|
||||
# MSVC 2015 (14.0) cl 19.00
|
||||
|
||||
|
||||
NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'Compiler Version' 2>&1 \
|
||||
| sed -e 's/^.* Version \(.*\)/\1/'`
|
||||
|
||||
echo " + cl version: $NGX_MSVC_VER"
|
||||
|
||||
have=NGX_COMPILER value="\"cl $NGX_MSVC_VER\"" . auto/define
|
||||
|
||||
|
||||
ngx_msvc_ver=`echo $NGX_MSVC_VER | sed -e 's/^\([0-9]*\).*/\1/'`
|
||||
|
||||
|
||||
# optimizations
|
||||
|
||||
# maximize speed, equivalent to -Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy
|
||||
CFLAGS="$CFLAGS -O2"
|
||||
|
||||
# enable global optimization
|
||||
#CFLAGS="$CFLAGS -Og"
|
||||
# enable intrinsic functions
|
||||
#CFLAGS="$CFLAGS -Oi"
|
||||
|
||||
# disable inline expansion
|
||||
#CFLAGS="$CFLAGS -Ob0"
|
||||
# explicit inline expansion
|
||||
#CFLAGS="$CFLAGS -Ob1"
|
||||
# explicit and implicit inline expansion
|
||||
#CFLAGS="$CFLAGS -Ob2"
|
||||
|
||||
# enable frame pointer omission
|
||||
#CFLAGS="$CFLAGS -Oy"
|
||||
# disable stack checking calls
|
||||
#CFLAGS="$CFLAGS -Gs"
|
||||
|
||||
# pools strings as read/write
|
||||
#CFLAGS="$CFLAGS -Gf"
|
||||
# pools strings as read-only
|
||||
#CFLAGS="$CFLAGS -GF"
|
||||
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium and Athlon
|
||||
CPU_OPT="-G5"
|
||||
;;
|
||||
|
||||
pentiumpro)
|
||||
# optimize for Pentium Pro, Pentium II and Pentium III
|
||||
CPU_OPT="-G6"
|
||||
;;
|
||||
|
||||
pentium4)
|
||||
# optimize for Pentium 4, MSVC 7
|
||||
CPU_OPT="-G7"
|
||||
;;
|
||||
esac
|
||||
|
||||
# __cdecl, default, must be used with OpenSSL, md5 asm, and sha1 asm
|
||||
#CPU_OPT="$CPU_OPT -Gd"
|
||||
# __stdcall
|
||||
#CPU_OPT="$CPU_OPT -Gz"
|
||||
# __fastcall
|
||||
#CPU_OPT="$CPU_OPT -Gr"
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS $CPU_OPT"
|
||||
|
||||
|
||||
# warnings
|
||||
|
||||
CFLAGS="$CFLAGS -W4"
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -WX"
|
||||
|
||||
# disable logo
|
||||
CFLAGS="$CFLAGS -nologo"
|
||||
|
||||
# the link flags
|
||||
CORE_LINK="$CORE_LINK -link -verbose:lib"
|
||||
|
||||
# link with libcmt.lib, multithreaded
|
||||
LIBC="-MT"
|
||||
# link with msvcrt.dll
|
||||
# however, MSVC Toolkit 2003 has no MSVCRT.LIB
|
||||
#LIBC="-MD"
|
||||
|
||||
CFLAGS="$CFLAGS $LIBC"
|
||||
|
||||
CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib"
|
||||
|
||||
# Win32 GUI mode application
|
||||
#CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup"
|
||||
|
||||
# debug
|
||||
# msvc under Wine issues
|
||||
# C1902: Program database manager mismatch; please check your installation
|
||||
if [ -z "$NGX_WINE" ]; then
|
||||
CFLAGS="$CFLAGS -Zi"
|
||||
CORE_LINK="$CORE_LINK -debug"
|
||||
fi
|
||||
|
||||
|
||||
# MSVC 2005 supports C99 variadic macros
|
||||
if [ "$ngx_msvc_ver" -ge 14 ]; then
|
||||
have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have
|
||||
fi
|
||||
|
||||
|
||||
# precompiled headers
|
||||
CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
|
||||
CORE_LINK="$CORE_LINK $NGX_OBJS/ngx_pch.obj"
|
||||
NGX_PCH="$NGX_OBJS/ngx_config.pch"
|
||||
NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch"
|
||||
NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch"
|
||||
|
||||
|
||||
# the resource file
|
||||
NGX_RES="$NGX_OBJS/nginx.res"
|
||||
NGX_RCC="rc -fo$NGX_RES \$(CORE_INCS) $NGX_WIN32_RC"
|
||||
CORE_LINK="$NGX_RES $CORE_LINK"
|
||||
|
||||
|
||||
# dynamic modules
|
||||
#MAIN_LINK="-link -def:$NGX_OBJS/nginx.def"
|
||||
#MODULE_LINK="-LD $NGX_OBJS/nginx.lib"
|
||||
|
||||
|
||||
ngx_pic_opt=
|
||||
ngx_objout="-Fo"
|
||||
ngx_binout="-Fe"
|
||||
ngx_objext="obj"
|
||||
ngx_binext=".exe"
|
||||
|
||||
ngx_long_start='@<<
|
||||
'
|
||||
ngx_long_end='<<'
|
||||
ngx_long_regex_cont=' \
|
||||
'
|
||||
ngx_long_cont='
|
||||
'
|
||||
|
||||
# MSVC understand / in path
|
||||
#ngx_regex_dirsep='\\'
|
||||
#ngx_dirsep="\\"
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ "$NGX_PLATFORM" != win32 ]; then
|
||||
|
||||
ngx_feature="C compiler"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=yes
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs=
|
||||
ngx_feature_test=
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
echo
|
||||
echo $0: error: C compiler $CC is not found
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if [ "$CC" = cl ]; then
|
||||
NGX_CC_NAME=msvc
|
||||
echo " + using Microsoft Visual C++ compiler"
|
||||
|
||||
elif [ "$CC" = wcl386 ]; then
|
||||
NGX_CC_NAME=owc
|
||||
echo " + using Open Watcom C compiler"
|
||||
|
||||
elif [ "$CC" = bcc32 ]; then
|
||||
NGX_CC_NAME=bcc
|
||||
echo " + using Borland C++ compiler"
|
||||
|
||||
elif `$CC -V 2>&1 | grep '^Intel(R) C' >/dev/null 2>&1`; then
|
||||
NGX_CC_NAME=icc
|
||||
echo " + using Intel C++ compiler"
|
||||
|
||||
elif `$CC -v 2>&1 | grep 'gcc version' >/dev/null 2>&1`; then
|
||||
NGX_CC_NAME=gcc
|
||||
echo " + using GNU C compiler"
|
||||
|
||||
elif `$CC -v 2>&1 | grep '\(clang\|LLVM\) version' >/dev/null 2>&1`; then
|
||||
NGX_CC_NAME=clang
|
||||
echo " + using Clang C compiler"
|
||||
|
||||
elif `$CC -V 2>&1 | grep 'Sun C' >/dev/null 2>&1`; then
|
||||
NGX_CC_NAME=sunc
|
||||
echo " + using Sun C compiler"
|
||||
|
||||
elif `$CC -V 2>&1 | grep '^Compaq C' >/dev/null 2>&1`; then
|
||||
NGX_CC_NAME=ccc
|
||||
echo " + using Compaq C compiler"
|
||||
|
||||
elif `$CC -V 2>&1 | grep '^aCC: ' >/dev/null 2>&1`; then
|
||||
NGX_CC_NAME=acc
|
||||
echo " + using HP aC++ compiler"
|
||||
|
||||
else
|
||||
NGX_CC_NAME=unknown
|
||||
|
||||
fi
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# Open Watcom C 1.0, 1.2, 1.3
|
||||
|
||||
# optimizations
|
||||
|
||||
# maximize speed
|
||||
CFLAGS="$CFLAGS -ot"
|
||||
# reorder instructions for best pipeline usage
|
||||
CFLAGS="$CFLAGS -op"
|
||||
# inline intrinsic functions
|
||||
CFLAGS="$CFLAGS -oi"
|
||||
# inline expansion
|
||||
CFLAGS="$CFLAGS -oe"
|
||||
# disable stack checking calls
|
||||
CFLAGS="$CFLAGS -s"
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium and Athlon
|
||||
# register-based arguments passing conventions
|
||||
CPU_OPT="-5r"
|
||||
# stack-based arguments passing conventions
|
||||
#CPU_OPT="-5s"
|
||||
;;
|
||||
|
||||
pentiumpro)
|
||||
# optimize for Pentium Pro, Pentium II and Pentium III
|
||||
# register-based arguments passing conventions
|
||||
CPU_OPT="-6r"
|
||||
# stack-based arguments passing conventions
|
||||
#CPU_OPT="-6s"
|
||||
;;
|
||||
esac
|
||||
|
||||
CFLAGS="$CFLAGS $CPU_OPT"
|
||||
|
||||
|
||||
# warnings
|
||||
|
||||
# maximum level
|
||||
CFLAGS="$CFLAGS -wx"
|
||||
#CFLAGS="$CFLAGS -w3"
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -we"
|
||||
|
||||
# built target is NT
|
||||
CFLAGS="$CFLAGS -bt=nt"
|
||||
|
||||
# multithreaded
|
||||
CFLAGS="$CFLAGS -bm"
|
||||
|
||||
# debug
|
||||
CFLAGS="$CFLAGS -d2"
|
||||
|
||||
# quiet
|
||||
CFLAGS="$CFLAGS -zq"
|
||||
|
||||
# Open Watcom C 1.2
|
||||
have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have
|
||||
|
||||
|
||||
# the precompiled headers
|
||||
#CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
|
||||
#NGX_PCH="$NGX_OBJS/ngx_config.pch"
|
||||
#NGX_BUILD_PCH="-fhq=$NGX_OBJS/ngx_config.pch"
|
||||
#NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pch"
|
||||
|
||||
|
||||
# the link flags, built target is NT GUI mode application
|
||||
#CORE_LINK="$CORE_LINK -l=nt_win"
|
||||
|
||||
|
||||
# the resource file
|
||||
NGX_RCC="wrc \$(CORE_INCS) -fo=$NGX_OBJS/nginx.res "
|
||||
NGX_RCC="$NGX_RCC $NGX_WIN32_RC $NGX_OBJS/nginx.exe"
|
||||
|
||||
|
||||
ngx_include_opt="-i="
|
||||
ngx_objout="-fo"
|
||||
ngx_binout="-fe="
|
||||
ngx_objext="obj"
|
||||
ngx_binext=".exe"
|
||||
|
||||
ngx_regex_dirsep='\\'
|
||||
ngx_dirsep="\\"
|
||||
|
||||
ngx_long_start=' '
|
||||
ngx_long_end=' '
|
||||
ngx_long_regex_cont=' \&\
|
||||
'
|
||||
ngx_long_cont=' &
|
||||
'
|
||||
|
||||
ngx_regex_cont=' \&\
|
||||
'
|
||||
ngx_cont=' &
|
||||
'
|
||||
ngx_tab=' &
|
||||
'
|
|
@ -0,0 +1,160 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
# Sun C 5.7 Patch 117837-04 2005/05/11 Sun Studio 10
|
||||
# Sun C 5.8 2005/10/13 Sun Studio 11
|
||||
# Sun C 5.9 SunOS_i386 2007/05/03 Sun Studio 12
|
||||
# Sun C 5.9 SunOS_sparc 2007/05/03
|
||||
# Sun C 5.10 SunOS_i386 2009/06/03 Sun Studio 12.1
|
||||
# Sun C 5.11 SunOS_i386 2010/08/13 Sun Studio 12.2
|
||||
|
||||
NGX_SUNC_VER=`$CC -V 2>&1 | grep 'Sun C' 2>&1 \
|
||||
| sed -e 's/^.* Sun C \(.*\)/\1/'`
|
||||
|
||||
echo " + Sun C version: $NGX_SUNC_VER"
|
||||
|
||||
have=NGX_COMPILER value="\"Sun C $NGX_SUNC_VER\"" . auto/define
|
||||
|
||||
|
||||
cat << END > $NGX_AUTOTEST.c
|
||||
|
||||
int main(void) {
|
||||
printf("%d", __SUNPRO_C);
|
||||
return 0;
|
||||
}
|
||||
|
||||
END
|
||||
|
||||
eval "$CC -o $NGX_AUTOTEST $NGX_AUTOTEST.c >> $NGX_ERR 2>&1"
|
||||
|
||||
if [ -x $NGX_AUTOTEST ]; then
|
||||
ngx_sunc_ver=`$NGX_AUTOTEST`
|
||||
fi
|
||||
|
||||
rm -rf $NGX_AUTOTEST*
|
||||
|
||||
# 1424 == 0x590, Sun Studio 12
|
||||
|
||||
if [ "$ngx_sunc_ver" -ge 1424 ]; then
|
||||
ngx_sparc32="-m32"
|
||||
ngx_sparc64="-m64"
|
||||
ngx_amd64="-m64"
|
||||
|
||||
else
|
||||
ngx_sparc32="-xarch=v8plus"
|
||||
ngx_sparc64="-xarch=v9"
|
||||
ngx_amd64="-xarch=amd64"
|
||||
fi
|
||||
|
||||
case "$NGX_MACHINE" in
|
||||
|
||||
i86pc)
|
||||
NGX_AUX=" src/os/unix/ngx_sunpro_x86.il"
|
||||
;;
|
||||
|
||||
sun4u | sun4v)
|
||||
NGX_AUX=" src/os/unix/ngx_sunpro_sparc64.il"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
MAIN_LINK=
|
||||
MODULE_LINK="-G"
|
||||
|
||||
|
||||
# optimizations
|
||||
|
||||
# 20736 == 0x5100, Sun Studio 12.1
|
||||
|
||||
if [ "$ngx_sunc_ver" -ge 20736 ]; then
|
||||
ngx_fast="-fast"
|
||||
|
||||
else
|
||||
# older versions had problems with bit-fields
|
||||
ngx_fast="-fast -xalias_level=any"
|
||||
fi
|
||||
|
||||
IPO=-xipo
|
||||
CFLAGS="$CFLAGS $ngx_fast $IPO"
|
||||
CORE_LINK="$CORE_LINK $ngx_fast $IPO"
|
||||
|
||||
|
||||
case $CPU in
|
||||
pentium)
|
||||
# optimize for Pentium and Athlon
|
||||
CPU_OPT="-xchip=pentium"
|
||||
;;
|
||||
|
||||
pentiumpro)
|
||||
# optimize for Pentium Pro, Pentium II
|
||||
CPU_OPT="-xchip=pentium_pro"
|
||||
;;
|
||||
|
||||
pentium3)
|
||||
# optimize for Pentium III
|
||||
CPU_OPT="-xchip=pentium3"
|
||||
#CPU_OPT="$CPU_OPT -xarch=sse"
|
||||
CPU_OPT="$CPU_OPT -xcache=16/32/4:256/32/4"
|
||||
;;
|
||||
|
||||
pentium4)
|
||||
# optimize for Pentium 4
|
||||
CPU_OPT="-xchip=pentium4"
|
||||
#CPU_OPT="$CPU_OPT -xarch=sse2"
|
||||
CPU_OPT="$CPU_OPT -xcache=8/64/4:256/128/8"
|
||||
;;
|
||||
|
||||
opteron)
|
||||
# optimize for Opteron
|
||||
CPU_OPT="-xchip=opteron"
|
||||
#CPU_OPT="$CPU_OPT -xarch=sse2"
|
||||
CPU_OPT="$CPU_OPT -xcache=64/64/2:1024/64/16"
|
||||
;;
|
||||
|
||||
sparc32)
|
||||
# build 32-bit UltraSparc binary
|
||||
CPU_OPT="$ngx_sparc32"
|
||||
CORE_LINK="$CORE_LINK $ngx_sparc32"
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS $ngx_sparc32"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
sparc64)
|
||||
# build 64-bit UltraSparc binary
|
||||
CPU_OPT="$ngx_sparc64"
|
||||
CORE_LINK="$CORE_LINK $ngx_sparc64"
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS $ngx_sparc64"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
amd64)
|
||||
# build 64-bit amd64 binary
|
||||
CPU_OPT="$ngx_amd64"
|
||||
CORE_LINK="$CORE_LINK $ngx_amd64"
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS $ngx_amd64"
|
||||
NGX_AUX=" src/os/unix/ngx_sunpro_amd64.il"
|
||||
NGX_CPU_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
CFLAGS="$CFLAGS $CPU_OPT"
|
||||
|
||||
|
||||
if [ ".$PCRE_OPT" = "." ]; then
|
||||
PCRE_OPT="$ngx_fast $IPO $CPU_OPT"
|
||||
fi
|
||||
|
||||
if [ ".$ZLIB_OPT" = "." ]; then
|
||||
ZLIB_OPT="$ngx_fast $IPO $CPU_OPT"
|
||||
fi
|
||||
|
||||
|
||||
# stop on warning
|
||||
CFLAGS="$CFLAGS -errwarn=%all"
|
||||
|
||||
# debug
|
||||
CFLAGS="$CFLAGS -g"
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
cat << END >> $NGX_AUTO_CONFIG_H
|
||||
|
||||
#ifndef $have
|
||||
#define $have $value
|
||||
#endif
|
||||
|
||||
END
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
echo $ngx_n "checking for system byte ordering ...$ngx_c"
|
||||
|
||||
cat << END >> $NGX_AUTOCONF_ERR
|
||||
|
||||
----------------------------------------
|
||||
checking for system byte ordering
|
||||
|
||||
END
|
||||
|
||||
|
||||
cat << END > $NGX_AUTOTEST.c
|
||||
|
||||
int main(void) {
|
||||
int i = 0x11223344;
|
||||
char *p;
|
||||
|
||||
p = (char *) &i;
|
||||
if (*p == 0x44) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
END
|
||||
|
||||
ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
|
||||
-o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
|
||||
|
||||
eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
|
||||
|
||||
if [ -x $NGX_AUTOTEST ]; then
|
||||
if $NGX_AUTOTEST >/dev/null 2>&1; then
|
||||
echo " little endian"
|
||||
have=NGX_HAVE_LITTLE_ENDIAN . auto/have
|
||||
else
|
||||
echo " big endian"
|
||||
fi
|
||||
|
||||
rm -rf $NGX_AUTOTEST*
|
||||
|
||||
else
|
||||
rm -rf $NGX_AUTOTEST*
|
||||
|
||||
echo
|
||||
echo "$0: error: cannot detect system byte ordering"
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,123 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
echo $ngx_n "checking for $ngx_feature ...$ngx_c"
|
||||
|
||||
cat << END >> $NGX_AUTOCONF_ERR
|
||||
|
||||
----------------------------------------
|
||||
checking for $ngx_feature
|
||||
|
||||
END
|
||||
|
||||
ngx_found=no
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
ngx_have_feature=`echo $ngx_feature_name \
|
||||
| tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||
fi
|
||||
|
||||
if test -n "$ngx_feature_path"; then
|
||||
for ngx_temp in $ngx_feature_path; do
|
||||
ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
|
||||
done
|
||||
fi
|
||||
|
||||
cat << END > $NGX_AUTOTEST.c
|
||||
|
||||
#include <sys/types.h>
|
||||
$NGX_INCLUDE_UNISTD_H
|
||||
$ngx_feature_incs
|
||||
|
||||
int main(void) {
|
||||
$ngx_feature_test;
|
||||
return 0;
|
||||
}
|
||||
|
||||
END
|
||||
|
||||
|
||||
ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
|
||||
-o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_TEST_LD_OPT $ngx_feature_libs"
|
||||
|
||||
ngx_feature_inc_path=
|
||||
|
||||
eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1"
|
||||
|
||||
|
||||
if [ -x $NGX_AUTOTEST ]; then
|
||||
|
||||
case "$ngx_feature_run" in
|
||||
|
||||
yes)
|
||||
# /bin/sh is used to intercept "Killed" or "Abort trap" messages
|
||||
if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
have=$ngx_have_feature . auto/have
|
||||
fi
|
||||
|
||||
else
|
||||
echo " found but is not working"
|
||||
fi
|
||||
;;
|
||||
|
||||
value)
|
||||
# /bin/sh is used to intercept "Killed" or "Abort trap" messages
|
||||
if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
cat << END >> $NGX_AUTO_CONFIG_H
|
||||
|
||||
#ifndef $ngx_feature_name
|
||||
#define $ngx_feature_name `$NGX_AUTOTEST`
|
||||
#endif
|
||||
|
||||
END
|
||||
else
|
||||
echo " found but is not working"
|
||||
fi
|
||||
;;
|
||||
|
||||
bug)
|
||||
# /bin/sh is used to intercept "Killed" or "Abort trap" messages
|
||||
if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
|
||||
echo " not found"
|
||||
|
||||
else
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
have=$ngx_have_feature . auto/have
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
have=$ngx_have_feature . auto/have
|
||||
fi
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
else
|
||||
echo " not found"
|
||||
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
echo $ngx_test >> $NGX_AUTOCONF_ERR
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
fi
|
||||
|
||||
rm -rf $NGX_AUTOTEST*
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
cat << END >> $NGX_AUTO_CONFIG_H
|
||||
|
||||
#ifndef $have
|
||||
#define $have 1
|
||||
#endif
|
||||
|
||||
END
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
cat << END >> $NGX_AUTO_HEADERS_H
|
||||
|
||||
#ifndef $have
|
||||
#define $have 1
|
||||
#endif
|
||||
|
||||
END
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
ngx_include="unistd.h"; . auto/include
|
||||
ngx_include="inttypes.h"; . auto/include
|
||||
ngx_include="limits.h"; . auto/include
|
||||
ngx_include="sys/filio.h"; . auto/include
|
||||
ngx_include="sys/param.h"; . auto/include
|
||||
ngx_include="sys/mount.h"; . auto/include
|
||||
ngx_include="sys/statvfs.h"; . auto/include
|
||||
ngx_include="crypt.h"; . auto/include
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
echo $ngx_n "checking for $ngx_include ...$ngx_c"
|
||||
|
||||
cat << END >> $NGX_AUTOCONF_ERR
|
||||
|
||||
----------------------------------------
|
||||
checking for $ngx_include
|
||||
|
||||
END
|
||||
|
||||
|
||||
ngx_found=no
|
||||
|
||||
cat << END > $NGX_AUTOTEST.c
|
||||
|
||||
$NGX_INCLUDE_SYS_PARAM_H
|
||||
#include <$ngx_include>
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
END
|
||||
|
||||
|
||||
ngx_test="$CC -o $NGX_AUTOTEST $NGX_AUTOTEST.c"
|
||||
|
||||
eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
|
||||
|
||||
if [ -x $NGX_AUTOTEST ]; then
|
||||
|
||||
ngx_found=yes
|
||||
|
||||
echo " found"
|
||||
|
||||
ngx_name=`echo $ngx_include \
|
||||
| tr abcdefghijklmnopqrstuvwxyz/. ABCDEFGHIJKLMNOPQRSTUVWXYZ__`
|
||||
|
||||
|
||||
have=NGX_HAVE_$ngx_name . auto/have_headers
|
||||
|
||||
eval "NGX_INCLUDE_$ngx_name='#include <$ngx_include>'"
|
||||
|
||||
else
|
||||
echo " not found"
|
||||
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
echo $ngx_test >> $NGX_AUTOCONF_ERR
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
fi
|
||||
|
||||
rm -rf $NGX_AUTOTEST*
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
NGX_MAKEFILE=$NGX_OBJS/Makefile
|
||||
NGX_MODULES_C=$NGX_OBJS/ngx_modules.c
|
||||
|
||||
NGX_AUTO_HEADERS_H=$NGX_OBJS/ngx_auto_headers.h
|
||||
NGX_AUTO_CONFIG_H=$NGX_OBJS/ngx_auto_config.h
|
||||
|
||||
NGX_AUTOTEST=$NGX_OBJS/autotest
|
||||
NGX_AUTOCONF_ERR=$NGX_OBJS/autoconf.err
|
||||
|
||||
# STUBs
|
||||
NGX_ERR=$NGX_OBJS/autoconf.err
|
||||
MAKEFILE=$NGX_OBJS/Makefile
|
||||
|
||||
|
||||
NGX_PCH=
|
||||
NGX_USE_PCH=
|
||||
|
||||
|
||||
# check the echo's "-n" option and "\c" capability
|
||||
|
||||
if echo "test\c" | grep c >/dev/null; then
|
||||
|
||||
if echo -n test | grep n >/dev/null; then
|
||||
ngx_n=
|
||||
ngx_c=
|
||||
|
||||
else
|
||||
ngx_n=-n
|
||||
ngx_c=
|
||||
fi
|
||||
|
||||
else
|
||||
ngx_n=
|
||||
ngx_c='\c'
|
||||
fi
|
||||
|
||||
|
||||
# create Makefile
|
||||
|
||||
cat << END > Makefile
|
||||
|
||||
default: build
|
||||
|
||||
clean:
|
||||
rm -rf Makefile $NGX_OBJS
|
||||
END
|
|
@ -0,0 +1,218 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $USE_PERL != NO ]; then
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
install_perl_modules:
|
||||
cd $NGX_OBJS/src/http/modules/perl && \$(MAKE) install
|
||||
END
|
||||
|
||||
NGX_INSTALL_PERL_MODULES=install_perl_modules
|
||||
|
||||
fi
|
||||
|
||||
|
||||
case ".$NGX_SBIN_PATH" in
|
||||
./*)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_SBIN_PATH=$NGX_PREFIX/$NGX_SBIN_PATH
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
case ".$NGX_MODULES_PATH" in
|
||||
./*)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_MODULES_PATH=$NGX_PREFIX/$NGX_MODULES_PATH
|
||||
;;
|
||||
esac
|
||||
|
||||
NGX_MODULES_PATH=`dirname $NGX_MODULES_PATH/.`
|
||||
|
||||
|
||||
case ".$NGX_CONF_PATH" in
|
||||
./*)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_CONF_PATH=$NGX_PREFIX/$NGX_CONF_PATH
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH`
|
||||
|
||||
|
||||
case ".$NGX_PID_PATH" in
|
||||
./*)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_PID_PATH=$NGX_PREFIX/$NGX_PID_PATH
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
case ".$NGX_ERROR_LOG_PATH" in
|
||||
./* | .)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_ERROR_LOG_PATH=$NGX_PREFIX/$NGX_ERROR_LOG_PATH
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
case ".$NGX_HTTP_LOG_PATH" in
|
||||
./*)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
if test -f man/nginx.8 ; then
|
||||
NGX_MAN=man/nginx.8
|
||||
else
|
||||
NGX_MAN=docs/man/nginx.8
|
||||
fi
|
||||
|
||||
if test -d html ; then
|
||||
NGX_HTML=html
|
||||
else
|
||||
NGX_HTML=docs/html
|
||||
fi
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
manpage: $NGX_OBJS/nginx.8
|
||||
|
||||
$NGX_OBJS/nginx.8: $NGX_MAN $NGX_AUTO_CONFIG_H
|
||||
sed -e "s|%%PREFIX%%|$NGX_PREFIX|" \\
|
||||
-e "s|%%PID_PATH%%|$NGX_PID_PATH|" \\
|
||||
-e "s|%%CONF_PATH%%|$NGX_CONF_PATH|" \\
|
||||
-e "s|%%ERROR_LOG_PATH%%|${NGX_ERROR_LOG_PATH:-stderr}|" \\
|
||||
< $NGX_MAN > \$@
|
||||
|
||||
install: build $NGX_INSTALL_PERL_MODULES
|
||||
test -d '\$(DESTDIR)$NGX_PREFIX' || mkdir -p '\$(DESTDIR)$NGX_PREFIX'
|
||||
|
||||
test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \\
|
||||
|| mkdir -p '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`'
|
||||
test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \\
|
||||
|| mv '\$(DESTDIR)$NGX_SBIN_PATH' \\
|
||||
'\$(DESTDIR)$NGX_SBIN_PATH.old'
|
||||
cp $NGX_OBJS/nginx '\$(DESTDIR)$NGX_SBIN_PATH'
|
||||
|
||||
test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \\
|
||||
|| mkdir -p '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
|
||||
cp conf/koi-win '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/koi-utf '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/win-utf '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
|
||||
test -f '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types' \\
|
||||
|| cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types.default'
|
||||
|
||||
test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params' \\
|
||||
|| cp conf/fastcgi_params '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/fastcgi_params \\
|
||||
'\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default'
|
||||
|
||||
test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \\
|
||||
|| cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default'
|
||||
|
||||
test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \\
|
||||
|| cp conf/uwsgi_params '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/uwsgi_params \\
|
||||
'\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params.default'
|
||||
|
||||
test -f '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params' \\
|
||||
|| cp conf/scgi_params '\$(DESTDIR)$NGX_CONF_PREFIX'
|
||||
cp conf/scgi_params \\
|
||||
'\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params.default'
|
||||
|
||||
test -f '\$(DESTDIR)$NGX_CONF_PATH' \\
|
||||
|| cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH'
|
||||
cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default'
|
||||
|
||||
test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \\
|
||||
|| mkdir -p '\$(DESTDIR)`dirname "$NGX_PID_PATH"`'
|
||||
|
||||
test -d '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' \\
|
||||
|| mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`'
|
||||
|
||||
test -d '\$(DESTDIR)$NGX_PREFIX/html' \\
|
||||
|| cp -R $NGX_HTML '\$(DESTDIR)$NGX_PREFIX'
|
||||
END
|
||||
|
||||
|
||||
if test -n "$NGX_ERROR_LOG_PATH"; then
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
test -d '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' \\
|
||||
|| mkdir -p '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`'
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
if test -n "$DYNAMIC_MODULES"; then
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
test -d '\$(DESTDIR)$NGX_MODULES_PATH' \\
|
||||
|| mkdir -p '\$(DESTDIR)$NGX_MODULES_PATH'
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
for ngx_module in $DYNAMIC_MODULES
|
||||
do
|
||||
ngx_module=$ngx_module$ngx_modext
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
test ! -f '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' \\
|
||||
|| mv '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' \\
|
||||
'\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module.old'
|
||||
cp $NGX_OBJS/$ngx_module '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module'
|
||||
END
|
||||
|
||||
done
|
||||
|
||||
|
||||
# create Makefile
|
||||
|
||||
cat << END >> Makefile
|
||||
|
||||
build:
|
||||
\$(MAKE) -f $NGX_MAKEFILE
|
||||
|
||||
install:
|
||||
\$(MAKE) -f $NGX_MAKEFILE install
|
||||
|
||||
modules:
|
||||
\$(MAKE) -f $NGX_MAKEFILE modules
|
||||
|
||||
upgrade:
|
||||
$NGX_SBIN_PATH -t
|
||||
|
||||
kill -USR2 \`cat $NGX_PID_PATH\`
|
||||
sleep 1
|
||||
test -f $NGX_PID_PATH.oldbin
|
||||
|
||||
kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
|
||||
END
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $USE_PCRE = YES -o $PCRE != NONE ]; then
|
||||
. auto/lib/pcre/conf
|
||||
|
||||
else
|
||||
if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: the HTTP rewrite module requires the PCRE library.
|
||||
You can either disable the module by using --without-http_rewrite_module
|
||||
option or you have to enable the PCRE support.
|
||||
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ $USE_OPENSSL = YES ]; then
|
||||
. auto/lib/openssl/conf
|
||||
fi
|
||||
|
||||
if [ $USE_ZLIB = YES ]; then
|
||||
. auto/lib/zlib/conf
|
||||
fi
|
||||
|
||||
if [ $USE_LIBXSLT != NO ]; then
|
||||
. auto/lib/libxslt/conf
|
||||
fi
|
||||
|
||||
if [ $USE_LIBGD != NO ]; then
|
||||
. auto/lib/libgd/conf
|
||||
fi
|
||||
|
||||
if [ $USE_PERL != NO ]; then
|
||||
. auto/lib/perl/conf
|
||||
fi
|
||||
|
||||
if [ $USE_GEOIP != NO ]; then
|
||||
. auto/lib/geoip/conf
|
||||
fi
|
||||
|
||||
if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then
|
||||
. auto/lib/google-perftools/conf
|
||||
fi
|
||||
|
||||
if [ $NGX_LIBATOMIC != NO ]; then
|
||||
. auto/lib/libatomic/conf
|
||||
fi
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
ngx_feature="GeoIP library"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <GeoIP.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-lGeoIP"
|
||||
ngx_feature_test="GeoIP_open(NULL, 0)"
|
||||
. auto/feature
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="GeoIP library in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lGeoIP"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lGeoIP"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# NetBSD port
|
||||
|
||||
ngx_feature="GeoIP library in /usr/pkg/"
|
||||
ngx_feature_path="/usr/pkg/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lGeoIP"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/pkg/lib -lGeoIP"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="GeoIP library in /opt/local/"
|
||||
ngx_feature_path="/opt/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lGeoIP"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lGeoIP"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
|
||||
CORE_INCS="$CORE_INCS $ngx_feature_path"
|
||||
|
||||
if [ $USE_GEOIP = YES ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
fi
|
||||
|
||||
NGX_LIB_GEOIP=$ngx_feature_libs
|
||||
|
||||
ngx_feature="GeoIP IPv6 support"
|
||||
ngx_feature_name="NGX_HAVE_GEOIP_V6"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <stdio.h>
|
||||
#include <GeoIP.h>"
|
||||
#ngx_feature_path=
|
||||
#ngx_feature_libs=
|
||||
ngx_feature_test="printf(\"%d\", GEOIP_CITY_EDITION_REV0_V6);"
|
||||
. auto/feature
|
||||
|
||||
else
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: the GeoIP module requires the GeoIP library.
|
||||
You can either do not enable the module or install the library.
|
||||
|
||||
END
|
||||
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
ngx_feature="Google perftools"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-lprofiler"
|
||||
ngx_feature_test="ProfilerStop()"
|
||||
. auto/feature
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="Google perftools in /usr/local/"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lprofiler"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lprofiler"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="Google perftools in /opt/local/"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lprofiler"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lprofiler"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
|
||||
else
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: the Google perftools module requires the Google perftools
|
||||
library. You can either do not enable the module or install the library.
|
||||
|
||||
END
|
||||
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $NGX_LIBATOMIC != YES ]; then
|
||||
|
||||
have=NGX_HAVE_LIBATOMIC . auto/have
|
||||
CORE_INCS="$CORE_INCS $NGX_LIBATOMIC/src"
|
||||
LINK_DEPS="$LINK_DEPS $NGX_LIBATOMIC/src/libatomic_ops.a"
|
||||
CORE_LIBS="$CORE_LIBS $NGX_LIBATOMIC/src/libatomic_ops.a"
|
||||
|
||||
else
|
||||
|
||||
ngx_feature="atomic_ops library"
|
||||
ngx_feature_name=NGX_HAVE_LIBATOMIC
|
||||
ngx_feature_run=yes
|
||||
ngx_feature_incs="#define AO_REQUIRE_CAS
|
||||
#include <atomic_ops.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-latomic_ops"
|
||||
ngx_feature_test="long n = 0;
|
||||
if (!AO_compare_and_swap(&n, 0, 1))
|
||||
return 1;
|
||||
if (AO_fetch_and_add(&n, 1) != 1)
|
||||
return 1;
|
||||
if (n != 2)
|
||||
return 1;
|
||||
AO_nop();"
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
else
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: libatomic_ops library was not found.
|
||||
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile
|
||||
cd $NGX_LIBATOMIC && \$(MAKE)
|
||||
|
||||
$NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE
|
||||
cd $NGX_LIBATOMIC \\
|
||||
&& if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
|
||||
&& ./configure
|
||||
|
||||
END
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
ngx_feature="GD library"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <gd.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-lgd"
|
||||
ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);"
|
||||
. auto/feature
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="GD library in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lgd"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lgd"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# NetBSD port
|
||||
|
||||
ngx_feature="GD library in /usr/pkg/"
|
||||
ngx_feature_path="/usr/pkg/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lgd"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/pkg/lib -lgd"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="GD library in /opt/local/"
|
||||
ngx_feature_path="/opt/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lgd"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lgd"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
|
||||
CORE_INCS="$CORE_INCS $ngx_feature_path"
|
||||
|
||||
if [ $USE_LIBGD = YES ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
fi
|
||||
|
||||
NGX_LIB_LIBGD=$ngx_feature_libs
|
||||
|
||||
ngx_feature="GD WebP support"
|
||||
ngx_feature_name="NGX_HAVE_GD_WEBP"
|
||||
ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);"
|
||||
. auto/feature
|
||||
|
||||
else
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: the HTTP image filter module requires the GD library.
|
||||
You can either do not enable the module or install the libraries.
|
||||
|
||||
END
|
||||
|
||||
exit 1
|
||||
|
||||
fi
|
|
@ -0,0 +1,165 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
ngx_feature="libxslt"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxslt/xslt.h>
|
||||
#include <libxslt/xsltInternals.h>
|
||||
#include <libxslt/transform.h>
|
||||
#include <libxslt/xsltutils.h>"
|
||||
ngx_feature_path="/usr/include/libxml2"
|
||||
ngx_feature_libs="-lxml2 -lxslt"
|
||||
ngx_feature_test="xmlParserCtxtPtr ctxt = NULL;
|
||||
xsltStylesheetPtr sheet = NULL;
|
||||
xmlDocPtr doc;
|
||||
doc = xmlParseChunk(ctxt, NULL, 0, 0);
|
||||
xsltApplyStylesheet(sheet, doc, NULL);"
|
||||
. auto/feature
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="libxslt in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include/libxml2 /usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lxml2 -lxslt"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lxml2 -lxslt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# NetBSD port
|
||||
|
||||
ngx_feature="libxslt in /usr/pkg/"
|
||||
ngx_feature_path="/usr/pkg/include/libxml2 /usr/pkg/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lxml2 -lxslt"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/pkg/lib -lxml2 -lxslt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="libxslt in /opt/local/"
|
||||
ngx_feature_path="/opt/local/include/libxml2 /opt/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lxml2 -lxslt"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lxml2 -lxslt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
|
||||
CORE_INCS="$CORE_INCS $ngx_feature_path"
|
||||
|
||||
if [ $USE_LIBXSLT = YES ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
fi
|
||||
|
||||
NGX_LIB_LIBXSLT=$ngx_feature_libs
|
||||
|
||||
else
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: the HTTP XSLT module requires the libxml2/libxslt
|
||||
libraries. You can either do not enable the module or install the libraries.
|
||||
|
||||
END
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
ngx_feature="libexslt"
|
||||
ngx_feature_name=NGX_HAVE_EXSLT
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <libexslt/exslt.h>"
|
||||
ngx_feature_path="/usr/include/libxml2"
|
||||
ngx_feature_libs="-lexslt"
|
||||
ngx_feature_test="exsltRegisterAll();"
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="libexslt in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include/libxml2 /usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lexslt"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lexslt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# NetBSD port
|
||||
|
||||
ngx_feature="libexslt in /usr/pkg/"
|
||||
ngx_feature_path="/usr/pkg/include/libxml2 /usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lexslt"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/pkg/lib -lexslt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="libexslt in /opt/local/"
|
||||
ngx_feature_path="/opt/local/include/libxml2 /opt/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lexslt"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lexslt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
if [ $USE_LIBXSLT = YES ]; then
|
||||
CORE_LIBS="$CORE_LIBS -lexslt"
|
||||
fi
|
||||
|
||||
NGX_LIB_LIBXSLT="$NGX_LIB_LIBXSLT -lexslt"
|
||||
fi
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $PCRE != NONE -a $PCRE != NO -a $PCRE != YES ]; then
|
||||
. auto/lib/pcre/make
|
||||
fi
|
||||
|
||||
if [ $OPENSSL != NONE -a $OPENSSL != NO -a $OPENSSL != YES ]; then
|
||||
. auto/lib/openssl/make
|
||||
fi
|
||||
|
||||
if [ $ZLIB != NONE -a $ZLIB != NO -a $ZLIB != YES ]; then
|
||||
. auto/lib/zlib/make
|
||||
fi
|
||||
|
||||
if [ $NGX_LIBATOMIC != NO -a $NGX_LIBATOMIC != YES ]; then
|
||||
. auto/lib/libatomic/make
|
||||
fi
|
||||
|
||||
if [ $USE_PERL != NO ]; then
|
||||
. auto/lib/perl/make
|
||||
fi
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $OPENSSL != NONE ]; then
|
||||
|
||||
case "$CC" in
|
||||
|
||||
cl | bcc32)
|
||||
have=NGX_OPENSSL . auto/have
|
||||
have=NGX_SSL . auto/have
|
||||
|
||||
CFLAGS="$CFLAGS -DNO_SYS_TYPES_H"
|
||||
|
||||
CORE_INCS="$CORE_INCS $OPENSSL/openssl/include"
|
||||
CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h"
|
||||
|
||||
if [ -f $OPENSSL/ms/do_ms.bat ]; then
|
||||
# before OpenSSL 1.1.0
|
||||
CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/ssleay32.lib"
|
||||
CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libeay32.lib"
|
||||
else
|
||||
# OpenSSL 1.1.0+
|
||||
CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libssl.lib"
|
||||
CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libcrypto.lib"
|
||||
fi
|
||||
|
||||
# libeay32.lib requires gdi32.lib
|
||||
CORE_LIBS="$CORE_LIBS gdi32.lib"
|
||||
# OpenSSL 1.0.0 requires crypt32.lib
|
||||
CORE_LIBS="$CORE_LIBS crypt32.lib"
|
||||
;;
|
||||
|
||||
*)
|
||||
have=NGX_OPENSSL . auto/have
|
||||
have=NGX_SSL . auto/have
|
||||
|
||||
CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include"
|
||||
CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h"
|
||||
CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a"
|
||||
CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a"
|
||||
CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
|
||||
|
||||
if [ "$NGX_PLATFORM" = win32 ]; then
|
||||
CORE_LIBS="$CORE_LIBS -lgdi32 -lcrypt32 -lws2_32"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
else
|
||||
|
||||
if [ "$NGX_PLATFORM" != win32 ]; then
|
||||
|
||||
OPENSSL=NO
|
||||
|
||||
ngx_feature="OpenSSL library"
|
||||
ngx_feature_name="NGX_OPENSSL"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <openssl/ssl.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-lssl -lcrypto $NGX_LIBDL"
|
||||
ngx_feature_test="SSL_CTX_set_options(NULL, 0)"
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="OpenSSL library in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lssl -lcrypto $NGX_LIBDL"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lssl -lcrypto $NGX_LIBDL"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# NetBSD port
|
||||
|
||||
ngx_feature="OpenSSL library in /usr/pkg/"
|
||||
ngx_feature_path="/usr/pkg/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lssl -lcrypto $NGX_LIBDL"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/pkg/lib -lssl -lcrypto $NGX_LIBDL"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="OpenSSL library in /opt/local/"
|
||||
ngx_feature_path="/opt/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lssl -lcrypto $NGX_LIBDL"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lssl -lcrypto $NGX_LIBDL"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
have=NGX_SSL . auto/have
|
||||
CORE_INCS="$CORE_INCS $ngx_feature_path"
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
OPENSSL=YES
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $OPENSSL != YES ]; then
|
||||
|
||||
cat << END
|
||||
|
||||
$0: error: SSL modules require the OpenSSL library.
|
||||
You can either do not enable the modules, or install the OpenSSL library
|
||||
into the system, or build the OpenSSL library statically from the source
|
||||
with nginx by using --with-openssl=<path> option.
|
||||
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
case "$CC" in
|
||||
|
||||
cl)
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$OPENSSL/openssl/include/openssl/ssl.h: $NGX_MAKEFILE
|
||||
\$(MAKE) -f auto/lib/openssl/makefile.msvc \
|
||||
OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT"
|
||||
|
||||
END
|
||||
|
||||
;;
|
||||
|
||||
bcc32)
|
||||
|
||||
ngx_opt=`echo "-DOPENSSL=\"$OPENSSL\" -DOPENSSL_OPT=\"$OPENSSL_OPT\"" \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
`echo "$OPENSSL\\openssl\\lib\\libeay32.lib: \
|
||||
$OPENSSL\\openssl\\include\\openssl\\ssl.h" \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
`echo "$OPENSSL\\openssl\\lib\\ssleay32.lib: \
|
||||
$OPENSSL\\openssl\\include\\openssl\\ssl.h" \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
`echo "$OPENSSL\\openssl\\include\\openssl\\ssl.h: $NGX_MAKEFILE" \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
\$(MAKE) -f auto/lib/openssl/makefile.bcc $ngx_opt
|
||||
|
||||
END
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
case $OPENSSL in
|
||||
/*) ngx_prefix="$OPENSSL/.openssl" ;;
|
||||
*) ngx_prefix="$PWD/$OPENSSL/.openssl" ;;
|
||||
esac
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE
|
||||
cd $OPENSSL \\
|
||||
&& if [ -f Makefile ]; then \$(MAKE) clean; fi \\
|
||||
&& ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\
|
||||
&& \$(MAKE) \\
|
||||
&& \$(MAKE) install_sw LIBDIR=lib
|
||||
|
||||
END
|
||||
|
||||
;;
|
||||
|
||||
esac
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
all:
|
||||
cd $(OPENSSL)
|
||||
|
||||
perl Configure BC-32 no-shared --prefix=openssl $(OPENSSL_OPT)
|
||||
|
||||
ms\do_nasm
|
||||
|
||||
$(MAKE) -f ms\bcb.mak
|
||||
$(MAKE) -f ms\bcb.mak install
|
||||
|
||||
# Borland's make does not expand "[ch]" in
|
||||
# copy "inc32\openssl\*.[ch]" "openssl\include\openssl"
|
||||
copy inc32\openssl\*.h openssl\include\openssl
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
all:
|
||||
cd $(OPENSSL)
|
||||
|
||||
perl Configure VC-WIN32 no-shared \
|
||||
--prefix="%cd%/openssl" \
|
||||
--openssldir="%cd%/openssl/ssl" \
|
||||
$(OPENSSL_OPT)
|
||||
|
||||
if exist ms\do_ms.bat ( \
|
||||
ms\do_ms \
|
||||
&& $(MAKE) -f ms\nt.mak \
|
||||
&& $(MAKE) -f ms\nt.mak install \
|
||||
) else ( \
|
||||
$(MAKE) \
|
||||
&& $(MAKE) install_sw \
|
||||
)
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $PCRE != NONE ]; then
|
||||
CORE_INCS="$CORE_INCS $PCRE"
|
||||
|
||||
case "$NGX_CC_NAME" in
|
||||
|
||||
msvc | owc | bcc)
|
||||
have=NGX_PCRE . auto/have
|
||||
have=PCRE_STATIC . auto/have
|
||||
CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
|
||||
LINK_DEPS="$LINK_DEPS $PCRE/pcre.lib"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib"
|
||||
;;
|
||||
|
||||
icc)
|
||||
have=NGX_PCRE . auto/have
|
||||
CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
|
||||
|
||||
LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
|
||||
|
||||
echo $ngx_n "checking for PCRE library ...$ngx_c"
|
||||
|
||||
if [ -f $PCRE/pcre.h ]; then
|
||||
ngx_pcre_ver=`grep PCRE_MAJOR $PCRE/pcre.h \
|
||||
| sed -e 's/^.*PCRE_MAJOR.* \(.*\)$/\1/'`
|
||||
|
||||
else if [ -f $PCRE/configure.in ]; then
|
||||
ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \
|
||||
| sed -e 's/^.*=\(.*\)$/\1/'`
|
||||
|
||||
else
|
||||
ngx_pcre_ver=`grep pcre_major, $PCRE/configure.ac \
|
||||
| sed -e 's/^.*pcre_major,.*\[\(.*\)\].*$/\1/'`
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " $ngx_pcre_ver major version found"
|
||||
|
||||
# to allow -ipo optimization we link with the *.o but not library
|
||||
|
||||
case "$ngx_pcre_ver" in
|
||||
4|5)
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre.o"
|
||||
;;
|
||||
|
||||
6)
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o"
|
||||
;;
|
||||
|
||||
*)
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/pcre_newline.o"
|
||||
;;
|
||||
|
||||
esac
|
||||
;;
|
||||
|
||||
*)
|
||||
have=NGX_PCRE . auto/have
|
||||
|
||||
if [ "$NGX_PLATFORM" = win32 ]; then
|
||||
have=PCRE_STATIC . auto/have
|
||||
fi
|
||||
|
||||
CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
|
||||
LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
|
||||
CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
if [ $PCRE_JIT = YES ]; then
|
||||
have=NGX_HAVE_PCRE_JIT . auto/have
|
||||
PCRE_CONF_OPT="$PCRE_CONF_OPT --enable-jit"
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
if [ "$NGX_PLATFORM" != win32 ]; then
|
||||
|
||||
PCRE=NO
|
||||
|
||||
ngx_feature="PCRE library"
|
||||
ngx_feature_name="NGX_PCRE"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <pcre.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-lpcre"
|
||||
ngx_feature_test="pcre *re;
|
||||
re = pcre_compile(NULL, 0, NULL, 0, NULL);
|
||||
if (re == NULL) return 1"
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# FreeBSD port
|
||||
|
||||
ngx_feature="PCRE library in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lpcre"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lpcre"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# RedHat RPM, Solaris package
|
||||
|
||||
ngx_feature="PCRE library in /usr/include/pcre/"
|
||||
ngx_feature_path="/usr/include/pcre"
|
||||
ngx_feature_libs="-lpcre"
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# NetBSD port
|
||||
|
||||
ngx_feature="PCRE library in /usr/pkg/"
|
||||
ngx_feature_path="/usr/pkg/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lpcre"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/pkg/lib -lpcre"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
|
||||
# MacPorts
|
||||
|
||||
ngx_feature="PCRE library in /opt/local/"
|
||||
ngx_feature_path="/opt/local/include"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lpcre"
|
||||
else
|
||||
ngx_feature_libs="-L/opt/local/lib -lpcre"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_INCS="$CORE_INCS $ngx_feature_path"
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
PCRE=YES
|
||||
fi
|
||||
|
||||
if [ $PCRE = YES ]; then
|
||||
ngx_feature="PCRE JIT support"
|
||||
ngx_feature_name="NGX_HAVE_PCRE_JIT"
|
||||
ngx_feature_test="int jit = 0;
|
||||
pcre_free_study(NULL);
|
||||
pcre_config(PCRE_CONFIG_JIT, &jit);
|
||||
if (jit != 1) return 1;"
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
PCRE_JIT=YES
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $PCRE != YES ]; then
|
||||
cat << END
|
||||
|
||||
$0: error: the HTTP rewrite module requires the PCRE library.
|
||||
You can either disable the module by using --without-http_rewrite_module
|
||||
option, or install the PCRE library into the system, or build the PCRE library
|
||||
statically from the source with nginx by using --with-pcre=<path> option.
|
||||
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
case "$NGX_CC_NAME" in
|
||||
|
||||
msvc)
|
||||
ngx_makefile=makefile.msvc
|
||||
ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC"
|
||||
ngx_pcre="PCRE=\"$PCRE\""
|
||||
;;
|
||||
|
||||
owc)
|
||||
ngx_makefile=makefile.owc
|
||||
ngx_opt="CPU_OPT=\"$CPU_OPT\""
|
||||
ngx_pcre=`echo PCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
;;
|
||||
|
||||
bcc)
|
||||
ngx_makefile=makefile.bcc
|
||||
ngx_opt="-DCPU_OPT=\"$CPU_OPT\""
|
||||
ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
;;
|
||||
|
||||
*)
|
||||
ngx_makefile=
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
if [ -n "$ngx_makefile" ]; then
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
`echo "$PCRE/pcre.lib: $PCRE/pcre.h $NGX_MAKEFILE" \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
\$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre $ngx_opt
|
||||
|
||||
`echo "$PCRE/pcre.h:" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
\$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre pcre.h
|
||||
|
||||
END
|
||||
|
||||
else
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$PCRE/pcre.h: $PCRE/Makefile
|
||||
|
||||
$PCRE/Makefile: $NGX_MAKEFILE
|
||||
cd $PCRE \\
|
||||
&& if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
|
||||
&& CC="\$(CC)" CFLAGS="$PCRE_OPT" \\
|
||||
./configure --disable-shared $PCRE_CONF_OPT
|
||||
|
||||
$PCRE/.libs/libpcre.a: $PCRE/Makefile
|
||||
cd $PCRE \\
|
||||
&& \$(MAKE) libpcre.la
|
||||
|
||||
END
|
||||
|
||||
fi
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
CFLAGS = -q -O2 -tWM -w-8004 $(CPU_OPT)
|
||||
PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 \
|
||||
-DSUPPORT_PCRE8 -DHAVE_MEMMOVE
|
||||
|
||||
|
||||
pcre.lib:
|
||||
cd $(PCRE)
|
||||
|
||||
bcc32 -c $(CFLAGS) -I. $(PCREFLAGS) pcre_*.c
|
||||
|
||||
copy /y nul pcre.lst
|
||||
for %n in (*.obj) do @echo +%n ^^& >> pcre.lst
|
||||
echo + >> pcre.lst
|
||||
|
||||
tlib pcre.lib @pcre.lst
|
||||
|
||||
pcre.h:
|
||||
cd $(PCRE)
|
||||
|
||||
copy /y pcre.h.generic pcre.h
|
||||
copy /y config.h.generic config.h
|
||||
copy /y pcre_chartables.c.dist pcre_chartables.c
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
CFLAGS = -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT)
|
||||
PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 \
|
||||
-DSUPPORT_PCRE8 -DHAVE_MEMMOVE
|
||||
|
||||
|
||||
pcre.lib:
|
||||
cd $(PCRE)
|
||||
|
||||
cl -nologo -c $(CFLAGS) -I . $(PCREFLAGS) pcre_*.c
|
||||
|
||||
link -lib -out:pcre.lib -verbose:lib pcre_*.obj
|
||||
|
||||
pcre.h:
|
||||
cd $(PCRE)
|
||||
|
||||
copy /y pcre.h.generic pcre.h
|
||||
copy /y config.h.generic config.h
|
||||
copy /y pcre_chartables.c.dist pcre_chartables.c
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
CFLAGS = -c -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT)
|
||||
PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 &
|
||||
-DSUPPORT_PCRE8 -DHAVE_MEMMOVE
|
||||
|
||||
|
||||
pcre.lib:
|
||||
cd $(PCRE)
|
||||
|
||||
wcl386 $(CFLAGS) -i=. $(PCREFLAGS) pcre_*.c
|
||||
|
||||
dir /b *.obj > pcre.lst
|
||||
|
||||
wlib -n pcre.lib @pcre.lst
|
||||
|
||||
pcre.h:
|
||||
cd $(PCRE)
|
||||
|
||||
copy /y pcre.h.generic pcre.h
|
||||
copy /y config.h.generic config.h
|
||||
copy /y pcre_chartables.c.dist pcre_chartables.c
|
|
@ -0,0 +1,83 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
echo "checking for perl"
|
||||
|
||||
|
||||
NGX_PERL_VER=`$NGX_PERL -v 2>&1 | grep '^This is perl' 2>&1 \
|
||||
| sed -e 's/^This is perl, \(.*\)/\1/'`
|
||||
|
||||
if test -n "$NGX_PERL_VER"; then
|
||||
echo " + perl version: $NGX_PERL_VER"
|
||||
|
||||
if [ "`$NGX_PERL -e 'use 5.008006; print "OK"'`" != "OK" ]; then
|
||||
echo
|
||||
echo "$0: error: perl 5.8.6 or higher is required"
|
||||
echo
|
||||
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ "`$NGX_PERL -MExtUtils::Embed -e 'print "OK"'`" != "OK" ]; then
|
||||
echo
|
||||
echo "$0: error: perl module ExtUtils::Embed is required"
|
||||
echo
|
||||
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
NGX_PM_CFLAGS=`$NGX_PERL -MExtUtils::Embed -e ccopts`
|
||||
NGX_PM_LDFLAGS=`$NGX_PERL -MConfig -e 'print $Config{lddlflags}'`
|
||||
|
||||
NGX_PERL_CFLAGS="$CFLAGS `$NGX_PERL -MExtUtils::Embed -e ccopts`"
|
||||
|
||||
# gcc 4.1/4.2 warn about unused values in pTHX_
|
||||
NGX_PERL_CFLAGS=`echo $NGX_PERL_CFLAGS \
|
||||
| sed -e 's/-Wunused-value/-Wno-unused-value/'`
|
||||
# icc8 warns 'declaration hides parameter "my_perl"' in ENTER and LEAVE
|
||||
NGX_PERL_CFLAGS=`echo $NGX_PERL_CFLAGS \
|
||||
| sed -e 's/-wd171/-wd171 -wd1599/'`
|
||||
|
||||
ngx_perl_ldopts=`$NGX_PERL -MExtUtils::Embed -e ldopts`
|
||||
|
||||
ngx_perl_dlext=`$NGX_PERL -MConfig -e 'print $Config{dlext}'`
|
||||
ngx_perl_libdir="src/http/modules/perl/blib/arch/auto"
|
||||
ngx_perl_module="$ngx_perl_libdir/nginx/nginx.$ngx_perl_dlext"
|
||||
|
||||
if $NGX_PERL -V:usemultiplicity | grep define > /dev/null; then
|
||||
have=NGX_HAVE_PERL_MULTIPLICITY . auto/have
|
||||
echo " + perl interpreter multiplicity found"
|
||||
fi
|
||||
|
||||
if $NGX_PERL -V:useithreads | grep undef > /dev/null; then
|
||||
# FreeBSD port wants to link with -pthread non-threaded perl
|
||||
ngx_perl_ldopts=`echo $ngx_perl_ldopts | sed 's/ -pthread//'`
|
||||
fi
|
||||
|
||||
if [ "$NGX_SYSTEM" = "Darwin" ]; then
|
||||
# OS X system perl wants to link universal binaries
|
||||
ngx_perl_ldopts=`echo $ngx_perl_ldopts \
|
||||
| sed -e 's/-arch i386//' -e 's/-arch x86_64//'`
|
||||
fi
|
||||
|
||||
if [ $USE_PERL = YES ]; then
|
||||
CORE_LINK="$CORE_LINK $ngx_perl_ldopts"
|
||||
fi
|
||||
|
||||
NGX_LIB_PERL="$ngx_perl_ldopts"
|
||||
|
||||
if test -n "$NGX_PERL_MODULES"; then
|
||||
have=NGX_PERL_MODULES value="(u_char *) \"$NGX_PERL_MODULES\""
|
||||
. auto/define
|
||||
NGX_PERL_MODULES_MAN=$NGX_PERL_MODULES/man3
|
||||
fi
|
||||
|
||||
else
|
||||
echo
|
||||
echo "$0: error: perl 5.8.6 or higher is required"
|
||||
echo
|
||||
|
||||
exit 1;
|
||||
fi
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$NGX_OBJS/src/http/modules/perl/ngx_http_perl_module.o: \\
|
||||
$NGX_OBJS/$ngx_perl_module
|
||||
|
||||
$NGX_OBJS/$ngx_perl_module: \\
|
||||
\$(CORE_DEPS) \$(HTTP_DEPS) \\
|
||||
src/http/modules/perl/ngx_http_perl_module.h \\
|
||||
$NGX_OBJS/src/http/modules/perl/Makefile
|
||||
cd $NGX_OBJS/src/http/modules/perl && \$(MAKE)
|
||||
|
||||
rm -rf $NGX_OBJS/install_perl
|
||||
|
||||
|
||||
$NGX_OBJS/src/http/modules/perl/Makefile: \\
|
||||
$NGX_AUTO_CONFIG_H \\
|
||||
src/core/nginx.h \\
|
||||
src/http/modules/perl/Makefile.PL \\
|
||||
src/http/modules/perl/nginx.pm \\
|
||||
src/http/modules/perl/nginx.xs \\
|
||||
src/http/modules/perl/typemap
|
||||
grep 'define NGINX_VERSION' src/core/nginx.h \\
|
||||
| sed -e 's/^.*"\(.*\)".*/\1/' > \\
|
||||
$NGX_OBJS/src/http/modules/perl/version
|
||||
sed "s/%%VERSION%%/\`cat $NGX_OBJS/src/http/modules/perl/version\`/" \\
|
||||
src/http/modules/perl/nginx.pm > \\
|
||||
$NGX_OBJS/src/http/modules/perl/nginx.pm
|
||||
cp -p src/http/modules/perl/nginx.xs $NGX_OBJS/src/http/modules/perl/
|
||||
cp -p src/http/modules/perl/typemap $NGX_OBJS/src/http/modules/perl/
|
||||
cp -p src/http/modules/perl/Makefile.PL $NGX_OBJS/src/http/modules/perl/
|
||||
|
||||
cd $NGX_OBJS/src/http/modules/perl \\
|
||||
&& NGX_PM_CFLAGS="\$(NGX_PM_CFLAGS) -g $NGX_CC_OPT" \\
|
||||
NGX_PM_LDFLAGS="$NGX_LD_OPT \$(NGX_PM_LDFLAGS)" \\
|
||||
NGX_INCS="$CORE_INCS $NGX_OBJS $HTTP_INCS" \\
|
||||
NGX_DEPS="\$(CORE_DEPS) \$(HTTP_DEPS)" \\
|
||||
$NGX_PERL Makefile.PL \\
|
||||
LIB=$NGX_PERL_MODULES \\
|
||||
INSTALLSITEMAN3DIR=$NGX_PERL_MODULES_MAN
|
||||
|
||||
END
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
if [ $ZLIB != NONE ]; then
|
||||
CORE_INCS="$CORE_INCS $ZLIB"
|
||||
|
||||
case "$NGX_CC_NAME" in
|
||||
|
||||
msvc | owc | bcc)
|
||||
have=NGX_ZLIB . auto/have
|
||||
LINK_DEPS="$LINK_DEPS $ZLIB/zlib.lib"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/zlib.lib"
|
||||
;;
|
||||
|
||||
icc)
|
||||
have=NGX_ZLIB . auto/have
|
||||
LINK_DEPS="$LINK_DEPS $ZLIB/libz.a"
|
||||
|
||||
# to allow -ipo optimization we link with the *.o but not library
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/adler32.o"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/crc32.o"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/deflate.o"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/trees.o"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/zutil.o"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/compress.o"
|
||||
|
||||
if [ $ZLIB_ASM != NO ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/match.o"
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
have=NGX_ZLIB . auto/have
|
||||
LINK_DEPS="$LINK_DEPS $ZLIB/libz.a"
|
||||
CORE_LIBS="$CORE_LIBS $ZLIB/libz.a"
|
||||
#CORE_LIBS="$CORE_LIBS -L $ZLIB -lz"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
else
|
||||
|
||||
if [ "$NGX_PLATFORM" != win32 ]; then
|
||||
ZLIB=NO
|
||||
|
||||
# FreeBSD, Solaris, Linux
|
||||
|
||||
ngx_feature="zlib library"
|
||||
ngx_feature_name="NGX_ZLIB"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <zlib.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-lz"
|
||||
ngx_feature_test="z_stream z; deflate(&z, Z_NO_FLUSH)"
|
||||
. auto/feature
|
||||
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
|
||||
ZLIB=YES
|
||||
ngx_found=no
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $ZLIB != YES ]; then
|
||||
cat << END
|
||||
|
||||
$0: error: the HTTP gzip module requires the zlib library.
|
||||
You can either disable the module by using --without-http_gzip_module
|
||||
option, or install the zlib library into the system, or build the zlib library
|
||||
statically from the source with nginx by using --with-zlib=<path> option.
|
||||
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
case "$NGX_CC_NAME" in
|
||||
|
||||
msvc)
|
||||
ngx_makefile=makefile.msvc
|
||||
ngx_opt="CPU_OPT=\"$CPU_OPT\" LIBC=$LIBC"
|
||||
ngx_zlib="ZLIB=\"$ZLIB\""
|
||||
|
||||
;;
|
||||
|
||||
owc)
|
||||
ngx_makefile=makefile.owc
|
||||
ngx_opt="CPU_OPT=\"$CPU_OPT\""
|
||||
ngx_zlib=`echo ZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
;;
|
||||
|
||||
bcc)
|
||||
ngx_makefile=makefile.bcc
|
||||
ngx_opt="-DCPU_OPT=\"$CPU_OPT\""
|
||||
ngx_zlib=`echo \-DZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
;;
|
||||
|
||||
*)
|
||||
ngx_makefile=
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
done=NO
|
||||
|
||||
|
||||
case "$NGX_PLATFORM" in
|
||||
|
||||
win32)
|
||||
|
||||
if [ -n "$ngx_makefile" ]; then
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
`echo "$ZLIB/zlib.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
\$(MAKE) -f auto/lib/zlib/$ngx_makefile $ngx_opt $ngx_zlib
|
||||
|
||||
END
|
||||
|
||||
else
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ZLIB/libz.a: $NGX_MAKEFILE
|
||||
cd $ZLIB \\
|
||||
&& \$(MAKE) distclean \\
|
||||
&& \$(MAKE) -f win32/Makefile.gcc \\
|
||||
CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\
|
||||
libz.a
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
done=YES
|
||||
;;
|
||||
|
||||
# FreeBSD: i386
|
||||
# Linux: i686
|
||||
|
||||
*:i386 | *:i686)
|
||||
case $ZLIB_ASM in
|
||||
pentium)
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ZLIB/libz.a: $NGX_MAKEFILE
|
||||
cd $ZLIB \\
|
||||
&& \$(MAKE) distclean \\
|
||||
&& cp contrib/asm586/match.S . \\
|
||||
&& CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\
|
||||
./configure \\
|
||||
&& \$(MAKE) OBJA=match.o libz.a
|
||||
|
||||
END
|
||||
|
||||
done=YES
|
||||
;;
|
||||
|
||||
pentiumpro)
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ZLIB/libz.a: $NGX_MAKEFILE
|
||||
cd $ZLIB \\
|
||||
&& \$(MAKE) distclean \\
|
||||
&& cp contrib/asm686/match.S . \\
|
||||
&& CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\
|
||||
./configure \\
|
||||
&& \$(MAKE) OBJA=match.o libz.a
|
||||
|
||||
END
|
||||
|
||||
done=YES
|
||||
;;
|
||||
|
||||
NO)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "$0: error: invalid --with-zlib-asm=$ZLIB_ASM option."
|
||||
echo "The valid values are \"pentium\" and \"pentiumpro\" only".
|
||||
echo
|
||||
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
if [ $done = NO ]; then
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ZLIB/libz.a: $NGX_MAKEFILE
|
||||
cd $ZLIB \\
|
||||
&& \$(MAKE) distclean \\
|
||||
&& CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\
|
||||
./configure \\
|
||||
&& \$(MAKE) libz.a
|
||||
|
||||
END
|
||||
|
||||
fi
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
CFLAGS = -q -O2 -tWM -w-8004 -w-8012 $(CPU_OPT)
|
||||
|
||||
zlib.lib:
|
||||
cd $(ZLIB)
|
||||
|
||||
bcc32 -c $(CFLAGS) adler32.c crc32.c deflate.c \
|
||||
trees.c zutil.c compress.c \
|
||||
inflate.c inffast.c inftrees.c
|
||||
|
||||
tlib zlib.lib +adler32.obj +crc32.obj +deflate.obj \
|
||||
+trees.obj +zutil.obj +compress.obj \
|
||||
+inflate.obj +inffast.obj +inftrees.obj
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT)
|
||||
|
||||
zlib.lib:
|
||||
cd $(ZLIB)
|
||||
|
||||
cl -c $(CFLAGS) adler32.c crc32.c deflate.c \
|
||||
trees.c zutil.c compress.c \
|
||||
inflate.c inffast.c inftrees.c
|
||||
|
||||
link -lib -out:zlib.lib adler32.obj crc32.obj deflate.obj \
|
||||
trees.obj zutil.obj compress.obj \
|
||||
inflate.obj inffast.obj inftrees.obj
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
CFLAGS = -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT)
|
||||
|
||||
zlib.lib:
|
||||
cd $(ZLIB)
|
||||
|
||||
wcl386 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c &
|
||||
compress.c inflate.c inffast.c inftrees.c
|
||||
wlib -n zlib.lib adler32.obj crc32.obj deflate.obj trees.obj &
|
||||
zutil.obj compress.obj inflate.obj inffast.obj inftrees.obj
|
|
@ -0,0 +1,691 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
echo "creating $NGX_MAKEFILE"
|
||||
|
||||
mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \
|
||||
$NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \
|
||||
$NGX_OBJS/src/http $NGX_OBJS/src/http/v2 $NGX_OBJS/src/http/modules \
|
||||
$NGX_OBJS/src/http/modules/perl \
|
||||
$NGX_OBJS/src/mail \
|
||||
$NGX_OBJS/src/stream \
|
||||
$NGX_OBJS/src/misc
|
||||
|
||||
|
||||
ngx_objs_dir=$NGX_OBJS$ngx_regex_dirsep
|
||||
ngx_use_pch=`echo $NGX_USE_PCH | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
|
||||
if [ ! $FF_PATH ]; then
|
||||
echo "Please define FF_PATH environment variable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! $FF_DPDK ]; then
|
||||
FF_DPDK=$FF_PATH/dpdk/x86_64-native-linuxapp-gcc
|
||||
echo "FF_DPDK environment variable not defined, default:$FF_DPDK"
|
||||
fi
|
||||
|
||||
CORE_LIBS+=" -L$FF_PATH/lib -L$FF_DPDK/lib -Wl,--whole-archive,-lfstack,--no-whole-archive"
|
||||
CORE_LIBS+=" -g -Wl,--no-as-needed -fvisibility=default -pthread -lm -lrt"
|
||||
CORE_LIBS+=" -Wl,--whole-archive -lrte_pmd_vmxnet3_uio -lrte_pmd_i40e -lrte_pmd_ixgbe -lrte_pmd_e1000 -lrte_pmd_ring"
|
||||
CORE_LIBS+=" -Wl,--whole-archive -lrte_hash -lrte_kvargs -Wl,-lrte_mbuf -lethdev -lrte_eal -Wl,-lrte_mempool"
|
||||
CORE_LIBS+=" -lrte_ring -lrte_cmdline -lrte_cfgfile -lrte_kni -lrte_timer -Wl,-lrte_pmd_virtio"
|
||||
CORE_LIBS+=" -Wl,--no-whole-archive -lrt -lm -ldl -lm -lcrypto"
|
||||
|
||||
cat << END > $NGX_MAKEFILE
|
||||
|
||||
CC = $CC
|
||||
CFLAGS = $CFLAGS
|
||||
CPP = $CPP
|
||||
LINK = $LINK
|
||||
|
||||
CFLAGS += -I$FF_PATH/lib
|
||||
|
||||
END
|
||||
|
||||
|
||||
if test -n "$NGX_PERL_CFLAGS"; then
|
||||
echo NGX_PERL_CFLAGS = $NGX_PERL_CFLAGS >> $NGX_MAKEFILE
|
||||
echo NGX_PM_CFLAGS = $NGX_PM_CFLAGS >> $NGX_MAKEFILE
|
||||
echo NGX_PM_LDFLAGS = $NGX_PM_LDFLAGS >> $NGX_MAKEFILE
|
||||
fi
|
||||
|
||||
|
||||
# ALL_INCS, required by the addons and by OpenWatcom C precompiled headers
|
||||
|
||||
ngx_incs=`echo $CORE_INCS $NGX_OBJS $HTTP_INCS $MAIL_INCS $STREAM_INCS\
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
ALL_INCS = $ngx_include_opt$ngx_incs
|
||||
|
||||
END
|
||||
|
||||
|
||||
ngx_all_srcs="$CORE_SRCS"
|
||||
|
||||
|
||||
# the core dependencies and include paths
|
||||
|
||||
ngx_deps=`echo $CORE_DEPS $NGX_AUTO_CONFIG_H $NGX_PCH \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_incs=`echo $CORE_INCS $NGX_OBJS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
CORE_DEPS = $ngx_deps
|
||||
|
||||
|
||||
CORE_INCS = $ngx_include_opt$ngx_incs
|
||||
|
||||
END
|
||||
|
||||
|
||||
# the http dependencies and include paths
|
||||
|
||||
if [ $HTTP = YES ]; then
|
||||
|
||||
ngx_all_srcs="$ngx_all_srcs $HTTP_SRCS"
|
||||
|
||||
ngx_deps=`echo $HTTP_DEPS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_incs=`echo $HTTP_INCS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
HTTP_DEPS = $ngx_deps
|
||||
|
||||
|
||||
HTTP_INCS = $ngx_include_opt$ngx_incs
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the mail dependencies and include paths
|
||||
|
||||
if [ $MAIL != NO ]; then
|
||||
|
||||
if [ $MAIL = YES ]; then
|
||||
ngx_all_srcs="$ngx_all_srcs $MAIL_SRCS"
|
||||
fi
|
||||
|
||||
ngx_deps=`echo $MAIL_DEPS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_incs=`echo $MAIL_INCS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
MAIL_DEPS = $ngx_deps
|
||||
|
||||
|
||||
MAIL_INCS = $ngx_include_opt$ngx_incs
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the stream dependencies and include paths
|
||||
|
||||
if [ $STREAM != NO ]; then
|
||||
|
||||
if [ $STREAM = YES ]; then
|
||||
ngx_all_srcs="$ngx_all_srcs $STREAM_SRCS"
|
||||
fi
|
||||
|
||||
ngx_deps=`echo $STREAM_DEPS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_incs=`echo $STREAM_INCS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont$ngx_include_opt\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
STREAM_DEPS = $ngx_deps
|
||||
|
||||
|
||||
STREAM_INCS = $ngx_include_opt$ngx_incs
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
ngx_all_srcs="$ngx_all_srcs $MISC_SRCS"
|
||||
|
||||
|
||||
if test -n "$NGX_ADDON_SRCS$DYNAMIC_MODULES"; then
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
ADDON_DEPS = \$(CORE_DEPS) $NGX_ADDON_DEPS
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# nginx
|
||||
|
||||
ngx_all_srcs=`echo $ngx_all_srcs | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
for ngx_src in $NGX_ADDON_SRCS
|
||||
do
|
||||
ngx_obj="addon/`basename \`dirname $ngx_src\``"
|
||||
|
||||
test -d $NGX_OBJS/$ngx_obj || mkdir -p $NGX_OBJS/$ngx_obj
|
||||
|
||||
ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_all_srcs="$ngx_all_srcs $ngx_obj"
|
||||
done
|
||||
|
||||
ngx_all_objs=`echo $ngx_all_srcs \
|
||||
| sed -e "s#\([^ ]*\.\)cpp#$NGX_OBJS\/\1$ngx_objext#g" \
|
||||
-e "s#\([^ ]*\.\)cc#$NGX_OBJS\/\1$ngx_objext#g" \
|
||||
-e "s#\([^ ]*\.\)c#$NGX_OBJS\/\1$ngx_objext#g" \
|
||||
-e "s#\([^ ]*\.\)S#$NGX_OBJS\/\1$ngx_objext#g"`
|
||||
|
||||
ngx_modules_c=`echo $NGX_MODULES_C | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_modules_obj=`echo $ngx_modules_c | sed -e "s/\(.*\.\)c/\1$ngx_objext/"`
|
||||
|
||||
|
||||
if test -n "$NGX_RES"; then
|
||||
ngx_res=$NGX_RES
|
||||
else
|
||||
ngx_res="$NGX_RC $NGX_ICONS"
|
||||
ngx_rcc=`echo $NGX_RCC | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
fi
|
||||
|
||||
ngx_deps=`echo $ngx_all_objs $ngx_modules_obj $ngx_res $LINK_DEPS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_objs=`echo $ngx_all_objs $ngx_modules_obj \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_libs=
|
||||
if test -n "$NGX_LD_OPT$CORE_LIBS"; then
|
||||
ngx_libs=`echo $NGX_LD_OPT $CORE_LIBS \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`
|
||||
fi
|
||||
|
||||
ngx_link=${CORE_LINK:+`echo $CORE_LINK \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
|
||||
|
||||
ngx_main_link=${MAIN_LINK:+`echo $MAIN_LINK \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
|
||||
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
build: binary modules manpage
|
||||
|
||||
binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext
|
||||
|
||||
$NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer
|
||||
\$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
|
||||
$ngx_rcc
|
||||
$ngx_long_end
|
||||
|
||||
modules:
|
||||
END
|
||||
|
||||
|
||||
# ngx_modules.c
|
||||
|
||||
if test -n "$NGX_PCH"; then
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
else
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS)"
|
||||
fi
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_modules_obj: \$(CORE_DEPS)$ngx_cont$ngx_modules_c
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_modules_obj$ngx_tab$ngx_modules_c$NGX_AUX
|
||||
|
||||
END
|
||||
|
||||
|
||||
# the core sources
|
||||
|
||||
for ngx_src in $CORE_SRCS
|
||||
do
|
||||
ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
ngx_obj=`echo $ngx_src \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(CORE_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
|
||||
done
|
||||
|
||||
|
||||
# the http sources
|
||||
|
||||
if [ $HTTP = YES ]; then
|
||||
|
||||
if test -n "$NGX_PCH"; then
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
else
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(HTTP_INCS)"
|
||||
ngx_perl_cc="\$(CC) $ngx_compile_opt \$(NGX_PERL_CFLAGS)"
|
||||
ngx_perl_cc="$ngx_perl_cc \$(CORE_INCS) \$(HTTP_INCS)"
|
||||
fi
|
||||
|
||||
for ngx_source in $HTTP_SRCS
|
||||
do
|
||||
ngx_src=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
ngx_obj=`echo $ngx_src \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
if [ $ngx_source = src/http/modules/perl/ngx_http_perl_module.c ]; then
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(CORE_DEPS) \$(HTTP_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_perl_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
else
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(CORE_DEPS) \$(HTTP_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the mail sources
|
||||
|
||||
if [ $MAIL = YES ]; then
|
||||
|
||||
if test -n "$NGX_PCH"; then
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
else
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(MAIL_INCS)"
|
||||
fi
|
||||
|
||||
for ngx_src in $MAIL_SRCS
|
||||
do
|
||||
ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
ngx_obj=`echo $ngx_src \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(CORE_DEPS) \$(MAIL_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the stream sources
|
||||
|
||||
if [ $STREAM = YES ]; then
|
||||
|
||||
if test -n "$NGX_PCH"; then
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
else
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(STREAM_INCS)"
|
||||
fi
|
||||
|
||||
for ngx_src in $STREAM_SRCS
|
||||
do
|
||||
ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
ngx_obj=`echo $ngx_src \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(CORE_DEPS) \$(STREAM_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the misc sources
|
||||
|
||||
if test -n "$MISC_SRCS"; then
|
||||
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
|
||||
for ngx_src in $MISC_SRCS
|
||||
do
|
||||
ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
ngx_obj=`echo $ngx_src \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(CORE_DEPS) $ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the addons sources
|
||||
|
||||
if test -n "$NGX_ADDON_SRCS"; then
|
||||
|
||||
ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
|
||||
for ngx_src in $NGX_ADDON_SRCS
|
||||
do
|
||||
ngx_obj="addon/`basename \`dirname $ngx_src\``"
|
||||
|
||||
ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_obj=`echo $ngx_obj \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the addons config.make
|
||||
|
||||
if test -n "$NGX_ADDONS$DYNAMIC_ADDONS"; then
|
||||
|
||||
for ngx_addon_dir in $NGX_ADDONS $DYNAMIC_ADDONS
|
||||
do
|
||||
if test -f $ngx_addon_dir/config.make; then
|
||||
. $ngx_addon_dir/config.make
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Win32 resource file
|
||||
|
||||
if test -n "$NGX_RES"; then
|
||||
|
||||
ngx_res=`echo "$NGX_RES: $NGX_RC $NGX_ICONS" \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
ngx_rcc=`echo $NGX_RCC | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_res
|
||||
$ngx_rcc
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# the precompiled headers
|
||||
|
||||
if test -n "$NGX_PCH"; then
|
||||
echo "#include <ngx_config.h>" > $NGX_OBJS/ngx_pch.c
|
||||
|
||||
ngx_pch="src/core/ngx_config.h $OS_CONFIG $NGX_OBJS/ngx_auto_config.h"
|
||||
ngx_pch=`echo "$NGX_PCH: $ngx_pch" | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_src="\$(CC) \$(CFLAGS) $NGX_BUILD_PCH $ngx_compile_opt \$(ALL_INCS)"
|
||||
ngx_src="$ngx_src $ngx_objout$NGX_OBJS/ngx_pch.obj $NGX_OBJS/ngx_pch.c"
|
||||
ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_pch
|
||||
$ngx_src
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# dynamic modules
|
||||
|
||||
if test -n "$NGX_PCH"; then
|
||||
ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
|
||||
else
|
||||
ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) \$(ALL_INCS)"
|
||||
ngx_perl_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(NGX_PERL_CFLAGS)"
|
||||
ngx_perl_cc="$ngx_perl_cc \$(ALL_INCS)"
|
||||
fi
|
||||
|
||||
for ngx_module in $DYNAMIC_MODULES
|
||||
do
|
||||
eval ngx_module_srcs="\$${ngx_module}_SRCS"
|
||||
eval eval ngx_module_libs="\\\"\$${ngx_module}_LIBS\\\""
|
||||
|
||||
eval ngx_module_modules="\$${ngx_module}_MODULES"
|
||||
eval ngx_module_order="\$${ngx_module}_ORDER"
|
||||
|
||||
ngx_modules_c=$NGX_OBJS/${ngx_module}_modules.c
|
||||
|
||||
cat << END > $ngx_modules_c
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
END
|
||||
|
||||
for mod in $ngx_module_modules
|
||||
do
|
||||
echo "extern ngx_module_t $mod;" >> $ngx_modules_c
|
||||
done
|
||||
|
||||
echo >> $ngx_modules_c
|
||||
echo 'ngx_module_t *ngx_modules[] = {' >> $ngx_modules_c
|
||||
|
||||
for mod in $ngx_module_modules
|
||||
do
|
||||
echo " &$mod," >> $ngx_modules_c
|
||||
done
|
||||
|
||||
cat << END >> $ngx_modules_c
|
||||
NULL
|
||||
};
|
||||
|
||||
END
|
||||
|
||||
echo 'char *ngx_module_names[] = {' >> $ngx_modules_c
|
||||
|
||||
for mod in $ngx_module_modules
|
||||
do
|
||||
echo " \"$mod\"," >> $ngx_modules_c
|
||||
done
|
||||
|
||||
cat << END >> $ngx_modules_c
|
||||
NULL
|
||||
};
|
||||
|
||||
END
|
||||
|
||||
echo 'char *ngx_module_order[] = {' >> $ngx_modules_c
|
||||
|
||||
for mod in $ngx_module_order
|
||||
do
|
||||
echo " \"$mod\"," >> $ngx_modules_c
|
||||
done
|
||||
|
||||
cat << END >> $ngx_modules_c
|
||||
NULL
|
||||
};
|
||||
|
||||
END
|
||||
|
||||
ngx_modules_c=`echo $ngx_modules_c | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_modules_obj=`echo $ngx_modules_c \
|
||||
| sed -e "s/\(.*\.\)c/\1$ngx_objext/"`
|
||||
|
||||
ngx_module_objs=
|
||||
for ngx_src in $ngx_module_srcs
|
||||
do
|
||||
case "$ngx_src" in
|
||||
src/*)
|
||||
ngx_obj=$ngx_src
|
||||
;;
|
||||
*)
|
||||
ngx_obj="addon/`basename \`dirname $ngx_src\``"
|
||||
mkdir -p $NGX_OBJS/$ngx_obj
|
||||
ngx_obj="$ngx_obj/`basename $ngx_src`"
|
||||
;;
|
||||
esac
|
||||
|
||||
ngx_module_objs="$ngx_module_objs $ngx_obj"
|
||||
done
|
||||
|
||||
ngx_module_objs=`echo $ngx_module_objs \
|
||||
| sed -e "s#\([^ ]*\.\)cpp#$NGX_OBJS\/\1$ngx_objext#g" \
|
||||
-e "s#\([^ ]*\.\)cc#$NGX_OBJS\/\1$ngx_objext#g" \
|
||||
-e "s#\([^ ]*\.\)c#$NGX_OBJS\/\1$ngx_objext#g" \
|
||||
-e "s#\([^ ]*\.\)S#$NGX_OBJS\/\1$ngx_objext#g"`
|
||||
|
||||
ngx_deps=`echo $ngx_module_objs $ngx_modules_obj $LINK_DEPS \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_objs=`echo $ngx_module_objs $ngx_modules_obj \
|
||||
| sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \
|
||||
-e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
ngx_obj=$NGX_OBJS$ngx_dirsep$ngx_module$ngx_modext
|
||||
|
||||
if [ "$NGX_PLATFORM" = win32 ]; then
|
||||
ngx_module_libs="$CORE_LIBS $ngx_module_libs"
|
||||
fi
|
||||
|
||||
ngx_libs=
|
||||
if test -n "$NGX_LD_OPT$ngx_module_libs"; then
|
||||
ngx_libs=`echo $NGX_LD_OPT $ngx_module_libs \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`
|
||||
fi
|
||||
|
||||
ngx_link=${CORE_LINK:+`echo $CORE_LINK \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
|
||||
|
||||
ngx_module_link=${MODULE_LINK:+`echo $MODULE_LINK \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`}
|
||||
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
modules: $ngx_obj
|
||||
|
||||
$ngx_obj: $ngx_deps$ngx_spacer
|
||||
\$(LINK) $ngx_long_start$ngx_binout$ngx_obj$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_module_link
|
||||
$ngx_long_end
|
||||
|
||||
$ngx_modules_obj: \$(CORE_DEPS)$ngx_cont$ngx_modules_c
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_modules_obj$ngx_tab$ngx_modules_c$NGX_AUX
|
||||
|
||||
END
|
||||
|
||||
for ngx_source in $ngx_module_srcs
|
||||
do
|
||||
case "$ngx_source" in
|
||||
src/*)
|
||||
ngx_obj=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
;;
|
||||
*)
|
||||
ngx_obj="addon/`basename \`dirname $ngx_source\``"
|
||||
ngx_obj=`echo $ngx_obj/\`basename $ngx_source\` \
|
||||
| sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
;;
|
||||
esac
|
||||
|
||||
ngx_obj=`echo $ngx_obj \
|
||||
| sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
|
||||
-e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
|
||||
|
||||
ngx_src=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"`
|
||||
|
||||
if [ $ngx_source = src/http/modules/perl/ngx_http_perl_module.c ]; then
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_perl_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
else
|
||||
|
||||
cat << END >> $NGX_MAKEFILE
|
||||
|
||||
$ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src
|
||||
$ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
|
||||
|
||||
END
|
||||
|
||||
fi
|
||||
done
|
||||
done
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
# Copyright (C) Ruslan Ermilov
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
case $ngx_module_type in
|
||||
HTTP_*) ngx_var=HTTP ;;
|
||||
*) ngx_var=$ngx_module_type ;;
|
||||
esac
|
||||
|
||||
|
||||
if [ "$ngx_module_link" = DYNAMIC ]; then
|
||||
|
||||
for ngx_module in $ngx_module_name; do
|
||||
# extract the first name
|
||||
break
|
||||
done
|
||||
|
||||
DYNAMIC_MODULES="$DYNAMIC_MODULES $ngx_module"
|
||||
eval ${ngx_module}_SRCS=\"$ngx_module_srcs\"
|
||||
|
||||
eval ${ngx_module}_MODULES=\"$ngx_module_name\"
|
||||
|
||||
if [ -z "$ngx_module_order" -a \
|
||||
\( "$ngx_module_type" = "HTTP_FILTER" \
|
||||
-o "$ngx_module_type" = "HTTP_AUX_FILTER" \) ]
|
||||
then
|
||||
eval ${ngx_module}_ORDER=\"$ngx_module_name \
|
||||
ngx_http_copy_filter_module\"
|
||||
else
|
||||
eval ${ngx_module}_ORDER=\"$ngx_module_order\"
|
||||
fi
|
||||
|
||||
if test -n "$ngx_module_incs"; then
|
||||
CORE_INCS="$CORE_INCS $ngx_module_incs"
|
||||
fi
|
||||
|
||||
if test -n "$ngx_module_deps"; then
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_module_deps"
|
||||
fi
|
||||
|
||||
libs=
|
||||
for lib in $ngx_module_libs
|
||||
do
|
||||
case $lib in
|
||||
|
||||
LIBXSLT | LIBGD | GEOIP | PERL)
|
||||
libs="$libs \$NGX_LIB_$lib"
|
||||
|
||||
if eval [ "\$USE_${lib}" = NO ] ; then
|
||||
eval USE_${lib}=DYNAMIC
|
||||
fi
|
||||
;;
|
||||
|
||||
PCRE | OPENSSL | ZLIB)
|
||||
eval USE_${lib}=YES
|
||||
;;
|
||||
|
||||
MD5 | SHA1)
|
||||
# obsolete
|
||||
;;
|
||||
|
||||
*)
|
||||
libs="$libs $lib"
|
||||
;;
|
||||
|
||||
esac
|
||||
done
|
||||
eval ${ngx_module}_LIBS=\'$libs\'
|
||||
|
||||
elif [ "$ngx_module_link" = YES ]; then
|
||||
|
||||
eval ${ngx_module_type}_MODULES=\"\$${ngx_module_type}_MODULES \
|
||||
$ngx_module_name\"
|
||||
|
||||
eval ${ngx_var}_SRCS=\"\$${ngx_var}_SRCS $ngx_module_srcs\"
|
||||
|
||||
if test -n "$ngx_module_incs"; then
|
||||
eval ${ngx_var}_INCS=\"\$${ngx_var}_INCS $ngx_module_incs\"
|
||||
fi
|
||||
|
||||
if test -n "$ngx_module_deps"; then
|
||||
eval ${ngx_var}_DEPS=\"\$${ngx_var}_DEPS $ngx_module_deps\"
|
||||
fi
|
||||
|
||||
for lib in $ngx_module_libs
|
||||
do
|
||||
case $lib in
|
||||
|
||||
PCRE | OPENSSL | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP)
|
||||
eval USE_${lib}=YES
|
||||
;;
|
||||
|
||||
MD5 | SHA1)
|
||||
# obsolete
|
||||
;;
|
||||
|
||||
*)
|
||||
CORE_LIBS="$CORE_LIBS $lib"
|
||||
;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
elif [ "$ngx_module_link" = ADDON ]; then
|
||||
|
||||
eval ${ngx_module_type}_MODULES=\"\$${ngx_module_type}_MODULES \
|
||||
$ngx_module_name\"
|
||||
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_module_srcs"
|
||||
|
||||
if test -n "$ngx_module_incs"; then
|
||||
eval ${ngx_var}_INCS=\"\$${ngx_var}_INCS $ngx_module_incs\"
|
||||
fi
|
||||
|
||||
if test -n "$ngx_module_deps"; then
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_module_deps"
|
||||
fi
|
||||
|
||||
for lib in $ngx_module_libs
|
||||
do
|
||||
case $lib in
|
||||
|
||||
PCRE | OPENSSL | ZLIB | LIBXSLT | LIBGD | PERL | GEOIP)
|
||||
eval USE_${lib}=YES
|
||||
;;
|
||||
|
||||
MD5 | SHA1)
|
||||
# obsolete
|
||||
;;
|
||||
|
||||
*)
|
||||
CORE_LIBS="$CORE_LIBS $lib"
|
||||
;;
|
||||
|
||||
esac
|
||||
done
|
||||
fi
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,12 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
cat << END >> $NGX_AUTO_CONFIG_H
|
||||
|
||||
#ifndef $have
|
||||
#define $have 0
|
||||
#endif
|
||||
|
||||
END
|
|
@ -0,0 +1,631 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
help=no
|
||||
|
||||
NGX_PREFIX=
|
||||
NGX_SBIN_PATH=
|
||||
NGX_MODULES_PATH=
|
||||
NGX_CONF_PREFIX=
|
||||
NGX_CONF_PATH=
|
||||
NGX_ERROR_LOG_PATH=
|
||||
NGX_PID_PATH=
|
||||
NGX_LOCK_PATH=
|
||||
NGX_USER=
|
||||
NGX_GROUP=
|
||||
NGX_BUILD=
|
||||
|
||||
CC=${CC:-cc}
|
||||
CPP=
|
||||
NGX_OBJS=objs
|
||||
|
||||
NGX_DEBUG=NO
|
||||
NGX_CC_OPT=
|
||||
NGX_LD_OPT=
|
||||
CPU=NO
|
||||
|
||||
NGX_RPATH=NO
|
||||
|
||||
NGX_TEST_BUILD_DEVPOLL=NO
|
||||
NGX_TEST_BUILD_EVENTPORT=NO
|
||||
NGX_TEST_BUILD_EPOLL=NO
|
||||
NGX_TEST_BUILD_SOLARIS_SENDFILEV=NO
|
||||
|
||||
NGX_PLATFORM=
|
||||
NGX_WINE=
|
||||
|
||||
EVENT_FOUND=NO
|
||||
|
||||
EVENT_SELECT=NO
|
||||
EVENT_POLL=NO
|
||||
|
||||
USE_THREADS=NO
|
||||
|
||||
NGX_FILE_AIO=NO
|
||||
|
||||
HTTP=YES
|
||||
|
||||
NGX_HTTP_LOG_PATH=
|
||||
NGX_HTTP_CLIENT_TEMP_PATH=
|
||||
NGX_HTTP_PROXY_TEMP_PATH=
|
||||
NGX_HTTP_FASTCGI_TEMP_PATH=
|
||||
NGX_HTTP_UWSGI_TEMP_PATH=
|
||||
NGX_HTTP_SCGI_TEMP_PATH=
|
||||
|
||||
HTTP_CACHE=YES
|
||||
HTTP_CHARSET=YES
|
||||
HTTP_GZIP=YES
|
||||
HTTP_SSL=NO
|
||||
HTTP_V2=NO
|
||||
HTTP_SSI=YES
|
||||
HTTP_POSTPONE=NO
|
||||
HTTP_REALIP=NO
|
||||
HTTP_XSLT=NO
|
||||
HTTP_IMAGE_FILTER=NO
|
||||
HTTP_SUB=NO
|
||||
HTTP_ADDITION=NO
|
||||
HTTP_DAV=NO
|
||||
HTTP_ACCESS=YES
|
||||
HTTP_AUTH_BASIC=YES
|
||||
HTTP_AUTH_REQUEST=NO
|
||||
HTTP_USERID=YES
|
||||
HTTP_SLICE=NO
|
||||
HTTP_AUTOINDEX=YES
|
||||
HTTP_RANDOM_INDEX=NO
|
||||
HTTP_STATUS=NO
|
||||
HTTP_GEO=YES
|
||||
HTTP_GEOIP=NO
|
||||
HTTP_MAP=YES
|
||||
HTTP_SPLIT_CLIENTS=YES
|
||||
HTTP_REFERER=YES
|
||||
HTTP_REWRITE=YES
|
||||
HTTP_PROXY=YES
|
||||
HTTP_FASTCGI=YES
|
||||
HTTP_UWSGI=YES
|
||||
HTTP_SCGI=YES
|
||||
HTTP_PERL=NO
|
||||
HTTP_MEMCACHED=YES
|
||||
HTTP_LIMIT_CONN=YES
|
||||
HTTP_LIMIT_REQ=YES
|
||||
HTTP_EMPTY_GIF=YES
|
||||
HTTP_BROWSER=YES
|
||||
HTTP_SECURE_LINK=NO
|
||||
HTTP_DEGRADATION=NO
|
||||
HTTP_FLV=NO
|
||||
HTTP_MP4=NO
|
||||
HTTP_GUNZIP=NO
|
||||
HTTP_GZIP_STATIC=NO
|
||||
HTTP_UPSTREAM_HASH=YES
|
||||
HTTP_UPSTREAM_IP_HASH=YES
|
||||
HTTP_UPSTREAM_LEAST_CONN=YES
|
||||
HTTP_UPSTREAM_KEEPALIVE=YES
|
||||
HTTP_UPSTREAM_ZONE=YES
|
||||
|
||||
# STUB
|
||||
HTTP_STUB_STATUS=NO
|
||||
|
||||
MAIL=NO
|
||||
MAIL_SSL=NO
|
||||
MAIL_POP3=YES
|
||||
MAIL_IMAP=YES
|
||||
MAIL_SMTP=YES
|
||||
|
||||
STREAM=NO
|
||||
STREAM_SSL=NO
|
||||
STREAM_REALIP=NO
|
||||
STREAM_LIMIT_CONN=YES
|
||||
STREAM_ACCESS=YES
|
||||
STREAM_GEO=YES
|
||||
STREAM_GEOIP=NO
|
||||
STREAM_MAP=YES
|
||||
STREAM_SPLIT_CLIENTS=YES
|
||||
STREAM_RETURN=YES
|
||||
STREAM_UPSTREAM_HASH=YES
|
||||
STREAM_UPSTREAM_LEAST_CONN=YES
|
||||
STREAM_UPSTREAM_ZONE=YES
|
||||
STREAM_SSL_PREREAD=NO
|
||||
|
||||
DYNAMIC_MODULES=
|
||||
|
||||
NGX_ADDONS=
|
||||
NGX_ADDON_DEPS=
|
||||
DYNAMIC_ADDONS=
|
||||
|
||||
NGX_COMPAT=NO
|
||||
|
||||
USE_PCRE=NO
|
||||
PCRE=NONE
|
||||
PCRE_OPT=
|
||||
PCRE_CONF_OPT=
|
||||
PCRE_JIT=NO
|
||||
|
||||
USE_OPENSSL=NO
|
||||
OPENSSL=NONE
|
||||
|
||||
USE_ZLIB=NO
|
||||
ZLIB=NONE
|
||||
ZLIB_OPT=
|
||||
ZLIB_ASM=NO
|
||||
|
||||
USE_PERL=NO
|
||||
NGX_PERL=perl
|
||||
|
||||
USE_LIBXSLT=NO
|
||||
USE_LIBGD=NO
|
||||
USE_GEOIP=NO
|
||||
|
||||
NGX_GOOGLE_PERFTOOLS=NO
|
||||
NGX_CPP_TEST=NO
|
||||
|
||||
NGX_LIBATOMIC=NO
|
||||
|
||||
NGX_CPU_CACHE_LINE=
|
||||
|
||||
NGX_POST_CONF_MSG=
|
||||
|
||||
USE_FSTACK=NO
|
||||
|
||||
opt=
|
||||
|
||||
for option
|
||||
do
|
||||
opt="$opt `echo $option | sed -e \"s/\(--[^=]*=\)\(.* .*\)/\1'\2'/\"`"
|
||||
|
||||
case "$option" in
|
||||
-*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;;
|
||||
*) value="" ;;
|
||||
esac
|
||||
|
||||
case "$option" in
|
||||
--help) help=yes ;;
|
||||
|
||||
--prefix=) NGX_PREFIX="!" ;;
|
||||
--prefix=*) NGX_PREFIX="$value" ;;
|
||||
--sbin-path=*) NGX_SBIN_PATH="$value" ;;
|
||||
--modules-path=*) NGX_MODULES_PATH="$value" ;;
|
||||
--conf-path=*) NGX_CONF_PATH="$value" ;;
|
||||
--error-log-path=*) NGX_ERROR_LOG_PATH="$value";;
|
||||
--pid-path=*) NGX_PID_PATH="$value" ;;
|
||||
--lock-path=*) NGX_LOCK_PATH="$value" ;;
|
||||
--user=*) NGX_USER="$value" ;;
|
||||
--group=*) NGX_GROUP="$value" ;;
|
||||
|
||||
--crossbuild=*) NGX_PLATFORM="$value" ;;
|
||||
|
||||
--build=*) NGX_BUILD="$value" ;;
|
||||
--builddir=*) NGX_OBJS="$value" ;;
|
||||
|
||||
--with-select_module) EVENT_SELECT=YES ;;
|
||||
--without-select_module) EVENT_SELECT=NONE ;;
|
||||
--with-poll_module) EVENT_POLL=YES ;;
|
||||
--without-poll_module) EVENT_POLL=NONE ;;
|
||||
|
||||
--with-ff_module) USE_FSTACK=YES ;;
|
||||
|
||||
--with-threads) USE_THREADS=YES ;;
|
||||
|
||||
--with-file-aio) NGX_FILE_AIO=YES ;;
|
||||
|
||||
--with-ipv6)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-ipv6\" option is deprecated"
|
||||
;;
|
||||
|
||||
--without-http) HTTP=NO ;;
|
||||
--without-http-cache) HTTP_CACHE=NO ;;
|
||||
|
||||
--http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;;
|
||||
--http-client-body-temp-path=*) NGX_HTTP_CLIENT_TEMP_PATH="$value" ;;
|
||||
--http-proxy-temp-path=*) NGX_HTTP_PROXY_TEMP_PATH="$value" ;;
|
||||
--http-fastcgi-temp-path=*) NGX_HTTP_FASTCGI_TEMP_PATH="$value" ;;
|
||||
--http-uwsgi-temp-path=*) NGX_HTTP_UWSGI_TEMP_PATH="$value" ;;
|
||||
--http-scgi-temp-path=*) NGX_HTTP_SCGI_TEMP_PATH="$value" ;;
|
||||
|
||||
--with-http_ssl_module) HTTP_SSL=YES ;;
|
||||
--with-http_v2_module) HTTP_V2=YES ;;
|
||||
--with-http_realip_module) HTTP_REALIP=YES ;;
|
||||
--with-http_addition_module) HTTP_ADDITION=YES ;;
|
||||
--with-http_xslt_module) HTTP_XSLT=YES ;;
|
||||
--with-http_xslt_module=dynamic) HTTP_XSLT=DYNAMIC ;;
|
||||
--with-http_image_filter_module) HTTP_IMAGE_FILTER=YES ;;
|
||||
--with-http_image_filter_module=dynamic)
|
||||
HTTP_IMAGE_FILTER=DYNAMIC ;;
|
||||
--with-http_geoip_module) HTTP_GEOIP=YES ;;
|
||||
--with-http_geoip_module=dynamic)
|
||||
HTTP_GEOIP=DYNAMIC ;;
|
||||
--with-http_sub_module) HTTP_SUB=YES ;;
|
||||
--with-http_dav_module) HTTP_DAV=YES ;;
|
||||
--with-http_flv_module) HTTP_FLV=YES ;;
|
||||
--with-http_mp4_module) HTTP_MP4=YES ;;
|
||||
--with-http_gunzip_module) HTTP_GUNZIP=YES ;;
|
||||
--with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;;
|
||||
--with-http_auth_request_module) HTTP_AUTH_REQUEST=YES ;;
|
||||
--with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;;
|
||||
--with-http_secure_link_module) HTTP_SECURE_LINK=YES ;;
|
||||
--with-http_degradation_module) HTTP_DEGRADATION=YES ;;
|
||||
--with-http_slice_module) HTTP_SLICE=YES ;;
|
||||
|
||||
--without-http_charset_module) HTTP_CHARSET=NO ;;
|
||||
--without-http_gzip_module) HTTP_GZIP=NO ;;
|
||||
--without-http_ssi_module) HTTP_SSI=NO ;;
|
||||
--without-http_userid_module) HTTP_USERID=NO ;;
|
||||
--without-http_access_module) HTTP_ACCESS=NO ;;
|
||||
--without-http_auth_basic_module) HTTP_AUTH_BASIC=NO ;;
|
||||
--without-http_autoindex_module) HTTP_AUTOINDEX=NO ;;
|
||||
--without-http_status_module) HTTP_STATUS=NO ;;
|
||||
--without-http_geo_module) HTTP_GEO=NO ;;
|
||||
--without-http_map_module) HTTP_MAP=NO ;;
|
||||
--without-http_split_clients_module) HTTP_SPLIT_CLIENTS=NO ;;
|
||||
--without-http_referer_module) HTTP_REFERER=NO ;;
|
||||
--without-http_rewrite_module) HTTP_REWRITE=NO ;;
|
||||
--without-http_proxy_module) HTTP_PROXY=NO ;;
|
||||
--without-http_fastcgi_module) HTTP_FASTCGI=NO ;;
|
||||
--without-http_uwsgi_module) HTTP_UWSGI=NO ;;
|
||||
--without-http_scgi_module) HTTP_SCGI=NO ;;
|
||||
--without-http_memcached_module) HTTP_MEMCACHED=NO ;;
|
||||
--without-http_limit_conn_module) HTTP_LIMIT_CONN=NO ;;
|
||||
--without-http_limit_req_module) HTTP_LIMIT_REQ=NO ;;
|
||||
--without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;;
|
||||
--without-http_browser_module) HTTP_BROWSER=NO ;;
|
||||
--without-http_upstream_hash_module) HTTP_UPSTREAM_HASH=NO ;;
|
||||
--without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;;
|
||||
--without-http_upstream_least_conn_module)
|
||||
HTTP_UPSTREAM_LEAST_CONN=NO ;;
|
||||
--without-http_upstream_keepalive_module) HTTP_UPSTREAM_KEEPALIVE=NO ;;
|
||||
--without-http_upstream_zone_module) HTTP_UPSTREAM_ZONE=NO ;;
|
||||
|
||||
--with-http_perl_module) HTTP_PERL=YES ;;
|
||||
--with-http_perl_module=dynamic) HTTP_PERL=DYNAMIC ;;
|
||||
--with-perl_modules_path=*) NGX_PERL_MODULES="$value" ;;
|
||||
--with-perl=*) NGX_PERL="$value" ;;
|
||||
|
||||
# STUB
|
||||
--with-http_stub_status_module) HTTP_STUB_STATUS=YES ;;
|
||||
|
||||
--with-mail) MAIL=YES ;;
|
||||
--with-mail=dynamic) MAIL=DYNAMIC ;;
|
||||
--with-mail_ssl_module) MAIL_SSL=YES ;;
|
||||
# STUB
|
||||
--with-imap)
|
||||
MAIL=YES
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-imap\" option is deprecated, \
|
||||
use the \"--with-mail\" option instead"
|
||||
;;
|
||||
--with-imap_ssl_module)
|
||||
MAIL_SSL=YES
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-imap_ssl_module\" option is deprecated, \
|
||||
use the \"--with-mail_ssl_module\" option instead"
|
||||
;;
|
||||
--without-mail_pop3_module) MAIL_POP3=NO ;;
|
||||
--without-mail_imap_module) MAIL_IMAP=NO ;;
|
||||
--without-mail_smtp_module) MAIL_SMTP=NO ;;
|
||||
|
||||
--with-stream) STREAM=YES ;;
|
||||
--with-stream=dynamic) STREAM=DYNAMIC ;;
|
||||
--with-stream_ssl_module) STREAM_SSL=YES ;;
|
||||
--with-stream_realip_module) STREAM_REALIP=YES ;;
|
||||
--with-stream_geoip_module) STREAM_GEOIP=YES ;;
|
||||
--with-stream_geoip_module=dynamic)
|
||||
STREAM_GEOIP=DYNAMIC ;;
|
||||
--with-stream_ssl_preread_module)
|
||||
STREAM_SSL_PREREAD=YES ;;
|
||||
--without-stream_limit_conn_module)
|
||||
STREAM_LIMIT_CONN=NO ;;
|
||||
--without-stream_access_module) STREAM_ACCESS=NO ;;
|
||||
--without-stream_geo_module) STREAM_GEO=NO ;;
|
||||
--without-stream_map_module) STREAM_MAP=NO ;;
|
||||
--without-stream_split_clients_module)
|
||||
STREAM_SPLIT_CLIENTS=NO ;;
|
||||
--without-stream_return_module) STREAM_RETURN=NO ;;
|
||||
--without-stream_upstream_hash_module)
|
||||
STREAM_UPSTREAM_HASH=NO ;;
|
||||
--without-stream_upstream_least_conn_module)
|
||||
STREAM_UPSTREAM_LEAST_CONN=NO ;;
|
||||
--without-stream_upstream_zone_module)
|
||||
STREAM_UPSTREAM_ZONE=NO ;;
|
||||
|
||||
--with-google_perftools_module) NGX_GOOGLE_PERFTOOLS=YES ;;
|
||||
--with-cpp_test_module) NGX_CPP_TEST=YES ;;
|
||||
|
||||
--add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;;
|
||||
--add-dynamic-module=*) DYNAMIC_ADDONS="$DYNAMIC_ADDONS $value" ;;
|
||||
|
||||
--with-compat) NGX_COMPAT=YES ;;
|
||||
|
||||
--with-cc=*) CC="$value" ;;
|
||||
--with-cpp=*) CPP="$value" ;;
|
||||
--with-cc-opt=*) NGX_CC_OPT="$value" ;;
|
||||
--with-ld-opt=*) NGX_LD_OPT="$value" ;;
|
||||
--with-cpu-opt=*) CPU="$value" ;;
|
||||
--with-debug) NGX_DEBUG=YES ;;
|
||||
|
||||
--without-pcre) USE_PCRE=DISABLED ;;
|
||||
--with-pcre) USE_PCRE=YES ;;
|
||||
--with-pcre=*) PCRE="$value" ;;
|
||||
--with-pcre-opt=*) PCRE_OPT="$value" ;;
|
||||
--with-pcre-jit) PCRE_JIT=YES ;;
|
||||
|
||||
--with-openssl=*) OPENSSL="$value" ;;
|
||||
--with-openssl-opt=*) OPENSSL_OPT="$value" ;;
|
||||
|
||||
--with-md5=*)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-md5\" option is deprecated"
|
||||
;;
|
||||
--with-md5-opt=*)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-md5-opt\" option is deprecated"
|
||||
;;
|
||||
--with-md5-asm)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-md5-asm\" option is deprecated"
|
||||
;;
|
||||
|
||||
--with-sha1=*)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-sha1\" option is deprecated"
|
||||
;;
|
||||
--with-sha1-opt=*)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-sha1-opt\" option is deprecated"
|
||||
;;
|
||||
--with-sha1-asm)
|
||||
NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
|
||||
$0: warning: the \"--with-sha1-asm\" option is deprecated"
|
||||
;;
|
||||
|
||||
--with-zlib=*) ZLIB="$value" ;;
|
||||
--with-zlib-opt=*) ZLIB_OPT="$value" ;;
|
||||
--with-zlib-asm=*) ZLIB_ASM="$value" ;;
|
||||
|
||||
--with-libatomic) NGX_LIBATOMIC=YES ;;
|
||||
--with-libatomic=*) NGX_LIBATOMIC="$value" ;;
|
||||
|
||||
--test-build-devpoll) NGX_TEST_BUILD_DEVPOLL=YES ;;
|
||||
--test-build-eventport) NGX_TEST_BUILD_EVENTPORT=YES ;;
|
||||
--test-build-epoll) NGX_TEST_BUILD_EPOLL=YES ;;
|
||||
--test-build-solaris-sendfilev) NGX_TEST_BUILD_SOLARIS_SENDFILEV=YES ;;
|
||||
|
||||
*)
|
||||
echo "$0: error: invalid option \"$option\""
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
NGX_CONFIGURE="$opt"
|
||||
|
||||
|
||||
if [ $help = yes ]; then
|
||||
|
||||
cat << END
|
||||
|
||||
--help print this message
|
||||
|
||||
--prefix=PATH set installation prefix
|
||||
--sbin-path=PATH set nginx binary pathname
|
||||
--modules-path=PATH set modules path
|
||||
--conf-path=PATH set nginx.conf pathname
|
||||
--error-log-path=PATH set error log pathname
|
||||
--pid-path=PATH set nginx.pid pathname
|
||||
--lock-path=PATH set nginx.lock pathname
|
||||
|
||||
--user=USER set non-privileged user for
|
||||
worker processes
|
||||
--group=GROUP set non-privileged group for
|
||||
worker processes
|
||||
|
||||
--build=NAME set build name
|
||||
--builddir=DIR set build directory
|
||||
|
||||
--with-select_module enable select module
|
||||
--without-select_module disable select module
|
||||
--with-poll_module enable poll module
|
||||
--without-poll_module disable poll module
|
||||
|
||||
--with-ff_module enable F-Stack module
|
||||
|
||||
--with-threads enable thread pool support
|
||||
|
||||
--with-file-aio enable file AIO support
|
||||
|
||||
--with-http_ssl_module enable ngx_http_ssl_module
|
||||
--with-http_v2_module enable ngx_http_v2_module
|
||||
--with-http_realip_module enable ngx_http_realip_module
|
||||
--with-http_addition_module enable ngx_http_addition_module
|
||||
--with-http_xslt_module enable ngx_http_xslt_module
|
||||
--with-http_xslt_module=dynamic enable dynamic ngx_http_xslt_module
|
||||
--with-http_image_filter_module enable ngx_http_image_filter_module
|
||||
--with-http_image_filter_module=dynamic
|
||||
enable dynamic ngx_http_image_filter_module
|
||||
--with-http_geoip_module enable ngx_http_geoip_module
|
||||
--with-http_geoip_module=dynamic enable dynamic ngx_http_geoip_module
|
||||
--with-http_sub_module enable ngx_http_sub_module
|
||||
--with-http_dav_module enable ngx_http_dav_module
|
||||
--with-http_flv_module enable ngx_http_flv_module
|
||||
--with-http_mp4_module enable ngx_http_mp4_module
|
||||
--with-http_gunzip_module enable ngx_http_gunzip_module
|
||||
--with-http_gzip_static_module enable ngx_http_gzip_static_module
|
||||
--with-http_auth_request_module enable ngx_http_auth_request_module
|
||||
--with-http_random_index_module enable ngx_http_random_index_module
|
||||
--with-http_secure_link_module enable ngx_http_secure_link_module
|
||||
--with-http_degradation_module enable ngx_http_degradation_module
|
||||
--with-http_slice_module enable ngx_http_slice_module
|
||||
--with-http_stub_status_module enable ngx_http_stub_status_module
|
||||
|
||||
--without-http_charset_module disable ngx_http_charset_module
|
||||
--without-http_gzip_module disable ngx_http_gzip_module
|
||||
--without-http_ssi_module disable ngx_http_ssi_module
|
||||
--without-http_userid_module disable ngx_http_userid_module
|
||||
--without-http_access_module disable ngx_http_access_module
|
||||
--without-http_auth_basic_module disable ngx_http_auth_basic_module
|
||||
--without-http_autoindex_module disable ngx_http_autoindex_module
|
||||
--without-http_geo_module disable ngx_http_geo_module
|
||||
--without-http_map_module disable ngx_http_map_module
|
||||
--without-http_split_clients_module disable ngx_http_split_clients_module
|
||||
--without-http_referer_module disable ngx_http_referer_module
|
||||
--without-http_rewrite_module disable ngx_http_rewrite_module
|
||||
--without-http_proxy_module disable ngx_http_proxy_module
|
||||
--without-http_fastcgi_module disable ngx_http_fastcgi_module
|
||||
--without-http_uwsgi_module disable ngx_http_uwsgi_module
|
||||
--without-http_scgi_module disable ngx_http_scgi_module
|
||||
--without-http_memcached_module disable ngx_http_memcached_module
|
||||
--without-http_limit_conn_module disable ngx_http_limit_conn_module
|
||||
--without-http_limit_req_module disable ngx_http_limit_req_module
|
||||
--without-http_empty_gif_module disable ngx_http_empty_gif_module
|
||||
--without-http_browser_module disable ngx_http_browser_module
|
||||
--without-http_upstream_hash_module
|
||||
disable ngx_http_upstream_hash_module
|
||||
--without-http_upstream_ip_hash_module
|
||||
disable ngx_http_upstream_ip_hash_module
|
||||
--without-http_upstream_least_conn_module
|
||||
disable ngx_http_upstream_least_conn_module
|
||||
--without-http_upstream_keepalive_module
|
||||
disable ngx_http_upstream_keepalive_module
|
||||
--without-http_upstream_zone_module
|
||||
disable ngx_http_upstream_zone_module
|
||||
|
||||
--with-http_perl_module enable ngx_http_perl_module
|
||||
--with-http_perl_module=dynamic enable dynamic ngx_http_perl_module
|
||||
--with-perl_modules_path=PATH set Perl modules path
|
||||
--with-perl=PATH set perl binary pathname
|
||||
|
||||
--http-log-path=PATH set http access log pathname
|
||||
--http-client-body-temp-path=PATH set path to store
|
||||
http client request body temporary files
|
||||
--http-proxy-temp-path=PATH set path to store
|
||||
http proxy temporary files
|
||||
--http-fastcgi-temp-path=PATH set path to store
|
||||
http fastcgi temporary files
|
||||
--http-uwsgi-temp-path=PATH set path to store
|
||||
http uwsgi temporary files
|
||||
--http-scgi-temp-path=PATH set path to store
|
||||
http scgi temporary files
|
||||
|
||||
--without-http disable HTTP server
|
||||
--without-http-cache disable HTTP cache
|
||||
|
||||
--with-mail enable POP3/IMAP4/SMTP proxy module
|
||||
--with-mail=dynamic enable dynamic POP3/IMAP4/SMTP proxy module
|
||||
--with-mail_ssl_module enable ngx_mail_ssl_module
|
||||
--without-mail_pop3_module disable ngx_mail_pop3_module
|
||||
--without-mail_imap_module disable ngx_mail_imap_module
|
||||
--without-mail_smtp_module disable ngx_mail_smtp_module
|
||||
|
||||
--with-stream enable TCP/UDP proxy module
|
||||
--with-stream=dynamic enable dynamic TCP/UDP proxy module
|
||||
--with-stream_ssl_module enable ngx_stream_ssl_module
|
||||
--with-stream_realip_module enable ngx_stream_realip_module
|
||||
--with-stream_geoip_module enable ngx_stream_geoip_module
|
||||
--with-stream_geoip_module=dynamic enable dynamic ngx_stream_geoip_module
|
||||
--with-stream_ssl_preread_module enable ngx_stream_ssl_preread_module
|
||||
--without-stream_limit_conn_module disable ngx_stream_limit_conn_module
|
||||
--without-stream_access_module disable ngx_stream_access_module
|
||||
--without-stream_geo_module disable ngx_stream_geo_module
|
||||
--without-stream_map_module disable ngx_stream_map_module
|
||||
--without-stream_split_clients_module
|
||||
disable ngx_stream_split_clients_module
|
||||
--without-stream_return_module disable ngx_stream_return_module
|
||||
--without-stream_upstream_hash_module
|
||||
disable ngx_stream_upstream_hash_module
|
||||
--without-stream_upstream_least_conn_module
|
||||
disable ngx_stream_upstream_least_conn_module
|
||||
--without-stream_upstream_zone_module
|
||||
disable ngx_stream_upstream_zone_module
|
||||
|
||||
--with-google_perftools_module enable ngx_google_perftools_module
|
||||
--with-cpp_test_module enable ngx_cpp_test_module
|
||||
|
||||
--add-module=PATH enable external module
|
||||
--add-dynamic-module=PATH enable dynamic external module
|
||||
|
||||
--with-compat dynamic modules compatibility
|
||||
|
||||
--with-cc=PATH set C compiler pathname
|
||||
--with-cpp=PATH set C preprocessor pathname
|
||||
--with-cc-opt=OPTIONS set additional C compiler options
|
||||
--with-ld-opt=OPTIONS set additional linker options
|
||||
--with-cpu-opt=CPU build for the specified CPU, valid values:
|
||||
pentium, pentiumpro, pentium3, pentium4,
|
||||
athlon, opteron, sparc32, sparc64, ppc64
|
||||
|
||||
--without-pcre disable PCRE library usage
|
||||
--with-pcre force PCRE library usage
|
||||
--with-pcre=DIR set path to PCRE library sources
|
||||
--with-pcre-opt=OPTIONS set additional build options for PCRE
|
||||
--with-pcre-jit build PCRE with JIT compilation support
|
||||
|
||||
--with-zlib=DIR set path to zlib library sources
|
||||
--with-zlib-opt=OPTIONS set additional build options for zlib
|
||||
--with-zlib-asm=CPU use zlib assembler sources optimized
|
||||
for the specified CPU, valid values:
|
||||
pentium, pentiumpro
|
||||
|
||||
--with-libatomic force libatomic_ops library usage
|
||||
--with-libatomic=DIR set path to libatomic_ops library sources
|
||||
|
||||
--with-openssl=DIR set path to OpenSSL library sources
|
||||
--with-openssl-opt=OPTIONS set additional build options for OpenSSL
|
||||
|
||||
--with-debug enable debug logging
|
||||
|
||||
END
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ $HTTP = NO ]; then
|
||||
HTTP_CHARSET=NO
|
||||
HTTP_GZIP=NO
|
||||
HTTP_SSI=NO
|
||||
HTTP_USERID=NO
|
||||
HTTP_ACCESS=NO
|
||||
HTTP_STATUS=NO
|
||||
HTTP_REWRITE=NO
|
||||
HTTP_PROXY=NO
|
||||
HTTP_FASTCGI=NO
|
||||
fi
|
||||
|
||||
|
||||
if [ ".$NGX_PLATFORM" = ".win32" ]; then
|
||||
NGX_WINE=$WINE
|
||||
fi
|
||||
|
||||
|
||||
NGX_SBIN_PATH=${NGX_SBIN_PATH:-sbin/nginx}
|
||||
NGX_MODULES_PATH=${NGX_MODULES_PATH:-modules}
|
||||
NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf}
|
||||
NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH`
|
||||
NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid}
|
||||
NGX_LOCK_PATH=${NGX_LOCK_PATH:-logs/nginx.lock}
|
||||
|
||||
if [ ".$NGX_ERROR_LOG_PATH" = ".stderr" ]; then
|
||||
NGX_ERROR_LOG_PATH=
|
||||
else
|
||||
NGX_ERROR_LOG_PATH=${NGX_ERROR_LOG_PATH:-logs/error.log}
|
||||
fi
|
||||
|
||||
NGX_HTTP_LOG_PATH=${NGX_HTTP_LOG_PATH:-logs/access.log}
|
||||
NGX_HTTP_CLIENT_TEMP_PATH=${NGX_HTTP_CLIENT_TEMP_PATH:-client_body_temp}
|
||||
NGX_HTTP_PROXY_TEMP_PATH=${NGX_HTTP_PROXY_TEMP_PATH:-proxy_temp}
|
||||
NGX_HTTP_FASTCGI_TEMP_PATH=${NGX_HTTP_FASTCGI_TEMP_PATH:-fastcgi_temp}
|
||||
NGX_HTTP_UWSGI_TEMP_PATH=${NGX_HTTP_UWSGI_TEMP_PATH:-uwsgi_temp}
|
||||
NGX_HTTP_SCGI_TEMP_PATH=${NGX_HTTP_SCGI_TEMP_PATH:-scgi_temp}
|
||||
|
||||
case ".$NGX_PERL_MODULES" in
|
||||
./*)
|
||||
;;
|
||||
|
||||
.)
|
||||
;;
|
||||
|
||||
*)
|
||||
NGX_PERL_MODULES=$NGX_PREFIX/$NGX_PERL_MODULES
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,116 @@
|
|||
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
|
||||
|
||||
echo "checking for $NGX_SYSTEM specific features"
|
||||
|
||||
case "$NGX_PLATFORM" in
|
||||
|
||||
FreeBSD:*)
|
||||
. auto/os/freebsd
|
||||
;;
|
||||
|
||||
Linux:*)
|
||||
. auto/os/linux
|
||||
;;
|
||||
|
||||
SunOS:*)
|
||||
. auto/os/solaris
|
||||
;;
|
||||
|
||||
Darwin:*)
|
||||
. auto/os/darwin
|
||||
;;
|
||||
|
||||
win32)
|
||||
. auto/os/win32
|
||||
;;
|
||||
|
||||
DragonFly:*)
|
||||
have=NGX_FREEBSD . auto/have_headers
|
||||
CORE_INCS="$UNIX_INCS"
|
||||
CORE_DEPS="$UNIX_DEPS $FREEBSD_DEPS"
|
||||
CORE_SRCS="$UNIX_SRCS $FREEBSD_SRCS"
|
||||
|
||||
echo " + sendfile() found"
|
||||
have=NGX_HAVE_SENDFILE . auto/have
|
||||
CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS"
|
||||
|
||||
ngx_spacer='
|
||||
'
|
||||
;;
|
||||
|
||||
HP-UX:*)
|
||||
# HP/UX
|
||||
have=NGX_HPUX . auto/have_headers
|
||||
CORE_INCS="$UNIX_INCS"
|
||||
CORE_DEPS="$UNIX_DEPS $POSIX_DEPS"
|
||||
CORE_SRCS="$UNIX_SRCS"
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS -D_HPUX_ALT_XOPEN_SOCKET_API"
|
||||
;;
|
||||
|
||||
OSF1:*)
|
||||
# Tru64 UNIX
|
||||
have=NGX_TRU64 . auto/have_headers
|
||||
have=NGX_HAVE_STRERROR_R . auto/nohave
|
||||
CORE_INCS="$UNIX_INCS"
|
||||
CORE_DEPS="$UNIX_DEPS $POSIX_DEPS"
|
||||
CORE_SRCS="$UNIX_SRCS"
|
||||
;;
|
||||
|
||||
GNU:*)
|
||||
# GNU Hurd
|
||||
have=NGX_GNU_HURD . auto/have_headers
|
||||
CORE_INCS="$UNIX_INCS"
|
||||
CORE_DEPS="$UNIX_DEPS $POSIX_DEPS"
|
||||
CORE_SRCS="$UNIX_SRCS"
|
||||
CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
|
||||
;;
|
||||
|
||||
*)
|
||||
CORE_INCS="$UNIX_INCS"
|
||||
CORE_DEPS="$UNIX_DEPS $POSIX_DEPS"
|
||||
CORE_SRCS="$UNIX_SRCS"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
|
||||
case "$NGX_MACHINE" in
|
||||
|
||||
i386 | i686 | i86pc)
|
||||
have=NGX_HAVE_NONALIGNED . auto/have
|
||||
NGX_MACH_CACHE_LINE=32
|
||||
;;
|
||||
|
||||
amd64 | x86_64)
|
||||
have=NGX_HAVE_NONALIGNED . auto/have
|
||||
NGX_MACH_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
sun4u | sun4v | sparc | sparc64)
|
||||
have=NGX_ALIGNMENT value=16 . auto/define
|
||||
# TODO
|
||||
NGX_MACH_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
ia64 )
|
||||
have=NGX_ALIGNMENT value=16 . auto/define
|
||||
# TODO
|
||||
NGX_MACH_CACHE_LINE=64
|
||||
;;
|
||||
|
||||
*)
|
||||
have=NGX_ALIGNMENT value=16 . auto/define
|
||||
NGX_MACH_CACHE_LINE=32
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
if test -z "$NGX_CPU_CACHE_LINE"; then
|
||||
NGX_CPU_CACHE_LINE=$NGX_MACH_CACHE_LINE
|
||||
fi
|
||||
|
||||
have=NGX_CPU_CACHE_LINE value=$NGX_CPU_CACHE_LINE . auto/define
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue