Skip to content

Commit

Permalink
Merge pull request #4 from oimyounis/feature/tls
Browse files Browse the repository at this point in the history
Feature/tls
  • Loading branch information
oimyounis authored Jan 20, 2020
2 parents 0571df5 + 844b2bd commit 765fda6
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 21 deletions.
75 changes: 62 additions & 13 deletions broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package gott

import (
gob "bytes"
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
"log"
"math"
"net"
Expand All @@ -24,6 +27,7 @@ var GOTT *Broker
// Broker is the main broker struct. Should not be used directly. Use the global GOTT var instead.
type Broker struct {
listener net.Listener
tlsListener net.Listener
clients map[string]*Client
mutex sync.RWMutex
config Config
Expand All @@ -40,6 +44,7 @@ type Broker struct {
func NewBroker() (*Broker, error) {
GOTT = &Broker{
listener: nil,
tlsListener: nil,
clients: map[string]*Client{},
config: defaultConfig(),
logger: nil,
Expand Down Expand Up @@ -67,25 +72,69 @@ func NewBroker() (*Broker, error) {
return GOTT, nil
}

// Listen starts the broker and listens for new connections on the "address" provided in the config file.
// Listen starts the broker and listens for new connections on the address provided in the config file.
func (b *Broker) Listen() error {
l, err := net.Listen("tcp", b.config.Listen)
if err != nil {
return err
listening := false

if b.config.Listen != "" {
l, err := net.Listen("tcp", b.config.Listen)
if err != nil {
return err
}
defer l.Close()

b.listener = l
log.Println("Broker listening on " + b.listener.Addr().String())
b.logger.Info("Broker listening on " + b.listener.Addr().String())

go func(b *Broker) {
for {
conn, err := b.listener.Accept()
if err != nil {
log.Printf("Couldn't accept connection: %v\n", err)
} else {
go b.handleConnection(conn)
}
}
}(b)
listening = true
}
defer l.Close()

b.listener = l
b.logger.Info("Broker listening on " + b.listener.Addr().String())
if b.config.Tls.Enabled() {
cert, err := tls.LoadX509KeyPair(b.config.Tls.Cert, b.config.Tls.Key)
if err != nil {
return fmt.Errorf("couldn't load cert or key file: %v", err)
}

for {
conn, err := b.listener.Accept()
config := tls.Config{Certificates: []tls.Certificate{cert}}

tl, err := tls.Listen("tcp", b.config.Tls.Listen, &config)
if err != nil {
log.Printf("Couldn't accept connection: %v\n", err)
} else {
go b.handleConnection(conn)
return err
}

b.tlsListener = tl
log.Println("Started TLS listener on " + b.tlsListener.Addr().String())
b.logger.Info("Started TLS listener on " + b.tlsListener.Addr().String())

go func(b *Broker) {
for {
conn, err := b.tlsListener.Accept()
if err != nil {
log.Printf("Couldn't accept connection: %v\n", err)
} else {
go b.handleConnection(conn)
}
}
}(b)
listening = true
}

if !listening {
return errors.New("no listeners started. Both non-tls and tls listeners are disabled")
}

select {}
}

func (b *Broker) addClient(client *Client) {
Expand Down Expand Up @@ -114,7 +163,7 @@ func (b *Broker) handleConnection(conn net.Conn) {
return
}

//log.Printf("Accepted connection from %v", conn.RemoteAddr().String())
log.Printf("Accepted connection from %v", conn.RemoteAddr().String())

c := &Client{
connection: conn,
Expand Down
3 changes: 2 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ loop:

_, err := sockBuffer.Read(fixedHeader)
if err != nil {
GOTT.logger.Info("client disconnected", zap.String("id", c.ClientID))
//log.Println("fixedHeader read error", err)
break
}
Expand Down Expand Up @@ -599,6 +598,8 @@ func (c *Client) disconnect() {

if connected {
GOTT.invokeOnDisconnect(c.ClientID, c.Username, c.gracefulDisconnect)

GOTT.logger.Info("client disconnected", zap.String("id", c.ClientID), zap.Bool("graceful", c.gracefulDisconnect))
}
}

Expand Down
13 changes: 12 additions & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,27 @@ import (
"gopkg.in/yaml.v2"
)

type tlsConfig struct {
Listen, Cert, Key string
}

func (t tlsConfig) Enabled() bool {
return t.Listen != "" && t.Cert != "" && t.Key != ""
}

type Config struct {
ConfigPath string
Listen string
LogLevel string `yaml:"logLevel"`
Tls tlsConfig
LogLevel string `yaml:"log_level"`
Plugins []string
logLevel zapcore.Level
}

func defaultConfig() Config {
return Config{
Listen: ":1883",
Tls: tlsConfig{Listen: ":8883", Cert: "", Key: ""},
LogLevel: "error",
ConfigPath: "config.yml",
}
Expand All @@ -34,6 +44,7 @@ func (c *Config) loadConfig() error {
if err = ioutil.WriteFile("config.yml", []byte(defaultConfigContent), 0664); err != nil {
log.Fatalln("Error creating default config.yml file:", err)
}
file = []byte(defaultConfigContent)
}

if err = yaml.Unmarshal(file, c); err != nil {
Expand Down
25 changes: 19 additions & 6 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,29 @@ const (
defaultConfigContent = `# GOTT configuration file
# listen property is the address that the broker will listen on,
# in the format hostname_or_ip:port,
# default is ":1883".
# in the format hostname_or_ip:port.
# In case you wanted to enable connections over TLS only, leave this empty to
# disable it.
# Default is ":1883".
listen: ":1883"
# logLevel property defines the level to which the broker should log messages,
# tls property defines TLS configurations.
# To disable leave any of the child properties empty.
# tls.listen: Defines the address that the broker will use to serve traffic over
# TLS, in the format hostname_or_ip:port, default is ":8883".
# tls.cert: Absolute path to the certificate file.
# tls.key: Absolute path to the key file.
# Disabled by default.
tls:
listen: ":8883"
cert: ""
key: ""
# log_level property defines the minimum level to which the broker should log messages,
# available levels are "debug", "info", "error" and "fatal",
# "debug" is the lowest and "fatal" is the highest,
# each level includes higher levels as well,
# default is "error".
logLevel: "error"
# each level includes higher levels as well, default is "error".
log_level: "error"
# plugins property is a collection of plugin names,
# all plugins listed here must be placed in the plugins directory to be loaded,
Expand Down

0 comments on commit 765fda6

Please sign in to comment.