2013-12-03 22:19:42 +00:00
|
|
|
package coordinator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
|
|
|
"io"
|
2014-04-08 18:29:03 +00:00
|
|
|
"io/ioutil"
|
2013-12-03 22:19:42 +00:00
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
"time"
|
2014-04-08 18:29:03 +00:00
|
|
|
|
|
|
|
log "code.google.com/p/log4go"
|
2014-06-27 16:57:06 +00:00
|
|
|
"github.com/influxdb/influxdb/protocol"
|
2013-12-03 22:19:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type ProtobufServer struct {
|
|
|
|
listener net.Listener
|
|
|
|
port string
|
2014-08-14 18:35:49 +00:00
|
|
|
requestHandler Handler
|
2013-12-03 22:19:42 +00:00
|
|
|
connectionMapLock sync.Mutex
|
|
|
|
connectionMap map[net.Conn]bool
|
|
|
|
}
|
|
|
|
|
2014-01-07 20:43:58 +00:00
|
|
|
const KILOBYTE = 1024
|
|
|
|
const MEGABYTE = 1024 * KILOBYTE
|
|
|
|
const MAX_REQUEST_SIZE = MEGABYTE * 2
|
2013-12-03 22:19:42 +00:00
|
|
|
|
2014-08-14 18:35:49 +00:00
|
|
|
func NewProtobufServer(port string, requestHandler Handler) *ProtobufServer {
|
2013-12-03 22:19:42 +00:00
|
|
|
server := &ProtobufServer{port: port, requestHandler: requestHandler, connectionMap: make(map[net.Conn]bool)}
|
|
|
|
return server
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *ProtobufServer) Close() {
|
|
|
|
self.listener.Close()
|
|
|
|
self.connectionMapLock.Lock()
|
|
|
|
defer self.connectionMapLock.Unlock()
|
2014-06-23 17:14:00 +00:00
|
|
|
for conn := range self.connectionMap {
|
2013-12-03 22:19:42 +00:00
|
|
|
conn.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
// loop while the port is still accepting connections
|
|
|
|
for {
|
|
|
|
_, port, _ := net.SplitHostPort(self.port)
|
|
|
|
conn, err := net.Dial("tcp", "localhost:"+port)
|
|
|
|
if err != nil {
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Error("Received error %s, assuming connection is closed.", err)
|
2013-12-03 22:19:42 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
conn.Close()
|
|
|
|
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Info("Waiting while the server port is closing")
|
2013-12-03 22:19:42 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *ProtobufServer) ListenAndServe() {
|
|
|
|
ln, err := net.Listen("tcp", self.port)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
self.listener = ln
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Info("ProtobufServer listening on %s", self.port)
|
2013-12-03 22:19:42 +00:00
|
|
|
for {
|
|
|
|
conn, err := ln.Accept()
|
|
|
|
if err != nil {
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Error("Error with TCP connection. Assuming server is closing: %s", err)
|
2013-12-03 22:19:42 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
self.connectionMapLock.Lock()
|
|
|
|
self.connectionMap[conn] = true
|
|
|
|
self.connectionMapLock.Unlock()
|
|
|
|
go self.handleConnection(conn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *ProtobufServer) handleConnection(conn net.Conn) {
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Info("ProtobufServer: client connected: %s", conn.RemoteAddr().String())
|
2013-12-03 22:19:42 +00:00
|
|
|
|
|
|
|
message := make([]byte, 0, MAX_REQUEST_SIZE)
|
|
|
|
buff := bytes.NewBuffer(message)
|
|
|
|
var messageSizeU uint32
|
|
|
|
for {
|
|
|
|
err := binary.Read(conn, binary.LittleEndian, &messageSizeU)
|
|
|
|
if err != nil {
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Error("Error reading from connection (%s): %s", conn.RemoteAddr().String(), err)
|
2013-12-03 22:19:42 +00:00
|
|
|
self.connectionMapLock.Lock()
|
|
|
|
delete(self.connectionMap, conn)
|
|
|
|
self.connectionMapLock.Unlock()
|
|
|
|
conn.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
messageSize := int64(messageSizeU)
|
|
|
|
if messageSize > MAX_REQUEST_SIZE {
|
2014-04-08 18:29:03 +00:00
|
|
|
err = self.handleRequestTooLarge(conn, messageSize)
|
2013-12-03 22:19:42 +00:00
|
|
|
} else {
|
|
|
|
err = self.handleRequest(conn, messageSize, buff)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Error("Error, closing connection: %s", err)
|
2013-12-03 22:19:42 +00:00
|
|
|
self.connectionMapLock.Lock()
|
|
|
|
delete(self.connectionMap, conn)
|
|
|
|
self.connectionMapLock.Unlock()
|
|
|
|
conn.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
buff.Reset()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *ProtobufServer) handleRequest(conn net.Conn, messageSize int64, buff *bytes.Buffer) error {
|
|
|
|
reader := io.LimitReader(conn, messageSize)
|
|
|
|
_, err := io.Copy(buff, reader)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
request, err := protocol.DecodeRequest(buff)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2014-03-07 20:21:49 +00:00
|
|
|
log.Debug("Received %s request: %d", request.GetType(), request.GetRequestNumber())
|
|
|
|
|
2013-12-03 22:19:42 +00:00
|
|
|
return self.requestHandler.HandleRequest(request, conn)
|
|
|
|
}
|
|
|
|
|
2014-04-08 18:29:03 +00:00
|
|
|
func (self *ProtobufServer) handleRequestTooLarge(conn net.Conn, messageSize int64) error {
|
2013-12-11 17:39:48 +00:00
|
|
|
log.Error("request too large, dumping: %s (%d)", conn.RemoteAddr().String(), messageSize)
|
2013-12-03 22:19:42 +00:00
|
|
|
for messageSize > 0 {
|
|
|
|
reader := io.LimitReader(conn, MAX_REQUEST_SIZE)
|
2014-04-08 18:29:03 +00:00
|
|
|
_, err := io.Copy(ioutil.Discard, reader)
|
2013-12-03 22:19:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
messageSize -= MAX_REQUEST_SIZE
|
|
|
|
}
|
|
|
|
return self.sendErrorResponse(conn, protocol.Response_REQUEST_TOO_LARGE, "request too large")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *ProtobufServer) sendErrorResponse(conn net.Conn, code protocol.Response_ErrorCode, message string) error {
|
|
|
|
response := &protocol.Response{ErrorCode: &code, ErrorMessage: &message}
|
|
|
|
data, err := response.Encode()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
buff := bytes.NewBuffer(make([]byte, 0, len(data)+4))
|
|
|
|
err = binary.Write(buff, binary.LittleEndian, uint32(len(data)))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = conn.Write(append(buff.Bytes(), data...))
|
|
|
|
return err
|
|
|
|
}
|