mirror of
https://gitee.com/lauix/HFish
synced 2025-05-11 12:28:02 +08:00
commit
72949e4839
@ -49,4 +49,9 @@ addr = 0.0.0.0:23 # Telnet 服务端地址 注意端
|
||||
|
||||
[ftp]
|
||||
status = 0 # 是否启动 Ftp 1 启动 0 关闭
|
||||
addr = 0.0.0.0:21 # Ftp 服务端地址 注意端口冲突
|
||||
addr = 0.0.0.0:21 # Ftp 服务端地址 注意端口冲突
|
||||
|
||||
[memcache]
|
||||
status = 0 # 是否启动 Memcache 1 启动 0 关闭
|
||||
addr = 0.0.0.0:11211 # Memcache 服务端地址 注意端口冲突
|
||||
ratelimit = 4 # 每秒响应次数
|
86
core/protocol/memcache/LinkedHashMap/linked_hashmap.go
Normal file
86
core/protocol/memcache/LinkedHashMap/linked_hashmap.go
Normal file
@ -0,0 +1,86 @@
|
||||
package LinkedHashMap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type LinkedHashMapNode struct {
|
||||
linklistNode *LinkListNode
|
||||
val interface{}
|
||||
}
|
||||
|
||||
type LinkedHashMap struct {
|
||||
linklist *LinkList
|
||||
hashmap map[string]interface{}
|
||||
mutex *sync.RWMutex
|
||||
}
|
||||
|
||||
func NewLinkedHashMap() *LinkedHashMap {
|
||||
return &LinkedHashMap{
|
||||
linklist: NewLinkList(),
|
||||
hashmap: make(map[string]interface{}),
|
||||
mutex: &sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) Lock() {
|
||||
this.mutex.Lock()
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) Unlock() {
|
||||
this.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) RLock() {
|
||||
this.mutex.RLock()
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) RUnlock() {
|
||||
this.mutex.RUnlock()
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) Add(key string, val interface{}) bool {
|
||||
_, isExists := this.hashmap[key]
|
||||
if isExists {
|
||||
return false
|
||||
}
|
||||
|
||||
linkListNode := this.linklist.AddToTail(key)
|
||||
this.hashmap[key] = &LinkedHashMapNode{
|
||||
linklistNode: linkListNode,
|
||||
val: val,
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) Get(key string) interface{} {
|
||||
originLinkedHashMapNode, isExists := this.hashmap[key]
|
||||
if !isExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (originLinkedHashMapNode.(*LinkedHashMapNode)).val
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) Len() int {
|
||||
return len(this.hashmap)
|
||||
}
|
||||
|
||||
|
||||
func (this *LinkedHashMap) Remove(key string) (bool, interface{}) {
|
||||
originLinkedHashMapNode, isExists := this.hashmap[key]
|
||||
if !isExists {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
linkedHashMapNode := originLinkedHashMapNode.(*LinkedHashMapNode)
|
||||
|
||||
delete(this.hashmap, key)
|
||||
this.linklist.RemoveNode(linkedHashMapNode.linklistNode)
|
||||
return true, linkedHashMapNode.val
|
||||
}
|
||||
|
||||
func (this *LinkedHashMap) GetLinkList() *LinkList {
|
||||
return this.linklist
|
||||
}
|
141
core/protocol/memcache/LinkedHashMap/linklist.go
Normal file
141
core/protocol/memcache/LinkedHashMap/linklist.go
Normal file
@ -0,0 +1,141 @@
|
||||
package LinkedHashMap
|
||||
|
||||
type LinkListNode struct {
|
||||
last *LinkListNode
|
||||
next *LinkListNode
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func NewLinkListNode(last *LinkListNode, next *LinkListNode, val interface{}) *LinkListNode {
|
||||
node := &LinkListNode{
|
||||
last: last,
|
||||
next: next,
|
||||
val: val,
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
func (this *LinkListNode) SetLast(node *LinkListNode) {
|
||||
this.last = node
|
||||
}
|
||||
|
||||
func (this *LinkListNode) SetNext(node *LinkListNode) {
|
||||
this.next = node
|
||||
}
|
||||
|
||||
func (this *LinkListNode) GetLast() *LinkListNode {
|
||||
return this.last
|
||||
}
|
||||
|
||||
func (this *LinkListNode) GetNext() *LinkListNode {
|
||||
return this.next
|
||||
}
|
||||
|
||||
func (this *LinkListNode) GetVal() interface{} {
|
||||
return this.val
|
||||
}
|
||||
|
||||
func (this *LinkListNode) IsHead() bool {
|
||||
return this.last == nil
|
||||
}
|
||||
|
||||
func (this *LinkListNode) IsTail() bool {
|
||||
return this.next == nil
|
||||
}
|
||||
|
||||
type LinkList struct {
|
||||
head *LinkListNode
|
||||
tail *LinkListNode
|
||||
length int
|
||||
}
|
||||
|
||||
func NewLinkList() *LinkList {
|
||||
return &LinkList{
|
||||
head: nil,
|
||||
tail: nil,
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *LinkList) GetHead() *LinkListNode {
|
||||
return this.head
|
||||
}
|
||||
|
||||
func (this *LinkList) GetTail() *LinkListNode {
|
||||
return this.tail
|
||||
}
|
||||
|
||||
func (this *LinkList) AddToHead(val interface{}) *LinkListNode {
|
||||
if this.head == nil && this.tail == nil {
|
||||
return this.addFirstNode(val)
|
||||
|
||||
}
|
||||
node := NewLinkListNode(nil, this.head, val)
|
||||
this.head.SetLast(node)
|
||||
this.head = node
|
||||
this.length++
|
||||
return node
|
||||
}
|
||||
|
||||
func (this *LinkList) AddToTail(val interface{}) *LinkListNode {
|
||||
if this.head == nil && this.tail == nil {
|
||||
return this.addFirstNode(val)
|
||||
|
||||
}
|
||||
node := NewLinkListNode(this.tail, nil, val)
|
||||
this.tail.SetNext(node)
|
||||
this.tail = node
|
||||
this.length++
|
||||
return node
|
||||
}
|
||||
|
||||
func (this *LinkList) RemoveNode(node *LinkListNode) {
|
||||
defer func() {
|
||||
this.length--
|
||||
}()
|
||||
|
||||
/* LinkList中只有1个元素 */
|
||||
if node.IsHead() && node.IsTail() {
|
||||
this.head = nil
|
||||
this.tail = nil
|
||||
return
|
||||
}
|
||||
|
||||
/* 节点是头节点 */
|
||||
if node.IsHead() {
|
||||
nextNode := node.GetNext()
|
||||
this.head = nextNode
|
||||
nextNode.SetLast(nil)
|
||||
node.SetNext(nil)
|
||||
return
|
||||
}
|
||||
|
||||
/* 节点是尾节点 */
|
||||
if node.IsTail() {
|
||||
lastNode := node.GetLast()
|
||||
this.tail = lastNode
|
||||
lastNode.SetNext(nil)
|
||||
node.SetLast(nil)
|
||||
return
|
||||
}
|
||||
|
||||
lastNode := node.GetLast()
|
||||
nextNode := node.GetNext()
|
||||
|
||||
lastNode.SetNext(nextNode)
|
||||
nextNode.SetLast(lastNode)
|
||||
node.SetLast(nil)
|
||||
node.SetNext(nil)
|
||||
}
|
||||
|
||||
func (this *LinkList) GetLength() int {
|
||||
return this.length
|
||||
}
|
||||
|
||||
func (this *LinkList) addFirstNode(val interface{}) *LinkListNode {
|
||||
node := NewLinkListNode(nil, nil, val)
|
||||
this.head = node
|
||||
this.tail = node
|
||||
this.length++
|
||||
return node
|
||||
}
|
23
core/protocol/memcache/global.go
Normal file
23
core/protocol/memcache/global.go
Normal file
@ -0,0 +1,23 @@
|
||||
package memcache
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func randNumber(min int, max int) int {
|
||||
return rand.Intn(max-min) + min
|
||||
}
|
||||
|
||||
var UPTIME time.Time = time.Now()
|
||||
var RESPONSE_OK []byte = []byte("OK\r\n")
|
||||
var RESPONSE_END []byte = []byte("END\r\n")
|
||||
var RESPONSE_RESET []byte = []byte("RESET\r\n")
|
||||
var RESPONSE_ERROR []byte = []byte("ERROR\r\n")
|
||||
var RESPONSE_DELETED []byte = []byte("DELETED\r\n")
|
||||
var RESPONSE_NOT_FOUND []byte = []byte("NOT_FOUND\r\n")
|
||||
var RESPONSE_VERSION []byte = []byte("VERSION 1.5.16\r\n")
|
||||
var RESPONSE_CLIENT_ERROR []byte = []byte("CLIENT_ERROR ")
|
||||
var RESPONSE_SERVER_ERROR []byte = []byte("SERVER_ERROR ")
|
||||
var RESPONSE_BAD_COMMAND_LINE []byte = []byte("bad command line format\r\n")
|
||||
var RESPONSE_OBJECT_TOO_LARGE []byte = []byte("object too large for cache\r\n")
|
554
core/protocol/memcache/memcache.go
Normal file
554
core/protocol/memcache/memcache.go
Normal file
@ -0,0 +1,554 @@
|
||||
package memcache
|
||||
|
||||
/**
|
||||
* Supported commands:
|
||||
* get <key>\r\n
|
||||
* set <key> <flags> <ttl> <size>\r\ndata\r\n
|
||||
* add <key> <flags> <ttl> <size>\r\ndata\r\n
|
||||
* delete <key>
|
||||
* flush_all
|
||||
* stats
|
||||
* stats slabs
|
||||
* stats malloc
|
||||
* stats items
|
||||
* stats detail
|
||||
* stats sizes
|
||||
* version
|
||||
* verbosity
|
||||
* quit
|
||||
*/
|
||||
|
||||
import (
|
||||
"HFish/core/protocol/memcache/LinkedHashMap"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var linkedHashMap = LinkedHashMap.NewLinkedHashMap()
|
||||
var networkRx = 100
|
||||
var networkTx = 150
|
||||
|
||||
var commands = map[string]func([]string) ([]byte, int){
|
||||
|
||||
"quit": func(args []string) ([]byte, int) {
|
||||
return nil, -1
|
||||
},
|
||||
|
||||
"verbosity": func(args []string) ([]byte, int) {
|
||||
if len(args) < 1 {
|
||||
return RESPONSE_ERROR, 0
|
||||
}
|
||||
return RESPONSE_OK, 0
|
||||
},
|
||||
|
||||
"flush_all": func(args []string) ([]byte, int) {
|
||||
linkedHashMap.Lock()
|
||||
defer linkedHashMap.Unlock()
|
||||
|
||||
linklist := linkedHashMap.GetLinkList()
|
||||
for {
|
||||
node := linklist.GetHead()
|
||||
if node == nil {
|
||||
break
|
||||
}
|
||||
key := node.GetVal().(string)
|
||||
nextNode := node.GetNext()
|
||||
linkedHashMap.Remove(key)
|
||||
node = nextNode
|
||||
}
|
||||
|
||||
return RESPONSE_OK, 0
|
||||
},
|
||||
|
||||
"version": func(args []string) ([]byte, int) {
|
||||
if len(args) != 0 {
|
||||
return RESPONSE_ERROR, 0
|
||||
}
|
||||
return RESPONSE_VERSION, 0
|
||||
},
|
||||
|
||||
"get": func(args []string) ([]byte, int) {
|
||||
if len(args) < 1 {
|
||||
return RESPONSE_ERROR, 0
|
||||
}
|
||||
|
||||
linkedHashMap.RLock()
|
||||
defer linkedHashMap.RUnlock()
|
||||
|
||||
val := linkedHashMap.Get(args[0])
|
||||
if val == nil {
|
||||
return RESPONSE_END, 0
|
||||
}
|
||||
return append([]byte(val.(string)+"\r\n"), RESPONSE_END...), 0
|
||||
},
|
||||
|
||||
"set": func(args []string) ([]byte, int) {
|
||||
if len(args) == 5 {
|
||||
key := args[0]
|
||||
data := args[4]
|
||||
linkedHashMap.Lock()
|
||||
defer linkedHashMap.Unlock()
|
||||
items := linkedHashMap.Len()
|
||||
for ; items > 60; items-- {
|
||||
_, _ = linkedHashMap.Remove(linkedHashMap.GetLinkList().GetHead().GetVal().(string))
|
||||
}
|
||||
linkedHashMap.Add(key, data)
|
||||
return []byte("STORED\r\n"), 0
|
||||
}
|
||||
|
||||
if len(args) == 4 {
|
||||
flags := args[1]
|
||||
ttl := args[2]
|
||||
size := args[3]
|
||||
|
||||
_, err := strconv.Atoi(flags)
|
||||
if err != nil {
|
||||
return append(RESPONSE_CLIENT_ERROR, RESPONSE_BAD_COMMAND_LINE...), 0
|
||||
}
|
||||
_, err = strconv.Atoi(ttl)
|
||||
if err != nil {
|
||||
return append(RESPONSE_CLIENT_ERROR, RESPONSE_BAD_COMMAND_LINE...), 0
|
||||
}
|
||||
parsedSize, err := strconv.Atoi(size)
|
||||
if err != nil {
|
||||
return append(RESPONSE_CLIENT_ERROR, RESPONSE_BAD_COMMAND_LINE...), 0
|
||||
}
|
||||
if parsedSize > 1500 {
|
||||
return append(RESPONSE_SERVER_ERROR, RESPONSE_OBJECT_TOO_LARGE...), 0
|
||||
}
|
||||
return nil, parsedSize
|
||||
}
|
||||
|
||||
return RESPONSE_ERROR, 0
|
||||
},
|
||||
|
||||
"add": func(args []string) ([]byte, int) {
|
||||
if len(args) == 5 {
|
||||
key := args[0]
|
||||
data := args[4]
|
||||
linkedHashMap.Lock()
|
||||
defer linkedHashMap.Unlock()
|
||||
if linkedHashMap.Get(key) != nil {
|
||||
return []byte("NOT_STORED\r\n"), 0
|
||||
}
|
||||
items := linkedHashMap.Len()
|
||||
for ; items > 60; items-- {
|
||||
fmt.Println(items)
|
||||
_, _ = linkedHashMap.Remove(linkedHashMap.GetLinkList().GetHead().GetVal().(string))
|
||||
}
|
||||
linkedHashMap.Add(key, data)
|
||||
return []byte("STORED\r\n"), 0
|
||||
}
|
||||
|
||||
if len(args) == 4 {
|
||||
flags := args[1]
|
||||
ttl := args[2]
|
||||
size := args[3]
|
||||
|
||||
_, err := strconv.Atoi(flags)
|
||||
if err != nil {
|
||||
return append(RESPONSE_CLIENT_ERROR, RESPONSE_BAD_COMMAND_LINE...), 0
|
||||
}
|
||||
_, err = strconv.Atoi(ttl)
|
||||
if err != nil {
|
||||
return append(RESPONSE_CLIENT_ERROR, RESPONSE_BAD_COMMAND_LINE...), 0
|
||||
}
|
||||
parsedSize, err := strconv.Atoi(size)
|
||||
if err != nil {
|
||||
return append(RESPONSE_CLIENT_ERROR, RESPONSE_BAD_COMMAND_LINE...), 0
|
||||
}
|
||||
if parsedSize > 1024 {
|
||||
return append(RESPONSE_SERVER_ERROR, RESPONSE_OBJECT_TOO_LARGE...), 0
|
||||
}
|
||||
return nil, parsedSize
|
||||
}
|
||||
|
||||
return RESPONSE_ERROR, 0
|
||||
},
|
||||
|
||||
"delete": func(args []string) ([]byte, int) {
|
||||
if len(args) < 1 {
|
||||
return RESPONSE_ERROR, 0
|
||||
}
|
||||
|
||||
linkedHashMap.Lock()
|
||||
defer linkedHashMap.Unlock()
|
||||
|
||||
result, _ := linkedHashMap.Remove(args[0])
|
||||
if !result {
|
||||
return RESPONSE_NOT_FOUND, 0
|
||||
}
|
||||
return RESPONSE_DELETED, 0
|
||||
},
|
||||
|
||||
"stats": func(args []string) ([]byte, int) {
|
||||
nowTime := time.Now()
|
||||
networkRx = networkRx + randNumber(10, 50)
|
||||
networkTx = networkTx + randNumber(100, 500)
|
||||
linkedHashMap.RLock()
|
||||
defer linkedHashMap.RUnlock()
|
||||
items := linkedHashMap.Len()
|
||||
|
||||
if len(args) == 0 {
|
||||
statsArray := []string{
|
||||
"STAT pid 1\r\n",
|
||||
fmt.Sprintf("STAT uptime %d\r\n", int(nowTime.Sub(UPTIME)/time.Second)),
|
||||
fmt.Sprintf("STAT time %d\r\n", nowTime.Unix()),
|
||||
"STAT version 1.5.16\r\n",
|
||||
"STAT libevent 2.1.8-stable\r\n",
|
||||
"STAT pointer_size 64\r\n",
|
||||
"STAT rusage_user 0.029000\r\n",
|
||||
"STAT rusage_system 0.029000\r\n",
|
||||
"STAT max_connections 1024\r\n",
|
||||
fmt.Sprintf("STAT curr_connections %d\r\n", randNumber(1, 5)),
|
||||
"STAT rejected_connections 0\r\n",
|
||||
"STAT connection_structures 3\r\n",
|
||||
"STAT reserved_fds 20\r\n",
|
||||
"STAT cmd_get 0\r\n",
|
||||
"STAT cmd_set 0\r\n",
|
||||
"STAT cmd_flush 0\r\n",
|
||||
"STAT cmd_touch 0\r\n",
|
||||
"STAT get_hits 0\r\n",
|
||||
"STAT get_misses 0\r\n",
|
||||
"STAT get_expired 0\r\n",
|
||||
"STAT get_flushed 0\r\n",
|
||||
"STAT delete_misses 0\r\n",
|
||||
"STAT delete_hits 0\r\n",
|
||||
"STAT incr_misses 0\r\n",
|
||||
"STAT incr_hits 0\r\n",
|
||||
"STAT decr_misses 0\r\n",
|
||||
"STAT decr_hits 0\r\n",
|
||||
"STAT cas_misses 0\r\n",
|
||||
"STAT cas_hits 0\r\n",
|
||||
"STAT cas_badval 0\r\n",
|
||||
"STAT touch_hits 0\r\n",
|
||||
"STAT touch_misses 0\r\n",
|
||||
"STAT auth_cmds 0\r\n",
|
||||
"STAT auth_errors 0\r\n",
|
||||
fmt.Sprintf("STAT bytes_read %d\r\n", networkRx),
|
||||
fmt.Sprintf("STAT bytes_written %d\r\n", networkTx),
|
||||
"STAT limit_maxbytes 67108864\r\n",
|
||||
"STAT accepting_conns 1\r\n",
|
||||
"STAT listen_disabled_num 0\r\n",
|
||||
"STAT time_in_listen_disabled_us 0\r\n",
|
||||
"STAT threads 4\r\n",
|
||||
"STAT conn_yields 0\r\n",
|
||||
"STAT hash_power_level 16\r\n",
|
||||
"STAT hash_bytes 524288\r\n",
|
||||
"STAT hash_is_expanding 0\r\n",
|
||||
"STAT slab_reassign_rescues 0\r\n",
|
||||
"STAT slab_reassign_chunk_rescues 0\r\n",
|
||||
"STAT slab_reassign_evictions_nomem 0\r\n",
|
||||
"STAT slab_reassign_inline_reclaim 0\r\n",
|
||||
"STAT slab_reassign_busy_items 0\r\n",
|
||||
"STAT slab_reassign_busy_deletes 0\r\n",
|
||||
"STAT slab_reassign_running 0\r\n",
|
||||
"STAT slabs_moved 0\r\n",
|
||||
"STAT lru_crawler_running 0\r\n",
|
||||
"STAT lru_crawler_starts 510\r\n",
|
||||
"STAT lru_maintainer_juggles 224\r\n",
|
||||
"STAT malloc_fails 0\r\n",
|
||||
"STAT log_worker_dropped 0\r\n",
|
||||
"STAT log_worker_written 0\r\n",
|
||||
"STAT log_watcher_skipped 0\r\n",
|
||||
"STAT log_watcher_sent 0\r\n",
|
||||
"STAT bytes 0\r\n",
|
||||
fmt.Sprintf("STAT curr_items %d\r\n", items),
|
||||
"STAT total_items 0\r\n",
|
||||
"STAT slab_global_page_pool 0\r\n",
|
||||
"STAT expired_unfetched 0\r\n",
|
||||
"STAT evicted_unfetched 0\r\n",
|
||||
"STAT evicted_active 0\r\n",
|
||||
"STAT evictions 0\r\n",
|
||||
"STAT reclaimed 0\r\n",
|
||||
"STAT crawler_reclaimed 0\r\n",
|
||||
"STAT crawler_items_checked 0\r\n",
|
||||
"STAT lrutail_reflocked 0\r\n",
|
||||
"STAT moves_to_cold 0\r\n",
|
||||
"STAT moves_to_warm 0\r\n",
|
||||
"STAT moves_within_lru 0\r\n",
|
||||
"STAT direct_reclaims 0\r\n",
|
||||
"STAT lru_bumps_dropped 0\r\n",
|
||||
"END\r\n",
|
||||
}
|
||||
responseBuffer := []byte{}
|
||||
for _, response := range statsArray {
|
||||
responseBuffer = append(responseBuffer, []byte(response)...)
|
||||
}
|
||||
return responseBuffer, 0
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "slabs":
|
||||
statsArray := []string{
|
||||
"STAT 1:chunk_size 96\r\n",
|
||||
"STAT 1:chunks_per_page 10922\r\n",
|
||||
"STAT 1:total_pages 1\r\n",
|
||||
"STAT 1:total_chunks 10922\r\n",
|
||||
"STAT 1:used_chunks 1\r\n",
|
||||
"STAT 1:free_chunks 10921\r\n",
|
||||
"STAT 1:free_chunks_end 0\r\n",
|
||||
"STAT 1:mem_requested 68\r\n",
|
||||
"STAT 1:get_hits 0\r\n",
|
||||
"STAT 1:cmd_set 0\r\n",
|
||||
"STAT 1:delete_hits 0\r\n",
|
||||
"STAT 1:incr_hits 0\r\n",
|
||||
"STAT 1:decr_hits 0\r\n",
|
||||
"STAT 1:cas_hits 0\r\n",
|
||||
"STAT 1:cas_badval 0\r\n",
|
||||
"STAT 1:touch_hits 0\r\n",
|
||||
"STAT 2:chunk_size 120\r\n",
|
||||
"STAT 2:chunks_per_page 8738\r\n",
|
||||
"STAT 2:total_pages 1\r\n",
|
||||
"STAT 2:total_chunks 8738\r\n",
|
||||
"STAT 2:used_chunks 0\r\n",
|
||||
"STAT 2:free_chunks 8738\r\n",
|
||||
"STAT 2:free_chunks_end 0\r\n",
|
||||
"STAT 2:mem_requested 0\r\n",
|
||||
"STAT 2:get_hits 0\r\n",
|
||||
"STAT 2:cmd_set 0\r\n",
|
||||
"STAT 2:delete_hits 0\r\n",
|
||||
"STAT 2:incr_hits 0\r\n",
|
||||
"STAT 2:decr_hits 0\r\n",
|
||||
"STAT 2:cas_hits 0\r\n",
|
||||
"STAT 2:cas_badval 0\r\n",
|
||||
"STAT 2:touch_hits 0\r\n",
|
||||
"STAT 39:chunk_size 524288\r\n",
|
||||
"STAT 39:chunks_per_page 2\r\n",
|
||||
"STAT 39:total_pages 1\r\n",
|
||||
"STAT 39:total_chunks 2\r\n",
|
||||
"STAT 39:used_chunks 0\r\n",
|
||||
"STAT 39:free_chunks 2\r\n",
|
||||
"STAT 39:free_chunks_end 0\r\n",
|
||||
"STAT 39:mem_requested 0\r\n",
|
||||
"STAT 39:get_hits 0\r\n",
|
||||
"STAT 39:cmd_set 0\r\n",
|
||||
"STAT 39:delete_hits 0\r\n",
|
||||
"STAT 39:incr_hits 0\r\n",
|
||||
"STAT 39:decr_hits 0\r\n",
|
||||
"STAT 39:cas_hits 0\r\n",
|
||||
"STAT 39:cas_badval 0\r\n",
|
||||
"STAT 39:touch_hits 0\r\n",
|
||||
"STAT active_slabs 3\r\n",
|
||||
"STAT total_malloced 3145728\r\n",
|
||||
"END\r\n",
|
||||
}
|
||||
responseBuffer := []byte{}
|
||||
for _, response := range statsArray {
|
||||
responseBuffer = append(responseBuffer, []byte(response)...)
|
||||
}
|
||||
return responseBuffer, 0
|
||||
case "items":
|
||||
statsArray := []string{
|
||||
fmt.Sprintf("STAT items:1:number %d\r\n", items),
|
||||
"STAT items:1:number_hot 0\r\n",
|
||||
"STAT items:1:number_warm 0\r\n",
|
||||
fmt.Sprintf("STAT items:1:number_cold %d\r\n", items),
|
||||
"STAT items:1:age_hot 0\r\n",
|
||||
"STAT items:1:age_warm 0\r\n",
|
||||
"STAT items:1:age 31\r\n",
|
||||
"STAT items:1:evicted 0\r\n",
|
||||
"STAT items:1:evicted_nonzero 0\r\n",
|
||||
"STAT items:1:evicted_time 0\r\n",
|
||||
"STAT items:1:outofmemory 0\r\n",
|
||||
"STAT items:1:tailrepairs 0\r\n",
|
||||
"STAT items:1:reclaimed 1\r\n",
|
||||
"STAT items:1:expired_unfetched 1",
|
||||
"STAT items:1:evicted_unfetched 0\r\n",
|
||||
"STAT items:1:evicted_active 0\r\n",
|
||||
"STAT items:1:crawler_reclaimed 0\r\n",
|
||||
"STAT items:1:crawler_items_checked 0\r\n",
|
||||
"STAT items:1:lrutail_reflocked 0\r\n",
|
||||
"STAT items:1:moves_to_cold 3\r\n",
|
||||
"STAT items:1:moves_to_warm 0\r\n",
|
||||
"STAT items:1:moves_within_lru 0\r\n",
|
||||
"STAT items:1:direct_reclaims 0\r\n",
|
||||
"STAT items:1:hits_to_hot 0\r\n",
|
||||
"STAT items:1:hits_to_warm 0\r\n",
|
||||
"STAT items:1:hits_to_cold 0\r\n",
|
||||
"STAT items:1:hits_to_temp 0\r\n",
|
||||
"END\r\n",
|
||||
}
|
||||
responseBuffer := []byte{}
|
||||
for _, response := range statsArray {
|
||||
responseBuffer = append(responseBuffer, []byte(response)...)
|
||||
}
|
||||
return responseBuffer, 0
|
||||
case "detail":
|
||||
return RESPONSE_OK, 0
|
||||
case "sizes":
|
||||
return append([]byte("STAT sizes_status disabled\r\n"), RESPONSE_END...), 0
|
||||
case "reset":
|
||||
return RESPONSE_RESET, 0
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return RESPONSE_ERROR, 0
|
||||
},
|
||||
}
|
||||
|
||||
// TCP服务端连接
|
||||
func tcpServer(address string, rateLimitChan chan int, exitChan chan int) {
|
||||
l, err := net.Listen("tcp", address)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
exitChan <- 1
|
||||
}
|
||||
|
||||
log.Println("[Memcache TCP] Listning on " + address)
|
||||
|
||||
defer l.Close()
|
||||
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
trackID := randNumber(100000, 999999)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
go func() {
|
||||
skip := false
|
||||
reader := bufio.NewReader(conn)
|
||||
log.Printf("[Memcache TCP %d] Accepted a client socket from %s\n", trackID, conn.RemoteAddr().String())
|
||||
for {
|
||||
<-rateLimitChan
|
||||
str, err := reader.ReadString('\n')
|
||||
if skip {
|
||||
skip = false
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("[Memcache TCP %d] Closed a client socket.\n", trackID)
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
log.Printf("[Memcache TCP %d] Client request: %s.\n", trackID, str)
|
||||
args := strings.Split(str, " ")
|
||||
function, exist := commands[args[0]]
|
||||
if !exist {
|
||||
conn.Write(RESPONSE_ERROR)
|
||||
continue
|
||||
}
|
||||
|
||||
args = args[1:]
|
||||
|
||||
for {
|
||||
response, requiredBytes := function(args)
|
||||
if requiredBytes == -1 {
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
if requiredBytes == 0 {
|
||||
conn.Write(response)
|
||||
break
|
||||
}
|
||||
|
||||
data := make([]byte, requiredBytes)
|
||||
_, err = io.ReadFull(reader, data)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
skip = true
|
||||
args = append(args, string(data))
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func udpServer(address string, rateLimitChan chan int, exitChan chan int) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", address)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
exitChan <- 1
|
||||
}
|
||||
|
||||
l, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
exitChan <- 1
|
||||
}
|
||||
|
||||
log.Println("[Memcache UDP] Listning on " + address)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 1500)
|
||||
for {
|
||||
<-rateLimitChan
|
||||
plen, addr, _ := l.ReadFromUDP(buf)
|
||||
/* UDP协议需要8个字节的头 */
|
||||
if plen < 8 {
|
||||
continue
|
||||
}
|
||||
requestStr := string(buf[8:plen])
|
||||
|
||||
for _, request := range strings.Split(requestStr, "\n") {
|
||||
request = strings.TrimSpace(request)
|
||||
if request == "" {
|
||||
continue
|
||||
}
|
||||
log.Printf("[Memcache UDP] Client request: [%s] from: %s\n", request, addr.String())
|
||||
args := strings.Split(request, " ")
|
||||
function, exist := commands[args[0]]
|
||||
if !exist {
|
||||
continue
|
||||
}
|
||||
args = args[1:]
|
||||
|
||||
response, requiredBytes := function(args)
|
||||
if requiredBytes != 0 {
|
||||
continue
|
||||
}
|
||||
if len(response) > 1300 {
|
||||
response = response[:1300]
|
||||
}
|
||||
l.WriteTo(append([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, response...), addr)
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func Start(addr string, rateLimitStr string) {
|
||||
// 创建一个程序结束码的通道
|
||||
exitChan := make(chan int)
|
||||
|
||||
// 响应间隔限制
|
||||
rateLimitChan := make(chan int)
|
||||
rateLimit, err := strconv.Atoi(rateLimitStr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
sleepTime := 1000 / rateLimit
|
||||
for {
|
||||
rateLimitChan <- 1
|
||||
time.Sleep(time.Duration(sleepTime) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// 将服务器并发运行
|
||||
go tcpServer(addr, rateLimitChan, exitChan)
|
||||
go udpServer(addr, rateLimitChan, exitChan)
|
||||
|
||||
// 通道阻塞,等待接受返回值
|
||||
code := <-exitChan
|
||||
|
||||
// 标记程序返回值并退出
|
||||
os.Exit(code)
|
||||
}
|
@ -14,6 +14,7 @@ import (
|
||||
"HFish/core/protocol/ssh"
|
||||
"HFish/core/protocol/redis"
|
||||
"HFish/core/protocol/mysql"
|
||||
"HFish/core/protocol/memcache"
|
||||
"HFish/core/protocol/ftp"
|
||||
"HFish/core/protocol/telnet"
|
||||
"HFish/core/rpc/server"
|
||||
@ -208,6 +209,18 @@ func Run() {
|
||||
|
||||
//=========================//
|
||||
|
||||
// 启动 Memcache 蜜罐
|
||||
memcacheStatus := conf.Get("memcache", "status")
|
||||
memcacheRateLimit := conf.Get("memcache", "ratelimit")
|
||||
|
||||
// 判断 暗网 Web 蜜罐 是否开启
|
||||
if memcacheStatus == "1" {
|
||||
memcacheAddr := conf.Get("memcache", "addr")
|
||||
go memcache.Start(memcacheAddr, memcacheRateLimit)
|
||||
}
|
||||
|
||||
//=========================//
|
||||
|
||||
// 启动 RPC
|
||||
rpcStatus := conf.Get("rpc", "status")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user