enc tryouts

This commit is contained in:
Marcos Pinto 2007-05-29 08:39:30 +00:00
parent 5e90d29f58
commit 49c29562f9
361 changed files with 109387 additions and 0 deletions

340
encryption/LICENSE Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
GNU GENERAL PUBLIC LICENSE
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.

11
encryption/MANIFEST.in Normal file
View File

@ -0,0 +1,11 @@
include LICENSE
include README
include Makefile
include deluge.desktop
include deluge.xpm
include msgfmt.py
recursive-include libtorrent/ *
recursive-include glade/ *.glade
recursive-include pixmaps/ *.png
recursive-include plugins/ *
recursive-include po/ *

15
encryption/Makefile Normal file
View File

@ -0,0 +1,15 @@
#
# Makefile for Deluge
#
PREFIX = /usr
all:
python setup.py build
install:
python setup.py install --prefix=$(PREFIX)
clean:
python setup.py clean; rm -rf ./build

57
encryption/README Normal file
View File

@ -0,0 +1,57 @@
Deluge BitTorrent Client
Authors:
Zach Tibbitts, aka zachtib
Alon Zakai, aka kripkenstein
Homepage: http://deluge-torrent.org
==========================
Installation Instructions:
==========================
First, make sure you have the proper bulid
dependencies installed. On a normal Debian
or Ubuntu system, those dependencies are:
python-all-dev
python-all
python-support
libboost-dev
libboost-thread-dev
libboost-date-time-dev
libboost-filesystem-dev
libboost-serialization-dev
libboost-program-options-dev
libboost-regex-dev
zlib1g-dev
But the names of the packages may vary
depending on your OS / distro.
Once you have the needed libraries installed,
build Deluge by running:
python setup.py build
You shouldn't get any errors. Then run, as
root (or by using sudo):
python setup.py install
and Deluge will be installed.
You can then run Deluge by executing:
deluge
Notes:
1) On some distributions, boost libraries are
renamed to have "-mt" at the end (boost_thread_mt
instead of boost_thread, for example), the "mt"
indicating "multithreaded". In some cases it
appears the distros lack symlinks to connect
things. The solution is to either add symlinks
from the short names to those with "-mt", or to
alter setup.py to look for the "-mt" versions.

12
encryption/deluge.desktop Normal file
View File

@ -0,0 +1,12 @@
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=Deluge BitTorrent Client
Comment=Bittorrent client written in Python/PyGTK
Exec=deluge
Icon=deluge.xpm
Terminal=false
Type=Application
Categories=Application;Network
StartupNotify=true
MimeType=application/x-bittorrent;

415
encryption/deluge.xpm Normal file
View File

@ -0,0 +1,415 @@
/* XPM */
static char * deluge_torrent_xpm[] = {
"32 32 380 2",
" c None",
". c #8893A8",
"+ c #8994A8",
"@ c #B0B7C5",
"# c #919BAE",
"$ c #737F98",
"% c #A3ABBB",
"& c #8E98AD",
"* c #AEB5C4",
"= c #858FA5",
"- c #5E6D89",
"; c #929CB0",
"> c #8794A9",
", c #8592AA",
"' c #919FB5",
") c #A5B0C3",
"! c #7688A4",
"~ c #7687A1",
"{ c #8A99B1",
"] c #768AA7",
"^ c #7E92AE",
"/ c #8397B3",
"( c #92A4BD",
"_ c #96A8C0",
": c #5B7295",
"< c #8B9DB7",
"[ c #6A83A4",
"} c #728BAD",
"| c #7791B3",
"1 c #7B95B6",
"2 c #7C96B8",
"3 c #95ABC6",
"4 c #829CBC",
"5 c #45618C",
"6 c #7F96B3",
"7 c #6483A9",
"8 c #6384AC",
"9 c #6B8BB3",
"0 c #7091B8",
"a c #7495BC",
"b c #7596BD",
"c c #7496BD",
"d c #95AECC",
"e c #6F91B9",
"f c #6081A9",
"g c #3C6292",
"h c #365989",
"i c #4B6B97",
"j c #5676A1",
"k c #5F81AB",
"l c #6E93BF",
"m c #7097C2",
"n c #7297C3",
"o c #8FADCE",
"p c #618AB7",
"q c #476D9D",
"r c #5A779F",
"s c #1B4075",
"t c #1F4377",
"u c #365785",
"v c #4A6791",
"w c #4D6B94",
"x c #5D80AA",
"y c #6C93BF",
"z c #779DC6",
"A c #84A6CB",
"B c #5382B6",
"C c #3A659A",
"D c #5C789F",
"E c #224579",
"F c #1E4277",
"G c #274A7C",
"H c #2E4F7F",
"I c #335483",
"J c #44628D",
"K c #557197",
"L c #526E95",
"M c #506F99",
"N c #668FBD",
"O c #7FA3CA",
"P c #7299C4",
"Q c #36639A",
"R c #4F6D97",
"S c #345484",
"T c #305181",
"U c #42618A",
"V c #4E6992",
"W c #4A678F",
"X c #4B6992",
"Y c #4B6994",
"Z c #5F7A9E",
"` c #5E779C",
" . c #597398",
".. c #527099",
"+. c #618ABA",
"@. c #84A6CD",
"#. c #5D89BB",
"$. c #375A89",
"%. c #4C6992",
"&. c #3A5986",
"*. c #536E94",
"=. c #577197",
"-. c #6F92BB",
";. c #759ECA",
">. c #739CCA",
",. c #759DC9",
"'. c #6880A4",
"). c #5C7699",
"!. c #4F6F98",
"~. c #618DBD",
"{. c #81A4CA",
"]. c #4B7CB3",
"^. c #274F84",
"/. c #5A759B",
"(. c #375784",
"_. c #577196",
":. c #5A7498",
"<. c #6F89AB",
"[. c #8BADD1",
"}. c #7EA5D0",
"|. c #7FA6D0",
"1. c #7CA4CF",
"2. c #7CA4CE",
"3. c #789FC7",
"4. c #6984A7",
"5. c #5A7398",
"6. c #5076A5",
"7. c #6791C0",
"8. c #7198C3",
"9. c #2D5081",
"0. c #25477A",
"a. c #4C6890",
"b. c #627A9D",
"c. c #657DA1",
"d. c #A0BBD7",
"e. c #89AED6",
"f. c #8BAFD7",
"g. c #8BB0D7",
"h. c #8AAED6",
"i. c #86ACD4",
"j. c #82A8D2",
"k. c #7CA3CF",
"l. c #749DC8",
"m. c #6984A6",
"n. c #567298",
"o. c #5786BA",
"p. c #779CC6",
"q. c #5583B7",
"r. c #295086",
"s. c #2C4E7F",
"t. c #345483",
"u. c #5B7498",
"v. c #5D7699",
"w. c #93AAC4",
"x. c #9EBDDD",
"y. c #96B8DD",
"z. c #97B9DE",
"A. c #94B7DC",
"B. c #90B3DA",
"C. c #8AAFD6",
"D. c #83A9D2",
"E. c #7AA2CE",
"F. c #6F95BF",
"G. c #667E9F",
"H. c #577FAF",
"I. c #5585B8",
"J. c #759AC5",
"K. c #3F6FA7",
"L. c #254A80",
"M. c #5C769C",
"N. c #3C5B87",
"O. c #60789C",
"P. c #B0C3D8",
"Q. c #A1C0E3",
"R. c #A3C2E4",
"S. c #A3C3E5",
"T. c #A2C2E4",
"U. c #9EBFE2",
"V. c #98BADE",
"W. c #91B4DA",
"X. c #88AED6",
"Y. c #759ECB",
"Z. c #6885AD",
"`. c #5780B0",
" + c #5383B8",
".+ c #7299C3",
"++ c #4675AB",
"@+ c #395A89",
"#+ c #46648F",
"$+ c #3E5D88",
"%+ c #617A9C",
"&+ c #637B9D",
"*+ c #BFD1E4",
"=+ c #ADCBEA",
"-+ c #B0CDEB",
";+ c #AFCCEB",
">+ c #ACCAE9",
",+ c #A7C6E6",
"'+ c #9FC0E2",
")+ c #8DB1D8",
"!+ c #82A9D2",
"~+ c #77A0CC",
"{+ c #6A94C4",
"]+ c #5F8DBF",
"^+ c #5C89BA",
"/+ c #5C85B4",
"(+ c #3F5E8B",
"_+ c #3B5A86",
":+ c #647C9E",
"<+ c #61799D",
"[+ c #C1D2E4",
"}+ c #BBD5F1",
"|+ c #BCD6F2",
"1+ c #BAD5F1",
"2+ c #B5D1EE",
"3+ c #AECBEA",
"4+ c #A5C4E5",
"5+ c #9BBCE0",
"6+ c #84AAD3",
"7+ c #78A0CC",
"8+ c #6B96C6",
"9+ c #5F8CBF",
"0+ c #5282B8",
"a+ c #4F7FB4",
"b+ c #668CB7",
"c+ c #43618D",
"d+ c #325382",
"e+ c #5E779B",
"f+ c #5F789A",
"g+ c #BACADC",
"h+ c #C9E0F9",
"i+ c #C7DFF8",
"j+ c #C3DCF6",
"k+ c #BCD7F2",
"l+ c #B3CFED",
"m+ c #A8C7E7",
"n+ c #9DBEE1",
"o+ c #6A96C5",
"p+ c #5D8BBE",
"q+ c #5081B7",
"r+ c #497BB2",
"s+ c #698DB7",
"t+ c #45638E",
"u+ c #2E5080",
"v+ c #25487B",
"w+ c #506B93",
"x+ c #647B9E",
"y+ c #9DAFC7",
"z+ c #D6E9FD",
"A+ c #D1E8FE",
"B+ c #CAE2FA",
"C+ c #C1DAF5",
"D+ c #A9C8E8",
"E+ c #6894C4",
"F+ c #5A89BC",
"G+ c #4D7EB5",
"H+ c #4577AF",
"I+ c #6B8DB5",
"J+ c #3B6090",
"K+ c #3D5D8A",
"L+ c #3C5B89",
"M+ c #1D4276",
"N+ c #647C9C",
"O+ c #657D9E",
"P+ c #C2D4E6",
"Q+ c #D3E9FF",
"R+ c #CEE5FC",
"S+ c #C2DBF5",
"T+ c #80A7D1",
"U+ c #729CC9",
"V+ c #6491C2",
"W+ c #5686BA",
"X+ c #497BB3",
"Y+ c #5580B3",
"Z+ c #5B7EAA",
"`+ c #335686",
" @ c #4D6993",
".@ c #26497B",
"+@ c #4C6990",
"@@ c #6B82A2",
"#@ c #7D92B0",
"$@ c #C1D4E9",
"%@ c #C0DAF4",
"&@ c #B2CFED",
"*@ c #7BA3CE",
"=@ c #6F99C7",
"-@ c #6390C0",
";@ c #5886B9",
">@ c #4A7BB2",
",@ c #698CB7",
"'@ c #4C6F9C",
")@ c #284C7F",
"!@ c #577299",
"~@ c #2F517F",
"{@ c #536E93",
"]@ c #7086A5",
"^@ c #7B8FAC",
"/@ c #9FB3CD",
"(@ c #B8D2EE",
"_@ c #91B5DB",
":@ c #85ABD4",
"<@ c #7CA3CD",
"[@ c #729AC8",
"}@ c #6791C1",
"|@ c #5A87BA",
"1@ c #5280B4",
"2@ c #7A97BB",
"3@ c #416290",
"4@ c #2F5080",
"5@ c #4F6B91",
"6@ c #687F9F",
"7@ c #7B8FAB",
"8@ c #8396B0",
"9@ c #8AA1BF",
"0@ c #8CACCE",
"a@ c #8FB2D8",
"b@ c #86AAD2",
"c@ c #7DA3CC",
"d@ c #749BC7",
"e@ c #6993C1",
"f@ c #5B88B9",
"g@ c #7999C0",
"h@ c #587AA5",
"i@ c #21416E",
"j@ c #516D96",
"k@ c #415F8A",
"l@ c #567196",
"m@ c #637B9E",
"n@ c #6F84A3",
"o@ c #778BA7",
"p@ c #758BAA",
"q@ c #7490B3",
"r@ c #749BC5",
"s@ c #6992C0",
"t@ c #799DC4",
"u@ c #7291B6",
"v@ c #46658C",
"w@ c #264878",
"x@ c #4F6C94",
"y@ c #42608C",
"z@ c #294B7D",
"A@ c #4A6790",
"B@ c #567095",
"C@ c #597599",
"D@ c #587398",
"E@ c #536F96",
"F@ c #4F6D95",
"G@ c #7690B4",
"H@ c #7090B7",
"I@ c #4A6991",
"J@ c #2B4871",
"K@ c #41608C",
"L@ c #59749A",
"M@ c #234679",
"N@ c #214578",
"O@ c #3A5A87",
"P@ c #47648F",
"Q@ c #667EA2",
"R@ c #7188A9",
"S@ c #4B6892",
"T@ c #395985",
"U@ c #1C314F",
"V@ c #2E4F7D",
"W@ c #395986",
"X@ c #526E96",
"Y@ c #58739A",
"Z@ c #5B759B",
"`@ c #6A82A5",
" # c #627CA0",
".# c #365887",
"+# c #324B69",
"@# c #344B69",
"## c #34537D",
"$# c #294C7C",
"%# c #315383",
"&# c #40618D",
"*# c #40638F",
"=# c #3B5C87",
"-# c #36537A",
";# c #2E4156",
" ",
" . ",
" + @ # ",
" $ % & * = ",
" - ; > , ' ) ! ",
" ~ { ] ^ / ( _ ",
" : < [ } | 1 2 3 4 ",
" 5 6 7 8 9 0 a b c d e ",
" 7 f g h i j k l m n o p ",
" q r s s s t u v w x y z A B ",
" C D E s F G H I J K L M N O P ",
" Q R S s T U V W X Y Z ` ...+.@.#. ",
" $.%.t &.*.=.r -.;.>.,.0 '.).!.~.{.]. ",
" ^./.F (._.:.<.[.}.|.}.1.2.3.4.5.6.7.8. ",
" 9.v 0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q. ",
" r.v s.t.u.v.w.x.y.z.z.A.B.C.D.E.F.G.H.I.J.K. ",
" L.M.s N.b.O.P.Q.R.S.T.U.V.W.X.|.Y.Z.`. +.+++ ",
" @+#+s $+%+&+*+=+-+;+>+,+'+z.)+!+~+{+]+ +^+/+ ",
" (+S s _+:+<+[+}+|+1+2+3+4+5+B.6+7+8+9+0+a+b+ ",
" c+T s d+e+f+g+h+i+j+k+l+m+n+W.6+~+o+p+q+r+s+ ",
" t+u+s v+w+x+y+z+A+B+C+2+D+n+B.D.Y.E+F+G+H+I+J+ ",
" K+L+s M+N.N+O+P+Q+R+S+2+m+5+)+T+U+V+W+X+Y+Z+ ",
" `+ @s s .@+@@@#@$@R+%@&@4+z.e.*@=@-@;@>@,@'@ ",
" )@!@t s s ~@{@]@^@/@(@=+'+_@:@<@[@}@|@1@2@3@ ",
" S #+s s s 4@5@6@7@8@9@0@a@b@c@d@e@f@g@h@ ",
" i@j@u s s s G k@l@m@n@o@p@q@a r@s@t@u@v@ ",
" w@x@y@s s s s z@_+A@B@C@D@E@F@G@H@I@ ",
" J@K@L@y@M@s s N@z@S O@P@Q@R@S@T@ ",
" U@V@W@X@L@Y@Z@L@c.`@ #v .#+# ",
" @###$#%#&#*#=#-#;# ",
" ",
" "};

2
encryption/gettextize.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
xgettext -f po/POTFILES.in -o po/deluge.pot

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.1.5 on Thu Feb 22 19:13:48 2007 by zach@notapowerbook-->
<glade-interface>
<widget class="GtkAboutDialog" id="aboutdialog">
<property name="border_width">5</property>
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="has_separator">False</property>
<property name="website"></property>
<property name="authors"></property>
<property name="documenters"></property>
<property name="artists"></property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="spacing">2</property>
<child>
<placeholder/>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.1.5 on Thu Feb 22 19:15:41 2007 by zach@notapowerbook-->
<glade-interface>
<widget class="GtkMenu" id="torrent_popup">
<property name="visible">True</property>
<child>
<widget class="GtkCheckMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="label" translatable="yes">Size</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="size_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="label" translatable="yes">Status</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="status_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem3">
<property name="visible">True</property>
<property name="label" translatable="yes">Seeders</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="seeders_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem4">
<property name="visible">True</property>
<property name="label" translatable="yes">Peers</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="peers_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem5">
<property name="visible">True</property>
<property name="label" translatable="yes">Download Speed</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="dl_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem6">
<property name="visible">True</property>
<property name="label" translatable="yes">Upload Speed</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="ul_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem7">
<property name="visible">True</property>
<property name="label" translatable="yes">Time Remaining</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="eta_toggle"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="menuitem8">
<property name="visible">True</property>
<property name="label" translatable="yes">Share Ratio</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="share_toggle"/>
</widget>
</child>
</widget>
<widget class="GtkDialog" id="remove_torrent_dlg">
<property name="title" translatable="yes">Remove Torrent</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox3">
<property name="visible">True</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Are you sure you want to remove the selected torrent(s) from Deluge?&lt;/b&gt;</property>
<property name="use_markup">True</property>
</widget>
<packing>
<property name="padding">10</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="data_also">
<property name="visible">True</property>
<property name="label" translatable="yes">Delete downloaded files</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="warning">
<property name="visible">True</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area3">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="button2">
<property name="visible">True</property>
<property name="label">gtk-no</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="label">gtk-yes</property>
<property name="use_stock">True</property>
<property name="response_id">1</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkMenu" id="tray_menu">
<property name="visible">True</property>
<child>
<widget class="GtkMenuItem" id="menuitem10">
<property name="visible">True</property>
<property name="label" translatable="yes">Show/Hide</property>
<property name="use_underline">True</property>
<signal name="activate" handler="show_hide_window"/>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem9">
<property name="visible">True</property>
<property name="label" translatable="yes">Add a Torrent...</property>
<property name="use_underline">True</property>
<signal name="activate" handler="add_torrent"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image1">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-add</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem11">
<property name="visible">True</property>
<property name="label" translatable="yes">Clear Finished</property>
<property name="use_underline">True</property>
<signal name="activate" handler="clear_finished"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-clear</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separatormenuitem2">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem12">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-preferences</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="preferences"/>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem13">
<property name="visible">True</property>
<property name="label" translatable="yes">Plugins</property>
<property name="use_underline">True</property>
<signal name="activate" handler="plugins"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image3">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-execute</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem14">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-quit</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="quit"/>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<glade-interface>
<widget class="GtkDialog" id="plugin_dialog">
<property name="width_request">480</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Plugin Manager</property>
<property name="default_width">583</property>
<property name="default_height">431</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property>
<property name="spacing">2</property>
<child>
<widget class="GtkNotebook" id="pref_notebook1">
<property name="visible">True</property>
<property name="show_tabs">False</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="homogeneous">True</property>
<child>
<widget class="GtkTreeView" id="plugin_view">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<child>
<widget class="GtkTextView" id="plugin_text">
<property name="visible">True</property>
<property name="editable">False</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
<property name="cursor_visible">False</property>
</widget>
<packing>
<property name="padding">10</property>
</packing>
</child>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox2">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
<child>
<widget class="GtkButton" id="plugin_conf">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="label" translatable="yes">gtk-preferences</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="plugin_pref"/>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">10</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="tab_expand">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label34">
<property name="visible">True</property>
<property name="label" translatable="yes">Plugins</property>
</widget>
<packing>
<property name="type">tab</property>
<property name="tab_expand">False</property>
<property name="tab_fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="button10">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-close</property>
<property name="use_stock">True</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<glade-interface>
<widget class="GtkMenu" id="torrent_menu">
<property name="visible">True</property>
<child>
<widget class="GtkImageMenuItem" id="menu_pause">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">StartPause</property>
<property name="use_underline">True</property>
<signal name="activate" handler="start_pause"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image9">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-missing-image</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem5">
<property name="visible">True</property>
<property name="label" translatable="yes">Update Tracker</property>
<property name="use_underline">True</property>
<signal name="activate" handler="update_tracker"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image5">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-refresh</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Queue</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu1">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImageMenuItem" id="menuitem1">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Top</property>
<property name="use_underline">True</property>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image10">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-goto-top</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem6">
<property name="visible">True</property>
<property name="label" translatable="yes">Up</property>
<property name="use_underline">True</property>
<signal name="activate" handler="queue_up"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image6">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-go-up</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem7">
<property name="visible">True</property>
<property name="label" translatable="yes">Down</property>
<property name="use_underline">True</property>
<signal name="activate" handler="queue_down"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image7">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-go-down</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem8">
<property name="visible">True</property>
<property name="label" translatable="yes">Bottom</property>
<property name="use_underline">True</property>
<signal name="activate" handler="queue_bottom"/>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image8">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-goto-bottom</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image11">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-sort-ascending</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem3">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Upload</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu2">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkMenuItem" id="menuitem9">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">menuitem9</property>
<property name="use_underline">True</property>
</widget>
</child>
</widget>
</child>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image12">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-go-up</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="menuitem4">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Download</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="menu3">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkMenuItem" id="menuitem11">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">menuitem11</property>
<property name="use_underline">True</property>
</widget>
</child>
</widget>
</child>
<child internal-child="image">
<widget class="GtkImage" id="menu-item-image13">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="stock">gtk-go-down</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -0,0 +1,164 @@
/*
Copyright (c) 2003, Arvid Norberg, Daniel Wallin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of the author 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 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.
*/
#ifndef TORRENT_ALERT_HPP_INCLUDED
#define TORRENT_ALERT_HPP_INCLUDED
#include <memory>
#include <queue>
#include <string>
#include <cassert>
#include <typeinfo>
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/thread/mutex.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "libtorrent/time.hpp"
#include "libtorrent/config.hpp"
#ifndef TORRENT_MAX_ALERT_TYPES
#define TORRENT_MAX_ALERT_TYPES 15
#endif
namespace libtorrent {
class TORRENT_EXPORT alert
{
public:
enum severity_t { debug, info, warning, critical, fatal, none };
alert(severity_t severity, const std::string& msg);
virtual ~alert();
// a timestamp is automatically created in the constructor
ptime timestamp() const;
std::string const& msg() const;
severity_t severity() const;
virtual std::auto_ptr<alert> clone() const = 0;
private:
std::string m_msg;
severity_t m_severity;
ptime m_timestamp;
};
class TORRENT_EXPORT alert_manager
{
public:
alert_manager();
~alert_manager();
void post_alert(const alert& alert_);
bool pending() const;
std::auto_ptr<alert> get();
void set_severity(alert::severity_t severity);
bool should_post(alert::severity_t severity) const;
private:
std::queue<alert*> m_alerts;
alert::severity_t m_severity;
mutable boost::mutex m_mutex;
};
struct TORRENT_EXPORT unhandled_alert : std::exception
{
unhandled_alert() {}
};
namespace detail {
struct void_;
template<class Handler
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)>
void handle_alert_dispatch(
const std::auto_ptr<alert>& alert_, const Handler& handler
, const std::type_info& typeid_
, BOOST_PP_ENUM_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
{
if (typeid_ == typeid(T0))
handler(*static_cast<T0*>(alert_.get()));
else
handle_alert_dispatch(alert_, handler, typeid_
, BOOST_PP_ENUM_SHIFTED_PARAMS(
TORRENT_MAX_ALERT_TYPES, p), (void_*)0);
}
template<class Handler>
void handle_alert_dispatch(
const std::auto_ptr<alert>& alert_
, const Handler& handler
, const std::type_info& typeid_
, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
{
throw unhandled_alert();
}
} // namespace detail
template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
TORRENT_MAX_ALERT_TYPES, class T, detail::void_)>
struct TORRENT_EXPORT handle_alert
{
template<class Handler>
handle_alert(const std::auto_ptr<alert>& alert_
, const Handler& handler)
{
#define ALERT_POINTER_TYPE(z, n, text) (BOOST_PP_CAT(T, n)*)0
detail::handle_alert_dispatch(alert_, handler, typeid(*alert_)
, BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _));
#undef ALERT_POINTER_TYPE
}
};
} // namespace libtorrent
#endif // TORRENT_ALERT_HPP_INCLUDED

View File

@ -0,0 +1,300 @@
/*
Copyright (c) 2003, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of the author 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 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.
*/
#ifndef TORRENT_ALERT_TYPES_HPP_INCLUDED
#define TORRENT_ALERT_TYPES_HPP_INCLUDED
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/config.hpp"
namespace libtorrent
{
struct TORRENT_EXPORT torrent_alert: alert
{
torrent_alert(torrent_handle const& h, alert::severity_t s
, std::string const& msg)
: alert(s, msg)
, handle(h)
{}
torrent_handle handle;
};
struct TORRENT_EXPORT tracker_alert: torrent_alert
{
tracker_alert(torrent_handle const& h
, int times
, int status
, std::string const& msg)
: torrent_alert(h, alert::warning, msg)
, times_in_row(times)
, status_code(status)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new tracker_alert(*this)); }
int times_in_row;
int status_code;
};
struct TORRENT_EXPORT tracker_warning_alert: torrent_alert
{
tracker_warning_alert(torrent_handle const& h
, std::string const& msg)
: torrent_alert(h, alert::warning, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new tracker_warning_alert(*this)); }
};
struct TORRENT_EXPORT tracker_reply_alert: torrent_alert
{
tracker_reply_alert(torrent_handle const& h
, int np
, std::string const& msg)
: torrent_alert(h, alert::info, msg)
, num_peers(np)
{}
int num_peers;
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new tracker_reply_alert(*this)); }
};
struct TORRENT_EXPORT tracker_announce_alert: torrent_alert
{
tracker_announce_alert(torrent_handle const& h, std::string const& msg)
: torrent_alert(h, alert::info, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new tracker_announce_alert(*this)); }
};
struct TORRENT_EXPORT hash_failed_alert: torrent_alert
{
hash_failed_alert(
torrent_handle const& h
, int index
, std::string const& msg)
: torrent_alert(h, alert::info, msg)
, piece_index(index)
{ assert(index >= 0);}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new hash_failed_alert(*this)); }
int piece_index;
};
struct TORRENT_EXPORT peer_ban_alert: torrent_alert
{
peer_ban_alert(tcp::endpoint const& pip, torrent_handle h, std::string const& msg)
: torrent_alert(h, alert::info, msg)
, ip(pip)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new peer_ban_alert(*this)); }
tcp::endpoint ip;
};
struct TORRENT_EXPORT peer_error_alert: alert
{
peer_error_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg)
: alert(alert::debug, msg)
, ip(pip)
, pid(pid_)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new peer_error_alert(*this)); }
tcp::endpoint ip;
peer_id pid;
};
struct TORRENT_EXPORT invalid_request_alert: torrent_alert
{
invalid_request_alert(
peer_request const& r
, torrent_handle const& h
, tcp::endpoint const& sender
, peer_id const& pid_
, std::string const& msg)
: torrent_alert(h, alert::debug, msg)
, ip(sender)
, request(r)
, pid(pid_)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new invalid_request_alert(*this)); }
tcp::endpoint ip;
peer_request request;
peer_id pid;
};
struct TORRENT_EXPORT torrent_finished_alert: torrent_alert
{
torrent_finished_alert(
const torrent_handle& h
, const std::string& msg)
: torrent_alert(h, alert::warning, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new torrent_finished_alert(*this)); }
};
struct TORRENT_EXPORT url_seed_alert: torrent_alert
{
url_seed_alert(
torrent_handle const& h
, const std::string& url_
, const std::string& msg)
: torrent_alert(h, alert::warning, msg)
, url(url_)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new url_seed_alert(*this)); }
std::string url;
};
struct TORRENT_EXPORT file_error_alert: torrent_alert
{
file_error_alert(
const torrent_handle& h
, const std::string& msg)
: torrent_alert(h, alert::fatal, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new file_error_alert(*this)); }
};
struct TORRENT_EXPORT metadata_failed_alert: torrent_alert
{
metadata_failed_alert(
const torrent_handle& h
, const std::string& msg)
: torrent_alert(h, alert::info, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new metadata_failed_alert(*this)); }
};
struct TORRENT_EXPORT metadata_received_alert: torrent_alert
{
metadata_received_alert(
const torrent_handle& h
, const std::string& msg)
: torrent_alert(h, alert::info, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new metadata_received_alert(*this)); }
};
struct TORRENT_EXPORT listen_failed_alert: alert
{
listen_failed_alert(
const std::string& msg)
: alert(alert::fatal, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new listen_failed_alert(*this)); }
};
struct TORRENT_EXPORT portmap_error_alert: alert
{
portmap_error_alert(const std::string& msg)
: alert(alert::warning, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new portmap_error_alert(*this)); }
};
struct TORRENT_EXPORT portmap_alert: alert
{
portmap_alert(const std::string& msg)
: alert(alert::info, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new portmap_alert(*this)); }
};
struct TORRENT_EXPORT fastresume_rejected_alert: torrent_alert
{
fastresume_rejected_alert(torrent_handle const& h
, std::string const& msg)
: torrent_alert(h, alert::warning, msg)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new fastresume_rejected_alert(*this)); }
};
struct TORRENT_EXPORT peer_blocked_alert: alert
{
peer_blocked_alert(address const& ip_
, std::string const& msg)
: alert(alert::info, msg)
, ip(ip_)
{}
address ip;
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new peer_blocked_alert(*this)); }
};
}
#endif

View File

@ -0,0 +1,78 @@
/*
Copyright (c) 2003, Magnus Jonsson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of the author 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 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.
*/
#ifndef TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED
#define TORRENT_ALLOCATE_RESOURCES_HPP_INCLUDED
#include <map>
#include <utility>
#include <boost/shared_ptr.hpp>
#include "libtorrent/resource_request.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/session.hpp"
namespace libtorrent
{
class peer_connection;
class torrent;
int saturated_add(int a, int b);
// Function to allocate a limited resource fairly among many consumers.
// It takes into account the current use, and the consumer's desired use.
// Should be invoked periodically to allow it adjust to the situation (make
// sure "used" is updated between calls!).
// If resources = std::numeric_limits<int>::max() it means there is an infinite
// supply of resources (so everyone can get what they want).
void allocate_resources(
int resources
, std::map<sha1_hash, boost::shared_ptr<torrent> >& torrents
, resource_request torrent::* res);
void allocate_resources(
int resources
, std::map<tcp::endpoint, peer_connection*>& connections
, resource_request peer_connection::* res);
// Used for global limits.
void allocate_resources(
int resources
, std::vector<session*>& _sessions
, resource_request session::* res);
}
#endif

View File

@ -0,0 +1,73 @@
//
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_HPP
#define ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/basic_datagram_socket.hpp"
#include "asio/basic_deadline_timer.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_socket_streambuf.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/basic_streambuf.hpp"
#include "asio/buffer.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/buffered_stream.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/completion_condition.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/deadline_timer.hpp"
#include "asio/error.hpp"
#include "asio/error_code.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/handler_invoke_hook.hpp"
#include "asio/io_service.hpp"
#include "asio/ip/address.hpp"
#include "asio/ip/address_v4.hpp"
#include "asio/ip/address_v6.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_entry.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/host_name.hpp"
#include "asio/ip/multicast.hpp"
#include "asio/ip/resolver_query_base.hpp"
#include "asio/ip/resolver_service.hpp"
#include "asio/ip/tcp.hpp"
#include "asio/ip/udp.hpp"
#include "asio/ip/unicast.hpp"
#include "asio/ip/v6_only.hpp"
#include "asio/is_read_buffered.hpp"
#include "asio/is_write_buffered.hpp"
#include "asio/placeholders.hpp"
#include "asio/read.hpp"
#include "asio/read_until.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/strand.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/streambuf.hpp"
#include "asio/system_error.hpp"
#include "asio/thread.hpp"
#include "asio/time_traits.hpp"
#include "asio/write.hpp"
#endif // ASIO_HPP

View File

@ -0,0 +1,803 @@
//
// basic_datagram_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_DATAGRAM_SOCKET_HPP
#define ASIO_BASIC_DATAGRAM_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides datagram-oriented socket functionality.
/**
* The basic_datagram_socket class template provides asynchronous and blocking
* datagram-oriented socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol,
typename DatagramSocketService = datagram_socket_service<Protocol> >
class basic_datagram_socket
: public basic_socket<Protocol, DatagramSocketService>
{
public:
/// The native representation of a socket.
typedef typename DatagramSocketService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_datagram_socket without opening it.
/**
* This constructor creates a datagram socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*/
explicit basic_datagram_socket(asio::io_service& io_service)
: basic_socket<Protocol, DatagramSocketService>(io_service)
{
}
/// Construct and open a basic_datagram_socket.
/**
* This constructor creates and opens a datagram socket.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_service& io_service,
const protocol_type& protocol)
: basic_socket<Protocol, DatagramSocketService>(io_service, protocol)
{
}
/// Construct a basic_datagram_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a datagram socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*
* @param endpoint An endpoint on the local machine to which the datagram
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_service& io_service,
const endpoint_type& endpoint)
: basic_socket<Protocol, DatagramSocketService>(io_service, endpoint)
{
}
/// Construct a basic_datagram_socket on an existing native socket.
/**
* This constructor creates a datagram socket object to hold an existing
* native socket.
*
* @param io_service The io_service object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_socket)
: basic_socket<Protocol, DatagramSocketService>(
io_service, protocol, native_socket)
{
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One ore more data buffers to be sent on the socket.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation can only be used with a connected socket. Use
* the send_to function to send data on an unconnected datagram socket.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code socket.send(asio::buffer(data, size)); @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One ore more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation can only be used with a connected socket. Use
* the send_to function to send data on an unconnected datagram socket.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.send(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent.
*
* @note The send operation can only be used with a connected socket. Use
* the send_to function to send data on an unconnected datagram socket.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.send(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous send on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
* socket.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous send on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
* call will block until the data has been sent successfully or an error
* occurs.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
* socket.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, flags, handler);
}
/// Send a datagram to the specified endpoint.
/**
* This function is used to send a datagram to the specified remote endpoint.
* The function call will block until the data has been sent successfully or
* an error occurs.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
*
* @param destination The remote endpoint to which the data will be sent.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* asio::ip::udp::endpoint destination(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.send_to(asio::buffer(data, size), destination);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination)
{
asio::error_code ec;
std::size_t s = this->service.send_to(
this->implementation, buffers, destination, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send a datagram to the specified endpoint.
/**
* This function is used to send a datagram to the specified remote endpoint.
* The function call will block until the data has been sent successfully or
* an error occurs.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
*
* @param destination The remote endpoint to which the data will be sent.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ConstBufferSequence>
std::size_t send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.send_to(
this->implementation, buffers, destination, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send a datagram to the specified endpoint.
/**
* This function is used to send a datagram to the specified remote endpoint.
* The function call will block until the data has been sent successfully or
* an error occurs.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
*
* @param destination The remote endpoint to which the data will be sent.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent.
*/
template <typename ConstBufferSequence>
std::size_t send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->service.send_to(this->implementation,
buffers, destination, flags, ec);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send a datagram to the specified
* remote endpoint. The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param destination The remote endpoint to which the data will be sent.
* Copies will be made of the endpoint as required.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* asio::ip::udp::endpoint destination(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.async_send_to(
* asio::buffer(data, size), destination, handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, WriteHandler handler)
{
this->service.async_send_to(this->implementation, buffers, destination, 0,
handler);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send a datagram to the specified
* remote endpoint. The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent to the remote endpoint.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param destination The remote endpoint to which the data will be sent.
* Copies will be made of the endpoint as required.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send_to(const ConstBufferSequence& buffers,
const endpoint_type& destination, socket_base::message_flags flags,
WriteHandler handler)
{
this->service.async_send_to(this->implementation, buffers, destination,
flags, handler);
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the datagram socket. The function
* call will block until data has been received successfully or an error
* occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*
* @note The receive operation can only be used with a connected socket. Use
* the receive_from function to receive data on an unconnected datagram
* socket.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code socket.receive(asio::buffer(data, size)); @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.receive(
this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the datagram socket. The function
* call will block until data has been received successfully or an error
* occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*
* @note The receive operation can only be used with a connected socket. Use
* the receive_from function to receive data on an unconnected datagram
* socket.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.receive(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the datagram socket. The function
* call will block until data has been received successfully or an error
* occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received.
*
* @note The receive operation can only be used with a connected socket. Use
* the receive_from function to receive data on an unconnected datagram
* socket.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.receive(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous receive on a connected socket.
/**
* This function is used to asynchronously receive data from the datagram
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
* datagram socket.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous receive on a connected socket.
/**
* This function is used to asynchronously receive data from the datagram
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
* datagram socket.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, flags, handler);
}
/// Receive a datagram with the endpoint of the sender.
/**
* This function is used to receive a datagram. The function call will block
* until data has been received successfully or an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* asio::ip::udp::endpoint sender_endpoint;
* socket.receive_from(
* asio::buffer(data, size), sender_endpoint);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint)
{
asio::error_code ec;
std::size_t s = this->service.receive_from(
this->implementation, buffers, sender_endpoint, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive a datagram with the endpoint of the sender.
/**
* This function is used to receive a datagram. The function call will block
* until data has been received successfully or an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename MutableBufferSequence>
std::size_t receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.receive_from(
this->implementation, buffers, sender_endpoint, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive a datagram with the endpoint of the sender.
/**
* This function is used to receive a datagram. The function call will block
* until data has been received successfully or an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received.
*/
template <typename MutableBufferSequence>
std::size_t receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->service.receive_from(this->implementation, buffers,
sender_endpoint, flags, ec);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive a datagram. The function
* call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram. Ownership of the sender_endpoint object
* is retained by the caller, which must guarantee that it is valid until the
* handler is called.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::system_error& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code socket.async_receive_from(
* asio::buffer(data, size), 0, sender_endpoint, handler); @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, ReadHandler handler)
{
this->service.async_receive_from(this->implementation, buffers,
sender_endpoint, 0, handler);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive a datagram. The function
* call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param sender_endpoint An endpoint object that receives the endpoint of
* the remote sender of the datagram. Ownership of the sender_endpoint object
* is retained by the caller, which must guarantee that it is valid until the
* handler is called.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive_from(const MutableBufferSequence& buffers,
endpoint_type& sender_endpoint, socket_base::message_flags flags,
ReadHandler handler)
{
this->service.async_receive_from(this->implementation, buffers,
sender_endpoint, flags, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP

View File

@ -0,0 +1,399 @@
//
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_DEADLINE_TIMER_HPP
#define ASIO_BASIC_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/error.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides waitable timer functionality.
/**
* The basic_deadline_timer class template provides the ability to perform a
* blocking or asynchronous wait for a timer to expire.
*
* Most applications will use the asio::deadline_timer typedef.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @sa @ref deadline_timer_reset
*
* @par Examples
* Performing a blocking wait:
* @code
* // Construct a timer without setting an expiry time.
* asio::deadline_timer timer(io_service);
*
* // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5));
*
* // Wait for the timer to expire.
* timer.wait();
* @endcode
*
* @par
* Performing an asynchronous wait:
* @code
* void handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Timer expired.
* }
* }
*
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::deadline_timer timer(io_service,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
*
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*/
template <typename Time,
typename TimeTraits = asio::time_traits<Time>,
typename TimerService = deadline_timer_service<Time, TimeTraits> >
class basic_deadline_timer
: public basic_io_object<TimerService>
{
public:
/// The time traits type.
typedef TimeTraits traits_type;
/// The time type.
typedef typename traits_type::time_type time_type;
/// The duration type.
typedef typename traits_type::duration_type duration_type;
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param io_service The io_service object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
*/
explicit basic_deadline_timer(asio::io_service& io_service)
: basic_io_object<TimerService>(io_service)
{
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_service The io_service object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_deadline_timer(asio::io_service& io_service,
const time_type& expiry_time)
: basic_io_object<TimerService>(io_service)
{
asio::error_code ec;
this->service.expires_at(this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_service The io_service object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_deadline_timer(asio::io_service& io_service,
const duration_type& expiry_time)
: basic_io_object<TimerService>(io_service)
{
asio::error_code ec;
this->service.expires_from_now(this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = this->service.cancel(this->implementation, ec);
asio::detail::throw_error(ec);
return s;
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*/
std::size_t cancel(asio::error_code& ec)
{
return this->service.cancel(this->implementation, ec);
}
/// Get the timer's expiry time as an absolute time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_type expires_at() const
{
return this->service.expires_at(this->implementation);
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t expires_at(const time_type& expiry_time)
{
asio::error_code ec;
std::size_t s = this->service.expires_at(
this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
return s;
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*/
std::size_t expires_at(const time_type& expiry_time,
asio::error_code& ec)
{
return this->service.expires_at(this->implementation, expiry_time, ec);
}
/// Get the timer's expiry time relative to now.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
duration_type expires_from_now() const
{
return this->service.expires_from_now(this->implementation);
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t expires_from_now(const duration_type& expiry_time)
{
asio::error_code ec;
std::size_t s = this->service.expires_from_now(
this->implementation, expiry_time, ec);
asio::detail::throw_error(ec);
return s;
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*/
std::size_t expires_from_now(const duration_type& expiry_time,
asio::error_code& ec)
{
return this->service.expires_from_now(
this->implementation, expiry_time, ec);
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @throws asio::system_error Thrown on failure.
*/
void wait()
{
asio::error_code ec;
this->service.wait(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @param ec Set to indicate what error occurred, if any.
*/
void wait(asio::error_code& ec)
{
this->service.wait(this->implementation, ec);
}
/// Start an asynchronous wait on the timer.
/**
* This function may be used to initiate an asynchronous wait against the
* timer. It always returns immediately.
*
* For each call to async_wait(), the supplied handler will be called exactly
* once. The handler will be called when:
*
* @li The timer has expired.
*
* @li The timer was cancelled, in which case the handler is passed the error
* code asio::error::operation_aborted.
*
* @param handler The handler to be called when the timer expires. Copies
* will be made of the handler as required. The function signature of the
* handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename WaitHandler>
void async_wait(WaitHandler handler)
{
this->service.async_wait(this->implementation, handler);
}
};
/**
* @page deadline_timer_reset Changing an active deadline_timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_from_now(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const asio::error_code& e)
* {
* if (e != asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The asio::basic_deadline_timer::expires_from_now() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*
* @sa asio::basic_deadline_timer
*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_DEADLINE_TIMER_HPP

View File

@ -0,0 +1,75 @@
//
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_IO_OBJECT_HPP
#define ASIO_BASIC_IO_OBJECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Base class for all I/O objects.
template <typename IoObjectService>
class basic_io_object
: private noncopyable
{
public:
/// The type of the service that will be used to provide I/O operations.
typedef IoObjectService service_type;
/// The underlying implementation type of I/O object.
typedef typename service_type::implementation_type implementation_type;
/// Get the io_service associated with the object.
/**
* This function may be used to obtain the io_service object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_service object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_service& io_service()
{
return service.io_service();
}
protected:
/// Construct a basic_io_object.
explicit basic_io_object(asio::io_service& io_service)
: service(asio::use_service<IoObjectService>(io_service))
{
service.construct(implementation);
}
/// Protected destructor to prevent deletion through this type.
~basic_io_object()
{
service.destroy(implementation);
}
// The backend service implementation.
service_type& service;
// The underlying native implementation.
implementation_type implementation;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_IO_OBJECT_HPP

View File

@ -0,0 +1,252 @@
//
// basic_resolver.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_RESOLVER_HPP
#define ASIO_BASIC_RESOLVER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/error_handler.hpp"
#include "asio/resolver_service.hpp"
namespace asio {
/// Provides endpoint resolution functionality.
/**
* The basic_resolver class template provides the ability to resolve a query
* to a list of endpoints.
*
* @par Thread Safety:
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* Async_Object, Error_Source.
*/
template <typename Protocol, typename Service = resolver_service<Protocol> >
class basic_resolver
: public basic_io_object<Service>
{
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The query type.
typedef typename Protocol::resolver_query query;
/// The iterator type.
typedef typename Protocol::resolver_iterator iterator;
/// The type used for reporting errors.
typedef asio::error error_type;
/// Constructor.
/**
* This constructor creates a basic_resolver.
*
* @param io_service The io_service object that the resolver will use to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_resolver(asio::io_service& io_service)
: basic_io_object<Service>(io_service)
{
}
/// Cancel any asynchronous operations that are waiting on the resolver.
/**
* This function forces the completion of any pending asynchronous
* operations on the host resolver. The handler for each cancelled operation
* will be invoked with the asio::error::operation_aborted error code.
*/
void cancel()
{
return this->service.cancel(this->implementation);
}
/// Resolve a query to a list of entries.
/**
* This function is used to resolve a query into a list of endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries.
*
* @throws asio::error Thrown on failure.
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
iterator resolve(const query& q)
{
return this->service.resolve(this->implementation, q, throw_error());
}
/// Resolve a query to a list of entries.
/**
* This function is used to resolve a query into a list of endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries. Returns a default constructed iterator if an error
* occurs.
*
* @param error_handler A handler to be called when the operation completes,
* to indicate whether or not an error has occurred. Copies will be made of
* the handler as required. The function signature of the handler must be:
* @code void error_handler(
* const asio::error& error // Result of operation.
* ); @endcode
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
template <typename Error_Handler>
iterator resolve(const query& q, Error_Handler error_handler)
{
return this->service.resolve(this->implementation, q, error_handler);
}
/// Asynchronously resolve a query to a list of entries.
/**
* This function is used to asynchronously resolve a query into a list of
* endpoint entries.
*
* @param q A query object that determines what endpoints will be returned.
*
* @param handler The handler to be called when the resolve operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error& error, // Result of operation.
* resolver::iterator iterator // Forward-only iterator that can be used to
* // traverse the list of endpoint entries.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful resolve operation is guaranteed to pass at least one
* entry to the handler.
*/
template <typename Handler>
void async_resolve(const query& q, Handler handler)
{
return this->service.async_resolve(this->implementation, q, handler);
}
/// Resolve an endpoint to a list of entries.
/**
* This function is used to resolve an endpoint into a list of endpoint
* entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries.
*
* @throws asio::error Thrown on failure.
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
iterator resolve(const endpoint_type& e)
{
return this->service.resolve(this->implementation, e, throw_error());
}
/// Resolve an endpoint to a list of entries.
/**
* This function is used to resolve an endpoint into a list of endpoint
* entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @returns A forward-only iterator that can be used to traverse the list
* of endpoint entries. Returns a default constructed iterator if an error
* occurs.
*
* @param error_handler A handler to be called when the operation completes,
* to indicate whether or not an error has occurred. Copies will be made of
* the handler as required. The function signature of the handler must be:
* @code void error_handler(
* const asio::error& error // Result of operation.
* ); @endcode
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful call to this function is guaranteed to return at least
* one entry.
*/
template <typename Error_Handler>
iterator resolve(const endpoint_type& e, Error_Handler error_handler)
{
return this->service.resolve(this->implementation, e, error_handler);
}
/// Asynchronously resolve an endpoint to a list of entries.
/**
* This function is used to asynchronously resolve an endpoint into a list of
* endpoint entries.
*
* @param e An endpoint object that determines what endpoints will be
* returned.
*
* @param handler The handler to be called when the resolve operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error& error, // Result of operation.
* resolver::iterator iterator // Forward-only iterator that can be used to
* // traverse the list of endpoint entries.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note A default constructed iterator represents the end of the list.
*
* @note A successful resolve operation is guaranteed to pass at least one
* entry to the handler.
*/
template <typename Handler>
void async_resolve(const endpoint_type& e, Handler handler)
{
return this->service.async_resolve(this->implementation, e, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_RESOLVER_HPP

View File

@ -0,0 +1,972 @@
//
// basic_socket.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SOCKET_HPP
#define ASIO_BASIC_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/error.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides socket functionality.
/**
* The basic_socket class template provides functionality that is common to both
* stream-oriented and datagram-oriented sockets.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol, typename SocketService>
class basic_socket
: public basic_io_object<SocketService>,
public socket_base
{
public:
/// The native representation of a socket.
typedef typename SocketService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// A basic_socket is always the lowest layer.
typedef basic_socket<Protocol, SocketService> lowest_layer_type;
/// Construct a basic_socket without opening it.
/**
* This constructor creates a socket without opening it.
*
* @param io_service The io_service object that the socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_socket(asio::io_service& io_service)
: basic_io_object<SocketService>(io_service)
{
}
/// Construct and open a basic_socket.
/**
* This constructor creates and opens a socket.
*
* @param io_service The io_service object that the socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket(asio::io_service& io_service,
const protocol_type& protocol)
: basic_io_object<SocketService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, protocol, ec);
asio::detail::throw_error(ec);
}
/// Construct a basic_socket, opening it and binding it to the given local
/// endpoint.
/**
* This constructor creates a socket and automatically opens it bound to the
* specified endpoint on the local machine. The protocol used is the protocol
* associated with the given endpoint.
*
* @param io_service The io_service object that the socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the socket will
* be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket(asio::io_service& io_service,
const endpoint_type& endpoint)
: basic_io_object<SocketService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, endpoint.protocol(), ec);
asio::detail::throw_error(ec);
this->service.bind(this->implementation, endpoint, ec);
asio::detail::throw_error(ec);
}
/// Construct a basic_socket on an existing native socket.
/**
* This constructor creates a socket object to hold an existing native socket.
*
* @param io_service The io_service object that the socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket A native socket.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_socket)
: basic_io_object<SocketService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, protocol, native_socket, ec);
asio::detail::throw_error(ec);
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_socket cannot contain any further layers, it simply
* returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Open the socket using the specified protocol.
/**
* This function opens the socket so that it will use the specified protocol.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* socket.open(asio::ip::tcp::v4());
* @endcode
*/
void open(const protocol_type& protocol = protocol_type())
{
asio::error_code ec;
this->service.open(this->implementation, protocol, ec);
asio::detail::throw_error(ec);
}
/// Open the socket using the specified protocol.
/**
* This function opens the socket so that it will use the specified protocol.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* asio::error_code ec;
* socket.open(asio::ip::tcp::v4(), ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code open(const protocol_type& protocol,
asio::error_code& ec)
{
return this->service.open(this->implementation, protocol, ec);
}
/// Assign an existing native socket to the socket.
/*
* This function opens the socket to hold an existing native socket.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param native_socket A native socket.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const protocol_type& protocol, const native_type& native_socket)
{
asio::error_code ec;
this->service.assign(this->implementation, protocol, native_socket, ec);
asio::detail::throw_error(ec);
}
/// Assign an existing native socket to the socket.
/*
* This function opens the socket to hold an existing native socket.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param native_socket A native socket.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const protocol_type& protocol,
const native_type& native_socket, asio::error_code& ec)
{
return this->service.assign(this->implementation,
protocol, native_socket, ec);
}
/// Determine whether the socket is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
}
/// Close the socket.
/**
* This function is used to close the socket. Any asynchronous send, receive
* or connect operations will be cancelled immediately, and will complete
* with the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
this->service.close(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Close the socket.
/**
* This function is used to close the socket. Any asynchronous send, receive
* or connect operations will be cancelled immediately, and will complete
* with the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::error_code ec;
* socket.close(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
}
/// Get the native socket representation.
/**
* This function may be used to obtain the underlying representation of the
* socket. This is intended to allow access to native socket functionality
* that is not otherwise provided.
*/
native_type native()
{
return this->service.native(this->implementation);
}
/// Cancel all asynchronous operations associated with the socket.
/**
* This function causes all outstanding asynchronous connect, send and receive
* operations to finish immediately, and the handlers for cancelled operations
* will be passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
this->service.cancel(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Cancel all asynchronous operations associated with the socket.
/**
* This function causes all outstanding asynchronous connect, send and receive
* operations to finish immediately, and the handlers for cancelled operations
* will be passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code cancel(asio::error_code& ec)
{
return this->service.cancel(this->implementation, ec);
}
/// Determine whether the socket is at the out-of-band data mark.
/**
* This function is used to check whether the socket input is currently
* positioned at the out-of-band data mark.
*
* @return A bool indicating whether the socket is at the out-of-band data
* mark.
*
* @throws asio::system_error Thrown on failure.
*/
bool at_mark() const
{
asio::error_code ec;
bool b = this->service.at_mark(this->implementation, ec);
asio::detail::throw_error(ec);
return b;
}
/// Determine whether the socket is at the out-of-band data mark.
/**
* This function is used to check whether the socket input is currently
* positioned at the out-of-band data mark.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return A bool indicating whether the socket is at the out-of-band data
* mark.
*/
bool at_mark(asio::error_code& ec) const
{
return this->service.at_mark(this->implementation, ec);
}
/// Determine the number of bytes available for reading.
/**
* This function is used to determine the number of bytes that may be read
* without blocking.
*
* @return The number of bytes that may be read without blocking, or 0 if an
* error occurs.
*
* @throws asio::system_error Thrown on failure.
*/
std::size_t available() const
{
asio::error_code ec;
std::size_t s = this->service.available(this->implementation, ec);
asio::detail::throw_error(ec);
return s;
}
/// Determine the number of bytes available for reading.
/**
* This function is used to determine the number of bytes that may be read
* without blocking.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of bytes that may be read without blocking, or 0 if an
* error occurs.
*/
std::size_t available(asio::error_code& ec) const
{
return this->service.available(this->implementation, ec);
}
/// Bind the socket to the given local endpoint.
/**
* This function binds the socket to the specified endpoint on the local
* machine.
*
* @param endpoint An endpoint on the local machine to which the socket will
* be bound.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* socket.open(asio::ip::tcp::v4());
* socket.bind(asio::ip::tcp::endpoint(
* asio::ip::tcp::v4(), 12345));
* @endcode
*/
void bind(const endpoint_type& endpoint)
{
asio::error_code ec;
this->service.bind(this->implementation, endpoint, ec);
asio::detail::throw_error(ec);
}
/// Bind the socket to the given local endpoint.
/**
* This function binds the socket to the specified endpoint on the local
* machine.
*
* @param endpoint An endpoint on the local machine to which the socket will
* be bound.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* socket.open(asio::ip::tcp::v4());
* asio::error_code ec;
* socket.bind(asio::ip::tcp::endpoint(
* asio::ip::tcp::v4(), 12345), ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code bind(const endpoint_type& endpoint,
asio::error_code& ec)
{
return this->service.bind(this->implementation, endpoint, ec);
}
/// Connect the socket to the specified endpoint.
/**
* This function is used to connect a socket to the specified remote endpoint.
* The function call will block until the connection is successfully made or
* an error occurs.
*
* The socket is automatically opened if it is not already open. If the
* connect fails, and the socket was automatically opened, the socket is
* returned to the closed state.
*
* @param peer_endpoint The remote endpoint to which the socket will be
* connected.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.connect(endpoint);
* @endcode
*/
void connect(const endpoint_type& peer_endpoint)
{
asio::error_code ec;
if (!is_open())
{
this->service.open(this->implementation, peer_endpoint.protocol(), ec);
asio::detail::throw_error(ec);
}
this->service.connect(this->implementation, peer_endpoint, ec);
asio::detail::throw_error(ec);
}
/// Connect the socket to the specified endpoint.
/**
* This function is used to connect a socket to the specified remote endpoint.
* The function call will block until the connection is successfully made or
* an error occurs.
*
* The socket is automatically opened if it is not already open. If the
* connect fails, and the socket was automatically opened, the socket is
* returned to the closed state.
*
* @param peer_endpoint The remote endpoint to which the socket will be
* connected.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* asio::error_code ec;
* socket.connect(endpoint, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code connect(const endpoint_type& peer_endpoint,
asio::error_code& ec)
{
if (!is_open())
{
if (this->service.open(this->implementation,
peer_endpoint.protocol(), ec))
{
return ec;
}
}
return this->service.connect(this->implementation, peer_endpoint, ec);
}
/// Start an asynchronous connect.
/**
* This function is used to asynchronously connect a socket to the specified
* remote endpoint. The function call always returns immediately.
*
* The socket is automatically opened if it is not already open. If the
* connect fails, and the socket was automatically opened, the socket is
* returned to the closed state.
*
* @param peer_endpoint The remote endpoint to which the socket will be
* connected. Copies will be made of the endpoint object as required.
*
* @param handler The handler to be called when the connection operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* @code
* void connect_handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Connect succeeded.
* }
* }
*
* ...
*
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint(
* asio::ip::address::from_string("1.2.3.4"), 12345);
* socket.async_connect(endpoint, connect_handler);
* @endcode
*/
template <typename ConnectHandler>
void async_connect(const endpoint_type& peer_endpoint, ConnectHandler handler)
{
if (!is_open())
{
asio::error_code ec;
if (this->service.open(this->implementation,
peer_endpoint.protocol(), ec))
{
this->io_service().post(asio::detail::bind_handler(handler, ec));
return;
}
}
this->service.async_connect(this->implementation, peer_endpoint, handler);
}
/// Set an option on the socket.
/**
* This function is used to set an option on the socket.
*
* @param option The new option value to be set on the socket.
*
* @throws asio::system_error Thrown on failure.
*
* @sa SettableSocketOption @n
* asio::socket_base::broadcast @n
* asio::socket_base::do_not_route @n
* asio::socket_base::keep_alive @n
* asio::socket_base::linger @n
* asio::socket_base::receive_buffer_size @n
* asio::socket_base::receive_low_watermark @n
* asio::socket_base::reuse_address @n
* asio::socket_base::send_buffer_size @n
* asio::socket_base::send_low_watermark @n
* asio::ip::multicast::join_group @n
* asio::ip::multicast::leave_group @n
* asio::ip::multicast::enable_loopback @n
* asio::ip::multicast::outbound_interface @n
* asio::ip::multicast::hops @n
* asio::ip::tcp::no_delay
*
* @par Example
* Setting the IPPROTO_TCP/TCP_NODELAY option:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::no_delay option(true);
* socket.set_option(option);
* @endcode
*/
template <typename SettableSocketOption>
void set_option(const SettableSocketOption& option)
{
asio::error_code ec;
this->service.set_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Set an option on the socket.
/**
* This function is used to set an option on the socket.
*
* @param option The new option value to be set on the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSocketOption @n
* asio::socket_base::broadcast @n
* asio::socket_base::do_not_route @n
* asio::socket_base::keep_alive @n
* asio::socket_base::linger @n
* asio::socket_base::receive_buffer_size @n
* asio::socket_base::receive_low_watermark @n
* asio::socket_base::reuse_address @n
* asio::socket_base::send_buffer_size @n
* asio::socket_base::send_low_watermark @n
* asio::ip::multicast::join_group @n
* asio::ip::multicast::leave_group @n
* asio::ip::multicast::enable_loopback @n
* asio::ip::multicast::outbound_interface @n
* asio::ip::multicast::hops @n
* asio::ip::tcp::no_delay
*
* @par Example
* Setting the IPPROTO_TCP/TCP_NODELAY option:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::no_delay option(true);
* asio::error_code ec;
* socket.set_option(option, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SettableSocketOption>
asio::error_code set_option(const SettableSocketOption& option,
asio::error_code& ec)
{
return this->service.set_option(this->implementation, option, ec);
}
/// Get an option from the socket.
/**
* This function is used to get the current value of an option on the socket.
*
* @param option The option value to be obtained from the socket.
*
* @throws asio::system_error Thrown on failure.
*
* @sa GettableSocketOption @n
* asio::socket_base::broadcast @n
* asio::socket_base::do_not_route @n
* asio::socket_base::keep_alive @n
* asio::socket_base::linger @n
* asio::socket_base::receive_buffer_size @n
* asio::socket_base::receive_low_watermark @n
* asio::socket_base::reuse_address @n
* asio::socket_base::send_buffer_size @n
* asio::socket_base::send_low_watermark @n
* asio::ip::multicast::join_group @n
* asio::ip::multicast::leave_group @n
* asio::ip::multicast::enable_loopback @n
* asio::ip::multicast::outbound_interface @n
* asio::ip::multicast::hops @n
* asio::ip::tcp::no_delay
*
* @par Example
* Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::socket::keep_alive option;
* socket.get_option(option);
* bool is_set = option.get();
* @endcode
*/
template <typename GettableSocketOption>
void get_option(GettableSocketOption& option) const
{
asio::error_code ec;
this->service.get_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Get an option from the socket.
/**
* This function is used to get the current value of an option on the socket.
*
* @param option The option value to be obtained from the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa GettableSocketOption @n
* asio::socket_base::broadcast @n
* asio::socket_base::do_not_route @n
* asio::socket_base::keep_alive @n
* asio::socket_base::linger @n
* asio::socket_base::receive_buffer_size @n
* asio::socket_base::receive_low_watermark @n
* asio::socket_base::reuse_address @n
* asio::socket_base::send_buffer_size @n
* asio::socket_base::send_low_watermark @n
* asio::ip::multicast::join_group @n
* asio::ip::multicast::leave_group @n
* asio::ip::multicast::enable_loopback @n
* asio::ip::multicast::outbound_interface @n
* asio::ip::multicast::hops @n
* asio::ip::tcp::no_delay
*
* @par Example
* Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::socket::keep_alive option;
* asio::error_code ec;
* socket.get_option(option, ec);
* if (ec)
* {
* // An error occurred.
* }
* bool is_set = option.get();
* @endcode
*/
template <typename GettableSocketOption>
asio::error_code get_option(GettableSocketOption& option,
asio::error_code& ec) const
{
return this->service.get_option(this->implementation, option, ec);
}
/// Perform an IO control command on the socket.
/**
* This function is used to execute an IO control command on the socket.
*
* @param command The IO control command to be performed on the socket.
*
* @throws asio::system_error Thrown on failure.
*
* @sa IoControlCommand @n
* asio::socket_base::bytes_readable @n
* asio::socket_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::socket::bytes_readable command;
* socket.io_control(command);
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
void io_control(IoControlCommand& command)
{
asio::error_code ec;
this->service.io_control(this->implementation, command, ec);
asio::detail::throw_error(ec);
}
/// Perform an IO control command on the socket.
/**
* This function is used to execute an IO control command on the socket.
*
* @param command The IO control command to be performed on the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa IoControlCommand @n
* asio::socket_base::bytes_readable @n
* asio::socket_base::non_blocking_io
*
* @par Example
* Getting the number of bytes ready to read:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::socket::bytes_readable command;
* asio::error_code ec;
* socket.io_control(command, ec);
* if (ec)
* {
* // An error occurred.
* }
* std::size_t bytes_readable = command.get();
* @endcode
*/
template <typename IoControlCommand>
asio::error_code io_control(IoControlCommand& command,
asio::error_code& ec)
{
return this->service.io_control(this->implementation, command, ec);
}
/// Get the local endpoint of the socket.
/**
* This function is used to obtain the locally bound endpoint of the socket.
*
* @returns An object that represents the local endpoint of the socket.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
* @endcode
*/
endpoint_type local_endpoint() const
{
asio::error_code ec;
endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
asio::detail::throw_error(ec);
return ep;
}
/// Get the local endpoint of the socket.
/**
* This function is used to obtain the locally bound endpoint of the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns An object that represents the local endpoint of the socket.
* Returns a default-constructed endpoint object if an error occurred.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::error_code ec;
* asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
endpoint_type local_endpoint(asio::error_code& ec) const
{
return this->service.local_endpoint(this->implementation, ec);
}
/// Get the remote endpoint of the socket.
/**
* This function is used to obtain the remote endpoint of the socket.
*
* @returns An object that represents the remote endpoint of the socket.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
* @endcode
*/
endpoint_type remote_endpoint() const
{
asio::error_code ec;
endpoint_type ep = this->service.remote_endpoint(this->implementation, ec);
asio::detail::throw_error(ec);
return ep;
}
/// Get the remote endpoint of the socket.
/**
* This function is used to obtain the remote endpoint of the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns An object that represents the remote endpoint of the socket.
* Returns a default-constructed endpoint object if an error occurred.
*
* @par Example
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::error_code ec;
* asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
endpoint_type remote_endpoint(asio::error_code& ec) const
{
return this->service.remote_endpoint(this->implementation, ec);
}
/// Disable sends or receives on the socket.
/**
* This function is used to disable send operations, receive operations, or
* both.
*
* @param what Determines what types of operation will no longer be allowed.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* Shutting down the send side of the socket:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* socket.shutdown(asio::ip::tcp::socket::shutdown_send);
* @endcode
*/
void shutdown(shutdown_type what)
{
asio::error_code ec;
this->service.shutdown(this->implementation, what, ec);
asio::detail::throw_error(ec);
}
/// Disable sends or receives on the socket.
/**
* This function is used to disable send operations, receive operations, or
* both.
*
* @param what Determines what types of operation will no longer be allowed.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* Shutting down the send side of the socket:
* @code
* asio::ip::tcp::socket socket(io_service);
* ...
* asio::error_code ec;
* socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code shutdown(shutdown_type what,
asio::error_code& ec)
{
return this->service.shutdown(this->implementation, what, ec);
}
protected:
/// Protected destructor to prevent deletion through this type.
~basic_socket()
{
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_HPP

View File

@ -0,0 +1,824 @@
//
// basic_socket_acceptor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SOCKET_ACCEPTOR_HPP
#define ASIO_BASIC_SOCKET_ACCEPTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_socket.hpp"
#include "asio/error.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides the ability to accept new connections.
/**
* The basic_socket_acceptor class template is used for accepting new socket
* connections.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Example
* Opening a socket acceptor with the SO_REUSEADDR option enabled:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
* acceptor.open(endpoint.protocol());
* acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
* acceptor.bind(endpoint);
* acceptor.listen();
* @endcode
*/
template <typename Protocol,
typename SocketAcceptorService = socket_acceptor_service<Protocol> >
class basic_socket_acceptor
: public basic_io_object<SocketAcceptorService>,
public socket_base
{
public:
/// The native representation of an acceptor.
typedef typename SocketAcceptorService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct an acceptor without opening it.
/**
* This constructor creates an acceptor without opening it to listen for new
* connections. The open() function must be called before the acceptor can
* accept new socket connections.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*/
explicit basic_socket_acceptor(asio::io_service& io_service)
: basic_io_object<SocketAcceptorService>(io_service)
{
}
/// Construct an open acceptor.
/**
* This constructor creates an acceptor and automatically opens it.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket_acceptor(asio::io_service& io_service,
const protocol_type& protocol)
: basic_io_object<SocketAcceptorService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, protocol, ec);
asio::detail::throw_error(ec);
}
/// Construct an acceptor opened on the given endpoint.
/**
* This constructor creates an acceptor and automatically opens it to listen
* for new connections on the specified endpoint.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*
* @param endpoint An endpoint on the local machine on which the acceptor
* will listen for new connections.
*
* @param reuse_addr Whether the constructor should set the socket option
* socket_base::reuse_address.
*
* @throws asio::system_error Thrown on failure.
*
* @note This constructor is equivalent to the following code:
* @code
* basic_socket_acceptor<Protocol> acceptor(io_service);
* acceptor.open(endpoint.protocol());
* if (reuse_addr)
* acceptor.set_option(socket_base::reuse_address(true));
* acceptor.bind(endpoint);
* acceptor.listen(listen_backlog);
* @endcode
*/
basic_socket_acceptor(asio::io_service& io_service,
const endpoint_type& endpoint, bool reuse_addr = true)
: basic_io_object<SocketAcceptorService>(io_service)
{
asio::error_code ec;
this->service.open(this->implementation, endpoint.protocol(), ec);
asio::detail::throw_error(ec);
if (reuse_addr)
{
this->service.set_option(this->implementation,
socket_base::reuse_address(true), ec);
asio::detail::throw_error(ec);
}
this->service.bind(this->implementation, endpoint, ec);
asio::detail::throw_error(ec);
this->service.listen(this->implementation,
socket_base::max_connections, ec);
asio::detail::throw_error(ec);
}
/// Construct a basic_socket_acceptor on an existing native acceptor.
/**
* This constructor creates an acceptor object to hold an existing native
* acceptor.
*
* @param io_service The io_service object that the acceptor will use to
* dispatch handlers for any asynchronous operations performed on the
* acceptor.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_acceptor A native acceptor.
*
* @throws asio::system_error Thrown on failure.
*/
basic_socket_acceptor(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_acceptor)
: basic_io_object<SocketAcceptorService>(io_service)
{
asio::error_code ec;
this->service.assign(this->implementation, protocol, native_acceptor, ec);
asio::detail::throw_error(ec);
}
/// Open the acceptor using the specified protocol.
/**
* This function opens the socket acceptor so that it will use the specified
* protocol.
*
* @param protocol An object specifying which protocol is to be used.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* acceptor.open(asio::ip::tcp::v4());
* @endcode
*/
void open(const protocol_type& protocol = protocol_type())
{
asio::error_code ec;
this->service.open(this->implementation, protocol, ec);
asio::detail::throw_error(ec);
}
/// Open the acceptor using the specified protocol.
/**
* This function opens the socket acceptor so that it will use the specified
* protocol.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* asio::error_code ec;
* acceptor.open(asio::ip::tcp::v4(), ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code open(const protocol_type& protocol,
asio::error_code& ec)
{
return this->service.open(this->implementation, protocol, ec);
}
/// Assigns an existing native acceptor to the acceptor.
/*
* This function opens the acceptor to hold an existing native acceptor.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param native_acceptor A native acceptor.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const protocol_type& protocol, const native_type& native_acceptor)
{
asio::error_code ec;
this->service.assign(this->implementation, protocol, native_acceptor, ec);
asio::detail::throw_error(ec);
}
/// Assigns an existing native acceptor to the acceptor.
/*
* This function opens the acceptor to hold an existing native acceptor.
*
* @param protocol An object specifying which protocol is to be used.
*
* @param native_acceptor A native acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const protocol_type& protocol,
const native_type& native_acceptor, asio::error_code& ec)
{
return this->service.assign(this->implementation,
protocol, native_acceptor, ec);
}
/// Determine whether the acceptor is open.
bool is_open() const
{
return this->service.is_open(this->implementation);
}
/// Bind the acceptor to the given local endpoint.
/**
* This function binds the socket acceptor to the specified endpoint on the
* local machine.
*
* @param endpoint An endpoint on the local machine to which the socket
* acceptor will be bound.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* acceptor.open(asio::ip::tcp::v4());
* acceptor.bind(asio::ip::tcp::endpoint(12345));
* @endcode
*/
void bind(const endpoint_type& endpoint)
{
asio::error_code ec;
this->service.bind(this->implementation, endpoint, ec);
asio::detail::throw_error(ec);
}
/// Bind the acceptor to the given local endpoint.
/**
* This function binds the socket acceptor to the specified endpoint on the
* local machine.
*
* @param endpoint An endpoint on the local machine to which the socket
* acceptor will be bound.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* acceptor.open(asio::ip::tcp::v4());
* asio::error_code ec;
* acceptor.bind(asio::ip::tcp::endpoint(12345), ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code bind(const endpoint_type& endpoint,
asio::error_code& ec)
{
return this->service.bind(this->implementation, endpoint, ec);
}
/// Place the acceptor into the state where it will listen for new
/// connections.
/**
* This function puts the socket acceptor into the state where it may accept
* new connections.
*
* @param backlog The maximum length of the queue of pending connections.
*
* @throws asio::system_error Thrown on failure.
*/
void listen(int backlog = socket_base::max_connections)
{
asio::error_code ec;
this->service.listen(this->implementation, backlog, ec);
asio::detail::throw_error(ec);
}
/// Place the acceptor into the state where it will listen for new
/// connections.
/**
* This function puts the socket acceptor into the state where it may accept
* new connections.
*
* @param backlog The maximum length of the queue of pending connections.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::error_code ec;
* acceptor.listen(asio::socket_base::max_connections, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code listen(int backlog, asio::error_code& ec)
{
return this->service.listen(this->implementation, backlog, ec);
}
/// Close the acceptor.
/**
* This function is used to close the acceptor. Any asynchronous accept
* operations will be cancelled immediately.
*
* A subsequent call to open() is required before the acceptor can again be
* used to again perform socket accept operations.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
this->service.close(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Close the acceptor.
/**
* This function is used to close the acceptor. Any asynchronous accept
* operations will be cancelled immediately.
*
* A subsequent call to open() is required before the acceptor can again be
* used to again perform socket accept operations.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::error_code ec;
* acceptor.close(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
asio::error_code close(asio::error_code& ec)
{
return this->service.close(this->implementation, ec);
}
/// Get the native acceptor representation.
/**
* This function may be used to obtain the underlying representation of the
* acceptor. This is intended to allow access to native acceptor functionality
* that is not otherwise provided.
*/
native_type native()
{
return this->service.native(this->implementation);
}
/// Cancel all asynchronous operations associated with the acceptor.
/**
* This function causes all outstanding asynchronous connect, send and receive
* operations to finish immediately, and the handlers for cancelled operations
* will be passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
this->service.cancel(this->implementation, ec);
asio::detail::throw_error(ec);
}
/// Cancel all asynchronous operations associated with the acceptor.
/**
* This function causes all outstanding asynchronous connect, send and receive
* operations to finish immediately, and the handlers for cancelled operations
* will be passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code cancel(asio::error_code& ec)
{
return this->service.cancel(this->implementation, ec);
}
/// Set an option on the acceptor.
/**
* This function is used to set an option on the acceptor.
*
* @param option The new option value to be set on the acceptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa SettableSocketOption @n
* asio::socket_base::reuse_address
* asio::socket_base::enable_connection_aborted
*
* @par Example
* Setting the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option(true);
* acceptor.set_option(option);
* @endcode
*/
template <typename SettableSocketOption>
void set_option(const SettableSocketOption& option)
{
asio::error_code ec;
this->service.set_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Set an option on the acceptor.
/**
* This function is used to set an option on the acceptor.
*
* @param option The new option value to be set on the acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSocketOption @n
* asio::socket_base::reuse_address
* asio::socket_base::enable_connection_aborted
*
* @par Example
* Setting the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option(true);
* asio::error_code ec;
* acceptor.set_option(option, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SettableSocketOption>
asio::error_code set_option(const SettableSocketOption& option,
asio::error_code& ec)
{
return this->service.set_option(this->implementation, option, ec);
}
/// Get an option from the acceptor.
/**
* This function is used to get the current value of an option on the
* acceptor.
*
* @param option The option value to be obtained from the acceptor.
*
* @throws asio::system_error Thrown on failure.
*
* @sa GettableSocketOption @n
* asio::socket_base::reuse_address
*
* @par Example
* Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option;
* acceptor.get_option(option);
* bool is_set = option.get();
* @endcode
*/
template <typename GettableSocketOption>
void get_option(GettableSocketOption& option)
{
asio::error_code ec;
this->service.get_option(this->implementation, option, ec);
asio::detail::throw_error(ec);
}
/// Get an option from the acceptor.
/**
* This function is used to get the current value of an option on the
* acceptor.
*
* @param option The option value to be obtained from the acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa GettableSocketOption @n
* asio::socket_base::reuse_address
*
* @par Example
* Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::acceptor::reuse_address option;
* asio::error_code ec;
* acceptor.get_option(option, ec);
* if (ec)
* {
* // An error occurred.
* }
* bool is_set = option.get();
* @endcode
*/
template <typename GettableSocketOption>
asio::error_code get_option(GettableSocketOption& option,
asio::error_code& ec)
{
return this->service.get_option(this->implementation, option, ec);
}
/// Get the local endpoint of the acceptor.
/**
* This function is used to obtain the locally bound endpoint of the acceptor.
*
* @returns An object that represents the local endpoint of the acceptor.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint();
* @endcode
*/
endpoint_type local_endpoint() const
{
asio::error_code ec;
endpoint_type ep = this->service.local_endpoint(this->implementation, ec);
asio::detail::throw_error(ec);
return ep;
}
/// Get the local endpoint of the acceptor.
/**
* This function is used to obtain the locally bound endpoint of the acceptor.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns An object that represents the local endpoint of the acceptor.
* Returns a default-constructed endpoint object if an error occurred and the
* error handler did not throw an exception.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::error_code ec;
* asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
endpoint_type local_endpoint(asio::error_code& ec) const
{
return this->service.local_endpoint(this->implementation, ec);
}
/// Accept a new connection.
/**
* This function is used to accept a new connection from a peer into the
* given socket. The function call will block until a new connection has been
* accepted successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* acceptor.accept(socket);
* @endcode
*/
template <typename SocketService>
void accept(basic_socket<protocol_type, SocketService>& peer)
{
asio::error_code ec;
this->service.accept(this->implementation, peer, 0, ec);
asio::detail::throw_error(ec);
}
/// Accept a new connection.
/**
* This function is used to accept a new connection from a peer into the
* given socket. The function call will block until a new connection has been
* accepted successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::soocket socket(io_service);
* asio::error_code ec;
* acceptor.accept(socket, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SocketService>
asio::error_code accept(
basic_socket<protocol_type, SocketService>& peer,
asio::error_code& ec)
{
return this->service.accept(this->implementation, peer, 0, ec);
}
/// Start an asynchronous accept.
/**
* This function is used to asynchronously accept a new connection into a
* socket. The function call always returns immediately.
*
* @param peer The socket into which the new connection will be accepted.
* Ownership of the peer object is retained by the caller, which must
* guarantee that it is valid until the handler is called.
*
* @param handler The handler to be called when the accept operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @par Example
* @code
* void accept_handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Accept succeeded.
* }
* }
*
* ...
*
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* acceptor.async_accept(socket, accept_handler);
* @endcode
*/
template <typename SocketService, typename AcceptHandler>
void async_accept(basic_socket<protocol_type, SocketService>& peer,
AcceptHandler handler)
{
this->service.async_accept(this->implementation, peer, 0, handler);
}
/// Accept a new connection and obtain the endpoint of the peer
/**
* This function is used to accept a new connection from a peer into the
* given socket, and additionally provide the endpoint of the remote peer.
* The function call will block until a new connection has been accepted
* successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @param peer_endpoint An endpoint object which will receive the endpoint of
* the remote peer.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint;
* acceptor.accept(socket, endpoint);
* @endcode
*/
template <typename SocketService>
void accept(basic_socket<protocol_type, SocketService>& peer,
endpoint_type& peer_endpoint)
{
asio::error_code ec;
this->service.accept(this->implementation, peer, &peer_endpoint, ec);
asio::detail::throw_error(ec);
}
/// Accept a new connection and obtain the endpoint of the peer
/**
* This function is used to accept a new connection from a peer into the
* given socket, and additionally provide the endpoint of the remote peer.
* The function call will block until a new connection has been accepted
* successfully or an error occurs.
*
* @param peer The socket into which the new connection will be accepted.
*
* @param peer_endpoint An endpoint object which will receive the endpoint of
* the remote peer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::ip::tcp::acceptor acceptor(io_service);
* ...
* asio::ip::tcp::socket socket(io_service);
* asio::ip::tcp::endpoint endpoint;
* asio::error_code ec;
* acceptor.accept(socket, endpoint, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
template <typename SocketService>
asio::error_code accept(
basic_socket<protocol_type, SocketService>& peer,
endpoint_type& peer_endpoint, asio::error_code& ec)
{
return this->service.accept(this->implementation, peer, &peer_endpoint, ec);
}
/// Start an asynchronous accept.
/**
* This function is used to asynchronously accept a new connection into a
* socket, and additionally obtain the endpoint of the remote peer. The
* function call always returns immediately.
*
* @param peer The socket into which the new connection will be accepted.
* Ownership of the peer object is retained by the caller, which must
* guarantee that it is valid until the handler is called.
*
* @param peer_endpoint An endpoint object into which the endpoint of the
* remote peer will be written. Ownership of the peer_endpoint object is
* retained by the caller, which must guarantee that it is valid until the
* handler is called.
*
* @param handler The handler to be called when the accept operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*/
template <typename SocketService, typename AcceptHandler>
void async_accept(basic_socket<protocol_type, SocketService>& peer,
endpoint_type& peer_endpoint, AcceptHandler handler)
{
this->service.async_accept(this->implementation,
peer, &peer_endpoint, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP

View File

@ -0,0 +1,146 @@
//
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SOCKET_IOSTREAM_HPP
#define ASIO_BASIC_SOCKET_IOSTREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket_streambuf.hpp"
#include "asio/stream_socket_service.hpp"
#if !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY)
#define ASIO_SOCKET_IOSTREAM_MAX_ARITY 5
#endif // !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY)
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
// : basic_iostream<char>(&this->boost::base_from_member<
// basic_socket_streambuf<Protocol, StreamSocketService> >::member)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
#define ASIO_PRIVATE_CTR_DEF(z, n, data) \
template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
explicit basic_socket_iostream(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
: std::basic_iostream<char>(&this->boost::base_from_member< \
basic_socket_streambuf<Protocol, StreamSocketService> >::member) \
{ \
if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// void connect(T1 x1, ..., Tn xn)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
#define ASIO_PRIVATE_CONNECT_DEF(z, n, data) \
template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
void connect(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
{ \
if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
namespace asio {
/// Iostream interface for a socket.
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
class basic_socket_iostream
: public boost::base_from_member<
basic_socket_streambuf<Protocol, StreamSocketService> >,
public std::basic_iostream<char>
{
public:
/// Construct a basic_socket_iostream without establishing a connection.
basic_socket_iostream()
: std::basic_iostream<char>(&this->boost::base_from_member<
basic_socket_streambuf<Protocol, StreamSocketService> >::member)
{
}
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This constructor automatically establishes a connection based on the
* supplied resolver query parameters. The arguments are used to construct
* a resolver query object.
*/
template <typename T1, ..., typename TN>
explicit basic_socket_iostream(T1 t1, ..., TN tn);
#else
BOOST_PP_REPEAT_FROM_TO(
1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY),
ASIO_PRIVATE_CTR_DEF, _ )
#endif
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*/
template <typename T1, ..., typename TN>
void connect(T1 t1, ..., TN tn);
#else
BOOST_PP_REPEAT_FROM_TO(
1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY),
ASIO_PRIVATE_CONNECT_DEF, _ )
#endif
/// Close the connection.
void close()
{
if (rdbuf()->close() == 0)
this->setstate(std::ios_base::failbit);
}
/// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol, StreamSocketService>* rdbuf() const
{
return const_cast<basic_socket_streambuf<Protocol, StreamSocketService>*>(
&this->boost::base_from_member<
basic_socket_streambuf<Protocol, StreamSocketService> >::member);
}
};
} // namespace asio
#undef ASIO_PRIVATE_CTR_DEF
#undef ASIO_PRIVATE_CONNECT_DEF
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP

View File

@ -0,0 +1,284 @@
//
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SOCKET_STREAMBUF_HPP
#define ASIO_BASIC_SOCKET_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <streambuf>
#include <boost/array.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/utility/base_from_member.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/io_service.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/detail/throw_error.hpp"
#if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
#define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5
#endif // !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY)
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// basic_socket_streambuf<Protocol, StreamSocketService>* connect(
// T1 x1, ..., Tn xn)
// {
// init_buffers();
// asio::error_code ec;
// this->basic_socket<Protocol, StreamSocketService>::close(ec);
// typedef typename Protocol::resolver_query resolver_query;
// resolver_query query(x1, ..., xn);
// resolve_and_connect(query, ec);
// return !ec ? this : 0;
// }
// This macro should only persist within this file.
#define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \
template <BOOST_PP_ENUM_PARAMS(n, typename T)> \
basic_socket_streambuf<Protocol, StreamSocketService>* connect( \
BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \
{ \
init_buffers(); \
asio::error_code ec; \
this->basic_socket<Protocol, StreamSocketService>::close(ec); \
typedef typename Protocol::resolver_query resolver_query; \
resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \
resolve_and_connect(query, ec); \
return !ec ? this : 0; \
} \
/**/
namespace asio {
/// Iostream streambuf for a socket.
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
class basic_socket_streambuf
: public std::streambuf,
private boost::base_from_member<io_service>,
public basic_socket<Protocol, StreamSocketService>
{
public:
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf()
: basic_socket<Protocol, StreamSocketService>(
boost::base_from_member<asio::io_service>::member),
unbuffered_(false)
{
init_buffers();
}
/// Destructor flushes buffered data.
virtual ~basic_socket_streambuf()
{
if (pptr() != pbase())
overflow(traits_type::eof());
}
/// Establish a connection.
/**
* This function establishes a connection to the specified endpoint.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf<Protocol, StreamSocketService>* connect(
const endpoint_type& endpoint)
{
init_buffers();
asio::error_code ec;
this->basic_socket<Protocol, StreamSocketService>::close(ec);
this->basic_socket<Protocol, StreamSocketService>::connect(endpoint, ec);
return !ec ? this : 0;
}
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
template <typename T1, ..., typename TN>
basic_socket_streambuf<Protocol, StreamSocketService>* connect(
T1 t1, ..., TN tn);
#else
BOOST_PP_REPEAT_FROM_TO(
1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY),
ASIO_PRIVATE_CONNECT_DEF, _ )
#endif
/// Close the connection.
/**
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf<Protocol, StreamSocketService>* close()
{
asio::error_code ec;
sync();
this->basic_socket<Protocol, StreamSocketService>::close(ec);
if (!ec)
init_buffers();
return !ec ? this : 0;
}
protected:
int_type underflow()
{
if (gptr() == egptr())
{
asio::error_code ec;
std::size_t bytes_transferred = this->service.receive(
this->implementation,
asio::buffer(asio::buffer(get_buffer_) + putback_max),
0, ec);
if (ec)
return traits_type::eof();
setg(get_buffer_.begin(), get_buffer_.begin() + putback_max,
get_buffer_.begin() + putback_max + bytes_transferred);
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
int_type overflow(int_type c)
{
if (unbuffered_)
{
if (traits_type::eq_int_type(c, traits_type::eof()))
{
// Nothing to do.
return traits_type::not_eof(c);
}
else
{
// Send the single character immediately.
asio::error_code ec;
char_type ch = traits_type::to_char_type(c);
this->service.send(this->implementation,
asio::buffer(&ch, sizeof(char_type)), 0, ec);
if (ec)
return traits_type::eof();
return c;
}
}
else
{
// Send all data in the output buffer.
asio::const_buffer buffer =
asio::buffer(pbase(), pptr() - pbase());
while (asio::buffer_size(buffer) > 0)
{
asio::error_code ec;
std::size_t bytes_transferred = this->service.send(
this->implementation, asio::buffer(buffer),
0, ec);
if (ec)
return traits_type::eof();
buffer = buffer + bytes_transferred;
}
setp(put_buffer_.begin(), put_buffer_.end());
// If the new character is eof then our work here is done.
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c);
// Add the new character to the output buffer.
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
}
int sync()
{
return overflow(traits_type::eof());
}
std::streambuf* setbuf(char_type* s, std::streamsize n)
{
if (pptr() == pbase() && s == 0 && n == 0)
{
unbuffered_ = true;
setp(0, 0);
return this;
}
return 0;
}
private:
void init_buffers()
{
setg(get_buffer_.begin(),
get_buffer_.begin() + putback_max,
get_buffer_.begin() + putback_max);
if (unbuffered_)
setp(0, 0);
else
setp(put_buffer_.begin(), put_buffer_.end());
}
void resolve_and_connect(const typename Protocol::resolver_query& query,
asio::error_code& ec)
{
typedef typename Protocol::resolver resolver_type;
typedef typename Protocol::resolver_iterator iterator_type;
resolver_type resolver(
boost::base_from_member<asio::io_service>::member);
iterator_type i = resolver.resolve(query, ec);
if (!ec)
{
iterator_type end;
ec = asio::error::host_not_found;
while (ec && i != end)
{
this->basic_socket<Protocol, StreamSocketService>::close();
this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec);
++i;
}
}
}
enum { putback_max = 8 };
enum { buffer_size = 512 };
boost::array<char, buffer_size> get_buffer_;
boost::array<char, buffer_size> put_buffer_;
bool unbuffered_;
};
} // namespace asio
#undef ASIO_PRIVATE_CONNECT_DEF
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP

View File

@ -0,0 +1,718 @@
//
// basic_stream_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_STREAM_SOCKET_HPP
#define ASIO_BASIC_STREAM_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_socket.hpp"
#include "asio/error.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/detail/throw_error.hpp"
namespace asio {
/// Provides stream-oriented socket functionality.
/**
* The basic_stream_socket class template provides asynchronous and blocking
* stream-oriented socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
class basic_stream_socket
: public basic_socket<Protocol, StreamSocketService>
{
public:
/// The native representation of a socket.
typedef typename StreamSocketService::native_type native_type;
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_stream_socket without opening it.
/**
* This constructor creates a stream socket without opening it. The socket
* needs to be opened and then connected or accepted before data can be sent
* or received on it.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_stream_socket(asio::io_service& io_service)
: basic_socket<Protocol, StreamSocketService>(io_service)
{
}
/// Construct and open a basic_stream_socket.
/**
* This constructor creates and opens a stream socket. The socket needs to be
* connected or accepted before data can be sent or received on it.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_service& io_service,
const protocol_type& protocol)
: basic_socket<Protocol, StreamSocketService>(io_service, protocol)
{
}
/// Construct a basic_stream_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a stream socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the stream
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_service& io_service,
const endpoint_type& endpoint)
: basic_socket<Protocol, StreamSocketService>(io_service, endpoint)
{
}
/// Construct a basic_stream_socket on an existing native socket.
/**
* This constructor creates a stream socket object to hold an existing native
* socket.
*
* @param io_service The io_service object that the stream socket will use to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_service& io_service,
const protocol_type& protocol, const native_type& native_socket)
: basic_socket<Protocol, StreamSocketService>(
io_service, protocol, native_socket)
{
}
/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
* call will block until one or more bytes of the data has been sent
* successfully, or an until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.send(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.send(
this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
* call will block until one or more bytes of the data has been sent
* successfully, or an until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.send(asio::buffer(data, size), 0);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.send(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
* call will block until one or more bytes of the data has been sent
* successfully, or an until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent. Returns 0 if an error occurred.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.send(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send data on the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send data on the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param handler The handler to be called when the send operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), 0, handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, flags, handler);
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the stream socket. The function
* call will block until one or more bytes of data has been received
* successfully, or until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the stream socket. The function
* call will block until one or more bytes of data has been received
* successfully, or until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(asio::buffer(data, size), 0);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->service.receive(
this->implementation, buffers, flags, ec);
asio::detail::throw_error(ec);
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the stream socket. The function
* call will block until one or more bytes of data has been received
* successfully, or until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received. Returns 0 if an error occurred.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->service.receive(this->implementation, buffers, flags, ec);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the stream
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
* that the requested amount of data is received before the asynchronous
* operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, 0, handler);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the stream
* socket. The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param flags Flags specifying how the receive call is to be made.
*
* @param handler The handler to be called when the receive operation
* completes. Copies will be made of the handler as required. The function
* signature of the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
* that the requested amount of data is received before the asynchronous
* operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), 0, handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, flags, handler);
}
/// Write some data to the socket.
/**
* This function is used to write data to the stream socket. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the socket.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* socket.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.send(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Write some data to the socket.
/**
* This function is used to write data to the stream socket. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the socket.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->service.send(this->implementation, buffers, 0, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more data buffers to be written to the socket.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
this->service.async_send(this->implementation, buffers, 0, handler);
}
/// Read some data from the socket.
/**
* This function is used to read data from the stream socket. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* socket.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->service.receive(this->implementation, buffers, 0, ec);
asio::detail::throw_error(ec);
return s;
}
/// Read some data from the socket.
/**
* This function is used to read data from the stream socket. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->service.receive(this->implementation, buffers, 0, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream socket.
* The function call always returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the handler is called.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of
* the handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_service::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_read_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
this->service.async_receive(this->implementation, buffers, 0, handler);
}
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_STREAM_SOCKET_HPP

View File

@ -0,0 +1,200 @@
//
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_STREAMBUF_HPP
#define ASIO_BASIC_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <limits>
#include <memory>
#include <stdexcept>
#include <streambuf>
#include <vector>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Automatically resizable buffer class based on std::streambuf.
template <typename Allocator = std::allocator<char> >
class basic_streambuf
: public std::streambuf,
private noncopyable
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The type used to represent the get area as a list of buffers.
typedef implementation_defined const_buffers_type;
/// The type used to represent the put area as a list of buffers.
typedef implementation_defined mutable_buffers_type;
#else
typedef asio::const_buffers_1 const_buffers_type;
typedef asio::mutable_buffers_1 mutable_buffers_type;
#endif
/// Construct a buffer with a specified maximum size.
explicit basic_streambuf(
std::size_t max_size = (std::numeric_limits<std::size_t>::max)(),
const Allocator& allocator = Allocator())
: max_size_(max_size),
buffer_(allocator)
{
std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
buffer_.resize((std::max<std::size_t>)(pend, 1));
setg(&buffer_[0], &buffer_[0], &buffer_[0]);
setp(&buffer_[0], &buffer_[0] + pend);
}
/// Return the size of the get area in characters.
std::size_t size() const
{
return pptr() - gptr();
}
/// Return the maximum size of the buffer.
std::size_t max_size() const
{
return max_size_;
}
/// Get a list of buffers that represents the get area.
const_buffers_type data() const
{
return asio::buffer(asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type)));
}
/// Get a list of buffers that represents the put area, with the given size.
mutable_buffers_type prepare(std::size_t size)
{
reserve(size);
return asio::buffer(asio::mutable_buffer(
pptr(), size * sizeof(char_type)));
}
/// Move the start of the put area by the specified number of characters.
void commit(std::size_t n)
{
if (pptr() + n > epptr())
n = epptr() - pptr();
pbump(static_cast<int>(n));
}
/// Move the start of the get area by the specified number of characters.
void consume(std::size_t n)
{
while (n > 0)
{
sbumpc();
--n;
}
}
protected:
enum { buffer_delta = 128 };
int_type underflow()
{
if (gptr() < pptr())
{
setg(&buffer_[0], gptr(), pptr());
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
int_type overflow(int_type c)
{
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
if (pptr() == epptr())
{
std::size_t buffer_size = pptr() - gptr();
if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
{
reserve(max_size_ - buffer_size);
}
else
{
reserve(buffer_delta);
}
}
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
return traits_type::not_eof(c);
}
void reserve(std::size_t n)
{
// Get current stream positions as offsets.
std::size_t gnext = gptr() - &buffer_[0];
std::size_t gend = egptr() - &buffer_[0];
std::size_t pnext = pptr() - &buffer_[0];
std::size_t pend = epptr() - &buffer_[0];
// Check if there is already enough space in the put area.
if (n <= pend - pnext)
{
return;
}
// Shift existing contents of get area to start of buffer.
if (gnext > 0)
{
std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend);
gend -= gnext;
pnext -= gnext;
}
// Ensure buffer is large enough to hold at least the specified size.
if (n > pend - pnext)
{
if (n <= max_size_ && pnext <= max_size_ - n)
{
buffer_.resize((std::max<std::size_t>)(pnext + n, 1));
}
else
{
throw std::length_error("asio::streambuf too long");
}
}
// Update stream positions.
setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend);
setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n);
}
private:
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_STREAMBUF_HPP

View File

@ -0,0 +1,782 @@
//
// buffer.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFER_HPP
#define ASIO_BUFFER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/array.hpp>
#include <boost/type_traits/is_const.hpp>
#include <string>
#include <vector>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_MSVC)
# if defined(_HAS_ITERATOR_DEBUGGING)
# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# define ASIO_ENABLE_BUFFER_DEBUGGING
# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# endif // defined(_HAS_ITERATOR_DEBUGGING)
#endif // defined(BOOST_MSVC)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
# include "asio/detail/push_options.hpp"
# include <boost/function.hpp>
# include "asio/detail/pop_options.hpp"
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
namespace asio {
class mutable_buffer;
class const_buffer;
namespace detail {
void* buffer_cast_helper(const mutable_buffer&);
const void* buffer_cast_helper(const const_buffer&);
std::size_t buffer_size_helper(const mutable_buffer&);
std::size_t buffer_size_helper(const const_buffer&);
} // namespace detail
/// Holds a buffer that can be modified.
/**
* The mutable_buffer class provides a safe representation of a buffer that can
* be modified. It does not own the underlying data, and so is cheap to copy or
* assign.
*/
class mutable_buffer
{
public:
/// Construct an empty buffer.
mutable_buffer()
: data_(0),
size_(0)
{
}
/// Construct a buffer to represent a given memory range.
mutable_buffer(void* data, std::size_t size)
: data_(data),
size_(size)
{
}
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
mutable_buffer(void* data, std::size_t size,
boost::function<void()> debug_check)
: data_(data),
size_(size),
debug_check_(debug_check)
{
}
const boost::function<void()>& get_debug_check() const
{
return debug_check_;
}
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
private:
friend void* asio::detail::buffer_cast_helper(
const mutable_buffer& b);
friend std::size_t asio::detail::buffer_size_helper(
const mutable_buffer& b);
void* data_;
std::size_t size_;
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
boost::function<void()> debug_check_;
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
};
namespace detail {
inline void* buffer_cast_helper(const mutable_buffer& b)
{
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
if (b.debug_check_)
b.debug_check_();
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
return b.data_;
}
inline std::size_t buffer_size_helper(const mutable_buffer& b)
{
return b.size_;
}
} // namespace detail
/// Cast a non-modifiable buffer to a specified pointer to POD type.
/**
* @relates mutable_buffer
*/
template <typename PointerToPodType>
inline PointerToPodType buffer_cast(const mutable_buffer& b)
{
return static_cast<PointerToPodType>(detail::buffer_cast_helper(b));
}
/// Get the number of bytes in a non-modifiable buffer.
/**
* @relates mutable_buffer
*/
inline std::size_t buffer_size(const mutable_buffer& b)
{
return detail::buffer_size_helper(b);
}
/// Create a new modifiable buffer that is offset from the start of another.
/**
* @relates mutable_buffer
*/
inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start)
{
if (start > buffer_size(b))
return mutable_buffer();
char* new_data = buffer_cast<char*>(b) + start;
std::size_t new_size = buffer_size(b) - start;
return mutable_buffer(new_data, new_size
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Create a new modifiable buffer that is offset from the start of another.
/**
* @relates mutable_buffer
*/
inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b)
{
if (start > buffer_size(b))
return mutable_buffer();
char* new_data = buffer_cast<char*>(b) + start;
std::size_t new_size = buffer_size(b) - start;
return mutable_buffer(new_data, new_size
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Adapts a single modifiable buffer so that it meets the requirements of the
/// MutableBufferSequence concept.
class mutable_buffers_1
: public mutable_buffer
{
public:
/// The type for each element in the list of buffers.
typedef mutable_buffer value_type;
/// A random-access iterator type that may be used to read elements.
typedef const mutable_buffer* const_iterator;
/// Construct to represent a single modifiable buffer.
explicit mutable_buffers_1(const mutable_buffer& b)
: mutable_buffer(b)
{
}
/// Get a random-access iterator to the first element.
const_iterator begin() const
{
return this;
}
/// Get a random-access iterator for one past the last element.
const_iterator end() const
{
return begin() + 1;
}
};
/// Holds a buffer that cannot be modified.
/**
* The const_buffer class provides a safe representation of a buffer that cannot
* be modified. It does not own the underlying data, and so is cheap to copy or
* assign.
*/
class const_buffer
{
public:
/// Construct an empty buffer.
const_buffer()
: data_(0),
size_(0)
{
}
/// Construct a buffer to represent a given memory range.
const_buffer(const void* data, std::size_t size)
: data_(data),
size_(size)
{
}
/// Construct a non-modifiable buffer from a modifiable one.
const_buffer(const mutable_buffer& b)
: data_(asio::detail::buffer_cast_helper(b)),
size_(asio::detail::buffer_size_helper(b))
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, debug_check_(b.get_debug_check())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
{
}
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
const_buffer(const void* data, std::size_t size,
boost::function<void()> debug_check)
: data_(data),
size_(size),
debug_check_(debug_check)
{
}
const boost::function<void()>& get_debug_check() const
{
return debug_check_;
}
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
private:
friend const void* asio::detail::buffer_cast_helper(
const const_buffer& b);
friend std::size_t asio::detail::buffer_size_helper(
const const_buffer& b);
const void* data_;
std::size_t size_;
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
boost::function<void()> debug_check_;
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
};
namespace detail {
inline const void* buffer_cast_helper(const const_buffer& b)
{
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
if (b.debug_check_)
b.debug_check_();
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
return b.data_;
}
inline std::size_t buffer_size_helper(const const_buffer& b)
{
return b.size_;
}
} // namespace detail
/// Cast a non-modifiable buffer to a specified pointer to POD type.
/**
* @relates const_buffer
*/
template <typename PointerToPodType>
inline PointerToPodType buffer_cast(const const_buffer& b)
{
return static_cast<PointerToPodType>(detail::buffer_cast_helper(b));
}
/// Get the number of bytes in a non-modifiable buffer.
/**
* @relates const_buffer
*/
inline std::size_t buffer_size(const const_buffer& b)
{
return detail::buffer_size_helper(b);
}
/// Create a new non-modifiable buffer that is offset from the start of another.
/**
* @relates const_buffer
*/
inline const_buffer operator+(const const_buffer& b, std::size_t start)
{
if (start > buffer_size(b))
return const_buffer();
const char* new_data = buffer_cast<const char*>(b) + start;
std::size_t new_size = buffer_size(b) - start;
return const_buffer(new_data, new_size
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Create a new non-modifiable buffer that is offset from the start of another.
/**
* @relates const_buffer
*/
inline const_buffer operator+(std::size_t start, const const_buffer& b)
{
if (start > buffer_size(b))
return const_buffer();
const char* new_data = buffer_cast<const char*>(b) + start;
std::size_t new_size = buffer_size(b) - start;
return const_buffer(new_data, new_size
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
);
}
/// Adapts a single non-modifiable buffer so that it meets the requirements of
/// the ConstBufferSequence concept.
class const_buffers_1
: public const_buffer
{
public:
/// The type for each element in the list of buffers.
typedef const_buffer value_type;
/// A random-access iterator type that may be used to read elements.
typedef const const_buffer* const_iterator;
/// Construct to represent a single non-modifiable buffer.
explicit const_buffers_1(const const_buffer& b)
: const_buffer(b)
{
}
/// Get a random-access iterator to the first element.
const_iterator begin() const
{
return this;
}
/// Get a random-access iterator for one past the last element.
const_iterator end() const
{
return begin() + 1;
}
};
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
namespace detail {
template <typename Iterator>
class buffer_debug_check
{
public:
buffer_debug_check(Iterator iter)
: iter_(iter)
{
}
void operator()()
{
*iter_;
}
private:
Iterator iter_;
};
} // namespace detail
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
/** @defgroup buffer asio::buffer
*
* @brief The asio::buffer function is used to create a buffer object to
* represent raw memory, an array of POD elements, or a vector of POD elements.
*
* The simplest use case involves reading or writing a single buffer of a
* specified size:
*
* @code sock.write(asio::buffer(data, size)); @endcode
*
* In the above example, the return value of asio::buffer meets the
* requirements of the ConstBufferSequence concept so that it may be directly
* passed to the socket's write function. A buffer created for modifiable
* memory also meets the requirements of the MutableBufferSequence concept.
*
* An individual buffer may be created from a builtin array, std::vector or
* boost::array of POD elements. This helps prevent buffer overruns by
* automatically determining the size of the buffer:
*
* @code char d1[128];
* size_t bytes_transferred = sock.read(asio::buffer(d1));
*
* std::vector<char> d2(128);
* bytes_transferred = sock.read(asio::buffer(d2));
*
* boost::array<char, 128> d3;
* bytes_transferred = sock.read(asio::buffer(d3)); @endcode
*
* To read or write using multiple buffers (i.e. scatter-gather I/O), multiple
* buffer objects may be assigned into a container that supports the
* MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts:
*
* @code
* char d1[128];
* std::vector<char> d2(128);
* boost::array<char, 128> d3;
*
* boost::array<mutable_buffer, 3> bufs1 = {
* asio::buffer(d1),
* asio::buffer(d2),
* asio::buffer(d3) };
* bytes_transferred = sock.read(bufs1);
*
* std::vector<const_buffer> bufs2;
* bufs2.push_back(asio::buffer(d1));
* bufs2.push_back(asio::buffer(d2));
* bufs2.push_back(asio::buffer(d3));
* bytes_transferred = sock.write(bufs2); @endcode
*/
/*@{*/
/// Create a new modifiable buffer from an existing buffer.
inline mutable_buffers_1 buffer(const mutable_buffer& b)
{
return mutable_buffers_1(b);
}
/// Create a new modifiable buffer from an existing buffer.
inline mutable_buffers_1 buffer(const mutable_buffer& b,
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(buffer_cast<void*>(b),
buffer_size(b) < max_size_in_bytes
? buffer_size(b) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer from an existing buffer.
inline const_buffers_1 buffer(const const_buffer& b)
{
return const_buffers_1(b);
}
/// Create a new non-modifiable buffer from an existing buffer.
inline const_buffers_1 buffer(const const_buffer& b,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(buffer_cast<const void*>(b),
buffer_size(b) < max_size_in_bytes
? buffer_size(b) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, b.get_debug_check()
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new modifiable buffer that represents the given memory range.
inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes)
{
return mutable_buffers_1(mutable_buffer(data, size_in_bytes));
}
/// Create a new non-modifiable buffer that represents the given memory range.
inline const_buffers_1 buffer(const void* data,
std::size_t size_in_bytes)
{
return const_buffers_1(const_buffer(data, size_in_bytes));
}
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(PodType (&data)[N])
{
return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType)));
}
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(PodType (&data)[N],
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(data,
N * sizeof(PodType) < max_size_in_bytes
? N * sizeof(PodType) : max_size_in_bytes));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const PodType (&data)[N])
{
return const_buffers_1(const_buffer(data, N * sizeof(PodType)));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const PodType (&data)[N],
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data,
N * sizeof(PodType) < max_size_in_bytes
? N * sizeof(PodType) : max_size_in_bytes));
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
// Borland C++ thinks the overloads:
//
// unspecified buffer(boost::array<PodType, N>& array ...);
//
// and
//
// unspecified buffer(boost::array<const PodType, N>& array ...);
//
// are ambiguous. This will be worked around by using a buffer_types traits
// class that contains typedefs for the appropriate buffer and container
// classes, based on whether PodType is const or non-const.
namespace detail {
template <bool IsConst>
struct buffer_types_base;
template <>
struct buffer_types_base<false>
{
typedef mutable_buffer buffer_type;
typedef mutable_buffers_1 container_type;
};
template <>
struct buffer_types_base<true>
{
typedef const_buffer buffer_type;
typedef const_buffers_1 container_type;
};
template <typename PodType>
struct buffer_types
: public buffer_types_base<boost::is_const<PodType>::value>
{
};
} // namespace detail
template <typename PodType, std::size_t N>
inline typename detail::buffer_types<PodType>::container_type
buffer(boost::array<PodType, N>& data)
{
typedef typename asio::detail::buffer_types<PodType>::buffer_type
buffer_type;
typedef typename asio::detail::buffer_types<PodType>::container_type
container_type;
return container_type(
buffer_type(data.c_array(), data.size() * sizeof(PodType)));
}
template <typename PodType, std::size_t N>
inline typename detail::buffer_types<PodType>::container_type
buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes)
{
typedef typename asio::detail::buffer_types<PodType>::buffer_type
buffer_type;
typedef typename asio::detail::buffer_types<PodType>::container_type
container_type;
return container_type(
buffer_type(data.c_array(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(boost::array<PodType, N>& data)
{
return mutable_buffers_1(
mutable_buffer(data.c_array(), data.size() * sizeof(PodType)));
}
/// Create a new modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline mutable_buffers_1 buffer(boost::array<PodType, N>& data,
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(data.c_array(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(boost::array<const PodType, N>& data)
{
return const_buffers_1(
const_buffer(data.data(), data.size() * sizeof(PodType)));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(boost::array<const PodType, N>& data,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data.data(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const boost::array<PodType, N>& data)
{
return const_buffers_1(
const_buffer(data.data(), data.size() * sizeof(PodType)));
}
/// Create a new non-modifiable buffer that represents the given POD array.
template <typename PodType, std::size_t N>
inline const_buffers_1 buffer(const boost::array<PodType, N>& data,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data.data(),
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes));
}
/// Create a new modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data)
{
return mutable_buffers_1(
mutable_buffer(&data[0], data.size() * sizeof(PodType)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data,
std::size_t max_size_in_bytes)
{
return mutable_buffers_1(
mutable_buffer(&data[0],
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline const_buffers_1 buffer(
const std::vector<PodType, Allocator>& data)
{
return const_buffers_1(
const_buffer(&data[0], data.size() * sizeof(PodType)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::const_iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given POD vector.
/**
* @note The buffer is invalidated by any vector operation that would also
* invalidate iterators.
*/
template <typename PodType, typename Allocator>
inline const_buffers_1 buffer(
const std::vector<PodType, Allocator>& data, std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(&data[0],
data.size() * sizeof(PodType) < max_size_in_bytes
? data.size() * sizeof(PodType) : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<
typename std::vector<PodType, Allocator>::const_iterator
>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given string.
/**
* @note The buffer is invalidated by any non-const operation called on the
* given string object.
*/
inline const_buffers_1 buffer(const std::string& data)
{
return const_buffers_1(const_buffer(data.data(), data.size()
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<std::string::const_iterator>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/// Create a new non-modifiable buffer that represents the given string.
/**
* @note The buffer is invalidated by any non-const operation called on the
* given string object.
*/
inline const_buffers_1 buffer(const std::string& data,
std::size_t max_size_in_bytes)
{
return const_buffers_1(
const_buffer(data.data(),
data.size() < max_size_in_bytes
? data.size() : max_size_in_bytes
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
, detail::buffer_debug_check<std::string::const_iterator>(data.begin())
#endif // ASIO_ENABLE_BUFFER_DEBUGGING
));
}
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFER_HPP

View File

@ -0,0 +1,407 @@
//
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_READ_STREAM_HPP
#define ASIO_BUFFERED_READ_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <cstring>
#include <boost/config.hpp>
#include <boost/type_traits.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_resize_guard.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Adds buffering to the read-related operations of a stream.
/**
* The buffered_read_stream class template can be used to add buffering to the
* synchronous and asynchronous read operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, Sync_Read_Stream, SyncWriteStream.
*/
template <typename Stream>
class buffered_read_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename boost::remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_read_stream(Arg& a)
: next_layer_(a),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_read_stream(Arg& a, std::size_t buffer_size)
: next_layer_(a),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// Get the io_service associated with the object.
asio::io_service& io_service()
{
return next_layer_.io_service();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
asio::error_code close(asio::error_code& ec)
{
return next_layer_.close(ec);
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return next_layer_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
next_layer_.async_write_some(buffers, handler);
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill()
{
detail::buffer_resize_guard<detail::buffered_stream_storage>
resize_guard(storage_);
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
storage_.resize(previous_size + next_layer_.read_some(buffer(
storage_.data() + previous_size,
storage_.size() - previous_size)));
resize_guard.commit();
return storage_.size() - previous_size;
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(asio::error_code& ec)
{
detail::buffer_resize_guard<detail::buffered_stream_storage>
resize_guard(storage_);
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
storage_.resize(previous_size + next_layer_.read_some(buffer(
storage_.data() + previous_size,
storage_.size() - previous_size),
ec));
resize_guard.commit();
return storage_.size() - previous_size;
}
template <typename ReadHandler>
class fill_handler
{
public:
fill_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage,
std::size_t previous_size, ReadHandler handler)
: io_service_(io_service),
storage_(storage),
previous_size_(previous_size),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_transferred)
{
storage_.resize(previous_size_ + bytes_transferred);
io_service_.dispatch(detail::bind_handler(
handler_, ec, bytes_transferred));
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
std::size_t previous_size_;
ReadHandler handler_;
};
/// Start an asynchronous fill.
template <typename ReadHandler>
void async_fill(ReadHandler handler)
{
std::size_t previous_size = storage_.size();
storage_.resize(storage_.capacity());
next_layer_.async_read_some(
buffer(
storage_.data() + previous_size,
storage_.size() - previous_size),
fill_handler<ReadHandler>(io_service(),
storage_, previous_size, handler));
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
if (storage_.empty())
fill();
return copy(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.empty() && !fill(ec))
return 0;
return copy(buffers);
}
template <typename MutableBufferSequence, typename ReadHandler>
class read_some_handler
{
public:
read_some_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage,
const MutableBufferSequence& buffers, ReadHandler handler)
: io_service_(io_service),
storage_(storage),
buffers_(buffers),
handler_(handler)
{
}
void operator()(const asio::error_code& ec, std::size_t)
{
if (ec || storage_.empty())
{
std::size_t length = 0;
io_service_.dispatch(detail::bind_handler(handler_, ec, length));
}
else
{
using namespace std; // For memcpy.
std::size_t bytes_avail = storage_.size();
std::size_t bytes_copied = 0;
typename MutableBufferSequence::const_iterator iter = buffers_.begin();
typename MutableBufferSequence::const_iterator end = buffers_.end();
for (; iter != end && bytes_avail > 0; ++iter)
{
std::size_t max_length = buffer_size(*iter);
std::size_t length = (max_length < bytes_avail)
? max_length : bytes_avail;
memcpy(buffer_cast<void*>(*iter),
storage_.data() + bytes_copied, length);
bytes_copied += length;
bytes_avail -= length;
}
storage_.consume(bytes_copied);
io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
}
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
MutableBufferSequence buffers_;
ReadHandler handler_;
};
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
if (storage_.empty())
{
async_fill(read_some_handler<MutableBufferSequence, ReadHandler>(
io_service(), storage_, buffers, handler));
}
else
{
std::size_t length = copy(buffers);
io_service().post(detail::bind_handler(
handler, asio::error_code(), length));
}
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
if (storage_.empty())
fill();
return peek_copy(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.empty() && !fill(ec))
return 0;
return peek_copy(buffers);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return storage_.size();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
ec = asio::error_code();
return storage_.size();
}
private:
/// Copy data out of the internal buffer to the specified target buffer.
/// Returns the number of bytes copied.
template <typename MutableBufferSequence>
std::size_t copy(const MutableBufferSequence& buffers)
{
using namespace std; // For memcpy.
std::size_t bytes_avail = storage_.size();
std::size_t bytes_copied = 0;
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
for (; iter != end && bytes_avail > 0; ++iter)
{
std::size_t max_length = buffer_size(*iter);
std::size_t length = (max_length < bytes_avail)
? max_length : bytes_avail;
memcpy(buffer_cast<void*>(*iter), storage_.data() + bytes_copied, length);
bytes_copied += length;
bytes_avail -= length;
}
storage_.consume(bytes_copied);
return bytes_copied;
}
/// Copy data from the internal buffer to the specified target buffer, without
/// removing the data from the internal buffer. Returns the number of bytes
/// copied.
template <typename MutableBufferSequence>
std::size_t peek_copy(const MutableBufferSequence& buffers)
{
using namespace std; // For memcpy.
std::size_t bytes_avail = storage_.size();
std::size_t bytes_copied = 0;
typename MutableBufferSequence::const_iterator iter = buffers.begin();
typename MutableBufferSequence::const_iterator end = buffers.end();
for (; iter != end && bytes_avail > 0; ++iter)
{
std::size_t max_length = buffer_size(*iter);
std::size_t length = (max_length < bytes_avail)
? max_length : bytes_avail;
memcpy(buffer_cast<void*>(*iter), storage_.data() + bytes_copied, length);
bytes_copied += length;
bytes_avail -= length;
}
return bytes_copied;
}
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_READ_STREAM_HPP

View File

@ -0,0 +1,29 @@
//
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_READ_STREAM_FWD_HPP
#define ASIO_BUFFERED_READ_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
class buffered_read_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP

View File

@ -0,0 +1,243 @@
//
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_STREAM_HPP
#define ASIO_BUFFERED_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Adds buffering to the read- and write-related operations of a stream.
/**
* The buffered_stream class template can be used to add buffering to the
* synchronous and asynchronous read and write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename boost::remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg& a)
: inner_stream_impl_(a),
stream_impl_(inner_stream_impl_)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg& a, std::size_t read_buffer_size,
std::size_t write_buffer_size)
: inner_stream_impl_(a, write_buffer_size),
stream_impl_(inner_stream_impl_, read_buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return stream_impl_.next_layer().next_layer();
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return stream_impl_.lowest_layer();
}
/// Get the io_service associated with the object.
asio::io_service& io_service()
{
return stream_impl_.io_service();
}
/// Close the stream.
void close()
{
stream_impl_.close();
}
/// Close the stream.
asio::error_code close(asio::error_code& ec)
{
return stream_impl_.close(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush()
{
return stream_impl_.next_layer().flush();
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(asio::error_code& ec)
{
return stream_impl_.next_layer().flush(ec);
}
/// Start an asynchronous flush.
template <typename WriteHandler>
void async_flush(WriteHandler handler)
{
return stream_impl_.next_layer().async_flush(handler);
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return stream_impl_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
stream_impl_.async_write_some(buffers, handler);
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill()
{
return stream_impl_.fill();
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(asio::error_code& ec)
{
return stream_impl_.fill(ec);
}
/// Start an asynchronous fill.
template <typename ReadHandler>
void async_fill(ReadHandler handler)
{
stream_impl_.async_fill(handler);
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return stream_impl_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
stream_impl_.async_read_some(buffers, handler);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return stream_impl_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return stream_impl_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
return stream_impl_.in_avail(ec);
}
private:
// The buffered write stream.
typedef buffered_write_stream<Stream> write_stream_type;
write_stream_type inner_stream_impl_;
// The buffered read stream.
typedef buffered_read_stream<write_stream_type&> read_stream_type;
read_stream_type stream_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_STREAM_HPP

View File

@ -0,0 +1,29 @@
//
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_STREAM_FWD_HPP
#define ASIO_BUFFERED_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
class buffered_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_STREAM_FWD_HPP

View File

@ -0,0 +1,361 @@
//
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_WRITE_STREAM_HPP
#define ASIO_BUFFERED_WRITE_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <cstring>
#include <boost/config.hpp>
#include <boost/type_traits.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/write.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
/// Adds buffering to the write-related operations of a stream.
/**
* The buffered_write_stream class template can be used to add buffering to the
* synchronous and asynchronous write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_write_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename boost::remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_write_stream(Arg& a)
: next_layer_(a),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_write_stream(Arg& a, std::size_t buffer_size)
: next_layer_(a),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// Get the io_service associated with the object.
asio::io_service& io_service()
{
return next_layer_.io_service();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
asio::error_code close(asio::error_code& ec)
{
return next_layer_.close(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush()
{
std::size_t bytes_written = write(next_layer_,
buffer(storage_.data(), storage_.size()));
storage_.consume(bytes_written);
return bytes_written;
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(asio::error_code& ec)
{
std::size_t bytes_written = write(next_layer_,
buffer(storage_.data(), storage_.size()),
transfer_all(), ec);
storage_.consume(bytes_written);
return bytes_written;
}
template <typename WriteHandler>
class flush_handler
{
public:
flush_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage, WriteHandler handler)
: io_service_(io_service),
storage_(storage),
handler_(handler)
{
}
void operator()(const asio::error_code& ec,
std::size_t bytes_written)
{
storage_.consume(bytes_written);
io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written));
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
WriteHandler handler_;
};
/// Start an asynchronous flush.
template <typename WriteHandler>
void async_flush(WriteHandler handler)
{
async_write(next_layer_, buffer(storage_.data(), storage_.size()),
flush_handler<WriteHandler>(io_service(), storage_, handler));
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
if (storage_.size() == storage_.capacity())
flush();
return copy(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred and the error handler did not throw.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
ec = asio::error_code();
if (storage_.size() == storage_.capacity() && !flush(ec))
return 0;
return copy(buffers);
}
template <typename ConstBufferSequence, typename WriteHandler>
class write_some_handler
{
public:
write_some_handler(asio::io_service& io_service,
detail::buffered_stream_storage& storage,
const ConstBufferSequence& buffers, WriteHandler handler)
: io_service_(io_service),
storage_(storage),
buffers_(buffers),
handler_(handler)
{
}
void operator()(const asio::error_code& ec, std::size_t)
{
if (ec)
{
std::size_t length = 0;
io_service_.dispatch(detail::bind_handler(handler_, ec, length));
}
else
{
using namespace std; // For memcpy.
std::size_t orig_size = storage_.size();
std::size_t space_avail = storage_.capacity() - orig_size;
std::size_t bytes_copied = 0;
typename ConstBufferSequence::const_iterator iter = buffers_.begin();
typename ConstBufferSequence::const_iterator end = buffers_.end();
for (; iter != end && space_avail > 0; ++iter)
{
std::size_t bytes_avail = buffer_size(*iter);
std::size_t length = (bytes_avail < space_avail)
? bytes_avail : space_avail;
storage_.resize(orig_size + bytes_copied + length);
memcpy(storage_.data() + orig_size + bytes_copied,
buffer_cast<const void*>(*iter), length);
bytes_copied += length;
space_avail -= length;
}
io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
}
}
private:
asio::io_service& io_service_;
detail::buffered_stream_storage& storage_;
ConstBufferSequence buffers_;
WriteHandler handler_;
};
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some(const ConstBufferSequence& buffers,
WriteHandler handler)
{
if (storage_.size() == storage_.capacity())
{
async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
io_service(), storage_, buffers, handler));
}
else
{
std::size_t bytes_copied = copy(buffers);
io_service().post(detail::bind_handler(
handler, asio::error_code(), bytes_copied));
}
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return next_layer_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some(const MutableBufferSequence& buffers,
ReadHandler handler)
{
next_layer_.async_read_some(buffers, handler);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return next_layer_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return next_layer_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
return next_layer_.in_avail(ec);
}
private:
/// Copy data into the internal buffer from the specified source buffer.
/// Returns the number of bytes copied.
template <typename ConstBufferSequence>
std::size_t copy(const ConstBufferSequence& buffers)
{
using namespace std; // For memcpy.
std::size_t orig_size = storage_.size();
std::size_t space_avail = storage_.capacity() - orig_size;
std::size_t bytes_copied = 0;
typename ConstBufferSequence::const_iterator iter = buffers.begin();
typename ConstBufferSequence::const_iterator end = buffers.end();
for (; iter != end && space_avail > 0; ++iter)
{
std::size_t bytes_avail = buffer_size(*iter);
std::size_t length = (bytes_avail < space_avail)
? bytes_avail : space_avail;
storage_.resize(orig_size + bytes_copied + length);
memcpy(storage_.data() + orig_size + bytes_copied,
buffer_cast<const void*>(*iter), length);
bytes_copied += length;
space_avail -= length;
}
return bytes_copied;
}
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_WRITE_STREAM_HPP

View File

@ -0,0 +1,29 @@
//
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename Stream>
class buffered_write_stream;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP

View File

@ -0,0 +1,101 @@
//
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_COMPLETION_CONDITION_HPP
#define ASIO_COMPLETION_CONDITION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class transfer_all_t
{
public:
typedef bool result_type;
template <typename Error>
bool operator()(const Error& err, std::size_t)
{
return !!err;
}
};
class transfer_at_least_t
{
public:
typedef bool result_type;
explicit transfer_at_least_t(std::size_t minimum)
: minimum_(minimum)
{
}
template <typename Error>
bool operator()(const Error& err, std::size_t bytes_transferred)
{
return !!err || bytes_transferred >= minimum_;
}
private:
std::size_t minimum_;
};
} // namespace detail
/**
* @defgroup completion_condition Completion Condition Function Objects
*
* Function objects used for determining when a read or write operation should
* complete.
*/
/*@{*/
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until all of the data has been transferred,
/// or until an error occurs.
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_all();
#else
inline detail::transfer_all_t transfer_all()
{
return detail::transfer_all_t();
}
#endif
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until a minimum number of bytes has been
/// transferred, or until an error occurs.
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_at_least(std::size_t minimum);
#else
inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)
{
return detail::transfer_at_least_t(minimum);
}
#endif
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_COMPLETION_CONDITION_HPP

View File

@ -0,0 +1,320 @@
//
// datagram_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DATAGRAM_SOCKET_SERVICE_HPP
#define ASIO_DATAGRAM_SOCKET_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/select_reactor.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/reactive_socket_service.hpp"
#include "asio/detail/win_iocp_socket_service.hpp"
namespace asio {
/// Default service implementation for a datagram socket.
template <typename Protocol>
class datagram_socket_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<datagram_socket_service<Protocol> >
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::reactive_socket_service<
Protocol, detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::reactive_socket_service<
Protocol, detail::kqueue_reactor<false> > service_impl_type;
#else
typedef detail::reactive_socket_service<
Protocol, detail::select_reactor<false> > service_impl_type;
#endif
public:
/// The type of a datagram socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif
/// The native socket type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_type;
#else
typedef typename service_impl_type::native_type native_type;
#endif
/// Construct a new datagram socket service for the specified io_service.
explicit datagram_socket_service(asio::io_service& io_service)
: asio::detail::service_base<
datagram_socket_service<Protocol> >(io_service),
service_impl_(asio::use_service<service_impl_type>(io_service))
{
}
/// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
/// Construct a new datagram socket implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a datagram socket implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
// Open a new datagram socket implementation.
asio::error_code open(implementation_type& impl,
const protocol_type& protocol, asio::error_code& ec)
{
if (protocol.type() == SOCK_DGRAM)
service_impl_.open(impl, protocol, ec);
else
ec = asio::error::invalid_argument;
return ec;
}
/// Assign an existing native socket to a datagram socket.
asio::error_code assign(implementation_type& impl,
const protocol_type& protocol, const native_type& native_socket,
asio::error_code& ec)
{
return service_impl_.assign(impl, protocol, native_socket, ec);
}
/// Determine whether the socket is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}
/// Close a datagram socket implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}
/// Get the native socket implementation.
native_type native(implementation_type& impl)
{
return service_impl_.native(impl);
}
/// Cancel all asynchronous operations associated with the socket.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Determine whether the socket is at the out-of-band data mark.
bool at_mark(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.at_mark(impl, ec);
}
/// Determine the number of bytes available for reading.
std::size_t available(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.available(impl, ec);
}
// Bind the datagram socket to the specified local endpoint.
asio::error_code bind(implementation_type& impl,
const endpoint_type& endpoint, asio::error_code& ec)
{
return service_impl_.bind(impl, endpoint, ec);
}
/// Connect the datagram socket to the specified endpoint.
asio::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, asio::error_code& ec)
{
return service_impl_.connect(impl, peer_endpoint, ec);
}
/// Start an asynchronous connect.
template <typename ConnectHandler>
void async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint, ConnectHandler handler)
{
service_impl_.async_connect(impl, peer_endpoint, handler);
}
/// Set a socket option.
template <typename SettableSocketOption>
asio::error_code set_option(implementation_type& impl,
const SettableSocketOption& option, asio::error_code& ec)
{
return service_impl_.set_option(impl, option, ec);
}
/// Get a socket option.
template <typename GettableSocketOption>
asio::error_code get_option(const implementation_type& impl,
GettableSocketOption& option, asio::error_code& ec) const
{
return service_impl_.get_option(impl, option, ec);
}
/// Perform an IO control command on the socket.
template <typename IoControlCommand>
asio::error_code io_control(implementation_type& impl,
IoControlCommand& command, asio::error_code& ec)
{
return service_impl_.io_control(impl, command, ec);
}
/// Get the local endpoint.
endpoint_type local_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.local_endpoint(impl, ec);
}
/// Get the remote endpoint.
endpoint_type remote_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.remote_endpoint(impl, ec);
}
/// Disable sends or receives on the socket.
asio::error_code shutdown(implementation_type& impl,
socket_base::shutdown_type what, asio::error_code& ec)
{
return service_impl_.shutdown(impl, what, ec);
}
/// Send the given data to the peer.
template <typename ConstBufferSequence>
std::size_t send(implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.send(impl, buffers, flags, ec);
}
/// Start an asynchronous send.
template <typename ConstBufferSequence, typename WriteHandler>
void async_send(implementation_type& impl, const ConstBufferSequence& buffers,
socket_base::message_flags flags, WriteHandler handler)
{
service_impl_.async_send(impl, buffers, flags, handler);
}
/// Send a datagram to the specified endpoint.
template <typename ConstBufferSequence>
std::size_t send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.send_to(impl, buffers, destination, flags, ec);
}
/// Start an asynchronous send.
template <typename ConstBufferSequence, typename WriteHandler>
void async_send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, WriteHandler handler)
{
service_impl_.async_send_to(impl, buffers, destination, flags, handler);
}
/// Receive some data from the peer.
template <typename MutableBufferSequence>
std::size_t receive(implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.receive(impl, buffers, flags, ec);
}
/// Start an asynchronous receive.
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive(implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, ReadHandler handler)
{
service_impl_.async_receive(impl, buffers, flags, handler);
}
/// Receive a datagram with the endpoint of the sender.
template <typename MutableBufferSequence>
std::size_t receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.receive_from(impl, buffers, sender_endpoint, flags,
ec);
}
/// Start an asynchronous receive that will get the endpoint of the sender.
template <typename MutableBufferSequence, typename ReadHandler>
void async_receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags, ReadHandler handler)
{
service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags,
handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DATAGRAM_SOCKET_SERVICE_HPP

View File

@ -0,0 +1,37 @@
//
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DEADLINE_TIMER_HPP
#define ASIO_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/basic_deadline_timer.hpp"
namespace asio {
/// Typedef for the typical usage of timer.
typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DEADLINE_TIMER_HPP

View File

@ -0,0 +1,164 @@
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DEADLINE_TIMER_SERVICE_HPP
#define ASIO_DEADLINE_TIMER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/time_traits.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/select_reactor.hpp"
#include "asio/detail/service_base.hpp"
namespace asio {
/// Default service implementation for a timer.
template <typename TimeType,
typename TimeTraits = asio::time_traits<TimeType> >
class deadline_timer_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_service::service
#else
: public asio::detail::service_base<
deadline_timer_service<TimeType, TimeTraits> >
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_service::id id;
#endif
/// The time traits type.
typedef TimeTraits traits_type;
/// The time type.
typedef typename traits_type::time_type time_type;
/// The duration type.
typedef typename traits_type::duration_type duration_type;
private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::deadline_timer_service<
traits_type, detail::select_reactor<true> > service_impl_type;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::deadline_timer_service<
traits_type, detail::epoll_reactor<false> > service_impl_type;
#elif defined(ASIO_HAS_KQUEUE)
typedef detail::deadline_timer_service<
traits_type, detail::kqueue_reactor<false> > service_impl_type;
#else
typedef detail::deadline_timer_service<
traits_type, detail::select_reactor<false> > service_impl_type;
#endif
public:
/// The implementation type of the deadline timer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif
/// Construct a new timer service for the specified io_service.
explicit deadline_timer_service(asio::io_service& io_service)
: asio::detail::service_base<
deadline_timer_service<TimeType, TimeTraits> >(io_service),
service_impl_(asio::use_service<service_impl_type>(io_service))
{
}
/// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
/// Construct a new timer implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}
/// Destroy a timer implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}
/// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}
/// Get the expiry time for the timer as an absolute time.
time_type expires_at(const implementation_type& impl) const
{
return service_impl_.expires_at(impl);
}
/// Set the expiry time for the timer as an absolute time.
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
return service_impl_.expires_at(impl, expiry_time, ec);
}
/// Get the expiry time for the timer relative to now.
duration_type expires_from_now(const implementation_type& impl) const
{
return service_impl_.expires_from_now(impl);
}
/// Set the expiry time for the timer relative to now.
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return service_impl_.expires_from_now(impl, expiry_time, ec);
}
// Perform a blocking wait on the timer.
void wait(implementation_type& impl, asio::error_code& ec)
{
service_impl_.wait(impl, ec);
}
// Start an asynchronous wait on the timer.
template <typename WaitHandler>
void async_wait(implementation_type& impl, WaitHandler handler)
{
service_impl_.async_wait(impl, handler);
}
private:
// The service that provides the platform-specific implementation.
service_impl_type& service_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DEADLINE_TIMER_SERVICE_HPP

View File

@ -0,0 +1,349 @@
//
// bind_handler.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_BIND_HANDLER_HPP
#define ASIO_DETAIL_BIND_HANDLER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
namespace asio {
namespace detail {
template <typename Handler, typename Arg1>
class binder1
{
public:
binder1(const Handler& handler, const Arg1& arg1)
: handler_(handler),
arg1_(arg1)
{
}
void operator()()
{
handler_(arg1_);
}
void operator()() const
{
handler_(arg1_);
}
//private:
Handler handler_;
Arg1 arg1_;
};
template <typename Handler, typename Arg1>
inline void* asio_handler_allocate(std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1>
inline void asio_handler_invoke(const Function& function,
binder1<Handler, Arg1>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline binder1<Handler, Arg1> bind_handler(const Handler& handler,
const Arg1& arg1)
{
return binder1<Handler, Arg1>(handler, arg1);
}
template <typename Handler, typename Arg1, typename Arg2>
class binder2
{
public:
binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2)
: handler_(handler),
arg1_(arg1),
arg2_(arg2)
{
}
void operator()()
{
handler_(arg1_, arg2_);
}
void operator()() const
{
handler_(arg1_, arg2_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
};
template <typename Handler, typename Arg1, typename Arg2>
inline void* asio_handler_allocate(std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1, typename Arg2>
inline void asio_handler_invoke(const Function& function,
binder2<Handler, Arg1, Arg2>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline binder2<Handler, Arg1, Arg2> bind_handler(const Handler& handler,
const Arg1& arg1, const Arg2& arg2)
{
return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
class binder3
{
public:
binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void* asio_handler_allocate(std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1, typename Arg2,
typename Arg3>
inline void asio_handler_invoke(const Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(const Handler& handler,
const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
{
return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
class binder4
{
public:
binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
inline void* asio_handler_allocate(std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4>
inline void asio_handler_invoke(const Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4>
inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(
const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4)
{
return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,
arg4);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
class binder5
{
public:
binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(handler),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}
void operator()()
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
Arg5 arg5_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
inline void* asio_handler_allocate(std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, &this_handler->handler_);
}
template <typename Function, typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(const Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, &this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5>
inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(
const Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
{
return binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
arg3, arg4, arg5);
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BIND_HANDLER_HPP

View File

@ -0,0 +1,70 @@
//
// buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <limits>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
// Helper class to manage buffer resizing in an exception safe way.
template <typename Buffer>
class buffer_resize_guard
{
public:
// Constructor.
buffer_resize_guard(Buffer& buffer)
: buffer_(buffer),
old_size_(buffer.size())
{
}
// Destructor rolls back the buffer resize unless commit was called.
~buffer_resize_guard()
{
if (old_size_
!= std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
{
buffer_.resize(old_size_);
}
}
// Commit the resize transaction.
void commit()
{
old_size_
= std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION();
}
private:
// The buffer being managed.
Buffer& buffer_;
// The size of the buffer at the time the guard was constructed.
size_t old_size_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP

View File

@ -0,0 +1,127 @@
//
// buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <vector>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class buffered_stream_storage
{
public:
// The type of the bytes stored in the buffer.
typedef unsigned char byte_type;
// The type used for offsets into the buffer.
typedef std::size_t size_type;
// Constructor.
explicit buffered_stream_storage(std::size_t capacity)
: begin_offset_(0),
end_offset_(0),
buffer_(capacity)
{
}
/// Clear the buffer.
void clear()
{
begin_offset_ = 0;
end_offset_ = 0;
}
// Return a pointer to the beginning of the unread data.
byte_type* data()
{
return &buffer_[0] + begin_offset_;
}
// Return a pointer to the beginning of the unread data.
const byte_type* data() const
{
return &buffer_[0] + begin_offset_;
}
// Is there no unread data in the buffer.
bool empty() const
{
return begin_offset_ == end_offset_;
}
// Return the amount of unread data the is in the buffer.
size_type size() const
{
return end_offset_ - begin_offset_;
}
// Resize the buffer to the specified length.
void resize(size_type length)
{
assert(length <= capacity());
if (begin_offset_ + length <= capacity())
{
end_offset_ = begin_offset_ + length;
}
else
{
using namespace std; // For memmove.
memmove(&buffer_[0], &buffer_[0] + begin_offset_, size());
end_offset_ = length;
begin_offset_ = 0;
}
}
// Return the maximum size for data in the buffer.
size_type capacity() const
{
return buffer_.size();
}
// Consume multiple bytes from the beginning of the buffer.
void consume(size_type count)
{
assert(begin_offset_ + count <= end_offset_);
begin_offset_ += count;
if (empty())
clear();
}
private:
// The offset to the beginning of the unread data.
size_type begin_offset_;
// The offset to the end of the unread data.
size_type end_offset_;
// The data in the buffer.
std::vector<byte_type> buffer_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP

View File

@ -0,0 +1,90 @@
//
// call_stack.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_CALL_STACK_HPP
#define ASIO_DETAIL_CALL_STACK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/tss_ptr.hpp"
namespace asio {
namespace detail {
// Helper class to determine whether or not the current thread is inside an
// invocation of io_service::run() for a specified io_service object.
template <typename Owner>
class call_stack
{
public:
// Context class automatically pushes an owner on to the stack.
class context
: private noncopyable
{
public:
// Push the owner on to the stack.
explicit context(Owner* d)
: owner_(d),
next_(call_stack<Owner>::top_)
{
call_stack<Owner>::top_ = this;
}
// Pop the owner from the stack.
~context()
{
call_stack<Owner>::top_ = next_;
}
private:
friend class call_stack<Owner>;
// The owner associated with the context.
Owner* owner_;
// The next element in the stack.
context* next_;
};
friend class context;
// Determine whether the specified owner is on the stack.
static bool contains(Owner* d)
{
context* elem = top_;
while (elem)
{
if (elem->owner_ == d)
return true;
elem = elem->next_;
}
return false;
}
private:
// The top of the stack of calls for the current thread.
static tss_ptr<context> top_;
};
template <typename Owner>
tss_ptr<typename call_stack<Owner>::context>
call_stack<Owner>::top_;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CALL_STACK_HPP

View File

@ -0,0 +1,151 @@
//
// const_buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
#define ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
namespace asio {
namespace detail {
// A proxy iterator for a sub-range in a list of buffers.
template <typename ConstBufferSequence>
class const_buffers_iterator
: public boost::iterator_facade<const_buffers_iterator<ConstBufferSequence>,
const char, boost::bidirectional_traversal_tag>
{
public:
// Default constructor creates an iterator in an undefined state.
const_buffers_iterator()
{
}
// Create an iterator for the specified position.
const_buffers_iterator(const ConstBufferSequence& buffers,
std::size_t position)
: begin_(buffers.begin()),
current_(buffers.begin()),
end_(buffers.end()),
position_(0)
{
while (current_ != end_)
{
current_buffer_ = *current_;
std::size_t buffer_size = asio::buffer_size(current_buffer_);
if (position - position_ < buffer_size)
{
current_buffer_position_ = position - position_;
position_ = position;
return;
}
position_ += buffer_size;
++current_;
}
current_buffer_ = asio::const_buffer();
current_buffer_position_ = 0;
}
std::size_t position() const
{
return position_;
}
private:
friend class boost::iterator_core_access;
void increment()
{
if (current_ == end_)
return;
++position_;
++current_buffer_position_;
if (current_buffer_position_ != asio::buffer_size(current_buffer_))
return;
++current_;
current_buffer_position_ = 0;
while (current_ != end_)
{
current_buffer_ = *current_;
if (asio::buffer_size(current_buffer_) > 0)
return;
++current_;
}
}
void decrement()
{
if (position_ == 0)
return;
--position_;
if (current_buffer_position_ != 0)
{
--current_buffer_position_;
return;
}
typename ConstBufferSequence::const_iterator iter = current_;
while (iter != begin_)
{
--iter;
asio::const_buffer buffer = *iter;
std::size_t buffer_size = asio::buffer_size(buffer);
if (buffer_size > 0)
{
current_ = iter;
current_buffer_ = buffer;
current_buffer_position_ = buffer_size - 1;
return;
}
}
}
bool equal(const const_buffers_iterator& other) const
{
return position_ == other.position_;
}
const char& dereference() const
{
return asio::buffer_cast<const char*>(
current_buffer_)[current_buffer_position_];
}
asio::const_buffer current_buffer_;
std::size_t current_buffer_position_;
typename ConstBufferSequence::const_iterator begin_;
typename ConstBufferSequence::const_iterator current_;
typename ConstBufferSequence::const_iterator end_;
std::size_t position_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP

View File

@ -0,0 +1,205 @@
//
// consuming_buffers.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP
#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <cstddef>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
// A proxy iterator for a sub-range in a list of buffers.
template <typename Buffer, typename Buffer_Iterator>
class consuming_buffers_iterator
: public boost::iterator_facade<
consuming_buffers_iterator<Buffer, Buffer_Iterator>,
const Buffer, boost::forward_traversal_tag>
{
public:
// Default constructor creates an end iterator.
consuming_buffers_iterator()
: at_end_(true)
{
}
// Construct with a buffer for the first entry and an iterator
// range for the remaining entries.
consuming_buffers_iterator(bool at_end, const Buffer& first,
Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder)
: at_end_(at_end),
first_(buffer(first, max_size)),
begin_remainder_(begin_remainder),
end_remainder_(end_remainder),
offset_(0)
{
}
private:
friend class boost::iterator_core_access;
enum { max_size = 65536 };
void increment()
{
if (!at_end_)
{
if (begin_remainder_ == end_remainder_
|| offset_ + buffer_size(first_) >= max_size)
{
at_end_ = true;
}
else
{
offset_ += buffer_size(first_);
first_ = buffer(*begin_remainder_++, max_size - offset_);
}
}
}
bool equal(const consuming_buffers_iterator& other) const
{
if (at_end_ && other.at_end_)
return true;
return !at_end_ && !other.at_end_
&& buffer_cast<const void*>(first_)
== buffer_cast<const void*>(other.first_)
&& buffer_size(first_) == buffer_size(other.first_)
&& begin_remainder_ == other.begin_remainder_
&& end_remainder_ == other.end_remainder_;
}
const Buffer& dereference() const
{
return first_;
}
bool at_end_;
Buffer first_;
Buffer_Iterator begin_remainder_;
Buffer_Iterator end_remainder_;
std::size_t offset_;
};
// A proxy for a sub-range in a list of buffers.
template <typename Buffer, typename Buffers>
class consuming_buffers
{
public:
// The type for each element in the list of buffers.
typedef Buffer value_type;
// A forward-only iterator type that may be used to read elements.
typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
const_iterator;
// Construct to represent the entire list of buffers.
consuming_buffers(const Buffers& buffers)
: buffers_(buffers),
at_end_(buffers_.begin() == buffers_.end()),
first_(*buffers_.begin()),
begin_remainder_(buffers_.begin())
{
if (!at_end_)
++begin_remainder_;
}
// Copy constructor.
consuming_buffers(const consuming_buffers& other)
: buffers_(other.buffers_),
at_end_(other.at_end_),
first_(other.first_),
begin_remainder_(buffers_.begin())
{
typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_;
std::advance(begin_remainder_, std::distance(first, second));
}
// Assignment operator.
consuming_buffers& operator=(const consuming_buffers& other)
{
buffers_ = other.buffers_;
at_end_ = other.at_end_;
first_ = other.first_;
begin_remainder_ = buffers_.begin();
typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_;
std::advance(begin_remainder_, std::distance(first, second));
return *this;
}
// Get a forward-only iterator to the first element.
const_iterator begin() const
{
return const_iterator(at_end_, first_, begin_remainder_, buffers_.end());
}
// Get a forward-only iterator for one past the last element.
const_iterator end() const
{
return const_iterator();
}
// Consume the specified number of bytes from the buffers.
void consume(std::size_t size)
{
// Remove buffers from the start until the specified size is reached.
while (size > 0 && !at_end_)
{
if (buffer_size(first_) <= size)
{
size -= buffer_size(first_);
if (begin_remainder_ == buffers_.end())
at_end_ = true;
else
first_ = *begin_remainder_++;
}
else
{
first_ = first_ + size;
size = 0;
}
}
// Remove any more empty buffers at the start.
while (!at_end_ && buffer_size(first_) == 0)
{
if (begin_remainder_ == buffers_.end())
at_end_ = true;
else
first_ = *begin_remainder_++;
}
}
private:
Buffers buffers_;
bool at_end_;
Buffer first_;
typename Buffers::const_iterator begin_remainder_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP

View File

@ -0,0 +1,199 @@
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits, typename Timer_Scheduler>
class deadline_timer_service
: public asio::detail::service_base<
deadline_timer_service<Time_Traits, Timer_Scheduler> >
{
public:
// The time type.
typedef typename Time_Traits::time_type time_type;
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
// The implementation type of the timer. This type is dependent on the
// underlying implementation of the timer service.
struct implementation_type
: private asio::detail::noncopyable
{
time_type expiry;
bool might_have_pending_waits;
};
// Constructor.
deadline_timer_service(asio::io_service& io_service)
: asio::detail::service_base<
deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
scheduler_(asio::use_service<Timer_Scheduler>(io_service))
{
scheduler_.add_timer_queue(timer_queue_);
}
// Destructor.
~deadline_timer_service()
{
scheduler_.remove_timer_queue(timer_queue_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
}
// Construct a new timer implementation.
void construct(implementation_type& impl)
{
impl.expiry = time_type();
impl.might_have_pending_waits = false;
}
// Destroy a timer implementation.
void destroy(implementation_type& impl)
{
asio::error_code ec;
cancel(impl, ec);
}
// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{
if (!impl.might_have_pending_waits)
{
ec = asio::error_code();
return 0;
}
std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
impl.might_have_pending_waits = false;
ec = asio::error_code();
return count;
}
// Get the expiry time for the timer as an absolute time.
time_type expires_at(const implementation_type& impl) const
{
return impl.expiry;
}
// Set the expiry time for the timer as an absolute time.
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
std::size_t count = cancel(impl, ec);
impl.expiry = expiry_time;
ec = asio::error_code();
return count;
}
// Get the expiry time for the timer relative to now.
duration_type expires_from_now(const implementation_type& impl) const
{
return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
}
// Set the expiry time for the timer relative to now.
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return expires_at(impl,
Time_Traits::add(Time_Traits::now(), expiry_time), ec);
}
// Perform a blocking wait on the timer.
void wait(implementation_type& impl, asio::error_code& ec)
{
time_type now = Time_Traits::now();
while (Time_Traits::less_than(now, impl.expiry))
{
boost::posix_time::time_duration timeout =
Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now));
::timeval tv;
tv.tv_sec = timeout.total_seconds();
tv.tv_usec = timeout.total_microseconds() % 1000000;
asio::error_code ec;
socket_ops::select(0, 0, 0, 0, &tv, ec);
now = Time_Traits::now();
}
ec = asio::error_code();
}
template <typename Handler>
class wait_handler
{
public:
wait_handler(asio::io_service& io_service, Handler handler)
: io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()(const asio::error_code& result)
{
io_service_.post(detail::bind_handler(handler_, result));
}
private:
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Start an asynchronous wait on the timer.
template <typename Handler>
void async_wait(implementation_type& impl, Handler handler)
{
impl.might_have_pending_waits = true;
scheduler_.schedule_timer(timer_queue_, impl.expiry,
wait_handler<Handler>(this->io_service(), handler), &impl);
}
private:
// The queue of timers.
timer_queue<Time_Traits> timer_queue_;
// The object that schedules and executes timers. Usually a reactor.
Timer_Scheduler& scheduler_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP

View File

@ -0,0 +1,613 @@
//
// epoll_reactor.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_EPOLL_REACTOR_HPP
#define ASIO_DETAIL_EPOLL_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/epoll_reactor_fwd.hpp"
#if defined(ASIO_HAS_EPOLL)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <sys/epoll.h>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class epoll_reactor
: public asio::detail::service_base<epoll_reactor<Own_Thread> >
{
public:
// Constructor.
epoll_reactor(asio::io_service& io_service)
: asio::detail::service_base<epoll_reactor<Own_Thread> >(io_service),
mutex_(),
epoll_fd_(do_epoll_create()),
wait_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
{
// Start the reactor's internal thread only if needed.
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&epoll_reactor::call_run_thread, this));
}
// Add the interrupter's descriptor to epoll.
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR;
ev.data.fd = interrupter_.read_descriptor();
epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
}
// Destructor.
~epoll_reactor()
{
shutdown_service();
close(epoll_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
{
// No need to lock according to epoll documentation.
epoll_event ev = { 0, { 0 } };
ev.events = 0;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
if (result != 0)
return errno;
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
if (write_op_queue_.has_operation(descriptor))
ev.events |= EPOLLOUT;
if (except_op_queue_.has_operation(descriptor))
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno, asio::native_ecat);
read_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= EPOLLIN;
if (except_op_queue_.has_operation(descriptor))
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno, asio::native_ecat);
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= EPOLLIN;
if (write_op_queue_.has_operation(descriptor))
ev.events |= EPOLLOUT;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno, asio::native_ecat);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler);
need_mod = except_op_queue_.enqueue_operation(descriptor, handler)
&& need_mod;
if (need_mod)
{
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP;
if (read_op_queue_.has_operation(descriptor))
ev.events |= EPOLLIN;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0)
{
asio::error_code ec(errno, asio::native_ecat);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// epoll_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from epoll.
epoll_event ev = { 0, { 0 } };
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
timer_queues_.push_back(&timer_queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
if (timer_queues_[i] == &timer_queue)
{
timer_queues_.erase(timer_queues_.begin() + i);
return;
}
}
}
// Schedule a timer in the given timer queue to expire at the specified
// absolute time. The handler object will be invoked when the timer expires.
template <typename Time_Traits, typename Handler>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
return timer_queue.cancel_timer(token);
}
private:
friend class task_io_service<epoll_reactor<Own_Thread> >;
// Run epoll once until interrupted or events are ready to be dispatched.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
return;
}
int timeout = block ? get_timeout() : 0;
wait_in_progress_ = true;
lock.unlock();
// Block on the epoll descriptor.
epoll_event events[128];
int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].data.fd;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else
{
if (events[i].events & (EPOLLERR | EPOLLHUP))
{
asio::error_code ec;
except_op_queue_.dispatch_all_operations(descriptor, ec);
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
epoll_event ev = { 0, { 0 } };
ev.events = 0;
ev.data.fd = descriptor;
epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
}
else
{
bool more_reads = false;
bool more_writes = false;
bool more_except = false;
asio::error_code ec;
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
if (events[i].events & EPOLLPRI)
more_except = except_op_queue_.dispatch_operation(descriptor, ec);
else
more_except = except_op_queue_.has_operation(descriptor);
if (events[i].events & EPOLLIN)
more_reads = read_op_queue_.dispatch_operation(descriptor, ec);
else
more_reads = read_op_queue_.has_operation(descriptor);
if (events[i].events & EPOLLOUT)
more_writes = write_op_queue_.dispatch_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
epoll_event ev = { 0, { 0 } };
ev.events = EPOLLERR | EPOLLHUP;
if (more_reads)
ev.events |= EPOLLIN;
if (more_writes)
ev.events |= EPOLLOUT;
if (more_except)
ev.events |= EPOLLPRI;
ev.data.fd = descriptor;
int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
if (result != 0)
{
ec = asio::error_code(errno, asio::native_ecat);
read_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_timers();
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(epoll_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// The hint to pass to epoll_create to size its data structures.
enum { epoll_size = 20000 };
// Create the epoll file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_epoll_create()
{
int fd = epoll_create(epoll_size);
if (fd == -1)
{
boost::throw_exception(asio::system_error(
asio::error_code(errno, asio::native_ecat),
"epoll"));
}
return fd;
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the epoll_wait call. The timeout value is
// returned as a number of milliseconds. A return value of -1 indicates
// that epoll_wait should block indefinitely.
int get_timeout()
{
if (all_timer_queues_are_empty())
return -1;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
return minimum_wait_duration.total_milliseconds();
}
else
{
return 0;
}
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the epoll_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The epoll file descriptor.
int epoll_fd_;
// Whether the epoll_wait call is currently in progress
bool wait_in_progress_;
// The interrupter is used to break a blocking epoll_wait call.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_EPOLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP

View File

@ -0,0 +1,44 @@
//
// epoll_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
#define ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#if !defined(ASIO_DISABLE_EPOLL)
#if defined(__linux__) // This service is only supported on Linux.
#include "asio/detail/push_options.hpp"
#include <linux/version.h>
#include "asio/detail/pop_options.hpp"
// Define this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_EPOLL 1
namespace asio {
namespace detail {
template <bool Own_Thread>
class epoll_reactor;
} // namespace detail
} // namespace asio
#endif // defined(__linux__)
#endif // !defined(ASIO_DISABLE_EPOLL)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP

View File

@ -0,0 +1,50 @@
//
// event.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_EVENT_HPP
#define ASIO_DETAIL_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_event.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_event.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_event.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_event event;
#elif defined(BOOST_WINDOWS)
typedef win_event event;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_event event;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_EVENT_HPP

View File

@ -0,0 +1,41 @@
//
// fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_FD_SET_ADAPTER_HPP
#define ASIO_DETAIL_FD_SET_ADAPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/posix_fd_set_adapter.hpp"
#include "asio/detail/win_fd_set_adapter.hpp"
namespace asio {
namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef win_fd_set_adapter fd_set_adapter;
#else
typedef posix_fd_set_adapter fd_set_adapter;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP

View File

@ -0,0 +1,256 @@
//
// handler_alloc_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/detail/noncopyable.hpp"
// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
// a namespace that does not contain any overloads of these functions. The
// asio_handler_alloc_helpers namespace is defined here for that purpose.
namespace asio_handler_alloc_helpers {
template <typename Handler>
inline void* allocate(std::size_t s, Handler* h)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
return ::operator new(s);
#else
using namespace asio;
return asio_handler_allocate(s, h);
#endif
}
template <typename Handler>
inline void deallocate(void* p, std::size_t s, Handler* h)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
::operator delete(p);
#else
using namespace asio;
asio_handler_deallocate(p, s, h);
#endif
}
} // namespace asio_handler_alloc_helpers
namespace asio {
namespace detail {
// Traits for handler allocation.
template <typename Handler, typename Object>
struct handler_alloc_traits
{
typedef Handler handler_type;
typedef Object value_type;
typedef Object* pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
};
template <typename Alloc_Traits>
class handler_ptr;
// Helper class to provide RAII on uninitialised handler memory.
template <typename Alloc_Traits>
class raw_handler_ptr
: private noncopyable
{
public:
typedef typename Alloc_Traits::handler_type handler_type;
typedef typename Alloc_Traits::value_type value_type;
typedef typename Alloc_Traits::pointer_type pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
// Constructor allocates the memory.
raw_handler_ptr(handler_type& handler)
: handler_(handler),
pointer_(static_cast<pointer_type>(
asio_handler_alloc_helpers::allocate(value_size, &handler_)))
{
}
// Destructor automatically deallocates memory, unless it has been stolen by
// a handler_ptr object.
~raw_handler_ptr()
{
if (pointer_)
asio_handler_alloc_helpers::deallocate(
pointer_, value_size, &handler_);
}
private:
friend class handler_ptr<Alloc_Traits>;
handler_type& handler_;
pointer_type pointer_;
};
// Helper class to provide RAII on uninitialised handler memory.
template <typename Alloc_Traits>
class handler_ptr
: private noncopyable
{
public:
typedef typename Alloc_Traits::handler_type handler_type;
typedef typename Alloc_Traits::value_type value_type;
typedef typename Alloc_Traits::pointer_type pointer_type;
BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
// Take ownership of existing memory.
handler_ptr(handler_type& handler, pointer_type pointer)
: handler_(handler),
pointer_(pointer)
{
}
// Construct object in raw memory and take ownership if construction succeeds.
handler_ptr(raw_ptr_type& raw_ptr)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type)
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6, Arg7& a7)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
{
raw_ptr.pointer_ = 0;
}
// Construct object in raw memory and take ownership if construction succeeds.
template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7, typename Arg8>
handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
: handler_(raw_ptr.handler_),
pointer_(new (raw_ptr.pointer_) value_type(
a1, a2, a3, a4, a5, a6, a7, a8))
{
raw_ptr.pointer_ = 0;
}
// Destructor automatically deallocates memory, unless it has been released.
~handler_ptr()
{
reset();
}
// Get the memory.
pointer_type get() const
{
return pointer_;
}
// Release ownership of the memory.
pointer_type release()
{
pointer_type tmp = pointer_;
pointer_ = 0;
return tmp;
}
// Explicitly destroy and deallocate the memory.
void reset()
{
if (pointer_)
{
pointer_->value_type::~value_type();
asio_handler_alloc_helpers::deallocate(
pointer_, value_size, &handler_);
pointer_ = 0;
}
}
private:
handler_type& handler_;
pointer_type pointer_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP

View File

@ -0,0 +1,47 @@
//
// handler_invoke_helpers.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/handler_invoke_hook.hpp"
// Calls to asio_handler_invoke must be made from a namespace that does not
// contain overloads of this function. The asio_handler_invoke_helpers
// namespace is defined here for that purpose.
namespace asio_handler_invoke_helpers {
template <typename Function, typename Context>
inline void invoke(const Function& function, Context* context)
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
Function tmp(function);
tmp();
#else
using namespace asio;
asio_handler_invoke(function, context);
#endif
}
} // namespace asio_handler_invoke_helpers
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP

View File

@ -0,0 +1,209 @@
//
// hash_map.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_HASH_MAP_HPP
#define ASIO_DETAIL_HASH_MAP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cassert>
#include <list>
#include <utility>
#include <boost/functional/hash.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
template <typename T>
inline std::size_t calculate_hash_value(const T& t)
{
return boost::hash_value(t);
}
#if defined(_WIN64)
inline std::size_t calculate_hash_value(SOCKET s)
{
return static_cast<std::size_t>(s);
}
#endif // defined(_WIN64)
template <typename K, typename V>
class hash_map
: private noncopyable
{
public:
// The type of a value in the map.
typedef std::pair<K, V> value_type;
// The type of a non-const iterator over the hash map.
typedef typename std::list<value_type>::iterator iterator;
// The type of a const iterator over the hash map.
typedef typename std::list<value_type>::const_iterator const_iterator;
// Constructor.
hash_map()
{
// Initialise all buckets to empty.
for (size_t i = 0; i < num_buckets; ++i)
buckets_[i].first = buckets_[i].last = values_.end();
}
// Get an iterator for the beginning of the map.
iterator begin()
{
return values_.begin();
}
// Get an iterator for the beginning of the map.
const_iterator begin() const
{
return values_.begin();
}
// Get an iterator for the end of the map.
iterator end()
{
return values_.end();
}
// Get an iterator for the end of the map.
const_iterator end() const
{
return values_.end();
}
// Check whether the map is empty.
bool empty() const
{
return values_.empty();
}
// Find an entry in the map.
iterator find(const K& k)
{
size_t bucket = calculate_hash_value(k) % num_buckets;
iterator it = buckets_[bucket].first;
if (it == values_.end())
return values_.end();
iterator end = buckets_[bucket].last;
++end;
while (it != end)
{
if (it->first == k)
return it;
++it;
}
return values_.end();
}
// Find an entry in the map.
const_iterator find(const K& k) const
{
size_t bucket = calculate_hash_value(k) % num_buckets;
const_iterator it = buckets_[bucket].first;
if (it == values_.end())
return it;
const_iterator end = buckets_[bucket].last;
++end;
while (it != end)
{
if (it->first == k)
return it;
++it;
}
return values_.end();
}
// Insert a new entry into the map.
std::pair<iterator, bool> insert(const value_type& v)
{
size_t bucket = calculate_hash_value(v.first) % num_buckets;
iterator it = buckets_[bucket].first;
if (it == values_.end())
{
buckets_[bucket].first = buckets_[bucket].last =
values_.insert(values_.end(), v);
return std::pair<iterator, bool>(buckets_[bucket].last, true);
}
iterator end = buckets_[bucket].last;
++end;
while (it != end)
{
if (it->first == v.first)
return std::pair<iterator, bool>(it, false);
++it;
}
buckets_[bucket].last = values_.insert(end, v);
return std::pair<iterator, bool>(buckets_[bucket].last, true);
}
// Erase an entry from the map.
void erase(iterator it)
{
assert(it != values_.end());
size_t bucket = calculate_hash_value(it->first) % num_buckets;
bool is_first = (it == buckets_[bucket].first);
bool is_last = (it == buckets_[bucket].last);
if (is_first && is_last)
buckets_[bucket].first = buckets_[bucket].last = values_.end();
else if (is_first)
++buckets_[bucket].first;
else if (is_last)
--buckets_[bucket].last;
values_.erase(it);
}
// Remove all entries from the map.
void clear()
{
// Clear the values.
values_.clear();
// Initialise all buckets to empty.
for (size_t i = 0; i < num_buckets; ++i)
buckets_[i].first = buckets_[i].last = values_.end();
}
private:
// The list of all values in the hash map.
std::list<value_type> values_;
// The type for a bucket in the hash table.
struct bucket_type
{
iterator first;
iterator last;
};
// The number of buckets in the hash.
enum { num_buckets = 1021 };
// The buckets in the hash.
bucket_type buckets_[num_buckets];
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_HASH_MAP_HPP

View File

@ -0,0 +1,137 @@
//
// io_control.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_IO_CONTROL_HPP
#define ASIO_DETAIL_IO_CONTROL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
namespace io_control {
// IO control command for non-blocking I/O.
class non_blocking_io
{
public:
// Default constructor.
non_blocking_io()
: value_(0)
{
}
// Construct with a specific command value.
non_blocking_io(bool value)
: value_(value ? 1 : 0)
{
}
// Get the name of the IO control command.
int name() const
{
return FIONBIO;
}
// Set the value of the I/O control command.
void set(bool value)
{
value_ = value ? 1 : 0;
}
// Get the current value of the I/O control command.
bool get() const
{
return value_ != 0;
}
// Get the address of the command data.
detail::ioctl_arg_type* data()
{
return &value_;
}
// Get the address of the command data.
const detail::ioctl_arg_type* data() const
{
return &value_;
}
private:
detail::ioctl_arg_type value_;
};
// I/O control command for getting number of bytes available.
class bytes_readable
{
public:
// Default constructor.
bytes_readable()
: value_(0)
{
}
// Construct with a specific command value.
bytes_readable(std::size_t value)
: value_(static_cast<detail::ioctl_arg_type>(value))
{
}
// Get the name of the IO control command.
int name() const
{
return FIONREAD;
}
// Set the value of the I/O control command.
void set(std::size_t value)
{
value_ = static_cast<detail::ioctl_arg_type>(value);
}
// Get the current value of the I/O control command.
std::size_t get() const
{
return static_cast<std::size_t>(value_);
}
// Get the address of the command data.
detail::ioctl_arg_type* data()
{
return &value_;
}
// Get the address of the command data.
const detail::ioctl_arg_type* data() const
{
return &value_;
}
private:
detail::ioctl_arg_type value_;
};
} // namespace io_control
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_IO_CONTROL_HPP

View File

@ -0,0 +1,620 @@
//
// kqueue_reactor.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_KQUEUE_REACTOR_HPP
#define ASIO_DETAIL_KQUEUE_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/kqueue_reactor_fwd.hpp"
#if defined(ASIO_HAS_KQUEUE)
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <vector>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/timer_queue.hpp"
// Older versions of Mac OS X may not define EV_OOBAND.
#if !defined(EV_OOBAND)
# define EV_OOBAND EV_FLAG1
#endif // !defined(EV_OOBAND)
namespace asio {
namespace detail {
template <bool Own_Thread>
class kqueue_reactor
: public asio::detail::service_base<kqueue_reactor<Own_Thread> >
{
public:
// Constructor.
kqueue_reactor(asio::io_service& io_service)
: asio::detail::service_base<
kqueue_reactor<Own_Thread> >(io_service),
mutex_(),
kqueue_fd_(do_kqueue_create()),
wait_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
{
// Start the reactor's internal thread only if needed.
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&kqueue_reactor::call_run_thread, this));
}
// Add the interrupter's descriptor to the kqueue.
struct kevent event;
EV_SET(&event, interrupter_.read_descriptor(),
EVFILT_READ, EV_ADD, 0, 0, 0);
::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
}
// Destructor.
~kqueue_reactor()
{
shutdown_service();
close(kqueue_fd_);
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type)
{
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!read_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (read_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno, asio::native_ecat);
read_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (!write_op_queue_.has_operation(descriptor))
if (handler(asio::error_code()))
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno, asio::native_ecat);
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
if (read_op_queue_.has_operation(descriptor))
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno, asio::native_ecat);
except_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (shutdown_)
return;
if (write_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno, asio::native_ecat);
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
if (except_op_queue_.enqueue_operation(descriptor, handler))
{
struct kevent event;
if (read_op_queue_.has_operation(descriptor))
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code ec(errno, asio::native_ecat);
except_op_queue_.dispatch_all_operations(descriptor, ec);
write_op_queue_.dispatch_all_operations(descriptor, ec);
}
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// kqueue_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Remove the descriptor from kqueue.
struct kevent event[2];
EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
::kevent(kqueue_fd_, event, 2, 0, 0, 0);
// Cancel any outstanding operations associated with the descriptor.
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
timer_queues_.push_back(&timer_queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
if (timer_queues_[i] == &timer_queue)
{
timer_queues_.erase(timer_queues_.begin() + i);
return;
}
}
}
// Schedule a timer in the given timer queue to expire at the specified
// absolute time. The handler object will be invoked when the timer expires.
template <typename Time_Traits, typename Handler>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
return timer_queue.cancel_timer(token);
}
private:
friend class task_io_service<kqueue_reactor<Own_Thread> >;
// Run the kqueue loop.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
return;
}
// Determine how long to block while waiting for events.
timespec timeout_buf = { 0, 0 };
timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
wait_in_progress_ = true;
lock.unlock();
// Block on the kqueue descriptor.
struct kevent events[128];
int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
lock.lock();
wait_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Dispatch the waiting events.
for (int i = 0; i < num_events; ++i)
{
int descriptor = events[i].ident;
if (descriptor == interrupter_.read_descriptor())
{
interrupter_.reset();
}
else if (events[i].filter == EVFILT_READ)
{
// Dispatch operations associated with the descriptor.
bool more_reads = false;
bool more_except = false;
if (events[i].flags & EV_ERROR)
{
asio::error_code error(
events[i].data, asio::native_ecat);
except_op_queue_.dispatch_all_operations(descriptor, error);
read_op_queue_.dispatch_all_operations(descriptor, error);
}
else if (events[i].flags & EV_OOBAND)
{
asio::error_code error;
more_except = except_op_queue_.dispatch_operation(descriptor, error);
if (events[i].data > 0)
more_reads = read_op_queue_.dispatch_operation(descriptor, error);
else
more_reads = read_op_queue_.has_operation(descriptor);
}
else
{
asio::error_code error;
more_reads = read_op_queue_.dispatch_operation(descriptor, error);
more_except = except_op_queue_.has_operation(descriptor);
}
// Update the descriptor in the kqueue.
struct kevent event;
if (more_reads)
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
else if (more_except)
EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno, asio::native_ecat);
except_op_queue_.dispatch_all_operations(descriptor, error);
read_op_queue_.dispatch_all_operations(descriptor, error);
}
}
else if (events[i].filter == EVFILT_WRITE)
{
// Dispatch operations associated with the descriptor.
bool more_writes = false;
if (events[i].flags & EV_ERROR)
{
asio::error_code error(
events[i].data, asio::native_ecat);
write_op_queue_.dispatch_all_operations(descriptor, error);
}
else
{
asio::error_code error;
more_writes = write_op_queue_.dispatch_operation(descriptor, error);
}
// Update the descriptor in the kqueue.
struct kevent event;
if (more_writes)
EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
else
EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
{
asio::error_code error(errno, asio::native_ecat);
write_op_queue_.dispatch_all_operations(descriptor, error);
}
}
}
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_timers();
// Issue any pending cancellations.
for (std::size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(kqueue_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// Create the kqueue file descriptor. Throws an exception if the descriptor
// cannot be created.
static int do_kqueue_create()
{
int fd = kqueue();
if (fd == -1)
{
boost::throw_exception(asio::system_error(
asio::error_code(errno, asio::native_ecat),
"kqueue"));
}
return fd;
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the kevent call.
timespec* get_timeout(timespec& ts)
{
if (all_timer_queues_are_empty())
return 0;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
ts.tv_sec = minimum_wait_duration.total_seconds();
ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000;
}
else
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
return &ts;
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the kqueue_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The kqueue file descriptor.
int kqueue_fd_;
// Whether the kqueue wait call is currently in progress
bool wait_in_progress_;
// The interrupter is used to break a blocking kevent call.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of except operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
};
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_KQUEUE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP

View File

@ -0,0 +1,41 @@
//
// kqueue_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
#define ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#if !defined(ASIO_DISABLE_KQUEUE)
#if defined(__MACH__) && defined(__APPLE__)
// Define this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_KQUEUE 1
namespace asio {
namespace detail {
template <bool Own_Thread>
class kqueue_reactor;
} // namespace detail
} // namespace asio
#endif // defined(__MACH__) && defined(__APPLE__)
#endif // !defined(ASIO_DISABLE_KQUEUE)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP

View File

@ -0,0 +1,59 @@
//
// local_free_on_block_exit.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class local_free_on_block_exit
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
explicit local_free_on_block_exit(void* p)
: p_(p)
{
}
// Destructor restores the previous signal mask.
~local_free_on_block_exit()
{
::LocalFree(p_);
}
private:
void* p_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP

View File

@ -0,0 +1,50 @@
//
// mutex.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_MUTEX_HPP
#define ASIO_DETAIL_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_mutex.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_mutex.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_mutex.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_mutex mutex;
#elif defined(BOOST_WINDOWS)
typedef win_mutex mutex;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_mutex mutex;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_MUTEX_HPP

View File

@ -0,0 +1,55 @@
//
// noncopyable.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_NONCOPYABLE_HPP
#define ASIO_DETAIL_NONCOPYABLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include <boost/noncopyable.hpp>
#include <boost/detail/workaround.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// Redefine the noncopyable class for Borland C++ since that compiler does not
// apply the empty base optimisation unless the base class contains a dummy
// char data member.
class noncopyable
{
protected:
noncopyable() {}
~noncopyable() {}
private:
noncopyable(const noncopyable&);
const noncopyable& operator=(const noncopyable&);
char dummy_;
};
#else
using boost::noncopyable;
#endif
} // namespace detail
using asio::detail::noncopyable;
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NONCOPYABLE_HPP

View File

@ -0,0 +1,68 @@
//
// null_event.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_NULL_EVENT_HPP
#define ASIO_DETAIL_NULL_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class null_event
: private noncopyable
{
public:
// Constructor.
null_event()
{
}
// Destructor.
~null_event()
{
}
// Signal the event.
void signal()
{
}
// Reset the event.
void clear()
{
}
// Wait for the event to become signalled.
void wait()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_EVENT_HPP

View File

@ -0,0 +1,66 @@
//
// null_mutex.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_NULL_MUTEX_HPP
#define ASIO_DETAIL_NULL_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scoped_lock.hpp"
namespace asio {
namespace detail {
class null_mutex
: private noncopyable
{
public:
typedef asio::detail::scoped_lock<null_mutex> scoped_lock;
// Constructor.
null_mutex()
{
}
// Destructor.
~null_mutex()
{
}
// Lock the mutex.
void lock()
{
}
// Unlock the mutex.
void unlock()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_MUTEX_HPP

View File

@ -0,0 +1,63 @@
//
// null_signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class null_signal_blocker
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
null_signal_blocker()
{
}
// Destructor restores the previous signal mask.
~null_signal_blocker()
{
}
// Block all signals for the calling thread.
void block()
{
}
// Restore the previous signal mask.
void unblock()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP

View File

@ -0,0 +1,68 @@
//
// null_thread.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_NULL_THREAD_HPP
#define ASIO_DETAIL_NULL_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class null_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
null_thread(Function f)
{
asio::system_error e(
asio::error::operation_not_supported, "thread");
boost::throw_exception(e);
}
// Destructor.
~null_thread()
{
}
// Wait for the thread to exit.
void join()
{
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_THREAD_HPP

View File

@ -0,0 +1,70 @@
//
// null_tss_ptr.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_NULL_TSS_PTR_HPP
#define ASIO_DETAIL_NULL_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
template <typename T>
class null_tss_ptr
: private noncopyable
{
public:
// Constructor.
null_tss_ptr()
: value_(0)
{
}
// Destructor.
~null_tss_ptr()
{
}
// Get the value.
operator T*() const
{
return value_;
}
// Set the value.
void operator=(T* value)
{
value_ = value;
}
private:
T* value_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_HAS_THREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP

View File

@ -0,0 +1,317 @@
//
// old_win_sdk_compat.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
// Guess whether we are building against on old Platform SDK.
#if !defined(IN6ADDR_ANY_INIT)
#define ASIO_HAS_OLD_WIN_SDK 1
#endif // !defined(IN6ADDR_ANY_INIT)
#if defined(ASIO_HAS_OLD_WIN_SDK)
// Emulation of types that are missing from old Platform SDKs.
namespace asio {
namespace detail {
enum
{
sockaddr_storage_maxsize = 128, // Maximum size.
sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment.
sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)),
sockaddr_storage_pad2size = (sockaddr_storage_maxsize -
(sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize))
};
struct sockaddr_storage_emulation
{
short ss_family;
char __ss_pad1[sockaddr_storage_pad1size];
__int64 __ss_align;
char __ss_pad2[sockaddr_storage_pad2size];
};
struct in6_addr_emulation
{
u_char s6_addr[16];
};
struct sockaddr_in6_emulation
{
short sin6_family;
u_short sin6_port;
u_long sin6_flowinfo;
in6_addr_emulation sin6_addr;
u_long sin6_scope_id;
};
struct ipv6_mreq_emulation
{
in6_addr_emulation ipv6mr_multiaddr;
unsigned int ipv6mr_interface;
};
#if !defined(IN6ADDR_ANY_INIT)
# define IN6ADDR_ANY_INIT { 0 }
#endif
#if !defined(IN6ADDR_LOOPBACK_INIT)
# define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
#endif
struct addrinfo_emulation
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
sockaddr* ai_addr;
addrinfo_emulation* ai_next;
};
#if !defined(AI_PASSIVE)
# define AI_PASSIVE 0x1
#endif
#if !defined(AI_CANONNAME)
# define AI_CANONNAME 0x2
#endif
#if !defined(AI_NUMERICHOST)
# define AI_NUMERICHOST 0x4
#endif
#if !defined(EAI_AGAIN)
# define EAI_AGAIN WSATRY_AGAIN
#endif
#if !defined(EAI_BADFLAGS)
# define EAI_BADFLAGS WSAEINVAL
#endif
#if !defined(EAI_FAIL)
# define EAI_FAIL WSANO_RECOVERY
#endif
#if !defined(EAI_FAMILY)
# define EAI_FAMILY WSAEAFNOSUPPORT
#endif
#if !defined(EAI_MEMORY)
# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
#endif
#if !defined(EAI_NODATA)
# define EAI_NODATA WSANO_DATA
#endif
#if !defined(EAI_NONAME)
# define EAI_NONAME WSAHOST_NOT_FOUND
#endif
#if !defined(EAI_SERVICE)
# define EAI_SERVICE WSATYPE_NOT_FOUND
#endif
#if !defined(EAI_SOCKTYPE)
# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
#endif
#if !defined(NI_NOFQDN)
# define NI_NOFQDN 0x01
#endif
#if !defined(NI_NUMERICHOST)
# define NI_NUMERICHOST 0x02
#endif
#if !defined(NI_NAMEREQD)
# define NI_NAMEREQD 0x04
#endif
#if !defined(NI_NUMERICSERV)
# define NI_NUMERICSERV 0x08
#endif
#if !defined(NI_DGRAM)
# define NI_DGRAM 0x10
#endif
#if !defined(IPPROTO_IPV6)
# define IPPROTO_IPV6 41
#endif
#if !defined(IPV6_MULTICAST_IF)
# define IPV6_MULTICAST_IF 9
#endif
#if !defined(IPV6_MULTICAST_HOPS)
# define IPV6_MULTICAST_HOPS 10
#endif
#if !defined(IPV6_MULTICAST_LOOP)
# define IPV6_MULTICAST_LOOP 11
#endif
#if !defined(IPV6_JOIN_GROUP)
# define IPV6_JOIN_GROUP 12
#endif
#if !defined(IPV6_LEAVE_GROUP)
# define IPV6_LEAVE_GROUP 13
#endif
inline int IN6_IS_ADDR_UNSPECIFIED(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0)
&& (a->s6_addr[11] == 0)
&& (a->s6_addr[12] == 0)
&& (a->s6_addr[13] == 0)
&& (a->s6_addr[14] == 0)
&& (a->s6_addr[15] == 0));
}
inline int IN6_IS_ADDR_LOOPBACK(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0)
&& (a->s6_addr[11] == 0)
&& (a->s6_addr[12] == 0)
&& (a->s6_addr[13] == 0)
&& (a->s6_addr[14] == 0)
&& (a->s6_addr[15] == 1));
}
inline int IN6_IS_ADDR_MULTICAST(const in6_addr_emulation* a)
{
return (a->s6_addr[0] == 0xff);
}
inline int IN6_IS_ADDR_LINKLOCAL(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80));
}
inline int IN6_IS_ADDR_SITELOCAL(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0xc0));
}
inline int IN6_IS_ADDR_V4MAPPED(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0xff)
&& (a->s6_addr[11] == 0xff));
}
inline int IN6_IS_ADDR_V4COMPAT(const in6_addr_emulation* a)
{
return ((a->s6_addr[0] == 0)
&& (a->s6_addr[1] == 0)
&& (a->s6_addr[2] == 0)
&& (a->s6_addr[3] == 0)
&& (a->s6_addr[4] == 0)
&& (a->s6_addr[5] == 0)
&& (a->s6_addr[6] == 0)
&& (a->s6_addr[7] == 0)
&& (a->s6_addr[8] == 0)
&& (a->s6_addr[9] == 0)
&& (a->s6_addr[10] == 0xff)
&& (a->s6_addr[11] == 0xff)
&& !((a->s6_addr[12] == 0)
&& (a->s6_addr[13] == 0)
&& (a->s6_addr[14] == 0)
&& ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1))));
}
inline int IN6_IS_ADDR_MC_NODELOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 1);
}
inline int IN6_IS_ADDR_MC_LINKLOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 2);
}
inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5);
}
inline int IN6_IS_ADDR_MC_ORGLOCAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 8);
}
inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
{
return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe);
}
} // namespace detail
} // namespace asio
#endif // defined(ASIO_HAS_OLD_WIN_SDK)
// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.
#if !defined(IPV6_V6ONLY)
# define IPV6_V6ONLY 27
#endif
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP

View File

@ -0,0 +1,104 @@
//
// pipe_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
#include <fcntl.h>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class pipe_select_interrupter
{
public:
// Constructor.
pipe_select_interrupter()
{
int pipe_fds[2];
if (pipe(pipe_fds) == 0)
{
read_descriptor_ = pipe_fds[0];
::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
write_descriptor_ = pipe_fds[1];
::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
}
}
// Destructor.
~pipe_select_interrupter()
{
if (read_descriptor_ != -1)
::close(read_descriptor_);
if (write_descriptor_ != -1)
::close(write_descriptor_);
}
// Interrupt the select call.
void interrupt()
{
char byte = 0;
::write(write_descriptor_, &byte, 1);
}
// Reset the select interrupt. Returns true if the call was interrupted.
bool reset()
{
char data[1024];
int bytes_read = ::read(read_descriptor_, data, sizeof(data));
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = ::read(read_descriptor_, data, sizeof(data));
return was_interrupted;
}
// Get the read descriptor to be passed to select.
int read_descriptor() const
{
return read_descriptor_;
}
private:
// The read end of a connection used to interrupt the select call. This file
// descriptor is passed to select such that when it is time to stop, a single
// byte will be written on the other end of the connection and this
// descriptor will become readable.
int read_descriptor_;
// The write end of a connection used to interrupt the select call. A single
// byte may be written to this to wake up the select which is waiting for the
// other end to become readable.
int write_descriptor_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP

View File

@ -0,0 +1,88 @@
//
// pop_options.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// No header guard
#if defined(__COMO__)
// Comeau C++
#elif defined(__DMC__)
// Digital Mars C++
#elif defined(__INTEL_COMPILER) || defined(__ICL) \
|| defined(__ICC) || defined(__ECC)
// Intel C++
#elif defined(__GNUC__)
// GNU C++
# if defined(__MINGW32__) || defined(__CYGWIN__)
# pragma pack (pop)
# endif
#elif defined(__KCC)
// Kai C++
#elif defined(__sgi)
// SGI MIPSpro C++
#elif defined(__DECCXX)
// Compaq Tru64 Unix cxx
#elif defined(__ghs)
// Greenhills C++
#elif defined(__BORLANDC__)
// Borland C++
# pragma option pop
# pragma nopushoptwarn
# pragma nopackwarning
#elif defined(__MWERKS__)
// Metrowerks CodeWarrior
#elif defined(__SUNPRO_CC)
// Sun Workshop Compiler C++
#elif defined(__HP_aCC)
// HP aCC
#elif defined(__MRC__) || defined(__SC__)
// MPW MrCpp or SCpp
#elif defined(__IBMCPP__)
// IBM Visual Age
#elif defined(_MSC_VER)
// Microsoft Visual C++
//
// Must remain the last #elif since some other vendors (Metrowerks, for example)
// also #define _MSC_VER
# pragma warning (pop)
# pragma pack (pop)
#endif

View File

@ -0,0 +1,111 @@
//
// posix_event.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_POSIX_EVENT_HPP
#define ASIO_DETAIL_POSIX_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class posix_event
: private noncopyable
{
public:
// Constructor.
posix_event()
: signalled_(false)
{
int error = ::pthread_mutex_init(&mutex_, 0);
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"event");
boost::throw_exception(e);
}
error = ::pthread_cond_init(&cond_, 0);
if (error != 0)
{
::pthread_mutex_destroy(&mutex_);
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"event");
boost::throw_exception(e);
}
}
// Destructor.
~posix_event()
{
::pthread_cond_destroy(&cond_);
::pthread_mutex_destroy(&mutex_);
}
// Signal the event.
void signal()
{
::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK.
signalled_ = true;
::pthread_cond_signal(&cond_); // Ignore EINVAL.
::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM.
}
// Reset the event.
void clear()
{
::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK.
signalled_ = false;
::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM.
}
// Wait for the event to become signalled.
void wait()
{
::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK.
while (!signalled_)
::pthread_cond_wait(&cond_, &mutex_); // Ignore EINVAL.
::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM.
}
private:
::pthread_mutex_t mutex_;
::pthread_cond_t cond_;
bool signalled_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_EVENT_HPP

View File

@ -0,0 +1,72 @@
//
// posix_fd_set_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
namespace asio {
namespace detail {
// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
class posix_fd_set_adapter
{
public:
posix_fd_set_adapter()
: max_descriptor_(invalid_socket)
{
using namespace std; // Needed for memset on Solaris.
FD_ZERO(&fd_set_);
}
void set(socket_type descriptor)
{
if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
max_descriptor_ = descriptor;
FD_SET(descriptor, &fd_set_);
}
bool is_set(socket_type descriptor) const
{
return FD_ISSET(descriptor, &fd_set_) != 0;
}
operator fd_set*()
{
return &fd_set_;
}
socket_type max_descriptor() const
{
return max_descriptor_;
}
private:
fd_set fd_set_;
socket_type max_descriptor_;
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP

View File

@ -0,0 +1,100 @@
//
// posix_mutex.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_POSIX_MUTEX_HPP
#define ASIO_DETAIL_POSIX_MUTEX_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scoped_lock.hpp"
namespace asio {
namespace detail {
class posix_mutex
: private noncopyable
{
public:
typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
// Constructor.
posix_mutex()
{
int error = ::pthread_mutex_init(&mutex_, 0);
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"mutex");
boost::throw_exception(e);
}
}
// Destructor.
~posix_mutex()
{
::pthread_mutex_destroy(&mutex_);
}
// Lock the mutex.
void lock()
{
int error = ::pthread_mutex_lock(&mutex_);
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"mutex");
boost::throw_exception(e);
}
}
// Unlock the mutex.
void unlock()
{
int error = ::pthread_mutex_unlock(&mutex_);
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"mutex");
boost::throw_exception(e);
}
}
private:
::pthread_mutex_t mutex_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_MUTEX_HPP

View File

@ -0,0 +1,90 @@
//
// posix_signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <csignal>
#include <pthread.h>
#include <signal.h>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class posix_signal_blocker
: private noncopyable
{
public:
// Constructor blocks all signals for the calling thread.
posix_signal_blocker()
: blocked_(false)
{
sigset_t new_mask;
sigfillset(&new_mask);
blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
}
// Destructor restores the previous signal mask.
~posix_signal_blocker()
{
if (blocked_)
pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
}
// Block all signals for the calling thread.
void block()
{
if (!blocked_)
{
sigset_t new_mask;
sigfillset(&new_mask);
blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
}
}
// Restore the previous signal mask.
void unblock()
{
if (blocked_)
blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0);
}
private:
// Have signals been blocked.
bool blocked_;
// The previous signal mask.
sigset_t old_mask_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP

View File

@ -0,0 +1,127 @@
//
// posix_thread.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_POSIX_THREAD_HPP
#define ASIO_DETAIL_POSIX_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <memory>
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
extern "C" void* asio_detail_posix_thread_function(void* arg);
class posix_thread
: private noncopyable
{
public:
// Constructor.
template <typename Function>
posix_thread(Function f)
: joined_(false)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
int error = ::pthread_create(&thread_, 0,
asio_detail_posix_thread_function, arg.get());
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"thread");
boost::throw_exception(e);
}
arg.release();
}
// Destructor.
~posix_thread()
{
if (!joined_)
::pthread_detach(thread_);
}
// Wait for the thread to exit.
void join()
{
if (!joined_)
{
::pthread_join(thread_, 0);
joined_ = true;
}
}
private:
friend void* asio_detail_posix_thread_function(void* arg);
class func_base
{
public:
virtual ~func_base() {}
virtual void run() = 0;
};
template <typename Function>
class func
: public func_base
{
public:
func(Function f)
: f_(f)
{
}
virtual void run()
{
f_();
}
private:
Function f_;
};
::pthread_t thread_;
bool joined_;
};
inline void* asio_detail_posix_thread_function(void* arg)
{
std::auto_ptr<posix_thread::func_base> f(
static_cast<posix_thread::func_base*>(arg));
f->run();
return 0;
}
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_THREAD_HPP

View File

@ -0,0 +1,86 @@
//
// posix_tss_ptr.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_POSIX_TSS_PTR_HPP
#define ASIO_DETAIL_POSIX_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_HAS_PTHREADS)
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include <pthread.h>
#include "asio/detail/pop_options.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
template <typename T>
class posix_tss_ptr
: private noncopyable
{
public:
// Constructor.
posix_tss_ptr()
{
int error = ::pthread_key_create(&tss_key_, 0);
if (error != 0)
{
asio::system_error e(
asio::error_code(error, asio::native_ecat),
"tss");
boost::throw_exception(e);
}
}
// Destructor.
~posix_tss_ptr()
{
::pthread_key_delete(tss_key_);
}
// Get the value.
operator T*() const
{
return static_cast<T*>(::pthread_getspecific(tss_key_));
}
// Set the value.
void operator=(T* value)
{
::pthread_setspecific(tss_key_, value);
}
private:
// Thread-specific storage to allow unlocked access to determine whether a
// thread is a member of the pool.
pthread_key_t tss_key_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_HAS_PTHREADS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP

View File

@ -0,0 +1,106 @@
//
// push_options.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// No header guard
#if defined(__COMO__)
// Comeau C++
#elif defined(__DMC__)
// Digital Mars C++
#elif defined(__INTEL_COMPILER) || defined(__ICL) \
|| defined(__ICC) || defined(__ECC)
// Intel C++
#elif defined(__GNUC__)
// GNU C++
# if defined(__MINGW32__) || defined(__CYGWIN__)
# pragma pack (push, 8)
# endif
#elif defined(__KCC)
// Kai C++
#elif defined(__sgi)
// SGI MIPSpro C++
#elif defined(__DECCXX)
// Compaq Tru64 Unix cxx
#elif defined(__ghs)
// Greenhills C++
#elif defined(__BORLANDC__)
// Borland C++
# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi-
# pragma nopushoptwarn
# pragma nopackwarning
# if !defined(__MT__)
# error Multithreaded RTL must be selected.
# endif // !defined(__MT__)
#elif defined(__MWERKS__)
// Metrowerks CodeWarrior
#elif defined(__SUNPRO_CC)
// Sun Workshop Compiler C++
#elif defined(__HP_aCC)
// HP aCC
#elif defined(__MRC__) || defined(__SC__)
// MPW MrCpp or SCpp
#elif defined(__IBMCPP__)
// IBM Visual Age
#elif defined(_MSC_VER)
// Microsoft Visual C++
//
// Must remain the last #elif since some other vendors (Metrowerks, for example)
// also #define _MSC_VER
# pragma warning (disable:4103)
# pragma warning (push)
# pragma warning (disable:4244)
# pragma warning (disable:4355)
# pragma warning (disable:4675)
# pragma pack (push, 8)
// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler
// has a tendency to incorrectly optimise away some calls to member template
// functions, even though those functions contain code that should not be
// optimised away! Therefore we will always disable this optimisation option
// for the MSVC6 compiler.
# if (_MSC_VER < 1300)
# pragma optimize ("g", off)
# endif
# if !defined(_MT)
# error Multithreaded RTL must be selected.
# endif // !defined(_MT)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,384 @@
//
// reactor_op_queue.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <memory>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
template <typename Descriptor>
class reactor_op_queue
: private noncopyable
{
public:
// Constructor.
reactor_op_queue()
: operations_(),
cancelled_operations_(0),
cleanup_operations_(0)
{
}
// Add a new operation to the queue. Returns true if this is the only
// operation for the given descriptor, in which case the reactor's event
// demultiplexing function call may need to be interrupted and restarted.
template <typename Handler>
bool enqueue_operation(Descriptor descriptor, Handler handler)
{
op_base* new_op = new op<Handler>(descriptor, handler);
typedef typename operation_map::iterator iterator;
typedef typename operation_map::value_type value_type;
std::pair<iterator, bool> entry =
operations_.insert(value_type(descriptor, new_op));
if (entry.second)
return true;
op_base* current_op = entry.first->second;
while (current_op->next_)
current_op = current_op->next_;
current_op->next_ = new_op;
return false;
}
// Cancel all operations associated with the descriptor. Any operations
// pending for the descriptor will be notified that they have been cancelled
// next time dispatch_cancellations is called. Returns true if any operations
// were cancelled, in which case the reactor's event demultiplexing function
// may need to be interrupted and restarted.
bool cancel_operations(Descriptor descriptor)
{
typename operation_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
op_base* last_op = i->second;
while (last_op->next_)
last_op = last_op->next_;
last_op->next_ = cancelled_operations_;
cancelled_operations_ = i->second;
operations_.erase(i);
return true;
}
return false;
}
// Whether there are no operations in the queue.
bool empty() const
{
return operations_.empty();
}
// Determine whether there are any operations associated with the descriptor.
bool has_operation(Descriptor descriptor) const
{
return operations_.find(descriptor) != operations_.end();
}
// Dispatch the first operation corresponding to the descriptor. Returns true
// if there are more operations queued for the descriptor.
bool dispatch_operation(Descriptor descriptor,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
op_base* this_op = i->second;
i->second = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
bool done = this_op->invoke(result);
if (done)
{
// Operation has finished.
if (i->second)
{
return true;
}
else
{
operations_.erase(i);
return false;
}
}
else
{
// Operation wants to be called again. Leave it at the front of the
// queue for this descriptor, and remove from the cleanup list.
cleanup_operations_ = this_op->next_;
this_op->next_ = i->second;
i->second = this_op;
return true;
}
}
return false;
}
// Dispatch all operations corresponding to the descriptor.
void dispatch_all_operations(Descriptor descriptor,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.find(descriptor);
if (i != operations_.end())
{
while (i->second)
{
op_base* this_op = i->second;
i->second = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
bool done = this_op->invoke(result);
if (!done)
{
// Operation has not finished yet, so leave at front of queue, and
// remove from the cleanup list.
cleanup_operations_ = this_op->next_;
this_op->next_ = i->second;
i->second = this_op;
return;
}
}
operations_.erase(i);
}
}
// Fill a descriptor set with the descriptors corresponding to each active
// operation.
template <typename Descriptor_Set>
void get_descriptors(Descriptor_Set& descriptors)
{
typename operation_map::iterator i = operations_.begin();
while (i != operations_.end())
{
descriptors.set(i->first);
++i;
}
}
// Dispatch the operations corresponding to the ready file descriptors
// contained in the given descriptor set.
template <typename Descriptor_Set>
void dispatch_descriptors(const Descriptor_Set& descriptors,
const asio::error_code& result)
{
typename operation_map::iterator i = operations_.begin();
while (i != operations_.end())
{
typename operation_map::iterator op_iter = i++;
if (descriptors.is_set(op_iter->first))
{
op_base* this_op = op_iter->second;
op_iter->second = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
bool done = this_op->invoke(result);
if (done)
{
if (!op_iter->second)
operations_.erase(op_iter);
}
else
{
// Operation has not finished yet, so leave at front of queue, and
// remove from the cleanup list.
cleanup_operations_ = this_op->next_;
this_op->next_ = op_iter->second;
op_iter->second = this_op;
}
}
}
}
// Dispatch any pending cancels for operations.
void dispatch_cancellations()
{
while (cancelled_operations_)
{
op_base* this_op = cancelled_operations_;
cancelled_operations_ = this_op->next_;
this_op->next_ = cleanup_operations_;
cleanup_operations_ = this_op;
this_op->invoke(asio::error::operation_aborted);
}
}
// Destroy operations that are waiting to be cleaned up.
void cleanup_operations()
{
while (cleanup_operations_)
{
op_base* next_op = cleanup_operations_->next_;
cleanup_operations_->next_ = 0;
cleanup_operations_->destroy();
cleanup_operations_ = next_op;
}
}
// Destroy all operations owned by the queue.
void destroy_operations()
{
while (cancelled_operations_)
{
op_base* next_op = cancelled_operations_->next_;
cancelled_operations_->next_ = 0;
cancelled_operations_->destroy();
cancelled_operations_ = next_op;
}
while (cleanup_operations_)
{
op_base* next_op = cleanup_operations_->next_;
cleanup_operations_->next_ = 0;
cleanup_operations_->destroy();
cleanup_operations_ = next_op;
}
typename operation_map::iterator i = operations_.begin();
while (i != operations_.end())
{
typename operation_map::iterator op_iter = i++;
op_base* curr_op = op_iter->second;
operations_.erase(op_iter);
while (curr_op)
{
op_base* next_op = curr_op->next_;
curr_op->next_ = 0;
curr_op->destroy();
curr_op = next_op;
}
}
}
private:
// Base class for reactor operations. A function pointer is used instead of
// virtual functions to avoid the associated overhead.
class op_base
{
public:
// Get the descriptor associated with the operation.
Descriptor descriptor() const
{
return descriptor_;
}
// Perform the operation.
bool invoke(const asio::error_code& result)
{
return invoke_func_(this, result);
}
// Destroy the operation.
void destroy()
{
return destroy_func_(this);
}
protected:
typedef bool (*invoke_func_type)(op_base*,
const asio::error_code&);
typedef void (*destroy_func_type)(op_base*);
// Construct an operation for the given descriptor.
op_base(invoke_func_type invoke_func,
destroy_func_type destroy_func, Descriptor descriptor)
: invoke_func_(invoke_func),
destroy_func_(destroy_func),
descriptor_(descriptor),
next_(0)
{
}
// Prevent deletion through this type.
~op_base()
{
}
private:
friend class reactor_op_queue<Descriptor>;
// The function to be called to dispatch the handler.
invoke_func_type invoke_func_;
// The function to be called to delete the handler.
destroy_func_type destroy_func_;
// The descriptor associated with the operation.
Descriptor descriptor_;
// The next operation for the same file descriptor.
op_base* next_;
};
// Adaptor class template for using handlers in operations.
template <typename Handler>
class op
: public op_base
{
public:
// Constructor.
op(Descriptor descriptor, Handler handler)
: op_base(&op<Handler>::invoke_handler,
&op<Handler>::destroy_handler, descriptor),
handler_(handler)
{
}
// Invoke the handler.
static bool invoke_handler(op_base* base,
const asio::error_code& result)
{
return static_cast<op<Handler>*>(base)->handler_(result);
}
// Delete the handler.
static void destroy_handler(op_base* base)
{
delete static_cast<op<Handler>*>(base);
}
private:
Handler handler_;
};
// The type for a map of operations.
typedef hash_map<Descriptor, op_base*> operation_map;
// The operations that are currently executing asynchronously.
operation_map operations_;
// The list of operations that have been cancelled.
op_base* cancelled_operations_;
// The list of operations to be destroyed.
op_base* cleanup_operations_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP

View File

@ -0,0 +1,357 @@
//
// resolver_service.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP
#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstring>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/thread.hpp"
namespace asio {
namespace detail {
template <typename Protocol>
class resolver_service
: public asio::detail::service_base<resolver_service<Protocol> >
{
private:
// Helper class to perform exception-safe cleanup of addrinfo objects.
class auto_addrinfo
: private asio::detail::noncopyable
{
public:
explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
: ai_(ai)
{
}
~auto_addrinfo()
{
if (ai_)
socket_ops::freeaddrinfo(ai_);
}
operator asio::detail::addrinfo_type*()
{
return ai_;
}
private:
asio::detail::addrinfo_type* ai_;
};
public:
// The implementation type of the resolver. The shared pointer is used as a
// cancellation token to indicate to the background thread that the operation
// has been cancelled.
typedef boost::shared_ptr<void> implementation_type;
struct noop_deleter { void operator()(void*) {} };
// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
// The query type.
typedef typename Protocol::resolver_query query_type;
// The iterator type.
typedef typename Protocol::resolver_iterator iterator_type;
// Constructor.
resolver_service(asio::io_service& io_service)
: asio::detail::service_base<
resolver_service<Protocol> >(io_service),
mutex_(),
work_io_service_(new asio::io_service),
work_(new asio::io_service::work(*work_io_service_)),
work_thread_(0)
{
}
// Destructor.
~resolver_service()
{
shutdown_service();
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
work_.reset();
if (work_io_service_)
{
work_io_service_->stop();
if (work_thread_)
{
work_thread_->join();
work_thread_.reset();
}
work_io_service_.reset();
}
}
// Construct a new resolver implementation.
void construct(implementation_type& impl)
{
impl.reset(static_cast<void*>(0), noop_deleter());
}
// Destroy a resolver implementation.
void destroy(implementation_type&)
{
}
// Cancel pending asynchronous operations.
void cancel(implementation_type& impl)
{
impl.reset(static_cast<void*>(0), noop_deleter());
}
// Resolve a query to a list of entries.
iterator_type resolve(implementation_type&, const query_type& query,
asio::error_code& ec)
{
asio::detail::addrinfo_type* address_info = 0;
std::string host_name = query.host_name();
std::string service_name = query.service_name();
asio::detail::addrinfo_type hints = query.hints();
socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
service_name.c_str(), &hints, &address_info, ec);
auto_addrinfo auto_address_info(address_info);
if (ec)
return iterator_type();
return iterator_type::create(address_info, host_name, service_name);
}
template <typename Handler>
class resolve_query_handler
{
public:
resolve_query_handler(implementation_type impl, const query_type& query,
asio::io_service& io_service, Handler handler)
: impl_(impl),
query_(query),
io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()()
{
// Check if the operation has been cancelled.
if (impl_.expired())
{
iterator_type iterator;
io_service_.post(asio::detail::bind_handler(handler_,
asio::error::operation_aborted, iterator));
return;
}
// Perform the blocking host resolution operation.
asio::detail::addrinfo_type* address_info = 0;
std::string host_name = query_.host_name();
std::string service_name = query_.service_name();
asio::detail::addrinfo_type hints = query_.hints();
asio::error_code ec;
socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
service_name.c_str(), &hints, &address_info, ec);
auto_addrinfo auto_address_info(address_info);
// Invoke the handler and pass the result.
iterator_type iterator;
if (!ec)
iterator = iterator_type::create(address_info, host_name, service_name);
io_service_.post(asio::detail::bind_handler(
handler_, ec, iterator));
}
private:
boost::weak_ptr<void> impl_;
query_type query_;
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Asynchronously resolve a query to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const query_type& query,
Handler handler)
{
if (work_io_service_)
{
start_work_thread();
work_io_service_->post(
resolve_query_handler<Handler>(
impl, query, this->io_service(), handler));
}
}
// Resolve an endpoint to a list of entries.
iterator_type resolve(implementation_type&,
const endpoint_type& endpoint, asio::error_code& ec)
{
// First try resolving with the service name. If that fails try resolving
// but allow the service to be returned as a number.
char host_name[NI_MAXHOST];
char service_name[NI_MAXSERV];
int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
if (ec)
{
flags |= NI_NUMERICSERV;
socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
}
if (ec)
return iterator_type();
return iterator_type::create(endpoint, host_name, service_name);
}
template <typename Handler>
class resolve_endpoint_handler
{
public:
resolve_endpoint_handler(implementation_type impl,
const endpoint_type& endpoint, asio::io_service& io_service,
Handler handler)
: impl_(impl),
endpoint_(endpoint),
io_service_(io_service),
work_(io_service),
handler_(handler)
{
}
void operator()()
{
// Check if the operation has been cancelled.
if (impl_.expired())
{
iterator_type iterator;
io_service_.post(asio::detail::bind_handler(handler_,
asio::error::operation_aborted, iterator));
return;
}
// First try resolving with the service name. If that fails try resolving
// but allow the service to be returned as a number.
char host_name[NI_MAXHOST];
char service_name[NI_MAXSERV];
int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
asio::error_code ec;
socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
if (ec)
{
flags |= NI_NUMERICSERV;
socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
}
// Invoke the handler and pass the result.
iterator_type iterator;
if (!ec)
iterator = iterator_type::create(endpoint_, host_name, service_name);
io_service_.post(asio::detail::bind_handler(
handler_, ec, iterator));
}
private:
boost::weak_ptr<void> impl_;
endpoint_type endpoint_;
asio::io_service& io_service_;
asio::io_service::work work_;
Handler handler_;
};
// Asynchronously resolve an endpoint to a list of entries.
template <typename Handler>
void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
Handler handler)
{
if (work_io_service_)
{
start_work_thread();
work_io_service_->post(
resolve_endpoint_handler<Handler>(
impl, endpoint, this->io_service(), handler));
}
}
private:
// Helper class to run the work io_service in a thread.
class work_io_service_runner
{
public:
work_io_service_runner(asio::io_service& io_service)
: io_service_(io_service) {}
void operator()() { io_service_.run(); }
private:
asio::io_service& io_service_;
};
// Start the work thread if it's not already running.
void start_work_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (work_thread_ == 0)
{
work_thread_.reset(new asio::detail::thread(
work_io_service_runner(*work_io_service_)));
}
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// Private io_service used for performing asynchronous host resolution.
boost::scoped_ptr<asio::io_service> work_io_service_;
// Work for the private io_service to perform.
boost::scoped_ptr<asio::io_service::work> work_;
// Thread used for running the work io_service's run loop.
boost::scoped_ptr<asio::detail::thread> work_thread_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP

View File

@ -0,0 +1,79 @@
//
// scoped_lock.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SCOPED_LOCK_HPP
#define ASIO_DETAIL_SCOPED_LOCK_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
// Helper class to lock and unlock a mutex automatically.
template <typename Mutex>
class scoped_lock
: private noncopyable
{
public:
// Constructor acquires the lock.
scoped_lock(Mutex& m)
: mutex_(m)
{
mutex_.lock();
locked_ = true;
}
// Destructor releases the lock.
~scoped_lock()
{
if (locked_)
mutex_.unlock();
}
// Explicitly acquire the lock.
void lock()
{
if (!locked_)
{
mutex_.lock();
locked_ = true;
}
}
// Explicitly release the lock.
void unlock()
{
if (locked_)
{
mutex_.unlock();
locked_ = false;
}
}
private:
// The underlying mutex.
Mutex& mutex_;
// Whether the mutex is currently locked or unlocked.
bool locked_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SCOPED_LOCK_HPP

View File

@ -0,0 +1,41 @@
//
// select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SELECT_INTERRUPTER_HPP
#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/pipe_select_interrupter.hpp"
#include "asio/detail/socket_select_interrupter.hpp"
namespace asio {
namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef socket_select_interrupter select_interrupter;
#else
typedef pipe_select_interrupter select_interrupter;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP

View File

@ -0,0 +1,456 @@
//
// select_reactor.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SELECT_REACTOR_HPP
#define ASIO_DETAIL_SELECT_REACTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <boost/config.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <vector>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/fd_set_adapter.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/reactor_op_queue.hpp"
#include "asio/detail/select_interrupter.hpp"
#include "asio/detail/select_reactor_fwd.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/signal_blocker.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/task_io_service.hpp"
#include "asio/detail/thread.hpp"
#include "asio/detail/timer_queue.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class select_reactor
: public asio::detail::service_base<select_reactor<Own_Thread> >
{
public:
// Constructor.
select_reactor(asio::io_service& io_service)
: asio::detail::service_base<
select_reactor<Own_Thread> >(io_service),
mutex_(),
select_in_progress_(false),
interrupter_(),
read_op_queue_(),
write_op_queue_(),
except_op_queue_(),
pending_cancellations_(),
stop_thread_(false),
thread_(0),
shutdown_(false)
{
if (Own_Thread)
{
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&select_reactor::call_run_thread, this));
}
}
// Destructor.
~select_reactor()
{
shutdown_service();
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
stop_thread_ = true;
lock.unlock();
if (thread_)
{
interrupter_.interrupt();
thread_->join();
delete thread_;
thread_ = 0;
}
read_op_queue_.destroy_operations();
write_op_queue_.destroy_operations();
except_op_queue_.destroy_operations();
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->destroy_timers();
timer_queues_.clear();
}
// Register a socket with the reactor. Returns 0 on success, system error
// code on failure.
int register_descriptor(socket_type descriptor)
{
return 0;
}
// Start a new read operation. The handler object will be invoked when the
// given descriptor is ready to be read, or an error has occurred.
template <typename Handler>
void start_read_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (read_op_queue_.enqueue_operation(descriptor, handler))
interrupter_.interrupt();
}
// Start a new write operation. The handler object will be invoked when the
// given descriptor is ready to be written, or an error has occurred.
template <typename Handler>
void start_write_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (write_op_queue_.enqueue_operation(descriptor, handler))
interrupter_.interrupt();
}
// Start a new exception operation. The handler object will be invoked when
// the given descriptor has exception information, or an error has occurred.
template <typename Handler>
void start_except_op(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (except_op_queue_.enqueue_operation(descriptor, handler))
interrupter_.interrupt();
}
// Start new write and exception operations. The handler object will be
// invoked when the given descriptor is ready for writing or has exception
// information available, or an error has occurred.
template <typename Handler>
void start_write_and_except_ops(socket_type descriptor, Handler handler)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
{
bool interrupt = write_op_queue_.enqueue_operation(descriptor, handler);
interrupt = except_op_queue_.enqueue_operation(descriptor, handler)
|| interrupt;
if (interrupt)
interrupter_.interrupt();
}
}
// Cancel all operations associated with the given descriptor. The
// handlers associated with the descriptor will be invoked with the
// operation_aborted error.
void cancel_ops(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Enqueue cancellation of all operations associated with the given
// descriptor. The handlers associated with the descriptor will be invoked
// with the operation_aborted error. This function does not acquire the
// select_reactor's mutex, and so should only be used from within a reactor
// handler.
void enqueue_cancel_ops_unlocked(socket_type descriptor)
{
pending_cancellations_.push_back(descriptor);
}
// Cancel any operations that are running against the descriptor and remove
// its registration from the reactor.
void close_descriptor(socket_type descriptor)
{
asio::detail::mutex::scoped_lock lock(mutex_);
cancel_ops_unlocked(descriptor);
}
// Add a new timer queue to the reactor.
template <typename Time_Traits>
void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
timer_queues_.push_back(&timer_queue);
}
// Remove a timer queue from the reactor.
template <typename Time_Traits>
void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
{
asio::detail::mutex::scoped_lock lock(mutex_);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
if (timer_queues_[i] == &timer_queue)
{
timer_queues_.erase(timer_queues_.begin() + i);
return;
}
}
}
// Schedule a timer in the given timer queue to expire at the specified
// absolute time. The handler object will be invoked when the timer expires.
template <typename Time_Traits, typename Handler>
void schedule_timer(timer_queue<Time_Traits>& timer_queue,
const typename Time_Traits::time_type& time, Handler handler, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_)
if (timer_queue.enqueue_timer(time, handler, token))
interrupter_.interrupt();
}
// Cancel the timer associated with the given token. Returns the number of
// handlers that have been posted or dispatched.
template <typename Time_Traits>
std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
{
asio::detail::mutex::scoped_lock lock(mutex_);
return timer_queue.cancel_timer(token);
}
private:
friend class task_io_service<select_reactor<Own_Thread> >;
// Run select once until interrupted or events are ready to be dispatched.
void run(bool block)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Dispatch any operation cancellations that were made while the select
// loop was not running.
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
except_op_queue_.dispatch_cancellations();
// Check if the thread is supposed to stop.
if (stop_thread_)
{
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
return;
}
// We can return immediately if there's no work to do and the reactor is
// not supposed to block.
if (!block && read_op_queue_.empty() && write_op_queue_.empty()
&& except_op_queue_.empty() && all_timer_queues_are_empty())
{
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
return;
}
// Set up the descriptor sets.
fd_set_adapter read_fds;
read_fds.set(interrupter_.read_descriptor());
read_op_queue_.get_descriptors(read_fds);
fd_set_adapter write_fds;
write_op_queue_.get_descriptors(write_fds);
fd_set_adapter except_fds;
except_op_queue_.get_descriptors(except_fds);
socket_type max_fd = read_fds.max_descriptor();
if (write_fds.max_descriptor() > max_fd)
max_fd = write_fds.max_descriptor();
if (except_fds.max_descriptor() > max_fd)
max_fd = except_fds.max_descriptor();
// Block on the select call without holding the lock so that new
// operations can be started while the call is executing.
timeval tv_buf = { 0, 0 };
timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
select_in_progress_ = true;
lock.unlock();
asio::error_code ec;
int retval = socket_ops::select(static_cast<int>(max_fd + 1),
read_fds, write_fds, except_fds, tv, ec);
lock.lock();
select_in_progress_ = false;
// Block signals while dispatching operations.
asio::detail::signal_blocker sb;
// Reset the interrupter.
if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor()))
interrupter_.reset();
// Dispatch all ready operations.
if (retval > 0)
{
// Exception operations must be processed first to ensure that any
// out-of-band data is read before normal data.
except_op_queue_.dispatch_descriptors(except_fds,
asio::error_code());
read_op_queue_.dispatch_descriptors(read_fds,
asio::error_code());
write_op_queue_.dispatch_descriptors(write_fds,
asio::error_code());
except_op_queue_.dispatch_cancellations();
read_op_queue_.dispatch_cancellations();
write_op_queue_.dispatch_cancellations();
}
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
timer_queues_[i]->dispatch_timers();
// Issue any pending cancellations.
for (size_t i = 0; i < pending_cancellations_.size(); ++i)
cancel_ops_unlocked(pending_cancellations_[i]);
pending_cancellations_.clear();
// Clean up operations. We must not hold the lock since the operations may
// make calls back into this reactor.
lock.unlock();
read_op_queue_.cleanup_operations();
write_op_queue_.cleanup_operations();
except_op_queue_.cleanup_operations();
}
// Run the select loop in the thread.
void run_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
while (!stop_thread_)
{
lock.unlock();
run(true);
lock.lock();
}
}
// Entry point for the select loop thread.
static void call_run_thread(select_reactor* reactor)
{
reactor->run_thread();
}
// Interrupt the select loop.
void interrupt()
{
interrupter_.interrupt();
}
// Check if all timer queues are empty.
bool all_timer_queues_are_empty() const
{
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
if (!timer_queues_[i]->empty())
return false;
return true;
}
// Get the timeout value for the select call.
timeval* get_timeout(timeval& tv)
{
if (all_timer_queues_are_empty())
return 0;
// By default we will wait no longer than 5 minutes. This will ensure that
// any changes to the system clock are detected after no longer than this.
boost::posix_time::time_duration minimum_wait_duration
= boost::posix_time::minutes(5);
for (std::size_t i = 0; i < timer_queues_.size(); ++i)
{
boost::posix_time::time_duration wait_duration
= timer_queues_[i]->wait_duration();
if (wait_duration < minimum_wait_duration)
minimum_wait_duration = wait_duration;
}
if (minimum_wait_duration > boost::posix_time::time_duration())
{
tv.tv_sec = minimum_wait_duration.total_seconds();
tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000;
}
else
{
tv.tv_sec = 0;
tv.tv_usec = 0;
}
return &tv;
}
// Cancel all operations associated with the given descriptor. The do_cancel
// function of the handler objects will be invoked. This function does not
// acquire the select_reactor's mutex.
void cancel_ops_unlocked(socket_type descriptor)
{
bool interrupt = read_op_queue_.cancel_operations(descriptor);
interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
if (interrupt)
interrupter_.interrupt();
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// Whether the select loop is currently running or not.
bool select_in_progress_;
// The interrupter is used to break a blocking select call.
select_interrupter interrupter_;
// The queue of read operations.
reactor_op_queue<socket_type> read_op_queue_;
// The queue of write operations.
reactor_op_queue<socket_type> write_op_queue_;
// The queue of exception operations.
reactor_op_queue<socket_type> except_op_queue_;
// The timer queues.
std::vector<timer_queue_base*> timer_queues_;
// The descriptors that are pending cancellation.
std::vector<socket_type> pending_cancellations_;
// Does the reactor loop thread need to stop.
bool stop_thread_;
// The thread that is running the reactor loop.
asio::detail::thread* thread_;
// Whether the service has been shut down.
bool shutdown_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SELECT_REACTOR_HPP

View File

@ -0,0 +1,31 @@
//
// select_reactor_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
#define ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <bool Own_Thread>
class select_reactor;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP

View File

@ -0,0 +1,49 @@
//
// service_base.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SERVICE_BASE_HPP
#define ASIO_DETAIL_SERVICE_BASE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/service_id.hpp"
namespace asio {
namespace detail {
// Special service base class to keep classes header-file only.
template <typename Type>
class service_base
: public asio::io_service::service
{
public:
static asio::detail::service_id<Type> id;
// Constructor.
service_base(asio::io_service& io_service)
: asio::io_service::service(io_service)
{
}
};
template <typename Type>
asio::detail::service_id<Type> service_base<Type>::id;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_BASE_HPP

View File

@ -0,0 +1,37 @@
//
// service_id.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SERVICE_ID_HPP
#define ASIO_DETAIL_SERVICE_ID_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/io_service.hpp"
namespace asio {
namespace detail {
// Special derived service id type to keep classes header-file only.
template <typename Type>
class service_id
: public asio::io_service::id
{
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_ID_HPP

View File

@ -0,0 +1,198 @@
//
// service_registry.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SERVICE_REGISTRY_HPP
#define ASIO_DETAIL_SERVICE_REGISTRY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <memory>
#include <typeinfo>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_id.hpp"
namespace asio {
namespace detail {
class service_registry
: private noncopyable
{
public:
// Constructor.
service_registry(asio::io_service& o)
: owner_(o),
first_service_(0)
{
}
// Destructor.
~service_registry()
{
// Shutdown all services. This must be done in a separate loop before the
// services are destroyed since the destructors of user-defined handler
// objects may try to access other service objects.
asio::io_service::service* service = first_service_;
while (service)
{
service->shutdown_service();
service = service->next_;
}
// Destroy all services.
while (first_service_)
{
asio::io_service::service* next_service = first_service_->next_;
delete first_service_;
first_service_ = next_service;
}
}
// Get the service object corresponding to the specified service type. Will
// create a new service object automatically if no such object already
// exists. Ownership of the service object is not transferred to the caller.
template <typename Service>
Service& use_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
// First see if there is an existing service object for the given type.
asio::io_service::service* service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return *static_cast<Service*>(service);
service = service->next_;
}
// Create a new service object. The service registry's mutex is not locked
// at this time to allow for nested calls into this function from the new
// service's constructor.
lock.unlock();
std::auto_ptr<Service> new_service(new Service(owner_));
init_service_id(*new_service, Service::id);
Service& new_service_ref = *new_service;
lock.lock();
// Check that nobody else created another service object of the same type
// while the lock was released.
service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return *static_cast<Service*>(service);
service = service->next_;
}
// Service was successfully initialised, pass ownership to registry.
new_service->next_ = first_service_;
first_service_ = new_service.release();
return new_service_ref;
}
// Add a service object. Returns false on error, in which case ownership of
// the object is retained by the caller.
template <typename Service>
bool add_service(Service* new_service)
{
asio::detail::mutex::scoped_lock lock(mutex_);
// Check if there is an existing service object for the given type.
asio::io_service::service* service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return false;
service = service->next_;
}
// Take ownership of the service object.
init_service_id(*new_service, Service::id);
new_service->next_ = first_service_;
first_service_ = new_service;
return true;
}
// Check whether a service object of the specified type already exists.
template <typename Service>
bool has_service() const
{
asio::detail::mutex::scoped_lock lock(mutex_);
asio::io_service::service* service = first_service_;
while (service)
{
if (service_id_matches(*service, Service::id))
return true;
service = service->next_;
}
return false;
}
private:
// Set a service's id.
void init_service_id(asio::io_service::service& service,
const asio::io_service::id& id)
{
service.type_info_ = 0;
service.id_ = &id;
}
// Set a service's id.
template <typename Service>
void init_service_id(asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/)
{
service.type_info_ = &typeid(Service);
service.id_ = 0;
}
// Check if a service matches the given id.
bool service_id_matches(const asio::io_service::service& service,
const asio::io_service::id& id)
{
return service.id_ == &id;
}
// Check if a service matches the given id.
template <typename Service>
bool service_id_matches(const asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/)
{
return service.type_info_ != 0 && *service.type_info_ == typeid(Service);
}
// Mutex to protect access to internal data.
mutable asio::detail::mutex mutex_;
// The owner of this service registry and the services it contains.
asio::io_service& owner_;
// The first service in the list of contained services.
asio::io_service::service* first_service_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP

View File

@ -0,0 +1,30 @@
//
// service_registry_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
#define ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class service_registry;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP

View File

@ -0,0 +1,50 @@
//
// signal_blocker.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SIGNAL_BLOCKER_HPP
#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_signal_blocker.hpp"
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# include "asio/detail/win_signal_blocker.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_signal_blocker.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_signal_blocker signal_blocker;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef win_signal_blocker signal_blocker;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_signal_blocker signal_blocker;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP

View File

@ -0,0 +1,51 @@
//
// signal_init.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SIGNAL_INIT_HPP
#define ASIO_DETAIL_SIGNAL_INIT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/push_options.hpp"
#include <csignal>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
template <int Signal = SIGPIPE>
class signal_init
{
public:
// Constructor.
signal_init()
{
std::signal(Signal, SIG_IGN);
}
};
} // namespace detail
} // namespace asio
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SIGNAL_INIT_HPP

View File

@ -0,0 +1,95 @@
//
// socket_holder.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SOCKET_HOLDER_HPP
#define ASIO_DETAIL_SOCKET_HOLDER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_ops.hpp"
namespace asio {
namespace detail {
// Implement the resource acquisition is initialisation idiom for sockets.
class socket_holder
: private noncopyable
{
public:
// Construct as an uninitialised socket.
socket_holder()
: socket_(invalid_socket)
{
}
// Construct to take ownership of the specified socket.
explicit socket_holder(socket_type s)
: socket_(s)
{
}
// Destructor.
~socket_holder()
{
if (socket_ != invalid_socket)
{
asio::error_code ec;
socket_ops::close(socket_, ec);
}
}
// Get the underlying socket.
socket_type get() const
{
return socket_;
}
// Reset to an uninitialised socket.
void reset()
{
if (socket_ != invalid_socket)
{
asio::error_code ec;
socket_ops::close(socket_, ec);
socket_ = invalid_socket;
}
}
// Reset to take ownership of the specified socket.
void reset(socket_type s)
{
reset();
socket_ = s;
}
// Release ownership of the socket.
socket_type release()
{
socket_type tmp = socket_;
socket_ = invalid_socket;
return tmp;
}
private:
// The underlying socket.
socket_type socket_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,298 @@
//
// socket_option.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SOCKET_OPTION_HPP
#define ASIO_DETAIL_SOCKET_OPTION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <stdexcept>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
namespace socket_option {
// Helper template for implementing boolean-based options.
template <int Level, int Name>
class boolean
{
public:
// Default constructor.
boolean()
: value_(0)
{
}
// Construct with a specific option value.
explicit boolean(bool v)
: value_(v ? 1 : 0)
{
}
// Set the current value of the boolean.
boolean& operator=(bool v)
{
value_ = v ? 1 : 0;
return *this;
}
// Get the current value of the boolean.
bool value() const
{
return !!value_;
}
// Convert to bool.
operator bool() const
{
return !!value_;
}
// Test for false.
bool operator!() const
{
return !value_;
}
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return Level;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the boolean data.
template <typename Protocol>
int* data(const Protocol&)
{
return &value_;
}
// Get the address of the boolean data.
template <typename Protocol>
const int* data(const Protocol&) const
{
return &value_;
}
// Get the size of the boolean data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(value_);
}
// Set the size of the boolean data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
{
if (s != sizeof(value_))
throw std::length_error("boolean socket option resize");
}
private:
int value_;
};
// Helper template for implementing integer options.
template <int Level, int Name>
class integer
{
public:
// Default constructor.
integer()
: value_(0)
{
}
// Construct with a specific option value.
explicit integer(int v)
: value_(v)
{
}
// Set the value of the int option.
integer& operator=(int v)
{
value_ = v;
return *this;
}
// Get the current value of the int option.
int value() const
{
return value_;
}
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return Level;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the int data.
template <typename Protocol>
int* data(const Protocol&)
{
return &value_;
}
// Get the address of the int data.
template <typename Protocol>
const int* data(const Protocol&) const
{
return &value_;
}
// Get the size of the int data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(value_);
}
// Set the size of the int data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
{
if (s != sizeof(value_))
throw std::length_error("integer socket option resize");
}
private:
int value_;
};
// Helper template for implementing linger options.
template <int Level, int Name>
class linger
{
public:
// Default constructor.
linger()
{
value_.l_onoff = 0;
value_.l_linger = 0;
}
// Construct with specific option values.
linger(bool e, int t)
{
enabled(e);
timeout(t);
}
// Set the value for whether linger is enabled.
void enabled(bool value)
{
value_.l_onoff = value ? 1 : 0;
}
// Get the value for whether linger is enabled.
bool enabled() const
{
return value_.l_onoff != 0;
}
// Set the value for the linger timeout.
void timeout(int value)
{
#if defined(WIN32)
value_.l_linger = static_cast<u_short>(value);
#else
value_.l_linger = value;
#endif
}
// Get the value for the linger timeout.
int timeout() const
{
return static_cast<int>(value_.l_linger);
}
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return Level;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the linger data.
template <typename Protocol>
::linger* data(const Protocol&)
{
return &value_;
}
// Get the address of the linger data.
template <typename Protocol>
const ::linger* data(const Protocol&) const
{
return &value_;
}
// Get the size of the linger data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(value_);
}
// Set the size of the int data.
template <typename Protocol>
void resize(const Protocol&, std::size_t s)
{
if (s != sizeof(value_))
throw std::length_error("linger socket option resize");
}
private:
::linger value_;
};
} // namespace socket_option
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_OPTION_HPP

View File

@ -0,0 +1,184 @@
//
// socket_select_interrupter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/system_error.hpp"
#include "asio/detail/socket_holder.hpp"
#include "asio/detail/socket_ops.hpp"
#include "asio/detail/socket_types.hpp"
namespace asio {
namespace detail {
class socket_select_interrupter
{
public:
// Constructor.
socket_select_interrupter()
{
asio::error_code ec;
socket_holder acceptor(socket_ops::socket(
AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
if (acceptor.get() == invalid_socket)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
int opt = 1;
socket_ops::setsockopt(acceptor.get(),
SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
sockaddr_in4_type addr;
socket_addr_len_type addr_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = 0;
if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
addr_len, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
&addr_len, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
if (socket_ops::listen(acceptor.get(),
SOMAXCONN, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
socket_holder client(socket_ops::socket(
AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
if (client.get() == invalid_socket)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
addr_len, ec) == socket_error_retval)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
if (server.get() == invalid_socket)
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
opt = 1;
socket_ops::setsockopt(client.get(),
IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
non_blocking = 1;
if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
{
asio::system_error e(ec, "socket_select_interrupter");
boost::throw_exception(e);
}
opt = 1;
socket_ops::setsockopt(server.get(),
IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
read_descriptor_ = server.release();
write_descriptor_ = client.release();
}
// Destructor.
~socket_select_interrupter()
{
asio::error_code ec;
if (read_descriptor_ != invalid_socket)
socket_ops::close(read_descriptor_, ec);
if (write_descriptor_ != invalid_socket)
socket_ops::close(write_descriptor_, ec);
}
// Interrupt the select call.
void interrupt()
{
char byte = 0;
socket_ops::buf b;
socket_ops::init_buf(b, &byte, 1);
asio::error_code ec;
socket_ops::send(write_descriptor_, &b, 1, 0, ec);
}
// Reset the select interrupt. Returns true if the call was interrupted.
bool reset()
{
char data[1024];
socket_ops::buf b;
socket_ops::init_buf(b, data, sizeof(data));
asio::error_code ec;
int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
bool was_interrupted = (bytes_read > 0);
while (bytes_read == sizeof(data))
bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
return was_interrupted;
}
// Get the read descriptor to be passed to select.
socket_type read_descriptor() const
{
return read_descriptor_;
}
private:
// The read end of a connection used to interrupt the select call. This file
// descriptor is passed to select such that when it is time to stop, a single
// byte will be written on the other end of the connection and this
// descriptor will become readable.
socket_type read_descriptor_;
// The write end of a connection used to interrupt the select call. A single
// byte may be written to this to wake up the select which is waiting for the
// other end to become readable.
socket_type write_descriptor_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP

View File

@ -0,0 +1,178 @@
//
// socket_types.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_SOCKET_TYPES_HPP
#define ASIO_DETAIL_SOCKET_TYPES_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/push_options.hpp"
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
# error WinSock.h has already been included
# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER) || defined(__BORLANDC__)
# pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately")
# pragma message("Assuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target)")
# else // defined(_MSC_VER) || defined(__BORLANDC__)
# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately
# warning Assuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target)
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# define _WIN32_WINNT 0x0500
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER)
# if defined(_WIN32) && !defined(WIN32)
# if !defined(_WINSOCK2API_)
# define WIN32 // Needed for correct types in winsock2.h
# else // !defined(_WINSOCK2API_)
# error Please define the macro WIN32 in your compiler options
# endif // !defined(_WINSOCK2API_)
# endif // defined(_WIN32) && !defined(WIN32)
# endif // defined(_MSC_VER)
# if defined(__BORLANDC__)
# include <stdlib.h> // Needed for __errno
# if defined(__WIN32__) && !defined(WIN32)
# if !defined(_WINSOCK2API_)
# define WIN32 // Needed for correct types in winsock2.h
# else // !defined(_WINSOCK2API_)
# error Please define the macro WIN32 in your compiler options
# endif // !defined(_WINSOCK2API_)
# endif // defined(__WIN32__) && !defined(WIN32)
# if !defined(_WSPIAPI_H_)
# define _WSPIAPI_H_
# define ASIO_WSPIAPI_H_DEFINED
# endif // !defined(_WSPIAPI_H_)
# endif // defined(__BORLANDC__)
# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif // !defined(WIN32_LEAN_AND_MEAN)
# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
# if defined(__CYGWIN__)
# if !defined(__USE_W32_SOCKETS)
# error You must add -D__USE_W32_SOCKETS to your compiler options.
# endif // !defined(__USE_W32_SOCKETS)
# if !defined(NOMINMAX)
# define NOMINMAX 1
# endif // !defined(NOMINMAX)
# endif // defined(__CYGWIN__)
# include <winsock2.h>
# include <ws2tcpip.h>
# include <mswsock.h>
# if defined(ASIO_WSPIAPI_H_DEFINED)
# undef _WSPIAPI_H_
# undef ASIO_WSPIAPI_H_DEFINED
# endif // defined(ASIO_WSPIAPI_H_DEFINED)
# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
# if defined(_MSC_VER) || defined(__BORLANDC__)
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "mswsock.lib")
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
# include "asio/detail/old_win_sdk_compat.hpp"
#else
# include <sys/ioctl.h>
# include <sys/poll.h>
# include <sys/types.h>
# include <sys/select.h>
# include <sys/socket.h>
# include <sys/uio.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <net/if.h>
# if defined(__sun)
# include <sys/filio.h>
# include <sys/sockio.h>
# endif
#endif
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef SOCKET socket_type;
const SOCKET invalid_socket = INVALID_SOCKET;
const int socket_error_retval = SOCKET_ERROR;
const int max_addr_v4_str_len = 256;
const int max_addr_v6_str_len = 256;
typedef sockaddr socket_addr_type;
typedef int socket_addr_len_type;
typedef in_addr in4_addr_type;
typedef ip_mreq in4_mreq_type;
typedef sockaddr_in sockaddr_in4_type;
# if defined(ASIO_HAS_OLD_WIN_SDK)
typedef in6_addr_emulation in6_addr_type;
typedef ipv6_mreq_emulation in6_mreq_type;
typedef sockaddr_in6_emulation sockaddr_in6_type;
typedef sockaddr_storage_emulation sockaddr_storage_type;
typedef addrinfo_emulation addrinfo_type;
# else
typedef in6_addr in6_addr_type;
typedef ipv6_mreq in6_mreq_type;
typedef sockaddr_in6 sockaddr_in6_type;
typedef sockaddr_storage sockaddr_storage_type;
typedef addrinfo addrinfo_type;
# endif
typedef unsigned long ioctl_arg_type;
typedef u_long u_long_type;
typedef u_short u_short_type;
const int shutdown_receive = SD_RECEIVE;
const int shutdown_send = SD_SEND;
const int shutdown_both = SD_BOTH;
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
#else
typedef int socket_type;
const int invalid_socket = -1;
const int socket_error_retval = -1;
const int max_addr_v4_str_len = INET_ADDRSTRLEN;
const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
typedef sockaddr socket_addr_type;
typedef socklen_t socket_addr_len_type;
typedef in_addr in4_addr_type;
typedef ip_mreq in4_mreq_type;
typedef sockaddr_in sockaddr_in4_type;
typedef in6_addr in6_addr_type;
typedef ipv6_mreq in6_mreq_type;
typedef sockaddr_in6 sockaddr_in6_type;
typedef sockaddr_storage sockaddr_storage_type;
typedef addrinfo addrinfo_type;
typedef int ioctl_arg_type;
typedef uint32_t u_long_type;
typedef uint16_t u_short_type;
const int shutdown_receive = SHUT_RD;
const int shutdown_send = SHUT_WR;
const int shutdown_both = SHUT_RDWR;
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
#endif
const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_SOCKET_TYPES_HPP

View File

@ -0,0 +1,526 @@
//
// strand_service.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_STRAND_SERVICE_HPP
#define ASIO_DETAIL_STRAND_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/aligned_storage.hpp>
#include <boost/assert.hpp>
#include <boost/intrusive_ptr.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/service_base.hpp"
namespace asio {
namespace detail {
// Default service implementation for a strand.
class strand_service
: public asio::detail::service_base<strand_service>
{
public:
class handler_base;
class invoke_current_handler;
class post_next_waiter_on_exit;
// The underlying implementation of a strand.
class strand_impl
{
#if defined (__BORLANDC__)
public:
#else
private:
#endif
void add_ref()
{
asio::detail::mutex::scoped_lock lock(mutex_);
++ref_count_;
}
void release()
{
asio::detail::mutex::scoped_lock lock(mutex_);
--ref_count_;
if (ref_count_ == 0)
{
lock.unlock();
delete this;
}
}
private:
// Only this service will have access to the internal values.
friend class strand_service;
friend class post_next_waiter_on_exit;
friend class invoke_current_handler;
strand_impl(strand_service& owner)
: owner_(owner),
current_handler_(0),
first_waiter_(0),
last_waiter_(0),
ref_count_(0)
{
// Insert implementation into linked list of all implementations.
asio::detail::mutex::scoped_lock lock(owner_.mutex_);
next_ = owner_.impl_list_;
prev_ = 0;
if (owner_.impl_list_)
owner_.impl_list_->prev_ = this;
owner_.impl_list_ = this;
}
~strand_impl()
{
// Remove implementation from linked list of all implementations.
asio::detail::mutex::scoped_lock lock(owner_.mutex_);
if (owner_.impl_list_ == this)
owner_.impl_list_ = next_;
if (prev_)
prev_->next_ = next_;
if (next_)
next_->prev_= prev_;
next_ = 0;
prev_ = 0;
lock.unlock();
if (current_handler_)
{
current_handler_->destroy();
}
while (first_waiter_)
{
handler_base* next = first_waiter_->next_;
first_waiter_->destroy();
first_waiter_ = next;
}
}
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The service that owns this implementation.
strand_service& owner_;
// The handler that is ready to execute. If this pointer is non-null then it
// indicates that a handler holds the lock.
handler_base* current_handler_;
// The start of the list of waiting handlers for the strand.
handler_base* first_waiter_;
// The end of the list of waiting handlers for the strand.
handler_base* last_waiter_;
// Storage for posted handlers.
typedef boost::aligned_storage<64> handler_storage_type;
#if defined(__BORLANDC__)
boost::aligned_storage<64> handler_storage_;
#else
handler_storage_type handler_storage_;
#endif
// Pointers to adjacent socket implementations in linked list.
strand_impl* next_;
strand_impl* prev_;
// The reference count on the strand implementation.
size_t ref_count_;
#if !defined(__BORLANDC__)
friend void intrusive_ptr_add_ref(strand_impl* p)
{
p->add_ref();
}
friend void intrusive_ptr_release(strand_impl* p)
{
p->release();
}
#endif
};
friend class strand_impl;
typedef boost::intrusive_ptr<strand_impl> implementation_type;
// Base class for all handler types.
class handler_base
{
public:
typedef void (*invoke_func_type)(handler_base*,
strand_service&, implementation_type&);
typedef void (*destroy_func_type)(handler_base*);
handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func)
: next_(0),
invoke_func_(invoke_func),
destroy_func_(destroy_func)
{
}
void invoke(strand_service& service_impl, implementation_type& impl)
{
invoke_func_(this, service_impl, impl);
}
void destroy()
{
destroy_func_(this);
}
protected:
~handler_base()
{
}
private:
friend class strand_service;
friend class strand_impl;
friend class post_next_waiter_on_exit;
handler_base* next_;
invoke_func_type invoke_func_;
destroy_func_type destroy_func_;
};
// Helper class to allow handlers to be dispatched.
class invoke_current_handler
{
public:
invoke_current_handler(strand_service& service_impl,
const implementation_type& impl)
: service_impl_(service_impl),
impl_(impl)
{
}
void operator()()
{
impl_->current_handler_->invoke(service_impl_, impl_);
}
friend void* asio_handler_allocate(std::size_t size,
invoke_current_handler* this_handler)
{
return this_handler->do_handler_allocate(size);
}
friend void asio_handler_deallocate(void*, std::size_t,
invoke_current_handler*)
{
}
void* do_handler_allocate(std::size_t size)
{
#if defined(__BORLANDC__)
BOOST_ASSERT(size <= boost::aligned_storage<64>::size);
#else
BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
#endif
return impl_->handler_storage_.address();
}
// The asio_handler_invoke hook is not defined here since the default one
// provides the correct behaviour, and including it here breaks MSVC 7.1
// in some situations.
private:
strand_service& service_impl_;
implementation_type impl_;
};
// Helper class to automatically enqueue next waiter on block exit.
class post_next_waiter_on_exit
{
public:
post_next_waiter_on_exit(strand_service& service_impl,
implementation_type& impl)
: service_impl_(service_impl),
impl_(impl),
cancelled_(false)
{
}
~post_next_waiter_on_exit()
{
if (!cancelled_)
{
asio::detail::mutex::scoped_lock lock(impl_->mutex_);
impl_->current_handler_ = impl_->first_waiter_;
if (impl_->current_handler_)
{
impl_->first_waiter_ = impl_->first_waiter_->next_;
if (impl_->first_waiter_ == 0)
impl_->last_waiter_ = 0;
lock.unlock();
service_impl_.io_service().post(
invoke_current_handler(service_impl_, impl_));
}
}
}
void cancel()
{
cancelled_ = true;
}
private:
strand_service& service_impl_;
implementation_type& impl_;
bool cancelled_;
};
// Class template for a waiter.
template <typename Handler>
class handler_wrapper
: public handler_base
{
public:
handler_wrapper(Handler handler)
: handler_base(&handler_wrapper<Handler>::do_invoke,
&handler_wrapper<Handler>::do_destroy),
handler_(handler)
{
}
static void do_invoke(handler_base* base,
strand_service& service_impl, implementation_type& impl)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
post_next_waiter_on_exit p1(service_impl, impl);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(h->handler_);
// A handler object must still be valid when the next waiter is posted
// since destroying the last handler might cause the strand object to be
// destroyed. Therefore we create a second post_next_waiter_on_exit object
// that will be destroyed before the handler object.
p1.cancel();
post_next_waiter_on_exit p2(service_impl, impl);
// Free the memory associated with the handler.
ptr.reset();
// Indicate that this strand is executing on the current thread.
call_stack<strand_impl>::context ctx(impl.get());
// Make the upcall.
asio_handler_invoke_helpers::invoke(handler, &handler);
}
static void do_destroy(handler_base* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
}
private:
Handler handler_;
};
// Construct a new strand service for the specified io_service.
explicit strand_service(asio::io_service& io_service)
: asio::detail::service_base<strand_service>(io_service),
mutex_(),
impl_list_(0)
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
// Construct a list of all handlers to be destroyed.
asio::detail::mutex::scoped_lock lock(mutex_);
strand_impl* impl = impl_list_;
handler_base* first_handler = 0;
while (impl)
{
if (impl->current_handler_)
{
impl->current_handler_->next_ = first_handler;
first_handler = impl->current_handler_;
impl->current_handler_ = 0;
}
if (impl->first_waiter_)
{
impl->last_waiter_->next_ = first_handler;
first_handler = impl->first_waiter_;
impl->first_waiter_ = 0;
impl->last_waiter_ = 0;
}
impl = impl->next_;
}
// Destroy all handlers without holding the lock.
lock.unlock();
while (first_handler)
{
handler_base* next = first_handler->next_;
first_handler->destroy();
first_handler = next;
}
}
// Construct a new strand implementation.
void construct(implementation_type& impl)
{
impl = implementation_type(new strand_impl(*this));
}
// Destroy a strand implementation.
void destroy(implementation_type& impl)
{
implementation_type().swap(impl);
}
// Request the io_service to invoke the given handler.
template <typename Handler>
void dispatch(implementation_type& impl, Handler handler)
{
if (call_stack<strand_impl>::contains(impl.get()))
{
asio_handler_invoke_helpers::invoke(handler, &handler);
}
else
{
asio::detail::mutex::scoped_lock lock(impl->mutex_);
// Allocate and construct an object to wrap the handler.
typedef handler_wrapper<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
if (impl->current_handler_ == 0)
{
// This handler now has the lock, so can be dispatched immediately.
impl->current_handler_ = ptr.get();
lock.unlock();
this->io_service().dispatch(invoke_current_handler(*this, impl));
ptr.release();
}
else
{
// Another handler already holds the lock, so this handler must join
// the list of waiters. The handler will be posted automatically when
// its turn comes.
if (impl->last_waiter_)
{
impl->last_waiter_->next_ = ptr.get();
impl->last_waiter_ = impl->last_waiter_->next_;
}
else
{
impl->first_waiter_ = ptr.get();
impl->last_waiter_ = ptr.get();
}
ptr.release();
}
}
}
// Request the io_service to invoke the given handler and return immediately.
template <typename Handler>
void post(implementation_type& impl, Handler handler)
{
asio::detail::mutex::scoped_lock lock(impl->mutex_);
// Allocate and construct an object to wrap the handler.
typedef handler_wrapper<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
if (impl->current_handler_ == 0)
{
// This handler now has the lock, so can be dispatched immediately.
impl->current_handler_ = ptr.get();
lock.unlock();
this->io_service().post(invoke_current_handler(*this, impl));
ptr.release();
}
else
{
// Another handler already holds the lock, so this handler must join the
// list of waiters. The handler will be posted automatically when its turn
// comes.
if (impl->last_waiter_)
{
impl->last_waiter_->next_ = ptr.get();
impl->last_waiter_ = impl->last_waiter_->next_;
}
else
{
impl->first_waiter_ = ptr.get();
impl->last_waiter_ = ptr.get();
}
ptr.release();
}
}
private:
// Mutex to protect access to the linked list of implementations.
asio::detail::mutex mutex_;
// The head of a linked list of all implementations.
strand_impl* impl_list_;
};
} // namespace detail
} // namespace asio
#if defined(__BORLANDC__)
namespace boost {
inline void intrusive_ptr_add_ref(
asio::detail::strand_service::strand_impl* p)
{
p->add_ref();
}
inline void intrusive_ptr_release(
asio::detail::strand_service::strand_impl* p)
{
p->release();
}
} // namespace boost
#endif // defined(__BORLANDC__)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_STRAND_SERVICE_HPP

View File

@ -0,0 +1,538 @@
//
// task_io_service.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_TASK_IO_SERVICE_HPP
#define ASIO_DETAIL_TASK_IO_SERVICE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/error_code.hpp"
#include "asio/io_service.hpp"
#include "asio/detail/call_stack.hpp"
#include "asio/detail/event.hpp"
#include "asio/detail/handler_alloc_helpers.hpp"
#include "asio/detail/handler_invoke_helpers.hpp"
#include "asio/detail/mutex.hpp"
#include "asio/detail/service_base.hpp"
#include "asio/detail/task_io_service_fwd.hpp"
namespace asio {
namespace detail {
template <typename Task>
class task_io_service
: public asio::detail::service_base<task_io_service<Task> >
{
public:
// Constructor.
task_io_service(asio::io_service& io_service)
: asio::detail::service_base<task_io_service<Task> >(io_service),
mutex_(),
task_(use_service<Task>(io_service)),
outstanding_work_(0),
handler_queue_(&task_handler_),
handler_queue_end_(&task_handler_),
stopped_(false),
shutdown_(false),
first_idle_thread_(0)
{
}
void init(size_t /*concurrency_hint*/)
{
}
// Destroy all user-defined handler objects owned by the service.
void shutdown_service()
{
asio::detail::mutex::scoped_lock lock(mutex_);
shutdown_ = true;
lock.unlock();
// Destroy handler objects.
while (handler_queue_)
{
handler_base* h = handler_queue_;
handler_queue_ = h->next_;
if (h != &task_handler_)
h->destroy();
}
// Reset handler queue to initial state.
handler_queue_ = &task_handler_;
handler_queue_end_ = &task_handler_;
}
// Run the event loop until interrupted or no more work.
size_t run(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.prev = &this_idle_thread;
this_idle_thread.next = &this_idle_thread;
asio::detail::mutex::scoped_lock lock(mutex_);
size_t n = 0;
while (do_one(lock, &this_idle_thread, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
// Run until interrupted or one operation is performed.
size_t run_one(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
idle_thread_info this_idle_thread;
this_idle_thread.prev = &this_idle_thread;
this_idle_thread.next = &this_idle_thread;
asio::detail::mutex::scoped_lock lock(mutex_);
return do_one(lock, &this_idle_thread, ec);
}
// Poll for operations without blocking.
size_t poll(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
asio::detail::mutex::scoped_lock lock(mutex_);
size_t n = 0;
while (do_one(lock, 0, ec))
if (n != (std::numeric_limits<size_t>::max)())
++n;
return n;
}
// Poll for one operation without blocking.
size_t poll_one(asio::error_code& ec)
{
typename call_stack<task_io_service>::context ctx(this);
asio::detail::mutex::scoped_lock lock(mutex_);
return do_one(lock, 0, ec);
}
// Interrupt the event processing loop.
void stop()
{
asio::detail::mutex::scoped_lock lock(mutex_);
stop_all_threads();
}
// Reset in preparation for a subsequent run invocation.
void reset()
{
asio::detail::mutex::scoped_lock lock(mutex_);
stopped_ = false;
}
// Notify that some work has started.
void work_started()
{
asio::detail::mutex::scoped_lock lock(mutex_);
++outstanding_work_;
}
// Notify that some work has finished.
void work_finished()
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (--outstanding_work_ == 0)
stop_all_threads();
}
// Request invocation of the given handler.
template <typename Handler>
void dispatch(Handler handler)
{
if (call_stack<task_io_service>::contains(this))
asio_handler_invoke_helpers::invoke(handler, &handler);
else
post(handler);
}
// Request invocation of the given handler and return immediately.
template <typename Handler>
void post(Handler handler)
{
// Allocate and construct an operation to wrap the handler.
typedef handler_wrapper<Handler> value_type;
typedef handler_alloc_traits<Handler, value_type> alloc_traits;
raw_handler_ptr<alloc_traits> raw_ptr(handler);
handler_ptr<alloc_traits> ptr(raw_ptr, handler);
asio::detail::mutex::scoped_lock lock(mutex_);
// If the service has been shut down we silently discard the handler.
if (shutdown_)
return;
// Add the handler to the end of the queue.
if (handler_queue_end_)
{
handler_queue_end_->next_ = ptr.get();
handler_queue_end_ = ptr.get();
}
else
{
handler_queue_ = handler_queue_end_ = ptr.get();
}
ptr.release();
// An undelivered handler is treated as unfinished work.
++outstanding_work_;
// Wake up a thread to execute the handler.
if (!interrupt_one_idle_thread())
if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_)
task_.interrupt();
}
private:
struct idle_thread_info;
size_t do_one(asio::detail::mutex::scoped_lock& lock,
idle_thread_info* this_idle_thread, asio::error_code& ec)
{
if (outstanding_work_ == 0 && !stopped_)
{
stop_all_threads();
ec = asio::error_code();
return 0;
}
bool polling = !this_idle_thread;
bool task_has_run = false;
while (!stopped_)
{
if (handler_queue_)
{
// Prepare to execute first handler from queue.
handler_base* h = handler_queue_;
handler_queue_ = h->next_;
if (handler_queue_ == 0)
handler_queue_end_ = 0;
bool more_handlers = (handler_queue_ != 0);
lock.unlock();
if (h == &task_handler_)
{
// If the task has already run and we're polling then we're done.
if (task_has_run && polling)
{
ec = asio::error_code();
return 0;
}
task_has_run = true;
task_cleanup c(lock, *this);
// Run the task. May throw an exception. Only block if the handler
// queue is empty and we have an idle_thread_info object, otherwise
// we want to return as soon as possible.
task_.run(!more_handlers && !polling);
}
else
{
handler_cleanup c(lock, *this);
// Invoke the handler. May throw an exception.
h->call(); // call() deletes the handler object
ec = asio::error_code();
return 1;
}
}
else if (this_idle_thread)
{
// Nothing to run right now, so just wait for work to do.
if (first_idle_thread_)
{
this_idle_thread->next = first_idle_thread_;
this_idle_thread->prev = first_idle_thread_->prev;
first_idle_thread_->prev->next = this_idle_thread;
first_idle_thread_->prev = this_idle_thread;
}
first_idle_thread_ = this_idle_thread;
this_idle_thread->wakeup_event.clear();
lock.unlock();
this_idle_thread->wakeup_event.wait();
lock.lock();
if (this_idle_thread->next == this_idle_thread)
{
first_idle_thread_ = 0;
}
else
{
if (first_idle_thread_ == this_idle_thread)
first_idle_thread_ = this_idle_thread->next;
this_idle_thread->next->prev = this_idle_thread->prev;
this_idle_thread->prev->next = this_idle_thread->next;
this_idle_thread->next = this_idle_thread;
this_idle_thread->prev = this_idle_thread;
}
}
else
{
ec = asio::error_code();
return 0;
}
}
ec = asio::error_code();
return 0;
}
// Stop the task and all idle threads.
void stop_all_threads()
{
stopped_ = true;
interrupt_all_idle_threads();
if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_)
task_.interrupt();
}
// Interrupt a single idle thread. Returns true if a thread was interrupted,
// false if no running thread could be found to interrupt.
bool interrupt_one_idle_thread()
{
if (first_idle_thread_)
{
first_idle_thread_->wakeup_event.signal();
first_idle_thread_ = first_idle_thread_->next;
return true;
}
return false;
}
// Interrupt all idle threads.
void interrupt_all_idle_threads()
{
if (first_idle_thread_)
{
first_idle_thread_->wakeup_event.signal();
idle_thread_info* current_idle_thread = first_idle_thread_->next;
while (current_idle_thread != first_idle_thread_)
{
current_idle_thread->wakeup_event.signal();
current_idle_thread = current_idle_thread->next;
}
}
}
class task_cleanup;
friend class task_cleanup;
// The base class for all handler wrappers. A function pointer is used
// instead of virtual functions to avoid the associated overhead.
class handler_base
{
public:
typedef void (*call_func_type)(handler_base*);
typedef void (*destroy_func_type)(handler_base*);
handler_base(call_func_type call_func, destroy_func_type destroy_func)
: next_(0),
call_func_(call_func),
destroy_func_(destroy_func)
{
}
void call()
{
call_func_(this);
}
void destroy()
{
destroy_func_(this);
}
protected:
// Prevent deletion through this type.
~handler_base()
{
}
private:
friend class task_io_service<Task>;
friend class task_cleanup;
handler_base* next_;
call_func_type call_func_;
destroy_func_type destroy_func_;
};
// Template wrapper for handlers.
template <typename Handler>
class handler_wrapper
: public handler_base
{
public:
handler_wrapper(Handler handler)
: handler_base(&handler_wrapper<Handler>::do_call,
&handler_wrapper<Handler>::do_destroy),
handler_(handler)
{
}
static void do_call(handler_base* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
// Make a copy of the handler so that the memory can be deallocated before
// the upcall is made.
Handler handler(h->handler_);
// Free the memory associated with the handler.
ptr.reset();
// Make the upcall.
asio_handler_invoke_helpers::invoke(handler, &handler);
}
static void do_destroy(handler_base* base)
{
// Take ownership of the handler object.
typedef handler_wrapper<Handler> this_type;
this_type* h(static_cast<this_type*>(base));
typedef handler_alloc_traits<Handler, this_type> alloc_traits;
handler_ptr<alloc_traits> ptr(h->handler_, h);
}
private:
Handler handler_;
};
// Helper class to perform task-related operations on block exit.
class task_cleanup
{
public:
task_cleanup(asio::detail::mutex::scoped_lock& lock,
task_io_service& task_io_svc)
: lock_(lock),
task_io_service_(task_io_svc)
{
}
~task_cleanup()
{
// Reinsert the task at the end of the handler queue.
lock_.lock();
task_io_service_.task_handler_.next_ = 0;
if (task_io_service_.handler_queue_end_)
{
task_io_service_.handler_queue_end_->next_
= &task_io_service_.task_handler_;
task_io_service_.handler_queue_end_
= &task_io_service_.task_handler_;
}
else
{
task_io_service_.handler_queue_
= task_io_service_.handler_queue_end_
= &task_io_service_.task_handler_;
}
}
private:
asio::detail::mutex::scoped_lock& lock_;
task_io_service& task_io_service_;
};
// Helper class to perform handler-related operations on block exit.
class handler_cleanup;
friend class handler_cleanup;
class handler_cleanup
{
public:
handler_cleanup(asio::detail::mutex::scoped_lock& lock,
task_io_service& task_io_svc)
: lock_(lock),
task_io_service_(task_io_svc)
{
}
~handler_cleanup()
{
lock_.lock();
if (--task_io_service_.outstanding_work_ == 0)
task_io_service_.stop_all_threads();
}
private:
asio::detail::mutex::scoped_lock& lock_;
task_io_service& task_io_service_;
};
// Mutex to protect access to internal data.
asio::detail::mutex mutex_;
// The task to be run by this service.
Task& task_;
// Handler object to represent the position of the task in the queue.
class task_handler
: public handler_base
{
public:
task_handler()
: handler_base(0, 0)
{
}
} task_handler_;
// The count of unfinished work.
int outstanding_work_;
// The start of a linked list of handlers that are ready to be delivered.
handler_base* handler_queue_;
// The end of a linked list of handlers that are ready to be delivered.
handler_base* handler_queue_end_;
// Flag to indicate that the dispatcher has been stopped.
bool stopped_;
// Flag to indicate that the dispatcher has been shut down.
bool shutdown_;
// Structure containing information about an idle thread.
struct idle_thread_info
{
event wakeup_event;
idle_thread_info* prev;
idle_thread_info* next;
};
// The number of threads that are currently idle.
idle_thread_info* first_idle_thread_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP

View File

@ -0,0 +1,31 @@
//
// task_io_service_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
#define ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename Task>
class task_io_service;
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP

View File

@ -0,0 +1,50 @@
//
// thread.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_THREAD_HPP
#define ASIO_DETAIL_THREAD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_thread.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_thread.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_thread.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
#if !defined(BOOST_HAS_THREADS)
typedef null_thread thread;
#elif defined(BOOST_WINDOWS)
typedef win_thread thread;
#elif defined(BOOST_HAS_PTHREADS)
typedef posix_thread thread;
#endif
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_THREAD_HPP

View File

@ -0,0 +1,44 @@
//
// throw_error.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_THROW_ERROR_HPP
#define ASIO_DETAIL_THROW_ERROR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error_code.hpp"
#include "asio/system_error.hpp"
namespace asio {
namespace detail {
inline void throw_error(const asio::error_code& err)
{
if (err)
{
asio::system_error e(err);
boost::throw_exception(e);
}
}
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_THROW_ERROR_HPP

View File

@ -0,0 +1,347 @@
//
// timer_queue.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_TIMER_QUEUE_HPP
#define ASIO_DETAIL_TIMER_QUEUE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstddef>
#include <functional>
#include <limits>
#include <memory>
#include <vector>
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/error.hpp"
#include "asio/detail/hash_map.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/timer_queue_base.hpp"
namespace asio {
namespace detail {
template <typename Time_Traits>
class timer_queue
: public timer_queue_base
{
public:
// The time type.
typedef typename Time_Traits::time_type time_type;
// The duration type.
typedef typename Time_Traits::duration_type duration_type;
// Constructor.
timer_queue()
: timers_(),
heap_()
{
}
// Add a new timer to the queue. Returns true if this is the timer that is
// earliest in the queue, in which case the reactor's event demultiplexing
// function call may need to be interrupted and restarted.
template <typename Handler>
bool enqueue_timer(const time_type& time, Handler handler, void* token)
{
// Ensure that there is space for the timer in the heap. We reserve here so
// that the push_back below will not throw due to a reallocation failure.
heap_.reserve(heap_.size() + 1);
// Create a new timer object.
std::auto_ptr<timer<Handler> > new_timer(
new timer<Handler>(time, handler, token));
// Insert the new timer into the hash.
typedef typename hash_map<void*, timer_base*>::iterator iterator;
typedef typename hash_map<void*, timer_base*>::value_type value_type;
std::pair<iterator, bool> result =
timers_.insert(value_type(token, new_timer.get()));
if (!result.second)
{
result.first->second->prev_ = new_timer.get();
new_timer->next_ = result.first->second;
result.first->second = new_timer.get();
}
// Put the timer at the correct position in the heap.
new_timer->heap_index_ = heap_.size();
heap_.push_back(new_timer.get());
up_heap(heap_.size() - 1);
bool is_first = (heap_[0] == new_timer.get());
// Ownership of the timer is transferred to the timer queue.
new_timer.release();
return is_first;
}
// Whether there are no timers in the queue.
virtual bool empty() const
{
return heap_.empty();
}
// Get the time for the timer that is earliest in the queue.
virtual boost::posix_time::time_duration wait_duration() const
{
return Time_Traits::to_posix_duration(
Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
}
// Dispatch the timers that are earlier than the specified time.
virtual void dispatch_timers()
{
const time_type now = Time_Traits::now();
while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
{
timer_base* t = heap_[0];
remove_timer(t);
t->invoke(asio::error_code());
}
}
// Cancel the timer with the given token. The handler will be invoked
// immediately with the result operation_aborted.
std::size_t cancel_timer(void* timer_token)
{
std::size_t num_cancelled = 0;
typedef typename hash_map<void*, timer_base*>::iterator iterator;
iterator it = timers_.find(timer_token);
if (it != timers_.end())
{
timer_base* t = it->second;
while (t)
{
timer_base* next = t->next_;
remove_timer(t);
t->invoke(asio::error::operation_aborted);
t = next;
++num_cancelled;
}
}
return num_cancelled;
}
// Destroy all timers.
virtual void destroy_timers()
{
typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
typename hash_map<void*, timer_base*>::iterator end = timers_.end();
while (i != end)
{
timer_base* t = i->second;
typename hash_map<void*, timer_base*>::iterator old_i = i++;
timers_.erase(old_i);
t->destroy();
}
heap_.clear();
timers_.clear();
}
private:
// Base class for timer operations. Function pointers are used instead of
// virtual functions to avoid the associated overhead.
class timer_base
{
public:
// Perform the timer operation and then destroy.
void invoke(const asio::error_code& result)
{
invoke_func_(this, result);
}
// Destroy the timer operation.
void destroy()
{
destroy_func_(this);
}
protected:
typedef void (*invoke_func_type)(timer_base*,
const asio::error_code&);
typedef void (*destroy_func_type)(timer_base*);
// Constructor.
timer_base(invoke_func_type invoke_func, destroy_func_type destroy_func,
const time_type& time, void* token)
: invoke_func_(invoke_func),
destroy_func_(destroy_func),
time_(time),
token_(token),
next_(0),
prev_(0),
heap_index_(
std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
{
}
// Prevent deletion through this type.
~timer_base()
{
}
private:
friend class timer_queue<Time_Traits>;
// The function to be called to dispatch the handler.
invoke_func_type invoke_func_;
// The function to be called to destroy the handler.
destroy_func_type destroy_func_;
// The time when the operation should fire.
time_type time_;
// The token associated with the timer.
void* token_;
// The next timer known to the queue.
timer_base* next_;
// The previous timer known to the queue.
timer_base* prev_;
// The index of the timer in the heap.
size_t heap_index_;
};
// Adaptor class template for using handlers in timers.
template <typename Handler>
class timer
: public timer_base
{
public:
// Constructor.
timer(const time_type& time, Handler handler, void* token)
: timer_base(&timer<Handler>::invoke_handler,
&timer<Handler>::destroy_handler, time, token),
handler_(handler)
{
}
// Invoke the handler and then destroy it.
static void invoke_handler(timer_base* base,
const asio::error_code& result)
{
std::auto_ptr<timer<Handler> > t(static_cast<timer<Handler>*>(base));
t->handler_(result);
}
// Destroy the handler.
static void destroy_handler(timer_base* base)
{
delete static_cast<timer<Handler>*>(base);
}
private:
Handler handler_;
};
// Move the item at the given index up the heap to its correct position.
void up_heap(size_t index)
{
size_t parent = (index - 1) / 2;
while (index > 0
&& Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
{
swap_heap(index, parent);
index = parent;
parent = (index - 1) / 2;
}
}
// Move the item at the given index down the heap to its correct position.
void down_heap(size_t index)
{
size_t child = index * 2 + 1;
while (child < heap_.size())
{
size_t min_child = (child + 1 == heap_.size()
|| Time_Traits::less_than(
heap_[child]->time_, heap_[child + 1]->time_))
? child : child + 1;
if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_))
break;
swap_heap(index, min_child);
index = min_child;
child = index * 2 + 1;
}
}
// Swap two entries in the heap.
void swap_heap(size_t index1, size_t index2)
{
timer_base* tmp = heap_[index1];
heap_[index1] = heap_[index2];
heap_[index2] = tmp;
heap_[index1]->heap_index_ = index1;
heap_[index2]->heap_index_ = index2;
}
// Remove a timer from the heap and list of timers.
void remove_timer(timer_base* t)
{
// Remove the timer from the heap.
size_t index = t->heap_index_;
if (!heap_.empty() && index < heap_.size())
{
if (index == heap_.size() - 1)
{
heap_.pop_back();
}
else
{
swap_heap(index, heap_.size() - 1);
heap_.pop_back();
size_t parent = (index - 1) / 2;
if (index > 0 && Time_Traits::less_than(t->time_, heap_[parent]->time_))
up_heap(index);
else
down_heap(index);
}
}
// Remove the timer from the hash.
typedef typename hash_map<void*, timer_base*>::iterator iterator;
iterator it = timers_.find(t->token_);
if (it != timers_.end())
{
if (it->second == t)
it->second = t->next_;
if (t->prev_)
t->prev_->next_ = t->next_;
if (t->next_)
t->next_->prev_ = t->prev_;
if (it->second == 0)
timers_.erase(it);
}
}
// A hash of timer token to linked lists of timers.
hash_map<void*, timer_base*> timers_;
// The heap of timers, with the earliest timer at the front.
std::vector<timer_base*> heap_;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TIMER_QUEUE_HPP

View File

@ -0,0 +1,56 @@
//
// timer_queue_base.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/detail/push_options.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/noncopyable.hpp"
namespace asio {
namespace detail {
class timer_queue_base
: private noncopyable
{
public:
// Destructor.
virtual ~timer_queue_base() {}
// Whether there are no timers in the queue.
virtual bool empty() const = 0;
// Get the time to wait until the next timer.
virtual boost::posix_time::time_duration wait_duration() const = 0;
// Dispatch all ready timers.
virtual void dispatch_timers() = 0;
// Destroy all timers.
virtual void destroy_timers() = 0;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP

View File

@ -0,0 +1,65 @@
//
// tss_ptr.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_TSS_PTR_HPP
#define ASIO_DETAIL_TSS_PTR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if !defined(BOOST_HAS_THREADS)
# include "asio/detail/null_tss_ptr.hpp"
#elif defined(BOOST_WINDOWS)
# include "asio/detail/win_tss_ptr.hpp"
#elif defined(BOOST_HAS_PTHREADS)
# include "asio/detail/posix_tss_ptr.hpp"
#else
# error Only Windows and POSIX are supported!
#endif
namespace asio {
namespace detail {
template <typename T>
class tss_ptr
#if !defined(BOOST_HAS_THREADS)
: public null_tss_ptr<T>
#elif defined(BOOST_WINDOWS)
: public win_tss_ptr<T>
#elif defined(BOOST_HAS_PTHREADS)
: public posix_tss_ptr<T>
#endif
{
public:
void operator=(T* value)
{
#if !defined(BOOST_HAS_THREADS)
null_tss_ptr<T>::operator=(value);
#elif defined(BOOST_WINDOWS)
win_tss_ptr<T>::operator=(value);
#elif defined(BOOST_HAS_PTHREADS)
posix_tss_ptr<T>::operator=(value);
#endif
}
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_TSS_PTR_HPP

View File

@ -0,0 +1,90 @@
//
// win_event.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_WIN_EVENT_HPP
#define ASIO_DETAIL_WIN_EVENT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
#if defined(BOOST_WINDOWS)
#include "asio/system_error.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/socket_types.hpp"
#include "asio/detail/push_options.hpp"
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
namespace asio {
namespace detail {
class win_event
: private noncopyable
{
public:
// Constructor.
win_event()
: event_(::CreateEvent(0, true, false, 0))
{
if (!event_)
{
DWORD last_error = ::GetLastError();
asio::system_error e(
asio::error_code(last_error, asio::native_ecat),
"event");
boost::throw_exception(e);
}
}
// Destructor.
~win_event()
{
::CloseHandle(event_);
}
// Signal the event.
void signal()
{
::SetEvent(event_);
}
// Reset the event.
void clear()
{
::ResetEvent(event_);
}
// Wait for the event to become signalled.
void wait()
{
::WaitForSingleObject(event_, INFINITE);
}
private:
HANDLE event_;
};
} // namespace detail
} // namespace asio
#endif // defined(BOOST_WINDOWS)
#include "asio/detail/pop_options.hpp"
#endif // ASIO_DETAIL_WIN_EVENT_HPP

Some files were not shown because too many files have changed in this diff Show More