redis-server 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +38 -0
- data/README.md +33 -0
- data/bin/redis +114 -0
- data/redis/Makefile +5 -0
- data/redis/extconf.rb +3 -0
- data/redis/redis-2.2.11/00-RELEASENOTES +199 -0
- data/redis/redis-2.2.11/BUGS +1 -0
- data/redis/redis-2.2.11/CONTRIBUTING +13 -0
- data/redis/redis-2.2.11/COPYING +10 -0
- data/redis/redis-2.2.11/Changelog +1032 -0
- data/redis/redis-2.2.11/INSTALL +30 -0
- data/redis/redis-2.2.11/Makefile +22 -0
- data/redis/redis-2.2.11/README +83 -0
- data/redis/redis-2.2.11/TODO +4 -0
- data/redis/redis-2.2.11/client-libraries/README +11 -0
- data/redis/redis-2.2.11/deps/hiredis/COPYING +10 -0
- data/redis/redis-2.2.11/deps/hiredis/Makefile +115 -0
- data/redis/redis-2.2.11/deps/hiredis/README.md +311 -0
- data/redis/redis-2.2.11/deps/hiredis/TODO +2 -0
- data/redis/redis-2.2.11/deps/hiredis/adapters/ae.h +95 -0
- data/redis/redis-2.2.11/deps/hiredis/adapters/libev.h +113 -0
- data/redis/redis-2.2.11/deps/hiredis/adapters/libevent.h +76 -0
- data/redis/redis-2.2.11/deps/hiredis/async.c +321 -0
- data/redis/redis-2.2.11/deps/hiredis/async.h +112 -0
- data/redis/redis-2.2.11/deps/hiredis/example-ae.c +53 -0
- data/redis/redis-2.2.11/deps/hiredis/example-libev.c +47 -0
- data/redis/redis-2.2.11/deps/hiredis/example-libevent.c +48 -0
- data/redis/redis-2.2.11/deps/hiredis/example.c +67 -0
- data/redis/redis-2.2.11/deps/hiredis/fmacros.h +15 -0
- data/redis/redis-2.2.11/deps/hiredis/hiredis.c +1058 -0
- data/redis/redis-2.2.11/deps/hiredis/hiredis.h +170 -0
- data/redis/redis-2.2.11/deps/hiredis/net.c +170 -0
- data/redis/redis-2.2.11/deps/hiredis/net.h +43 -0
- data/redis/redis-2.2.11/deps/hiredis/sds.c +479 -0
- data/redis/redis-2.2.11/deps/hiredis/sds.h +77 -0
- data/redis/redis-2.2.11/deps/hiredis/test.c +479 -0
- data/redis/redis-2.2.11/deps/hiredis/util.h +40 -0
- data/redis/redis-2.2.11/deps/linenoise/Makefile +10 -0
- data/redis/redis-2.2.11/deps/linenoise/README.markdown +45 -0
- data/redis/redis-2.2.11/deps/linenoise/example.c +27 -0
- data/redis/redis-2.2.11/deps/linenoise/linenoise.c +609 -0
- data/redis/redis-2.2.11/deps/linenoise/linenoise.h +55 -0
- data/redis/redis-2.2.11/design-documents/REDIS-CLUSTER +214 -0
- data/redis/redis-2.2.11/design-documents/REDIS-CLUSTER-2 +343 -0
- data/redis/redis-2.2.11/doc/AppendCommand.html +48 -0
- data/redis/redis-2.2.11/doc/AppendOnlyFileHowto.html +41 -0
- data/redis/redis-2.2.11/doc/AuthCommand.html +39 -0
- data/redis/redis-2.2.11/doc/Benchmarks.html +129 -0
- data/redis/redis-2.2.11/doc/BgrewriteaofCommand.html +41 -0
- data/redis/redis-2.2.11/doc/BgsaveCommand.html +39 -0
- data/redis/redis-2.2.11/doc/BlpopCommand.html +51 -0
- data/redis/redis-2.2.11/doc/BrpoplpushCommand.html +39 -0
- data/redis/redis-2.2.11/doc/CommandReference.html +47 -0
- data/redis/redis-2.2.11/doc/Comparisons.html +42 -0
- data/redis/redis-2.2.11/doc/ConfigCommand.html +76 -0
- data/redis/redis-2.2.11/doc/Configuration.html +38 -0
- data/redis/redis-2.2.11/doc/ConnectionHandlingSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/ControlCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Credits.html +38 -0
- data/redis/redis-2.2.11/doc/DbsizeCommand.html +38 -0
- data/redis/redis-2.2.11/doc/DelCommand.html +41 -0
- data/redis/redis-2.2.11/doc/DesignPatterns.html +37 -0
- data/redis/redis-2.2.11/doc/EventLibray.html +44 -0
- data/redis/redis-2.2.11/doc/ExistsCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ExpireCommand.html +96 -0
- data/redis/redis-2.2.11/doc/FAQ.html +70 -0
- data/redis/redis-2.2.11/doc/Features.html +38 -0
- data/redis/redis-2.2.11/doc/FlushallCommand.html +39 -0
- data/redis/redis-2.2.11/doc/FlushdbCommand.html +39 -0
- data/redis/redis-2.2.11/doc/FromSqlToDataStructures.html +37 -0
- data/redis/redis-2.2.11/doc/GenericCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/GetCommand.html +39 -0
- data/redis/redis-2.2.11/doc/GetbitCommand.html +39 -0
- data/redis/redis-2.2.11/doc/GetsetCommand.html +38 -0
- data/redis/redis-2.2.11/doc/HackingStrings.html +83 -0
- data/redis/redis-2.2.11/doc/HashCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Hashes.html +37 -0
- data/redis/redis-2.2.11/doc/HdelCommand.html +39 -0
- data/redis/redis-2.2.11/doc/HexistsCommand.html +39 -0
- data/redis/redis-2.2.11/doc/HgetCommand.html +39 -0
- data/redis/redis-2.2.11/doc/HgetallCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HincrbyCommand.html +45 -0
- data/redis/redis-2.2.11/doc/HlenCommand.html +38 -0
- data/redis/redis-2.2.11/doc/HmgetCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HmsetCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HsetCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HsetnxCommand.html +41 -0
- data/redis/redis-2.2.11/doc/IncrCommand.html +43 -0
- data/redis/redis-2.2.11/doc/InfoCommand.html +48 -0
- data/redis/redis-2.2.11/doc/IntroductionToRedisDataTypes.html +152 -0
- data/redis/redis-2.2.11/doc/KeysCommand.html +43 -0
- data/redis/redis-2.2.11/doc/LastsaveCommand.html +39 -0
- data/redis/redis-2.2.11/doc/LindexCommand.html +40 -0
- data/redis/redis-2.2.11/doc/ListCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Lists.html +42 -0
- data/redis/redis-2.2.11/doc/LlenCommand.html +41 -0
- data/redis/redis-2.2.11/doc/LpopCommand.html +41 -0
- data/redis/redis-2.2.11/doc/LrangeCommand.html +47 -0
- data/redis/redis-2.2.11/doc/LremCommand.html +41 -0
- data/redis/redis-2.2.11/doc/LsetCommand.html +38 -0
- data/redis/redis-2.2.11/doc/LtrimCommand.html +47 -0
- data/redis/redis-2.2.11/doc/MgetCommand.html +52 -0
- data/redis/redis-2.2.11/doc/MonitorCommand.html +63 -0
- data/redis/redis-2.2.11/doc/MoveCommand.html +42 -0
- data/redis/redis-2.2.11/doc/MsetCommand.html +44 -0
- data/redis/redis-2.2.11/doc/MultiExecCommand.html +166 -0
- data/redis/redis-2.2.11/doc/NonexistentCommands.html +51 -0
- data/redis/redis-2.2.11/doc/ObjectHashMappers.html +39 -0
- data/redis/redis-2.2.11/doc/Pipelining.html +36 -0
- data/redis/redis-2.2.11/doc/ProgrammingExamples.html +38 -0
- data/redis/redis-2.2.11/doc/ProtocolSpecification.html +137 -0
- data/redis/redis-2.2.11/doc/PublishSubscribe.html +115 -0
- data/redis/redis-2.2.11/doc/QuickStart.html +68 -0
- data/redis/redis-2.2.11/doc/QuitCommand.html +38 -0
- data/redis/redis-2.2.11/doc/README.html +119 -0
- data/redis/redis-2.2.11/doc/RandomkeyCommand.html +39 -0
- data/redis/redis-2.2.11/doc/Redis0100ChangeLog.html +67 -0
- data/redis/redis-2.2.11/doc/Redis0900ChangeLog.html +56 -0
- data/redis/redis-2.2.11/doc/RedisBigData.html +61 -0
- data/redis/redis-2.2.11/doc/RedisCLI.html +37 -0
- data/redis/redis-2.2.11/doc/RedisEventLibrary.html +70 -0
- data/redis/redis-2.2.11/doc/RedisGuides.html +37 -0
- data/redis/redis-2.2.11/doc/RedisInternals.html +38 -0
- data/redis/redis-2.2.11/doc/RedisPipelining.html +93 -0
- data/redis/redis-2.2.11/doc/RedisStatus.html +56 -0
- data/redis/redis-2.2.11/doc/Redis_1_2_0_Changelog.html +40 -0
- data/redis/redis-2.2.11/doc/Redis_2_0_0_Changelog.html +62 -0
- data/redis/redis-2.2.11/doc/Redis_2_0_Whats_new.html +59 -0
- data/redis/redis-2.2.11/doc/RenameCommand.html +39 -0
- data/redis/redis-2.2.11/doc/RenamenxCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ReplicationHowto.html +43 -0
- data/redis/redis-2.2.11/doc/ReplyTypes.html +42 -0
- data/redis/redis-2.2.11/doc/RoadMap.html +38 -0
- data/redis/redis-2.2.11/doc/RpoplpushCommand.html +44 -0
- data/redis/redis-2.2.11/doc/RpushCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SaddCommand.html +41 -0
- data/redis/redis-2.2.11/doc/SaveCommand.html +39 -0
- data/redis/redis-2.2.11/doc/ScardCommand.html +41 -0
- data/redis/redis-2.2.11/doc/SdiffCommand.html +45 -0
- data/redis/redis-2.2.11/doc/SdiffstoreCommand.html +38 -0
- data/redis/redis-2.2.11/doc/SelectCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SetCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SetCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/SetbitCommand.html +45 -0
- data/redis/redis-2.2.11/doc/SetexCommand.html +42 -0
- data/redis/redis-2.2.11/doc/SetnxCommand.html +51 -0
- data/redis/redis-2.2.11/doc/SetrangeCommand.html +58 -0
- data/redis/redis-2.2.11/doc/Sets.html +36 -0
- data/redis/redis-2.2.11/doc/ShutdownCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SideBar.html +36 -0
- data/redis/redis-2.2.11/doc/SinterCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SinterstoreCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SismemberCommand.html +42 -0
- data/redis/redis-2.2.11/doc/SlaveofCommand.html +41 -0
- data/redis/redis-2.2.11/doc/SmembersCommand.html +38 -0
- data/redis/redis-2.2.11/doc/SmoveCommand.html +44 -0
- data/redis/redis-2.2.11/doc/SortCommand.html +75 -0
- data/redis/redis-2.2.11/doc/SortedSetCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/SortedSets.html +36 -0
- data/redis/redis-2.2.11/doc/Speed.html +38 -0
- data/redis/redis-2.2.11/doc/SponsorshipHistory.html +38 -0
- data/redis/redis-2.2.11/doc/SpopCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SrandmemberCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SremCommand.html +42 -0
- data/redis/redis-2.2.11/doc/StringCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Strings.html +37 -0
- data/redis/redis-2.2.11/doc/StrlenCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SubstrCommand.html +52 -0
- data/redis/redis-2.2.11/doc/SunionCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SunionstoreCommand.html +38 -0
- data/redis/redis-2.2.11/doc/SupportedLanguages.html +60 -0
- data/redis/redis-2.2.11/doc/SupportedPlatforms.html +37 -0
- data/redis/redis-2.2.11/doc/TemplateCommand.html +38 -0
- data/redis/redis-2.2.11/doc/TtlCommand.html +38 -0
- data/redis/redis-2.2.11/doc/TwitterAlikeExample.html +250 -0
- data/redis/redis-2.2.11/doc/TypeCommand.html +46 -0
- data/redis/redis-2.2.11/doc/UnstableSource.html +39 -0
- data/redis/redis-2.2.11/doc/VirtualMemorySpecification.html +156 -0
- data/redis/redis-2.2.11/doc/VirtualMemoryUserGuide.html +66 -0
- data/redis/redis-2.2.11/doc/ZaddCommand.html +43 -0
- data/redis/redis-2.2.11/doc/ZcardCommand.html +41 -0
- data/redis/redis-2.2.11/doc/ZincrbyCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZrangeCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZrangebyscoreCommand.html +77 -0
- data/redis/redis-2.2.11/doc/ZrankCommand.html +43 -0
- data/redis/redis-2.2.11/doc/ZremCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZremrangebyrankCommand.html +39 -0
- data/redis/redis-2.2.11/doc/ZremrangebyscoreCommand.html +39 -0
- data/redis/redis-2.2.11/doc/ZscoreCommand.html +41 -0
- data/redis/redis-2.2.11/doc/ZunionCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZunionstoreCommand.html +43 -0
- data/redis/redis-2.2.11/doc/index.html +43 -0
- data/redis/redis-2.2.11/doc/redis.png +0 -0
- data/redis/redis-2.2.11/doc/style.css +25 -0
- data/redis/redis-2.2.11/redis.conf +417 -0
- data/redis/redis-2.2.11/src/Makefile +177 -0
- data/redis/redis-2.2.11/src/adlist.c +325 -0
- data/redis/redis-2.2.11/src/adlist.h +92 -0
- data/redis/redis-2.2.11/src/ae.c +390 -0
- data/redis/redis-2.2.11/src/ae.h +117 -0
- data/redis/redis-2.2.11/src/ae_epoll.c +91 -0
- data/redis/redis-2.2.11/src/ae_kqueue.c +93 -0
- data/redis/redis-2.2.11/src/ae_select.c +72 -0
- data/redis/redis-2.2.11/src/anet.c +347 -0
- data/redis/redis-2.2.11/src/anet.h +57 -0
- data/redis/redis-2.2.11/src/aof.c +675 -0
- data/redis/redis-2.2.11/src/config.c +627 -0
- data/redis/redis-2.2.11/src/config.h +64 -0
- data/redis/redis-2.2.11/src/db.c +543 -0
- data/redis/redis-2.2.11/src/debug.c +314 -0
- data/redis/redis-2.2.11/src/dict.c +721 -0
- data/redis/redis-2.2.11/src/dict.h +156 -0
- data/redis/redis-2.2.11/src/fmacros.h +15 -0
- data/redis/redis-2.2.11/src/help.h +638 -0
- data/redis/redis-2.2.11/src/intset.c +422 -0
- data/redis/redis-2.2.11/src/intset.h +19 -0
- data/redis/redis-2.2.11/src/lzf.h +100 -0
- data/redis/redis-2.2.11/src/lzfP.h +159 -0
- data/redis/redis-2.2.11/src/lzf_c.c +295 -0
- data/redis/redis-2.2.11/src/lzf_d.c +150 -0
- data/redis/redis-2.2.11/src/mkreleasehdr.sh +9 -0
- data/redis/redis-2.2.11/src/multi.c +268 -0
- data/redis/redis-2.2.11/src/networking.c +899 -0
- data/redis/redis-2.2.11/src/object.c +484 -0
- data/redis/redis-2.2.11/src/pqsort.c +197 -0
- data/redis/redis-2.2.11/src/pqsort.h +15 -0
- data/redis/redis-2.2.11/src/pubsub.c +267 -0
- data/redis/redis-2.2.11/src/rdb.c +1020 -0
- data/redis/redis-2.2.11/src/redis-benchmark.c +530 -0
- data/redis/redis-2.2.11/src/redis-check-aof.c +185 -0
- data/redis/redis-2.2.11/src/redis-check-dump.c +681 -0
- data/redis/redis-2.2.11/src/redis-cli.c +773 -0
- data/redis/redis-2.2.11/src/redis.c +1677 -0
- data/redis/redis-2.2.11/src/redis.h +1022 -0
- data/redis/redis-2.2.11/src/release.c +13 -0
- data/redis/redis-2.2.11/src/replication.c +557 -0
- data/redis/redis-2.2.11/src/sds.c +639 -0
- data/redis/redis-2.2.11/src/sds.h +78 -0
- data/redis/redis-2.2.11/src/sha1.c +276 -0
- data/redis/redis-2.2.11/src/sha1.h +17 -0
- data/redis/redis-2.2.11/src/solarisfixes.h +22 -0
- data/redis/redis-2.2.11/src/sort.c +389 -0
- data/redis/redis-2.2.11/src/syncio.c +154 -0
- data/redis/redis-2.2.11/src/t_hash.c +476 -0
- data/redis/redis-2.2.11/src/t_list.c +986 -0
- data/redis/redis-2.2.11/src/t_set.c +610 -0
- data/redis/redis-2.2.11/src/t_string.c +438 -0
- data/redis/redis-2.2.11/src/t_zset.c +1084 -0
- data/redis/redis-2.2.11/src/testhelp.h +54 -0
- data/redis/redis-2.2.11/src/util.c +243 -0
- data/redis/redis-2.2.11/src/valgrind.sup +5 -0
- data/redis/redis-2.2.11/src/version.h +1 -0
- data/redis/redis-2.2.11/src/vm.c +1149 -0
- data/redis/redis-2.2.11/src/ziplist.c +1323 -0
- data/redis/redis-2.2.11/src/ziplist.h +15 -0
- data/redis/redis-2.2.11/src/zipmap.c +455 -0
- data/redis/redis-2.2.11/src/zipmap.h +48 -0
- data/redis/redis-2.2.11/src/zmalloc.c +278 -0
- data/redis/redis-2.2.11/src/zmalloc.h +47 -0
- data/redis/redis-2.2.11/tests/assets/default.conf +308 -0
- data/redis/redis-2.2.11/tests/integration/aof.tcl +104 -0
- data/redis/redis-2.2.11/tests/integration/redis-cli.tcl +208 -0
- data/redis/redis-2.2.11/tests/integration/replication.tcl +98 -0
- data/redis/redis-2.2.11/tests/support/redis.tcl +241 -0
- data/redis/redis-2.2.11/tests/support/server.tcl +294 -0
- data/redis/redis-2.2.11/tests/support/test.tcl +190 -0
- data/redis/redis-2.2.11/tests/support/tmpfile.tcl +15 -0
- data/redis/redis-2.2.11/tests/support/util.tcl +296 -0
- data/redis/redis-2.2.11/tests/test_helper.tcl +221 -0
- data/redis/redis-2.2.11/tests/unit/auth.tcl +15 -0
- data/redis/redis-2.2.11/tests/unit/basic.tcl +616 -0
- data/redis/redis-2.2.11/tests/unit/cas.tcl +135 -0
- data/redis/redis-2.2.11/tests/unit/expire.tcl +74 -0
- data/redis/redis-2.2.11/tests/unit/other.tcl +240 -0
- data/redis/redis-2.2.11/tests/unit/printver.tcl +6 -0
- data/redis/redis-2.2.11/tests/unit/protocol.tcl +62 -0
- data/redis/redis-2.2.11/tests/unit/pubsub.tcl +195 -0
- data/redis/redis-2.2.11/tests/unit/quit.tcl +40 -0
- data/redis/redis-2.2.11/tests/unit/sort.tcl +189 -0
- data/redis/redis-2.2.11/tests/unit/type/hash.tcl +300 -0
- data/redis/redis-2.2.11/tests/unit/type/list.tcl +819 -0
- data/redis/redis-2.2.11/tests/unit/type/set.tcl +334 -0
- data/redis/redis-2.2.11/tests/unit/type/zset.tcl +587 -0
- data/redis/redis-2.2.11/utils/build-static-symbols.tcl +22 -0
- data/redis/redis-2.2.11/utils/generate-command-help.rb +112 -0
- data/redis/redis-2.2.11/utils/mktarball.sh +13 -0
- data/redis/redis-2.2.11/utils/redis-copy.rb +78 -0
- data/redis/redis-2.2.11/utils/redis-sha1.rb +52 -0
- data/redis/redis-2.2.11/utils/redis_init_script +42 -0
- metadata +362 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
/* A simple event-driven programming library. Originally I wrote this code
|
2
|
+
* for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
|
3
|
+
* it in form of a library for easy reuse.
|
4
|
+
*
|
5
|
+
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
6
|
+
* All rights reserved.
|
7
|
+
*
|
8
|
+
* Redistribution and use in source and binary forms, with or without
|
9
|
+
* modification, are permitted provided that the following conditions are met:
|
10
|
+
*
|
11
|
+
* * Redistributions of source code must retain the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer.
|
13
|
+
* * Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
* * Neither the name of Redis nor the names of its contributors may be used
|
17
|
+
* to endorse or promote products derived from this software without
|
18
|
+
* specific prior written permission.
|
19
|
+
*
|
20
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
*/
|
32
|
+
|
33
|
+
#ifndef __AE_H__
|
34
|
+
#define __AE_H__
|
35
|
+
|
36
|
+
#define AE_SETSIZE (1024*10) /* Max number of fd supported */
|
37
|
+
|
38
|
+
#define AE_OK 0
|
39
|
+
#define AE_ERR -1
|
40
|
+
|
41
|
+
#define AE_NONE 0
|
42
|
+
#define AE_READABLE 1
|
43
|
+
#define AE_WRITABLE 2
|
44
|
+
|
45
|
+
#define AE_FILE_EVENTS 1
|
46
|
+
#define AE_TIME_EVENTS 2
|
47
|
+
#define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS)
|
48
|
+
#define AE_DONT_WAIT 4
|
49
|
+
|
50
|
+
#define AE_NOMORE -1
|
51
|
+
|
52
|
+
/* Macros */
|
53
|
+
#define AE_NOTUSED(V) ((void) V)
|
54
|
+
|
55
|
+
struct aeEventLoop;
|
56
|
+
|
57
|
+
/* Types and data structures */
|
58
|
+
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
|
59
|
+
typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
|
60
|
+
typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
|
61
|
+
typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);
|
62
|
+
|
63
|
+
/* File event structure */
|
64
|
+
typedef struct aeFileEvent {
|
65
|
+
int mask; /* one of AE_(READABLE|WRITABLE) */
|
66
|
+
aeFileProc *rfileProc;
|
67
|
+
aeFileProc *wfileProc;
|
68
|
+
void *clientData;
|
69
|
+
} aeFileEvent;
|
70
|
+
|
71
|
+
/* Time event structure */
|
72
|
+
typedef struct aeTimeEvent {
|
73
|
+
long long id; /* time event identifier. */
|
74
|
+
long when_sec; /* seconds */
|
75
|
+
long when_ms; /* milliseconds */
|
76
|
+
aeTimeProc *timeProc;
|
77
|
+
aeEventFinalizerProc *finalizerProc;
|
78
|
+
void *clientData;
|
79
|
+
struct aeTimeEvent *next;
|
80
|
+
} aeTimeEvent;
|
81
|
+
|
82
|
+
/* A fired event */
|
83
|
+
typedef struct aeFiredEvent {
|
84
|
+
int fd;
|
85
|
+
int mask;
|
86
|
+
} aeFiredEvent;
|
87
|
+
|
88
|
+
/* State of an event based program */
|
89
|
+
typedef struct aeEventLoop {
|
90
|
+
int maxfd;
|
91
|
+
long long timeEventNextId;
|
92
|
+
aeFileEvent events[AE_SETSIZE]; /* Registered events */
|
93
|
+
aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
|
94
|
+
aeTimeEvent *timeEventHead;
|
95
|
+
int stop;
|
96
|
+
void *apidata; /* This is used for polling API specific data */
|
97
|
+
aeBeforeSleepProc *beforesleep;
|
98
|
+
} aeEventLoop;
|
99
|
+
|
100
|
+
/* Prototypes */
|
101
|
+
aeEventLoop *aeCreateEventLoop(void);
|
102
|
+
void aeDeleteEventLoop(aeEventLoop *eventLoop);
|
103
|
+
void aeStop(aeEventLoop *eventLoop);
|
104
|
+
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
|
105
|
+
aeFileProc *proc, void *clientData);
|
106
|
+
void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);
|
107
|
+
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
|
108
|
+
aeTimeProc *proc, void *clientData,
|
109
|
+
aeEventFinalizerProc *finalizerProc);
|
110
|
+
int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);
|
111
|
+
int aeProcessEvents(aeEventLoop *eventLoop, int flags);
|
112
|
+
int aeWait(int fd, int mask, long long milliseconds);
|
113
|
+
void aeMain(aeEventLoop *eventLoop);
|
114
|
+
char *aeGetApiName(void);
|
115
|
+
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep);
|
116
|
+
|
117
|
+
#endif
|
@@ -0,0 +1,91 @@
|
|
1
|
+
/* Linux epoll(2) based ae.c module
|
2
|
+
* Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
|
3
|
+
* Released under the BSD license. See the COPYING file for more info. */
|
4
|
+
|
5
|
+
#include <sys/epoll.h>
|
6
|
+
|
7
|
+
typedef struct aeApiState {
|
8
|
+
int epfd;
|
9
|
+
struct epoll_event events[AE_SETSIZE];
|
10
|
+
} aeApiState;
|
11
|
+
|
12
|
+
static int aeApiCreate(aeEventLoop *eventLoop) {
|
13
|
+
aeApiState *state = zmalloc(sizeof(aeApiState));
|
14
|
+
|
15
|
+
if (!state) return -1;
|
16
|
+
state->epfd = epoll_create(1024); /* 1024 is just an hint for the kernel */
|
17
|
+
if (state->epfd == -1) return -1;
|
18
|
+
eventLoop->apidata = state;
|
19
|
+
return 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
static void aeApiFree(aeEventLoop *eventLoop) {
|
23
|
+
aeApiState *state = eventLoop->apidata;
|
24
|
+
|
25
|
+
close(state->epfd);
|
26
|
+
zfree(state);
|
27
|
+
}
|
28
|
+
|
29
|
+
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
30
|
+
aeApiState *state = eventLoop->apidata;
|
31
|
+
struct epoll_event ee;
|
32
|
+
/* If the fd was already monitored for some event, we need a MOD
|
33
|
+
* operation. Otherwise we need an ADD operation. */
|
34
|
+
int op = eventLoop->events[fd].mask == AE_NONE ?
|
35
|
+
EPOLL_CTL_ADD : EPOLL_CTL_MOD;
|
36
|
+
|
37
|
+
ee.events = 0;
|
38
|
+
mask |= eventLoop->events[fd].mask; /* Merge old events */
|
39
|
+
if (mask & AE_READABLE) ee.events |= EPOLLIN;
|
40
|
+
if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
|
41
|
+
ee.data.u64 = 0; /* avoid valgrind warning */
|
42
|
+
ee.data.fd = fd;
|
43
|
+
if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;
|
44
|
+
return 0;
|
45
|
+
}
|
46
|
+
|
47
|
+
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) {
|
48
|
+
aeApiState *state = eventLoop->apidata;
|
49
|
+
struct epoll_event ee;
|
50
|
+
int mask = eventLoop->events[fd].mask & (~delmask);
|
51
|
+
|
52
|
+
ee.events = 0;
|
53
|
+
if (mask & AE_READABLE) ee.events |= EPOLLIN;
|
54
|
+
if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
|
55
|
+
ee.data.u64 = 0; /* avoid valgrind warning */
|
56
|
+
ee.data.fd = fd;
|
57
|
+
if (mask != AE_NONE) {
|
58
|
+
epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee);
|
59
|
+
} else {
|
60
|
+
/* Note, Kernel < 2.6.9 requires a non null event pointer even for
|
61
|
+
* EPOLL_CTL_DEL. */
|
62
|
+
epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
|
67
|
+
aeApiState *state = eventLoop->apidata;
|
68
|
+
int retval, numevents = 0;
|
69
|
+
|
70
|
+
retval = epoll_wait(state->epfd,state->events,AE_SETSIZE,
|
71
|
+
tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
|
72
|
+
if (retval > 0) {
|
73
|
+
int j;
|
74
|
+
|
75
|
+
numevents = retval;
|
76
|
+
for (j = 0; j < numevents; j++) {
|
77
|
+
int mask = 0;
|
78
|
+
struct epoll_event *e = state->events+j;
|
79
|
+
|
80
|
+
if (e->events & EPOLLIN) mask |= AE_READABLE;
|
81
|
+
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
|
82
|
+
eventLoop->fired[j].fd = e->data.fd;
|
83
|
+
eventLoop->fired[j].mask = mask;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return numevents;
|
87
|
+
}
|
88
|
+
|
89
|
+
static char *aeApiName(void) {
|
90
|
+
return "epoll";
|
91
|
+
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
/* Kqueue(2)-based ae.c module
|
2
|
+
* Copyright (C) 2009 Harish Mallipeddi - harish.mallipeddi@gmail.com
|
3
|
+
* Released under the BSD license. See the COPYING file for more info. */
|
4
|
+
|
5
|
+
#include <sys/types.h>
|
6
|
+
#include <sys/event.h>
|
7
|
+
#include <sys/time.h>
|
8
|
+
|
9
|
+
typedef struct aeApiState {
|
10
|
+
int kqfd;
|
11
|
+
struct kevent events[AE_SETSIZE];
|
12
|
+
} aeApiState;
|
13
|
+
|
14
|
+
static int aeApiCreate(aeEventLoop *eventLoop) {
|
15
|
+
aeApiState *state = zmalloc(sizeof(aeApiState));
|
16
|
+
|
17
|
+
if (!state) return -1;
|
18
|
+
state->kqfd = kqueue();
|
19
|
+
if (state->kqfd == -1) return -1;
|
20
|
+
eventLoop->apidata = state;
|
21
|
+
|
22
|
+
return 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
static void aeApiFree(aeEventLoop *eventLoop) {
|
26
|
+
aeApiState *state = eventLoop->apidata;
|
27
|
+
|
28
|
+
close(state->kqfd);
|
29
|
+
zfree(state);
|
30
|
+
}
|
31
|
+
|
32
|
+
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
33
|
+
aeApiState *state = eventLoop->apidata;
|
34
|
+
struct kevent ke;
|
35
|
+
|
36
|
+
if (mask & AE_READABLE) {
|
37
|
+
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
38
|
+
if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1;
|
39
|
+
}
|
40
|
+
if (mask & AE_WRITABLE) {
|
41
|
+
EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
42
|
+
if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1;
|
43
|
+
}
|
44
|
+
return 0;
|
45
|
+
}
|
46
|
+
|
47
|
+
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
48
|
+
aeApiState *state = eventLoop->apidata;
|
49
|
+
struct kevent ke;
|
50
|
+
|
51
|
+
if (mask & AE_READABLE) {
|
52
|
+
EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
53
|
+
kevent(state->kqfd, &ke, 1, NULL, 0, NULL);
|
54
|
+
}
|
55
|
+
if (mask & AE_WRITABLE) {
|
56
|
+
EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
57
|
+
kevent(state->kqfd, &ke, 1, NULL, 0, NULL);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
|
62
|
+
aeApiState *state = eventLoop->apidata;
|
63
|
+
int retval, numevents = 0;
|
64
|
+
|
65
|
+
if (tvp != NULL) {
|
66
|
+
struct timespec timeout;
|
67
|
+
timeout.tv_sec = tvp->tv_sec;
|
68
|
+
timeout.tv_nsec = tvp->tv_usec * 1000;
|
69
|
+
retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, &timeout);
|
70
|
+
} else {
|
71
|
+
retval = kevent(state->kqfd, NULL, 0, state->events, AE_SETSIZE, NULL);
|
72
|
+
}
|
73
|
+
|
74
|
+
if (retval > 0) {
|
75
|
+
int j;
|
76
|
+
|
77
|
+
numevents = retval;
|
78
|
+
for(j = 0; j < numevents; j++) {
|
79
|
+
int mask = 0;
|
80
|
+
struct kevent *e = state->events+j;
|
81
|
+
|
82
|
+
if (e->filter == EVFILT_READ) mask |= AE_READABLE;
|
83
|
+
if (e->filter == EVFILT_WRITE) mask |= AE_WRITABLE;
|
84
|
+
eventLoop->fired[j].fd = e->ident;
|
85
|
+
eventLoop->fired[j].mask = mask;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
return numevents;
|
89
|
+
}
|
90
|
+
|
91
|
+
static char *aeApiName(void) {
|
92
|
+
return "kqueue";
|
93
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
/* Select()-based ae.c module
|
2
|
+
* Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
|
3
|
+
* Released under the BSD license. See the COPYING file for more info. */
|
4
|
+
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
typedef struct aeApiState {
|
8
|
+
fd_set rfds, wfds;
|
9
|
+
/* We need to have a copy of the fd sets as it's not safe to reuse
|
10
|
+
* FD sets after select(). */
|
11
|
+
fd_set _rfds, _wfds;
|
12
|
+
} aeApiState;
|
13
|
+
|
14
|
+
static int aeApiCreate(aeEventLoop *eventLoop) {
|
15
|
+
aeApiState *state = zmalloc(sizeof(aeApiState));
|
16
|
+
|
17
|
+
if (!state) return -1;
|
18
|
+
FD_ZERO(&state->rfds);
|
19
|
+
FD_ZERO(&state->wfds);
|
20
|
+
eventLoop->apidata = state;
|
21
|
+
return 0;
|
22
|
+
}
|
23
|
+
|
24
|
+
static void aeApiFree(aeEventLoop *eventLoop) {
|
25
|
+
zfree(eventLoop->apidata);
|
26
|
+
}
|
27
|
+
|
28
|
+
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
29
|
+
aeApiState *state = eventLoop->apidata;
|
30
|
+
|
31
|
+
if (mask & AE_READABLE) FD_SET(fd,&state->rfds);
|
32
|
+
if (mask & AE_WRITABLE) FD_SET(fd,&state->wfds);
|
33
|
+
return 0;
|
34
|
+
}
|
35
|
+
|
36
|
+
static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
|
37
|
+
aeApiState *state = eventLoop->apidata;
|
38
|
+
|
39
|
+
if (mask & AE_READABLE) FD_CLR(fd,&state->rfds);
|
40
|
+
if (mask & AE_WRITABLE) FD_CLR(fd,&state->wfds);
|
41
|
+
}
|
42
|
+
|
43
|
+
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
|
44
|
+
aeApiState *state = eventLoop->apidata;
|
45
|
+
int retval, j, numevents = 0;
|
46
|
+
|
47
|
+
memcpy(&state->_rfds,&state->rfds,sizeof(fd_set));
|
48
|
+
memcpy(&state->_wfds,&state->wfds,sizeof(fd_set));
|
49
|
+
|
50
|
+
retval = select(eventLoop->maxfd+1,
|
51
|
+
&state->_rfds,&state->_wfds,NULL,tvp);
|
52
|
+
if (retval > 0) {
|
53
|
+
for (j = 0; j <= eventLoop->maxfd; j++) {
|
54
|
+
int mask = 0;
|
55
|
+
aeFileEvent *fe = &eventLoop->events[j];
|
56
|
+
|
57
|
+
if (fe->mask == AE_NONE) continue;
|
58
|
+
if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds))
|
59
|
+
mask |= AE_READABLE;
|
60
|
+
if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds))
|
61
|
+
mask |= AE_WRITABLE;
|
62
|
+
eventLoop->fired[numevents].fd = j;
|
63
|
+
eventLoop->fired[numevents].mask = mask;
|
64
|
+
numevents++;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
return numevents;
|
68
|
+
}
|
69
|
+
|
70
|
+
static char *aeApiName(void) {
|
71
|
+
return "select";
|
72
|
+
}
|
@@ -0,0 +1,347 @@
|
|
1
|
+
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
2
|
+
*
|
3
|
+
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions are met:
|
8
|
+
*
|
9
|
+
* * Redistributions of source code must retain the above copyright notice,
|
10
|
+
* this list of conditions and the following disclaimer.
|
11
|
+
* * Redistributions in binary form must reproduce the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer in the
|
13
|
+
* documentation and/or other materials provided with the distribution.
|
14
|
+
* * Neither the name of Redis nor the names of its contributors may be used
|
15
|
+
* to endorse or promote products derived from this software without
|
16
|
+
* specific prior written permission.
|
17
|
+
*
|
18
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
22
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
23
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include "fmacros.h"
|
32
|
+
|
33
|
+
#include <sys/types.h>
|
34
|
+
#include <sys/socket.h>
|
35
|
+
#include <sys/un.h>
|
36
|
+
#include <netinet/in.h>
|
37
|
+
#include <netinet/tcp.h>
|
38
|
+
#include <arpa/inet.h>
|
39
|
+
#include <unistd.h>
|
40
|
+
#include <fcntl.h>
|
41
|
+
#include <string.h>
|
42
|
+
#include <netdb.h>
|
43
|
+
#include <errno.h>
|
44
|
+
#include <stdarg.h>
|
45
|
+
#include <stdio.h>
|
46
|
+
|
47
|
+
#include "anet.h"
|
48
|
+
|
49
|
+
static void anetSetError(char *err, const char *fmt, ...)
|
50
|
+
{
|
51
|
+
va_list ap;
|
52
|
+
|
53
|
+
if (!err) return;
|
54
|
+
va_start(ap, fmt);
|
55
|
+
vsnprintf(err, ANET_ERR_LEN, fmt, ap);
|
56
|
+
va_end(ap);
|
57
|
+
}
|
58
|
+
|
59
|
+
int anetNonBlock(char *err, int fd)
|
60
|
+
{
|
61
|
+
int flags;
|
62
|
+
|
63
|
+
/* Set the socket nonblocking.
|
64
|
+
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
|
65
|
+
* interrupted by a signal. */
|
66
|
+
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
67
|
+
anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
|
68
|
+
return ANET_ERR;
|
69
|
+
}
|
70
|
+
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
71
|
+
anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
|
72
|
+
return ANET_ERR;
|
73
|
+
}
|
74
|
+
return ANET_OK;
|
75
|
+
}
|
76
|
+
|
77
|
+
int anetTcpNoDelay(char *err, int fd)
|
78
|
+
{
|
79
|
+
int yes = 1;
|
80
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1)
|
81
|
+
{
|
82
|
+
anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
|
83
|
+
return ANET_ERR;
|
84
|
+
}
|
85
|
+
return ANET_OK;
|
86
|
+
}
|
87
|
+
|
88
|
+
int anetSetSendBuffer(char *err, int fd, int buffsize)
|
89
|
+
{
|
90
|
+
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1)
|
91
|
+
{
|
92
|
+
anetSetError(err, "setsockopt SO_SNDBUF: %s", strerror(errno));
|
93
|
+
return ANET_ERR;
|
94
|
+
}
|
95
|
+
return ANET_OK;
|
96
|
+
}
|
97
|
+
|
98
|
+
int anetTcpKeepAlive(char *err, int fd)
|
99
|
+
{
|
100
|
+
int yes = 1;
|
101
|
+
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) {
|
102
|
+
anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
|
103
|
+
return ANET_ERR;
|
104
|
+
}
|
105
|
+
return ANET_OK;
|
106
|
+
}
|
107
|
+
|
108
|
+
int anetResolve(char *err, char *host, char *ipbuf)
|
109
|
+
{
|
110
|
+
struct sockaddr_in sa;
|
111
|
+
|
112
|
+
sa.sin_family = AF_INET;
|
113
|
+
if (inet_aton(host, &sa.sin_addr) == 0) {
|
114
|
+
struct hostent *he;
|
115
|
+
|
116
|
+
he = gethostbyname(host);
|
117
|
+
if (he == NULL) {
|
118
|
+
anetSetError(err, "can't resolve: %s", host);
|
119
|
+
return ANET_ERR;
|
120
|
+
}
|
121
|
+
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
|
122
|
+
}
|
123
|
+
strcpy(ipbuf,inet_ntoa(sa.sin_addr));
|
124
|
+
return ANET_OK;
|
125
|
+
}
|
126
|
+
|
127
|
+
static int anetCreateSocket(char *err, int domain) {
|
128
|
+
int s, on = 1;
|
129
|
+
if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
|
130
|
+
anetSetError(err, "creating socket: %s", strerror(errno));
|
131
|
+
return ANET_ERR;
|
132
|
+
}
|
133
|
+
|
134
|
+
/* Make sure connection-intensive things like the redis benckmark
|
135
|
+
* will be able to close/open sockets a zillion of times */
|
136
|
+
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
137
|
+
anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
|
138
|
+
return ANET_ERR;
|
139
|
+
}
|
140
|
+
return s;
|
141
|
+
}
|
142
|
+
|
143
|
+
#define ANET_CONNECT_NONE 0
|
144
|
+
#define ANET_CONNECT_NONBLOCK 1
|
145
|
+
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
|
146
|
+
{
|
147
|
+
int s;
|
148
|
+
struct sockaddr_in sa;
|
149
|
+
|
150
|
+
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
|
151
|
+
return ANET_ERR;
|
152
|
+
|
153
|
+
sa.sin_family = AF_INET;
|
154
|
+
sa.sin_port = htons(port);
|
155
|
+
if (inet_aton(addr, &sa.sin_addr) == 0) {
|
156
|
+
struct hostent *he;
|
157
|
+
|
158
|
+
he = gethostbyname(addr);
|
159
|
+
if (he == NULL) {
|
160
|
+
anetSetError(err, "can't resolve: %s", addr);
|
161
|
+
close(s);
|
162
|
+
return ANET_ERR;
|
163
|
+
}
|
164
|
+
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
|
165
|
+
}
|
166
|
+
if (flags & ANET_CONNECT_NONBLOCK) {
|
167
|
+
if (anetNonBlock(err,s) != ANET_OK)
|
168
|
+
return ANET_ERR;
|
169
|
+
}
|
170
|
+
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
171
|
+
if (errno == EINPROGRESS &&
|
172
|
+
flags & ANET_CONNECT_NONBLOCK)
|
173
|
+
return s;
|
174
|
+
|
175
|
+
anetSetError(err, "connect: %s", strerror(errno));
|
176
|
+
close(s);
|
177
|
+
return ANET_ERR;
|
178
|
+
}
|
179
|
+
return s;
|
180
|
+
}
|
181
|
+
|
182
|
+
int anetTcpConnect(char *err, char *addr, int port)
|
183
|
+
{
|
184
|
+
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
|
185
|
+
}
|
186
|
+
|
187
|
+
int anetTcpNonBlockConnect(char *err, char *addr, int port)
|
188
|
+
{
|
189
|
+
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
|
190
|
+
}
|
191
|
+
|
192
|
+
int anetUnixGenericConnect(char *err, char *path, int flags)
|
193
|
+
{
|
194
|
+
int s;
|
195
|
+
struct sockaddr_un sa;
|
196
|
+
|
197
|
+
if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
|
198
|
+
return ANET_ERR;
|
199
|
+
|
200
|
+
sa.sun_family = AF_LOCAL;
|
201
|
+
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
202
|
+
if (flags & ANET_CONNECT_NONBLOCK) {
|
203
|
+
if (anetNonBlock(err,s) != ANET_OK)
|
204
|
+
return ANET_ERR;
|
205
|
+
}
|
206
|
+
if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) {
|
207
|
+
if (errno == EINPROGRESS &&
|
208
|
+
flags & ANET_CONNECT_NONBLOCK)
|
209
|
+
return s;
|
210
|
+
|
211
|
+
anetSetError(err, "connect: %s", strerror(errno));
|
212
|
+
close(s);
|
213
|
+
return ANET_ERR;
|
214
|
+
}
|
215
|
+
return s;
|
216
|
+
}
|
217
|
+
|
218
|
+
int anetUnixConnect(char *err, char *path)
|
219
|
+
{
|
220
|
+
return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE);
|
221
|
+
}
|
222
|
+
|
223
|
+
int anetUnixNonBlockConnect(char *err, char *path)
|
224
|
+
{
|
225
|
+
return anetUnixGenericConnect(err,path,ANET_CONNECT_NONBLOCK);
|
226
|
+
}
|
227
|
+
|
228
|
+
/* Like read(2) but make sure 'count' is read before to return
|
229
|
+
* (unless error or EOF condition is encountered) */
|
230
|
+
int anetRead(int fd, char *buf, int count)
|
231
|
+
{
|
232
|
+
int nread, totlen = 0;
|
233
|
+
while(totlen != count) {
|
234
|
+
nread = read(fd,buf,count-totlen);
|
235
|
+
if (nread == 0) return totlen;
|
236
|
+
if (nread == -1) return -1;
|
237
|
+
totlen += nread;
|
238
|
+
buf += nread;
|
239
|
+
}
|
240
|
+
return totlen;
|
241
|
+
}
|
242
|
+
|
243
|
+
/* Like write(2) but make sure 'count' is read before to return
|
244
|
+
* (unless error is encountered) */
|
245
|
+
int anetWrite(int fd, char *buf, int count)
|
246
|
+
{
|
247
|
+
int nwritten, totlen = 0;
|
248
|
+
while(totlen != count) {
|
249
|
+
nwritten = write(fd,buf,count-totlen);
|
250
|
+
if (nwritten == 0) return totlen;
|
251
|
+
if (nwritten == -1) return -1;
|
252
|
+
totlen += nwritten;
|
253
|
+
buf += nwritten;
|
254
|
+
}
|
255
|
+
return totlen;
|
256
|
+
}
|
257
|
+
|
258
|
+
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
|
259
|
+
if (bind(s,sa,len) == -1) {
|
260
|
+
anetSetError(err, "bind: %s", strerror(errno));
|
261
|
+
close(s);
|
262
|
+
return ANET_ERR;
|
263
|
+
}
|
264
|
+
if (listen(s, 511) == -1) { /* the magic 511 constant is from nginx */
|
265
|
+
anetSetError(err, "listen: %s", strerror(errno));
|
266
|
+
close(s);
|
267
|
+
return ANET_ERR;
|
268
|
+
}
|
269
|
+
return ANET_OK;
|
270
|
+
}
|
271
|
+
|
272
|
+
int anetTcpServer(char *err, int port, char *bindaddr)
|
273
|
+
{
|
274
|
+
int s;
|
275
|
+
struct sockaddr_in sa;
|
276
|
+
|
277
|
+
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
|
278
|
+
return ANET_ERR;
|
279
|
+
|
280
|
+
memset(&sa,0,sizeof(sa));
|
281
|
+
sa.sin_family = AF_INET;
|
282
|
+
sa.sin_port = htons(port);
|
283
|
+
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
284
|
+
if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) {
|
285
|
+
anetSetError(err, "invalid bind address");
|
286
|
+
close(s);
|
287
|
+
return ANET_ERR;
|
288
|
+
}
|
289
|
+
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
|
290
|
+
return ANET_ERR;
|
291
|
+
return s;
|
292
|
+
}
|
293
|
+
|
294
|
+
int anetUnixServer(char *err, char *path)
|
295
|
+
{
|
296
|
+
int s;
|
297
|
+
struct sockaddr_un sa;
|
298
|
+
|
299
|
+
if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
|
300
|
+
return ANET_ERR;
|
301
|
+
|
302
|
+
memset(&sa,0,sizeof(sa));
|
303
|
+
sa.sun_family = AF_LOCAL;
|
304
|
+
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
305
|
+
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
|
306
|
+
return ANET_ERR;
|
307
|
+
return s;
|
308
|
+
}
|
309
|
+
|
310
|
+
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
|
311
|
+
int fd;
|
312
|
+
while(1) {
|
313
|
+
fd = accept(s,sa,len);
|
314
|
+
if (fd == -1) {
|
315
|
+
if (errno == EINTR)
|
316
|
+
continue;
|
317
|
+
else {
|
318
|
+
anetSetError(err, "accept: %s", strerror(errno));
|
319
|
+
return ANET_ERR;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
break;
|
323
|
+
}
|
324
|
+
return fd;
|
325
|
+
}
|
326
|
+
|
327
|
+
int anetTcpAccept(char *err, int s, char *ip, int *port) {
|
328
|
+
int fd;
|
329
|
+
struct sockaddr_in sa;
|
330
|
+
socklen_t salen = sizeof(sa);
|
331
|
+
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
|
332
|
+
return ANET_ERR;
|
333
|
+
|
334
|
+
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
|
335
|
+
if (port) *port = ntohs(sa.sin_port);
|
336
|
+
return fd;
|
337
|
+
}
|
338
|
+
|
339
|
+
int anetUnixAccept(char *err, int s) {
|
340
|
+
int fd;
|
341
|
+
struct sockaddr_un sa;
|
342
|
+
socklen_t salen = sizeof(sa);
|
343
|
+
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
|
344
|
+
return ANET_ERR;
|
345
|
+
|
346
|
+
return fd;
|
347
|
+
}
|