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

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

	"github.com/jessevdk/go-flags"
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
16
17
)

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
18
19
20
21
// See https://godoc.org/github.com/jessevdk/go-flags for available tags
var opts struct {
	Config string  `long:"config" description:"This specifies the configuration file" value-name:"filename" default:"servers"`
	Vote   []int64 `short:"v" long:"vote" description:"This specifies the vote. Must be either 0 or 1" choice:"0" choice:"1"`
22
23
24
	Root   string  `short:"r" long:"root" description:"This specifies the root certificate to use" value-name:"filename" default:"config/cert/root.crt"`
	Cert   string  `short:"c" long:"cert" description:"This specifies the certificate to use" value-name:"filename" default:"config/cert/client/c5.crt"`
	Key    string  `short:"k" long:"key" description:"This specifies the private key to use" value-name:"filename" default:"config/cert/client/c5.key"`
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
25
26
27
}

var voter struct {
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
28
	sync.Mutex
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
29
30
31
32

	Config *network.Config

	Client *network.Client
33
34
35
36
37

	ConnectionCount int
	RecievedCount   int
	Acks            map[string]bool
	Done            chan bool
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
38
}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
39

Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
40
func init() {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
41
42
	_, err := flags.Parse(&opts)
	if err != nil {
43
		panic(err)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
44
	}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
45
46

	// Load config
47
48
	config, err := network.LoadConfig()
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
49
		log.Fatal("fatal: " + err.Error())
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
50
	}
51
52
53
	config.CertPath = opts.Cert
	config.KeyPath = opts.Key

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
54
	// Init client
55
	voter.RecievedCount = 0
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
56
	voter.Client = network.NewClient(config)
57
58
59
60
61
62
63
64
65
66
67
68
69
	voter.Client.OnMessage(election.MsgBallotAck, func(conn *network.Conn, data network.MessageData) *network.Message {
		voter.Lock()
		defer voter.Unlock()

		voter.Acks[conn.RemoteAddr().String()] = true
		conn.Close()

		voter.RecievedCount++
		if voter.RecievedCount == voter.ConnectionCount {
			voter.Done <- true
		}
		return nil
	})
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
70
71
72
73

	voter.Mutex = sync.Mutex{}
	voter.Acks = make(map[string]bool)
	voter.Done = make(chan bool, 1)
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
74
75
76
77
}

func main() {
	// Parse commandline arguments and exit if help message was printed.
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
78

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
79
	vote := inputVote()
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
80
	if vote != 0 && vote != 1 {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
81
		fmt.Println("error: vote must be 0 or 1")
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
82
83
84
		os.Exit(0)
	}

85
86
	config, err := network.LoadConfig()
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
87
		log.Fatal("fatal: " + err.Error())
88
	}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
89
	voter.Config = config
90

91
	t := (len(config.Servers) / 2) + 1 // One more than half must be honest!
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
92

93
94
95
96
97
98
	xs := make([]*big.Int, 0, len(config.Servers))
	for _, x := range voter.Config.Servers {
		xs = append(xs, x)
	}

	ballots := election.CreateBallots(t, xs, big.NewInt(vote))
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
99
	sendBallots(ballots)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
100
101
102
103
104

	// Wait for acknowledgements or timeout
	timeout := network.TimeoutAfter(10 * time.Second)
	select {
	case <-voter.Done:
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
105
		log.Println("Main: all servers acknowledged")
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
106
107
108
	case <-timeout:
		for address, status := range voter.Acks {
			if !status {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
109
				log.Println("Main: no acknowledgment from ", address)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
110
111
112
113
114
115
			}
		}
	}

	err = voter.Client.Close()
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
116
		log.Println("Main: error: ", err.Error())
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
117
	}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
118
119
120
121
122
123
124
125
126
127
128
}

func inputVote() int64 {
	if len(opts.Vote) != 0 {
		return opts.Vote[0]
	}

	fmt.Print("Input vote: ")
	reader := bufio.NewReader(os.Stdin)
	text, err := reader.ReadString('\n')
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
129
		log.Fatal("fatal: could not read input")
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
130
	}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
131

Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
132
133
	vote, err := strconv.Atoi(text[0 : len(text)-1])
	if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
134
		fmt.Println("error: vote must be an integer")
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
135
136
137
138
139
140
		os.Exit(0)
	}

	return int64(vote)
}

141
func sendBallots(ballots map[election.UniqueID]*election.Ballot) {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
142
143
144
	voter.Lock()
	defer voter.Unlock()

145
	i := 0
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
146
	for address := range voter.Config.Servers {
147
		conn, err := voter.Client.Connect(address)
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
148
		if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
149
			log.Println("Main: error:", err)
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
150
151
			continue
		}
152
153
		ballot := ballots[conn.SerialNumber()]
		message := network.NewMessage(election.MsgBallot, ballot)
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
154

Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
155
156
		err = conn.WriteMessage(message)
		if err != nil {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
157
			log.Println("Main: error:", err)
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
158
159
			continue
		}
160
161
		voter.Acks[conn.RemoteAddr().String()] = false
		voter.ConnectionCount++
162
		i++
Anders Jensen Løvig's avatar
Stuff    
Anders Jensen Løvig committed
163
	}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
164

165
	if voter.ConnectionCount == 0 {
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
166
		log.Fatal("fatal: could not connect to servers")
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
167
	}
Anders Jensen Løvig's avatar
Anders Jensen Løvig committed
168
}