main.go 4.33 KB
Newer Older
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
1
2
3
package main

import (
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
4
	"bsc-shamir/election"
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
5
	"bsc-shamir/network"
6
	"fmt"
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
7
	"log"
8
	"math/big"
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
9
	"os"
10
	"strings"
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
11
	"time"
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
12

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
13
14
	"github.com/jessevdk/go-flags"
)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
15

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
16
var opts struct {
17
	Port int `short:"p" long:"port" description:"This specifies the port where the server listens" value-name:"port" default:"27000"`
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
18
19
}

20
21
22
23
24
25
var server struct {
	// Server enables this authority to listen for incomming connections.
	Server *network.Server
	// The election being held
	Election *election.Election

26
	Config *network.Config
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
27

28
	Address string
29
30
31

	Closed chan bool
	Done   chan bool
32
33

	Connections map[string]*network.Conn
34
35
36
}

func init() {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
37
38
39
	_, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(0)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
40
41
	}

42
	server.Closed = make(chan bool, 1)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
43
	server.Done = make(chan bool, 1)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
44

45
	// Load configuration to get election parameters and server list.
46
	server.Config, err = network.LoadConfig()
47
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
48
		log.Fatal("fatal:", err)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
49
50
	}

51
	// Find our current port and server id
52
	portStr := fmt.Sprintf(":%d", opts.Port)
53
54
	var serialNumber *big.Int = nil
	for address, sn := range server.Config.Servers {
55
56
		if strings.HasSuffix(address, portStr) {
			server.Address = address
57
			serialNumber = sn
58
59
60
			break
		}
	}
61
	if serialNumber == nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
62
		log.Fatal("fatal: server is not on server list")
63
64
	}

65
	// Initialize server using correct certificates
66
67
	server.Config.CertPath = fmt.Sprintf("config/cert/server/s%d.crt", serialNumber)
	server.Config.KeyPath = fmt.Sprintf("config/cert/server/s%d.key", serialNumber)
68
	server.Server = network.NewServer(server.Config)
69
	server.Server.OnClientMessage(election.MsgBallot, func(conn *network.Conn, data network.MessageData) *network.Message {
70
71
72
		var ballot election.Ballot
		err := data.Unmarshal(&ballot)
		if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
73
			log.Println("Main: error:", err)
74
		} else {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
75
			go server.Election.HandleBallot(conn.SerialNumber(), &ballot)
76
77
		}
		return network.NewMessage(election.MsgBallotAck, nil)
78
79
	})
	server.Server.OnServerMessage(election.MsgClosing, func(conn *network.Conn, data network.MessageData) *network.Message {
80
		server.Election.HandleClosing(conn.SerialNumber())
81
		return nil
82
83
	})
	server.Server.OnServerMessage(election.MsgTally, func(conn *network.Conn, data network.MessageData) *network.Message {
84
85
86
		var tally election.Tally
		err := data.Unmarshal(&tally)
		if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
87
			log.Println("Main: error:", err)
88
		} else {
89
			go server.Election.HandleTally(conn.SerialNumber(), &tally)
90
91
92
		}
		return nil
	})
93
94
95
96
97
98
99
100
101
102
103
104
105

	// Initialize election
	servers := len(server.Config.Servers)
	required := (servers / 2) + 1
	config := &election.Config{
		ServerID:        election.UniqueID(serialNumber.String()),
		Voters:          10,
		Servers:         servers,
		RequiredServers: required,
		Deadline:        time.Now().Add(30 * time.Second),
		CloseCallback:   closeCallback,
		TallyCallback:   tallyCallback,
		ResultCallback:  resultCallback,
106
	}
107
108
109
110
111
	server.Election = election.NewElection(config)
}

func startServer() {
	err := server.Server.Start(opts.Port)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
112
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
113
		log.Fatal("Main: fatal:", err)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
114
	}
115
116
}

117
func conenctServers() {
118
119
120
	connections := 0
	for address := range server.Config.Servers {
		if address != server.Address {
121
			_, err := server.Server.Connect(address)
122
			if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
123
				log.Println("Main: error:", err)
124
125
126
127
128
129
				continue
			}
			connections++
		}
	}
	if connections == 0 {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
130
		log.Fatal("Main: fatal: could not connect to servers")
131
	}
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
}

func startElection() {
	err := server.Election.Start()
	if err != nil {
		log.Fatal("Main: fatal:", err)
	}
}

func main() {
	startServer()
	time.Sleep(2 * time.Second) // Give servers time to start before connecting
	conenctServers()
	time.Sleep(1 * time.Second) // To let servers connect before starting election
	startElection()

	<-server.Done // Closed
	<-server.Done // Result

	time.Sleep(1 * time.Second) // Grace period

	server.Server.Close()
}

func closeCallback(reason election.Reason) {
	msgClosed := network.NewMessage(election.MsgClosing, nil)
	server.Server.Broadcast(msgClosed)
159
160

	server.Done <- true
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
161
}
162

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
163
func tallyCallback(tally *election.Tally) {
164
	msgTally := network.NewMessage(election.MsgTally, tally)
165
	server.Server.Broadcast(msgTally)
166
167
168
169
}

func resultCallback(result *election.Result) {
	if result == nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
170
		log.Printf("Main: no votes received")
171
172
	} else {
		percentage := (float64(result.Tally) / float64(result.Votes)) * 100
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
173
		log.Printf("Main: final result: %d of %d (%.2f%%) voted 1\n", result.Tally, result.Votes, percentage)
174
175
	}

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
176
	server.Done <- true
177
}